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 | |
123 | FRDP ("uc2:vertex n: %d, v0: %d, from: %08lx\n", n, v0, addr); |
124 | |
125 | if (v0 < 0) |
126 | { |
127 | RDP_E ("** ERROR: uc2:vertex v0 < 0\n"); |
128 | LRDP("** ERROR: uc2:vertex v0 < 0\n"); |
129 | return; |
130 | } |
131 | |
132 | wxUint32 geom_mode = rdp.geom_mode; |
133 | if ((settings.hacks&hack_Fzero) && (rdp.geom_mode & 0x40000)) |
134 | { |
135 | if (((short*)gfx.RDRAM)[(((addr) >> 1) + 4)^1] || ((short*)gfx.RDRAM)[(((addr) >> 1) + 5)^1]) |
136 | rdp.geom_mode ^= 0x40000; |
137 | } |
138 | #ifdef __ARM_NEON__ |
139 | float32x4_t comb0, comb1, comb2, comb3; |
140 | float32x4_t v_xyzw; |
141 | comb0 = vld1q_f32(rdp.combined[0]); |
142 | comb1 = vld1q_f32(rdp.combined[1]); |
143 | comb2 = vld1q_f32(rdp.combined[2]); |
144 | comb3 = vld1q_f32(rdp.combined[3]); |
145 | #endif |
146 | for (i=0; i < (n<<4); i+=16) |
147 | { |
148 | VERTEX *v = &rdp.vtx[v0 + (i>>4)]; |
149 | x = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 0)^1]; |
150 | y = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 1)^1]; |
151 | z = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 2)^1]; |
152 | v->flags = ((wxUint16*)gfx.RDRAM)[(((addr+i) >> 1) + 3)^1]; |
153 | v->ou = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 4)^1]; |
154 | v->ov = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 5)^1]; |
155 | v->uv_scaled = 0; |
156 | v->a = ((wxUint8*)gfx.RDRAM)[(addr+i + 15)^3]; |
157 | |
158 | #ifdef __ARM_NEON__ |
159 | v_xyzw = x*comb0+y*comb1+z*comb2+comb3; |
160 | //vst1q_f32((float*)v, v_xyzw); |
161 | v->x=v_xyzw[0]; |
162 | v->y=v_xyzw[1]; |
163 | v->z=v_xyzw[2]; |
164 | v->w=v_xyzw[3]; |
165 | #else |
166 | v->x = x*rdp.combined[0][0] + y*rdp.combined[1][0] + z*rdp.combined[2][0] + rdp.combined[3][0]; |
167 | v->y = x*rdp.combined[0][1] + y*rdp.combined[1][1] + z*rdp.combined[2][1] + rdp.combined[3][1]; |
168 | v->z = x*rdp.combined[0][2] + y*rdp.combined[1][2] + z*rdp.combined[2][2] + rdp.combined[3][2]; |
169 | v->w = x*rdp.combined[0][3] + y*rdp.combined[1][3] + z*rdp.combined[2][3] + rdp.combined[3][3]; |
170 | #endif |
171 | |
172 | v->uv_calculated = 0xFFFFFFFF; |
173 | v->screen_translated = 0; |
174 | v->shade_mod = 0; |
175 | |
176 | if (fabs(v->w) < 0.001) v->w = 0.001f; |
177 | v->oow = 1.0f / v->w; |
178 | #ifdef __ARM_NEON__ |
179 | v_xyzw *= v->oow; |
180 | v->x_w=v_xyzw[0]; |
181 | v->y_w=v_xyzw[1]; |
182 | v->z_w=v_xyzw[2]; |
183 | #else |
184 | v->x_w = v->x * v->oow; |
185 | v->y_w = v->y * v->oow; |
186 | v->z_w = v->z * v->oow; |
187 | #endif |
188 | CalculateFog (v); |
189 | |
190 | |
191 | v->scr_off = 0; |
192 | if (v->x < -v->w) v->scr_off |= 1; |
193 | if (v->x > v->w) v->scr_off |= 2; |
194 | if (v->y < -v->w) v->scr_off |= 4; |
195 | if (v->y > v->w) v->scr_off |= 8; |
196 | if (v->w < 0.1f) v->scr_off |= 16; |
197 | // if (v->z_w > 1.0f) v->scr_off |= 32; |
198 | |
199 | if (rdp.geom_mode & 0x00020000) |
200 | { |
201 | v->vec[0] = ((char*)gfx.RDRAM)[(addr+i + 12)^3]; |
202 | v->vec[1] = ((char*)gfx.RDRAM)[(addr+i + 13)^3]; |
203 | v->vec[2] = ((char*)gfx.RDRAM)[(addr+i + 14)^3]; |
204 | // FRDP("Calc light. x: %f, y: %f z: %f\n", v->vec[0], v->vec[1], v->vec[2]); |
205 | // if (!(rdp.geom_mode & 0x800000)) |
206 | { |
207 | if (rdp.geom_mode & 0x40000) |
208 | { |
209 | if (rdp.geom_mode & 0x80000) |
210 | { |
211 | calc_linear (v); |
212 | #ifdef EXTREME_LOGGING |
213 | FRDP ("calc linear: v%d - u: %f, v: %f\n", i>>4, v->ou, v->ov); |
214 | #endif |
215 | } |
216 | else |
217 | { |
218 | calc_sphere (v); |
219 | #ifdef EXTREME_LOGGING |
220 | FRDP ("calc sphere: v%d - u: %f, v: %f\n", i>>4, v->ou, v->ov); |
221 | #endif |
222 | } |
223 | } |
224 | } |
225 | if (rdp.geom_mode & 0x00400000) |
226 | { |
227 | float tmpvec[3] = {x, y, z}; |
228 | calc_point_light (v, tmpvec); |
229 | } |
230 | else |
231 | { |
232 | NormalizeVector (v->vec); |
233 | calc_light (v); |
234 | } |
235 | } |
236 | else |
237 | { |
238 | v->r = ((wxUint8*)gfx.RDRAM)[(addr+i + 12)^3]; |
239 | v->g = ((wxUint8*)gfx.RDRAM)[(addr+i + 13)^3]; |
240 | v->b = ((wxUint8*)gfx.RDRAM)[(addr+i + 14)^3]; |
241 | } |
242 | #ifdef EXTREME_LOGGING |
243 | 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); |
244 | #endif |
245 | } |
246 | rdp.geom_mode = geom_mode; |
247 | } |
248 | |
249 | static void uc2_modifyvtx () |
250 | { |
251 | Check_FrameSkip; |
252 | |
253 | wxUint8 where = (wxUint8)((rdp.cmd0 >> 16) & 0xFF); |
254 | wxUint16 vtx = (wxUint16)((rdp.cmd0 >> 1) & 0xFFFF); |
255 | |
256 | FRDP ("uc2:modifyvtx: vtx: %d, where: 0x%02lx, val: %08lx - ", vtx, where, rdp.cmd1); |
257 | uc0_modifyvtx(where, vtx, rdp.cmd1); |
258 | } |
259 | |
260 | static void uc2_culldl () |
261 | { |
262 | wxUint16 vStart = (wxUint16)(rdp.cmd0 & 0xFFFF) >> 1; |
263 | wxUint16 vEnd = (wxUint16)(rdp.cmd1 & 0xFFFF) >> 1; |
264 | wxUint32 cond = 0; |
265 | FRDP ("uc2:culldl start: %d, end: %d\n", vStart, vEnd); |
266 | |
267 | if (vEnd < vStart) return; |
268 | for (wxUint16 i=vStart; i<=vEnd; i++) |
269 | { |
270 | /* |
271 | VERTEX v = &rdp.vtx[i]; |
272 | // Check if completely off the screen (quick frustrum clipping for 90 FOV) |
273 | if (v->x >= -v->w) |
274 | cond |= 0x01; |
275 | if (v->x <= v->w) |
276 | cond |= 0x02; |
277 | if (v->y >= -v->w) |
278 | cond |= 0x04; |
279 | if (v->y <= v->w) |
280 | cond |= 0x08; |
281 | if (v->w >= 0.1f) |
282 | cond |= 0x10; |
283 | |
284 | if (cond == 0x1F) |
285 | return; |
286 | //*/ |
287 | |
288 | #ifdef EXTREME_LOGGING |
289 | 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); |
290 | #endif |
291 | |
292 | cond |= (~rdp.vtx[i].scr_off) & 0x1F; |
293 | if (cond == 0x1F) |
294 | return; |
295 | } |
296 | |
297 | LRDP(" - "); // specify that the enddl is not a real command |
298 | uc0_enddl (); |
299 | } |
300 | |
301 | static void uc6_obj_loadtxtr (); |
302 | |
303 | static void uc2_tri1() |
304 | { |
305 | Check_FrameSkip; |
306 | |
307 | if ((rdp.cmd0 & 0x00FFFFFF) == 0x17) |
308 | { |
309 | uc6_obj_loadtxtr (); |
310 | return; |
311 | } |
312 | if (rdp.skip_drawing) |
313 | { |
314 | LRDP("uc2:tri1. skipped\n"); |
315 | return; |
316 | } |
317 | |
318 | FRDP("uc2:tri1 #%d - %d, %d, %d\n", rdp.tri_n, |
319 | ((rdp.cmd0 >> 17) & 0x7F), |
320 | ((rdp.cmd0 >> 9) & 0x7F), |
321 | ((rdp.cmd0 >> 1) & 0x7F)); |
322 | |
323 | VERTEX *v[3] = { |
324 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
325 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
326 | &rdp.vtx[(rdp.cmd0 >> 1) & 0x7F] |
327 | }; |
328 | |
329 | rsp_tri1(v); |
330 | } |
331 | |
332 | static void uc6_obj_ldtx_sprite (); |
333 | static void uc6_obj_ldtx_rect (); |
334 | |
335 | static void uc2_quad () |
336 | { |
337 | Check_FrameSkip; |
338 | |
339 | if ((rdp.cmd0 & 0x00FFFFFF) == 0x2F) |
340 | { |
341 | wxUint32 command = rdp.cmd0>>24; |
342 | if (command == 0x6) |
343 | { |
344 | uc6_obj_ldtx_sprite (); |
345 | return; |
346 | } |
347 | if (command == 0x7) |
348 | { |
349 | uc6_obj_ldtx_rect (); |
350 | return; |
351 | } |
352 | } |
353 | |
354 | if (rdp.skip_drawing) |
355 | { |
356 | LRDP("uc2_quad. skipped\n"); |
357 | return; |
358 | } |
359 | |
360 | LRDP("uc2:quad"); |
361 | |
362 | FRDP(" #%d, #%d - %d, %d, %d - %d, %d, %d\n", rdp.tri_n, rdp.tri_n+1, |
363 | ((rdp.cmd0 >> 17) & 0x7F), |
364 | ((rdp.cmd0 >> 9) & 0x7F), |
365 | ((rdp.cmd0 >> 1) & 0x7F), |
366 | ((rdp.cmd1 >> 17) & 0x7F), |
367 | ((rdp.cmd1 >> 9) & 0x7F), |
368 | ((rdp.cmd1 >> 1) & 0x7F)); |
369 | |
370 | VERTEX *v[6] = { |
371 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
372 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
373 | &rdp.vtx[(rdp.cmd0 >> 1) & 0x7F], |
374 | &rdp.vtx[(rdp.cmd1 >> 17) & 0x7F], |
375 | &rdp.vtx[(rdp.cmd1 >> 9) & 0x7F], |
376 | &rdp.vtx[(rdp.cmd1 >> 1) & 0x7F] |
377 | }; |
378 | |
379 | rsp_tri2(v); |
380 | } |
381 | |
382 | static void uc6_ldtx_rect_r (); |
383 | |
384 | static void uc2_line3d () |
385 | { |
386 | Check_FrameSkip; |
387 | |
388 | if ( (rdp.cmd0&0xFF) == 0x2F ) |
389 | uc6_ldtx_rect_r (); |
390 | else |
391 | { |
392 | FRDP("uc2:line3d #%d, #%d - %d, %d\n", rdp.tri_n, rdp.tri_n+1, |
393 | (rdp.cmd0 >> 17) & 0x7F, |
394 | (rdp.cmd0 >> 9) & 0x7F); |
395 | |
396 | VERTEX *v[3] = { |
397 | &rdp.vtx[(rdp.cmd0 >> 17) & 0x7F], |
398 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F], |
399 | &rdp.vtx[(rdp.cmd0 >> 9) & 0x7F] |
400 | }; |
401 | wxUint16 width = (wxUint16)(rdp.cmd0 + 3)&0xFF; |
402 | wxUint32 cull_mode = (rdp.flags & CULLMASK) >> CULLSHIFT; |
403 | rdp.flags |= CULLMASK; |
404 | rdp.update |= UPDATE_CULL_MODE; |
405 | rsp_tri1(v, width); |
406 | rdp.flags ^= CULLMASK; |
407 | rdp.flags |= cull_mode << CULLSHIFT; |
408 | rdp.update |= UPDATE_CULL_MODE; |
409 | } |
410 | } |
411 | |
412 | static void uc2_special3 () |
413 | { |
414 | LRDP("uc2:special3\n"); |
415 | } |
416 | |
417 | static void uc2_special2 () |
418 | { |
419 | LRDP("uc2:special2\n"); |
420 | } |
421 | |
422 | static void uc2_dma_io () |
423 | { |
424 | LRDP("uc2:dma_io\n"); |
425 | } |
426 | |
427 | static void uc2_pop_matrix () |
428 | { |
429 | FRDP ("uc2:pop_matrix %08lx, %08lx\n", rdp.cmd0, rdp.cmd1); |
430 | |
431 | // Just pop the modelview matrix |
432 | modelview_pop (rdp.cmd1 >> 6); |
433 | } |
434 | |
435 | static void uc2_geom_mode () |
436 | { |
437 | // Switch around some things |
438 | wxUint32 clr_mode = (rdp.cmd0 & 0x00DFC9FF) | |
439 | ((rdp.cmd0 & 0x00000600) << 3) | |
440 | ((rdp.cmd0 & 0x00200000) >> 12) | 0xFF000000; |
441 | wxUint32 set_mode = (rdp.cmd1 & 0xFFDFC9FF) | |
442 | ((rdp.cmd1 & 0x00000600) << 3) | |
443 | ((rdp.cmd1 & 0x00200000) >> 12); |
444 | |
445 | FRDP("uc2:geom_mode c:%08lx, s:%08lx ", clr_mode, set_mode); |
446 | |
447 | rdp.geom_mode &= clr_mode; |
448 | rdp.geom_mode |= set_mode; |
449 | |
450 | FRDP ("result:%08lx\n", rdp.geom_mode); |
451 | |
452 | if (rdp.geom_mode & 0x00000001) // Z-Buffer enable |
453 | { |
454 | if (!(rdp.flags & ZBUF_ENABLED)) |
455 | { |
456 | rdp.flags |= ZBUF_ENABLED; |
457 | rdp.update |= UPDATE_ZBUF_ENABLED; |
458 | } |
459 | } |
460 | else |
461 | { |
462 | if ((rdp.flags & ZBUF_ENABLED)) |
463 | { |
464 | if (!settings.flame_corona || (rdp.rm != 0x00504341)) //hack for flame's corona |
465 | rdp.flags ^= ZBUF_ENABLED; |
466 | rdp.update |= UPDATE_ZBUF_ENABLED; |
467 | } |
468 | } |
469 | if (rdp.geom_mode & 0x00001000) // Front culling |
470 | { |
471 | if (!(rdp.flags & CULL_FRONT)) |
472 | { |
473 | rdp.flags |= CULL_FRONT; |
474 | rdp.update |= UPDATE_CULL_MODE; |
475 | } |
476 | } |
477 | else |
478 | { |
479 | if (rdp.flags & CULL_FRONT) |
480 | { |
481 | rdp.flags ^= CULL_FRONT; |
482 | rdp.update |= UPDATE_CULL_MODE; |
483 | } |
484 | } |
485 | if (rdp.geom_mode & 0x00002000) // Back culling |
486 | { |
487 | if (!(rdp.flags & CULL_BACK)) |
488 | { |
489 | rdp.flags |= CULL_BACK; |
490 | rdp.update |= UPDATE_CULL_MODE; |
491 | } |
492 | } |
493 | else |
494 | { |
495 | if (rdp.flags & CULL_BACK) |
496 | { |
497 | rdp.flags ^= CULL_BACK; |
498 | rdp.update |= UPDATE_CULL_MODE; |
499 | } |
500 | } |
501 | |
502 | //Added by Gonetz |
503 | if (rdp.geom_mode & 0x00010000) // Fog enable |
504 | { |
505 | if (!(rdp.flags & FOG_ENABLED)) |
506 | { |
507 | rdp.flags |= FOG_ENABLED; |
508 | rdp.update |= UPDATE_FOG_ENABLED; |
509 | } |
510 | } |
511 | else |
512 | { |
513 | if (rdp.flags & FOG_ENABLED) |
514 | { |
515 | rdp.flags ^= FOG_ENABLED; |
516 | rdp.update |= UPDATE_FOG_ENABLED; |
517 | } |
518 | } |
519 | } |
520 | |
521 | static void uc6_obj_rectangle_r (); |
522 | |
523 | static void uc2_matrix () |
524 | { |
525 | if (!(rdp.cmd0 & 0x00FFFFFF)) |
526 | { |
527 | uc6_obj_rectangle_r(); |
528 | return; |
529 | } |
530 | LRDP("uc2:matrix\n"); |
531 | |
532 | DECLAREALIGN16VAR(m[4][4]); |
533 | load_matrix(m, segoffset(rdp.cmd1)); |
534 | |
535 | wxUint8 command = (wxUint8)((rdp.cmd0 ^ 1) & 0xFF); |
536 | switch (command) |
537 | { |
538 | case 0: // modelview mul nopush |
539 | LRDP("modelview mul\n"); |
540 | modelview_mul (m); |
541 | break; |
542 | |
543 | case 1: // modelview mul push |
544 | LRDP("modelview mul push\n"); |
545 | modelview_mul_push (m); |
546 | break; |
547 | |
548 | case 2: // modelview load nopush |
549 | LRDP("modelview load\n"); |
550 | modelview_load (m); |
551 | break; |
552 | |
553 | case 3: // modelview load push |
554 | LRDP("modelview load push\n"); |
555 | modelview_load_push (m); |
556 | break; |
557 | |
558 | case 4: // projection mul nopush |
559 | case 5: // projection mul push, can't push projection |
560 | LRDP("projection mul\n"); |
561 | projection_mul (m); |
562 | break; |
563 | |
564 | case 6: // projection load nopush |
565 | case 7: // projection load push, can't push projection |
566 | LRDP("projection load\n"); |
567 | projection_load (m); |
568 | break; |
569 | |
570 | default: |
571 | FRDP_E ("Unknown matrix command, %02lx", command); |
572 | FRDP ("Unknown matrix command, %02lx", command); |
573 | } |
574 | |
575 | #ifdef EXTREME_LOGGING |
576 | FRDP ("{%f,%f,%f,%f}\n", m[0][0], m[0][1], m[0][2], m[0][3]); |
577 | FRDP ("{%f,%f,%f,%f}\n", m[1][0], m[1][1], m[1][2], m[1][3]); |
578 | FRDP ("{%f,%f,%f,%f}\n", m[2][0], m[2][1], m[2][2], m[2][3]); |
579 | FRDP ("{%f,%f,%f,%f}\n", m[3][0], m[3][1], m[3][2], m[3][3]); |
580 | FRDP ("\nmodel\n{%f,%f,%f,%f}\n", rdp.model[0][0], rdp.model[0][1], rdp.model[0][2], rdp.model[0][3]); |
581 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[1][0], rdp.model[1][1], rdp.model[1][2], rdp.model[1][3]); |
582 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[2][0], rdp.model[2][1], rdp.model[2][2], rdp.model[2][3]); |
583 | FRDP ("{%f,%f,%f,%f}\n", rdp.model[3][0], rdp.model[3][1], rdp.model[3][2], rdp.model[3][3]); |
584 | FRDP ("\nproj\n{%f,%f,%f,%f}\n", rdp.proj[0][0], rdp.proj[0][1], rdp.proj[0][2], rdp.proj[0][3]); |
585 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[1][0], rdp.proj[1][1], rdp.proj[1][2], rdp.proj[1][3]); |
586 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[2][0], rdp.proj[2][1], rdp.proj[2][2], rdp.proj[2][3]); |
587 | FRDP ("{%f,%f,%f,%f}\n", rdp.proj[3][0], rdp.proj[3][1], rdp.proj[3][2], rdp.proj[3][3]); |
588 | #endif |
589 | } |
590 | |
591 | static void uc2_moveword () |
592 | { |
593 | wxUint8 index = (wxUint8)((rdp.cmd0 >> 16) & 0xFF); |
594 | wxUint16 offset = (wxUint16)(rdp.cmd0 & 0xFFFF); |
595 | wxUint32 data = rdp.cmd1; |
596 | |
597 | FRDP ("uc2:moveword "); |
598 | |
599 | switch (index) |
600 | { |
601 | // NOTE: right now it's assuming that it sets the integer part first. This could |
602 | // be easily fixed, but only if i had something to test with. |
603 | |
604 | case 0x00: // moveword matrix |
605 | { |
606 | // do matrix pre-mult so it's re-updated next time |
607 | if (rdp.update & UPDATE_MULT_MAT) |
608 | { |
609 | rdp.update ^= UPDATE_MULT_MAT; |
610 | MulMatrices(rdp.model, rdp.proj, rdp.combined); |
611 | } |
612 | |
613 | if (rdp.cmd0 & 0x20) // fractional part |
614 | { |
615 | int index_x = (rdp.cmd0 & 0x1F) >> 1; |
616 | int index_y = index_x >> 2; |
617 | index_x &= 3; |
618 | |
619 | float fpart = (rdp.cmd1>>16)/65536.0f; |
620 | rdp.combined[index_y][index_x] = (float)(int)rdp.combined[index_y][index_x]; |
621 | rdp.combined[index_y][index_x] += fpart; |
622 | |
623 | fpart = (rdp.cmd1&0xFFFF)/65536.0f; |
624 | rdp.combined[index_y][index_x+1] = (float)(int)rdp.combined[index_y][index_x+1]; |
625 | rdp.combined[index_y][index_x+1] += fpart; |
626 | } |
627 | else |
628 | { |
629 | int index_x = (rdp.cmd0 & 0x1F) >> 1; |
630 | int index_y = index_x >> 2; |
631 | index_x &= 3; |
632 | |
633 | rdp.combined[index_y][index_x] = (short)(rdp.cmd1>>16); |
634 | rdp.combined[index_y][index_x+1] = (short)(rdp.cmd1&0xFFFF); |
635 | } |
636 | |
637 | LRDP("matrix\n"); |
638 | } |
639 | break; |
640 | |
641 | case 0x02: |
642 | rdp.num_lights = data / 24; |
643 | rdp.update |= UPDATE_LIGHTS; |
644 | FRDP ("numlights: %d\n", rdp.num_lights); |
645 | break; |
646 | |
647 | case 0x04: |
648 | if (offset == 0x04) |
649 | { |
650 | rdp.clip_ratio = sqrt((float)rdp.cmd1); |
651 | rdp.update |= UPDATE_VIEWPORT; |
652 | } |
653 | FRDP ("mw_clip %08lx, %08lx\n", rdp.cmd0, rdp.cmd1); |
654 | break; |
655 | |
656 | case 0x06: // moveword SEGMENT |
657 | { |
658 | FRDP ("SEGMENT %08lx -> seg%d\n", data, offset >> 2); |
659 | if ((data&BMASK)<BMASK) |
660 | rdp.segment[(offset >> 2) & 0xF] = data; |
661 | } |
662 | break; |
663 | |
664 | |
665 | case 0x08: |
666 | { |
667 | rdp.fog_multiplier = (short)(rdp.cmd1 >> 16); |
668 | rdp.fog_offset = (short)(rdp.cmd1 & 0x0000FFFF); |
669 | FRDP ("fog: multiplier: %f, offset: %f\n", rdp.fog_multiplier, rdp.fog_offset); |
670 | |
671 | //offset must be 0 for move_fog, but it can be non zero in Nushi Zuri 64 - Shiokaze ni Notte |
672 | //low-level display list has setothermode commands in this place, so this is obviously not move_fog. |
673 | if (offset == 0x04) |
674 | rdp.tlut_mode = (data == 0xffffffff) ? 0 : 2; |
675 | } |
676 | break; |
677 | |
678 | case 0x0a: // moveword LIGHTCOL |
679 | { |
680 | int n = offset / 24; |
681 | FRDP ("lightcol light:%d, %08lx\n", n, data); |
682 | |
683 | rdp.light[n].r = (float)((data >> 24) & 0xFF) / 255.0f; |
684 | rdp.light[n].g = (float)((data >> 16) & 0xFF) / 255.0f; |
685 | rdp.light[n].b = (float)((data >> 8) & 0xFF) / 255.0f; |
686 | rdp.light[n].a = 255; |
687 | } |
688 | break; |
689 | |
690 | case 0x0c: |
691 | RDP_E ("uc2:moveword forcemtx - IGNORED\n"); |
692 | LRDP("forcemtx - IGNORED\n"); |
693 | break; |
694 | |
695 | case 0x0e: |
696 | LRDP("perspnorm - IGNORED\n"); |
697 | break; |
698 | |
699 | default: |
700 | FRDP_E("uc2:moveword unknown (index: 0x%08lx, offset 0x%08lx)\n", index, offset); |
701 | FRDP ("unknown (index: 0x%08lx, offset 0x%08lx)\n", index, offset); |
702 | } |
703 | } |
704 | |
705 | static void uc6_obj_movemem (); |
706 | |
707 | static void uc2_movemem () |
708 | { |
709 | int idx = rdp.cmd0 & 0xFF; |
710 | wxUint32 addr = segoffset(rdp.cmd1); |
711 | int ofs = (rdp.cmd0 >> 5) & 0x7F8; |
712 | |
713 | FRDP ("uc2:movemem ofs:%d ", ofs); |
714 | |
715 | switch (idx) |
716 | { |
717 | case 0: |
718 | case 2: |
719 | uc6_obj_movemem (); |
720 | break; |
721 | |
722 | case 8: // VIEWPORT |
723 | { |
724 | wxUint32 a = addr >> 1; |
725 | short scale_x = ((short*)gfx.RDRAM)[(a+0)^1] >> 2; |
726 | short scale_y = ((short*)gfx.RDRAM)[(a+1)^1] >> 2; |
727 | short scale_z = ((short*)gfx.RDRAM)[(a+2)^1]; |
728 | short trans_x = ((short*)gfx.RDRAM)[(a+4)^1] >> 2; |
729 | short trans_y = ((short*)gfx.RDRAM)[(a+5)^1] >> 2; |
730 | short trans_z = ((short*)gfx.RDRAM)[(a+6)^1]; |
731 | rdp.view_scale[0] = scale_x * rdp.scale_x; |
732 | rdp.view_scale[1] = -scale_y * rdp.scale_y; |
733 | rdp.view_scale[2] = 32.0f * scale_z; |
734 | rdp.view_trans[0] = trans_x * rdp.scale_x; |
735 | rdp.view_trans[1] = trans_y * rdp.scale_y; |
736 | rdp.view_trans[2] = 32.0f * trans_z; |
737 | |
738 | rdp.update |= UPDATE_VIEWPORT; |
739 | |
740 | FRDP ("viewport scale(%d, %d, %d), trans(%d, %d, %d), from:%08lx\n", scale_x, scale_y, scale_z, |
741 | trans_x, trans_y, trans_z, a); |
742 | } |
743 | break; |
744 | |
745 | case 10: // LIGHT |
746 | { |
747 | int n = ofs / 24; |
748 | |
749 | if (n < 2) |
750 | { |
751 | char dir_x = ((char*)gfx.RDRAM)[(addr+8)^3]; |
752 | rdp.lookat[n][0] = (float)(dir_x) / 127.0f; |
753 | char dir_y = ((char*)gfx.RDRAM)[(addr+9)^3]; |
754 | rdp.lookat[n][1] = (float)(dir_y) / 127.0f; |
755 | char dir_z = ((char*)gfx.RDRAM)[(addr+10)^3]; |
756 | rdp.lookat[n][2] = (float)(dir_z) / 127.0f; |
757 | rdp.use_lookat = TRUE; |
758 | if (n == 1) |
759 | { |
760 | if (!dir_x && !dir_y) |
761 | rdp.use_lookat = FALSE; |
762 | } |
763 | FRDP("lookat_%d (%f, %f, %f)\n", n, rdp.lookat[n][0], rdp.lookat[n][1], rdp.lookat[n][2]); |
764 | return; |
765 | } |
766 | n -= 2; |
767 | if (n > 7) return; |
768 | |
769 | // Get the data |
770 | wxUint8 col = gfx.RDRAM[(addr+0)^3]; |
771 | rdp.light[n].r = (float)col / 255.0f; |
772 | rdp.light[n].nonblack = col; |
773 | col = gfx.RDRAM[(addr+1)^3]; |
774 | rdp.light[n].g = (float)col / 255.0f; |
775 | rdp.light[n].nonblack += col; |
776 | col = gfx.RDRAM[(addr+2)^3]; |
777 | rdp.light[n].b = (float)col / 255.0f; |
778 | rdp.light[n].nonblack += col; |
779 | rdp.light[n].a = 1.0f; |
780 | // ** Thanks to Icepir8 for pointing this out ** |
781 | // Lighting must be signed byte instead of byte |
782 | rdp.light[n].dir_x = (float)(((char*)gfx.RDRAM)[(addr+8)^3]) / 127.0f; |
783 | rdp.light[n].dir_y = (float)(((char*)gfx.RDRAM)[(addr+9)^3]) / 127.0f; |
784 | rdp.light[n].dir_z = (float)(((char*)gfx.RDRAM)[(addr+10)^3]) / 127.0f; |
785 | wxUint32 a = addr >> 1; |
786 | rdp.light[n].x = (float)(((short*)gfx.RDRAM)[(a+4)^1]); |
787 | rdp.light[n].y = (float)(((short*)gfx.RDRAM)[(a+5)^1]); |
788 | rdp.light[n].z = (float)(((short*)gfx.RDRAM)[(a+6)^1]); |
789 | rdp.light[n].ca = (float)(gfx.RDRAM[(addr+3)^3]) / 16.0f; |
790 | rdp.light[n].la = (float)(gfx.RDRAM[(addr+7)^3]); |
791 | rdp.light[n].qa = (float)(gfx.RDRAM[(addr+14)^3]) / 8.0f; |
792 | #ifdef EXTREME_LOGGING |
793 | FRDP ("light: n: %d, pos: x: %f, y: %f, z: %f, ca: %f, la:%f, qa: %f\n", |
794 | 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); |
795 | #endif |
796 | FRDP ("light: n: %d, r: %.3f, g: %.3f, b: %.3f. dir: x: %.3f, y: %.3f, z: %.3f\n", |
797 | n, rdp.light[n].r, rdp.light[n].g, rdp.light[n].b, |
798 | rdp.light[n].dir_x, rdp.light[n].dir_y, rdp.light[n].dir_z); |
799 | } |
800 | break; |
801 | |
802 | case 14: // matrix |
803 | { |
804 | // do not update the combined matrix! |
805 | rdp.update &= ~UPDATE_MULT_MAT; |
806 | load_matrix(rdp.combined, segoffset(rdp.cmd1)); |
807 | |
808 | #ifdef EXTREME_LOGGING |
809 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[0][0], rdp.combined[0][1], rdp.combined[0][2], rdp.combined[0][3]); |
810 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[1][0], rdp.combined[1][1], rdp.combined[1][2], rdp.combined[1][3]); |
811 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[2][0], rdp.combined[2][1], rdp.combined[2][2], rdp.combined[2][3]); |
812 | FRDP ("{%f,%f,%f,%f}\n", rdp.combined[3][0], rdp.combined[3][1], rdp.combined[3][2], rdp.combined[3][3]); |
813 | #endif |
814 | } |
815 | break; |
816 | |
817 | default: |
818 | FRDP ("uc2:matrix unknown (%d)\n", idx); |
819 | FRDP ("** UNKNOWN %d\n", idx); |
820 | } |
821 | } |
822 | |
823 | static void uc2_load_ucode () |
824 | { |
825 | LRDP("uc2:load_ucode\n"); |
826 | } |
827 | |
828 | static void uc2_rdphalf_2 () |
829 | { |
830 | LRDP("uc2:rdphalf_2\n"); |
831 | } |
832 | |
833 | static void uc2_dlist_cnt () |
834 | { |
835 | wxUint32 addr = segoffset(rdp.cmd1) & BMASK; |
836 | int count = rdp.cmd0 & 0x000000FF; |
837 | FRDP ("dl_count - addr: %08lx, count: %d\n", addr, count); |
838 | if (addr == 0) |
839 | return; |
840 | |
841 | if (rdp.pc_i >= 9) { |
842 | RDP_E ("** DL stack overflow **\n"); |
843 | LRDP("** DL stack overflow **\n"); |
844 | return; |
845 | } |
846 | rdp.pc_i ++; // go to the next PC in the stack |
847 | rdp.pc[rdp.pc_i] = addr; // jump to the address |
848 | rdp.dl_count = count + 1; |
849 | } |