tex archives (#1072)

* extraction

* hmm

* eth cleanup

* tex skeleton

* building

* OK

* pal OK

* cleaned texture names

* moved tex code to separate file

* additional error checking

* proposed splits

* split a5dd0

* additional cleanup

* myoop

* wahoo

* lru

* fixules

* fixin agin

---------

Co-authored-by: HailSanta <Hail2Santa@gmail.com>
Co-authored-by: Ethan Roseman <ethteck@gmail.com>
This commit is contained in:
HailSanta 2023-06-29 08:06:23 -04:00 committed by GitHub
parent 8f0f0bd941
commit 6bb14ff8be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2981 additions and 2381 deletions

View File

@ -994,14 +994,13 @@ typedef struct BattleStatus {
/* 0x45C */ char unk_45C[4]; /* 0x45C */ char unk_45C[4];
} BattleStatus; // size = 0x460 } BattleStatus; // size = 0x460
// alternative name: TileDescriptor
typedef struct TextureHeader { typedef struct TextureHeader {
/* 0x00 */ s8 name[32]; /* 0x00 */ s8 name[32];
/* 0x20 */ u16 auxW; /* 0x20 */ u16 auxW;
/* 0x22 */ u16 mainW; /* 0x22 */ u16 mainW;
/* 0x24 */ u16 auxH; /* 0x24 */ u16 auxH;
/* 0x26 */ u16 mainH; /* 0x26 */ u16 mainH;
/* 0x28 */ u8 unk_28; /* 0x28 */ u8 isVariant;
/* 0x29 */ u8 extraTiles; // 0 - none, 1 - mipmap, 2 - ?, 3 - use aux tile /* 0x29 */ u8 extraTiles; // 0 - none, 1 - mipmap, 2 - ?, 3 - use aux tile
/* 0x2A */ u8 colorCombineType : 6; /* 0x2A */ u8 colorCombineType : 6;
/* 0x2A */ u8 colorCombineSubType : 2; /* 0x2A */ u8 colorCombineSubType : 2;

View File

@ -113,7 +113,7 @@ void filemenu_choose_name_update(MenuPanel*);
void filemenu_choose_name_cleanup(MenuPanel*); void filemenu_choose_name_cleanup(MenuPanel*);
void filemenu_draw_message(u8*, s32, s32, s32, s32, u32); void filemenu_draw_message(u8*, s32, s32, s32, s32, u32);
void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy); void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy);
extern WindowStyleCustom filemenu_windowStyles[]; extern WindowStyleCustom filemenu_windowStyles[];
extern u8 filemenu_createfile_gridData[]; extern u8 filemenu_createfile_gridData[];

View File

@ -1097,7 +1097,7 @@ void btl_update(void);
void update_item_entities(void); void update_item_entities(void);
void iterate_models(void); void iterate_models(void);
void restore_map_collision_data(void); void restore_map_collision_data(void);
void load_model_textures(struct ModelNode* model, s32 romOffset, s32 size); void mdl_load_all_textures(struct ModelNode* model, s32 romOffset, s32 size);
void calculate_model_sizes(void); void calculate_model_sizes(void);
#endif #endif

View File

@ -179,7 +179,7 @@ void update_model_animator(s32);
void update_model_animator_with_transform(s32 animatorID, Mtx* mtx); void update_model_animator_with_transform(s32 animatorID, Mtx* mtx);
void set_mdl_custom_gfx_set(Model*, s32, u32); void set_mdl_custom_gfx_set(Model*, s32, u32);
ModelNodeProperty* get_model_property(ModelNode* node, ModelPropertyKeys key); ModelNodeProperty* get_model_property(ModelNode* node, ModelPropertyKeys key);
void func_80115498(u32 romOffset, s32 textureID, s32 baseOffset, s32 size); void load_texture_variants(u32 romOffset, s32 textureID, s32 baseOffset, s32 size);
s32 step_model_animator(ModelAnimator* animator); s32 step_model_animator(ModelAnimator* animator);
AnimatorNode* get_animator_node_for_tree_index(ModelAnimator* animator, s32 treeIndex); AnimatorNode* get_animator_node_for_tree_index(ModelAnimator* animator, s32 treeIndex);
AnimatorNode* get_animator_node_with_id(ModelAnimator* animator, s32 id); AnimatorNode* get_animator_node_with_id(ModelAnimator* animator, s32 id);

View File

@ -146,7 +146,7 @@ extern u16 gCurrentDoorSounds;
extern UNK_TYPE D_800E92D8; extern UNK_TYPE D_800E92D8;
extern UNK_TYPE D_80147574; extern UNK_TYPE D_80147574;
extern s8 D_8014C248[]; extern b8 D_8014C248;
extern UNK_FUN_PTR(TalkNotificationCallback); extern UNK_FUN_PTR(TalkNotificationCallback);
extern UNK_FUN_PTR(InteractNotificationCallback); extern UNK_FUN_PTR(InteractNotificationCallback);

View File

@ -193,8 +193,8 @@ void btl_state_update_normal_start(void) {
s32 size; s32 size;
UiStatus* uiStatus; UiStatus* uiStatus;
void* compressedAsset; void* compressedAsset;
ModelNode* model; ModelNode* rootModel;
s32 textureRom; s32 texturesOffset;
Actor* actor; Actor* actor;
Evt* script; Evt* script;
s32 enemyNotDone; s32 enemyNotDone;
@ -226,10 +226,10 @@ void btl_state_update_normal_start(void) {
ASSERT(size <= 0x8000); ASSERT(size <= 0x8000);
model = gMapShapeData.header.root; rootModel = gMapShapeData.header.root;
textureRom = get_asset_offset(stage->texture, &size); texturesOffset = get_asset_offset(stage->texture, &size);
if (model != NULL) { if (rootModel != NULL) {
load_data_for_models(model, textureRom, size); load_data_for_models(rootModel, texturesOffset, size);
} }
load_battle_hit_asset(stage->hit); load_battle_hit_asset(stage->hit);

1759
src/entity.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -181,14 +181,14 @@ BSS u16 D_802517E0[2][0x400] ALIGNED(16);
BSS u8 filemenu_glyphBuffer[20][0x80]; BSS u8 filemenu_glyphBuffer[20][0x80];
#endif #endif
void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { void filemenu_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy) {
if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) { if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) {
return; return;
} }
if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) { if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) {
return; return;
} }
gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileDescriptor, uls, ult, dsdx, dtdy); gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileIdx, uls, ult, dsdx, dtdy);
} }
void filemenu_set_selected(MenuPanel* menu, s32 col, s32 row) { void filemenu_set_selected(MenuPanel* menu, s32 col, s32 row) {

180
src/game_states.c Normal file
View File

@ -0,0 +1,180 @@
#include "common.h"
extern GameMode gMainGameState[2]; // TODO rename
void state_delegate_NOP(void) {
}
void clear_game_modes(void) {
GameMode* gameMode;
s32 i;
for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
gameMode->flags = 0;
}
}
GameMode* set_next_game_mode(GameMode* arg0) {
GameMode* gameMode;
s32 i;
for (gameMode = gMainGameState, i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags == 0) {
break;
}
}
ASSERT(i < ARRAY_COUNT(gMainGameState));
gameMode->flags = 1 | 2;
gameMode->init = arg0->init;
gameMode->step = arg0->step;
gameMode->render = arg0->render;
gameMode->unk_0C = NULL;
if (gameMode->init == NULL) {
gameMode->init = state_delegate_NOP;
}
if (gameMode->step == NULL) {
gameMode->step = state_delegate_NOP;
}
if (gameMode->unk_0C == NULL) {
gameMode->unk_0C = state_delegate_NOP;
}
if (gameMode->render == NULL) {
gameMode->render = state_delegate_NOP;
}
gameMode->renderAux = state_delegate_NOP;
gameMode->init();
return gameMode;
}
GameMode* set_game_mode_slot(s32 i, GameMode* mode) {
GameMode* gameMode = &gMainGameState[i];
ASSERT(i < ARRAY_COUNT(gMainGameState));
gameMode->flags = 2 | 1;
gameMode->init = mode->init;
gameMode->step = mode->step;
gameMode->render = mode->render;
gameMode->unk_0C = NULL;
if (gameMode->init == NULL) gameMode->init = state_delegate_NOP;
if (gameMode->step == NULL) gameMode->step = state_delegate_NOP;
if (gameMode->unk_0C == NULL) gameMode->unk_0C = state_delegate_NOP;
if (gameMode->render == NULL) gameMode->render = state_delegate_NOP;
gameMode->renderAux = state_delegate_NOP;
gameMode->init();
return gameMode;
}
void game_mode_set_fpDrawAuxUI(s32 i, void (*fn)(void)) {
GameMode* gameMode = &gMainGameState[i];
ASSERT(i < ARRAY_COUNT(gMainGameState));
gameMode->renderAux = fn;
gameMode->flags |= 0x20;
if (fn == NULL) {
gameMode->renderAux = state_delegate_NOP;
}
}
void func_80112DD4(s32 i) {
gMainGameState[i].flags |= 4;
}
void func_80112DFC(s32 i) {
gMainGameState[i].flags |= 8;
}
void func_80112E24(s32 i) {
gMainGameState[i].flags &= ~0x1C;
}
void func_80112E4C(s32 i) {
gMainGameState[i].flags &= ~0x0C;
gMainGameState[i].flags |= 0x10;
}
void step_current_game_mode(void) {
GameMode* gameMode = gMainGameState;
s32 i;
for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags != 0) {
if (!(gameMode->flags & 4)) {
if (!(gameMode->flags & 8)) {
gameMode->flags &= ~2;
gameMode->step();
}
}
}
}
}
void state_do_unk(void) {
GameMode* gameMode = gMainGameState;
s32 i;
for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags != 0) {
if (!(gameMode->flags & 4)) {
if (!(gameMode->flags & 0x10)) {
gameMode->unk_0C();
}
}
}
}
}
void state_render_backUI(void) {
GameMode* gameMode = gMainGameState;
s32 i;
for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags != 0) {
if (!(gameMode->flags & 4)) {
if (!(gameMode->flags & 0x10)) {
gameMode->render();
}
}
}
}
}
void state_render_frontUI(void) {
GameMode* gameMode = gMainGameState;
s32 i;
for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags != 0) {
if (!(gameMode->flags & 4)) {
if (!(gameMode->flags & 2)) {
if (gameMode->flags & 0x20) {
gameMode->renderAux();
}
}
}
}
}
// re-initialization needed - evidence of inlining? or just copy/pasting?
gameMode = &gMainGameState[0];
for (i = 0; i < ARRAY_COUNT(gMainGameState); i++, gameMode++) {
if (gameMode->flags != 0) {
if (!(gameMode->flags & 4)) {
if (!(gameMode->flags & 2)) {
if (gameMode->flags & 0x10) {
gameMode->render();
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -126,7 +126,7 @@ void pause_set_cursor_pos_immediate(s32 windowID, s32 posX, s32 posY);
void pause_set_cursor_opacity(s32 val); void pause_set_cursor_opacity(s32 val);
void pause_draw_menu_label(s32 index, s32 x, s32 y); void pause_draw_menu_label(s32 index, s32 x, s32 y);
s32 pause_get_total_equipped_bp_cost(void); s32 pause_get_total_equipped_bp_cost(void);
void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy); void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy);
s32 pause_get_menu_msg(s32 index); s32 pause_get_menu_msg(s32 index);
s32 pause_interp_vertical_scroll(s32 deltaBefore); s32 pause_interp_vertical_scroll(s32 deltaBefore);
void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *)); void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *));

View File

@ -845,14 +845,14 @@ s32 pause_get_total_equipped_bp_cost(void) {
return totalCost; return totalCost;
} }
void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileDescriptor, s32 uls, s32 ult, s32 dsdx, s32 dtdy) { void pause_draw_rect(s32 ulx, s32 uly, s32 lrx, s32 lry, s32 tileIdx, s32 uls, s32 ult, s32 dsdx, s32 dtdy) {
if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) { if (ulx <= -2688 || uly <= -2688 || lrx <= 0 || lry <= 0) {
return; return;
} }
if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) { if (ulx >= 1280 || uly >= 960 || lrx >= 2688 || lry >= 2688) {
return; return;
} }
gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileDescriptor, uls, ult, dsdx, dtdy); gSPScisTextureRectangle(gMainGfxPos++, ulx, uly, lrx, lry, tileIdx, uls, ult, dsdx, dtdy);
} }
void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *)) { void pause_sort_item_list(s16* arr, s32 len, s32 (*compare)(s16*, s16 *)) {

View File

@ -195,7 +195,7 @@ void state_step_end_battle(void) {
set_background_size(296, 200, 12, 20); set_background_size(296, 200, 12, 20);
} }
load_model_textures(mapSettings->modelTreeRoot, get_asset_offset(wMapTexName, &sizeTemp), sizeTemp); mdl_load_all_textures(mapSettings->modelTreeRoot, get_asset_offset(wMapTexName, &sizeTemp), sizeTemp);
calculate_model_sizes(); calculate_model_sizes();
npc_reload_all(); npc_reload_all();

View File

@ -57,7 +57,7 @@ void state_init_file_select(void) {
general_heap_create(); general_heap_create();
hud_element_set_aux_cache(0, 0); hud_element_set_aux_cache(0, 0);
hud_element_clear_cache(); hud_element_clear_cache();
load_model_textures(0, 0, 0); mdl_load_all_textures(NULL, 0, 0);
gCameras[CAM_DEFAULT].updateMode = CAM_UPDATE_MODE_6; gCameras[CAM_DEFAULT].updateMode = CAM_UPDATE_MODE_6;
gCameras[CAM_DEFAULT].needsInit = TRUE; gCameras[CAM_DEFAULT].needsInit = TRUE;
gCameras[CAM_DEFAULT].nearClip = 16; gCameras[CAM_DEFAULT].nearClip = 16;

View File

@ -100,7 +100,7 @@ void state_init_title_screen(void) {
gOverrideFlags = 0; gOverrideFlags = 0;
timeFreezeMode = 0; timeFreezeMode = 0;
D_8014C248[0] = 1; D_8014C248 = TRUE;
general_heap_create(); general_heap_create();
clear_printers(); clear_printers();
sfx_set_reverb_mode(0); sfx_set_reverb_mode(0);

View File

@ -1910,11 +1910,6 @@ EvtScript N(EVS_Intro_Main) = {
f32 N(AnimBowser_FlyOff_Time) = 0.0; f32 N(AnimBowser_FlyOff_Time) = 0.0;
#if VERSION_PAL
API_CALLABLE(N(AnimBowser_FlyOff));
INCLUDE_ASM(ApiResult, "world/area_hos/hos_05/hos_05_5_intro", AnimBowser_FlyOff);
asm(".section .data");
#else
API_CALLABLE(N(AnimBowser_FlyOff)) { API_CALLABLE(N(AnimBowser_FlyOff)) {
Npc* bowserMain = resolve_npc(script, NPC_Bowser_Body); Npc* bowserMain = resolve_npc(script, NPC_Bowser_Body);
Npc* bowserProp = resolve_npc(script, NPC_Bowser_Prop); Npc* bowserProp = resolve_npc(script, NPC_Bowser_Prop);
@ -1931,20 +1926,15 @@ API_CALLABLE(N(AnimBowser_FlyOff)) {
bowserMain->colliderPos.y = bowserMain->pos.y; bowserMain->colliderPos.y = bowserMain->pos.y;
bowserProp->colliderPos.y = bowserProp->pos.y; bowserProp->colliderPos.y = bowserProp->pos.y;
N(AnimBowser_FlyOff_Time)++; N(AnimBowser_FlyOff_Time)++;
if (N(AnimBowser_FlyOff_Time) > 40.0f) { if (N(AnimBowser_FlyOff_Time) > (int)(40 * DT)) {
return ApiStatus_DONE1; return ApiStatus_DONE1;
} else { } else {
return ApiStatus_BLOCK; return ApiStatus_BLOCK;
} }
} }
#endif
f32 N(AnimKammy_FlyOff_Time) = 0.0; f32 N(AnimKammy_FlyOff_Time) = 0.0;
#if VERSION_PAL
API_CALLABLE(N(AnimKammy_FlyOff));
INCLUDE_ASM(ApiResult, "world/area_hos/hos_05/hos_05_5_intro", AnimKammy_FlyOff);
#else
API_CALLABLE(N(AnimKammy_FlyOff)) { API_CALLABLE(N(AnimKammy_FlyOff)) {
Npc* kammy = resolve_npc(script, NPC_Kammy); Npc* kammy = resolve_npc(script, NPC_Kammy);
@ -1958,13 +1948,12 @@ API_CALLABLE(N(AnimKammy_FlyOff)) {
40.0f, &kammy->pos.y); 40.0f, &kammy->pos.y);
kammy->colliderPos.y = kammy->pos.y; kammy->colliderPos.y = kammy->pos.y;
N(AnimKammy_FlyOff_Time)++; N(AnimKammy_FlyOff_Time)++;
if (N(AnimKammy_FlyOff_Time) > 40.0f) { if (N(AnimKammy_FlyOff_Time) > (int)(40 * DT)) {
return ApiStatus_DONE1; return ApiStatus_DONE1;
} else { } else {
return ApiStatus_BLOCK; return ApiStatus_BLOCK;
} }
} }
#endif
API_CALLABLE(N(func_80244934_A2EB74)) { API_CALLABLE(N(func_80244934_A2EB74)) {
if (isInitialCall) { if (isInitialCall) {

View File

@ -44,3 +44,7 @@ extern EvtScript N(EVS_Main);
extern EvtScript N(EVS_Dummy); extern EvtScript N(EVS_Dummy);
extern EvtScript N(EVS_InitializeMinigame); extern EvtScript N(EVS_InitializeMinigame);
extern NpcGroupList N(DefaultNPCs); extern NpcGroupList N(DefaultNPCs);
#if VERSION_PAL
extern s32 N(pal_variable);
#endif

View File

@ -1,7 +1,6 @@
#include "mgm_02.h" #include "mgm_02.h"
#if VERSION_PAL #if VERSION_PAL
extern s32 N(pal_variable);
s32 N(get_tattle)(void) { s32 N(get_tattle)(void) {
s32 msgID = MSG_MapTattle_mgm_02; s32 msgID = MSG_MapTattle_mgm_02;
if (N(pal_variable) != 0) { if (N(pal_variable) != 0) {

View File

@ -438,7 +438,7 @@ API_CALLABLE(N(RunMinigame)) {
gameFinished = FALSE; gameFinished = FALSE;
hittingPeachBlock = FALSE; hittingPeachBlock = FALSE;
data = get_enemy(0)->varTablePtr[0]; data = get_enemy(SCOREKEEPER_ENEMY_IDX)->varTablePtr[SMASH_DATA_VAR_IDX];
for (i = 0; i < NUM_BOXES; i++) { for (i = 0; i < NUM_BOXES; i++) {
if (data->box[i].npcID != -1) { if (data->box[i].npcID != -1) {

View File

@ -199,10 +199,10 @@ void load_map_by_IDs(s16 areaID, s16 mapID, s16 loadType) {
sfx_reset_door_sounds(); sfx_reset_door_sounds();
if (!skipLoadingAssets) { if (!skipLoadingAssets) {
s32 thing = get_asset_offset(wMapTexName, &decompressedSize); s32 texturesOffset = get_asset_offset(wMapTexName, &decompressedSize);
if (mapSettings->modelTreeRoot != NULL) { if (mapSettings->modelTreeRoot != NULL) {
load_data_for_models(mapSettings->modelTreeRoot, thing, decompressedSize); load_data_for_models(mapSettings->modelTreeRoot, texturesOffset, decompressedSize);
} }
} }

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from functools import cache from functools import lru_cache
import os import os
import shutil import shutil
from typing import List, Dict, Optional, Set, Union from typing import List, Dict, Optional, Set, Union
@ -21,6 +21,7 @@ YAY0_COMPRESS_TOOL = f"{BUILD_TOOLS}/yay0/Yay0compress"
CRC_TOOL = f"{BUILD_TOOLS}/rom/n64crc" CRC_TOOL = f"{BUILD_TOOLS}/rom/n64crc"
def exec_shell(command: List[str]) -> str: def exec_shell(command: List[str]) -> str:
ret = subprocess.run(command, stdout=subprocess.PIPE, text=True) ret = subprocess.run(command, stdout=subprocess.PIPE, text=True)
return ret.stdout return ret.stdout
@ -238,6 +239,12 @@ def write_ninja_rules(
command=f"$python {BUILD_TOOLS}/mapfs/combine.py $version $out $in", command=f"$python {BUILD_TOOLS}/mapfs/combine.py $version $out $in",
) )
ninja.rule(
"tex",
description="tex $out",
command=f"$python {BUILD_TOOLS}/mapfs/tex.py $out $tex_dir",
)
ninja.rule( ninja.rule(
"pack_title_data", "pack_title_data",
description="pack_title_data $out", description="pack_title_data $out",
@ -400,7 +407,7 @@ class Configure:
return [str(v) for v in ret.values()] return [str(v) for v in ret.values()]
@cache @lru_cache(maxsize=None)
def resolve_asset_path(self, path: Path) -> Path: def resolve_asset_path(self, path: Path) -> Path:
parts = list(path.parts) parts = list(path.parts)
@ -887,7 +894,15 @@ class Configure:
) )
elif name.endswith("_tex"): elif name.endswith("_tex"):
compress = False compress = False
bin_path = path tex_dir = path.parent / name
build(
bin_path,
[tex_dir],
"tex",
variables={
"tex_dir": str(tex_dir)
}
)
elif name.endswith("_shape"): elif name.endswith("_shape"):
map_name = "_".join(name.split("_")[:-1]) map_name = "_".join(name.split("_")[:-1])

View File

@ -6,6 +6,7 @@ from glob import glob
import png # type: ignore import png # type: ignore
def unpack_color(s): def unpack_color(s):
r = (s >> 11) & 0x1F r = (s >> 11) & 0x1F
g = (s >> 6) & 0x1F g = (s >> 6) & 0x1F
@ -47,12 +48,11 @@ def reversed_if(iterator, cond):
class Converter: class Converter:
def __init__(self, mode, infile, outfile, *argv): def __init__(self, mode, infile, flip_x: bool = False, flip_y: bool = False):
self.mode = mode self.mode = mode
self.infile = infile self.infile = infile
self.outfile = outfile self.flip_x = flip_x
self.flip_x = "--flip-x" in argv self.flip_y = flip_y
self.flip_y = "--flip-y" in argv
assert self.flip_x == False, "flip_x is not supported" assert self.flip_x == False, "flip_x is not supported"
@ -64,151 +64,150 @@ class Converter:
print(self.infile + ": warning: " + msg, file=stderr) print(self.infile + ": warning: " + msg, file=stderr)
def convert(self): def convert(self):
out_bytes = bytearray()
out_width = 0
out_height = 0
img = png.Reader(self.infile) img = png.Reader(self.infile)
if self.mode == "rgba32": if self.mode == "rgba32":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
f.write(row) out_bytes += row
elif self.mode == "rgba16": elif self.mode == "rgba16":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for rgba in iter_in_groups(row, 4): for rgba in iter_in_groups(row, 4):
if rgba[3] not in (0, 0xFF): if rgba[3] not in (0, 0xFF):
self.warn("alpha mask mode but translucent pixels used") self.warn("alpha mask mode but translucent pixels used")
color = pack_color(*rgba) color = pack_color(*rgba)
f.write(color.to_bytes(2, byteorder="big")) out_bytes += color.to_bytes(2, byteorder="big")
elif self.mode == "ci8": elif self.mode == "ci8":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.read()
for row in reversed_if(img.read()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
f.write(row) out_bytes += row
elif self.mode == "ci4": elif self.mode == "ci4":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.read()
for row in reversed_if(img.read()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for a, b in iter_in_groups(row, 2): for a, b in iter_in_groups(row, 2):
byte = (a << 4) | b byte = (a << 4) | b
byte = byte & 0xFF byte = byte & 0xFF
f.write(byte.to_bytes(1, byteorder="big")) out_bytes += byte.to_bytes(1, byteorder="big")
elif self.mode == "palette": elif self.mode == "palette":
img.preamble(True) img.preamble(True)
palette = img.palette(alpha="force") palette = img.palette(alpha="force")
with open(self.outfile, "wb") as f: for rgba in palette:
for rgba in palette: if rgba[3] not in (0, 0xFF):
if rgba[3] not in (0, 0xFF): self.warn("alpha mask mode but translucent pixels used")
self.warn("alpha mask mode but translucent pixels used")
color = pack_color(*rgba) color = pack_color(*rgba)
f.write(color.to_bytes(2, byteorder="big")) out_bytes += color.to_bytes(2, byteorder="big")
elif self.mode == "ia4": elif self.mode == "ia4":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2):
i1 = rgb_to_intensity(*c1[:3]) i1 = rgb_to_intensity(*c1[:3])
a1 = c1[3] a1 = c1[3]
i2 = rgb_to_intensity(*c2[:3]) i2 = rgb_to_intensity(*c2[:3])
a2 = c2[3] a2 = c2[3]
i1 = i1 >> 5 i1 = i1 >> 5
i2 = i2 >> 5 i2 = i2 >> 5
if a1 not in (0, 0xFF) or a2 not in (0, 0xFF): if a1 not in (0, 0xFF) or a2 not in (0, 0xFF):
self.warn("alpha mask mode but translucent pixels used") self.warn("alpha mask mode but translucent pixels used")
if c1[0] != c1[1] != c1[2]: if c1[0] != c1[1] != c1[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
if c2[0] != c2[1] != c2[2]: if c2[0] != c2[1] != c2[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
a1 = 1 if a1 > 128 else 0 a1 = 1 if a1 > 128 else 0
a2 = 1 if a2 > 128 else 0 a2 = 1 if a2 > 128 else 0
h = (i1 << 1) | a1 h = (i1 << 1) | a1
l = (i2 << 1) | a2 l = (i2 << 1) | a2
byte = (h << 4) | l byte = (h << 4) | l
f.write(byte.to_bytes(1, byteorder="big")) out_bytes += byte.to_bytes(1, byteorder="big")
elif self.mode == "ia8": elif self.mode == "ia8":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for rgba in iter_in_groups(row, 4): for rgba in iter_in_groups(row, 4):
i = rgb_to_intensity(*rgba[:3]) i = rgb_to_intensity(*rgba[:3])
a = rgba[3] a = rgba[3]
i = floor(15 * (i / 0xFF)) i = floor(15 * (i / 0xFF))
a = floor(15 * (a / 0xFF)) a = floor(15 * (a / 0xFF))
if rgba[0] != rgba[1] != rgba[2]: if rgba[0] != rgba[1] != rgba[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
byte = (i << 4) | a byte = (i << 4) | a
f.write(byte.to_bytes(1, byteorder="big")) out_bytes += byte.to_bytes(1, byteorder="big")
elif self.mode == "ia16": elif self.mode == "ia16":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for rgba in iter_in_groups(row, 4): for rgba in iter_in_groups(row, 4):
i = rgb_to_intensity(*rgba[:3]) i = rgb_to_intensity(*rgba[:3])
a = rgba[3] a = rgba[3]
if rgba[0] != rgba[1] != rgba[2]: if rgba[0] != rgba[1] != rgba[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
f.write(bytes((i, a))) out_bytes += bytes((i, a))
elif self.mode == "i4": elif self.mode == "i4":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2): for c1, c2 in iter_in_groups(iter_in_groups(row, 4), 2):
if c1[3] != 0xFF or c2[3] != 0xFF: if c1[3] != 0xFF or c2[3] != 0xFF:
self.warn("discarding alpha channel") self.warn("discarding alpha channel")
i1 = rgb_to_intensity(*c1[:3]) i1 = rgb_to_intensity(*c1[:3])
i2 = rgb_to_intensity(*c2[:3]) i2 = rgb_to_intensity(*c2[:3])
i1 = floor(15 * (i1 / 0xFF)) i1 = floor(15 * (i1 / 0xFF))
i2 = floor(15 * (i2 / 0xFF)) i2 = floor(15 * (i2 / 0xFF))
if c1[0] != c1[1] != c1[2]: if c1[0] != c1[1] != c1[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
if c2[0] != c2[1] != c2[2]: if c2[0] != c2[1] != c2[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
byte = (i1 << 4) | i2 byte = (i1 << 4) | i2
f.write(byte.to_bytes(1, byteorder="big")) out_bytes += byte.to_bytes(1, byteorder="big")
elif self.mode == "i8": elif self.mode == "i8":
with open(self.outfile, "wb") as f: (out_width, out_height, data, info) = img.asRGBA()
for row in reversed_if(img.asRGBA()[2], self.flip_y): for row in reversed_if(data, self.flip_y):
for rgba in iter_in_groups(row, 4): for rgba in iter_in_groups(row, 4):
if rgba[3] != 0xFF or rgba[3] != 0xFF: if rgba[3] != 0xFF or rgba[3] != 0xFF:
self.warn("discarding alpha channel") self.warn("discarding alpha channel")
if rgba[0] != rgba[1] != rgba[2]: if rgba[0] != rgba[1] != rgba[2]:
self.warn("grayscale mode but image is not") self.warn("grayscale mode but image is not")
i = rgb_to_intensity(*rgba[:3]) i = rgb_to_intensity(*rgba[:3])
f.write(i.to_bytes(1, byteorder="big")) out_bytes += i.to_bytes(1, byteorder="big")
elif self.mode == "party": elif self.mode == "party":
data = img.read()[2] (out_width, out_height, data, info) = img.read()
img.preamble(True) img.preamble(True)
palette = img.palette(alpha="force") palette = img.palette(alpha="force")
with open(self.outfile, "wb") as f: # palette
# palette for rgba in palette:
for rgba in palette: if rgba[3] not in (0, 0xFF):
if rgba[3] not in (0, 0xFF): self.warn("alpha mask mode but translucent pixels used")
self.warn("alpha mask mode but translucent pixels used")
color = pack_color(*rgba) color = pack_color(*rgba)
f.write(color.to_bytes(2, byteorder="big")) out_bytes += color.to_bytes(2, byteorder="big")
assert f.tell() == 0x200, "palette has wrong size" # ci 8
for row in reversed_if(data, self.flip_y):
out_bytes += row
# ci 8 out_bytes += b"\0\0\0\0\0\0\0\0\0\0" # padding
for row in reversed_if(data, self.flip_y):
f.write(row)
f.write(b"\0\0\0\0\0\0\0\0\0\0") # padding
elif self.mode == "bg": elif self.mode == "bg":
width, height, data, info = img.read() (out_width, out_height, data, info) = img.read()
img.preamble(True) img.preamble(True)
palettes = [img.palette(alpha="force")] palettes = [img.palette(alpha="force")]
@ -217,52 +216,56 @@ class Converter:
pal.preamble(True) pal.preamble(True)
palettes.append(pal.palette(alpha="force")) palettes.append(pal.palette(alpha="force"))
with open(self.outfile, "wb") as f: baseaddr = 0x80200000 # gBackgroundImage
baseaddr = 0x80200000 # gBackgroundImage headers_len = 0x10 * len(palettes)
headers_len = 0x10 * len(palettes) palettes_len = 0x200 * len(palettes)
palettes_len = 0x200 * len(palettes)
# header (struct BackgroundHeader) # header (struct BackgroundHeader)
for i, palette in enumerate(palettes): for i, palette in enumerate(palettes):
f.write( out_bytes += (baseaddr + palettes_len + headers_len).to_bytes(
(baseaddr + palettes_len + headers_len).to_bytes( 4, byteorder="big"
4, byteorder="big" ) # raster offset
) out_bytes += (baseaddr + headers_len + 0x200 * i).to_bytes(
) # raster offset 4, byteorder="big"
f.write( ) # palette offset
(baseaddr + headers_len + 0x200 * i).to_bytes( out_bytes += (12).to_bytes(2, byteorder="big") # startX
4, byteorder="big" out_bytes += (20).to_bytes(2, byteorder="big") # startY
) out_bytes += (out_width).to_bytes(2, byteorder="big") # width
) # palette offset out_bytes += (out_height).to_bytes(2, byteorder="big") # height
f.write((12).to_bytes(2, byteorder="big")) # startX
f.write((20).to_bytes(2, byteorder="big")) # startY
f.write((width).to_bytes(2, byteorder="big")) # width
f.write((height).to_bytes(2, byteorder="big")) # height
assert f.tell() == headers_len for palette in palettes:
# palette
for rgba in palette:
if rgba[3] not in (0, 0xFF):
self.warn("alpha mask mode but translucent pixels used")
for palette in palettes: color = pack_color(*rgba)
# palette out_bytes += color.to_bytes(2, byteorder="big")
for rgba in palette:
if rgba[3] not in (0, 0xFF):
self.warn("alpha mask mode but translucent pixels used")
color = pack_color(*rgba) # ci 8
f.write(color.to_bytes(2, byteorder="big")) for row in reversed_if(data, self.flip_y):
out_bytes += row
assert f.tell() == palettes_len + headers_len
# ci 8
for row in reversed_if(data, self.flip_y):
f.write(row)
else: else:
print("unsupported mode", file=stderr) print("unsupported mode", file=stderr)
exit(1) exit(1)
return (out_bytes, out_width, out_height)
if __name__ == "__main__": if __name__ == "__main__":
if len(argv) < 4: if len(argv) < 4:
print("usage: build.py MODE INFILE OUTFILE [--flip-x] [--flip-y]") print("usage: build.py MODE INFILE OUTFILE [--flip-x] [--flip-y]")
exit(1) exit(1)
Converter(*argv[1:]).convert() mode = argv[1]
infile = argv[2]
outfile = argv[3]
flip_x = "--flip-x" in argv
flip_y = "--flip-y" in argv
(out_bytes, out_width, out_height) = Converter(
mode, infile, flip_x, flip_y
).convert()
with open(argv[3], "wb") as f:
f.write(out_bytes)

19
tools/build/mapfs/tex.py Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
import argparse
from pathlib import Path
from sys import argv, path
path.append(str(Path(__file__).parent.parent.parent / "splat"))
path.append(str(Path(__file__).parent.parent.parent / "splat_ext"))
from tex_archives import TexArchive
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Texture archives")
parser.add_argument("bin_out", type=Path, help="Output binary file path")
parser.add_argument("tex_dir", type=Path, help="File path to input tex subdirectory")
parser.add_argument(
"--endian", choices=["big", "little"], default="big", help="Output endianness"
)
args = parser.parse_args()
TexArchive.build(args.bin_out, args.tex_dir, args.endian)

View File

@ -2,7 +2,7 @@
import argparse import argparse
from dataclasses import dataclass from dataclasses import dataclass
from functools import cache from functools import lru_cache
from pathlib import Path from pathlib import Path
import sys import sys
from typing import List from typing import List
@ -95,7 +95,7 @@ SPECIAL_RASTER_BYTES = (
) )
@cache @lru_cache(maxsize=None)
def get_asset_path(asset: str) -> Path: def get_asset_path(asset: str) -> Path:
for sdir in ASSET_STACK: for sdir in ASSET_STACK:
potential_path = ASSET_DIR / sdir / "sprite" / asset potential_path = ASSET_DIR / sdir / "sprite" / asset

View File

@ -17,3 +17,11 @@ def unpack_color(data):
b = ceil(0xFF * (b / 31)) b = ceil(0xFF * (b / 31))
return r, g, b, a return r, g, b, a
def pack_color(r, g, b, a):
r = r >> 3
g = g >> 3
b = b >> 3
a = a >> 7
return (r << 11) | (g << 6) | (b << 1) | a

View File

@ -1,5 +1,6 @@
import os import os, sys
from pathlib import Path from pathlib import Path
from typing import List
from segtypes.n64.segment import N64Segment from segtypes.n64.segment import N64Segment
from util.n64.Yay0decompress import Yay0Decompressor from util.n64.Yay0decompress import Yay0Decompressor
from util.color import unpack_color from util.color import unpack_color
@ -9,6 +10,10 @@ import png # type: ignore
import yaml as yaml_loader import yaml as yaml_loader
import n64img.image import n64img.image
SPLAT_EXT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(str(Path(SPLAT_EXT_DIR)))
from tex_archives import TexArchive
script_dir = Path(os.path.dirname(os.path.realpath(__file__))) script_dir = Path(os.path.dirname(os.path.realpath(__file__)))
@ -69,6 +74,8 @@ class N64SegPm_map_data(N64Segment):
self.files = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader) self.files = yaml_loader.load(f.read(), Loader=yaml_loader.SafeLoader)
def split(self, rom_bytes): def split(self, rom_bytes):
assert isinstance(self.rom_start, int)
fs_dir = options.opts.asset_path / self.dir / self.name fs_dir = options.opts.asset_path / self.dir / self.name
(fs_dir / "title").mkdir(parents=True, exist_ok=True) (fs_dir / "title").mkdir(parents=True, exist_ok=True)
(fs_dir / "party").mkdir(parents=True, exist_ok=True) (fs_dir / "party").mkdir(parents=True, exist_ok=True)
@ -104,6 +111,7 @@ class N64SegPm_map_data(N64Segment):
bytes = Yay0Decompressor.decompress_python(bytes) bytes = Yay0Decompressor.decompress_python(bytes)
if name.startswith("party_"): if name.startswith("party_"):
assert path is not None
with open(path, "wb") as f: with open(path, "wb") as f:
# CI-8 # CI-8
w = png.Writer(150, 105, palette=parse_palette(bytes[:0x200])) w = png.Writer(150, 105, palette=parse_palette(bytes[:0x200]))
@ -143,7 +151,7 @@ class N64SegPm_map_data(N64Segment):
w = 128 w = 128
h = 32 h = 32
img = n64img.image.CI4( img = n64img.image.CI4(
data=bytes[0x10 : 0x10 + w * h], width=w, height=h data=bytes[0x10 : 0x10 + (w * h // 2)], width=w, height=h
) )
img.palette = parse_palette(bytes[0x810:0x830]) img.palette = parse_palette(bytes[0x810:0x830])
img.write(fs_dir / "title/copyright.png") img.write(fs_dir / "title/copyright.png")
@ -189,7 +197,10 @@ class N64SegPm_map_data(N64Segment):
write_bg_png( write_bg_png(
bytes, fs_dir / "bg" / f"{name}.alt.png", header_offset=0x10 bytes, fs_dir / "bg" / f"{name}.alt.png", header_offset=0x10
) )
elif name.endswith("_tex"):
TexArchive.extract(bytes, fs_dir / "tex" / name)
else: else:
assert path is not None
with open(path, "wb") as f: with open(path, "wb") as f:
f.write(bytes) f.write(bytes)

View File

@ -0,0 +1,642 @@
from dataclasses import dataclass
import os
import struct
import json
from pathlib import Path
import png
import n64img.image
from util.color import unpack_color, pack_color
from segtypes.n64.palette import iter_in_groups
from sys import path
path.append(str(Path(__file__).parent.parent / "build"))
from img.build import Converter
def decode_null_terminated_ascii(data):
length = 0
for byte in data:
if byte == 0:
break
length += 1
return data[:length].decode("ascii")
def parse_palette(data):
palette = []
for a, b in iter_in_groups(data, 2):
palette.append(unpack_color([a, b]))
return palette
FMT_RGBA = 0
FMT_CI = 2
FMT_IA = 3
FMT_I = 4
DEPTH_4_BIT = 0
DEPTH_8_BIT = 1
DEPTH_16_BIT = 2
DEPTH_32_BIT = 3
# extra tile modes
TILES_BASIC = 0
TILES_MIPMAPS = 1
TILES_SHARED_AUX = 2
TILES_INDEPENDENT_AUX = 3
aux_combine_modes = {
0x00: "None", # multiply main * prim, ignore aux
0x08: "Multiply", # multiply main * aux * prim
0x0D: "ModulateAlpha", # use prim color, but multiply alpha by the difference between main and aux red channels
0x10: "LerpMainAux", # use prim alpha to lerp between main and aux color, use main alpha
}
aux_combine_modes_inv = {v: k for k, v in aux_combine_modes.items()}
wrap_modes = {
0: "Repeat",
1: "Mirror",
2: "Clamp",
}
wrap_modes_inv = {v: k for k, v in wrap_modes.items()}
# correspond to modes provided to gSetTextureFilter, only 0 and 2 are ever used
filter_modes = {
0: "Nearest",
2: "Bilerp",
3: "Average",
}
filter_modes_inv = {v: k for k, v in filter_modes.items()}
def get_format_name(fmt, depth):
# get image from bytes for valid combinations of fmt and bit depth
if fmt == FMT_RGBA:
if depth == DEPTH_16_BIT:
return "RGBA16"
if depth == DEPTH_32_BIT:
return "RGBA32"
elif fmt == FMT_CI:
if depth == DEPTH_4_BIT:
return "CI4"
elif depth == DEPTH_8_BIT:
return "CI8"
elif fmt == FMT_IA:
if depth == DEPTH_4_BIT:
return "IA4"
elif depth == DEPTH_8_BIT:
return "IA8"
elif depth == DEPTH_16_BIT:
return "IA16"
elif fmt == FMT_I:
if depth == DEPTH_4_BIT:
return "I4"
elif depth == DEPTH_8_BIT:
return "I8"
else:
raise Exception(f"Invalid format/depth pair: {fmt} and {depth}")
def get_format_code(name):
# get image from bytes for valid combinations of fmt and bit depth
if name == "RGBA16":
return (FMT_RGBA, DEPTH_16_BIT)
elif name == "RGBA32":
return (FMT_RGBA, DEPTH_32_BIT)
elif name == "CI4":
return (FMT_CI, DEPTH_4_BIT)
elif name == "CI8":
return (FMT_CI, DEPTH_8_BIT)
elif name == "IA4":
return (FMT_IA, DEPTH_4_BIT)
elif name == "IA8":
return (FMT_IA, DEPTH_8_BIT)
elif name == "IA16":
return (FMT_IA, DEPTH_16_BIT)
elif name == "I4":
return (FMT_I, DEPTH_4_BIT)
elif name == "I8":
return (FMT_I, DEPTH_8_BIT)
else:
raise Exception(f"Invalid format: {name}")
# class for reading a tex file buffer one chunk at a time
@dataclass
class TexBuffer:
data: bytes
pos: int = 0
@property
def capacity(self):
return len(self.data)
def get(self, count):
amt = int(min(count, self.capacity - self.pos))
ret = self.data[self.pos : self.pos + amt]
self.pos += amt
return ret
def remaining(self):
return self.capacity - self.pos
class TexImage:
# utility function for unpacking aux/main property pairs from a single byte
def split_byte(self, byte):
return (byte >> 4 & 0xF), (byte & 0xF)
# utility function for unpacking aux/main property pairs from a single byte
def pack_byte(self, aux, main):
return ((aux & 0xF) << 4) | (main & 0xF)
# get n64img object from the buffer
def get_n64_img(self, texbuf: TexBuffer, fmt, depth, w, h):
# calculate size for bit depth
if depth == DEPTH_4_BIT:
size = w * h // 2
elif depth == DEPTH_8_BIT:
size = w * h
elif depth == DEPTH_16_BIT:
size = w * h * 2
elif depth == DEPTH_32_BIT:
size = w * h * 4
else:
raise Exception(f"Invalid bit depth: {depth}")
bytes = texbuf.get(size)
# get image from bytes for valid combinations of fmt and bit depth
fmt_name = get_format_name(fmt, depth)
if fmt_name == "RGBA16":
img = n64img.image.RGBA16(data=bytes, width=w, height=h)
elif fmt_name == "RGBA32":
img = n64img.image.RGBA32(data=bytes, width=w, height=h)
elif fmt_name == "CI4":
img = n64img.image.CI4(data=bytes, width=w, height=h)
elif fmt_name == "CI8":
img = n64img.image.CI8(data=bytes, width=w, height=h)
elif fmt_name == "IA4":
img = n64img.image.IA4(data=bytes, width=w, height=h)
elif fmt_name == "IA8":
img = n64img.image.IA8(data=bytes, width=w, height=h)
elif fmt_name == "IA16":
img = n64img.image.IA16(data=bytes, width=w, height=h)
elif fmt_name == "I4":
img = n64img.image.I4(data=bytes, width=w, height=h)
elif fmt_name == "I8":
img = n64img.image.I8(data=bytes, width=w, height=h)
else:
raise Exception(f"Invalid format: {fmt_name}")
img.flip_v = True
return img
# get palette from the buffer
def get_n64_pal(self, texbuf, fmt, depth):
if fmt == FMT_CI:
if depth == DEPTH_4_BIT:
return parse_palette(texbuf.get(0x20))
elif depth == DEPTH_8_BIT:
return parse_palette(texbuf.get(0x200))
# extract texture properties and rasters from buffer
def from_bytes(self, texbuf: TexBuffer):
# strip area prefix and original extension suffix
raw_name = decode_null_terminated_ascii(texbuf.get(32))
self.img_name = raw_name[4:-3]
self.raw_ext = raw_name[-3:]
(
self.aux_width,
self.main_width,
self.aux_height,
self.main_height,
self.is_variant,
self.extra_tiles,
self.combine_mode,
fmts,
depths,
hwraps,
vwraps,
self.filter_mode,
) = struct.unpack(">HHHHBBBBBBBB", texbuf.get(16))
# unpack upper/lower nibbles for aux/main
(self.aux_fmt, self.main_fmt) = self.split_byte(fmts)
(self.aux_depth, self.main_depth) = self.split_byte(depths)
(self.aux_hwrap, self.main_hwrap) = self.split_byte(hwraps)
(self.aux_vwrap, self.main_vwrap) = self.split_byte(vwraps)
self.has_mipmaps = False
self.has_aux = False
# main img only
if self.extra_tiles == TILES_BASIC:
self.main_img = self.get_n64_img(
texbuf,
self.main_fmt,
self.main_depth,
self.main_width,
self.main_height,
)
if self.main_fmt == FMT_CI:
self.main_img.palette = self.get_n64_pal(
texbuf, self.main_fmt, self.main_depth
)
# main img + mipmaps
elif self.extra_tiles == TILES_MIPMAPS:
self.has_mipmaps = True
self.main_img = self.get_n64_img(
texbuf,
self.main_fmt,
self.main_depth,
self.main_width,
self.main_height,
)
# read mipmaps
self.mipmaps = []
divisor = 2
if self.main_width >= (32 >> self.main_depth):
while True:
if (self.main_width // divisor) <= 0:
break
mmw = self.main_width // divisor
mmh = self.main_height // divisor
mipmap = self.get_n64_img(
texbuf, self.main_fmt, self.main_depth, mmw, mmh
)
self.mipmaps.append(mipmap)
divisor = divisor * 2
if (self.main_width // divisor) < (16 >> self.main_depth):
break
# read palette and assign to all images
if self.main_fmt == FMT_CI:
shared_pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth)
self.main_img.palette = shared_pal
for mipmap in self.mipmaps:
mipmap.palette = shared_pal
# main + aux (shared attributes)
elif self.extra_tiles == TILES_SHARED_AUX:
self.has_aux = True
self.main_img = self.get_n64_img(
texbuf,
self.main_fmt,
self.main_depth,
self.main_width,
self.main_height // 2,
)
self.aux_img = self.get_n64_img(
texbuf,
self.main_fmt,
self.main_depth,
self.main_width,
self.main_height // 2,
)
if self.main_fmt == FMT_CI:
shared_pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth)
self.main_img.palette = shared_pal
self.aux_img.palette = shared_pal
# main + aux (independent attributes)
elif self.extra_tiles == TILES_INDEPENDENT_AUX:
self.has_aux = True
# read main
self.main_img = self.get_n64_img(
texbuf,
self.main_fmt,
self.main_depth,
self.main_width,
self.main_height,
)
if self.main_fmt == FMT_CI:
pal = self.get_n64_pal(texbuf, self.main_fmt, self.main_depth)
self.main_img.palette = pal
# read aux
self.aux_img = self.get_n64_img(
texbuf, self.aux_fmt, self.aux_depth, self.aux_width, self.aux_height
)
if self.aux_fmt == FMT_CI:
self.aux_img.palette = self.get_n64_pal(
texbuf, self.aux_fmt, self.aux_depth
)
# constructs a dictionary entry for the tex archive for this texture
def get_json_entry(self):
out = {}
out["name"] = self.img_name
# only a single texture in 'tst_tex' has 'rgb', otherwise this is always 'tif'
if self.raw_ext != "tif":
out["ext"] = self.raw_ext
out["main"] = {
"format": get_format_name(self.main_fmt, self.main_depth),
"hwrap": wrap_modes.get(self.main_hwrap),
"vwrap": wrap_modes.get(self.main_vwrap),
}
if self.has_aux:
if self.extra_tiles == TILES_SHARED_AUX:
out["aux"] = {
"format": "Shared",
"hwrap": wrap_modes.get(self.aux_hwrap),
"vwrap": wrap_modes.get(self.aux_vwrap),
}
else:
out["aux"] = {
"format": get_format_name(self.aux_fmt, self.aux_depth),
"hwrap": wrap_modes.get(self.aux_hwrap),
"vwrap": wrap_modes.get(self.aux_vwrap),
}
if self.has_mipmaps:
out["hasMipmaps"] = True
if self.filter_mode == 2:
out["filter"] = True
out["combine"] = aux_combine_modes.get(self.combine_mode)
if self.is_variant:
out["variant"] = True
return out
def save_images(self, tex_path):
self.main_img.write(tex_path / f"{self.img_name}.png")
if self.has_aux:
self.aux_img.write(tex_path / f"{self.img_name}_AUX.png")
if self.has_mipmaps:
for idx, mipmap in enumerate(self.mipmaps):
mipmap.write(tex_path / f"{self.img_name}_MM{idx + 1}.png")
def read_json_img(self, img_data, tile_name, img_name):
fmt_str = img_data.get("format")
if fmt_str == None:
raise Exception(f"Texture {img_name} is missing 'format' for '{tile_name}'")
hwrap_str = img_data.get("hwrap", "Missing")
hwrap = wrap_modes_inv.get(hwrap_str)
if hwrap == None:
raise Exception(f"Texture {img_name} has invalid 'hwrap' for '{tile_name}'")
vwrap_str = img_data.get("vwrap", "Missing")
vwrap = wrap_modes_inv.get(vwrap_str)
if vwrap == None:
raise Exception(f"Texture {img_name} has invalid 'vwrap' for '{tile_name}'")
return fmt_str, hwrap, vwrap
def get_img_file(self, fmt_str, img_file):
(out_img, out_w, out_h) = Converter(
mode=fmt_str.lower(), infile=img_file, flip_y=True
).convert()
out_pal = bytearray()
if fmt_str == "CI4" or fmt_str == "CI8":
img = png.Reader(img_file)
img.preamble(True)
palette = img.palette(alpha="force")
for rgba in palette:
if rgba[3] not in (0, 0xFF):
self.warn("alpha mask mode but translucent pixels used")
color = pack_color(*rgba)
out_pal += color.to_bytes(2, byteorder="big")
return (out_img, out_pal, out_w, out_h)
# read texture properties from dictionary and load images
def from_json(self, tex_path: Path, json_data):
self.img_name = json_data["name"]
if "ext" in json_data:
self.raw_ext = json_data["ext"]
else:
self.raw_ext = "tif"
# read data for main tile
main_data = json_data.get("main")
if main_data == None:
raise Exception(f"Texture {self.img_name} has no definition for 'main'")
(main_fmt_name, self.main_hwrap, self.main_vwrap) = self.read_json_img(
main_data, "main", self.img_name
)
(self.main_fmt, self.main_depth) = get_format_code(main_fmt_name)
# read main image
img_path = str(tex_path / f"{self.img_name}.png")
if not os.path.isfile(img_path):
raise Exception(f"Could not find main image for texture: {self.img_name}")
(
self.main_img,
self.main_pal,
self.main_width,
self.main_height,
) = self.get_img_file(main_fmt_name, img_path)
# read data for aux tile
self.has_aux = "aux" in json_data
if self.has_aux:
aux_data = json_data.get("aux")
(aux_fmt_name, self.aux_hwrap, self.aux_vwrap) = self.read_json_img(
aux_data, "aux", self.img_name
)
if aux_fmt_name == "Shared":
# aux tiles have blank attributes in SHARED mode
aux_fmt_name = main_fmt_name
self.aux_fmt = 0
self.aux_depth = 0
self.aux_hwrap = 0
self.aux_vwrap = 0
self.extra_tiles = TILES_SHARED_AUX
else:
(self.aux_fmt, self.aux_depth) = get_format_code(aux_fmt_name)
self.extra_tiles = TILES_INDEPENDENT_AUX
# read aux image
img_path = str(tex_path / f"{self.img_name}_AUX.png")
if not os.path.isfile(img_path):
raise Exception(
f"Could not find AUX image for texture: {self.img_name}"
)
(
self.aux_img,
self.aux_pal,
self.aux_width,
self.aux_height,
) = self.get_img_file(aux_fmt_name, img_path)
if self.extra_tiles == TILES_SHARED_AUX:
# aux tiles have blank sizes in SHARED mode
self.main_height *= 2
self.aux_width = 0
self.aux_height = 0
else:
self.aux_fmt = 0
self.aux_depth = 0
self.aux_hwrap = 0
self.aux_vwrap = 0
self.aux_width = 0
self.aux_height = 0
self.extra_tiles = TILES_BASIC
# read mipmaps
self.has_mipmaps = json_data.get("hasMipmaps", False)
if self.has_mipmaps:
self.mipmaps = []
mipmap_idx = 1
divisor = 2
if self.main_width >= (32 >> self.main_depth):
while True:
if (self.main_width // divisor) <= 0:
break
mmw = self.main_width // divisor
mmh = self.main_height // divisor
img_path = str(tex_path / f"{self.img_name}_MM{mipmap_idx}.png")
if not os.path.isfile(img_path):
raise Exception(
f"Texture {self.img_name} is missing mipmap level {mipmap_idx} (size = {mmw} x {mmh})"
)
(raster, pal, width, height) = self.get_img_file(
main_fmt_name, img_path
)
self.mipmaps.append(raster)
if width != mmw or height != mmh:
raise Exception(
f"Texture {self.img_name} has wrong size for mipmap level {mipmap_idx} \n"
+ f"MM{mipmap_idx} size = {width} x {height}, but should be = {mmw} x {mmh}"
)
divisor = divisor * 2
mipmap_idx += 1
if (self.main_width // divisor) < (16 >> self.main_depth):
break
self.extra_tiles = TILES_MIPMAPS
# read filter mode
if json_data.get("filter", False):
self.filter_mode = 2
else:
self.filter_mode = 0
# read tile combine mode
combine_str = json_data.get("combine", "Missing")
self.combine = aux_combine_modes_inv.get(combine_str)
if self.combine == None:
raise Exception(f"Texture {self.img_name} has invalid 'combine'")
self.is_variant = json_data.get("variant", False)
# write texture header and image raster/palettes to byte array
def add_bytes(self, tex_name: str, bytes: bytearray):
# form raw name and write to header
raw_name = tex_name[:4] + self.img_name + self.raw_ext
name_bytes = raw_name.encode("ascii")
bytes += name_bytes
# pad name out to 32 bytes
pad_len = 32 - len(name_bytes)
assert pad_len > 0
bytes += b"\0" * pad_len
# write header fields
bytes += struct.pack(
">HHHHBBBBBBBB",
self.aux_width,
self.main_width,
self.aux_height,
self.main_height,
self.is_variant,
self.extra_tiles,
self.combine,
self.pack_byte(self.aux_fmt, self.main_fmt),
self.pack_byte(self.aux_depth, self.main_depth),
self.pack_byte(self.aux_hwrap, self.main_hwrap),
self.pack_byte(self.aux_vwrap, self.main_vwrap),
self.filter_mode,
)
# write rasters and palettes
if self.extra_tiles == TILES_BASIC:
bytes += self.main_img
if self.main_fmt == FMT_CI:
bytes += self.main_pal
elif self.extra_tiles == TILES_MIPMAPS:
bytes += self.main_img
for mipmap in self.mipmaps:
bytes += mipmap
if self.main_fmt == FMT_CI:
bytes += self.main_pal
elif self.extra_tiles == TILES_SHARED_AUX:
bytes += self.main_img
bytes += self.aux_img
if self.main_fmt == FMT_CI:
bytes += self.main_pal
elif self.extra_tiles == TILES_INDEPENDENT_AUX:
bytes += self.main_img
if self.main_fmt == FMT_CI:
bytes += self.main_pal
bytes += self.aux_img
if self.aux_fmt == FMT_CI:
bytes += self.aux_pal
class TexArchive:
@staticmethod
def extract(bytes, tex_path: Path):
textures = []
texbuf = TexBuffer(bytes)
while texbuf.remaining() > 0:
img = TexImage()
img.from_bytes(texbuf)
textures.append(img)
tex_path.mkdir(parents=True, exist_ok=True)
out = []
for texture in textures:
texture.save_images(tex_path)
out.append(texture.get_json_entry())
json_out = json.dumps(out, sort_keys=False, indent=4)
json_fn = str(tex_path) + ".json"
with open(json_fn, "w") as f:
f.write(json_out)
@staticmethod
def build(out_path: Path, tex_path: Path, endian: str = "big"):
out_bytes = bytearray()
tex_name = os.path.basename(tex_path)
json_fn = str(tex_path) + ".json"
with open(json_fn, "r") as json_file:
json_str = json_file.read()
json_data = json.loads(json_str)
if len(json_data) > 128:
raise Exception(
f"Maximum number of textures (128) exceeded by {tex_name} ({len(json_data)})`"
)
for img_data in json_data:
img = TexImage()
img.from_json(tex_path, img_data)
img.add_bytes(tex_name, out_bytes)
with open(out_path, "wb") as out_bin:
out_bin.write(out_bytes)

View File

@ -106,7 +106,7 @@ dlabel entity_numShadows
dlabel gSpriteShadingProfile dlabel gSpriteShadingProfile
.space 4 .space 4
dlabel entity_area_specific_data_is_loaded dlabel isAreaSpecificEntityDataLoaded
.space 4 .space 4
dlabel entity_updateCounter dlabel entity_updateCounter
@ -178,7 +178,7 @@ dlabel D_801516FC
dlabel gMainGameState dlabel gMainGameState
.space 0x00000040 .space 0x00000040
dlabel gCurrentTileDescriptor dlabel gCurrentTextureHeader
.space 0x00000030 .space 0x00000030
dlabel wModelList dlabel wModelList
@ -268,7 +268,7 @@ dlabel texPannerAuxU
dlabel texPannerAuxV dlabel texPannerAuxV
.space 0x00000040 .space 0x00000040
dlabel mdl_nextTextureAddress dlabel TextureHeapPos
.space 4 .space 4
dlabel mdl_currentTransformGroupChildIndex dlabel mdl_currentTransformGroupChildIndex

View File

@ -401,7 +401,9 @@ segments:
vram: 0x8010dab0 vram: 0x8010dab0
subsegments: subsegments:
- [0xA4990, hasm, bss3] - [0xA4990, hasm, bss3]
- [0xA4990, c, a5dd0_len_114e0] - [0xA4990, c, entity]
- [auto, c, game_states]
- [auto, c, model]
- [0xB3140, c, B4580] - [0xB3140, c, B4580]
- [0xB5E70, c, entity_model] - [0xB5E70, c, entity_model]
- [0xB8370, c, worker] - [0xB8370, c, worker]
@ -419,7 +421,9 @@ segments:
- [0xDD6B0, c, sprite_shading] - [0xDD6B0, c, sprite_shading]
- [0xDE8C0, c, audio/sfx] - [0xDE8C0, c, audio/sfx]
- [0xDFAA0, c, audio/e0b30_len_b80] - [0xDFAA0, c, audio/e0b30_len_b80]
- [0xE0620, .data, a5dd0_len_114e0] - [0xE0620, .data, entity]
- [auto, .data, game_states]
- [auto, .data, model]
- [0xE18C0, .data, B4580] - [0xE18C0, .data, B4580]
- [0xE18D0, .data, entity_model] - [0xE18D0, .data, entity_model]
- [0xE18F0, .data, msg] - [0xE18F0, .data, msg]

View File

@ -176,7 +176,7 @@ game_mode_set_fpDrawAuxUI = 0x80117F94;
step_current_game_mode = 0x80118088; step_current_game_mode = 0x80118088;
state_render_backUI = 0x80118168; state_render_backUI = 0x80118168;
state_render_frontUI = 0x801181D4; state_render_frontUI = 0x801181D4;
load_model_textures = 0x8011AE34; mdl_load_all_textures = 0x8011AE34;
clear_model_data = 0x8011AF54; clear_model_data = 0x8011AF54;
init_model_data = 0x8011B1F8; init_model_data = 0x8011B1F8;
calculate_model_sizes = 0x8011B33C; calculate_model_sizes = 0x8011B33C;

View File

@ -1,70 +0,0 @@
.set noat /* allow manual use of $at */
.set noreorder /* don't insert nops after branches */
/* Generated by spimdisasm 1.11.1 */
glabel hos_05_AnimBowser_FlyOff
/* A9A8B4 80244774 27BDFFD0 */ addiu $sp, $sp, -0x30
/* A9A8B8 80244778 AFB00018 */ sw $s0, 0x18($sp)
/* A9A8BC 8024477C 0080802D */ daddu $s0, $a0, $zero
/* A9A8C0 80244780 AFB1001C */ sw $s1, 0x1C($sp)
/* A9A8C4 80244784 00A0882D */ daddu $s1, $a1, $zero
/* A9A8C8 80244788 24050007 */ addiu $a1, $zero, 0x7
/* A9A8CC 8024478C AFBF0028 */ sw $ra, 0x28($sp)
/* A9A8D0 80244790 AFB30024 */ sw $s3, 0x24($sp)
/* A9A8D4 80244794 0C0B42B0 */ jal resolve_npc
/* A9A8D8 80244798 AFB20020 */ sw $s2, 0x20($sp)
/* A9A8DC 8024479C 0200202D */ daddu $a0, $s0, $zero
/* A9A8E0 802447A0 24050008 */ addiu $a1, $zero, 0x8
/* A9A8E4 802447A4 0C0B42B0 */ jal resolve_npc
/* A9A8E8 802447A8 0040902D */ daddu $s2, $v0, $zero
/* A9A8EC 802447AC 12200004 */ beqz $s1, .LPAL_802447C0
/* A9A8F0 802447B0 0040982D */ daddu $s3, $v0, $zero
/* A9A8F4 802447B4 C640003C */ lwc1 $f0, 0x3C($s2)
/* A9A8F8 802447B8 3C018025 */ lui $at, %hi(hos_05_AnimBowser_FlyOff_InitialY)
/* A9A8FC 802447BC E420F314 */ swc1 $f0, %lo(hos_05_AnimBowser_FlyOff_InitialY)($at)
.LPAL_802447C0:
/* A9A900 802447C0 3C018025 */ lui $at, %hi(hos_05_AnimBowser_FlyOff_InitialY)
/* A9A904 802447C4 C420F314 */ lwc1 $f0, %lo(hos_05_AnimBowser_FlyOff_InitialY)($at)
/* A9A908 802447C8 24040003 */ addiu $a0, $zero, 0x3
/* A9A90C 802447CC 44050000 */ mfc1 $a1, $f0
/* A9A910 802447D0 3C0143FA */ lui $at, (0x43FA0000 >> 16)
/* A9A914 802447D4 44810000 */ mtc1 $at, $f0
/* A9A918 802447D8 44853000 */ mtc1 $a1, $f6
/* A9A91C 802447DC 3C108025 */ lui $s0, %hi(hos_05_AnimBowser_FlyOff_Time)
/* A9A920 802447E0 2610AE70 */ addiu $s0, $s0, %lo(hos_05_AnimBowser_FlyOff_Time)
/* A9A924 802447E4 46003180 */ add.s $f6, $f6, $f0
/* A9A928 802447E8 3C014220 */ lui $at, (0x42200000 >> 16)
/* A9A92C 802447EC 44811000 */ mtc1 $at, $f2
/* A9A930 802447F0 8E070000 */ lw $a3, 0x0($s0)
/* A9A934 802447F4 44063000 */ mfc1 $a2, $f6
/* A9A938 802447F8 2642003C */ addiu $v0, $s2, 0x3C
/* A9A93C 802447FC AFA20014 */ sw $v0, 0x14($sp)
/* A9A940 80244800 0C090439 */ jal interp_value_with_easing
/* A9A944 80244804 E7A20010 */ swc1 $f2, 0x10($sp)
/* A9A948 80244808 C640003C */ lwc1 $f0, 0x3C($s2)
/* A9A94C 8024480C 3C013F80 */ lui $at, (0x3F800000 >> 16)
/* A9A950 80244810 44811000 */ mtc1 $at, $f2
/* A9A954 80244814 E660003C */ swc1 $f0, 0x3C($s3)
/* A9A958 80244818 C6000000 */ lwc1 $f0, 0x0($s0)
/* A9A95C 8024481C C644003C */ lwc1 $f4, 0x3C($s2)
/* A9A960 80244820 46020000 */ add.s $f0, $f0, $f2
/* A9A964 80244824 E6440070 */ swc1 $f4, 0x70($s2)
/* A9A968 80244828 C662003C */ lwc1 $f2, 0x3C($s3)
/* A9A96C 8024482C 3C014204 */ lui $at, (0x42040000 >> 16)
/* A9A970 80244830 44812000 */ mtc1 $at, $f4
/* A9A974 80244834 24020001 */ addiu $v0, $zero, 0x1
/* A9A978 80244838 E6620070 */ swc1 $f2, 0x70($s3)
/* A9A97C 8024483C 4600203C */ c.lt.s $f4, $f0
/* A9A980 80244840 00000000 */ nop
/* A9A984 80244844 45010002 */ bc1t .LPAL_80244850
/* A9A988 80244848 E6000000 */ swc1 $f0, 0x0($s0)
/* A9A98C 8024484C 0000102D */ daddu $v0, $zero, $zero
.LPAL_80244850:
/* A9A990 80244850 8FBF0028 */ lw $ra, 0x28($sp)
/* A9A994 80244854 8FB30024 */ lw $s3, 0x24($sp)
/* A9A998 80244858 8FB20020 */ lw $s2, 0x20($sp)
/* A9A99C 8024485C 8FB1001C */ lw $s1, 0x1C($sp)
/* A9A9A0 80244860 8FB00018 */ lw $s0, 0x18($sp)
/* A9A9A4 80244864 03E00008 */ jr $ra
/* A9A9A8 80244868 27BD0030 */ addiu $sp, $sp, 0x30

View File

@ -1,57 +0,0 @@
.set noat /* allow manual use of $at */
.set noreorder /* don't insert nops after branches */
/* Generated by spimdisasm 1.11.1 */
glabel hos_05_AnimKammy_FlyOff
/* A9A9AC 8024486C 27BDFFD8 */ addiu $sp, $sp, -0x28
/* A9A9B0 80244870 AFB00018 */ sw $s0, 0x18($sp)
/* A9A9B4 80244874 00A0802D */ daddu $s0, $a1, $zero
/* A9A9B8 80244878 24050009 */ addiu $a1, $zero, 0x9
/* A9A9BC 8024487C AFBF0020 */ sw $ra, 0x20($sp)
/* A9A9C0 80244880 0C0B42B0 */ jal resolve_npc
/* A9A9C4 80244884 AFB1001C */ sw $s1, 0x1C($sp)
/* A9A9C8 80244888 12000004 */ beqz $s0, .LPAL_8024489C
/* A9A9CC 8024488C 0040882D */ daddu $s1, $v0, $zero
/* A9A9D0 80244890 C620003C */ lwc1 $f0, 0x3C($s1)
/* A9A9D4 80244894 3C018025 */ lui $at, %hi(hos_05_AnimKammy_FlyOff_InitialY)
/* A9A9D8 80244898 E420F318 */ swc1 $f0, %lo(hos_05_AnimKammy_FlyOff_InitialY)($at)
.LPAL_8024489C:
/* A9A9DC 8024489C 3C018025 */ lui $at, %hi(hos_05_AnimKammy_FlyOff_InitialY)
/* A9A9E0 802448A0 C420F318 */ lwc1 $f0, %lo(hos_05_AnimKammy_FlyOff_InitialY)($at)
/* A9A9E4 802448A4 24040003 */ addiu $a0, $zero, 0x3
/* A9A9E8 802448A8 44050000 */ mfc1 $a1, $f0
/* A9A9EC 802448AC 3C0143FA */ lui $at, (0x43FA0000 >> 16)
/* A9A9F0 802448B0 44810000 */ mtc1 $at, $f0
/* A9A9F4 802448B4 44853000 */ mtc1 $a1, $f6
/* A9A9F8 802448B8 3C108025 */ lui $s0, %hi(hos_05_AnimKammy_FlyOff_Time)
/* A9A9FC 802448BC 2610AE74 */ addiu $s0, $s0, %lo(hos_05_AnimKammy_FlyOff_Time)
/* A9AA00 802448C0 46003180 */ add.s $f6, $f6, $f0
/* A9AA04 802448C4 3C014220 */ lui $at, (0x42200000 >> 16)
/* A9AA08 802448C8 44811000 */ mtc1 $at, $f2
/* A9AA0C 802448CC 8E070000 */ lw $a3, 0x0($s0)
/* A9AA10 802448D0 44063000 */ mfc1 $a2, $f6
/* A9AA14 802448D4 2622003C */ addiu $v0, $s1, 0x3C
/* A9AA18 802448D8 AFA20014 */ sw $v0, 0x14($sp)
/* A9AA1C 802448DC 0C090439 */ jal interp_value_with_easing
/* A9AA20 802448E0 E7A20010 */ swc1 $f2, 0x10($sp)
/* A9AA24 802448E4 C6020000 */ lwc1 $f2, 0x0($s0)
/* A9AA28 802448E8 3C013F80 */ lui $at, (0x3F800000 >> 16)
/* A9AA2C 802448EC 44810000 */ mtc1 $at, $f0
/* A9AA30 802448F0 3C014204 */ lui $at, (0x42040000 >> 16)
/* A9AA34 802448F4 44812000 */ mtc1 $at, $f4
/* A9AA38 802448F8 46001080 */ add.s $f2, $f2, $f0
/* A9AA3C 802448FC C620003C */ lwc1 $f0, 0x3C($s1)
/* A9AA40 80244900 24020001 */ addiu $v0, $zero, 0x1
/* A9AA44 80244904 E6200070 */ swc1 $f0, 0x70($s1)
/* A9AA48 80244908 4602203C */ c.lt.s $f4, $f2
/* A9AA4C 8024490C 00000000 */ nop
/* A9AA50 80244910 45010002 */ bc1t .LPAL_8024491C
/* A9AA54 80244914 E6020000 */ swc1 $f2, 0x0($s0)
/* A9AA58 80244918 0000102D */ daddu $v0, $zero, $zero
.LPAL_8024491C:
/* A9AA5C 8024491C 8FBF0020 */ lw $ra, 0x20($sp)
/* A9AA60 80244920 8FB1001C */ lw $s1, 0x1C($sp)
/* A9AA64 80244924 8FB00018 */ lw $s0, 0x18($sp)
/* A9AA68 80244928 03E00008 */ jr $ra
/* A9AA6C 8024492C 27BD0028 */ addiu $sp, $sp, 0x28

View File

@ -106,7 +106,7 @@ dlabel entity_numShadows
dlabel gSpriteShadingProfile dlabel gSpriteShadingProfile
.space 4 .space 4
dlabel entity_area_specific_data_is_loaded dlabel isAreaSpecificEntityDataLoaded
.space 4 .space 4
dlabel entity_updateCounter dlabel entity_updateCounter
@ -178,7 +178,7 @@ dlabel D_801516FC
dlabel gMainGameState dlabel gMainGameState
.space 0x00000040 .space 0x00000040
dlabel gCurrentTileDescriptor dlabel gCurrentTextureHeader
.space 0x00000030 .space 0x00000030
dlabel wModelList dlabel wModelList
@ -268,7 +268,7 @@ dlabel texPannerAuxU
dlabel texPannerAuxV dlabel texPannerAuxV
.space 0x00000040 .space 0x00000040
dlabel mdl_nextTextureAddress dlabel TextureHeapPos
.space 4 .space 4
dlabel mdl_currentTransformGroupChildIndex dlabel mdl_currentTransformGroupChildIndex

View File

@ -824,7 +824,9 @@ segments:
follows_vram: engine1 follows_vram: engine1
subsegments: subsegments:
- [0xA5DD0, hasm, bss3] - [0xA5DD0, hasm, bss3]
- [0xA5DD0, c, a5dd0_len_114e0] - [0xA5DD0, c, entity]
- [0xA9290, c, game_states]
- [0xA9790, c, model]
- [0xB4580, c, B4580] - [0xB4580, c, B4580]
- [0xB72B0, c, entity_model] - [0xB72B0, c, entity_model]
- [0xB97B0, c, worker] - [0xB97B0, c, worker]
@ -842,7 +844,9 @@ segments:
- [0xDE740, c, sprite_shading] - [0xDE740, c, sprite_shading]
- [0xDF950, c, audio/sfx] - [0xDF950, c, audio/sfx]
- [0xE0B30, c, audio/e0b30_len_b80] - [0xE0B30, c, audio/e0b30_len_b80]
- [0xE16B0, .data, a5dd0_len_114e0] - [0xE16B0, .data, entity]
- [0xE16C0, .data, game_states]
- [0xE16C0, .data, model]
- [0xE2950, .data, B4580] - [0xE2950, .data, B4580]
- [0xE2960, .data, entity_model] - [0xE2960, .data, entity_model]
- [0xE2980, .data, msg] - [0xE2980, .data, msg]

View File

@ -3998,12 +3998,12 @@ state_do_unk = 0x80112EEC; // type:func rom:0xA95EC
state_render_backUI = 0x80112F58; // type:func rom:0xA9658 state_render_backUI = 0x80112F58; // type:func rom:0xA9658
state_render_frontUI = 0x80112FC4; // type:func rom:0xA96C4 state_render_frontUI = 0x80112FC4; // type:func rom:0xA96C4
appendGfx_model = 0x80113090; // type:func rom:0xA9790 appendGfx_model = 0x80113090; // type:func rom:0xA9790
func_80114B58 = 0x80114B58; // type:func rom:0xAB258 load_texture_impl = 0x80114B58; // type:func rom:0xAB258
load_tile_header = 0x80114D6C; // type:func rom:0xAB46C load_texture_by_name = 0x80114D6C; // type:func rom:0xAB46C
func_80115498 = 0x80115498; // type:func rom:0xABB98 load_texture_variants = 0x80115498; // type:func rom:0xABB98
get_model_property = 0x80115B0C; // type:func rom:0xAC20C get_model_property = 0x80115B0C; // type:func rom:0xAC20C
_load_model_textures = 0x80115B44; // type:func rom:0xAC244 load_next_model_textures = 0x80115B44; // type:func rom:0xAC244
load_model_textures = 0x80115C24; // type:func rom:0xAC324 mdl_load_all_textures = 0x80115C24; // type:func rom:0xAC324
mdl_get_child_count = 0x80115CA8; // type:func rom:0xAC3A8 mdl_get_child_count = 0x80115CA8; // type:func rom:0xAC3A8
clear_model_data = 0x80115D44; // type:func rom:0xAC444 clear_model_data = 0x80115D44; // type:func rom:0xAC444
init_model_data = 0x80115FE8; // type:func rom:0xAC6E8 init_model_data = 0x80115FE8; // type:func rom:0xAC6E8
@ -4016,7 +4016,7 @@ appendGfx_model_group = 0x80117C94; // type:func rom:0xAE394
func_80117D00 = 0x80117D00; // type:func rom:0xAE400 func_80117D00 = 0x80117D00; // type:func rom:0xAE400
render_transform_group_node = 0x80117E74; // type:func rom:0xAE574 render_transform_group_node = 0x80117E74; // type:func rom:0xAE574
render_transform_group = 0x8011800C; // type:func rom:0xAE70C render_transform_group = 0x8011800C; // type:func rom:0xAE70C
func_801180E8 = 0x801180E8; // type:func rom:0xAE7E8 make_texture_gfx = 0x801180E8; // type:func rom:0xAE7E8
get_model_from_list_index = 0x8011AD30; // type:func rom:0xB1430 get_model_from_list_index = 0x8011AD30; // type:func rom:0xB1430
load_data_for_models = 0x8011AD48; // type:func rom:0xB1448 load_data_for_models = 0x8011AD48; // type:func rom:0xB1448
load_model_transforms = 0x8011ADC8; // type:func rom:0xB14C8 load_model_transforms = 0x8011ADC8; // type:func rom:0xB14C8
@ -4493,7 +4493,7 @@ D_8014B0B8 = 0x8014B0B8; // rom:0xE17B8
D_8014B0BC = 0x8014B0BC; // rom:0xE17BC D_8014B0BC = 0x8014B0BC; // rom:0xE17BC
D_8014B400 = 0x8014B400; // rom:0xE1B00 D_8014B400 = 0x8014B400; // rom:0xE1B00
D_8014B404 = 0x8014B404; // rom:0xE1B04 D_8014B404 = 0x8014B404; // rom:0xE1B04
mdl_textureBaseAddress = 0x8014B748; // rom:0xE1E48 TextureHeapBase = 0x8014B748; // rom:0xE1E48
mdl_bgMultiplyColorA = 0x8014B74C; // rom:0xE1E4C mdl_bgMultiplyColorA = 0x8014B74C; // rom:0xE1E4C
mdl_bgMultiplyColorR = 0x8014B74D; // rom:0xE1E4D mdl_bgMultiplyColorR = 0x8014B74D; // rom:0xE1E4D
mdl_bgMultiplyColorG = 0x8014B74E; // rom:0xE1E4E mdl_bgMultiplyColorG = 0x8014B74E; // rom:0xE1E4E