Rotate envmaps to be consistent with vanilla (#636)

* Start work on envmap rotation stuff

* n64graphic envmap rotation working

* Add comment to rotation function

* Fix DLs of non 32x32 env maps, fix envmap rotation

* fix metal flying vanish cap

* fix metal mario's medium poly butt

* new asset version for flipped env maps

* added missing env textures to extract script

* restore asset_needs_update

* Skip asset_needs_update calls if local version matches new version

* removed the goddard textures from envmap rotation

---------

Co-authored-by: mineqwerty <mineqwerty25@gmail.com>
Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>
This commit is contained in:
Gregory Heskett
2023-09-18 09:10:56 -04:00
committed by GitHub
parent 8a83359ed1
commit ab0cebab7a
7 changed files with 126 additions and 49 deletions

View File

@@ -368,8 +368,8 @@ const Gfx mario_metal_butt[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_butt_dl),
@@ -966,8 +966,8 @@ const Gfx mario_metal_left_thigh[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_left_thigh_dl),
@@ -3249,8 +3249,8 @@ const Gfx mario_metal_medium_poly_butt[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_medium_poly_butt_dl),
@@ -3638,8 +3638,8 @@ const Gfx mario_metal_medium_poly_left_thigh[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_medium_poly_left_thigh_dl),
@@ -4128,8 +4128,8 @@ const Gfx mario_metal_low_poly_butt[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_low_poly_butt_dl),
@@ -4373,8 +4373,8 @@ const Gfx mario_metal_low_poly_left_thigh[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_low_poly_left_thigh_dl),
@@ -6608,8 +6608,8 @@ const Gfx mario_metal_cap_unused_dl[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_MODULATERGB, G_CC_MODULATERGB),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_cap_unused_m_logo_dl),
@@ -6787,7 +6787,7 @@ const Gfx mario_metal_cap_wings_transparent[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN | G_CULL_BACK | G_SHADING_SMOOTH),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_texture_metal, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPEndDisplayList(),
};

View File

@@ -271,8 +271,8 @@ const Gfx mario_cap_seg3_dl_03022FF8[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_MODULATERGBFADE, G_CC_MODULATERGBFADE),
gsDPLoadTextureBlock(mario_cap_seg3_texture_0301CF50, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_cap_seg3_texture_0301CF50, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_cap_seg3_dl_03022B30),
@@ -281,7 +281,7 @@ const Gfx mario_cap_seg3_dl_03022FF8[] = {
gsDPPipeSync(),
gsSPClearGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_OFF),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_OFF),
gsDPSetAlphaCompare(G_AC_NONE),
gsDPSetEnvColor(255, 255, 255, 255),
gsSPEndDisplayList(),
@@ -365,14 +365,8 @@ const Gfx mario_cap_seg3_dl_03023298[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_MODULATERGBFADE, G_CC_MODULATERGBFADE),
gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, mario_cap_seg3_texture_0301CF50),
gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 6, G_TX_NOLOD),
gsDPLoadSync(),
gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 64 * 32 - 1, CALC_DXT(64, G_IM_SIZ_16b_BYTES)),
gsDPPipeSync(),
gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 6, G_TX_NOLOD),
gsDPSetTileSize(0, 0, 0, (64 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(mario_cap_seg3_texture_0301CF50, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x7f7f7fff),
gsSPDisplayList(mario_cap_seg3_dl_03022B30),

View File

@@ -160,8 +160,8 @@ const Gfx water_ring_seg6_dl_06013AC0[] = {
gsDPPipeSync(),
gsSPSetGeometryMode(G_TEXTURE_GEN),
gsDPSetCombineMode(G_CC_DECALFADE, G_CC_DECALFADE),
gsDPLoadTextureBlock(water_ring_seg6_texture_06012380, G_IM_FMT_RGBA, G_IM_SIZ_16b, 64, 32, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 6, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x1800, 0x07C0, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(water_ring_seg6_texture_06012380, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 64, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD),
gsSPTexture(0x07C0, 0x1800, 0, G_TX_RENDERTILE, G_ON),
gsSPLightColor(LIGHT_1, 0xffffffff),
gsSPLightColor(LIGHT_2, 0x3f3f3fff),
gsSPVertex(water_ring_seg6_vertex_06013380, 16, 0),
@@ -212,6 +212,6 @@ const Gfx water_ring_seg6_dl_06013AC0[] = {
gsSPClearGeometryMode(G_TEXTURE_GEN),
gsDPSetEnvColor(255, 255, 255, 255),
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
gsSPTexture(0x0F80, 0x07C0, 0, G_TX_RENDERTILE, G_OFF),
gsSPTexture(0x07C0, 0x0F80, 0, G_TX_RENDERTILE, G_OFF),
gsSPEndDisplayList(),
};

View File

@@ -6,6 +6,19 @@ import subprocess
from tools.detect_baseroms import get_rom_candidates
envmap_table = set([
"actors/mario/mario_metal.rgba16.png",
"actors/mario_cap/mario_cap_metal.rgba16.png",
"actors/star/star_surface.rgba16.png",
"actors/water_bubble/water_bubble.rgba16.png",
"actors/water_ring/water_ring.rgba16.png",
"levels/castle_inside/29.rgba16.png",
"levels/castle_inside/30.rgba16.png",
"levels/hmc/7.rgba16.png",
"levels/castle_inside/16.ia16.png",
"levels/cotmc/2.rgba16.png"
])
def read_asset_map():
with open("assets.json") as f:
ret = json.load(f)
@@ -20,6 +33,26 @@ def read_local_asset_list(f):
ret.append(line.strip())
return ret
def asset_needs_update(asset, version):
if version <= 7 and asset in envmap_table:
return True
if version <= 6 and asset in ["actors/king_bobomb/king_bob-omb_eyes.rgba16.png", "actors/king_bobomb/king_bob-omb_hand.rgba16.png"]:
return True
if version <= 5 and asset == "textures/spooky/bbh_textures.00800.rgba16.png":
return True
if version <= 4 and asset in ["textures/mountain/ttm_textures.01800.rgba16.png", "textures/mountain/ttm_textures.05800.rgba16.png"]:
return True
if version <= 3 and asset == "textures/cave/hmc_textures.01800.rgba16.png":
return True
if version <= 2 and asset == "textures/inside/inside_castle_textures.09000.rgba16.png":
return True
if version <= 1 and asset.endswith(".m64"):
return True
if version <= 0 and asset.endswith(".aiff"):
return True
return False
def remove_file(fname):
os.remove(fname)
print("deleting", fname)
@@ -44,7 +77,7 @@ def clean_assets(local_asset_file):
def main():
# In case we ever need to change formats of generated files, we keep a
# revision ID in the local asset file.
new_version = 7
new_version = 8
try:
local_asset_file = open(".assets-local.txt")
@@ -117,7 +150,7 @@ def main():
todo = defaultdict(lambda: [])
for (asset, data, exists) in all_assets:
# Leave existing assets alone if they have a compatible version.
if exists:
if exists and not (local_version == new_version or asset_needs_update(asset, local_version)):
continue
meta = data[:-2]
@@ -226,6 +259,9 @@ def main():
check=True,
)
else:
rotate_envmap = "false"
if asset in envmap_table:
rotate_envmap = "true"
w, h = meta
fmt = asset.split(".")[-2]
subprocess.run(
@@ -241,6 +277,8 @@ def main():
str(w),
"-h",
str(h),
"-r",
rotate_envmap,
],
check=True,
)

View File

@@ -116,13 +116,6 @@
*/
// #define PUPPYLIGHTS
/**
* Uses the correct "up" vector for the guLookAtReflect call in geo_process_master_list_sub.
* It is sideways in vanilla, and since vanilla's environment map textures are sideways too, those will appear as sideways in-game if this is enabled.
* Make sure your custom environment map textures are the correct orientation.
*/
// #define FIX_REFLECT_MTX
/**
* Disables all object shadows. You'll probably only want this either as a last resort for performance or if you're making a super stylized hack.
*/

View File

@@ -696,21 +696,17 @@ void geo_process_camera(struct GraphNodeCamera *node) {
// As a result, environment mapping is broken on Fast3DEX2 without the
// changes below.
Mat4* cameraMatrix = &gCameraTransform;
#ifdef FIX_REFLECT_MTX
/**
* HackerSM64 2.1: Now uses the correct "up" vector for the guLookAtReflect call in geo_process_master_list_sub.
* It was originally sideways in vanilla, with vanilla's environment map textures sideways to accommodate, but those
* textures are now rotated automatically on extraction to allow for this to be fixed.
*/
gCurLookAt->l[0].l.dir[0] = (s8)(127.0f * (*cameraMatrix)[0][0]);
gCurLookAt->l[0].l.dir[1] = (s8)(127.0f * (*cameraMatrix)[1][0]);
gCurLookAt->l[0].l.dir[2] = (s8)(127.0f * (*cameraMatrix)[2][0]);
gCurLookAt->l[1].l.dir[0] = (s8)(127.0f * -(*cameraMatrix)[0][1]);
gCurLookAt->l[1].l.dir[1] = (s8)(127.0f * -(*cameraMatrix)[1][1]);
gCurLookAt->l[1].l.dir[2] = (s8)(127.0f * -(*cameraMatrix)[2][1]);
#else
gCurLookAt->l[0].l.dir[0] = (s8)(127.0f * (*cameraMatrix)[0][0]);
gCurLookAt->l[0].l.dir[1] = (s8)(127.0f * (*cameraMatrix)[1][0]);
gCurLookAt->l[0].l.dir[2] = (s8)(127.0f * (*cameraMatrix)[2][0]);
gCurLookAt->l[1].l.dir[0] = (s8)(127.0f * (*cameraMatrix)[0][1]);
gCurLookAt->l[1].l.dir[1] = (s8)(127.0f * (*cameraMatrix)[1][1]);
gCurLookAt->l[1].l.dir[2] = (s8)(127.0f * (*cameraMatrix)[2][1]);
#endif
#endif // F3DEX_GBI_2
// Make a copy of the view matrix and scale its translation based on WORLD_SCALE

View File

@@ -38,6 +38,45 @@ typedef struct
// N64 RGBA/IA/I/CI -> internal RGBA/IA
//---------------------------------------------------------
// Rotate raw image counterclockwise (width and height need swapped externally)
void rotate_raw_img(uint8_t *raw, int width, int height, int depth) {
uint8_t *tmp_rotated;
int bytes;
int size;
if (depth == 32) {
bytes = 4;
} else if (depth == 16) {
bytes = 2;
} else {
ERROR("rotated raw image does not have a valid depth");
return;
}
size = width * height * bytes;
tmp_rotated = malloc(size);
if (!tmp_rotated) {
ERROR("Error allocating %d bytes\n", size);
return;
}
int offset_src = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int offset_dst = (((width - j - 1) * height) + i) * bytes;
for (int k = 0; k < bytes; k++) {
tmp_rotated[offset_dst + k] = raw[offset_src++];
}
}
}
bcopy(tmp_rotated, raw, size);
free(tmp_rotated);
tmp_rotated = NULL;
}
rgba *raw2rgba(const uint8_t *raw, int width, int height, int depth)
{
rgba *img;
@@ -602,6 +641,7 @@ typedef struct
int height;
int bin_truncate;
int pal_truncate;
int rotate_envmap;
} graphics_config;
static const graphics_config default_config =
@@ -619,6 +659,7 @@ static const graphics_config default_config =
.height = 32,
.bin_truncate = 1,
.pal_truncate = 1,
.rotate_envmap = 0,
};
typedef struct
@@ -701,7 +742,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] [-r ROTATE] [-V]\n"
"\n"
"n64graphics v" N64GRAPHICS_VERSION ": N64 graphics manipulator\n"
"\n"
@@ -715,6 +756,7 @@ static void print_usage(void)
" -s SCHEME output scheme: raw, u8 (hex), u64 (hex) (default: %s)\n"
" -w WIDTH export texture width (default: %d)\n"
" -h HEIGHT export texture height (default: %d)\n"
" -r ROTATE rotate envmap texture for rgba extraction only (default: false)\n"
"CI arguments:\n"
" -c CI_FORMAT CI palette format: rgba16, ia16 (default: %s)\n"
" -p PAL_FILE palette binary file to import/export from/to\n"
@@ -787,6 +829,14 @@ static int parse_arguments(int argc, char *argv[], graphics_config *config)
config->pal_offset = strtoul(argv[i], NULL, 0);
config->pal_truncate = 0;
break;
case 'r':
if (++i >= argc) return 0;
if (!strcmp(argv[i], "true") || !strcmp(argv[i], "True") || strtoul(argv[i], NULL, 0) == 1) {
config->rotate_envmap = 1;
} else {
config->rotate_envmap = 0;
}
break;
case 's':
if (++i >= argc) return 0;
if (!parse_encoding(&config->encoding, argv[i])) {
@@ -1006,6 +1056,12 @@ int main(int argc, char *argv[])
}
switch (config.format.format) {
case IMG_FORMAT_RGBA:
if (config.rotate_envmap) {
rotate_raw_img(raw, config.width, config.height, config.format.depth);
int tmp_height = config.height;
config.height = config.width;
config.width = tmp_height;
}
imgr = raw2rgba(raw, config.width, config.height, config.format.depth);
res = rgba2png(config.img_filename, imgr, config.width, config.height);
break;