Citro3d
Loading...
Searching...
No Matches
lightenv.c
Go to the documentation of this file.
1#include "internal.h"
2
3static void C3Di_LightEnvMtlBlend(C3D_LightEnv* env)
4{
5 int i;
6 C3D_Material* mtl = &env->material;
7 u32 color = 0;
8 for (i = 0; i < 3; i ++)
9 {
10 int v = 255*(mtl->emission[i] + mtl->ambient[i]*env->ambient[i]);
11 if (v < 0) v = 0;
12 else if (v > 255) v = 255;
13 color |= v << (i*10);
14 }
15 env->conf.ambient = color;
16}
17
18static void C3Di_LightLutUpload(u32 config, C3D_LightLut* lut)
19{
20 int i;
21 GPUCMD_AddWrite(GPUREG_LIGHTING_LUT_INDEX, config);
22 for (i = 0; i < 256; i += 8)
23 GPUCMD_AddWrites(GPUREG_LIGHTING_LUT_DATA0, &lut->data[i], 8);
24}
25
26static void C3Di_LightEnvSelectLayer(C3D_LightEnv* env)
27{
28 static const u8 layer_enabled[] =
29 {
30 BIT(GPU_LUT_D0) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
31 BIT(GPU_LUT_FR) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_SP) | BIT(GPU_LUT_DA),
32 BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_RR) | BIT(GPU_LUT_DA),
33 BIT(GPU_LUT_D0) | BIT(GPU_LUT_D1) | BIT(GPU_LUT_FR) | BIT(GPU_LUT_DA),
34 0xFF &~ BIT(GPU_LUT_FR),
35 0xFF &~ BIT(GPU_LUT_D1),
36 0xFF &~ (BIT(GPU_LUT_RB) | BIT(GPU_LUT_RG)),
37 };
38
39 u32 reg = ~env->conf.config[1];
40 if (reg & (0xFF<< 8)) reg |= GPU_LC1_LUTBIT(GPU_LUT_SP);
41 if (reg & (0xFF<<24)) reg |= GPU_LC1_LUTBIT(GPU_LUT_DA);
42 reg = (reg >> 16) & 0xFF;
43
44 int i = 7;
45 if (!(env->flags & C3DF_LightEnv_IsCP_Any))
46 for (i = 0; i < 7; i ++)
47 if ((layer_enabled[i] & reg) == reg) // Check if the layer supports all LUTs we need
48 break;
49 env->conf.config[0] = (env->conf.config[0] &~ (0xF<<4)) | (GPU_LIGHT_ENV_LAYER_CONFIG(i)<<4);
50}
51
52void C3Di_LightEnvUpdate(C3D_LightEnv* env)
53{
54 int i;
55 C3D_LightEnvConf* conf = &env->conf;
56
57 if (env->flags & C3DF_LightEnv_LCDirty)
58 {
59 conf->numLights = 0;
60 conf->permutation = 0;
61 for (i = 0; i < 8; i ++)
62 {
63 C3D_Light* light = env->lights[i];
64 if (!light) continue;
65 if (!(light->flags & C3DF_Light_Enabled)) continue;
66 conf->permutation |= GPU_LIGHTPERM(conf->numLights++, i);
67 }
68 if (conf->numLights > 0) conf->numLights --;
69 env->flags &= ~C3DF_LightEnv_LCDirty;
70 env->flags |= C3DF_LightEnv_Dirty;
71 }
72
73 if (env->flags & C3DF_LightEnv_MtlDirty)
74 {
75 C3Di_LightEnvMtlBlend(env);
76 env->flags &= ~C3DF_LightEnv_MtlDirty;
77 env->flags |= C3DF_LightEnv_Dirty;
78 }
79
80 if (env->flags & C3DF_LightEnv_Dirty)
81 {
82 C3Di_LightEnvSelectLayer(env);
83 GPUCMD_AddWrite(GPUREG_LIGHTING_AMBIENT, conf->ambient);
84 GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_NUM_LIGHTS, (u32*)&conf->numLights, 3);
85 GPUCMD_AddIncrementalWrites(GPUREG_LIGHTING_LUTINPUT_ABS, (u32*)&conf->lutInput, 3);
86 GPUCMD_AddWrite(GPUREG_LIGHTING_LIGHT_PERMUTATION, conf->permutation);
87 env->flags &= ~C3DF_LightEnv_Dirty;
88 }
89
90 if (env->flags & C3DF_LightEnv_LutDirtyAll)
91 {
92 for (i = 0; i < 6; i ++)
93 {
94 static const u8 lutIds[] = { 0, 1, 3, 4, 5, 6 };
95 if (!(env->flags & C3DF_LightEnv_LutDirty(i))) continue;
96 C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_COMMON, (u32)lutIds[i], 0), env->luts[i]);
97 }
98
99 env->flags &= ~C3DF_LightEnv_LutDirtyAll;
100 }
101
102 for (i = 0; i < 8; i ++)
103 {
104 C3D_Light* light = env->lights[i];
105 if (!light) continue;
106
107 if (light->flags & C3DF_Light_MatDirty)
108 {
109 C3Di_LightMtlBlend(light);
110 light->flags &= ~C3DF_Light_MatDirty;
111 light->flags |= C3DF_Light_Dirty;
112 }
113
114 if (light->flags & C3DF_Light_Dirty)
115 {
116 GPUCMD_AddIncrementalWrites(GPUREG_LIGHT0_SPECULAR0 + i*0x10, (u32*)&light->conf, 12);
117 light->flags &= ~C3DF_Light_Dirty;
118 }
119
120 if (light->flags & C3DF_Light_SPDirty)
121 {
122 C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_SP, i, 0), light->lut_SP);
123 light->flags &= ~C3DF_Light_SPDirty;
124 }
125
126 if (light->flags & C3DF_Light_DADirty)
127 {
128 C3Di_LightLutUpload(GPU_LIGHTLUTIDX(GPU_LUTSELECT_DA, i, 0), light->lut_DA);
129 light->flags &= ~C3DF_Light_DADirty;
130 }
131 }
132}
133
134void C3Di_LightEnvDirty(C3D_LightEnv* env)
135{
136 env->flags |= C3DF_LightEnv_Dirty;
137 int i;
138 for (i = 0; i < 6; i ++)
139 if (env->luts[i])
140 env->flags |= C3DF_LightEnv_LutDirty(i);
141 for (i = 0; i < 8; i ++)
142 {
143 C3D_Light* light = env->lights[i];
144 if (!light) continue;
145
146 light->flags |= C3DF_Light_Dirty;
147 if (light->lut_SP)
148 light->flags |= C3DF_Light_SPDirty;
149 if (light->lut_DA)
150 light->flags |= C3DF_Light_DADirty;
151 }
152}
153
154void C3D_LightEnvInit(C3D_LightEnv* env)
155{
156 memset(env, 0, sizeof(*env));
157 env->flags = C3DF_LightEnv_Dirty;
158 env->ambient[0] = env->ambient[1] = env->ambient[2] = 1.0f;
159 env->conf.config[0] = (4<<8) | BIT(27) | BIT(31);
160 env->conf.config[1] = ~0;
161 env->conf.lutInput.select = GPU_LIGHTLUTINPUT(GPU_LUT_SP, GPU_LUTINPUT_SP);
162 env->conf.lutInput.abs = 0x2222222;
163}
164
165void C3D_LightEnvBind(C3D_LightEnv* env)
166{
167 C3D_Context* ctx = C3Di_GetContext();
168
169 if (!(ctx->flags & C3DiF_Active))
170 return;
171
172 if (ctx->lightEnv == env)
173 return;
174
175 ctx->flags |= C3DiF_LightEnv;
176 ctx->lightEnv = env;
177}
178
179void C3D_LightEnvMaterial(C3D_LightEnv* env, const C3D_Material* mtl)
180{
181 int i;
182 memcpy(&env->material, mtl, sizeof(*mtl));
183 env->flags |= C3DF_LightEnv_MtlDirty;
184 for (i = 0; i < 8; i ++)
185 {
186 C3D_Light* light = env->lights[i];
187 if (light) light->flags |= C3DF_Light_MatDirty;
188 }
189}
190
191void C3D_LightEnvAmbient(C3D_LightEnv* env, float r, float g, float b)
192{
193 env->ambient[0] = b;
194 env->ambient[1] = g;
195 env->ambient[2] = r;
196 env->flags |= C3DF_LightEnv_MtlDirty;
197}
198
199void C3D_LightEnvLut(C3D_LightEnv* env, GPU_LIGHTLUTID lutId, GPU_LIGHTLUTINPUT input, bool negative, C3D_LightLut* lut)
200{
201 static const s8 ids[] = { 0, 1, -1, 2, 3, 4, 5, -1 };
202 int id = ids[lutId];
203 if (id >= 0)
204 {
205 env->luts[id] = lut;
206 if (lut)
207 {
208 env->conf.config[1] &= ~GPU_LC1_LUTBIT(lutId);
209 env->flags |= C3DF_LightEnv_LutDirty(id);
210 } else
211 {
212 env->conf.config[1] |= GPU_LC1_LUTBIT(lutId);
213 env->luts[id] = NULL;
214 }
215 }
216
217 env->conf.lutInput.select &= ~GPU_LIGHTLUTINPUT(lutId, 0xF);
218 env->conf.lutInput.select |= GPU_LIGHTLUTINPUT(lutId, input);
219
220 u32 absbit = 1 << (lutId*4 + 1);
221 env->conf.lutInput.abs &= ~absbit;
222 if (negative)
223 env->conf.lutInput.abs |= absbit;
224
225 env->flags |= C3DF_LightEnv_Dirty;
226 if (input == GPU_LUTINPUT_CP)
227 env->flags |= C3DF_LightEnv_IsCP(lutId);
228 else
229 env->flags &= ~C3DF_LightEnv_IsCP(lutId);
230}
231
232void C3D_LightEnvFresnel(C3D_LightEnv* env, GPU_FRESNELSEL selector)
233{
234 env->conf.config[0] &= ~(3<<2);
235 env->conf.config[0] |= (selector&3)<<2;
236 env->flags |= C3DF_LightEnv_Dirty;
237}
238
239void C3D_LightEnvBumpMode(C3D_LightEnv* env, GPU_BUMPMODE mode)
240{
241 env->conf.config[0] &= ~(3<<28);
242 env->conf.config[0] |= (mode&3)<<28;
243 env->flags |= C3DF_LightEnv_Dirty;
244}
245
246void C3D_LightEnvBumpSel(C3D_LightEnv* env, int texUnit)
247{
248 env->conf.config[0] &= ~(3<<22);
249 env->conf.config[0] |= (texUnit&3)<<22;
250 env->flags |= C3DF_LightEnv_Dirty;
251}
252
253void C3D_LightEnvShadowMode(C3D_LightEnv* env, u32 mode)
254{
255 mode &= 0xF<<16;
256 if (mode & (GPU_SHADOW_PRIMARY | GPU_SHADOW_SECONDARY | GPU_SHADOW_ALPHA))
257 mode |= BIT(0);
258 env->conf.config[0] &= ~((0xF<<16) | BIT(0));
259 env->conf.config[0] |= mode;
260 env->flags |= C3DF_LightEnv_Dirty;
261}
262
263void C3D_LightEnvShadowSel(C3D_LightEnv* env, int texUnit)
264{
265 env->conf.config[0] &= ~(3<<24);
266 env->conf.config[0] |= (texUnit&3)<<24;
267 env->flags |= C3DF_LightEnv_Dirty;
268}
269
270void C3D_LightEnvClampHighlights(C3D_LightEnv* env, bool clamp)
271{
272 if (clamp)
273 env->conf.config[0] |= BIT(27);
274 else
275 env->conf.config[0] &= ~BIT(27);
276 env->flags |= C3DF_LightEnv_Dirty;
277}
@ C3DiF_Active
Definition: internal.h:75
@ C3DiF_LightEnv
Definition: internal.h:85
void C3Di_LightMtlBlend(C3D_Light *light)
Definition: light.c:3
void C3D_LightEnvMaterial(C3D_LightEnv *env, const C3D_Material *mtl)
Definition: lightenv.c:179
void C3D_LightEnvLut(C3D_LightEnv *env, GPU_LIGHTLUTID lutId, GPU_LIGHTLUTINPUT input, bool negative, C3D_LightLut *lut)
Definition: lightenv.c:199
void C3Di_LightEnvDirty(C3D_LightEnv *env)
Definition: lightenv.c:134
void C3D_LightEnvBumpSel(C3D_LightEnv *env, int texUnit)
Definition: lightenv.c:246
void C3D_LightEnvBumpMode(C3D_LightEnv *env, GPU_BUMPMODE mode)
Definition: lightenv.c:239
void C3D_LightEnvAmbient(C3D_LightEnv *env, float r, float g, float b)
Definition: lightenv.c:191
void C3D_LightEnvBind(C3D_LightEnv *env)
Definition: lightenv.c:165
void C3Di_LightEnvUpdate(C3D_LightEnv *env)
Definition: lightenv.c:52
void C3D_LightEnvFresnel(C3D_LightEnv *env, GPU_FRESNELSEL selector)
Definition: lightenv.c:232
void C3D_LightEnvShadowMode(C3D_LightEnv *env, u32 mode)
Definition: lightenv.c:253
void C3D_LightEnvShadowSel(C3D_LightEnv *env, int texUnit)
Definition: lightenv.c:263
void C3D_LightEnvInit(C3D_LightEnv *env)
Definition: lightenv.c:154
void C3D_LightEnvClampHighlights(C3D_LightEnv *env, bool clamp)
Definition: lightenv.c:270
u32 flags
Definition: internal.h:38
C3D_LightEnv * lightEnv
Definition: internal.h:44