| 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 | } |