98e75f2d |
1 | /* |
2 | * Glide64 - Glide video plugin for Nintendo 64 emulators. |
3 | * Copyright (c) 2002 Dave2001 |
4 | * Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | //**************************************************************** |
22 | // |
23 | // Glide64 - Glide Plugin for Nintendo 64 emulators |
24 | // Project started on December 29th, 2001 |
25 | // |
26 | // Authors: |
27 | // Dave2001, original author, founded the project in 2001, left it in 2002 |
28 | // Gugaman, joined the project in 2002, left it in 2002 |
29 | // Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002 |
30 | // Hiroshi 'KoolSmoky' Morii, joined the project in 2007 |
31 | // |
32 | //**************************************************************** |
33 | // |
34 | // To modify Glide64: |
35 | // * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me. |
36 | // * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all. |
37 | // |
38 | //**************************************************************** |
39 | |
40 | static void calc_point_light (VERTEX *v, float * vpos) |
41 | { |
42 | Check_FrameSkip; |
43 | |
44 | float light_intensity = 0.0f; |
45 | register float color[3] = {rdp.light[rdp.num_lights].r, rdp.light[rdp.num_lights].g, rdp.light[rdp.num_lights].b}; |
46 | for (wxUint32 l=0; l<rdp.num_lights; l++) |
47 | { |
48 | if (rdp.light[l].nonblack) |
49 | { |
50 | float lvec[3] = {rdp.light[l].x, rdp.light[l].y, rdp.light[l].z}; |
51 | lvec[0] -= vpos[0]; |
52 | lvec[1] -= vpos[1]; |
53 | lvec[2] -= vpos[2]; |
54 | float light_len2 = lvec[0]*lvec[0] + lvec[1]*lvec[1] + lvec[2]*lvec[2]; |
55 | float light_len = sqrtf(light_len2); |
56 | #ifdef EXTREME_LOGGING |
57 | FRDP ("calc_point_light: len: %f, len2: %f\n", light_len, light_len2); |
58 | #endif |
59 | float at = rdp.light[l].ca + light_len/65535.0f*rdp.light[l].la + light_len2/65535.0f*rdp.light[l].qa; |
60 | if (at > 0.0f) |
61 | light_intensity = 1/at;//DotProduct (lvec, nvec) / (light_len * normal_len * at); |
62 | else |
63 | light_intensity = 0.0f; |
64 | } |
65 | else |
66 | { |
67 | light_intensity = 0.0f; |
68 | } |
69 | if (light_intensity > 0.0f) |
70 | { |
71 | color[0] += rdp.light[l].r * light_intensity; |
72 | color[1] += rdp.light[l].g * light_intensity; |
73 | color[2] += rdp.light[l].b * light_intensity; |
74 | } |
75 | } |
76 | if (color[0] > 1.0f) color[0] = 1.0f; |
77 | if (color[1] > 1.0f) color[1] = 1.0f; |
78 | if (color[2] > 1.0f) color[2] = 1.0f; |
79 | |
80 | v->r = (wxUint8)(color[0]*255.0f); |
81 | v->g = (wxUint8)(color[1]*255.0f); |
82 | v->b = (wxUint8)(color[2]*255.0f); |
83 | } |
84 | |
85 | static void uc6_obj_rectangle(); |
86 | |
87 | static void uc2_vertex () |
88 | { |
89 | Check_FrameSkip; |
90 | |
91 | if (!(rdp.cmd0 & 0x00FFFFFF)) |
92 | { |
93 | uc6_obj_rectangle(); |
94 | return; |
95 | } |
96 | |
97 | // This is special, not handled in update(), but here |
98 | // * Matrix Pre-multiplication idea by Gonetz (Gonetz@ngs.ru) |
99 | if (rdp.update & UPDATE_MULT_MAT) |
100 | { |
101 | rdp.update ^= UPDATE_MULT_MAT; |
102 | MulMatrices(rdp.model, rdp.proj, rdp.combined); |
103 | } |
104 | if (rdp.update & UPDATE_LIGHTS) |
105 | { |
106 | rdp.update ^= UPDATE_LIGHTS; |
107 | |
108 | // Calculate light vectors |
109 | for (wxUint32 l=0; l<rdp.num_lights; l++) |
110 | { |
111 | InverseTransformVector(&rdp.light[l].dir_x, rdp.light_vector[l], rdp.model); |
112 | NormalizeVector (rdp.light_vector[l]); |
113 | } |
114 | } |
115 | |
116 | wxUint32 addr = segoffset(rdp.cmd1); |
117 | int v0, i, n; |
118 | float x, y, z; |
119 | |
120 | rdp.vn = n = (rdp.cmd0 >> 12) & 0xFF; |
121 | rdp.v0 = v0 = ((rdp.cmd0 >> 1) & 0x7F) - n; |
122 | |
c2ff96e6 |
123 | #ifdef EXTREME_LOGGING |
98e75f2d |
124 | FRDP ("uc2:vertex n: %d, v0: %d, from: %08lx\n", n, v0, addr); |
c2ff96e6 |
125 | #endif |
98e75f2d |
126 | |
127 | if (v0 < 0) |
128 | { |
129 | RDP_E ("** ERROR: uc2:vertex v0 < 0\n"); |
130 | LRDP("** ERROR: uc2:vertex v0 < 0\n"); |
131 | return; |
132 | } |
133 | |
134 | wxUint32 geom_mode = rdp.geom_mode; |
135 | if ((settings.hacks&hack_Fzero) && (rdp.geom_mode & 0x40000)) |
136 | { |
137 | if (((short*)gfx.RDRAM)[(((addr) >> 1) + 4)^1] || ((short*)gfx.RDRAM)[(((addr) >> 1) + 5)^1]) |
138 | rdp.geom_mode ^= 0x40000; |
139 | } |
140 | #ifdef __ARM_NEON__ |
141 | float32x4_t comb0, comb1, comb2, comb3; |
142 | float32x4_t v_xyzw; |
143 | comb0 = vld1q_f32(rdp.combined[0]); |
144 | comb1 = vld1q_f32(rdp.combined[1]); |
145 | comb2 = vld1q_f32(rdp.combined[2]); |
146 | comb3 = vld1q_f32(rdp.combined[3]); |
147 | #endif |
148 | for (i=0; i < (n<<4); i+=16) |
149 | { |
150 | VERTEX *v = &rdp.vtx[v0 + (i>>4)]; |
151 | x = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 0)^1]; |
152 | y = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 1)^1]; |
153 | z = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 2)^1]; |
154 | v->flags = ((wxUint16*)gfx.RDRAM)[(((addr+i) >> 1) + 3)^1]; |
155 | v->ou = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 4)^1]; |
156 | v->ov = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 5)^1]; |
157 | v->uv_scaled = 0; |
158 | v->a = ((wxUint8*)gfx.RDRAM)[(addr+i + 15)^3]; |
159 | |
160 | #ifdef __ARM_NEON__ |
161 | v_xyzw = x*comb0+y*comb1+z*comb2+comb3; |
162 | //vst1q_f32((float*)v, v_xyzw); |
163 | v->x=v_xyzw[0]; |
164 | v->y=v_xyzw[1]; |
165 | v->z=v_xyzw[2]; |
166 | v->w=v_xyzw[3]; |
167 | #else |
168 | v->x = x*rdp.combined[0][0] + y*rdp.combined[1][0] + z*rdp.combined[2][0] + rdp.combined[3][0]; |
169 | v->y = x*rdp.combined[0][1] + y*rdp.combined[1][1] + z*rdp.combined[2][1] + rdp.combined[3][1]; |
170 | v->z = x*rdp.combined[0][2] + y*rdp.combined[1][2] + z*rdp.combined[2][2] + rdp.combined[3][2]; |
171 | v->w = x*rdp.combined[0][3] + y*rdp.combined[1][3] + z*rdp.combined[2][3] + rdp.combined[3][3]; |
172 | #endif |
173 | |
174 | v->uv_calculated = 0xFFFFFFFF; |
175 | v->screen_translated = 0; |
176 | v->shade_mod = 0; |
177 | |
178 | if (fabs(v->w) < 0.001) v->w = 0.001f; |
179 | v->oow = 1.0f / v->w; |
180 | #ifdef __ARM_NEON__ |
181 | v_xyzw *= v->oow; |
182 | v->x_w=v_xyzw[0]; |
183 | v->y_w=v_xyzw[1]; |
184 | v->z_w=v_xyzw[2]; |
185 | #else |
186 | v->x_w = v->x * v->oow; |
187 | v->y_w = v->y * v->oow; |
188 | v->z_w = v->z * v->oow; |
189 | #endif |
190 | CalculateFog (v); |
191 | |
192 | |
193 | v->scr_off = 0; |
194 | if (v->x < -v->w) v->scr_off |= 1; |
195 | if (v->x > v->w) v->scr_off |= 2; |
196 | if (v->y < -v->w) v->scr_off |= 4; |
197 | if (v->y > v->w) v->scr_off |= 8; |
198 | if (v->w < 0.1f) v->scr_off |= 16; |
199 | // if (v->z_w > 1.0f) v->scr_off |= 32; |
200 | |
201 | if (rdp.geom_mode & 0x00020000) |
202 | { |
203 | v->vec[0] = ((char*)gfx.RDRAM)[(addr+i + 12)^3]; |
204 | v->vec[1] = ((char*)gfx.RDRAM)[(addr+i + 13)^3]; |
205 | v->vec[2] = ((char*)gfx.RDRAM)[(addr+i + 14)^3]; |
206 | // FRDP("Calc light. x: %f, y: %f z: %f\n", v->vec[0], v->vec[1], v->vec[2]); |
207 | // if (!(rdp.geom_mode & 0x800000)) |
208 | { |
209 | if (rdp.geom_mode & 0x40000) |
210 | { |
211 | if (rdp.geom_mode & 0x80000) |
212 | { |
213 | calc_linear (v); |
214 | #ifdef EXTREME_LOGGING |
215 | FRDP ("calc linear: v%d - u: %f, v: %f\n", i>>4, v->ou, v->ov); |
216 | #endif |
217 | } |
218 | else |
219 | { |
220 | calc_sphere (v); |
221 | #ifdef EXTREME_LOGGING |
222 | FRDP ("calc sphere: v%d - u: %f, v: %f\n", i>>4, v->ou, v->ov); |
223 | #endif |
224 | } |
225 | } |
226 | } |
227 | if (rdp.geom_mode & 0x00400000) |
228 | { |
229 | float tmpvec[3] = {x, y, z}; |
230 | calc_point_light (v, tmpvec); |
231 | } |
232 | else |
233 | { |
234 | NormalizeVector (v->vec); |
235 | calc_light (v); |
236 | } |
237 | } |
238 | else |
239 | { |
240 | v->r = ((wxUint8*)gfx.RDRAM)[(addr+i + 12)^3]; |
241 | v->g = ((wxUint8*)gfx.RDRAM)[(addr+i + 13)^3]; |
242 | v->b = ((wxUint8*)gfx.RDRAM)[(addr+i + 14)^3]; |
243 | } |
244 | #ifdef EXTREME_LOGGING |
245 | FRDP ("v%d - x: %f, y: %f, z: %f, w: %f, u: %f, v: %f, f: %f, z_w: %f, r=%d, g=%d, b=%d, a=%d\n", i>>4, v->x, v->y, v->z, v->w, v->ou*rdp.tiles[rdp.cur_tile].s_scale, v->ov*rdp.tiles[rdp.cur_tile].t_scale, v->f, v->z_w, v->r, v->g, v->b, v->a); |
246 | #endif |
247 | } |
248 | rdp.geom_mode = geom_mode; |
249 | } |
250 | |
251 | static void uc2_modifyvtx () |
252 | { |
253 | Check_FrameSkip; |
254 | |
255 | wxUint8 where = (wxUint8)((rdp.cmd0 >> 16) & 0xFF); |
256 | wxUint16 vtx = (wxUint16)((rdp.cmd0 >> 1) & 0xFFFF); |
257 | |
c2ff96e6 |
258 | #ifdef EXTREME_LOGGING |
98e75f2d |
259 | FRDP ("uc2:modifyvtx: vtx: %d, where: 0x%02lx, val: %08lx - ", vtx, where, rdp.cmd1); |
c2ff96e6 |
260 | #endif |
98e75f2d |
261 | uc0_modifyvtx(where, vtx, rdp.cmd1); |
262 | } |
263 | |
264 | static void uc2_culldl () |
265 | { |
266 | wxUint16 vStart = (wxUint16)(rdp.cmd0 & 0xFFFF) >> 1; |
267 | wxUint16 vEnd = (wxUint16)(rdp.cmd1 & 0xFFFF) >> 1; |
268 | wxUint32 cond = 0; |
c2ff96e6 |
269 | #ifdef EXTREME_LOGGING |
98e75f2d |
270 | FRDP ("uc2:culldl start: %d, end: %d\n", vStart, vEnd); |
c2ff96e6 |
271 | #endif |
98e75f2d |
272 | |
273 | if (vEnd < vStart) return; |
274 | for (wxUint16 i=vStart; i<=vEnd; i++) |
275 | { |
276 | /* |
277 | VERTEX v = &rdp.vtx[i]; |
278 | // Check if completely off the screen (quick frustrum clipping for 90 FOV) |
279 | if (v->x >= -v->w) |
280 | cond |= 0x01; |
281 | if (v->x <= v->w) |
282 | cond |= 0x02; |
283 | if (v->y >= -v->w) |
284 | cond |= 0x04; |
285 | if (v->y <= v->w) |
286 | cond |= 0x08; |
287 | if (v->w >= 0.1f) |
288 | cond |= 0x10; |
289 | |
290 | if (cond == 0x1F) |
291 | return; |
292 | //*/ |
293 | |
294 | #ifdef EXTREME_LOGGING |
295 | FRDP (" v[%d] = (%02f, %02f, %02f, 0x%02lx)\n", i, rdp.vtx[i].x, rdp.vtx[i].y, rdp.vtx[i].w, rdp.vtx[i].scr_off); |
296 | #endif |
297 | |
298 | cond |= (~rdp.vtx[i].scr_off) & 0x1F; |
299 | if (cond == 0x1F) |
300 | return; |
301 | } |
302 | |
303 | LRDP(" - "); // specify that the enddl is not a real command |
304 | uc0_enddl (); |
305 | } |
306 | |
307 | static void uc6_obj_loadtxtr (); |
308 | |
309 | static void uc2_tri1() |
310 | { |
311 | Check_FrameSkip; |
312 | |
313 | if ((rdp.cmd0 & 0x00FFFFFF) == 0x17) |
314 | { |
315 | uc6_obj_loadtxtr (); |
316 | return; |
317 | } |
318 | if (rdp.skip_drawing) |
319 | { |
320 | LRDP("uc2:tri1. skipped\n"); |
321 | return; |
322 | } |
323 | |
c2ff96e6 |
324 | #ifdef EXTREME_LOGGING |
98e75f2d |
325 | FRDP("uc2:tri1 #%d - %d, %d, %d\n", rdp.tri_n, |
326 | ((rdp.cmd0 >> 17) & 0x7F), |
327 | ((rdp.cmd0 >> 9) & 0x7F), |
328 | ((rdp.cmd0 >> 1) & 0x7F)); |
c2ff96e6 |
329 | #endif |
98e75f2d |
330 | |
331 | VERTEX *v[3] = { |
332 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
333 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
334 | &rdp.vtx[(rdp.cmd0 >> 1) & 0x7F] |
335 | }; |
336 | |
337 | rsp_tri1(v); |
338 | } |
339 | |
340 | static void uc6_obj_ldtx_sprite (); |
341 | static void uc6_obj_ldtx_rect (); |
342 | |
343 | static void uc2_quad () |
344 | { |
345 | Check_FrameSkip; |
346 | |
347 | if ((rdp.cmd0 & 0x00FFFFFF) == 0x2F) |
348 | { |
349 | wxUint32 command = rdp.cmd0>>24; |
350 | if (command == 0x6) |
351 | { |
352 | uc6_obj_ldtx_sprite (); |
353 | return; |
354 | } |
355 | if (command == 0x7) |
356 | { |
357 | uc6_obj_ldtx_rect (); |
358 | return; |
359 | } |
360 | } |
361 | |
362 | if (rdp.skip_drawing) |
363 | { |
364 | LRDP("uc2_quad. skipped\n"); |
365 | return; |
366 | } |
367 | |
368 | LRDP("uc2:quad"); |
369 | |
c2ff96e6 |
370 | #ifdef EXTREME_LOGGING |
98e75f2d |
371 | FRDP(" #%d, #%d - %d, %d, %d - %d, %d, %d\n", rdp.tri_n, rdp.tri_n+1, |
372 | ((rdp.cmd0 >> 17) & 0x7F), |
373 | ((rdp.cmd0 >> 9) & 0x7F), |
374 | ((rdp.cmd0 >> 1) & 0x7F), |
375 | ((rdp.cmd1 >> 17) & 0x7F), |
376 | ((rdp.cmd1 >> 9) & 0x7F), |
377 | ((rdp.cmd1 >> 1) & 0x7F)); |
c2ff96e6 |
378 | #endif |
98e75f2d |
379 | |
380 | VERTEX *v[6] = { |
381 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
382 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
383 | &rdp.vtx[(rdp.cmd0 >> 1) & 0x7F], |
384 | &rdp.vtx[(rdp.cmd1 >> 17) & 0x7F], |
385 | &rdp.vtx[(rdp.cmd1 >> 9) & 0x7F], |
386 | &rdp.vtx[(rdp.cmd1 >> 1) & 0x7F] |
387 | }; |
388 | |
389 | rsp_tri2(v); |
390 | } |
391 | |
392 | static void uc6_ldtx_rect_r (); |
393 | |
394 | static void uc2_line3d () |
395 | { |
396 | Check_FrameSkip; |
397 | |
398 | if ( (rdp.cmd0&0xFF) == 0x2F ) |
399 | uc6_ldtx_rect_r (); |
400 | else |
401 | { |
c2ff96e6 |
402 | #ifdef EXTREME_LOGGING |
403 | FRDP("uc2:line3d #%d, #%d - %d, %d\n", rdp.tri_n, rdp.tri_n+1, |
98e75f2d |
404 | (rdp.cmd0 >> 17) & 0x7F, |
405 | (rdp.cmd0 >> 9) & 0x7F); |
c2ff96e6 |
406 | #endif |
98e75f2d |
407 | |
408 | VERTEX *v[3] = { |
409 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
410 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
411 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F] |
412 | }; |
413 | wxUint16 width = (wxUint16)(rdp.cmd0 + 3)&0xFF; |
414 | wxUint32 cull_mode = (rdp.flags & CULLMASK) >> CULLSHIFT; |
415 | rdp.flags |= CULLMASK; |
416 | rdp.update |= UPDATE_CULL_MODE; |
417 | rsp_tri1(v, width); |
418 | rdp.flags ^= CULLMASK; |
419 | rdp.flags |= cull_mode << CULLSHIFT; |
420 | rdp.update |= UPDATE_CULL_MODE; |
421 | } |
422 | } |
423 | |
424 | static void uc2_special3 () |
425 | { |
426 | LRDP("uc2:special3\n"); |
427 | } |
428 | |
429 | static void uc2_special2 () |
430 | { |
431 | LRDP("uc2:special2\n"); |
432 | } |
433 | |
434 | static void uc2_dma_io () |
435 | { |
436 | LRDP("uc2:dma_io\n"); |
437 | } |
438 | |
439 | static void uc2_pop_matrix () |
440 | { |
c2ff96e6 |
441 | #ifdef EXTREME_LOGGING |
442 | FRDP ("uc2:pop_matrix %08lx, %08lx\n", rdp.cmd0, rdp.cmd1); |
443 | #endif |
98e75f2d |
444 | |
445 | // Just pop the modelview matrix |
446 | modelview_pop (rdp.cmd1 >> 6); |
447 | } |
448 | |
449 | static void uc2_geom_mode () |
450 | { |
451 | // Switch around some things |
452 | wxUint32 clr_mode = (rdp.cmd0 & 0x00DFC9FF) | |
453 | ((rdp.cmd0 & 0x00000600) << 3) | |
454 | ((rdp.cmd0 & 0x00200000) >> 12) | 0xFF000000; |
455 | wxUint32 set_mode = (rdp.cmd1 & 0xFFDFC9FF) | |
456 | ((rdp.cmd1 & 0x00000600) << 3) | |
457 | ((rdp.cmd1 & 0x00200000) >> 12); |
458 | |
c2ff96e6 |
459 | #ifdef EXTREME_LOGGING |
98e75f2d |
460 | FRDP("uc2:geom_mode c:%08lx, s:%08lx ", clr_mode, set_mode); |
c2ff96e6 |
461 | #endif |
98e75f2d |
462 | |
463 | rdp.geom_mode &= clr_mode; |
464 | rdp.geom_mode |= set_mode; |
465 | |
c2ff96e6 |
466 | #ifdef EXTREME_LOGGING |
98e75f2d |
467 | FRDP ("result:%08lx\n", rdp.geom_mode); |
c2ff96e6 |
468 | #endif |
98e75f2d |
469 | |
470 | if (rdp.geom_mode & 0x00000001) // Z-Buffer enable |
471 | { |
472 | if (!(rdp.flags & ZBUF_ENABLED)) |
473 | { |
474 | rdp.flags |= ZBUF_ENABLED; |
475 | rdp.update |= UPDATE_ZBUF_ENABLED; |
476 | } |
477 | } |
478 | else |
479 | { |
480 | if ((rdp.flags & ZBUF_ENABLED)) |
481 | { |
482 | if (!settings.flame_corona || (rdp.rm != 0x00504341)) //hack for flame's corona |
483 | rdp.flags ^= ZBUF_ENABLED; |
484 | rdp.update |= UPDATE_ZBUF_ENABLED; |
485 | } |
486 | } |
487 | if (rdp.geom_mode & 0x00001000) // Front culling |
488 | { |
489 | if (!(rdp.flags & CULL_FRONT)) |
490 | { |
491 | rdp.flags |= CULL_FRONT; |
492 | rdp.update |= UPDATE_CULL_MODE; |
493 | } |
494 | } |
495 | else |
496 | { |
497 | if (rdp.flags & CULL_FRONT) |
498 | { |
499 | rdp.flags ^= CULL_FRONT; |
500 | rdp.update |= UPDATE_CULL_MODE; |
501 | } |
502 | } |
503 | if (rdp.geom_mode & 0x00002000) // Back culling |
504 | { |
505 | if (!(rdp.flags & CULL_BACK)) |
506 | { |
507 | rdp.flags |= CULL_BACK; |
508 | rdp.update |= UPDATE_CULL_MODE; |
509 | } |
510 | } |
511 | else |
512 | { |
513 | if (rdp.flags & CULL_BACK) |
514 | { |
515 | rdp.flags ^= CULL_BACK; |
516 | rdp.update |= UPDATE_CULL_MODE; |
517 | } |
518 | } |
519 | |
520 | //Added by Gonetz |
521 | if (rdp.geom_mode & 0x00010000) // Fog enable |
522 | { |
523 | if (!(rdp.flags & FOG_ENABLED)) |
524 | { |
525 | rdp.flags |= FOG_ENABLED; |
526 | rdp.update |= UPDATE_FOG_ENABLED; |
527 | } |
528 | } |
529 | else |
530 | { |
531 | if (rdp.flags & FOG_ENABLED) |
532 | { |
533 | rdp.flags ^= FOG_ENABLED; |
534 | rdp.update |= UPDATE_FOG_ENABLED; |
535 | } |
536 | } |
537 | } |
538 | |
539 | static void uc6_obj_rectangle_r (); |
540 | |
541 | static void uc2_matrix () |
542 | { |
543 | if (!(rdp.cmd0 & 0x00FFFFFF)) |
544 | { |
545 | uc6_obj_rectangle_r(); |
546 | return; |
547 | } |
548 | LRDP("uc2:matrix\n"); |
549 | |
550 | DECLAREALIGN16VAR(m[4][4]); |
551 | load_matrix(m, segoffset(rdp.cmd1)); |
552 | |
553 | wxUint8 command = (wxUint8)((rdp.cmd0 ^ 1) & 0xFF); |
554 | switch (command) |
555 | { |
556 | case 0: // modelview mul nopush |
557 | LRDP("modelview mul\n"); |
558 | modelview_mul (m); |
559 | break; |
560 | |
561 | case 1: // modelview mul push |
562 | LRDP("modelview mul push\n"); |
563 | modelview_mul_push (m); |
564 | break; |
565 | |
566 | case 2: // modelview load nopush |
567 | LRDP("modelview load\n"); |
568 | modelview_load (m); |
569 | break; |
570 | |
571 | case 3: // modelview load push |
572 | LRDP("modelview load push\n"); |
573 | modelview_load_push (m); |
574 | break; |
575 | |
576 | case 4: // projection mul nopush |
577 | case 5: // projection mul push, can't push projection |
578 | LRDP("projection mul\n"); |
579 | projection_mul (m); |
580 | break; |
581 | |
582 | case 6: // projection load nopush |
583 | case 7: // projection load push, can't push projection |
584 | LRDP("projection load\n"); |
585 | projection_load (m); |
586 | break; |
587 | |
588 | default: |
589 | FRDP_E ("Unknown matrix command, %02lx", command); |
c2ff96e6 |
590 | #ifdef EXTREME_LOGGING |
591 | FRDP ("Unknown matrix command, %02lx", command); |
592 | #endif |
98e75f2d |
593 | } |
594 | |
595 | #ifdef EXTREME_LOGGING |
596 | FRDP ("{%f,%f,%f,%f}\n", m[0][0], m[0][1], m[0][2], m[0][3]); |
597 | FRDP ("{%f,%f,%f,%f}\n", m[1][0], m[1][1], m[1][2], m[1][3]); |
598 | FRDP ("{%f,%f,%f,%f}\n", m[2][0], m[2][1], m[2][2], m[2][3]); |
599 | FRDP ("{%f,%f,%f,%f}\n", m[3][0], m[3][1], m[3][2], m[3][3]); |
600 | FRDP ("\nmodel\n{%f,%f,%f,%f}\n", rdp.model[0][0], rdp.model[0][1], rdp.model[0][2], rdp.model[0][3]); |
601 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[1][0], rdp.model[1][1], rdp.model[1][2], rdp.model[1][3]); |
602 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[2][0], rdp.model[2][1], rdp.model[2][2], rdp.model[2][3]); |
603 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[3][0], rdp.model[3][1], rdp.model[3][2], rdp.model[3][3]); |
604 | FRDP ("\nproj\n{%f,%f,%f,%f}\n", rdp.proj[0][0], rdp.proj[0][1], rdp.proj[0][2], rdp.proj[0][3]); |
605 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[1][0], rdp.proj[1][1], rdp.proj[1][2], rdp.proj[1][3]); |
606 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[2][0], rdp.proj[2][1], rdp.proj[2][2], rdp.proj[2][3]); |
607 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[3][0], rdp.proj[3][1], rdp.proj[3][2], rdp.proj[3][3]); |
608 | #endif |
609 | } |
610 | |
611 | static void uc2_moveword () |
612 | { |
613 | wxUint8 index = (wxUint8)((rdp.cmd0 >> 16) & 0xFF); |
614 | wxUint16 offset = (wxUint16)(rdp.cmd0 & 0xFFFF); |
615 | wxUint32 data = rdp.cmd1; |
616 | |
c2ff96e6 |
617 | #ifdef EXTREME_LOGGING |
98e75f2d |
618 | FRDP ("uc2:moveword "); |
c2ff96e6 |
619 | #endif |
98e75f2d |
620 | |
621 | switch (index) |
622 | { |
623 | // NOTE: right now it's assuming that it sets the integer part first. This could |
624 | // be easily fixed, but only if i had something to test with. |
625 | |
626 | case 0x00: // moveword matrix |
627 | { |
628 | // do matrix pre-mult so it's re-updated next time |
629 | if (rdp.update & UPDATE_MULT_MAT) |
630 | { |
631 | rdp.update ^= UPDATE_MULT_MAT; |
632 | MulMatrices(rdp.model, rdp.proj, rdp.combined); |
633 | } |
634 | |
635 | if (rdp.cmd0 & 0x20) // fractional part |
636 | { |
637 | int index_x = (rdp.cmd0 & 0x1F) >> 1; |
638 | int index_y = index_x >> 2; |
639 | index_x &= 3; |
640 | |
641 | float fpart = (rdp.cmd1>>16)/65536.0f; |
642 | rdp.combined[index_y][index_x] = (float)(int)rdp.combined[index_y][index_x]; |
643 | rdp.combined[index_y][index_x] += fpart; |
644 | |
645 | fpart = (rdp.cmd1&0xFFFF)/65536.0f; |
646 | rdp.combined[index_y][index_x+1] = (float)(int)rdp.combined[index_y][index_x+1]; |
647 | rdp.combined[index_y][index_x+1] += fpart; |
648 | } |
649 | else |
650 | { |
651 | int index_x = (rdp.cmd0 & 0x1F) >> 1; |
652 | int index_y = index_x >> 2; |
653 | index_x &= 3; |
654 | |
655 | rdp.combined[index_y][index_x] = (short)(rdp.cmd1>>16); |
656 | rdp.combined[index_y][index_x+1] = (short)(rdp.cmd1&0xFFFF); |
657 | } |
658 | |
659 | LRDP("matrix\n"); |
660 | } |
661 | break; |
662 | |
663 | case 0x02: |
664 | rdp.num_lights = data / 24; |
665 | rdp.update |= UPDATE_LIGHTS; |
c2ff96e6 |
666 | #ifdef EXTREME_LOGGING |
667 | FRDP ("numlights: %d\n", rdp.num_lights); |
668 | #endif |
98e75f2d |
669 | break; |
670 | |
671 | case 0x04: |
672 | if (offset == 0x04) |
673 | { |
674 | rdp.clip_ratio = sqrt((float)rdp.cmd1); |
675 | rdp.update |= UPDATE_VIEWPORT; |
676 | } |
c2ff96e6 |
677 | #ifdef EXTREME_LOGGING |
98e75f2d |
678 | FRDP ("mw_clip %08lx, %08lx\n", rdp.cmd0, rdp.cmd1); |
c2ff96e6 |
679 | #endif |
98e75f2d |
680 | break; |
681 | |
682 | case 0x06: // moveword SEGMENT |
683 | { |
c2ff96e6 |
684 | #ifdef EXTREME_LOGGING |
685 | FRDP ("SEGMENT %08lx -> seg%d\n", data, offset >> 2); |
686 | #endif |
98e75f2d |
687 | if ((data&BMASK)<BMASK) |
688 | rdp.segment[(offset >> 2) & 0xF] = data; |
689 | } |
690 | break; |
691 | |
692 | |
693 | case 0x08: |
694 | { |
695 | rdp.fog_multiplier = (short)(rdp.cmd1 >> 16); |
696 | rdp.fog_offset = (short)(rdp.cmd1 & 0x0000FFFF); |
c2ff96e6 |
697 | #ifdef EXTREME_LOGGING |
698 | FRDP ("fog: multiplier: %f, offset: %f\n", rdp.fog_multiplier, rdp.fog_offset); |
699 | #endif |
98e75f2d |
700 | |
701 | //offset must be 0 for move_fog, but it can be non zero in Nushi Zuri 64 - Shiokaze ni Notte |
702 | //low-level display list has setothermode commands in this place, so this is obviously not move_fog. |
703 | if (offset == 0x04) |
704 | rdp.tlut_mode = (data == 0xffffffff) ? 0 : 2; |
705 | } |
706 | break; |
707 | |
708 | case 0x0a: // moveword LIGHTCOL |
709 | { |
710 | int n = offset / 24; |
c2ff96e6 |
711 | #ifdef EXTREME_LOGGING |
98e75f2d |
712 | FRDP ("lightcol light:%d, %08lx\n", n, data); |
c2ff96e6 |
713 | #endif |
98e75f2d |
714 | |
715 | rdp.light[n].r = (float)((data >> 24) & 0xFF) / 255.0f; |
716 | rdp.light[n].g = (float)((data >> 16) & 0xFF) / 255.0f; |
717 | rdp.light[n].b = (float)((data >> 8) & 0xFF) / 255.0f; |
718 | rdp.light[n].a = 255; |
719 | } |
720 | break; |
721 | |
722 | case 0x0c: |
723 | RDP_E ("uc2:moveword forcemtx - IGNORED\n"); |
724 | LRDP("forcemtx - IGNORED\n"); |
725 | break; |
726 | |
727 | case 0x0e: |
728 | LRDP("perspnorm - IGNORED\n"); |
729 | break; |
730 | |
731 | default: |
732 | FRDP_E("uc2:moveword unknown (index: 0x%08lx, offset 0x%08lx)\n", index, offset); |
c2ff96e6 |
733 | #ifdef EXTREME_LOGGING |
98e75f2d |
734 | FRDP ("unknown (index: 0x%08lx, offset 0x%08lx)\n", index, offset); |
c2ff96e6 |
735 | #endif |
98e75f2d |
736 | } |
737 | } |
738 | |
739 | static void uc6_obj_movemem (); |
740 | |
741 | static void uc2_movemem () |
742 | { |
743 | int idx = rdp.cmd0 & 0xFF; |
744 | wxUint32 addr = segoffset(rdp.cmd1); |
745 | int ofs = (rdp.cmd0 >> 5) & 0x7F8; |
746 | |
c2ff96e6 |
747 | #ifdef EXTREME_LOGGING |
98e75f2d |
748 | FRDP ("uc2:movemem ofs:%d ", ofs); |
c2ff96e6 |
749 | #endif |
98e75f2d |
750 | |
751 | switch (idx) |
752 | { |
753 | case 0: |
754 | case 2: |
755 | uc6_obj_movemem (); |
756 | break; |
757 | |
758 | case 8: // VIEWPORT |
759 | { |
760 | wxUint32 a = addr >> 1; |
761 | short scale_x = ((short*)gfx.RDRAM)[(a+0)^1] >> 2; |
762 | short scale_y = ((short*)gfx.RDRAM)[(a+1)^1] >> 2; |
763 | short scale_z = ((short*)gfx.RDRAM)[(a+2)^1]; |
764 | short trans_x = ((short*)gfx.RDRAM)[(a+4)^1] >> 2; |
765 | short trans_y = ((short*)gfx.RDRAM)[(a+5)^1] >> 2; |
766 | short trans_z = ((short*)gfx.RDRAM)[(a+6)^1]; |
767 | rdp.view_scale[0] = scale_x * rdp.scale_x; |
768 | rdp.view_scale[1] = -scale_y * rdp.scale_y; |
769 | rdp.view_scale[2] = 32.0f * scale_z; |
770 | rdp.view_trans[0] = trans_x * rdp.scale_x; |
771 | rdp.view_trans[1] = trans_y * rdp.scale_y; |
772 | rdp.view_trans[2] = 32.0f * trans_z; |
773 | |
774 | rdp.update |= UPDATE_VIEWPORT; |
775 | |
c2ff96e6 |
776 | #ifdef EXTREME_LOGGING |
98e75f2d |
777 | FRDP ("viewport scale(%d, %d, %d), trans(%d, %d, %d), from:%08lx\n", scale_x, scale_y, scale_z, |
778 | trans_x, trans_y, trans_z, a); |
c2ff96e6 |
779 | #endif |
98e75f2d |
780 | } |
781 | break; |
782 | |
783 | case 10: // LIGHT |
784 | { |
785 | int n = ofs / 24; |
786 | |
787 | if (n < 2) |
788 | { |
789 | char dir_x = ((char*)gfx.RDRAM)[(addr+8)^3]; |
790 | rdp.lookat[n][0] = (float)(dir_x) / 127.0f; |
791 | char dir_y = ((char*)gfx.RDRAM)[(addr+9)^3]; |
792 | rdp.lookat[n][1] = (float)(dir_y) / 127.0f; |
793 | char dir_z = ((char*)gfx.RDRAM)[(addr+10)^3]; |
794 | rdp.lookat[n][2] = (float)(dir_z) / 127.0f; |
795 | rdp.use_lookat = TRUE; |
796 | if (n == 1) |
797 | { |
798 | if (!dir_x && !dir_y) |
799 | rdp.use_lookat = FALSE; |
800 | } |
c2ff96e6 |
801 | #ifdef EXTREME_LOGGING |
802 | FRDP("lookat_%d (%f, %f, %f)\n", n, rdp.lookat[n][0], rdp.lookat[n][1], rdp.lookat[n][2]); |
803 | #endif |
98e75f2d |
804 | return; |
805 | } |
806 | n -= 2; |
807 | if (n > 7) return; |
808 | |
809 | // Get the data |
810 | wxUint8 col = gfx.RDRAM[(addr+0)^3]; |
811 | rdp.light[n].r = (float)col / 255.0f; |
812 | rdp.light[n].nonblack = col; |
813 | col = gfx.RDRAM[(addr+1)^3]; |
814 | rdp.light[n].g = (float)col / 255.0f; |
815 | rdp.light[n].nonblack += col; |
816 | col = gfx.RDRAM[(addr+2)^3]; |
817 | rdp.light[n].b = (float)col / 255.0f; |
818 | rdp.light[n].nonblack += col; |
819 | rdp.light[n].a = 1.0f; |
820 | // ** Thanks to Icepir8 for pointing this out ** |
821 | // Lighting must be signed byte instead of byte |
822 | rdp.light[n].dir_x = (float)(((char*)gfx.RDRAM)[(addr+8)^3]) / 127.0f; |
823 | rdp.light[n].dir_y = (float)(((char*)gfx.RDRAM)[(addr+9)^3]) / 127.0f; |
824 | rdp.light[n].dir_z = (float)(((char*)gfx.RDRAM)[(addr+10)^3]) / 127.0f; |
825 | wxUint32 a = addr >> 1; |
826 | rdp.light[n].x = (float)(((short*)gfx.RDRAM)[(a+4)^1]); |
827 | rdp.light[n].y = (float)(((short*)gfx.RDRAM)[(a+5)^1]); |
828 | rdp.light[n].z = (float)(((short*)gfx.RDRAM)[(a+6)^1]); |
829 | rdp.light[n].ca = (float)(gfx.RDRAM[(addr+3)^3]) / 16.0f; |
830 | rdp.light[n].la = (float)(gfx.RDRAM[(addr+7)^3]); |
831 | rdp.light[n].qa = (float)(gfx.RDRAM[(addr+14)^3]) / 8.0f; |
832 | #ifdef EXTREME_LOGGING |
833 | FRDP ("light: n: %d, pos: x: %f, y: %f, z: %f, ca: %f, la:%f, qa: %f\n", |
834 | n, rdp.light[n].x, rdp.light[n].y, rdp.light[n].z, rdp.light[n].ca, rdp.light[n].la, rdp.light[n].qa); |
98e75f2d |
835 | FRDP ("light: n: %d, r: %.3f, g: %.3f, b: %.3f. dir: x: %.3f, y: %.3f, z: %.3f\n", |
836 | n, rdp.light[n].r, rdp.light[n].g, rdp.light[n].b, |
837 | rdp.light[n].dir_x, rdp.light[n].dir_y, rdp.light[n].dir_z); |
c2ff96e6 |
838 | #endif |
98e75f2d |
839 | } |
840 | break; |
841 | |
842 | case 14: // matrix |
843 | { |
844 | // do not update the combined matrix! |
845 | rdp.update &= ~UPDATE_MULT_MAT; |
846 | load_matrix(rdp.combined, segoffset(rdp.cmd1)); |
847 | |
848 | #ifdef EXTREME_LOGGING |
849 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[0][0], rdp.combined[0][1], rdp.combined[0][2], rdp.combined[0][3]); |
850 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[1][0], rdp.combined[1][1], rdp.combined[1][2], rdp.combined[1][3]); |
851 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[2][0], rdp.combined[2][1], rdp.combined[2][2], rdp.combined[2][3]); |
852 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[3][0], rdp.combined[3][1], rdp.combined[3][2], rdp.combined[3][3]); |
853 | #endif |
854 | } |
855 | break; |
856 | |
857 | default: |
858 | FRDP ("uc2:matrix unknown (%d)\n", idx); |
c2ff96e6 |
859 | #ifdef EXTREME_LOGGING |
98e75f2d |
860 | FRDP ("** UNKNOWN %d\n", idx); |
c2ff96e6 |
861 | #endif |
98e75f2d |
862 | } |
863 | } |
864 | |
865 | static void uc2_load_ucode () |
866 | { |
867 | LRDP("uc2:load_ucode\n"); |
868 | } |
869 | |
870 | static void uc2_rdphalf_2 () |
871 | { |
872 | LRDP("uc2:rdphalf_2\n"); |
873 | } |
874 | |
875 | static void uc2_dlist_cnt () |
876 | { |
877 | wxUint32 addr = segoffset(rdp.cmd1) & BMASK; |
878 | int count = rdp.cmd0 & 0x000000FF; |
c2ff96e6 |
879 | #ifdef EXTREME_LOGGING |
98e75f2d |
880 | FRDP ("dl_count - addr: %08lx, count: %d\n", addr, count); |
c2ff96e6 |
881 | #endif |
98e75f2d |
882 | if (addr == 0) |
883 | return; |
884 | |
885 | if (rdp.pc_i >= 9) { |
886 | RDP_E ("** DL stack overflow **\n"); |
887 | LRDP("** DL stack overflow **\n"); |
888 | return; |
889 | } |
890 | rdp.pc_i ++; // go to the next PC in the stack |
891 | rdp.pc[rdp.pc_i] = addr; // jump to the address |
892 | rdp.dl_count = count + 1; |
893 | } |