590 lines
12 KiB
C
590 lines
12 KiB
C
#include <ultra64.h>
|
|
#include "constants.h"
|
|
#include "game/atan2f.h"
|
|
#include "game/tex.h"
|
|
#include "game/playermgr.h"
|
|
#include "game/bg.h"
|
|
#include "game/texdecompress.h"
|
|
#include "bss.h"
|
|
#include "lib/mtx.h"
|
|
#include "data.h"
|
|
#include "types.h"
|
|
|
|
s32 texGetMask(s32 value)
|
|
{
|
|
if (value < 2) {
|
|
return 0;
|
|
}
|
|
|
|
if (value < 3) {
|
|
return 1;
|
|
}
|
|
|
|
if (value < 5) {
|
|
return 2;
|
|
}
|
|
|
|
if (value < 9) {
|
|
return 3;
|
|
}
|
|
|
|
if (value < 17) {
|
|
return 4;
|
|
}
|
|
|
|
if (value < 33) {
|
|
return 5;
|
|
}
|
|
|
|
if (value < 65) {
|
|
return 6;
|
|
}
|
|
|
|
if (value < 129) {
|
|
return 7;
|
|
}
|
|
|
|
return 8;
|
|
}
|
|
|
|
s32 tex0f0b33f8(s32 width, s32 height, s32 lod)
|
|
{
|
|
s32 sum = 0;
|
|
|
|
if (lod <= 0) {
|
|
lod = 1;
|
|
}
|
|
|
|
while (lod > 0) {
|
|
sum += (width + 15) / 16 * 4 * height;
|
|
|
|
lod--;
|
|
|
|
if (width >= 2) {
|
|
width >>= 1;
|
|
}
|
|
|
|
if (height >= 2) {
|
|
height >>= 1;
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
s32 tex0f0b3468(s32 width, s32 height, s32 lod)
|
|
{
|
|
s32 sum = 0;
|
|
|
|
if (lod <= 0) {
|
|
lod = 1;
|
|
}
|
|
|
|
while (lod > 0) {
|
|
sum += (width + 7) / 8 * 4 * height;
|
|
|
|
lod--;
|
|
|
|
if (width >= 2) {
|
|
width >>= 1;
|
|
}
|
|
|
|
if (height >= 2) {
|
|
height >>= 1;
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
s32 tex0f0b34d8(s32 width, s32 height, s32 lod)
|
|
{
|
|
s32 sum = 0;
|
|
|
|
if (lod <= 0) {
|
|
lod = 1;
|
|
}
|
|
|
|
while (lod > 0) {
|
|
sum += (width + 3) / 4 * 4 * height;
|
|
|
|
lod--;
|
|
|
|
if (width >= 2) {
|
|
width >>= 1;
|
|
}
|
|
|
|
if (height >= 2) {
|
|
height >>= 1;
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
s32 tex0f0b3548(s32 width, s32 height, s32 lod)
|
|
{
|
|
s32 sum = 0;
|
|
|
|
if (lod <= 0) {
|
|
lod = 1;
|
|
}
|
|
|
|
while (lod > 0) {
|
|
sum += (width + 3) / 4 * 4 * height;
|
|
|
|
lod--;
|
|
|
|
if (width >= 2) {
|
|
width >>= 1;
|
|
}
|
|
|
|
if (height >= 2) {
|
|
height >>= 1;
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
void texSetRenderMode(Gfx **gdlptr, s32 arg1, s32 numcycles, s32 arg3)
|
|
{
|
|
Gfx *gdl = *gdlptr;
|
|
|
|
if (numcycles == 1) {
|
|
gDPPipeSync(gdl++);
|
|
gDPSetCycleType(gdl++, G_CYC_1CYCLE);
|
|
|
|
switch (arg1) {
|
|
default:
|
|
case 1:
|
|
if (arg3) {
|
|
if (arg3 >= 2) {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_ZB_OPA_DECAL, G_RM_AA_ZB_OPA_DECAL2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
|
|
}
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (arg3) {
|
|
if (arg3 >= 2) {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_DECAL, G_RM_AA_ZB_XLU_DECAL2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2);
|
|
}
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (arg3) {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_ZB_TEX_EDGE, G_RM_AA_ZB_TEX_EDGE2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_AA_TEX_EDGE, G_RM_AA_TEX_EDGE2);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (arg3) {
|
|
gDPSetRenderMode(gdl++, G_RM_ZB_CLD_SURF, G_RM_ZB_CLD_SURF2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_CLD_SURF, G_RM_CLD_SURF2);
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
gDPPipeSync(gdl++);
|
|
gDPSetCycleType(gdl++, G_CYC_2CYCLE);
|
|
|
|
switch (arg1) {
|
|
default:
|
|
case 1:
|
|
if (arg3) {
|
|
if (arg3 >= 2) {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_ZB_OPA_DECAL2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2);
|
|
}
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_OPA_SURF2);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (arg3) {
|
|
if (arg3 >= 2) {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_ZB_XLU_DECAL2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_ZB_XLU_SURF2);
|
|
}
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_XLU_SURF2);
|
|
}
|
|
break;
|
|
case 3:
|
|
if (arg3) {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_ZB_TEX_EDGE2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_AA_TEX_EDGE2);
|
|
}
|
|
break;
|
|
case 4:
|
|
if (arg3) {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_ZB_CLD_SURF2);
|
|
} else {
|
|
gDPSetRenderMode(gdl++, G_RM_PASS, G_RM_CLD_SURF2);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
*gdlptr = gdl;
|
|
}
|
|
|
|
void texLoadFromConfig(struct textureconfig *config)
|
|
{
|
|
if ((u32)config->texturenum < NUM_TEXTURES) {
|
|
texLoadFromConfigs(config, 1, NULL, 0);
|
|
}
|
|
}
|
|
|
|
void texSelect(Gfx **gdlptr, struct textureconfig *tconfig, u32 arg2, s32 arg3, u32 ulst, bool arg5, struct texpool *pool)
|
|
{
|
|
struct tex *tex;
|
|
Gfx *gdl;
|
|
s32 tile;
|
|
|
|
gdl = *gdlptr;
|
|
|
|
if (tconfig == NULL) {
|
|
texSetRenderMode(&gdl, arg2, 1, arg3);
|
|
|
|
if (arg3 >= 2) {
|
|
gSPTextureL(gdl++, 0xffff, 0xffff, 0, arg3, G_TX_RENDERTILE, G_ON);
|
|
} else {
|
|
gSPTextureL(gdl++, 0xffff, 0xffff, 0, 0, G_TX_RENDERTILE, G_ON);
|
|
}
|
|
|
|
gDPSetCombineMode(gdl++, G_CC_SHADE, G_CC_SHADE);
|
|
} else {
|
|
s32 width = tconfig->width;
|
|
s32 height = tconfig->height;
|
|
u16 *ptr;
|
|
s32 index;
|
|
u8 format;
|
|
u8 depth;
|
|
s32 lutmode;
|
|
s32 depth2;
|
|
s32 lrs;
|
|
s32 line;
|
|
u16 texturenum;
|
|
|
|
tex = NULL;
|
|
|
|
if ((u32)tconfig->texturenum < NUM_TEXTURES) {
|
|
texLoadFromConfigs(tconfig, 1, pool, 0);
|
|
}
|
|
|
|
if (tconfig->unk0b == 1) {
|
|
ptr = (u16 *)tconfig->textureptr;
|
|
texturenum = ((u16 *)PHYS_TO_K0(ptr))[-4];
|
|
|
|
// GCC has problems with this area because it seems to think that
|
|
// registers are 64 bits wide. To do the index < g_TexNumConfigs
|
|
// comparison, it shifts index left and adds to it repeatedly,
|
|
// creating a 64-bit value, then uses a neg before the comparison.
|
|
// When a tconfig is passed that is not in the preset configs list,
|
|
// the index < g_TexNumConfigs check passes when it shouldn't,
|
|
// causing a read from g_TexWords using an invalid index.
|
|
// Casting the pointers to integers makes gcc emit different code
|
|
// which works around this issue.
|
|
#ifdef __sgi
|
|
index = tconfig - g_TexWallhitConfigs;
|
|
#else
|
|
index = ((s32) tconfig - (s32) g_TexWallhitConfigs) / sizeof(struct textureconfig);
|
|
#endif
|
|
|
|
if (index >= 0 && index < g_TexNumConfigs) {
|
|
tex = g_TexWords[index];
|
|
}
|
|
|
|
if (tex == NULL) {
|
|
tex = texFindInPool(texturenum, pool);
|
|
|
|
if (index >= 0 && index < g_TexNumConfigs) {
|
|
g_TexWords[index] = tex;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tconfig->level == 0) {
|
|
if (tex) {
|
|
format = tex->gbiformat;
|
|
depth = tex->depth;
|
|
lutmode = tex->lutmodeindex << G_MDSFT_TEXTLUT;
|
|
} else {
|
|
format = tconfig->format;
|
|
depth = tconfig->depth;
|
|
}
|
|
|
|
switch (depth) {
|
|
default:
|
|
break;
|
|
case G_IM_SIZ_32b:
|
|
depth2 = G_IM_SIZ_32b;
|
|
lrs = tex0f0b3548(width, height, 1) - 1;
|
|
line = (width + 3) >> 2;
|
|
break;
|
|
case G_IM_SIZ_16b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b34d8(width, height, 1) - 1;
|
|
line = (width + 3) >> 2;
|
|
break;
|
|
case G_IM_SIZ_8b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b3468(width, height, 1) - 1;
|
|
line = (width + 7) >> 3;
|
|
break;
|
|
case G_IM_SIZ_4b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b33f8(width, height, 1) - 1;
|
|
line = (width + 15) >> 4;
|
|
break;
|
|
}
|
|
|
|
if (arg5) {
|
|
texSetRenderMode(&gdl, arg2, 1, arg3);
|
|
|
|
if (arg3 >= 2) {
|
|
gSPTextureL(gdl++, 0xffff, 0xffff, 0, arg3, G_TX_RENDERTILE, G_ON);
|
|
} else {
|
|
gSPTextureL(gdl++, 0xffff, 0xffff, 0, 0, G_TX_RENDERTILE, G_ON);
|
|
}
|
|
|
|
gDPSetTextureLOD(gdl++, G_TL_TILE);
|
|
|
|
switch (format) {
|
|
case G_IM_FMT_RGBA:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
case G_IM_FMT_IA:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
case G_IM_FMT_I:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEI, G_CC_MODULATEI);
|
|
break;
|
|
case G_IM_FMT_CI:
|
|
switch (lutmode) {
|
|
case G_TT_RGBA16:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
case G_TT_IA16:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
gDPSetTextureImage(gdl++, format, depth2, 1, tconfig->textureptr);
|
|
|
|
if (depth2 == G_IM_SIZ_16b) {
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, G_TX_LOADTILE, 0, 0, lrs, 0);
|
|
} else {
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, depth2, 0, 0x0000, 5, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, 5, 0, 0, lrs, 0);
|
|
}
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
if (format == G_IM_FMT_CI) {
|
|
u32 a3 = lrs + 1;
|
|
u32 t0 = (0x3ff - tex->unk0a) < a3 ? (0x3ff - tex->unk0a) : 0;
|
|
|
|
a3 -= t0;
|
|
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadTLUT06(gdl++, a3, t0, tex->unk0a + a3, t0);
|
|
gDPPipeSync(gdl++);
|
|
|
|
if (arg5) {
|
|
gDPSetTextureLUT(gdl++, lutmode);
|
|
}
|
|
} else {
|
|
if (arg5) {
|
|
gDPSetTextureLUT(gdl++, G_TT_NONE);
|
|
}
|
|
}
|
|
|
|
if (arg5) {
|
|
gDPSetTile(gdl++, format, depth, line, 0x0000, G_TX_RENDERTILE, 0,
|
|
tconfig->t, texGetMask(height), G_TX_NOLOD,
|
|
tconfig->s, texGetMask(width), G_TX_NOLOD);
|
|
|
|
gDPSetTileSize(gdl++, G_TX_RENDERTILE, ulst, ulst, ((width - 1) << 2) + ulst, ((height - 1) << 2) + ulst);
|
|
}
|
|
} else {
|
|
s32 tmem = 0;
|
|
s32 lod = tconfig->level;
|
|
u8 format;
|
|
u8 depth;
|
|
s32 lutmode;
|
|
s32 depth2;
|
|
s32 lrs;
|
|
|
|
if (lod > 6) {
|
|
lod = 6;
|
|
}
|
|
|
|
if (tex) {
|
|
format = tex->gbiformat;
|
|
depth = tex->depth;
|
|
lutmode = tex->lutmodeindex << G_MDSFT_TEXTLUT;
|
|
} else {
|
|
format = tconfig->format;
|
|
depth = tconfig->depth;
|
|
}
|
|
|
|
if (tex && tex->hasloddata) {
|
|
tex0f173e50(tex, &depth2, &lrs);
|
|
} else {
|
|
switch (depth) {
|
|
case G_IM_SIZ_32b:
|
|
depth2 = G_IM_SIZ_32b;
|
|
lrs = tex0f0b3548(width, height, lod) - 1;
|
|
break;
|
|
case G_IM_SIZ_16b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b34d8(width, height, lod) - 1;
|
|
break;
|
|
case G_IM_SIZ_8b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b3468(width, height, lod) - 1;
|
|
break;
|
|
case G_IM_SIZ_4b:
|
|
depth2 = G_IM_SIZ_16b;
|
|
lrs = tex0f0b33f8(width, height, lod) - 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (arg5) {
|
|
texSetRenderMode(&gdl, arg2, 2, arg3);
|
|
|
|
if (arg3 >= 2) {
|
|
gSPTextureL(gdl++, 0xffff, 0xffff, lod - 1, arg3, G_TX_RENDERTILE, G_ON);
|
|
} else {
|
|
gSPTexture(gdl++, 0xffff, 0xffff, lod - 1, G_TX_RENDERTILE, G_ON);
|
|
}
|
|
|
|
gDPSetTextureLOD(gdl++, G_TL_LOD);
|
|
|
|
switch (format) {
|
|
case G_IM_FMT_RGBA:
|
|
gDPSetCombineMode(gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
|
|
break;
|
|
case G_IM_FMT_IA:
|
|
gDPSetCombineMode(gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
|
|
break;
|
|
case G_IM_FMT_I:
|
|
gDPSetCombineMode(gdl++, G_CC_TRILERP, G_CC_MODULATEI2);
|
|
break;
|
|
case G_IM_FMT_CI:
|
|
switch (lutmode) {
|
|
case G_TT_RGBA16:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
case G_TT_IA16:
|
|
gDPSetCombineMode(gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
gDPSetTextureImage(gdl++, format, depth2, 1, tconfig->textureptr);
|
|
|
|
if (depth2 == G_IM_SIZ_16b) {
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, G_TX_LOADTILE, 0, 0, lrs, 0);
|
|
} else {
|
|
gDPSetTile(gdl++, G_IM_FMT_RGBA, depth2, 0, 0x0000, 5, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadBlock(gdl++, 5, 0, 0, lrs, 0);
|
|
}
|
|
|
|
gDPPipeSync(gdl++);
|
|
|
|
if (format == G_IM_FMT_CI) {
|
|
u32 a2 = lrs + 1;
|
|
u32 a3 = (0x3ff - tex->unk0a) < a2 ? (0x3ff - tex->unk0a) : 0;
|
|
|
|
a2 -= a3;
|
|
|
|
gDPLoadSync(gdl++);
|
|
gDPLoadTLUT06(gdl++, a2, a3, tex->unk0a + a2, a3);
|
|
gDPPipeSync(gdl++);
|
|
|
|
if (arg5) {
|
|
gDPSetTextureLUT(gdl++, lutmode);
|
|
}
|
|
} else {
|
|
if (arg5) {
|
|
gDPSetTextureLUT(gdl++, G_TT_NONE);
|
|
}
|
|
}
|
|
|
|
for (tile = 0; tile < lod; tile++) {
|
|
s32 line;
|
|
|
|
if (tile > 0) {
|
|
if (tex && tex->hasloddata) {
|
|
width = texGetWidthAtLod(tex, tile);
|
|
height = texGetHeightAtLod(tex, tile);
|
|
} else {
|
|
if (width >= 2) {
|
|
width >>= 1;
|
|
}
|
|
|
|
if (height >= 2) {
|
|
height >>= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (depth) {
|
|
default:
|
|
break;
|
|
case G_IM_SIZ_32b:
|
|
line = (width + 3) / 4;
|
|
break;
|
|
case G_IM_SIZ_16b:
|
|
line = (width + 3) / 4;
|
|
break;
|
|
case G_IM_SIZ_8b:
|
|
line = (width + 7) / 8;
|
|
break;
|
|
case G_IM_SIZ_4b:
|
|
line = (width + 15) / 16;
|
|
break;
|
|
}
|
|
|
|
if (arg5) {
|
|
gDPSetTile(gdl++, format, depth, line, tmem, tile, 0,
|
|
tconfig->t, texGetMask(height), tile,
|
|
tconfig->s, texGetMask(width), tile);
|
|
|
|
gDPSetTileSize(gdl++, tile, ulst, ulst, ((width - 1) << 2) + ulst, ((height - 1) << 2) + ulst);
|
|
}
|
|
|
|
tmem += line * height;
|
|
}
|
|
}
|
|
}
|
|
|
|
*gdlptr = gdl;
|
|
}
|