mirror of
https://github.com/n64decomp/sm64
synced 2026-04-28 10:03:41 +00:00
Convert textures at compile time
This commit is contained in:
parent
8b4e478297
commit
2a3813c5eb
8
Makefile
8
Makefile
|
|
@ -572,14 +572,18 @@ $(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
|
|||
#==============================================================================#
|
||||
TEXTURE_ENCODING := u8
|
||||
|
||||
ifdef TARGET_NDS
|
||||
TEXTURE_OPTIONS := -d
|
||||
endif
|
||||
|
||||
# Convert PNGs to RGBA32, RGBA16, IA16, IA8, IA4, IA1, I8, I4 binary files
|
||||
$(BUILD_DIR)/%: %.png
|
||||
$(call print,Converting:,$<,$@)
|
||||
$(V)$(N64GRAPHICS) -s raw -i $@ -g $< -f $(lastword $(subst ., ,$@))
|
||||
$(V)$(N64GRAPHICS) -s raw -i $@ -g $< -f $(lastword $(subst ., ,$@)) $(TEXTURE_OPTIONS)
|
||||
|
||||
$(BUILD_DIR)/%.inc.c: %.png
|
||||
$(call print,Converting:,$<,$@)
|
||||
$(V)$(N64GRAPHICS) -s $(TEXTURE_ENCODING) -i $@ -g $< -f $(lastword ,$(subst ., ,$(basename $<)))
|
||||
$(V)$(N64GRAPHICS) -s $(TEXTURE_ENCODING) -i $@ -g $< -f $(lastword ,$(subst ., ,$(basename $<))) $(TEXTURE_OPTIONS)
|
||||
|
||||
# Color Index CI8
|
||||
$(BUILD_DIR)/%.ci8: %.ci8.png
|
||||
|
|
|
|||
|
|
@ -180,10 +180,10 @@ $(eval $(call level_rules,menu,generic)) # Menu (File Select)
|
|||
# Ending cake textures are generated in a special way
|
||||
$(BUILD_DIR)/levels/ending/cake_eu.inc.c: levels/ending/cake_eu.png
|
||||
@$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n"
|
||||
@$(SKYCONV) --type cake-eu --split $^ $(BUILD_DIR)/levels/ending
|
||||
@$(SKYCONV) --type cake-eu --split $^ $(BUILD_DIR)/levels/ending $(TEXTURE_OPTIONS)
|
||||
$(BUILD_DIR)/levels/ending/cake.inc.c: levels/ending/cake.png
|
||||
@$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n"
|
||||
@$(SKYCONV) --type cake --split $^ $(BUILD_DIR)/levels/ending
|
||||
@$(SKYCONV) --type cake --split $^ $(BUILD_DIR)/levels/ending $(TEXTURE_OPTIONS)
|
||||
|
||||
# --------------------------------------
|
||||
# Texture Bin Rules
|
||||
|
|
@ -251,7 +251,7 @@ $(BUILD_DIR)/bin/eu/translation_fr.elf: SEGMENT_ADDRESS := 0x19000000
|
|||
|
||||
$(BUILD_DIR)/bin/%_skybox.c: textures/skyboxes/%.png
|
||||
@$(PRINT) "$(GREEN)Splitting $(YELLOW)$< $(GREEN)to: $(BLUE)$@ $(NO_COL)\n"
|
||||
@$(SKYCONV) --type sky --split $^ $(BUILD_DIR)/bin
|
||||
@$(SKYCONV) --type sky --split $^ $(BUILD_DIR)/bin $(TEXTURE_OPTIONS)
|
||||
|
||||
$(BUILD_DIR)/bin/%_skybox.elf: SEGMENT_ADDRESS := 0x0A000000
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ struct Vertex {
|
|||
};
|
||||
|
||||
struct Texture {
|
||||
uint8_t *original;
|
||||
uint8_t *converted;
|
||||
uint8_t *address;
|
||||
int name;
|
||||
uint8_t type;
|
||||
uint8_t size_x;
|
||||
|
|
@ -82,14 +81,14 @@ static int frame_count;
|
|||
static void load_texture() {
|
||||
// Look up the current texture using a simple hash calculated from its address
|
||||
uint32_t index = ((uint32_t)texture_address >> 5) & 0x7FF;
|
||||
while (texture_map[index].original != texture_address && texture_map[index].original != NULL) {
|
||||
while (texture_map[index].address != texture_address && texture_map[index].address != NULL) {
|
||||
index = (index + 1) & 0x7FF;
|
||||
}
|
||||
|
||||
struct Texture *cur = &texture_map[index];
|
||||
|
||||
// Load the texture if it was found
|
||||
if (cur->original != NULL) {
|
||||
if (cur->address != NULL) {
|
||||
if (cur->name) {
|
||||
glBindTexture(GL_TEXTURE_2D, cur->name);
|
||||
return;
|
||||
|
|
@ -98,7 +97,7 @@ static void load_texture() {
|
|||
// Copy the texture back into VRAM if it was pushed out, pushing out other textures if necessary
|
||||
glGenTextures(1, &cur->name);
|
||||
glBindTexture(GL_TEXTURE_2D, cur->name);
|
||||
while (!glTexImage2D(GL_TEXTURE_2D, 0, cur->type, cur->size_x, cur->size_y, 0, TEXGEN_TEXCOORD, cur->converted)) {
|
||||
while (!glTexImage2D(GL_TEXTURE_2D, 0, cur->type, cur->size_x, cur->size_y, 0, TEXGEN_TEXCOORD, cur->address)) {
|
||||
glDeleteTextures(1, &texture_map[texture_fifo[texture_fifo_end]].name);
|
||||
texture_map[texture_fifo[texture_fifo_end]].name = 0;
|
||||
texture_fifo_end = (texture_fifo_end + 1) & 0x7FF;
|
||||
|
|
@ -108,100 +107,12 @@ static void load_texture() {
|
|||
return;
|
||||
}
|
||||
|
||||
cur->original = texture_address;
|
||||
cur->address = texture_address;
|
||||
|
||||
// The DS only supports texture sizes of 8 << x, but the N64 is less restricted
|
||||
// If a size is unsupported, the next size up is used and the texture is repeated to fill extra space
|
||||
|
||||
// Determine the width of the new texture
|
||||
const int width = texture_row_size << (4 - texture_bit_width);
|
||||
for (cur->size_x = 0; (width - 1) >> (cur->size_x + 3) != 0; cur->size_x++);
|
||||
const int conv_width = 8 << cur->size_x;
|
||||
|
||||
// Determine the height of the new texture
|
||||
const int height = ((texture_size << 1) >> texture_bit_width) / width;
|
||||
for (cur->size_y = 0; (height - 1) >> (cur->size_y + 3) != 0; cur->size_y++);
|
||||
const int conv_height = 8 << cur->size_y;
|
||||
|
||||
// Convert the texture to a format the DS understands
|
||||
// Set the texture format; textures are converted to DS formats at compile time
|
||||
switch (texture_format) {
|
||||
case G_IM_FMT_RGBA:
|
||||
switch (texture_bit_width) {
|
||||
case G_IM_SIZ_16b:
|
||||
cur->converted = (uint8_t*)malloc(conv_width * conv_height * 2);
|
||||
for (int y = 0; y < conv_height; y++) {
|
||||
for (int x = 0; x < conv_width; x++) {
|
||||
const int index = ((y % height) * width + (x % width)) * 2;
|
||||
const uint16_t color = (texture_address[index] << 8) | texture_address[index + 1];
|
||||
const uint8_t r = ((color >> 11) & 0x1F);
|
||||
const uint8_t g = ((color >> 6) & 0x1F);
|
||||
const uint8_t b = ((color >> 1) & 0x1F);
|
||||
const uint8_t a = ((color >> 0) & 0x01);
|
||||
((uint16_t*)cur->converted)[y * conv_width + x] = (a << 15) | (b << 10) | (g << 5) | r;
|
||||
}
|
||||
}
|
||||
DC_FlushRange(cur->converted, conv_width * conv_height * 2);
|
||||
cur->type = GL_RGBA;
|
||||
break;
|
||||
|
||||
default:
|
||||
//printf("Unsupported RGBA texture bit width: %d\n", texture_bit_width);
|
||||
glBindTexture(GL_TEXTURE_2D, cur->name = no_texture);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case G_IM_FMT_IA:
|
||||
switch (texture_bit_width) {
|
||||
case G_IM_SIZ_4b:
|
||||
cur->converted = (uint8_t*)malloc(conv_width * conv_height);
|
||||
for (int y = 0; y < conv_height; y++) {
|
||||
for (int x = 0; x < conv_width; x++) {
|
||||
const int index = (y % height) * width + (x % width);
|
||||
const uint8_t color = (texture_address[index / 2] >> ((index & 1) ? 0 : 4)) & 0x0F;
|
||||
const uint8_t i = ((color >> 1) & 0x07);
|
||||
const uint8_t a = ((color >> 0) & 0x01) ? 31 : 0;
|
||||
cur->converted[y * conv_width + x] = (a << 3) | i;
|
||||
}
|
||||
}
|
||||
DC_FlushRange(cur->converted, conv_width * conv_height);
|
||||
cur->type = GL_RGB8_A5;
|
||||
break;
|
||||
|
||||
case G_IM_SIZ_8b:
|
||||
cur->converted = (uint8_t*)malloc(conv_width * conv_height);
|
||||
for (int y = 0; y < conv_height; y++) {
|
||||
for (int x = 0; x < conv_width; x++) {
|
||||
const uint8_t color = texture_address[(y % height) * width + (x % width)];
|
||||
const uint8_t i = ((color >> 4) & 0x0F) * 7 / 15;
|
||||
const uint8_t a = ((color >> 0) & 0x0F) * 31 / 15;
|
||||
cur->converted[y * conv_width + x] = (a << 3) | i;
|
||||
}
|
||||
}
|
||||
DC_FlushRange(cur->converted, conv_width * conv_height);
|
||||
cur->type = GL_RGB8_A5;
|
||||
break;
|
||||
|
||||
case G_IM_SIZ_16b:
|
||||
cur->converted = (uint8_t*)malloc(conv_width * conv_height);
|
||||
for (int y = 0; y < conv_height; y++) {
|
||||
for (int x = 0; x < conv_width; x++) {
|
||||
const int index = ((y % height) * width + (x % width)) * 2;
|
||||
const uint8_t i = texture_address[index + 0] * 7 / 255;
|
||||
const uint8_t a = texture_address[index + 1] * 31 / 255;
|
||||
cur->converted[y * conv_width + x] = (a << 3) | i;
|
||||
}
|
||||
}
|
||||
DC_FlushRange(cur->converted, conv_width * conv_height);
|
||||
cur->type = GL_RGB8_A5;
|
||||
break;
|
||||
|
||||
default:
|
||||
//printf("Unsupported IA texture bit width: %d\n", texture_bit_width);
|
||||
glBindTexture(GL_TEXTURE_2D, cur->name = no_texture);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case G_IM_FMT_RGBA: cur->type = GL_RGBA; break;
|
||||
case G_IM_FMT_IA: cur->type = GL_RGB8_A5; break;
|
||||
|
||||
default:
|
||||
//printf("Unsupported texture format: %d\n", texture_format);
|
||||
|
|
@ -209,10 +120,16 @@ static void load_texture() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Determine the texture size in terms of 8 << x; textures are fitted to these constraints at compile time
|
||||
const int width = texture_row_size << (4 - texture_bit_width);
|
||||
const int height = ((texture_size << 1) >> texture_bit_width) / width;
|
||||
for (cur->size_x = 0; (width - 1) >> (cur->size_x + 3) != 0; cur->size_x++);
|
||||
for (cur->size_y = 0; (height - 1) >> (cur->size_y + 3) != 0; cur->size_y++);
|
||||
|
||||
// Copy the texture into VRAM, pushing out other textures if necessary
|
||||
glGenTextures(1, &cur->name);
|
||||
glBindTexture(GL_TEXTURE_2D, cur->name);
|
||||
while (!glTexImage2D(GL_TEXTURE_2D, 0, cur->type, cur->size_x, cur->size_y, 0, TEXGEN_TEXCOORD, cur->converted)) {
|
||||
while (!glTexImage2D(GL_TEXTURE_2D, 0, cur->type, cur->size_x, cur->size_y, 0, TEXGEN_TEXCOORD, cur->address)) {
|
||||
glDeleteTextures(1, &texture_map[texture_fifo[texture_fifo_end]].name);
|
||||
texture_map[texture_fifo[texture_fifo_end]].name = 0;
|
||||
texture_fifo_end = (texture_fifo_end + 1) & 0x7FF;
|
||||
|
|
|
|||
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
|||
/adpcm_xq
|
||||
/aifc_decode
|
||||
/aiff_extract_codebook
|
||||
/armips
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
|
@ -320,6 +321,78 @@ int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
|
|||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// internal RGBA/IA -> NDS RGBA/IA
|
||||
// returns length written to 'raw' used or -1 on error
|
||||
//---------------------------------------------------------
|
||||
|
||||
int rgba2nds(uint8_t *raw, const rgba *img, int width, int height, int depth, int nds_width, int nds_height)
|
||||
{
|
||||
int size = (nds_width * nds_height * 16 + 7) / 8;
|
||||
INFO("Converting RGBA%d %dx%d to NDS raw\n", depth, width, height);
|
||||
|
||||
switch (depth) {
|
||||
case 16: case 32:
|
||||
for (int y = 0; y < nds_height; y++) {
|
||||
for (int x = 0; x < nds_width; x++) {
|
||||
int i = (y % height) * width + (x % width);
|
||||
int j = y * nds_width + x;
|
||||
uint8_t r = SCALE_8_5(img[i].red);
|
||||
uint8_t g = SCALE_8_5(img[i].green);
|
||||
uint8_t b = SCALE_8_5(img[i].blue);
|
||||
uint8_t a = img[i].alpha ? 0x1 : 0x0;
|
||||
raw[j*2] = ((g & 0x7) << 5) | r;
|
||||
raw[j*2+1] = (a << 7) | (b << 2) | (g >> 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Error invalid depth %d\n", depth);
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int ia2nds(uint8_t *raw, const ia *img, int width, int height, int depth, int nds_width, int nds_height)
|
||||
{
|
||||
int size = (nds_width * nds_height * 8 + 7) / 8;
|
||||
INFO("Converting IA%d %dx%d to NDS raw\n", depth, width, height);
|
||||
|
||||
switch (depth) {
|
||||
case 1:
|
||||
for (int y = 0; y < nds_height; y++) {
|
||||
for (int x = 0; x < nds_width; x++) {
|
||||
int i = (y % height) * width + (x % width);
|
||||
int j = y * nds_width + x;
|
||||
uint8_t val = img[i].intensity ? 0x7 : 0x0;
|
||||
uint8_t alpha = img[i].intensity ? 0x1F : 0x00;
|
||||
raw[j] = (alpha << 3) | val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: case 8: case 16:
|
||||
for (int y = 0; y < nds_height; y++) {
|
||||
for (int x = 0; x < nds_width; x++) {
|
||||
int i = (y % height) * width + (x % width);
|
||||
int j = y * nds_width + x;
|
||||
uint8_t val = SCALE_8_3(img[i].intensity);
|
||||
uint8_t alpha = SCALE_8_5(img[i].alpha);
|
||||
raw[j] = (alpha << 3) | val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("Error invalid depth %d\n", depth);
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// internal RGBA/IA -> PNG
|
||||
//---------------------------------------------------------
|
||||
|
|
@ -602,6 +675,7 @@ typedef struct
|
|||
int height;
|
||||
int bin_truncate;
|
||||
int pal_truncate;
|
||||
bool nds_format;
|
||||
} graphics_config;
|
||||
|
||||
static const graphics_config default_config =
|
||||
|
|
@ -619,6 +693,7 @@ static const graphics_config default_config =
|
|||
.height = 32,
|
||||
.bin_truncate = 1,
|
||||
.pal_truncate = 1,
|
||||
.nds_format = false,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
@ -701,7 +776,7 @@ static int parse_encoding(write_encoding *encoding, const char *str)
|
|||
|
||||
static void print_usage(void)
|
||||
{
|
||||
ERROR("Usage: n64graphics -e/-i BIN_FILE -g IMG_FILE [-p PAL_FILE] [-o BIN_OFFSET] [-P PAL_OFFSET] [-f FORMAT] [-c CI_FORMAT] [-w WIDTH] [-h HEIGHT] [-V]\n"
|
||||
ERROR("Usage: n64graphics -e/-i BIN_FILE -g IMG_FILE [-p PAL_FILE] [-o BIN_OFFSET] [-P PAL_OFFSET] [-f FORMAT] [-c CI_FORMAT] [-w WIDTH] [-h HEIGHT] [-V] [-d]\n"
|
||||
"\n"
|
||||
"n64graphics v" N64GRAPHICS_VERSION ": N64 graphics manipulator\n"
|
||||
"\n"
|
||||
|
|
@ -721,7 +796,8 @@ static void print_usage(void)
|
|||
" -P PAL_OFFSET starting offset in PAL_FILE (prevents truncation during import)\n"
|
||||
"Other arguments:\n"
|
||||
" -v verbose logging\n"
|
||||
" -V print version information\n",
|
||||
" -V print version information\n"
|
||||
" -d export binary files in NDS format\n",
|
||||
format2str(&default_config.format),
|
||||
encoding2str(default_config.encoding),
|
||||
default_config.width,
|
||||
|
|
@ -749,6 +825,9 @@ static int parse_arguments(int argc, char *argv[], graphics_config *config)
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
config->nds_format = true;
|
||||
break;
|
||||
case 'e':
|
||||
if (++i >= argc) return 0;
|
||||
config->bin_filename = argv[i];
|
||||
|
|
@ -868,23 +947,56 @@ int main(int argc, char *argv[])
|
|||
switch (config.format.format) {
|
||||
case IMG_FORMAT_RGBA:
|
||||
imgr = png2rgba(config.img_filename, &config.width, &config.height);
|
||||
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
if (config.nds_format) {
|
||||
// The DS only supports texture sizes of 8 << x; use the smallest size big enough to hold the texture
|
||||
int size_x, size_y;
|
||||
for (size_x = 0; (config.width - 1) >> (size_x + 3) != 0; size_x++);
|
||||
for (size_y = 0; (config.height - 1) >> (size_y + 3) != 0; size_y++);
|
||||
const int nds_width = 8 << size_x;
|
||||
const int nds_height = 8 << size_y;
|
||||
raw_size = (nds_width * nds_height * 16 + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
}
|
||||
length = rgba2nds(raw, imgr, config.width, config.height, config.format.depth, nds_width, nds_height);
|
||||
} else {
|
||||
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
}
|
||||
length = rgba2raw(raw, imgr, config.width, config.height, config.format.depth);
|
||||
}
|
||||
length = rgba2raw(raw, imgr, config.width, config.height, config.format.depth);
|
||||
break;
|
||||
case IMG_FORMAT_IA:
|
||||
imgi = png2ia(config.img_filename, &config.width, &config.height);
|
||||
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
if (config.nds_format) {
|
||||
// The DS only supports texture sizes of 8 << x; use the smallest size big enough to hold the texture
|
||||
int size_x, size_y;
|
||||
for (size_x = 0; (config.width - 1) >> (size_x + 3) != 0; size_x++);
|
||||
for (size_y = 0; (config.height - 1) >> (size_y + 3) != 0; size_y++);
|
||||
const int nds_width = 8 << size_x;
|
||||
const int nds_height = 8 << size_y;
|
||||
raw_size = (nds_width * nds_height * 8 + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
}
|
||||
length = ia2nds(raw, imgi, config.width, config.height, config.format.depth, nds_width, nds_height);
|
||||
} else {
|
||||
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
if (!raw) {
|
||||
ERROR("Error allocating %u bytes\n", raw_size);
|
||||
}
|
||||
length = ia2raw(raw, imgi, config.width, config.height, config.format.depth);
|
||||
}
|
||||
length = ia2raw(raw, imgi, config.width, config.height, config.format.depth);
|
||||
break;
|
||||
case IMG_FORMAT_I:
|
||||
if (config.nds_format) {
|
||||
ERROR("I texture conversion to NDS format is unimplemented\n");
|
||||
}
|
||||
imgi = png2ia(config.img_filename, &config.width, &config.height);
|
||||
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
|
||||
raw = malloc(raw_size);
|
||||
|
|
@ -905,6 +1017,9 @@ int main(int argc, char *argv[])
|
|||
int pal_success;
|
||||
int pal_length;
|
||||
|
||||
if (config.nds_format) {
|
||||
ERROR("CI texture conversion to NDS format is unimplemented\n");
|
||||
}
|
||||
if (config.pal_truncate) {
|
||||
pal_fp = fopen(config.pal_filename, "wb");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,17 @@ int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
|
|||
// intermediate IA -> N64 raw I4/I8
|
||||
int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
|
||||
|
||||
//---------------------------------------------------------
|
||||
// intermediate RGBA/IA -> NDS RGBA/IA
|
||||
// returns length written to 'raw' used or -1 on error
|
||||
//---------------------------------------------------------
|
||||
|
||||
// intermediate RGBA -> NDS raw RGBA16/RGBA32
|
||||
int rgba2nds(uint8_t *raw, const rgba *img, int width, int height, int depth, int nds_width, int nds_height);
|
||||
|
||||
// intermediate IA -> NDS raw IA1/IA4/IA8/IA16
|
||||
int ia2nds(uint8_t *raw, const ia *img, int width, int height, int depth, int nds_width, int nds_height);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// N64 CI <-> N64 RGBA16/IA16
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ char *writeDir;
|
|||
char skyboxName[256];
|
||||
bool expanded = false;
|
||||
bool writeTiles;
|
||||
bool ndsFormat;
|
||||
|
||||
static void allocate_tiles() {
|
||||
const ImageProps props = IMAGE_PROPERTIES[type][true];
|
||||
|
|
@ -267,8 +268,21 @@ static unsigned int get_index(TextureTile *t, unsigned int i) {
|
|||
|
||||
static void print_raw_data(FILE *cFile, TextureTile *tile) {
|
||||
ImageProps props = IMAGE_PROPERTIES[type][true];
|
||||
uint8_t *raw = malloc(props.tileWidth * props.tileHeight * 2);
|
||||
int size = rgba2raw(raw, tile->px, props.tileWidth, props.tileHeight, 16);
|
||||
uint8_t *raw;
|
||||
int size;
|
||||
if (ndsFormat) {
|
||||
// The DS only supports texture sizes of 8 << x; use the smallest size big enough to hold the texture
|
||||
int size_x, size_y;
|
||||
for (size_x = 0; (props.tileWidth - 1) >> (size_x + 3) != 0; size_x++);
|
||||
for (size_y = 0; (props.tileHeight - 1) >> (size_y + 3) != 0; size_y++);
|
||||
const int nds_width = 8 << size_x;
|
||||
const int nds_height = 8 << size_y;
|
||||
raw = malloc(nds_width * nds_height * 2);
|
||||
size = rgba2nds(raw, tile->px, props.tileWidth, props.tileHeight, 16, nds_width, nds_height);
|
||||
} else {
|
||||
raw = malloc(props.tileWidth * props.tileHeight * 2);
|
||||
size = rgba2raw(raw, tile->px, props.tileWidth, props.tileHeight, 16);
|
||||
}
|
||||
fprint_write_output(cFile, SKYCONV_ENCODING, raw, size);
|
||||
free(raw);
|
||||
}
|
||||
|
|
@ -479,7 +493,8 @@ static void usage() {
|
|||
"Usage: %s --type sky|cake|cake_eu {--combine INPUT OUTPUT | --split INPUT OUTPUT}\n"
|
||||
"\n"
|
||||
"Optional arguments:\n"
|
||||
" --write-tiles OUTDIR Also create the individual tiles' PNG files\n", programName);
|
||||
" --write-tiles OUTDIR Also create the individual tiles' PNG files\n"
|
||||
" -d export binary files in NDS format\n", programName);
|
||||
}
|
||||
|
||||
// Modified from n64split
|
||||
|
|
@ -536,6 +551,10 @@ static int parse_arguments(int argc, char *argv[]) {
|
|||
writeTiles = true;
|
||||
writeDir = argv[i];
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-d") == 0) {
|
||||
ndsFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue