Path: blob/master/libmupen64plus/mupen64plus-video-glide64/src/Ucode00.h
2 views
/*1* Glide64 - Glide video plugin for Nintendo 64 emulators.2* Copyright (c) 2002 Dave20013*4* This program is free software; you can redistribute it and/or modify5* it under the terms of the GNU General Public License as published by6* the Free Software Foundation; either version 2 of the License, or7* any later version.8*9* This program is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12* GNU General Public License for more details.13*14* You should have received a copy of the GNU General Public15* License along with this program; if not, write to the Free16* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,17* Boston, MA 02110-1301, USA18*/1920//****************************************************************21//22// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)23// Project started on December 29th, 200124//25// To modify Glide64:26// * 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.27// * 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.28//29// Official Glide64 development channel: #Glide64 on EFnet30//31// Original author: Dave2001 ([email protected])32// Other authors: Gonetz, Gugaman33//34//****************************************************************3536#include <string.h>37#ifdef GCC38#include <stdint.h>39#define __int32 int32_t40#endif4142static void uc0_enddl();4344// ** Definitions **4546//47// matrix functions ***** SWITCH TO POINTERS LATER ******48//4950void modelview_load (float m[4][4])51{52memcpy (rdp.model, m, 64); // 4*4*4(float)5354rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS;55}5657void modelview_mul (float m[4][4])58{59__declspec( align(16) ) float m_src[4][4];60memcpy (m_src, rdp.model, 64);61MulMatrices(m, m_src, rdp.model);62rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS;63}6465void modelview_push ()66{67if (rdp.model_i == rdp.model_stack_size)68{69RDP_E ("** Model matrix stack overflow ** too many pushes\n");70RDP ("** Model matrix stack overflow ** too many pushes\n");71return;72}7374memcpy (rdp.model_stack[rdp.model_i], rdp.model, 64);75rdp.model_i ++;76}7778void modelview_pop (int num = 1)79{80if (rdp.model_i > num - 1)81{82rdp.model_i -= num;83}84else85{86RDP_E ("** Model matrix stack error ** too many pops\n");87RDP ("** Model matrix stack error ** too many pops\n");88return;89}90memcpy (rdp.model, rdp.model_stack[rdp.model_i], 64);91rdp.update |= UPDATE_MULT_MAT | UPDATE_LIGHTS;92}9394void modelview_load_push (float m[4][4])95{96modelview_push ();97modelview_load (m);98}99100void modelview_mul_push (float m[4][4])101{102modelview_push ();103modelview_mul (m);104}105106void projection_load (float m[4][4])107{108memcpy (rdp.proj, m, 64); // 4*4*4(float)109110rdp.update |= UPDATE_MULT_MAT;111}112113void projection_mul (float m[4][4])114{115__declspec( align(16) ) float m_src[4][4];116memcpy (m_src, rdp.proj, 64);117MulMatrices(m, m_src, rdp.proj);118rdp.update |= UPDATE_MULT_MAT;119}120121//122// uc0:matrix - performs matrix operations123//124125static void uc0_matrix()126{127RDP("uc0:matrix ");128129// Use segment offset to get the address130DWORD addr = segoffset(rdp.cmd1) & 0x00FFFFFF;131BYTE command = (BYTE)((rdp.cmd0 >> 16) & 0xFF);132133__declspec( align(16) ) float m[4][4];134int x,y; // matrix index135136addr >>= 1;137138for (x=0; x<16; x+=4) { // Adding 4 instead of one, just to remove mult. later139for (y=0; y<4; y++) {140m[x>>2][y] = (float)(141(((__int32)((WORD*)gfx.RDRAM)[(addr+x+y)^1]) << 16) |142((WORD*)gfx.RDRAM)[(addr+x+y+16)^1]143) / 65536.0f;144}145}146147switch (command)148{149case 0: // modelview mul nopush150RDP ("modelview mul\n");151modelview_mul (m);152break;153154case 1: // projection mul nopush155case 5: // projection mul push, can't push projection156RDP ("projection mul\n");157projection_mul (m);158break;159160case 2: // modelview load nopush161RDP ("modelview load\n");162modelview_load (m);163break;164165case 3: // projection load nopush166case 7: // projection load push, can't push projection167RDP ("projection load\n");168projection_load (m);169170break;171172case 4: // modelview mul push173RDP ("modelview mul push\n");174modelview_mul_push (m);175break;176177case 6: // modelview load push178RDP ("modelview load push\n");179modelview_load_push (m);180break;181182default:183FRDP_E ("Unknown matrix command, %02lx", command);184FRDP ("Unknown matrix command, %02lx", command);185}186187#ifdef EXTREME_LOGGING188FRDP ("{%f,%f,%f,%f}\n", m[0][0], m[0][1], m[0][2], m[0][3]);189FRDP ("{%f,%f,%f,%f}\n", m[1][0], m[1][1], m[1][2], m[1][3]);190FRDP ("{%f,%f,%f,%f}\n", m[2][0], m[2][1], m[2][2], m[2][3]);191FRDP ("{%f,%f,%f,%f}\n", m[3][0], m[3][1], m[3][2], m[3][3]);192FRDP ("\nmodel\n{%f,%f,%f,%f}\n", rdp.model[0][0], rdp.model[0][1], rdp.model[0][2], rdp.model[0][3]);193FRDP ("{%f,%f,%f,%f}\n", rdp.model[1][0], rdp.model[1][1], rdp.model[1][2], rdp.model[1][3]);194FRDP ("{%f,%f,%f,%f}\n", rdp.model[2][0], rdp.model[2][1], rdp.model[2][2], rdp.model[2][3]);195FRDP ("{%f,%f,%f,%f}\n", rdp.model[3][0], rdp.model[3][1], rdp.model[3][2], rdp.model[3][3]);196FRDP ("\nproj\n{%f,%f,%f,%f}\n", rdp.proj[0][0], rdp.proj[0][1], rdp.proj[0][2], rdp.proj[0][3]);197FRDP ("{%f,%f,%f,%f}\n", rdp.proj[1][0], rdp.proj[1][1], rdp.proj[1][2], rdp.proj[1][3]);198FRDP ("{%f,%f,%f,%f}\n", rdp.proj[2][0], rdp.proj[2][1], rdp.proj[2][2], rdp.proj[2][3]);199FRDP ("{%f,%f,%f,%f}\n", rdp.proj[3][0], rdp.proj[3][1], rdp.proj[3][2], rdp.proj[3][3]);200#endif201}202203//204// uc0:movemem - loads a structure with data205//206207static void uc0_movemem()208{209RDP("uc0:movemem ");210211DWORD i,a;212213// Check the command214switch ((rdp.cmd0 >> 16) & 0xFF)215{216case 0x80:217{218a = (segoffset(rdp.cmd1) & 0xFFFFFF) >> 1;219220short scale_x = ((short*)gfx.RDRAM)[(a+0)^1] / 4;221short scale_y = ((short*)gfx.RDRAM)[(a+1)^1] / 4;222short scale_z = ((short*)gfx.RDRAM)[(a+2)^1];223short trans_x = ((short*)gfx.RDRAM)[(a+4)^1] / 4;224short trans_y = ((short*)gfx.RDRAM)[(a+5)^1] / 4;225short trans_z = ((short*)gfx.RDRAM)[(a+6)^1];226rdp.view_scale[0] = scale_x * rdp.scale_x;227rdp.view_scale[1] = -scale_y * rdp.scale_y;228rdp.view_scale[2] = 32.0f * scale_z;229rdp.view_trans[0] = trans_x * rdp.scale_x + rdp.offset_x;230rdp.view_trans[1] = trans_y * rdp.scale_y + rdp.offset_y;231rdp.view_trans[2] = 32.0f * trans_z;232233// there are other values than x and y, but I don't know what they do234235rdp.update |= UPDATE_VIEWPORT;236237FRDP ("viewport scale(%d, %d, %d), trans(%d, %d, %d), from:%08lx\n", scale_x, scale_y, scale_z,238trans_x, trans_y, trans_z, rdp.cmd1);239}240break;241242case 0x82:243{244a = segoffset(rdp.cmd1) & 0x00ffffff;245char dir_x = ((char*)gfx.RDRAM)[(a+8)^3];246rdp.lookat[1][0] = (float)(dir_x) / 127.0f;247char dir_y = ((char*)gfx.RDRAM)[(a+9)^3];248rdp.lookat[1][1] = (float)(dir_y) / 127.0f;249char dir_z = ((char*)gfx.RDRAM)[(a+10)^3];250rdp.lookat[1][2] = (float)(dir_z) / 127.0f;251if (!dir_x && !dir_y)252rdp.use_lookat = FALSE;253else254rdp.use_lookat = TRUE;255FRDP("lookat_y (%f, %f, %f)\n", rdp.lookat[1][0], rdp.lookat[1][1], rdp.lookat[1][2]);256}257break;258259case 0x84:260a = segoffset(rdp.cmd1) & 0x00ffffff;261rdp.lookat[0][0] = (float)(((char*)gfx.RDRAM)[(a+8)^3]) / 127.0f;262rdp.lookat[0][1] = (float)(((char*)gfx.RDRAM)[(a+9)^3]) / 127.0f;263rdp.lookat[0][2] = (float)(((char*)gfx.RDRAM)[(a+10)^3]) / 127.0f;264rdp.use_lookat = TRUE;265FRDP("lookat_x (%f, %f, %f)\n", rdp.lookat[1][0], rdp.lookat[1][1], rdp.lookat[1][2]);266break;267268case 0x86:269case 0x88:270case 0x8a:271case 0x8c:272case 0x8e:273case 0x90:274case 0x92:275case 0x94:276// Get the light #277i = (((rdp.cmd0 >> 16) & 0xff) - 0x86) >> 1;278a = segoffset(rdp.cmd1) & 0x00ffffff;279280// Get the data281rdp.light[i].r = (float)(((BYTE*)gfx.RDRAM)[(a+0)^3]) / 255.0f;282rdp.light[i].g = (float)(((BYTE*)gfx.RDRAM)[(a+1)^3]) / 255.0f;283rdp.light[i].b = (float)(((BYTE*)gfx.RDRAM)[(a+2)^3]) / 255.0f;284rdp.light[i].a = 1.0f;285// ** Thanks to Icepir8 for pointing this out **286// Lighting must be signed byte instead of byte287rdp.light[i].dir_x = (float)(((char*)gfx.RDRAM)[(a+8)^3]) / 127.0f;288rdp.light[i].dir_y = (float)(((char*)gfx.RDRAM)[(a+9)^3]) / 127.0f;289rdp.light[i].dir_z = (float)(((char*)gfx.RDRAM)[(a+10)^3]) / 127.0f;290// **291292//rdp.update |= UPDATE_LIGHTS;293294FRDP ("light: n: %d, r: %.3f, g: %.3f, b: %.3f, x: %.3f, y: %.3f, z: %.3f\n",295i, rdp.light[i].r, rdp.light[i].g, rdp.light[i].b,296rdp.light_vector[i][0], rdp.light_vector[i][1], rdp.light_vector[i][2]);297break;298299300case 0x9E: //gSPForceMatrix command. Modification of uc2_movemem:matrix. Gonetz.301{302// do not update the combined matrix!303rdp.update &= ~UPDATE_MULT_MAT;304305int x,y;306DWORD addr = segoffset(rdp.cmd1) & 0x00FFFFFF;307FRDP ("matrix addr: %08lx\n", addr);308addr >>= 1;309310DWORD a = rdp.pc[rdp.pc_i] & BMASK;311rdp.pc[rdp.pc_i] = (a+24) & BMASK; //skip next 3 command, b/c they all are part of gSPForceMatrix312313for (x=0; x<16; x+=4) { // Adding 4 instead of one, just to remove mult. later314315for (y=0; y<4; y++) {316rdp.combined[x>>2][y] = (float)(317(((__int32)((WORD*)gfx.RDRAM)[(addr+x+y)^1]) << 16) |318((WORD*)gfx.RDRAM)[(addr+x+y+16)^1]319) / 65536.0f;320}321}322323#ifdef EXTREME_LOGGING324FRDP ("{%f,%f,%f,%f}\n", rdp.combined[0][0], rdp.combined[0][1], rdp.combined[0][2], rdp.combined[0][3]);325FRDP ("{%f,%f,%f,%f}\n", rdp.combined[1][0], rdp.combined[1][1], rdp.combined[1][2], rdp.combined[1][3]);326FRDP ("{%f,%f,%f,%f}\n", rdp.combined[2][0], rdp.combined[2][1], rdp.combined[2][2], rdp.combined[2][3]);327FRDP ("{%f,%f,%f,%f}\n", rdp.combined[3][0], rdp.combined[3][1], rdp.combined[3][2], rdp.combined[3][3]);328#endif329}330break;331332//next 3 command should never appear since they will be skipped in previous command333case 0x98:334RDP_E ("uc0:movemem matrix 0 - ERROR!\n");335RDP ("matrix 0 - IGNORED\n");336break;337338case 0x9A:339RDP_E ("uc0:movemem matrix 1 - ERROR!\n");340RDP ("matrix 1 - IGNORED\n");341break;342343case 0x9C:344RDP_E ("uc0:movemem matrix 2 - ERROR!\n");345RDP ("matrix 2 - IGNORED\n");346break;347348default:349FRDP_E ("uc0:movemem unknown (index: 0x%08lx)\n", (rdp.cmd0 >> 16) & 0xFF);350FRDP ("unknown (index: 0x%08lx)\n", (rdp.cmd0 >> 16) & 0xFF);351}352}353354//355// uc0:vertex - loads vertices356//357358static void uc0_vertex()359{360DWORD addr = segoffset(rdp.cmd1) & 0x00FFFFFF;361int v0, i, n;362float x, y, z;363364rdp.v0 = v0 = (rdp.cmd0 >> 16) & 0xF; // Current vertex365rdp.vn = n = ((rdp.cmd0 >> 20) & 0xF) + 1; // Number of vertices to copy366367FRDP("uc0:vertex: v0: %d, n: %d\n", v0, n);368369// This is special, not handled in update(), but here370// * Matrix Pre-multiplication idea by Gonetz ([email protected])371if (rdp.update & UPDATE_MULT_MAT)372{373rdp.update ^= UPDATE_MULT_MAT;374MulMatrices(rdp.model, rdp.proj, rdp.combined);375}376// *377378// This is special, not handled in update()379if (rdp.update & UPDATE_LIGHTS)380{381rdp.update ^= UPDATE_LIGHTS;382383// Calculate light vectors384for (DWORD l=0; l<rdp.num_lights; l++)385{386InverseTransformVector(&rdp.light[l].dir_x, rdp.light_vector[l], rdp.model);387NormalizeVector (rdp.light_vector[l]);388}389}390391for (i=0; i < (n<<4); i+=16)392{393VERTEX *v = &rdp.vtx[v0 + (i>>4)];394x = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 0)^1];395y = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 1)^1];396z = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 2)^1];397v->flags = ((WORD*)gfx.RDRAM)[(((addr+i) >> 1) + 3)^1];398v->ou = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 4)^1] * rdp.tiles[rdp.cur_tile].s_scale;399v->ov = (float)((short*)gfx.RDRAM)[(((addr+i) >> 1) + 5)^1] * rdp.tiles[rdp.cur_tile].t_scale;400v->a = ((BYTE*)gfx.RDRAM)[(addr+i + 15)^3];401402v->x = x*rdp.combined[0][0] + y*rdp.combined[1][0] + z*rdp.combined[2][0] + rdp.combined[3][0];403v->y = x*rdp.combined[0][1] + y*rdp.combined[1][1] + z*rdp.combined[2][1] + rdp.combined[3][1];404v->z = x*rdp.combined[0][2] + y*rdp.combined[1][2] + z*rdp.combined[2][2] + rdp.combined[3][2];405v->w = x*rdp.combined[0][3] + y*rdp.combined[1][3] + z*rdp.combined[2][3] + rdp.combined[3][3];406407#ifdef EXTREME_LOGGING408FRDP ("v%d - x: %f, y: %f, z: %f, u: %f, v: %f\n", i>>4, v->x, v->y, v->z, v->ou, v->ov);409#endif410411v->oow = 1.0f / v->w;412v->x_w = v->x * v->oow;413v->y_w = v->y * v->oow;414v->z_w = v->z * v->oow;415CalculateFog (v);416417v->uv_calculated = 0xFFFFFFFF;418v->screen_translated = 0;419v->shade_mods_allowed = 1;420421v->scr_off = 0;422if (v->x < -v->w) v->scr_off |= 1;423if (v->x > v->w) v->scr_off |= 2;424if (v->y < -v->w) v->scr_off |= 4;425if (v->y > v->w) v->scr_off |= 8;426if (v->w < 0.1f) v->scr_off |= 16;427428if (rdp.geom_mode & 0x00020000)429{430v->vec[0] = ((char*)gfx.RDRAM)[(addr+i + 12)^3];431v->vec[1] = ((char*)gfx.RDRAM)[(addr+i + 13)^3];432v->vec[2] = ((char*)gfx.RDRAM)[(addr+i + 14)^3];433if (rdp.geom_mode & 0x80000) calc_linear (v);434else if (rdp.geom_mode & 0x40000) calc_sphere (v);435NormalizeVector (v->vec);436437calc_light (v);438}439else440{441v->r = ((BYTE*)gfx.RDRAM)[(addr+i + 12)^3];442v->g = ((BYTE*)gfx.RDRAM)[(addr+i + 13)^3];443v->b = ((BYTE*)gfx.RDRAM)[(addr+i + 14)^3];444}445}446}447448//449// uc0:displaylist - makes a call to another section of code450//451452static void uc0_displaylist()453{454DWORD addr = segoffset(rdp.cmd1) & 0x00FFFFFF;455456// This fixes partially Gauntlet: Legends457if (addr == rdp.pc[rdp.pc_i] - 8) { RDP ("display list not executed!\n"); return; }458459DWORD push = (rdp.cmd0 >> 16) & 0xFF; // push the old location?460461FRDP("uc0:displaylist: %08lx, push:%s", addr, push?"no":"yes");462FRDP(" (seg %d, offset %08lx)\n", (rdp.cmd1>>24)&0x0F, rdp.cmd1&0x00FFFFFF);463464switch (push)465{466case 0: // push467if (rdp.pc_i >= 9) {468RDP_E ("** DL stack overflow **");469RDP ("** DL stack overflow **\n");470return;471}472rdp.pc_i ++; // go to the next PC in the stack473rdp.pc[rdp.pc_i] = addr; // jump to the address474break;475476case 1: // no push477rdp.pc[rdp.pc_i] = addr; // just jump to the address478break;479480default:481RDP_E("Unknown displaylist operation\n");482RDP ("Unknown displaylist operation\n");483}484}485486//487// tri1 - renders a triangle488//489490static void uc0_tri1()491{492FRDP("uc0:tri1 #%d - %d, %d, %d\n", rdp.tri_n,493((rdp.cmd1>>16) & 0xFF) / 10,494((rdp.cmd1>>8) & 0xFF) / 10,495(rdp.cmd1 & 0xFF) / 10);496497VERTEX *v[3] = {498&rdp.vtx[((rdp.cmd1 >> 16) & 0xFF) / 10],499&rdp.vtx[((rdp.cmd1 >> 8) & 0xFF) / 10],500&rdp.vtx[(rdp.cmd1 & 0xFF) / 10]501};502if (cull_tri(v))503rdp.tri_n ++;504else505{506update ();507DrawTri (v);508rdp.tri_n ++;509}510}511512static void uc0_culldl()513{514BYTE vStart = (BYTE)((rdp.cmd0 & 0x00FFFFFF) / 40) & 0xF;515BYTE vEnd = (BYTE)(rdp.cmd1 / 40) & 0x0F;516DWORD cond = 0;517VERTEX *v;518519FRDP("uc0:culldl start: %d, end: %d\n", vStart, vEnd);520521if (vEnd < vStart) return;522for (WORD i=vStart; i<=vEnd; i++)523{524v = &rdp.vtx[i];525// Check if completely off the screen (quick frustrum clipping for 90 FOV)526if (v->x >= -v->w)527cond |= 0x01;528if (v->x <= v->w)529cond |= 0x02;530if (v->y >= -v->w)531cond |= 0x04;532if (v->y <= v->w)533cond |= 0x08;534if (v->w >= 0.1f)535cond |= 0x10;536537if (cond == 0x1F)538return;539}540541RDP (" - "); // specify that the enddl is not a real command542uc0_enddl ();543}544545static void uc0_popmatrix()546{547RDP("uc0:popmatrix\n");548549DWORD param = rdp.cmd1;550551switch (param)552{553case 0: // modelview554modelview_pop ();555break;556557case 1: // projection, can't558break;559560default:561FRDP_E ("Unknown uc0:popmatrix command: 0x%08lx\n", param);562FRDP ("Unknown uc0:popmatrix command: 0x%08lx\n", param);563}564}565566void uc6_obj_sprite ();567568static void uc0_modifyvtx(BYTE where, WORD vtx, DWORD val)569{570VERTEX *v = &rdp.vtx[vtx];571572switch (where)573{574case 0:575uc6_obj_sprite ();576break;577578case 0x10: // RGBA579v->r = (BYTE)(val >> 24);580v->g = (BYTE)((val >> 16) & 0xFF);581v->b = (BYTE)((val >> 8) & 0xFF);582v->a = (BYTE)(val & 0xFF);583v->shade_mods_allowed = 1;584585FRDP ("RGBA: %d, %d, %d, %d\n", v->r, v->g, v->b, v->a);586break;587588case 0x14: // ST589v->ou = (float)((short)(val>>16)) / 32.0f;590v->ov = (float)((short)(val&0xFFFF)) / 32.0f;591v->uv_calculated = 0xFFFFFFFF;592v->uv_fixed = 0;593594FRDP ("u/v: (%04lx, %04lx), (%f, %f)\n", (short)(val>>16), (short)(val&0xFFFF),595v->ou, v->ov);596break;597598case 0x18: // XY screen599{600float scr_x = (float)((short)(val>>16)) / 4.0f;601float scr_y = (float)((short)(val&0xFFFF)) / 4.0f;602v->screen_translated = 1;603v->sx = scr_x * rdp.scale_x;604v->sy = scr_y * rdp.scale_y;605if (v->w < 0.01f)606{607v->w = 1.0f;608v->oow = 1.0f;609v->z_w = 1.0f;610}611v->sz = rdp.view_trans[2] + v->z_w * rdp.view_scale[2];612613v->scr_off = 0;614if (scr_x < 0) v->scr_off |= 1;615if (scr_x > rdp.vi_width) v->scr_off |= 2;616if (scr_y < 0) v->scr_off |= 4;617if (scr_y > rdp.vi_height) v->scr_off |= 8;618if (v->w < 0.1f) v->scr_off |= 16;619620FRDP ("x/y: (%f, %f)\n", scr_x, scr_y);621}622break;623624case 0x1C: // Z screen625{626float scr_z = (float)((short)(val>>16));627v->z_w = (scr_z - rdp.view_trans[2]) / rdp.view_scale[2];628v->z = v->z_w * v->w;629FRDP ("z: %f\n", scr_z);630}631break;632633default:634RDP("UNKNOWN\n");635break;636}637}638639//640// uc0:moveword - moves a word to someplace, like the segment pointers641//642643static void uc0_moveword()644{645RDP("uc0:moveword ");646647// Find which command this is (lowest byte of cmd0)648switch (rdp.cmd0 & 0xFF)649{650case 0x00:651RDP_E ("uc0:moveword matrix - IGNORED\n");652RDP ("matrix - IGNORED\n");653break;654655case 0x02:656rdp.num_lights = ((rdp.cmd1 - 0x80000000) >> 5) - 1; // inverse of equation657if (rdp.num_lights > 8) rdp.num_lights = 0;658659rdp.update |= UPDATE_LIGHTS;660FRDP ("numlights: %d\n", rdp.num_lights);661break;662663case 0x04:664FRDP ("clip %08lx, %08lx\n", rdp.cmd0, rdp.cmd1);665break;666667case 0x06: // segment668FRDP ("segment: %08lx -> seg%d\n", rdp.cmd1, (rdp.cmd0 >> 10) & 0x0F);669if ((rdp.cmd1&BMASK)<BMASK)670rdp.segment[(rdp.cmd0 >> 10) & 0x0F] = rdp.cmd1;671break;672673case 0x08:674{675rdp.fog_multiplier = (short)(rdp.cmd1 >> 16);676rdp.fog_offset = (short)(rdp.cmd1 & 0x0000FFFF);677FRDP ("fog: multiplier: %f, offset: %f\n", rdp.fog_multiplier, rdp.fog_offset);678}679break;680681case 0x0a: // moveword LIGHTCOL682{683int n = (rdp.cmd0&0xE000) >> 13;684FRDP ("lightcol light:%d, %08lx\n", n, rdp.cmd1);685686rdp.light[n].r = (float)((rdp.cmd1 >> 24) & 0xFF) / 255.0f;687rdp.light[n].g = (float)((rdp.cmd1 >> 16) & 0xFF) / 255.0f;688rdp.light[n].b = (float)((rdp.cmd1 >> 8) & 0xFF) / 255.0f;689rdp.light[n].a = 255;690}691break;692693case 0x0c:694{695WORD val = (WORD)((rdp.cmd0 >> 8) & 0xFFFF);696WORD vtx = val / 40;697BYTE where = val%40;698uc0_modifyvtx(where, vtx, rdp.cmd1);699FRDP ("uc0:modifyvtx: vtx: %d, where: 0x%02lx, val: %08lx - ", vtx, where, rdp.cmd1);700}701break;702703case 0x0e:704RDP ("perspnorm - IGNORED\n");705break;706707default:708FRDP_E ("uc0:moveword unknown (index: 0x%08lx)\n", rdp.cmd0 & 0xFF);709FRDP ("unknown (index: 0x%08lx)\n", rdp.cmd0 & 0xFF);710}711}712713static void uc0_texture()714{715int tile = (rdp.cmd0 >> 8) & 0x07;716rdp.mipmap_level = (rdp.cmd0 >> 11) & 0x07;717DWORD on = (rdp.cmd0 & 0xFF);718719if (on)720{721rdp.cur_tile = tile;722723WORD s = (WORD)((rdp.cmd1 >> 16) & 0xFFFF);724WORD t = (WORD)(rdp.cmd1 & 0xFFFF);725726TILE *tmp_tile = &rdp.tiles[tile];727tmp_tile->on = (BYTE)on;728tmp_tile->org_s_scale = s;729tmp_tile->org_t_scale = t;730tmp_tile->s_scale = (float)(s+1)/65536.0f;731tmp_tile->t_scale = (float)(t+1)/65536.0f;732tmp_tile->s_scale /= 32.0f;733tmp_tile->t_scale /= 32.0f;734735rdp.update |= UPDATE_TEXTURE;736737FRDP("uc0:texture: tile: %d, mipmap_lvl: %d, on: %d, s_scale: %f, t_scale: %f\n",738tile, rdp.mipmap_level, on, tmp_tile->s_scale, tmp_tile->t_scale);739}740else741{742RDP("uc0:texture skipped b/c of off\n");743}744}745746747static void uc0_setothermode_h()748{749RDP ("uc0:setothermode_h: ");750751int shift, len;752if ((settings.ucode == 2) || (settings.ucode == 8))753{754len = (rdp.cmd0 & 0xFF) + 1;755shift = 32 - ((rdp.cmd0 >> 8) & 0xFF) - len;756}757else758{759shift = (rdp.cmd0 >> 8) & 0xFF;760len = rdp.cmd0 & 0xFF;761}762763DWORD mask = 0;764int i = len;765for (; i; i--)766mask = (mask << 1) | 1;767mask <<= shift;768769rdp.cmd1 &= mask;770rdp.othermode_h &= ~mask;771rdp.othermode_h |= rdp.cmd1;772773if (mask & 0x00003000) // filter mode774{775rdp.filter_mode = (int)((rdp.othermode_h & 0x00003000) >> 12);776rdp.update |= UPDATE_TEXTURE;777FRDP ("filter mode: %s\n", str_filter[rdp.filter_mode]);778}779780if (mask & 0x0000C000) // tlut mode781{782rdp.tlut_mode = (BYTE)((rdp.othermode_h & 0x0000C000) >> 14);783FRDP ("tlut mode: %s\n", str_tlut[rdp.tlut_mode]);784}785786if (mask & 0x00300000) // cycle type787{788rdp.cycle_mode = (BYTE)((rdp.othermode_h & 0x00300000) >> 20);789FRDP ("cycletype: %d\n", rdp.cycle_mode);790}791792if (mask & 0x00010000) // LOD enable793{794rdp.LOD_en = (rdp.othermode_h & 0x00010000) ? TRUE : FALSE;795FRDP ("LOD_en: %d\n", rdp.LOD_en);796}797798DWORD unk = mask & 0xFFCF0FFF;799if (unk) // unknown portions, LARGE800{801FRDP ("UNKNOWN PORTIONS: shift: %d, len: %d, unknowns: %08lx\n", shift, len, unk);802}803}804805static void uc0_setothermode_l()806{807RDP("uc0:setothermode_l ");808809int shift, len;810if ((settings.ucode == 2) || (settings.ucode == 8))811{812len = (rdp.cmd0 & 0xFF) + 1;813shift = 32 - ((rdp.cmd0 >> 8) & 0xFF) - len;814}815else816{817len = rdp.cmd0 & 0xFF;818shift = (rdp.cmd0 >> 8) & 0xFF;819}820821DWORD mask = 0;822int i = len;823for (; i; i--)824mask = (mask << 1) | 1;825mask <<= shift;826827rdp.cmd1 &= mask;828rdp.othermode_l &= ~mask;829rdp.othermode_l |= rdp.cmd1;830831if (mask & 0x00000003) // alpha compare832{833rdp.acmp = rdp.othermode_l & 0x00000003;834FRDP ("alpha compare %s\n", ACmp[rdp.acmp]);835rdp.update |= UPDATE_ALPHA_COMPARE;836}837838if (mask & 0x00000004) // z-src selection839{840rdp.zsrc = (rdp.othermode_l & 0x00000004) >> 2;841FRDP ("z-src sel: %s\n", str_zs[rdp.zsrc]);842FRDP ("z-src sel: %08lx\n", rdp.zsrc);843}844845if (mask & 0xFFFFFFF8) // rendermode / blender bits846{847rdp.update |= UPDATE_FOG_ENABLED; //if blender has no fog bits, fog must be set off848rdp.render_mode_changed |= rdp.rm ^ rdp.othermode_l;849rdp.rm = rdp.othermode_l;850if (settings.flame_corona && (rdp.rm == 0x00504341)) //hack for flame's corona851rdp.othermode_l |= /*0x00000020 |*/ 0x00000010;852FRDP ("rendermode: %08lx\n", rdp.othermode_l); // just output whole othermode_l853}854855// there is not one setothermode_l that's not handled :)856}857858//859// uc0:enddl - ends a call made by uc0:displaylist860//861862static void uc0_enddl()863{864RDP("uc0:enddl\n");865866if (rdp.pc_i == 0)867{868RDP ("RDP end\n");869870// Halt execution here871rdp.halt = 1;872}873874rdp.pc_i --;875}876877static void uc0_setgeometrymode()878{879FRDP("uc0:setgeometrymode %08lx\n", rdp.cmd1);880881rdp.geom_mode |= rdp.cmd1;882883if (rdp.cmd1 & 0x00000001) // Z-Buffer enable884{885if (!(rdp.flags & ZBUF_ENABLED))886{887rdp.flags |= ZBUF_ENABLED;888rdp.update |= UPDATE_ZBUF_ENABLED;889}890}891if (rdp.cmd1 & 0x00001000) // Front culling892{893if (!(rdp.flags & CULL_FRONT))894{895rdp.flags |= CULL_FRONT;896rdp.update |= UPDATE_CULL_MODE;897}898}899if (rdp.cmd1 & 0x00002000) // Back culling900{901if (!(rdp.flags & CULL_BACK))902{903rdp.flags |= CULL_BACK;904rdp.update |= UPDATE_CULL_MODE;905}906}907908//Added by Gonetz909if (rdp.cmd1 & 0x00010000) // Fog enable910{911if (!(rdp.flags & FOG_ENABLED))912{913rdp.flags |= FOG_ENABLED;914rdp.update |= UPDATE_FOG_ENABLED;915}916}917}918919static void uc0_cleargeometrymode()920{921FRDP("uc0:cleargeometrymode %08lx\n", rdp.cmd1);922923rdp.geom_mode &= (~rdp.cmd1);924925if (rdp.cmd1 & 0x00000001) // Z-Buffer enable926{927if (rdp.flags & ZBUF_ENABLED)928{929rdp.flags ^= ZBUF_ENABLED;930rdp.update |= UPDATE_ZBUF_ENABLED;931}932}933if (rdp.cmd1 & 0x00001000) // Front culling934{935if (rdp.flags & CULL_FRONT)936{937rdp.flags ^= CULL_FRONT;938rdp.update |= UPDATE_CULL_MODE;939}940}941if (rdp.cmd1 & 0x00002000) // Back culling942{943if (rdp.flags & CULL_BACK)944{945rdp.flags ^= CULL_BACK;946rdp.update |= UPDATE_CULL_MODE;947}948}949950//Added by Gonetz951if (rdp.cmd1 & 0x00010000) // Fog enable952{953if (rdp.flags & FOG_ENABLED)954{955rdp.flags ^= FOG_ENABLED;956rdp.update |= UPDATE_FOG_ENABLED;957}958}959}960961static void uc0_quad3d()962{963// Actually line3d, not supported I think964965int v0 = ((rdp.cmd1 >> 16) & 0xff) / 10;966int v1 = ((rdp.cmd1 >> 8) & 0xff) / 10;967int f = (rdp.cmd1 >> 24) & 0xff;968969FRDP("uc0:line3d v0:%d, v1:%d, f:%02lx - IGNORED\n", v0, v1, f);970}971972static void uc0_rdphalf_1()973{974RDP_E("uc0:rdphalf_1 - IGNORED\n");975RDP ("uc0:rdphalf_1 - IGNORED\n");976}977978static void uc0_rdphalf_2()979{980RDP_E("uc0:rdphalf_2 - IGNORED\n");981RDP ("uc0:rdphalf_2 - IGNORED\n");982}983984static void uc0_rdphalf_cont()985{986RDP_E("uc0:rdphalf_cont - IGNORED\n");987RDP ("uc0:rdphalf_cont - IGNORED\n");988}989990static void uc0_tri4 ()991{992// c0: 0000 0123, c1: 456789ab993// becomes: 405 617 829 a3b994995RDP ("uc0:tri4");996FRDP(" #%d, #%d, #%d, #%d - %d, %d, %d - %d, %d, %d - %d, %d, %d - %d, %d, %d\n", rdp.tri_n, rdp.tri_n+1, rdp.tri_n+2, rdp.tri_n+3,997(rdp.cmd1 >> 28) & 0xF,998(rdp.cmd0 >> 12) & 0xF,999(rdp.cmd1 >> 24) & 0xF,1000(rdp.cmd1 >> 20) & 0xF,1001(rdp.cmd0 >> 8) & 0xF,1002(rdp.cmd1 >> 16) & 0xF,1003(rdp.cmd1 >> 12) & 0xF,1004(rdp.cmd0 >> 4) & 0xF,1005(rdp.cmd1 >> 8) & 0xF,1006(rdp.cmd1 >> 4) & 0xF,1007(rdp.cmd0 >> 0) & 0xF,1008(rdp.cmd1 >> 0) & 0xF);10091010VERTEX *v[12] = {1011&rdp.vtx[(rdp.cmd1 >> 28) & 0xF],1012&rdp.vtx[(rdp.cmd0 >> 12) & 0xF],1013&rdp.vtx[(rdp.cmd1 >> 24) & 0xF],1014&rdp.vtx[(rdp.cmd1 >> 20) & 0xF],1015&rdp.vtx[(rdp.cmd0 >> 8) & 0xF],1016&rdp.vtx[(rdp.cmd1 >> 16) & 0xF],1017&rdp.vtx[(rdp.cmd1 >> 12) & 0xF],1018&rdp.vtx[(rdp.cmd0 >> 4) & 0xF],1019&rdp.vtx[(rdp.cmd1 >> 8) & 0xF],1020&rdp.vtx[(rdp.cmd1 >> 4) & 0xF],1021&rdp.vtx[(rdp.cmd0 >> 0) & 0xF],1022&rdp.vtx[(rdp.cmd1 >> 0) & 0xF],1023};10241025BOOL updated = 0;10261027if (cull_tri(v))1028rdp.tri_n ++;1029else1030{1031updated = 1;1032update ();10331034DrawTri (v);1035rdp.tri_n ++;1036}10371038if (cull_tri(v+3))1039rdp.tri_n ++;1040else1041{1042if (!updated)1043{1044updated = 1;1045update ();1046}10471048DrawTri (v+3);1049rdp.tri_n ++;1050}10511052if (cull_tri(v+6))1053rdp.tri_n ++;1054else1055{1056if (!updated)1057{1058updated = 1;1059update ();1060}10611062DrawTri (v+6);1063rdp.tri_n ++;1064}10651066if (cull_tri(v+9))1067rdp.tri_n ++;1068else1069{1070if (!updated)1071{1072updated = 1;1073update ();1074}10751076DrawTri (v+9);1077rdp.tri_n ++;1078}1079}1080108110821083