mirror of https://github.com/zeldaret/tp.git
306 lines
8.4 KiB
C
306 lines
8.4 KiB
C
/**
|
|
* GXLight.c
|
|
* Description:
|
|
*/
|
|
|
|
#include "dolphin/gx/GXLight.h"
|
|
#include "dolphin/gx.h"
|
|
#include "math.h"
|
|
|
|
/* 8035D630-8035D64C 357F70 001C+00 0/0 1/1 0/0 .text GXInitLightAttn */
|
|
void GXInitLightAttn(GXLightObj* obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) {
|
|
obj->a0 = a0;
|
|
obj->a1 = a1;
|
|
obj->a2 = a2;
|
|
obj->k0 = k0;
|
|
obj->k1 = k1;
|
|
obj->k2 = k2;
|
|
}
|
|
|
|
/* 8035D64C-8035D7DC 357F8C 0190+00 1/0 2/2 0/0 .text GXInitLightSpot */
|
|
void GXInitLightSpot(GXLightObj* obj, f32 cutoff, GXSpotFn spot_fn) {
|
|
f32 rad;
|
|
f32 a, b, c, d;
|
|
|
|
if (cutoff <= 0.0f || cutoff > 90.0f) {
|
|
spot_fn = GX_SP_OFF;
|
|
}
|
|
|
|
rad = cosf((3.1415927f * cutoff) / 180.0f);
|
|
|
|
switch (spot_fn) {
|
|
case GX_SP_FLAT:
|
|
a = -1000.0f * rad;
|
|
b = 1000.0f;
|
|
c = 0.0f;
|
|
break;
|
|
case GX_SP_COS:
|
|
b = 1.0f / (1.0f - rad);
|
|
a = -rad * b;
|
|
c = 0.0f;
|
|
break;
|
|
case GX_SP_COS2:
|
|
c = 1.0f / (1.0f - rad);
|
|
a = 0.0f;
|
|
b = -rad * c;
|
|
break;
|
|
case GX_SP_SHARP:
|
|
d = 1.0f / ((1.0f - rad) * (1.0f - rad));
|
|
a = (rad * (rad - 2.0f)) * d;
|
|
b = 2.0f * d;
|
|
c = -d;
|
|
break;
|
|
case GX_SP_RING1:
|
|
d = 1.0f / ((1.0f - rad) * (1.0f - rad));
|
|
c = -4.0f * d;
|
|
a = c * rad;
|
|
b = 4.0f * (1.0f + rad) * d;
|
|
break;
|
|
case GX_SP_RING2:
|
|
d = 1.0f / ((1.0f - rad) * (1.0f - rad));
|
|
a = 1.0f - 2.0f * rad * rad * d;
|
|
b = 4.0f * rad * d;
|
|
c = -2.0f * d;
|
|
break;
|
|
case GX_SP_OFF:
|
|
default:
|
|
a = 1.0f;
|
|
b = 0.0f;
|
|
c = 0.0f;
|
|
break;
|
|
}
|
|
|
|
obj->a0 = a;
|
|
obj->a1 = b;
|
|
obj->a2 = c;
|
|
}
|
|
|
|
/* 8035D7DC-8035D8AC 35811C 00D0+00 0/0 2/2 0/0 .text GXInitLightDistAttn */
|
|
void GXInitLightDistAttn(GXLightObj* obj, f32 dist, f32 brightness, GXDistAttnFn dist_fn) {
|
|
f32 a, b, c;
|
|
|
|
if (dist < 0.0f) {
|
|
dist_fn = GX_DA_OFF;
|
|
}
|
|
|
|
if (brightness <= 0.0f || brightness >= 1.0f) {
|
|
dist_fn = GX_DA_OFF;
|
|
}
|
|
|
|
switch (dist_fn) {
|
|
case GX_DA_GENTLE:
|
|
a = 1.0f;
|
|
b = (1.0f - brightness) / (brightness * dist);
|
|
c = 0.0f;
|
|
break;
|
|
case GX_DA_MEDIUM:
|
|
a = 1.0f;
|
|
b = (0.5f * (1.0f - brightness)) / (brightness * dist);
|
|
c = (0.5f * (1.0f - brightness)) / (dist * (brightness * dist));
|
|
break;
|
|
case GX_DA_STEEP:
|
|
a = 1.0f;
|
|
b = 0.0f;
|
|
c = (1.0f - brightness) / (dist * (brightness * dist));
|
|
break;
|
|
case GX_DA_OFF:
|
|
default:
|
|
a = 1.0f;
|
|
b = 0.0f;
|
|
c = 0.0f;
|
|
break;
|
|
}
|
|
|
|
obj->k0 = a;
|
|
obj->k1 = b;
|
|
obj->k2 = c;
|
|
}
|
|
|
|
/* 8035D8AC-8035D8BC 3581EC 0010+00 0/0 3/3 0/0 .text GXInitLightPos */
|
|
void GXInitLightPos(GXLightObj* obj, f32 x, f32 y, f32 z) {
|
|
obj->posX = x;
|
|
obj->posY = y;
|
|
obj->posZ = z;
|
|
}
|
|
|
|
/* 8035D8BC-8035D8D8 3581FC 001C+00 0/0 3/3 0/0 .text GXInitLightDir */
|
|
void GXInitLightDir(GXLightObj* obj, f32 x, f32 y, f32 z) {
|
|
obj->dirX = -x;
|
|
obj->dirY = -y;
|
|
obj->dirZ = -z;
|
|
}
|
|
|
|
/* 8035D8D8-8035D8E4 358218 000C+00 0/0 3/3 0/0 .text GXInitLightColor */
|
|
void GXInitLightColor(GXLightObj* obj, GXColor color) {
|
|
*(u32*)&obj->color = *(u32*)&color;
|
|
}
|
|
|
|
static inline void PushLight(const register GXLightObj* lt_obj, register void* dest) {
|
|
register u32 zero, color;
|
|
register f32 a0_a1, a2_k0, k1_k2;
|
|
register f32 px_py, pz_dx, dy_dz;
|
|
#ifdef __MWERKS__ // clang-format off
|
|
asm {
|
|
lwz color, 12(lt_obj)
|
|
xor zero, zero, zero
|
|
psq_l a0_a1, 16(lt_obj), 0, 0
|
|
psq_l a2_k0, 24(lt_obj), 0, 0
|
|
psq_l k1_k2, 32(lt_obj), 0, 0
|
|
psq_l px_py, 40(lt_obj), 0, 0
|
|
psq_l pz_dx, 48(lt_obj), 0, 0
|
|
psq_l dy_dz, 56(lt_obj), 0, 0
|
|
|
|
stw zero, 0(dest)
|
|
stw zero, 0(dest)
|
|
stw zero, 0(dest)
|
|
stw color, 0(dest)
|
|
psq_st a0_a1, 0(dest), 0, 0
|
|
psq_st a2_k0, 0(dest), 0, 0
|
|
psq_st k1_k2, 0(dest), 0, 0
|
|
psq_st px_py, 0(dest), 0, 0
|
|
psq_st pz_dx, 0(dest), 0, 0
|
|
psq_st dy_dz, 0(dest), 0, 0
|
|
}
|
|
#endif // clang-format on
|
|
}
|
|
|
|
/* 8035D8E4-8035D960 358224 007C+00 0/0 4/4 2/2 .text GXLoadLightObjImm */
|
|
void GXLoadLightObjImm(GXLightObj* obj, GXLightID light) {
|
|
u32 addr;
|
|
u32 idx;
|
|
GXLightObj* pObj = (GXLightObj*)obj;
|
|
|
|
idx = 31 - __cntlzw(light);
|
|
idx &= 7;
|
|
|
|
addr = 0x600 + idx * 0x10;
|
|
|
|
GX_XF_LOAD_REG_HDR(addr | (0x10 - 1) << 16);
|
|
|
|
PushLight(pObj, (void*)GXFIFO_ADDR);
|
|
__GXData->bpSentNot = 1;
|
|
}
|
|
|
|
/* 8035D960-8035DA48 3582A0 00E8+00 0/0 7/7 4/4 .text GXSetChanAmbColor */
|
|
void GXSetChanAmbColor(GXChannelID channel, GXColor color) {
|
|
u32 reg;
|
|
u32 colorID;
|
|
u8 alpha;
|
|
|
|
switch (channel) {
|
|
case GX_COLOR0:
|
|
reg = __GXData->ambColor[GX_COLOR0];
|
|
reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_COLOR1:
|
|
reg = __GXData->ambColor[GX_COLOR1];
|
|
reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
case GX_ALPHA0:
|
|
reg = __GXData->ambColor[GX_COLOR0];
|
|
reg = GX_SET_TRUNC(reg, color.a, 24, 31);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_ALPHA1:
|
|
reg = __GXData->ambColor[GX_COLOR1];
|
|
reg = GX_SET_TRUNC(reg, color.a, 24, 31);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
case GX_COLOR0A0:
|
|
reg = GXCOLOR_AS_U32(color);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_COLOR1A1:
|
|
reg = GXCOLOR_AS_U32(color);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
GX_XF_LOAD_REG(GX_XF_REG_AMBIENT0 + colorID, reg);
|
|
__GXData->bpSentNot = GX_TRUE;
|
|
__GXData->ambColor[colorID] = reg;
|
|
}
|
|
|
|
/* 8035DA48-8035DB30 358388 00E8+00 0/0 20/20 2/2 .text GXSetChanMatColor */
|
|
void GXSetChanMatColor(GXChannelID channel, GXColor color) {
|
|
u32 reg = 0;
|
|
GXChannelID colorID;
|
|
|
|
switch (channel) {
|
|
case GX_COLOR0:
|
|
reg = __GXData->matColor[GX_COLOR0];
|
|
reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_COLOR1:
|
|
reg = __GXData->matColor[GX_COLOR1];
|
|
reg = GX_SET_TRUNC(reg, GXCOLOR_AS_U32(color), 0, 23);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
case GX_ALPHA0:
|
|
reg = __GXData->matColor[GX_COLOR0];
|
|
reg = GX_SET_TRUNC(reg, color.a, 24, 31);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_ALPHA1:
|
|
reg = __GXData->matColor[GX_COLOR1];
|
|
reg = GX_SET_TRUNC(reg, color.a, 24, 31);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
case GX_COLOR0A0:
|
|
reg = GXCOLOR_AS_U32(color);
|
|
colorID = GX_COLOR0;
|
|
break;
|
|
case GX_COLOR1A1:
|
|
reg = GXCOLOR_AS_U32(color);
|
|
colorID = GX_COLOR1;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
GX_XF_LOAD_REG(GX_XF_REG_MATERIAL0 + colorID, reg);
|
|
__GXData->bpSentNot = GX_TRUE;
|
|
__GXData->matColor[colorID] = reg;
|
|
}
|
|
|
|
/* 8035DB30-8035DB6C 358470 003C+00 0/0 51/51 6/6 .text GXSetNumChans */
|
|
void GXSetNumChans(u8 count) {
|
|
GX_SET_REG(__GXData->genMode, count, 25, 27);
|
|
GX_XF_LOAD_REG(GX_XF_REG_NUMCOLORS, count);
|
|
__GXData->dirtyState |= GX_DIRTY_GEN_MODE;
|
|
}
|
|
|
|
/* 8035DB6C-8035DC1C 3584AC 00B0+00 0/0 34/34 4/4 .text GXSetChanCtrl */
|
|
void GXSetChanCtrl(GXChannelID channel, GXBool doEnable, GXColorSrc ambSrc, GXColorSrc matSrc,
|
|
u32 mask, GXDiffuseFn diffFunc, GXAttnFn attnFunc) {
|
|
const u32 colorID = (u32)channel & 0x3;
|
|
u32 reg = 0;
|
|
|
|
GX_SET_REG(reg, doEnable, GX_XF_CLR0CTRL_LIGHT_ST, GX_XF_CLR0CTRL_LIGHT_END);
|
|
GX_SET_REG(reg, matSrc, GX_XF_CLR0CTRL_MTXSRC_ST, GX_XF_CLR0CTRL_MTXSRC_END);
|
|
GX_SET_REG(reg, ambSrc, GX_XF_CLR0CTRL_AMBSRC_ST, GX_XF_CLR0CTRL_AMBSRC_END);
|
|
GX_SET_REG(reg, (attnFunc == GX_AF_SPEC ? GX_DF_NONE : diffFunc), GX_XF_CLR0CTRL_DIFATTN_ST,
|
|
GX_XF_CLR0CTRL_DIFATTN_END);
|
|
GX_SET_REG(reg, (attnFunc != GX_AF_NONE), GX_XF_CLR0CTRL_ATTNENABLE_ST,
|
|
GX_XF_CLR0CTRL_ATTNENABLE_END);
|
|
GX_SET_REG(reg, (attnFunc != GX_AF_SPEC), GX_XF_CLR0CTRL_ATTNSEL_ST,
|
|
GX_XF_CLR0CTRL_ATTNSEL_END);
|
|
GX_BITFIELD_SET(reg, 26, 4, (u32)mask);
|
|
reg = __rlwimi(reg, (u32)mask, 7, 0x11, 0x14);
|
|
|
|
GX_XF_LOAD_REG(GX_XF_REG_COLOR0CNTRL + colorID, reg);
|
|
|
|
if (channel == GX_COLOR0A0) {
|
|
GX_XF_LOAD_REG(GX_XF_REG_ALPHA0CNTRL, reg);
|
|
} else if (channel == GX_COLOR1A1) {
|
|
GX_XF_LOAD_REG(GX_XF_REG_ALPHA1CNTRL, reg);
|
|
}
|
|
|
|
__GXData->bpSentNot = GX_TRUE;
|
|
}
|