diff --git a/include/PR/gbi.h b/include/PR/gbi.h index 8d9bd76cd7..1c16bb5823 100644 --- a/include/PR/gbi.h +++ b/include/PR/gbi.h @@ -1259,6 +1259,16 @@ typedef struct { char pad3; } Light_t; +// Added for Zelda decomp +typedef struct { + unsigned char col[3]; /* diffuse light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of diffuse light value (rgba) */ + char pad2; + signed short pos[3]; + char unkE; +} LightPos_t; + typedef struct { unsigned char col[3]; /* ambient light value (rgba) */ char pad1; @@ -1272,6 +1282,7 @@ typedef struct { typedef union { Light_t l; + LightPos_t lPos; long long int force_structure_alignment[2]; } Light; @@ -1629,13 +1640,13 @@ typedef union { } #define gDma1p(pkt, c, s, l, p) \ -{ \ +_DW({ \ Gfx *_g = (Gfx *)(pkt); \ \ _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \ _SHIFTL((l), 0, 16)); \ _g->words.w1 = (unsigned int)(s); \ -} +}) #define gsDma1p(c, s, l, p) \ { \ @@ -1645,12 +1656,12 @@ typedef union { } #define gDma2p(pkt, c, adrs, len, idx, ofs) \ -{ \ +_DW({ \ Gfx *_g = (Gfx *)(pkt); \ _g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ _SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)); \ _g->words.w1 = (unsigned int)(adrs); \ -} +}) #define gsDma2p(c, adrs, len, idx, ofs) \ { \ (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \ @@ -1663,7 +1674,7 @@ typedef union { #ifdef F3DEX_GBI_2 # define gSPMatrix(pkt, m, p) \ - _DW(gDma2p((pkt),G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0)) + gDma2p((pkt),G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0) # define gsSPMatrix(m, p) \ gsDma2p( G_MTX,(m),sizeof(Mtx),(p)^G_MTX_PUSH,0) #else /* F3DEX_GBI_2 */ @@ -1727,7 +1738,7 @@ typedef union { gsDma1p( G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT) #endif /* F3DEX_GBI_2 */ -#define gSPDisplayList(pkt,dl) _DW(gDma1p(pkt,G_DL,dl,0,G_DL_PUSH)) +#define gSPDisplayList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_PUSH) #define gsSPDisplayList( dl) gsDma1p( G_DL,dl,0,G_DL_PUSH) #define gSPBranchList(pkt,dl) gDma1p(pkt,G_DL,dl,0,G_DL_NOPUSH) @@ -2790,12 +2801,12 @@ typedef union { #ifdef F3DEX_GBI_2 #define gSPSetOtherMode(pkt, cmd, sft, len, data) \ -{ \ +_DW({ \ Gfx *_g = (Gfx *)(pkt); \ _g->words.w0 = (_SHIFTL(cmd,24,8)|_SHIFTL(32-(sft)-(len),8,8)| \ _SHIFTL((len)-1,0,8)); \ _g->words.w1 = (unsigned int)(data); \ -} +}) #define gsSPSetOtherMode(cmd, sft, len, data) \ { \ diff --git a/include/segment.h b/include/segment.h index 4a892ad033..aa5ca2a023 100644 --- a/include/segment.h +++ b/include/segment.h @@ -3,6 +3,8 @@ #include +extern UNK_TYPE D_04029CB0; // D_04029CB0 +extern UNK_TYPE D_04029CF0; // D_04029CF0 extern UNK_TYPE D_060005D0; // D_060005D0 extern UNK_TYPE D_06001100; // D_06001100 extern UNK_TYPE D_06001228; // D_06001228 diff --git a/include/structs.h b/include/structs.h index 5632c54aeb..3e82d735c4 100644 --- a/include/structs.h +++ b/include/structs.h @@ -432,8 +432,7 @@ typedef struct { /* 0x00 */ u8 enablePosLights; /* 0x01 */ u8 numLights; /* 0x02 */ UNK_TYPE1 pad2[6]; -/* 0x08 */ Ambient ambient; -/* 0x10 */ Light lights[7]; +/* 0x08 */ Lights7 lights; } LightMapper; typedef struct { diff --git a/linker_scripts/code_script.txt b/linker_scripts/code_script.txt index dd115c683a..6d535e226f 100644 --- a/linker_scripts/code_script.txt +++ b/linker_scripts/code_script.txt @@ -243,7 +243,7 @@ SECTIONS build/asm/z_kankyo.o(.text) build/src/code/z_lib.o(.text) build/asm/z_lifemeter.o(.text) - build/asm/z_lights.o(.text) + build/src/code/z_lights.o(.text) build/asm/code_0x80102C60.o(.text) build/asm/z_map_disp.o(.text) build/asm/z_map_data.o(.text) diff --git a/linker_scripts/object_script.txt b/linker_scripts/object_script.txt index 26d1dd0d45..e633f89bcf 100644 --- a/linker_scripts/object_script.txt +++ b/linker_scripts/object_script.txt @@ -1,3 +1,5 @@ +D_04029CB0 = 0x04029CB0; +D_04029CF0 = 0x04029CF0; D_060005D0 = 0x060005D0; D_06001100 = 0x06001100; D_06001228 = 0x06001228; diff --git a/src/code/z_lights.c b/src/code/z_lights.c new file mode 100644 index 0000000000..620edb5066 --- /dev/null +++ b/src/code/z_lights.c @@ -0,0 +1,448 @@ +#include +#include + +#pragma intrinsic (sqrtf) +extern float fabsf(float); +#pragma intrinsic (fabsf) + +void Lights_InitPositionalLight(LightInfoPositional* info, s16 posX, s16 posY, s16 posZ, u8 red, u8 green, u8 blue, s16 radius, u32 type) { + info->type = type; + info->params.posX = posX; + info->params.posY = posY; + info->params.posZ = posZ; + Lights_SetPositionalLightColorAndRadius(info, red, green, blue, radius); +} + +void Lights_InitType0PositionalLight(LightInfoPositional* info, s16 posX, s16 posY, s16 posZ, u8 red, u8 green, u8 blue, s16 radius) { + Lights_InitPositionalLight(info, posX, posY, posZ, red, green, blue, radius, 0); +} + +void Lights_InitType2PositionalLight(LightInfoPositional* info, s16 posX, s16 posY, s16 posZ, u8 red, u8 green, u8 blue, s16 radius) { + Lights_InitPositionalLight(info, posX, posY, posZ, red, green, blue, radius, 2); +} + +void Lights_SetPositionalLightColorAndRadius(LightInfoPositional* info, u8 red, u8 green, u8 blue, s16 radius) { + info->params.red = red; + info->params.green = green; + info->params.blue = blue; + info->params.radius = radius; +} + +void Lights_SetPositionalLightPosition(LightInfoPositional* info, s16 posX, s16 posY, s16 posZ) { + info->params.posX = posX; + info->params.posY = posY; + info->params.posZ = posZ; +} + +void Lights_InitDirectional(LightInfoDirectional* info, s8 dirX, s8 dirY, s8 dirZ, u8 red, u8 green, u8 blue) { + info->type = 1; + info->params.dirX = dirX; + info->params.dirY = dirY; + info->params.dirZ = dirZ; + info->params.red = red; + info->params.green = green; + info->params.blue = blue; +} + +void Lights_MapperInit(LightMapper* mapper, u8 red, u8 green, u8 blue) { + mapper->lights.a.l.colc[0] = red; + mapper->lights.a.l.col[0] = red; + mapper->lights.a.l.colc[1] = green; + mapper->lights.a.l.col[1] = green; + mapper->lights.a.l.colc[2] = blue; + mapper->lights.a.l.col[2] = blue; + mapper->numLights = 0; +} + +// XXX regalloc +#ifdef NONMATCHING +void Lights_UploadLights(LightMapper* mapper, GraphicsContext* gCtxt) { + Light* l; + s32 i; + + gSPNumLights(gCtxt->polyOpa.append++, mapper->numLights); + gSPNumLights(gCtxt->polyXlu.append++, mapper->numLights); + + l = &mapper->lights.l[0]; + + for (i = 0; i < mapper->numLights;) { + gSPLight(gCtxt->polyOpa.append++, l, ++i); + gSPLight(gCtxt->polyXlu.append++, l++, i); + } + + gSPLight(gCtxt->polyOpa.append++, &mapper->lights.a, ++i); + gSPLight(gCtxt->polyXlu.append++, &mapper->lights.a, i); +} +#else +GLOBAL_ASM("asm/nonmatching/z_lights/Lights_UploadLights.asm") +#endif + +Light* Lights_MapperGetNextFreeSlot(LightMapper* mapper) { + if (6 < mapper->numLights) { + return NULL; + } + return &mapper->lights.l[mapper->numLights++]; +} + +// XXX regalloc, some reorderings +#ifdef NONMATCHING +void Lights_MapPositionalWithReference(LightMapper* mapper, LightInfoPositionalParams* params, Vector3f* pos) { + f32 xDiff; + f32 yDiff; + f32 zDiff; + f32 dist; + f32 radiusF; + Light* light; + + if (pos == NULL) return; + + if (params->radius < 1) return; + + xDiff = params->posX - pos->x; + yDiff = params->posY - pos->y; + zDiff = params->posZ - pos->z; + radiusF = params->radius; + dist = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff; + + if (radiusF * radiusF > dist) { + light = Lights_MapperGetNextFreeSlot(mapper); + if (light == NULL) return; + + dist = sqrtf(dist); + + light->l.colc[0] = light->l.col[0] = params->red * (1 - (dist / radiusF) * (dist / radiusF)); + light->l.colc[1] = light->l.col[1] = params->green * (1 - (dist / radiusF) * (dist / radiusF)); + light->l.colc[2] = light->l.col[2] = params->blue * (1 - (dist / radiusF) * (dist / radiusF)); + + if (dist < 1) { + dist = 120; + } else { + dist = 120 / dist; + } + + xDiff *= dist; + yDiff *= dist; + zDiff *= dist; + + light->l.dir[0] = xDiff; + light->l.dir[1] = yDiff; + light->l.dir[2] = zDiff; + } +} +#else +GLOBAL_ASM("asm/nonmatching/z_lights/Lights_MapPositionalWithReference.asm") +#endif + +// This function matches, but uses .rodata. We don't have a good way to match partial .rodata for a file yet. +#ifdef NONMATCHING +void Lights_MapPositional(LightMapper* mapper, LightInfoPositionalParams* params, GlobalContext* ctxt) { + Light* light; + f32 radiusF = params->radius; + Vector3f posF; + Vector3f adjustedPos; + u32 pad; + if (radiusF > 0) { + posF.x = params->posX; + posF.y = params->posY; + posF.z = params->posZ; + Matrix_MultiplyByVectorXYZ(&ctxt->unk187B0,&posF,&adjustedPos); + if ((adjustedPos.z > -radiusF) && + (600 + radiusF > adjustedPos.z) && + (400 > fabsf(adjustedPos.x) - radiusF) && + (400 > fabsf(adjustedPos.y) - radiusF)) { + light = Lights_MapperGetNextFreeSlot(mapper); + if (light != NULL) { + radiusF = 4500000.0f / (radiusF * radiusF); + if (radiusF > 255) { + radiusF = 255; + } else if (20 > radiusF) { + radiusF = 20; + } + + light->lPos.col[0] = params->red; + light->lPos.colc[0] = light->lPos.col[0]; + light->lPos.col[1] = params->green; + light->lPos.colc[1] = light->lPos.col[1]; + light->lPos.col[2] = params->blue; + light->lPos.colc[2] = light->lPos.col[2]; + light->lPos.pos[0] = params->posX; + light->lPos.pos[1] = params->posY; + light->lPos.pos[2] = params->posZ; + light->lPos.pad1 = 0x8; + light->lPos.pad2 = 0xFF; + light->lPos.unkE = (s8)radiusF; + } + } + } +} +#else +GLOBAL_ASM("asm/nonmatching/z_lights/Lights_MapPositional.asm") +#endif + +void Lights_MapDirectional(LightMapper* mapper, LightInfoDirectionalParams* params, GlobalContext* ctxt) { + Light* light = Lights_MapperGetNextFreeSlot(mapper); + + if (light != NULL) { + light->l.col[0] = params->red; + light->l.colc[0] = light->l.col[0]; + light->l.col[1] = params->green; + light->l.colc[1] = light->l.col[1]; + light->l.col[2] = params->blue; + light->l.colc[2] = light->l.col[2]; + light->l.dir[0] = params->dirX; + light->l.dir[1] = params->dirY; + light->l.dir[2] = params->dirZ; + light->l.pad1 = 0; + } +} + +void Lights_MapLights(LightMapper* mapper, z_Light* lights, Vector3f* refPos, GlobalContext* ctxt) { + if (lights != NULL) { + if ((refPos == NULL) && (mapper->enablePosLights == 1)) { + do { + lightPositionalMapFuncs[lights->info->type](mapper, &lights->info->params, ctxt); + lights = lights->next; + } while (lights != NULL); + } else { + do { + lightDirectionalMapFuncs[lights->info->type](mapper, &lights->info->params, refPos); + lights = lights->next; + } while (lights != NULL); + } + } +} + +z_Light* Lights_FindFreeSlot(void) { + z_Light* ret; + + if (0x1f < lightsList.numOccupied) { + return NULL; + } + + ret = &lightsList.lights[lightsList.nextFree]; + while (ret->info != NULL) { + lightsList.nextFree++; + if (lightsList.nextFree < 0x20) { + ret++; + } else { + lightsList.nextFree = 0; + ret = &lightsList.lights[0]; + } + } + + lightsList.numOccupied++; + return ret; +} + +void Lights_Free(z_Light* light) { + if (light != NULL) { + lightsList.numOccupied--; + light->info = NULL; + lightsList.nextFree = (light - lightsList.lights) / (s32)sizeof(z_Light); //! @bug Due to pointer arithmetic, the division is unnecessary + } +} + +void Lights_Init(GlobalContext* ctxt, LightingContext* lCtxt) { + Lights_ClearHead(ctxt, lCtxt); + Lights_SetAmbientColor(lCtxt, 80, 80, 80); + func_80102544(lCtxt, 0, 0, 0, 0x3e4, 0x3200); + bzero(&lightsList, sizeof(LightsList)); +} + +void Lights_SetAmbientColor(LightingContext* lCtxt, u8 red, u8 green, u8 blue) { + lCtxt->ambientRed = red; + lCtxt->ambientGreen = green; + lCtxt->ambientBlue = blue; +} + +void func_80102544(LightingContext* lCtxt, u8 a1, u8 a2, u8 a3, s16 sp12, s16 sp16) { + lCtxt->unk7 = a1; + lCtxt->unk8 = a2; + lCtxt->unk9 = a3; + lCtxt->unkA = sp12; + lCtxt->unkC = sp16; +} + +LightMapper* Lights_CreateMapper(LightingContext* lCtxt, GraphicsContext* gCtxt) { + return Lights_MapperAllocateAndInit(gCtxt, lCtxt->ambientRed, lCtxt->ambientGreen, lCtxt->ambientBlue); +} + +void Lights_ClearHead(GlobalContext* ctxt, LightingContext* lCtxt) { + lCtxt->lightsHead = NULL; +} + +void Lights_RemoveAll(GlobalContext* ctxt, LightingContext* lCtxt) { + while (lCtxt->lightsHead != NULL) { + Lights_Remove(ctxt, lCtxt, lCtxt->lightsHead); + lCtxt->lightsHead = lCtxt->lightsHead->next; + } +} + +z_Light* Lights_Insert(GlobalContext* ctxt, LightingContext* lCtxt, LightInfo* info) { + z_Light* light; + + light = Lights_FindFreeSlot(); + if (light != NULL) { + light->info = info; + light->prev = NULL; + light->next = lCtxt->lightsHead; + + if (lCtxt->lightsHead != NULL) { + lCtxt->lightsHead->prev = light; + } + + lCtxt->lightsHead = light; + } + + return light; +} + +void Lights_Remove(GlobalContext* ctxt, LightingContext* lCtxt, z_Light* light) { + if (light != NULL) { + if (light->prev != NULL) { + light->prev->next = light->next; + } else { + lCtxt->lightsHead = light->next; + } + + if (light->next != NULL) { + light->next->prev = light->prev; + } + + Lights_Free(light); + } +} + +LightMapper* func_801026E8(GraphicsContext* gCtxt, u8 ambientRed, u8 ambientGreen, u8 ambientBlue, u8 numLights, u8 red, u8 green, u8 blue, s8 dirX, s8 dirY, s8 dirZ) { + LightMapper* mapper; + s32 i; + + // TODO allocation should be a macro + mapper = (LightMapper *)((int)gCtxt->polyOpa.appendEnd - sizeof(LightMapper)); + gCtxt->polyOpa.appendEnd = (void*)mapper; + + mapper->lights.a.l.col[0] = mapper->lights.a.l.colc[0] = ambientRed; + mapper->lights.a.l.col[1] = mapper->lights.a.l.colc[1] = ambientGreen; + mapper->lights.a.l.col[2] = mapper->lights.a.l.colc[2] = ambientBlue; + mapper->enablePosLights = 0; + mapper->numLights = numLights; + + for (i = 0; i < numLights; i++) { + mapper->lights.l[i].l.col[0] = mapper->lights.l[i].l.colc[0] = red; + mapper->lights.l[i].l.col[1] = mapper->lights.l[i].l.colc[1] = green; + mapper->lights.l[i].l.col[2] = mapper->lights.l[i].l.colc[2] = blue; + mapper->lights.l[i].l.dir[0] = dirX; + mapper->lights.l[i].l.dir[1] = dirY; + mapper->lights.l[i].l.dir[2] = dirZ; + } + + Lights_UploadLights(mapper,gCtxt); + + return mapper; +} + +LightMapper* Lights_MapperAllocateAndInit(GraphicsContext* gCtxt, u8 red, u8 green, u8 blue) { + LightMapper* mapper; + + // TODO allocation should be a macro + mapper = (LightMapper *)((int)gCtxt->polyOpa.appendEnd - sizeof(LightMapper)); + gCtxt->polyOpa.appendEnd = (void*)mapper; + + mapper->lights.a.l.col[0] = red; + mapper->lights.a.l.colc[0] = red; + mapper->lights.a.l.col[1] = green; + mapper->lights.a.l.colc[1] = green; + mapper->lights.a.l.col[2] = blue; + mapper->lights.a.l.colc[2] = blue; + mapper->enablePosLights = 0; + mapper->numLights = 0; + + return mapper; +} + +// XXX regalloc +#ifdef NONMATCHING +void func_80102880(GlobalContext* ctxt) { + z_Light* light = ctxt->lightsContext.lightsHead; + LightInfoPositionalParams* params; + Vector3f local_14; + Vector3f local_20; + f32 local_24; + f32 fVar4; + s32 s2; + u32 pad[2]; + + while (light != NULL) { + if (light->info->type == 2) { + params = (LightInfoPositionalParams*)&light->info->params; + local_14.x = params->posX; + local_14.y = params->posY; + local_14.z = params->posZ; + func_800B4EDC(ctxt, &local_14, &local_20, &local_24); + + params->unk9 = 0; + + if ((local_20.z > 1) && + (fabsf(local_20.x * local_24) < 1) && + (fabsf(local_20.y * local_24) < 1)) { + fVar4 = local_20.z * local_24; + s2 = (s32)(fVar4 * 16352) + 16352; + if (s2 < func_80178A94(local_20.x * local_24 * 160 + 160, local_20.y * local_24 * -120 + 120)) { + params->unk9 = 1; + } + } + } + + light = light->next; + } +} +#else +GLOBAL_ASM("asm/nonmatching/z_lights/func_80102880.asm") +#endif + +// XXX regalloc +#ifdef NONMATCHING +void func_80102A64(GlobalContext* ctxt) { + Gfx* dl; + LightInfoPositionalParams* params; + f32 scale; + GraphicsContext* gCtxt; + z_Light* light = ctxt->lightsContext.lightsHead; + + if (light != NULL) { + gCtxt = ctxt->common.gCtxt; + dl = func_8012C7FC(gCtxt->polyXlu.append); + + gSPSetOtherMode(dl++, G_SETOTHERMODE_H, 4, 4, 0x00000080); //! This doesn't resolve to any of the macros in gdi.h + + gDPSetCombineLERP(dl++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, + 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0); + + gSPDisplayList(dl++, &D_04029CB0); + + do { + if (light->info->type == 2) { + params = (LightInfoPositionalParams*)&light->info->params; + if (params->unk9 != 0) { + scale = (f32)params->radius * (f32)params->radius * 2e-6f; + + gDPSetPrimColor(dl++, 0, 0, params->red, params->green, params->blue, 50); + + SysMatrix_InsertTranslation(params->posX, params->posY, params->posZ, 0); + SysMatrix_InsertScale(scale,scale,scale,1); + + gSPMatrix(dl++, SysMatrix_AppendStateToPolyOpaDisp((ctxt->common).gCtxt), G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + gSPDisplayList(dl++, &D_04029CF0); + } + } + + light = light->next; + } while (light != NULL); + + gCtxt->polyXlu.append = dl; + } +} +#else +GLOBAL_ASM("asm/nonmatching/z_lights/func_80102A64.asm") +#endif diff --git a/tables/object_addr_variables.py b/tables/object_addr_variables.py index 87667065c1..82a037a010 100644 --- a/tables/object_addr_variables.py +++ b/tables/object_addr_variables.py @@ -1,5 +1,7 @@ # Follows the format of Address:(Name, Type, Array Info) { + 0x04029CB0:("D_04029CB0","UNK_TYPE",""), + 0x04029CF0:("D_04029CF0","UNK_TYPE",""), 0x060005D0:("D_060005D0","UNK_TYPE",""), 0x06001100:("D_06001100","UNK_TYPE",""), 0x06001228:("D_06001228","UNK_TYPE",""),