X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fgles2glide64%2Fsrc%2FGlide64%2Frdp.cpp;fp=source%2Fgles2glide64%2Fsrc%2FGlide64%2Frdp.cpp;h=9373bf6f8170778115333cfe5a91c3929c584dc7;hb=98e75f2d18c02c233da543560f76282f04fc796c;hp=0000000000000000000000000000000000000000;hpb=0ced54f867d36e8b324155bef49e8abfebfc3237;p=mupen64plus-pandora.git diff --git a/source/gles2glide64/src/Glide64/rdp.cpp b/source/gles2glide64/src/Glide64/rdp.cpp new file mode 100755 index 0000000..9373bf6 --- /dev/null +++ b/source/gles2glide64/src/Glide64/rdp.cpp @@ -0,0 +1,4355 @@ +/* +* Glide64 - Glide video plugin for Nintendo 64 emulators. +* Copyright (c) 2002 Dave2001 +* Copyright (c) 2003-2009 Sergey 'Gonetz' Lipski +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//**************************************************************** +// +// Glide64 - Glide Plugin for Nintendo 64 emulators +// Project started on December 29th, 2001 +// +// Authors: +// Dave2001, original author, founded the project in 2001, left it in 2002 +// Gugaman, joined the project in 2002, left it in 2002 +// Sergey 'Gonetz' Lipski, joined the project in 2002, main author since fall of 2002 +// Hiroshi 'KoolSmoky' Morii, joined the project in 2007 +// +//**************************************************************** +// +// To modify Glide64: +// * 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. +// * 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. +// +//**************************************************************** + +#include +#include "Gfx_1.3.h" +#include "m64p.h" +#include "Ini.h" +#include "Config.h" +#include "3dmath.h" +#include "Util.h" +#include "Debugger.h" +#include "Combine.h" +#include "TexCache.h" +#include "TexBuffer.h" +#include "FBtoScreen.h" +#include "CRC.h" + +#ifdef PAULSCODE +#include "FrameSkipper.h" +extern FrameSkipper frameSkipper; +#endif + +#ifdef PERFORMANCE +#include "ticks.h" +#endif + +#ifdef __ARM_NEON__ +#include "arm_neon.h" +//#include "ticks.h" +#endif + +/* +const int NumOfFormats = 3; +SCREEN_SHOT_FORMAT ScreenShotFormats[NumOfFormats] = { {wxT("BMP"), wxT("bmp"), wxBITMAP_TYPE_BMP}, {wxT("PNG"), wxT("png"), wxBITMAP_TYPE_PNG}, {wxT("JPEG"), wxT("jpeg"), wxBITMAP_TYPE_JPEG} }; +*/ +const char *ACmp[] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" }; + +const char *Mode0[] = { "COMBINED", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "1", "NOISE", + "0", "0", + "0", "0", + "0", "0", + "0", "0" }; + +const char *Mode1[] = { "COMBINED", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "CENTER", "K4", + "0", "0", + "0", "0", + "0", "0", + "0", "0" }; + +const char *Mode2[] = { "COMBINED", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "SCALE", "COMBINED_ALPHA", + "T0_ALPHA", "T1_ALPHA", + "PRIM_ALPHA", "SHADE_ALPHA", + "ENV_ALPHA", "LOD_FRACTION", + "PRIM_LODFRAC", "K5", + "0", "0", + "0", "0", + "0", "0", + "0", "0", + "0", "0", + "0", "0", + "0", "0", + "0", "0" }; + +const char *Mode3[] = { "COMBINED", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "1", "0" }; + +const char *Alpha0[] = { "COMBINED", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "1", "0" }; + +#define Alpha1 Alpha0 +const char *Alpha2[] = { "LOD_FRACTION", "TEXEL0", + "TEXEL1", "PRIMITIVE", + "SHADE", "ENVIORNMENT", + "PRIM_LODFRAC", "0" }; +#define Alpha3 Alpha0 + +const char *FBLa[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG" }; +const char *FBLb[] = { "G_BL_A_IN", "G_BL_A_FOG", "G_BL_A_SHADE", "G_BL_0" }; +const char *FBLc[] = { "G_BL_CLR_IN", "G_BL_CLR_MEM", "G_BL_CLR_BL", "G_BL_CLR_FOG"}; +const char *FBLd[] = { "G_BL_1MA", "G_BL_A_MEM", "G_BL_1", "G_BL_0" }; + +const char *str_zs[] = { "G_ZS_PIXEL", "G_ZS_PRIM" }; + +const char *str_yn[] = { "NO", "YES" }; +const char *str_offon[] = { "OFF", "ON" }; + +const char *str_cull[] = { "DISABLE", "FRONT", "BACK", "BOTH" }; + +// I=intensity probably +const char *str_format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" }; +const char *str_size[] = { "4bit", "8bit", "16bit", "32bit" }; +const char *str_cm[] = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" }; +const char *str_lod[] = { "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048" }; +const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" }; + +const char *str_filter[] = { "Point Sampled", "Average (box)", "Bilinear" }; + +const char *str_tlut[] = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" }; + +const char *str_dither[] = { "Pattern", "~Pattern", "Noise", "None" }; + +const char *CIStatus[] = { "ci_main", "ci_zimg", "ci_unknown", "ci_useless", + "ci_old_copy", "ci_copy", "ci_copy_self", + "ci_zcopy", "ci_aux", "ci_aux_copy" }; + +//static variables + +char out_buf[2048]; + +wxUint32 frame_count; // frame counter + +int ucode_error_report = TRUE; +int wrong_tile = -1; + +// ** RDP graphics functions ** +static void undef(); +static void spnoop(); + +static void rdp_noop(); +static void rdp_texrect(); +//static void rdp_texrectflip(); +static void rdp_loadsync(); +static void rdp_pipesync(); +static void rdp_tilesync(); +static void rdp_fullsync(); +static void rdp_setkeygb(); +static void rdp_setkeyr(); +static void rdp_setconvert(); +static void rdp_setscissor(); +static void rdp_setprimdepth(); +static void rdp_setothermode(); +static void rdp_loadtlut(); +static void rdp_settilesize(); +static void rdp_loadblock(); +static void rdp_loadtile(); +static void rdp_settile(); +static void rdp_fillrect(); +static void rdp_setfillcolor(); +static void rdp_setfogcolor(); +static void rdp_setblendcolor(); +static void rdp_setprimcolor(); +static void rdp_setenvcolor(); +static void rdp_setcombine(); +static void rdp_settextureimage(); +static void rdp_setdepthimage(); +static void rdp_setcolorimage(); +static void rdp_trifill(); +static void rdp_trishade(); +static void rdp_tritxtr(); +static void rdp_trishadetxtr(); +static void rdp_trifillz(); +static void rdp_trishadez(); +static void rdp_tritxtrz(); +static void rdp_trishadetxtrz(); +static void rdphalf_1(); +static void rdphalf_2(); +static void rdphalf_cont(); + +static void rsp_reserved0(); +static void rsp_reserved1(); +static void rsp_reserved2(); +static void rsp_reserved3(); + +static void ys_memrect(); + +wxUint8 microcode[4096]; +wxUint32 uc_crc; +void microcheck (); + +#ifdef PAULSCODE +#define Check_FrameSkip if (frameSkipper.willSkipNext()) return +#else +#define Check_FrameSkip {} +#endif + +// ** UCODE FUNCTIONS ** +#include "ucode00.h" +#include "ucode01.h" +#include "ucode02.h" +#include "ucode03.h" +#include "ucode04.h" +#include "ucode05.h" +#include "ucode06.h" +#include "ucode07.h" +#include "ucode08.h" +#include "ucode09.h" +#include "ucode.h" +#include "ucode09rdp.h" +#include "turbo3D.h" + +static int reset = 0; +static int old_ucode = -1; + +void RDP::Reset() +{ + memset(this, 0, sizeof(RDP_Base)); + // set all vertex numbers + for (int i=0; i>2; i++) + { + uc_crc += ((wxUint32*)microcode)[i]; + } + + FRDP_E ("crc: %08lx\n", uc_crc); + +#ifdef LOG_UCODE + std::ofstream ucf; + ucf.open ("ucode.txt", std::ios::out | std::ios::binary); + char d; + for (i=0; i<0x400000; i++) + { + d = ((char*)gfx.RDRAM)[i^3]; + ucf.write (&d, 1); + } + ucf.close (); +#endif + + FRDP("ucode = %08lx\n", uc_crc); + + Ini * ini = Ini::OpenIni(); + ini->SetPath("UCODE"); + char str[9]; + sprintf (str, "%08lx", (unsigned long)uc_crc); + int uc = ini->Read(str, -2); + + if (uc == -2 && ucode_error_report) + { + settings.ucode = Config_ReadInt("ucode", "Force microcode", 0, TRUE, FALSE); + + ReleaseGfx (); + ERRLOG("Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc); + + ucode_error_report = FALSE; // don't report any more ucode errors from this game + } + else if (uc == -1 && ucode_error_report) + { + settings.ucode = ini->Read(_T("/SETTINGS/ucode"), 0); + + ReleaseGfx (); + ERRLOG("Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc); + + ucode_error_report = FALSE; // don't report any more ucode errors from this game + } + else + { + old_ucode = settings.ucode; + settings.ucode = uc; + FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode, uc); + if (uc_crc == 0x8d5735b2 || uc_crc == 0xb1821ed3 || uc_crc == 0x1118b3e0) //F3DLP.Rej ucode. perspective texture correction is not implemented + { + rdp.Persp_en = 1; + rdp.persp_supported = FALSE; + } + else if (settings.texture_correction) + rdp.persp_supported = TRUE; + } +} + +#ifdef __WINDOWS__ +static void GetClientSize(int * width, int * height) +{ +#ifdef __WINDOWS__ + RECT win_rect; + GetClientRect (gfx.hWnd, &win_rect); + *width = win_rect.right; + *height = win_rect.bottom; +#else + GFXWindow->GetClientSize(width, height); +#endif +} +#endif + +void drawNoFullscreenMessage() +{ +//need to find, how to do it on non-windows OS +//the code below will compile on any OS +//but it works only on windows, because +//I don't know, how to initialize GFXWindow on other OS +#ifdef __WINDOWS__ + LOG ("drawNoFullscreenMessage ()\n"); + if (rdp.window_changed) + { + rdp.window_changed = FALSE; + int width, height; + GetClientSize(&width, &height); + + wxClientDC dc(GFXWindow); + dc.SetBrush(*wxMEDIUM_GREY_BRUSH); + dc.SetTextForeground(*wxWHITE); + dc.SetBackgroundMode(wxTRANSPARENT); + dc.DrawRectangle(0, 0, width, height); + + wxCoord w, h; + wxString text = wxT("Glide64mk2"); + dc.GetTextExtent(text, &w, &h); + wxCoord x = (width - w)/2; + wxCoord y = height/2 - h*4; + dc.DrawText(text, x, y); + + text = wxT("Gfx cannot be drawn in windowed mode"); + dc.GetTextExtent(text, &w, &h); + x = (width - w)/2; + y = height/2 - h; + dc.DrawText(text, x, y); + + text = wxT("Press Alt+Enter to switch to fullscreen"); + dc.GetTextExtent(text, &w, &h); + x = (width - w)/2; + y = (height - h)/2 + h*2; + dc.DrawText(text, x, y); + } +#endif +} + +static wxUint32 d_ul_x, d_ul_y, d_lr_x, d_lr_y; + +static void DrawPartFrameBufferToScreen() +{ + FB_TO_SCREEN_INFO fb_info; + fb_info.addr = rdp.cimg; + fb_info.size = rdp.ci_size; + fb_info.width = rdp.ci_width; + fb_info.height = rdp.ci_height; + fb_info.ul_x = d_ul_x; + fb_info.lr_x = d_lr_x; + fb_info.ul_y = d_ul_y; + fb_info.lr_y = d_lr_y; + fb_info.opaque = 0; + DrawFrameBufferToScreen(fb_info); + memset(gfx.RDRAM+rdp.cimg, 0, (rdp.ci_width*rdp.ci_height)<>1); +} + +#define RGBA16TO32(color) \ + ((color&1)?0xFF:0) | \ + ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \ + ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \ + ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8) + +static void CopyFrameBuffer (GrBuffer_t buffer = GR_BUFFER_BACKBUFFER) +{ + if (!fullscreen) + return; + FRDP ("CopyFrameBuffer: %08lx... ", rdp.cimg); + + // don't bother to write the stuff in asm... the slow part is the read from video card, + // not the copy. + + wxUint32 width = rdp.ci_width;//*gfx.VI_WIDTH_REG; + wxUint32 height; + if (fb_emulation_enabled && !(settings.hacks&hack_PPL)) + { + int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0; + height = rdp.frame_buffers[ind].height; + } + else + { + height = rdp.ci_lower_bound; + if (settings.hacks&hack_PPL) + height -= rdp.ci_upper_bound; + } + FRDP ("width: %d, height: %d... ", width, height); +//printf("CopyFrameBuffer width: %d, height: %d... ", width, height); + + if (rdp.scale_x < 1.1f) + { + wxUint16 * ptr_src = new wxUint16[width*height]; + if (grLfbReadRegion(buffer, + (wxUint32)rdp.offset_x, + (wxUint32)rdp.offset_y,//rdp.ci_upper_bound, + width, + height, + width<<1, + ptr_src)) + { + wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg); + wxUint32 *ptr_dst32 = (wxUint32*)(gfx.RDRAM+rdp.cimg); + wxUint16 c; + + for (wxUint32 y=0; y 0) + c = (c&0xFFC0) | ((c&0x001F) << 1) | 1; + } + else + { + c = (c&0xFFC0) | ((c&0x001F) << 1) | 1; + } + if (rdp.ci_size == 2) + ptr_dst[(x + y * width)^1] = c; + else + ptr_dst32[x + y * width] = RGBA16TO32(c); + } + } + LRDP("ReadRegion. Framebuffer copy complete.\n"); + } + else + { + LRDP("Framebuffer copy failed.\n"); + } + delete[] ptr_src; + } + else + { + if (rdp.motionblur && fb_hwfbe_enabled) + { + return; + } + else + { + float scale_x = (settings.scr_res_x - rdp.offset_x*2.0f) / max(width, rdp.vi_width); + float scale_y = (settings.scr_res_y - rdp.offset_y*2.0f) / max(height, rdp.vi_height); + + FRDP("width: %d, height: %d, ul_y: %d, lr_y: %d, scale_x: %f, scale_y: %f, ci_width: %d, ci_height: %d\n",width, height, rdp.ci_upper_bound, rdp.ci_lower_bound, scale_x, scale_y, rdp.ci_width, rdp.ci_height); +//printf("CopyFrameBuffer width: %d, height: %d, ul_y: %d, lr_y: %d, scale_x: %f, scale_y: %f, ci_width: %d, ci_height: %d\n",width, height, rdp.ci_upper_bound, rdp.ci_lower_bound, scale_x, scale_y, rdp.ci_width, rdp.ci_height); + GrLfbInfo_t info; + info.size = sizeof(GrLfbInfo_t); + + if (grLfbLock (GR_LFB_READ_ONLY, + buffer, + GR_LFBWRITEMODE_565, + GR_ORIGIN_UPPER_LEFT, + FXFALSE, + &info)) + { + wxUint16 *ptr_src = (wxUint16*)info.lfbPtr; + wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg); + wxUint32 *ptr_dst32 = (wxUint32*)(gfx.RDRAM+rdp.cimg); + wxUint16 c; + wxUint32 stride = info.strideInBytes>>1; + + int read_alpha = settings.frame_buffer & fb_read_alpha; + if ((settings.hacks&hack_PMario) && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux) + read_alpha = FALSE; + int x_start = 0, y_start = 0, x_end = width, y_end = height; + if (settings.hacks&hack_BAR) + { + x_start = 80, y_start = 24, x_end = 240, y_end = 86; + } + for (int y=y_start; y 0) + SwapOK = TRUE; + rdp.updatescreen = 1; + + rdp.tri_n = 0; // 0 triangles so far this frame + rdp.debug_n = 0; + + rdp.model_i = 0; // 0 matrices so far in stack + //stack_size can be less then 32! Important for Silicon Vally. Thanks Orkin! + rdp.model_stack_size = min(32, (*(wxUint32*)(gfx.DMEM+0x0FE4))>>6); + if (rdp.model_stack_size == 0) + rdp.model_stack_size = 32; + rdp.Persp_en = TRUE; + rdp.fb_drawn = rdp.fb_drawn_front = FALSE; + rdp.update = 0x7FFFFFFF; // All but clear cache + rdp.geom_mode = 0; + rdp.acmp = 0; + rdp.maincimg[1] = rdp.maincimg[0]; + rdp.skip_drawing = FALSE; + rdp.s2dex_tex_loaded = FALSE; + rdp.bg_image_height = 0xFFFF; + fbreads_front = fbreads_back = 0; + rdp.fog_multiplier = rdp.fog_offset = 0; + rdp.zsrc = 0; + if (rdp.vi_org_reg != *gfx.VI_ORIGIN_REG) + rdp.tlut_mode = 0; //is it correct? + rdp.scissor_set = FALSE; + ucode5_texshiftaddr = ucode5_texshiftcount = 0; + cpu_fb_write = FALSE; + cpu_fb_read_called = FALSE; + cpu_fb_write_called = FALSE; + cpu_fb_ignore = FALSE; + d_ul_x = 0xffff; + d_ul_y = 0xffff; + d_lr_x = 0; + d_lr_y = 0; + depth_buffer_fog = TRUE; +//printf("ProcessDList\n"); + //analize possible frame buffer usage + if (fb_emulation_enabled) + DetectFrameBufferUsage(); + if (!(settings.hacks&hack_Lego) || rdp.num_of_ci > 1) + rdp.last_bg = 0; + //* End of set states *// + + // Get the start of the display list and the length of it + wxUint32 dlist_start = *(wxUint32*)(gfx.DMEM+0xFF0); + wxUint32 dlist_length = *(wxUint32*)(gfx.DMEM+0xFF4); + FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_length: %d, x_scale: %f, y_scale: %f\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length, (*gfx.VI_X_SCALE_REG & 0xFFF)/1024.0f, (*gfx.VI_Y_SCALE_REG & 0xFFF)/1024.0f); + FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG); + + if (cpu_fb_write == TRUE) + DrawPartFrameBufferToScreen(); + if ((settings.hacks&hack_Tonic) && dlist_length < 16) + { + rdp_fullsync(); + FRDP_E("DLIST is too short!\n"); + return; + } + + // Start executing at the start of the display list + rdp.pc_i = 0; + rdp.pc[rdp.pc_i] = dlist_start; + rdp.dl_count = -1; + rdp.halt = 0; + wxUint32 a; + + + // catches exceptions so that it doesn't freeze +#ifdef CATCH_EXCEPTIONS + try { +#endif + if (settings.ucode == ucode_Turbo3d) + { + Turbo3D(); + } + else + { + // MAIN PROCESSING LOOP + do { + + // Get the address of the next command + a = rdp.pc[rdp.pc_i] & BMASK; + + // Load the next command and its input + rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit + rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // / + // cmd2 and cmd3 are filled only when needed, by the function that needs them + + // Output the address before the command +#ifdef LOG_COMMANDS + FRDP ("%08lx (c0:%08lx, c1:%08lx): ", a, rdp.cmd0, rdp.cmd1); +#else + FRDP ("%08lx: ", a); +#endif + + // Go to the next instruction + rdp.pc[rdp.pc_i] = (a+8) & BMASK; + +#ifdef PERFORMANCE + perf_cur = ticksGetTicks(); +#endif + // Process this instruction + gfx_instruction[settings.ucode][rdp.cmd0>>24] (); + + // check DL counter + if (rdp.dl_count != -1) + { + rdp.dl_count --; + if (rdp.dl_count == 0) + { + rdp.dl_count = -1; + + LRDP("End of DL\n"); + rdp.pc_i --; + } + } + +#ifdef PERFORMANCE + perf_next = ticksGetTicks(); + sprintf (out_buf, "perf %08x: %lli\n", a-8, (perf_next-perf_cur)); +#ifdef RDP_LOGGING + rdp_log << out_buf; +#else + printf(out_buf); +#endif +#endif + + } while (!rdp.halt); + } +#ifdef CATCH_EXCEPTIONS + } catch (...) { + + if (fullscreen) + { + ReleaseGfx (); + rdp_reset (); +#ifdef TEXTURE_FILTER + if (settings.ghq_use) + { + ext_ghq_shutdown(); + settings.ghq_use = 0; + } +#endif + } + ERRLOG("The GFX plugin caused an exception and has been disabled."); + exception = TRUE; + return; + } +#endif + + if (fb_emulation_enabled) + { + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + } +#ifdef PAULSCODE + if (!frameSkipper.willSkipNext()) +#endif + if (settings.frame_buffer & fb_ref) + CopyFrameBuffer (); + if (rdp.cur_image) + CloseTextureBuffer(rdp.read_whole_frame && ((settings.hacks&hack_PMario) || rdp.swap_ci_index >= 0)); + + if ((settings.hacks&hack_TGR2) && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET) + { + newSwapBuffers (); + CI_SET = FALSE; + } + LRDP("ProcessDList end\n"); +} + +#ifdef __cplusplus +} +#endif + +// undef - undefined instruction, always ignore +static void undef() +{ + FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0); + FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0); +#ifdef _ENDUSER_RELEASE_ + *gfx.MI_INTR_REG |= 0x20; + gfx.CheckInterrupts(); + rdp.halt = 1; +#endif +} + +// spnoop - no operation, always ignore +static void spnoop() +{ + LRDP("spnoop\n"); +} + +// noop - no operation, always ignore +static void rdp_noop() +{ + LRDP("noop\n"); +} + +static void ys_memrect () +{ + wxUint32 tile = (wxUint16)((rdp.cmd1 & 0x07000000) >> 24); + + wxUint32 lr_x = (wxUint16)((rdp.cmd0 & 0x00FFF000) >> 14); + wxUint32 lr_y = (wxUint16)((rdp.cmd0 & 0x00000FFF) >> 2); + wxUint32 ul_x = (wxUint16)((rdp.cmd1 & 0x00FFF000) >> 14); + wxUint32 ul_y = (wxUint16)((rdp.cmd1 & 0x00000FFF) >> 2); + + if (lr_y > rdp.scissor_o.lr_y) + lr_y = rdp.scissor_o.lr_y; + wxUint32 off_x = ((rdp.cmd2 & 0xFFFF0000) >> 16) >> 5; + wxUint32 off_y = (rdp.cmd2 & 0x0000FFFF) >> 5; + + FRDP ("memrect (%d, %d, %d, %d), ci_width: %d", ul_x, ul_y, lr_x, lr_y, rdp.ci_width); + if (off_x > 0) + FRDP (" off_x: %d", off_x); + if (off_y > 0) + FRDP (" off_y: %d", off_y); + LRDP("\n"); + + wxUint32 y, width = lr_x - ul_x; + wxUint32 tex_width = rdp.tiles[tile].line << 3; + wxUint8 * texaddr = gfx.RDRAM + rdp.addr[rdp.tiles[tile].t_mem] + tex_width*off_y + off_x; + wxUint8 * fbaddr = gfx.RDRAM + rdp.cimg + ul_x; + + for (y = ul_y; y < lr_y; y++) { + wxUint8 *src = texaddr + (y - ul_y) * tex_width; + wxUint8 *dst = fbaddr + y * rdp.ci_width; + memcpy (dst, src, width); + } +} + +static void pm_palette_mod () +{ + wxUint8 envr = (wxUint8)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f); + wxUint8 envg = (wxUint8)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f); + wxUint8 envb = (wxUint8)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f); + wxUint16 env16 = (wxUint16)((envr<<11)|(envg<<6)|(envb<<1)|1); + wxUint8 prmr = (wxUint8)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f); + wxUint8 prmg = (wxUint8)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f); + wxUint8 prmb = (wxUint8)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f); + wxUint16 prim16 = (wxUint16)((prmr<<11)|(prmg<<6)|(prmb<<1)|1); + wxUint16 * dst = (wxUint16*)(gfx.RDRAM+rdp.cimg); + for (int i = 0; i < 16; i++) + { + dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16; + } + LRDP("Texrect palette modification\n"); +} + +static void pd_zcopy () +{ + wxUint16 ul_x = (wxUint16)((rdp.cmd1 & 0x00FFF000) >> 14); + wxUint16 lr_x = (wxUint16)((rdp.cmd0 & 0x00FFF000) >> 14) + 1; + wxUint16 ul_u = (wxUint16)((rdp.cmd2 & 0xFFFF0000) >> 21) + 1; + wxUint16 *ptr_dst = (wxUint16*)(gfx.RDRAM+rdp.cimg); + wxUint16 width = lr_x - ul_x; + wxUint16 * ptr_src = ((wxUint16*)rdp.tmem)+ul_u; + wxUint16 c; + for (wxUint16 x=0; x> 8); + ptr_dst[(ul_x+x)^1] = c; + // FRDP("dst[%d]=%04lx \n", (x + ul_x)^1, c); + } +} + +static void DrawDepthBufferFog() +{ + if (rdp.zi_width < 200) + return; + FB_TO_SCREEN_INFO fb_info; + fb_info.addr = rdp.zimg; + fb_info.size = 2; + fb_info.width = rdp.zi_width; + fb_info.height = rdp.ci_height; + fb_info.ul_x = rdp.scissor_o.ul_x; + fb_info.lr_x = rdp.scissor_o.lr_x; + fb_info.ul_y = rdp.scissor_o.ul_y; + fb_info.lr_y = rdp.scissor_o.lr_y; + fb_info.opaque = 0; + DrawDepthBufferToScreen(fb_info); +} + +static void rdp_texrect() +{ + if (!rdp.LLE) + { + wxUint32 a = rdp.pc[rdp.pc_i]; + wxUint8 cmdHalf1 = gfx.RDRAM[a+3]; + wxUint8 cmdHalf2 = gfx.RDRAM[a+11]; + a >>= 2; + if ((cmdHalf1 == 0xE1 && cmdHalf2 == 0xF1) || (cmdHalf1 == 0xB4 && cmdHalf2 == 0xB3) || (cmdHalf1 == 0xB3 && cmdHalf2 == 0xB2)) + { + //gSPTextureRectangle + rdp.cmd2 = ((wxUint32*)gfx.RDRAM)[a+1]; + rdp.cmd3 = ((wxUint32*)gfx.RDRAM)[a+3]; + rdp.pc[rdp.pc_i] += 16; + } + else + { + //gDPTextureRectangle + if (settings.hacks&hack_ASB) + rdp.cmd2 = 0; + else + rdp.cmd2 = ((wxUint32*)gfx.RDRAM)[a+0]; + rdp.cmd3 = ((wxUint32*)gfx.RDRAM)[a+1]; + rdp.pc[rdp.pc_i] += 8; + } + } + if ((settings.hacks&hack_Yoshi) && settings.ucode == ucode_S2DEX) + { + ys_memrect(); + return; + } + + if (rdp.skip_drawing || (!fb_emulation_enabled && (rdp.cimg == rdp.zimg))) + { + if ((settings.hacks&hack_PMario) && rdp.ci_status == ci_useless) + { + pm_palette_mod (); + } + else + { + LRDP("Texrect skipped\n"); + } + return; + } + + if ((settings.ucode == ucode_CBFD) && rdp.cur_image && rdp.cur_image->format) + { + //FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1].addr, rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size); + LRDP("Shadow texrect is skipped.\n"); + rdp.tri_n += 2; + return; + } + + if ((settings.ucode == ucode_PerfectDark) && (rdp.frame_buffers[rdp.ci_count-1].status == ci_zcopy)) + { + pd_zcopy (); + LRDP("Depth buffer copied.\n"); + rdp.tri_n += 2; + return; + } + + if ((rdp.othermode_l >> 16) == 0x3c18 && rdp.cycle1 == 0x03ffffff && rdp.cycle2 == 0x01ff1fff) //depth image based fog + { + if (!depth_buffer_fog) + return; + if (settings.fog) + DrawDepthBufferFog(); + depth_buffer_fog = FALSE; + return; + } + + // FRDP ("rdp.cycle1 %08lx, rdp.cycle2 %08lx\n", rdp.cycle1, rdp.cycle2); + + float ul_x, ul_y, lr_x, lr_y; + if (rdp.cycle_mode == 2) + { + ul_x = max(0.0f, (short)((rdp.cmd1 & 0x00FFF000) >> 14)); + ul_y = max(0.0f, (short)((rdp.cmd1 & 0x00000FFF) >> 2)); + lr_x = max(0.0f, (short)((rdp.cmd0 & 0x00FFF000) >> 14)); + lr_y = max(0.0f, (short)((rdp.cmd0 & 0x00000FFF) >> 2)); + } + else + { + ul_x = max(0.0f, ((short)((rdp.cmd1 & 0x00FFF000) >> 12)) / 4.0f); + ul_y = max(0.0f, ((short)(rdp.cmd1 & 0x00000FFF)) / 4.0f); + lr_x = max(0.0f, ((short)((rdp.cmd0 & 0x00FFF000) >> 12)) / 4.0f); + lr_y = max(0.0f, ((short)(rdp.cmd0 & 0x00000FFF)) / 4.0f); + } + + if (ul_x >= lr_x) + { + FRDP("Wrong Texrect: ul_x: %f, lr_x: %f\n", ul_x, lr_x); + return; + } + + if (rdp.cycle_mode > 1) + { + lr_x += 1.0f; + lr_y += 1.0f; + } else if (lr_y - ul_y < 1.0f) + lr_y = ceil(lr_y); + + if (settings.increase_texrect_edge) + { + if (floor(lr_x) != lr_x) + lr_x = ceil(lr_x); + if (floor(lr_y) != lr_y) + lr_y = ceil(lr_y); + } + + //* + if (rdp.tbuff_tex && (settings.frame_buffer & fb_optimize_texrect)) + { + LRDP("Attempt to optimize texrect\n"); + if (!rdp.tbuff_tex->drawn) + { + DRAWIMAGE d; + d.imageX = 0; + d.imageW = (wxUint16)rdp.tbuff_tex->width; + d.frameX = (wxUint16)ul_x; + d.frameW = (wxUint16)(rdp.tbuff_tex->width); + + d.imageY = 0; + d.imageH = (wxUint16)rdp.tbuff_tex->height; + d.frameY = (wxUint16)ul_y; + d.frameH = (wxUint16)(rdp.tbuff_tex->height); + FRDP("texrect. ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d, width: %d, height: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.tbuff_tex->width, rdp.tbuff_tex->height); + d.scaleX = 1.0f; + d.scaleY = 1.0f; + DrawHiresImage(d, rdp.tbuff_tex->width == rdp.ci_width); + rdp.tbuff_tex->drawn = TRUE; + } + return; + } + //*/ + // framebuffer workaround for Zelda: MM LOT + if ((rdp.othermode_l & 0xFFFF0000) == 0x0f5a0000) + return; + + /*Gonetz*/ + //hack for Zelda MM. it removes black texrects which cover all geometry in "Link meets Zelda" cut scene + if ((settings.hacks&hack_Zelda) && rdp.timg.addr >= rdp.cimg && rdp.timg.addr < rdp.ci_end) + { + FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.cur_cache[0]->addr, rdp.cimg, rdp.cimg+rdp.ci_width*rdp.ci_height*2); + rdp.tri_n += 2; + return; + } + //* + //hack for Banjo2. it removes black texrects under Banjo + if (!fb_hwfbe_enabled && ((rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF)) == 0xFFFFFFFF && (rdp.othermode_l & 0xFFFF0000) == 0x00500000) + { + rdp.tri_n += 2; + return; + } + //*/ + //* + //remove motion blur in night vision + if ((settings.ucode == ucode_PerfectDark) && (rdp.maincimg[1].addr != rdp.maincimg[0].addr) && (rdp.timg.addr >= rdp.maincimg[1].addr) && (rdp.timg.addr < (rdp.maincimg[1].addr+rdp.ci_width*rdp.ci_height*rdp.ci_size))) + { + if (fb_emulation_enabled) + if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self) + { + //FRDP("Wrong Texrect. texaddr: %08lx, cimg: %08lx, cimg_end: %08lx\n", rdp.timg.addr, rdp.maincimg[1], rdp.maincimg[1]+rdp.ci_width*rdp.ci_height*rdp.ci_size); + LRDP("Wrong Texrect.\n"); + rdp.tri_n += 2; + return; + } + } + //*/ + + int i; + + wxUint32 tile = (wxUint16)((rdp.cmd1 & 0x07000000) >> 24); + + rdp.texrecting = 1; + + wxUint32 prev_tile = rdp.cur_tile; + rdp.cur_tile = tile; + + const float Z = set_sprite_combine_mode (); + + rdp.texrecting = 0; + + if (!rdp.cur_cache[0]) + { + rdp.cur_tile = prev_tile; + rdp.tri_n += 2; + return; + } + // **** + // ** Texrect offset by Gugaman ** + // + //integer representation of texture coordinate. + //needed to detect and avoid overflow after shifting + wxInt32 off_x_i = (rdp.cmd2 >> 16) & 0xFFFF; + wxInt32 off_y_i = rdp.cmd2 & 0xFFFF; + float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f; + float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f; + if (off_x_i & 0x8000) //check for sign bit + off_x_i |= ~0xffff; //make it negative + //the same as for off_x_i + if (off_y_i & 0x8000) + off_y_i |= ~0xffff; + + if (rdp.cycle_mode == 2) + dsdx /= 4.0f; + + float s_ul_x = ul_x * rdp.scale_x + rdp.offset_x; + float s_lr_x = lr_x * rdp.scale_x + rdp.offset_x; + float s_ul_y = ul_y * rdp.scale_y + rdp.offset_y; + float s_lr_y = lr_y * rdp.scale_y + rdp.offset_y; + + FRDP("texrect (%.2f, %.2f, %.2f, %.2f), tile: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, tile, rdp.tri_n, rdp.tri_n+1); + FRDP ("(%f, %f) -> (%f, %f), s: (%d, %d) -> (%d, %d)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y, rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); + FRDP("\toff_x: %f, off_y: %f, dsdx: %f, dtdy: %f\n", off_x_i/32.0f, off_y_i/32.0f, dsdx, dtdy); + + float off_size_x; + float off_size_y; + + if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip + { +#ifdef TEXTURE_FILTER + if (rdp.cur_cache[0]->is_hires_tex) + { + off_size_x = (float)((lr_y - ul_y) * dsdx); + off_size_y = (float)((lr_x - ul_x) * dtdy); + } + else +#endif + { + off_size_x = (lr_y - ul_y - 1) * dsdx; + off_size_y = (lr_x - ul_x - 1) * dtdy; + } + } + else + { +#ifdef TEXTURE_FILTER + if (rdp.cur_cache[0]->is_hires_tex) + { + off_size_x = (float)((lr_x - ul_x) * dsdx); + off_size_y = (float)((lr_y - ul_y) * dtdy); + } + else +#endif + { + off_size_x = (lr_x - ul_x - 1) * dsdx; + off_size_y = (lr_y - ul_y - 1) * dtdy; + } + } + + struct { + float ul_u, ul_v, lr_u, lr_v; + } texUV[2]; //struct for texture coordinates + //angrylion's macro, helps to cut overflowed values. + #define SIGN16(x) (((x) & 0x8000) ? ((x) | ~0xffff) : ((x) & 0xffff)) + + //calculate texture coordinates + for (int i = 0; i < 2; i++) + { + if (rdp.cur_cache[i] && (rdp.tex & (i+1))) + { + float sx = 1, sy = 1; + int x_i = off_x_i, y_i = off_y_i; + TILE & tile = rdp.tiles[rdp.cur_tile + i]; + //shifting + if (tile.shift_s) + { + if (tile.shift_s > 10) + { + wxUint8 iShift = (16 - tile.shift_s); + x_i <<= iShift; + sx = (float)(1 << iShift); + } + else + { + wxUint8 iShift = tile.shift_s; + x_i >>= iShift; + sx = 1.0f/(float)(1 << iShift); + } + } + if (tile.shift_t) + { + if (tile.shift_t > 10) + { + wxUint8 iShift = (16 - tile.shift_t); + y_i <<= iShift; + sy = (float)(1 << iShift); + } + else + { + wxUint8 iShift = tile.shift_t; + y_i >>= iShift; + sy = 1.0f/(float)(1 << iShift); + } + } + + if (rdp.aTBuffTex[i]) //hwfbe texture + { + float t0_off_x; + float t0_off_y; + if (off_x_i + off_y_i == 0) + { + t0_off_x = tile.ul_s; + t0_off_y = tile.ul_t; + } + else + { + t0_off_x = off_x_i/32.0f; + t0_off_y = off_y_i/32.0f; + } + t0_off_x += rdp.aTBuffTex[i]->u_shift;// + tile.ul_s; //commented for Paper Mario motion blur + t0_off_y += rdp.aTBuffTex[i]->v_shift;// + tile.ul_t; + texUV[i].ul_u = t0_off_x * sx; + texUV[i].ul_v = t0_off_y * sy; + + texUV[i].lr_u = texUV[i].ul_u + off_size_x * sx; + texUV[i].lr_v = texUV[i].ul_v + off_size_y * sy; + + texUV[i].ul_u *= rdp.aTBuffTex[i]->u_scale; + texUV[i].ul_v *= rdp.aTBuffTex[i]->v_scale; + texUV[i].lr_u *= rdp.aTBuffTex[i]->u_scale; + texUV[i].lr_v *= rdp.aTBuffTex[i]->v_scale; + FRDP("tbuff_tex[%d] ul_u: %f, ul_v: %f, lr_u: %f, lr_v: %f\n", + i, texUV[i].ul_u, texUV[i].ul_v, texUV[i].lr_u, texUV[i].lr_v); + } + else //common case + { + //kill 10.5 format overflow by SIGN16 macro + texUV[i].ul_u = SIGN16(x_i) / 32.0f; + texUV[i].ul_v = SIGN16(y_i) / 32.0f; + + texUV[i].ul_u -= tile.f_ul_s; + texUV[i].ul_v -= tile.f_ul_t; + + texUV[i].lr_u = texUV[i].ul_u + off_size_x * sx; + texUV[i].lr_v = texUV[i].ul_v + off_size_y * sy; + + texUV[i].ul_u = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_x * texUV[i].ul_u; + texUV[i].lr_u = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_x * texUV[i].lr_u; + texUV[i].ul_v = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_y * texUV[i].ul_v; + texUV[i].lr_v = rdp.cur_cache[i]->c_off + rdp.cur_cache[i]->c_scl_y * texUV[i].lr_v; + } + } + else + { + texUV[i].ul_u = texUV[i].ul_v = texUV[i].lr_u = texUV[i].lr_v = 0; + } + } + rdp.cur_tile = prev_tile; + + // **** + + FRDP (" scissor: (%d, %d) -> (%d, %d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, rdp.scissor.lr_y); + + CCLIP2 (s_ul_x, s_lr_x, texUV[0].ul_u, texUV[0].lr_u, texUV[1].ul_u, texUV[1].lr_u, (float)rdp.scissor.ul_x, (float)rdp.scissor.lr_x); + CCLIP2 (s_ul_y, s_lr_y, texUV[0].ul_v, texUV[0].lr_v, texUV[1].ul_v, texUV[1].lr_v, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y); + + FRDP (" draw at: (%f, %f) -> (%f, %f)\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y); + + VERTEX vstd[4] = { + { s_ul_x, s_ul_y, Z, 1.0f, texUV[0].ul_u, texUV[0].ul_v, texUV[1].ul_u, texUV[1].ul_v, {0, 0, 0, 0}, 255 }, + { s_lr_x, s_ul_y, Z, 1.0f, texUV[0].lr_u, texUV[0].ul_v, texUV[1].lr_u, texUV[1].ul_v, {0, 0, 0, 0}, 255 }, + { s_ul_x, s_lr_y, Z, 1.0f, texUV[0].ul_u, texUV[0].lr_v, texUV[1].ul_u, texUV[1].lr_v, {0, 0, 0, 0}, 255 }, + { s_lr_x, s_lr_y, Z, 1.0f, texUV[0].lr_u, texUV[0].lr_v, texUV[1].lr_u, texUV[1].lr_v, {0, 0, 0, 0}, 255 } }; + + if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip + { + vstd[1].u0 = texUV[0].ul_u; + vstd[1].v0 = texUV[0].lr_v; + vstd[1].u1 = texUV[1].ul_u; + vstd[1].v1 = texUV[1].lr_v; + + vstd[2].u0 = texUV[0].lr_u; + vstd[2].v0 = texUV[0].ul_v; + vstd[2].u1 = texUV[1].lr_u; + vstd[2].v1 = texUV[1].ul_v; + } + + VERTEX *vptr = vstd; + int n_vertices = 4; + + VERTEX *vnew = 0; + // for (int j =0; j < 4; j++) + // FRDP("v[%d] u0: %f, v0: %f, u1: %f, v1: %f\n", j, vstd[j].u0, vstd[j].v0, vstd[j].u1, vstd[j].v1); + + + if (!rdp.aTBuffTex[0] && rdp.cur_cache[0]->splits != 1) + { + // ** LARGE TEXTURE HANDLING ** + // *VERY* simple algebra for texrects + float min_u, min_x, max_u, max_x; + if (vstd[0].u0 < vstd[1].u0) + { + min_u = vstd[0].u0; + min_x = vstd[0].x; + max_u = vstd[1].u0; + max_x = vstd[1].x; + } + else + { + min_u = vstd[1].u0; + min_x = vstd[1].x; + max_u = vstd[0].u0; + max_x = vstd[0].x; + } + + int start_u_256, end_u_256; + start_u_256 = (int)min_u >> 8; + end_u_256 = (int)max_u >> 8; + //FRDP(" min_u: %f, max_u: %f start: %d, end: %d\n", min_u, max_u, start_u_256, end_u_256); + + int splitheight = rdp.cur_cache[0]->splitheight; + + int num_verts_line = 2 + ((end_u_256-start_u_256)<<1); + n_vertices = num_verts_line << 1; + vnew = new VERTEX [n_vertices]; + vptr = vnew; + + vnew[0] = vstd[0]; + vnew[0].u0 -= 256.0f * start_u_256; + vnew[0].v0 += splitheight * start_u_256; + vnew[0].u1 -= 256.0f * start_u_256; + vnew[0].v1 += splitheight * start_u_256; + vnew[1] = vstd[2]; + vnew[1].u0 -= 256.0f * start_u_256; + vnew[1].v0 += splitheight * start_u_256; + vnew[1].u1 -= 256.0f * start_u_256; + vnew[1].v1 += splitheight * start_u_256; + vnew[n_vertices-2] = vstd[1]; + vnew[n_vertices-2].u0 -= 256.0f * end_u_256; + vnew[n_vertices-2].v0 += splitheight * end_u_256; + vnew[n_vertices-2].u1 -= 256.0f * end_u_256; + vnew[n_vertices-2].v1 += splitheight * end_u_256; + vnew[n_vertices-1] = vstd[3]; + vnew[n_vertices-1].u0 -= 256.0f * end_u_256; + vnew[n_vertices-1].v0 += splitheight * end_u_256; + vnew[n_vertices-1].u1 -= 256.0f * end_u_256; + vnew[n_vertices-1].v1 += splitheight * end_u_256; + + // find the equation of the line of u,x + float m = (max_x - min_x) / (max_u - min_u); // m = delta x / delta u + float b = min_x - m * min_u; // b = y - m * x + + for (i=start_u_256; i 12) + { + float texbound = (float)(splitheight << 1); + for (int k = 0; k < n_vertices; k ++) + { + if (vnew[k].v0 > texbound) + vnew[k].v0 = (float)fmod(vnew[k].v0, texbound); + } + } + //*/ + } + + AllowShadeMods (vptr, n_vertices); + for (i=0; i= RDP::fog_blend) + { + float fog; + if (rdp.fog_mode == RDP::fog_blend) + fog = 1.0f/max(1, rdp.fog_color&0xFF); + else + fog = 1.0f/max(1, (~rdp.fog_color)&0xFF); + for (i = 0; i < n_vertices; i++) + { + vptr[i].f = fog; + } + grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT); + } + + ConvertCoordsConvert (vptr, n_vertices); + + if (settings.wireframe) + { + SetWireframeCol (); + grDrawLine (&vstd[0], &vstd[2]); + grDrawLine (&vstd[2], &vstd[1]); + grDrawLine (&vstd[1], &vstd[0]); + grDrawLine (&vstd[2], &vstd[3]); + grDrawLine (&vstd[3], &vstd[1]); + } + else + { + grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, n_vertices, vptr, sizeof(VERTEX)); + } + + if (_debugger.capture) + { + VERTEX vl[3]; + vl[0] = vstd[0]; + vl[1] = vstd[2]; + vl[2] = vstd[1]; + add_tri (vl, 3, TRI_TEXRECT); + rdp.tri_n ++; + vl[0] = vstd[2]; + vl[1] = vstd[3]; + vl[2] = vstd[1]; + add_tri (vl, 3, TRI_TEXRECT); + rdp.tri_n ++; + } + else + rdp.tri_n += 2; + } + else + { + rdp.tri_n += 2; + } + + delete[] vnew; +} + +static void rdp_loadsync() +{ + LRDP("loadsync - ignored\n"); +} + +static void rdp_pipesync() +{ + LRDP("pipesync - ignored\n"); +} + +static void rdp_tilesync() +{ + LRDP("tilesync - ignored\n"); +} + +static void rdp_fullsync() +{ + // Set an interrupt to allow the game to continue + *gfx.MI_INTR_REG |= 0x20; + gfx.CheckInterrupts(); + LRDP("fullsync\n"); +} + +static void rdp_setkeygb() +{ + wxUint32 sB = rdp.cmd1&0xFF; + wxUint32 cB = (rdp.cmd1>>8)&0xFF; + wxUint32 sG = (rdp.cmd1>>16)&0xFF; + wxUint32 cG = (rdp.cmd1>>24)&0xFF; + rdp.SCALE = (rdp.SCALE&0xFF0000FF) | (sG<<16) | (sB<<8); + rdp.CENTER = (rdp.CENTER&0xFF0000FF) | (cG<<16) | (cB<<8); + FRDP("setkeygb. cG=%02lx, sG=%02lx, cB=%02lx, sB=%02lx\n", cG, sG, cB, sB); +} + +static void rdp_setkeyr() +{ + wxUint32 sR = rdp.cmd1&0xFF; + wxUint32 cR = (rdp.cmd1>>8)&0xFF; + rdp.SCALE = (rdp.SCALE&0x00FFFFFF) | (sR<<24); + rdp.CENTER = (rdp.CENTER&0x00FFFFFF) | (cR<<24); + FRDP("setkeyr. cR=%02lx, sR=%02lx\n", cR, sR); +} + +static void rdp_setconvert() +{ + /* + rdp.YUV_C0 = 1.1647f ; + rdp.YUV_C1 = 0.79931f ; + rdp.YUV_C2 = -0.1964f ; + rdp.YUV_C3 = -0.40651f; + rdp.YUV_C4 = 1.014f ; + */ + rdp.K4 = (wxUint8)(rdp.cmd1>>9)&0x1FF; + rdp.K5 = (wxUint8)(rdp.cmd1&0x1FF); + // RDP_E("setconvert - IGNORED\n"); + FRDP("setconvert. K4=%02lx K5=%02lx\n", rdp.K4, rdp.K5); +} + +// +// setscissor - sets the screen clipping rectangle +// + +static void rdp_setscissor() +{ + // clipper resolution is 320x240, scale based on computer resolution + rdp.scissor_o.ul_x = /*min(*/(wxUint32)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/; + rdp.scissor_o.ul_y = /*min(*/(wxUint32)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/; + rdp.scissor_o.lr_x = /*min(*/(wxUint32)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/; + rdp.scissor_o.lr_y = /*min(*/(wxUint32)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/; + + rdp.ci_upper_bound = rdp.scissor_o.ul_y; + rdp.ci_lower_bound = rdp.scissor_o.lr_y; + rdp.scissor_set = TRUE; + + FRDP("setscissor: (%d,%d) -> (%d,%d)\n", rdp.scissor_o.ul_x, rdp.scissor_o.ul_y, + rdp.scissor_o.lr_x, rdp.scissor_o.lr_y); + + rdp.update |= UPDATE_SCISSOR; + + if (rdp.view_scale[0] == 0) //viewport is not set? + { + rdp.view_scale[0] = (rdp.scissor_o.lr_x>>1)*rdp.scale_x; + rdp.view_scale[1] = (rdp.scissor_o.lr_y>>1)*-rdp.scale_y; + rdp.view_trans[0] = rdp.view_scale[0]; + rdp.view_trans[1] = -rdp.view_scale[1]; + rdp.update |= UPDATE_VIEWPORT; + } +} + +static void rdp_setprimdepth() +{ + rdp.prim_depth = (wxUint16)((rdp.cmd1 >> 16) & 0x7FFF); + rdp.prim_dz = (wxUint16)(rdp.cmd1 & 0x7FFF); + + FRDP("setprimdepth: %d\n", rdp.prim_depth); +} + +static void rdp_setothermode() +{ +#define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \ + rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \ + rdp.cmd1 = data; \ + gfx_instruction[settings.ucode][cmd] (); \ +} +#define SETOTHERMODE(cmd,sft,len,data) { \ + rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \ + rdp.cmd1 = data; \ + gfx_instruction[settings.ucode][cmd] (); \ +} + + LRDP("rdp_setothermode\n"); + + if ((settings.ucode == ucode_F3DEX2) || (settings.ucode == ucode_CBFD)) + { + int cmd0 = rdp.cmd0; + F3DEX2_SETOTHERMODE(0xE2, 0, 32, rdp.cmd1); // SETOTHERMODE_L + F3DEX2_SETOTHERMODE(0xE3, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H + } + else + { + int cmd0 = rdp.cmd0; + SETOTHERMODE(0xB9, 0, 32, rdp.cmd1); // SETOTHERMODE_L + SETOTHERMODE(0xBA, 0, 32, cmd0 & 0x00FFFFFF); // SETOTHERMODE_H + } +} + +void load_palette (wxUint32 addr, wxUint16 start, wxUint16 count) +{ + LRDP("Loading palette... "); + wxUint16 *dpal = rdp.pal_8 + start; + wxUint16 end = start+count; +#ifdef TEXTURE_FILTER + wxUint16 *spal = (wxUint16*)(gfx.RDRAM + (addr & BMASK)); +#endif + + for (wxUint16 i=start; i>= 4; + end = start + (count >> 4); + if (end == start) // it can be if count < 16 + end = start + 1; + for (wxUint16 p = start; p < end; p++) + { + rdp.pal_8_crc[p] = CRC32( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 ); + } + rdp.pal_256_crc = CRC32( 0xFFFFFFFF, rdp.pal_8_crc, 64 ); + LRDP("Done.\n"); +} + +static void rdp_loadtlut() +{ + wxUint32 tile = (rdp.cmd1 >> 24) & 0x07; + wxUint16 start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes + // wxUint16 start = ((wxUint16)(rdp.cmd1 >> 2) & 0x3FF) + 1; + wxUint16 count = ((wxUint16)(rdp.cmd1 >> 14) & 0x3FF) + 1; // number to copy + + if (rdp.timg.addr + (count<<1) > BMASK) + count = (wxUint16)((BMASK - rdp.timg.addr) >> 1); + + if (start+count > 256) count = 256-start; + + FRDP("loadtlut: tile: %d, start: %d, count: %d, from: %08lx\n", tile, start, count, + rdp.timg.addr); + + load_palette (rdp.timg.addr, start, count); + + rdp.timg.addr += count << 1; + + if (rdp.tbuff_tex) //paranoid check. + { + //the buffer is definitely wrong, as there must be no CI frame buffers + //find and remove it + for (int i = 0; i < voodoo.num_tmu; i++) + { + for (int j = 0; j < rdp.texbufs[i].count; j++) + { + if (&(rdp.texbufs[i].images[j]) == rdp.tbuff_tex) + { + rdp.texbufs[i].count--; + if (j < rdp.texbufs[i].count) + memcpy(&(rdp.texbufs[i].images[j]), &(rdp.texbufs[i].images[j+1]), sizeof(TBUFF_COLOR_IMAGE)*(rdp.texbufs[i].count-j)); + return; + } + } + } + } +} + +int tile_set = 0; +static void rdp_settilesize() +{ + wxUint32 tile = (rdp.cmd1 >> 24) & 0x07; + rdp.last_tile_size = tile; + + rdp.tiles[tile].f_ul_s = (float)((rdp.cmd0 >> 12) & 0xFFF) / 4.0f; + rdp.tiles[tile].f_ul_t = (float)(rdp.cmd0 & 0xFFF) / 4.0f; + + int ul_s = (((wxUint16)(rdp.cmd0 >> 14)) & 0x03ff); + int ul_t = (((wxUint16)(rdp.cmd0 >> 2 )) & 0x03ff); + int lr_s = (((wxUint16)(rdp.cmd1 >> 14)) & 0x03ff); + int lr_t = (((wxUint16)(rdp.cmd1 >> 2 )) & 0x03ff); + + if (lr_s == 0 && ul_s == 0) //pokemon puzzle league set such tile size + wrong_tile = tile; + else if (wrong_tile == (int)tile) + wrong_tile = -1; + + if (settings.use_sts1_only) + { + // ** USE FIRST SETTILESIZE ONLY ** + // This option helps certain textures while using the 'Alternate texture size method', + // but may break others. (should help more than break) + + if (tile_set) + { + // coords in 10.2 format + rdp.tiles[tile].ul_s = ul_s; + rdp.tiles[tile].ul_t = ul_t; + rdp.tiles[tile].lr_s = lr_s; + rdp.tiles[tile].lr_t = lr_t; + tile_set = 0; + } + } + else + { + // coords in 10.2 format + rdp.tiles[tile].ul_s = ul_s; + rdp.tiles[tile].ul_t = ul_t; + rdp.tiles[tile].lr_s = lr_s; + rdp.tiles[tile].lr_t = lr_t; + } + + // handle wrapping + if (rdp.tiles[tile].lr_s < rdp.tiles[tile].ul_s) rdp.tiles[tile].lr_s += 0x400; + if (rdp.tiles[tile].lr_t < rdp.tiles[tile].ul_t) rdp.tiles[tile].lr_t += 0x400; + + rdp.update |= UPDATE_TEXTURE; + + rdp.first = 1; + + FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d, f_ul_s: %f, f_ul_t: %f\n", + tile, ul_s, ul_t, lr_s, lr_t, rdp.tiles[tile].f_ul_s, rdp.tiles[tile].f_ul_t); +} + +void setTBufTex(wxUint16 t_mem, wxUint32 cnt) +{ + FRDP("setTBufTex t_mem=%d, cnt=%d\n", t_mem, cnt); + TBUFF_COLOR_IMAGE * pTbufTex = rdp.tbuff_tex; + for (int i = 0; i < 2; i++) + { + LRDP("Before: "); + if (rdp.aTBuffTex[i]) { + FRDP("rdp.aTBuffTex[%d]: tmu=%d t_mem=%d tile=%d\n", i, rdp.aTBuffTex[i]->tmu, rdp.aTBuffTex[i]->t_mem, rdp.aTBuffTex[i]->tile); + } else { + FRDP("rdp.aTBuffTex[%d]=0\n", i); + } + if ((rdp.aTBuffTex[i] == 0 && rdp.aTBuffTex[i^1] != pTbufTex) || (rdp.aTBuffTex[i] && rdp.aTBuffTex[i]->t_mem >= t_mem && rdp.aTBuffTex[i]->t_mem < t_mem + cnt)) + { + if (pTbufTex) + { + rdp.aTBuffTex[i] = pTbufTex; + rdp.aTBuffTex[i]->t_mem = t_mem; + pTbufTex = 0; + FRDP("rdp.aTBuffTex[%d] tmu=%d t_mem=%d\n", i, rdp.aTBuffTex[i]->tmu, rdp.aTBuffTex[i]->t_mem); + } + else + { + rdp.aTBuffTex[i] = 0; + FRDP("rdp.aTBuffTex[%d]=0\n", i); + } + } + } +} + +static inline void loadBlock(uint32_t *src, uint32_t *dst, uint32_t off, int dxt, int cnt) +{ + uint32_t *v5; + int v6; + uint32_t *v7; + uint32_t v8; + int v9; + uint32_t v10; + uint32_t *v11; + uint32_t v12; + uint32_t v13; + uint32_t v14; + int v15; + int v16; + uint32_t *v17; + int v18; + uint32_t v19; + uint32_t v20; + int i; + + v5 = dst; + v6 = cnt; + if ( cnt ) + { + v7 = (uint32_t *)((char *)src + (off & 0xFFFFFFFC)); + v8 = off & 3; + if ( !(off & 3) ) + goto LABEL_23; + v9 = 4 - v8; + v10 = *v7; + v11 = v7 + 1; + do + { + v10 = __ROL__(v10, 8); + --v8; + } + while ( v8 ); + do + { + v10 = __ROL__(v10, 8); + *(uint8_t *)v5 = v10; + v5 = (uint32_t *)((char *)v5 + 1); + --v9; + } + while ( v9 ); + v12 = *v11; + v7 = v11 + 1; + *v5 = bswap32(v12); + ++v5; + v6 = cnt - 1; + if ( cnt != 1 ) + { +LABEL_23: + do + { + *v5 = bswap32(*v7); + v5[1] = bswap32(v7[1]); + v7 += 2; + v5 += 2; + --v6; + } + while ( v6 ); + } + v13 = off & 3; + if ( off & 3 ) + { + v14 = *(uint32_t *)((char *)src + ((8 * cnt + off) & 0xFFFFFFFC)); + do + { + v14 = __ROL__(v14, 8); + *(uint8_t *)v5 = v14; + v5 = (uint32_t *)((char *)v5 + 1); + --v13; + } + while ( v13 ); + } + } + v15 = cnt; + v16 = 0; + v17 = dst; + v18 = 0; +dxt_test: + while ( 1 ) + { + v17 += 2; + --v15; + if ( !v15 ) + break; + v16 += dxt; + if ( v16 < 0 ) + { + while ( 1 ) + { + ++v18; + --v15; + if ( !v15 ) + goto end_dxt_test; + v16 += dxt; + if ( v16 >= 0 ) + { + for ( i = v15; v18; --v18 ) + { + v19 = *v17; + *v17 = v17[1]; + v17[1] = v19; + v17 += 2; + } + v15 = i; + goto dxt_test; + } + } + } + } +end_dxt_test: + while ( v18 ) + { + v20 = *v17; + *v17 = v17[1]; + v17[1] = v20; + v17 += 2; + --v18; + } +} + +void LoadBlock32b(wxUint32 tile, wxUint32 ul_s, wxUint32 ul_t, wxUint32 lr_s, wxUint32 dxt); +static void rdp_loadblock() +{ + if (rdp.skip_drawing) + { + LRDP("loadblock skipped\n"); + return; + } + wxUint32 tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07); + wxUint32 dxt = (wxUint32)(rdp.cmd1 & 0x0FFF); + wxUint16 lr_s = (wxUint16)(rdp.cmd1 >> 14) & 0x3FF; + if (ucode5_texshiftaddr) + { + if (ucode5_texshift % ((lr_s+1)<<3)) + { + rdp.timg.addr -= ucode5_texshift; + ucode5_texshiftaddr = 0; + ucode5_texshift = 0; + ucode5_texshiftcount = 0; + } + else + ucode5_texshiftcount++; + } + + rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr; + + // ** DXT is used for swapping every other line + /* double fdxt = (double)0x8000000F/(double)((wxUint32)(2047/(dxt-1))); // F for error + wxUint32 _dxt = (wxUint32)fdxt;*/ + + // 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit) + wxUint32 _dxt = dxt << 20; + + wxUint32 addr = segoffset(rdp.timg.addr) & BMASK; + + // lr_s specifies number of 64-bit words to copy + // 10.2 format + wxUint16 ul_s = (wxUint16)(rdp.cmd0 >> 14) & 0x3FF; + wxUint16 ul_t = (wxUint16)(rdp.cmd0 >> 2) & 0x3FF; + + rdp.tiles[tile].ul_s = ul_s; + rdp.tiles[tile].ul_t = ul_t; + rdp.tiles[tile].lr_s = lr_s; + + rdp.timg.set_by = 0; // load block + +#ifdef TEXTURE_FILTER + LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[tile].t_mem]; + info.tile_width = lr_s; + info.dxt = dxt; +#endif + + // do a quick boundary check before copying to eliminate the possibility for exception + if (ul_s >= 512) { + lr_s = 1; // 1 so that it doesn't die on memcpy + ul_s = 511; + } + if (ul_s+lr_s > 512) + lr_s = 512-ul_s; + + if (addr+(lr_s<<3) > BMASK+1) + lr_s = (wxUint16)((BMASK-addr)>>3); + + //angrylion's advice to use ul_s in texture image offset and cnt calculations. + //Helps to fix Vigilante 8 jpeg backgrounds and logos + wxUint32 off = rdp.timg.addr + (ul_s << rdp.tiles[tile].size >> 1); + unsigned char *dst = ((unsigned char *)rdp.tmem) + (rdp.tiles[tile].t_mem<<3); + wxUint32 cnt = lr_s-ul_s+1; + if (rdp.tiles[tile].size == 3) + cnt <<= 1; + + if (((rdp.tiles[tile].t_mem + cnt) << 3) > sizeof(rdp.tmem)) { + WriteLog(M64MSG_INFO, "rdp_loadblock wanted to write %u bytes after the end of tmem", ((rdp.tiles[tile].t_mem + cnt) << 3) - sizeof(rdp.tmem)); + cnt = (sizeof(rdp.tmem) >> 3) - (rdp.tiles[tile].t_mem); + } + + if (rdp.timg.size == 3) + LoadBlock32b(tile, ul_s, ul_t, lr_s, dxt); + else + loadBlock((uint32_t *)gfx.RDRAM, (uint32_t *)dst, off, _dxt, cnt); + + rdp.timg.addr += cnt << 3; + rdp.tiles[tile].lr_t = ul_t + ((dxt*cnt)>>11); + + rdp.update |= UPDATE_TEXTURE; + + FRDP ("loadblock: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, dxt: %08lx -> %08lx\n", + tile, ul_s, ul_t, lr_s, + dxt, _dxt); + + if (fb_hwfbe_enabled) + setTBufTex(rdp.tiles[tile].t_mem, cnt); +} + + +static inline void loadTile(uint32_t *src, uint32_t *dst, int width, int height, int line, int off, uint32_t *end) +{ + uint32_t *v7; + int v8; + uint32_t *v9; + int v10; + int v11; + int v12; + uint32_t *v13; + int v14; + int v15; + uint32_t v16; + uint32_t *v17; + uint32_t v18; + int v19; + uint32_t v20; + int v21; + uint32_t v22; + int v23; + uint32_t *v24; + int v25; + int v26; + uint32_t *v27; + int v28; + int v29; + int v30; + uint32_t *v31; + + v7 = dst; + v8 = width; + v9 = src; + v10 = off; + v11 = 0; + v12 = height; + do + { + if ( end < v7 ) + break; + v31 = v7; + v30 = v8; + v29 = v12; + v28 = v11; + v27 = v9; + v26 = v10; + if ( v8 ) + { + v25 = v8; + v24 = v9; + v23 = v10; + v13 = (uint32_t *)((char *)v9 + (v10 & 0xFFFFFFFC)); + v14 = v10 & 3; + if ( !(v10 & 3) ) + goto LABEL_20; + v15 = 4 - v14; + v16 = *v13; + v17 = v13 + 1; + do + { + v16 = __ROL__(v16, 8); + --v14; + } + while ( v14 ); + do + { + v16 = __ROL__(v16, 8); + *(uint8_t *)v7 = v16; + v7 = (uint32_t *)((char *)v7 + 1); + --v15; + } + while ( v15 ); + v18 = *v17; + v13 = v17 + 1; + *v7 = bswap32(v18); + ++v7; + --v8; + if ( v8 ) + { +LABEL_20: + do + { + *v7 = bswap32(*v13); + v7[1] = bswap32(v13[1]); + v13 += 2; + v7 += 2; + --v8; + } + while ( v8 ); + } + v19 = v23 & 3; + if ( v23 & 3 ) + { + v20 = *(uint32_t *)((char *)v24 + ((8 * v25 + v23) & 0xFFFFFFFC)); + do + { + v20 = __ROL__(v20, 8); + *(uint8_t *)v7 = v20; + v7 = (uint32_t *)((char *)v7 + 1); + --v19; + } + while ( v19 ); + } + } + v9 = v27; + v21 = v29; + v8 = v30; + v11 = v28 ^ 1; + if ( v28 == 1 ) + { + v7 = v31; + if ( v30 ) + { + do + { + v22 = *v7; + *v7 = v7[1]; + v7[1] = v22; + v7 += 2; + --v8; + } + while ( v8 ); + } + v21 = v29; + v8 = v30; + } + v10 = line + v26; + v12 = v21 - 1; + } + while ( v12 ); +} + +void LoadTile32b (wxUint32 tile, wxUint32 ul_s, wxUint32 ul_t, wxUint32 width, wxUint32 height); +static void rdp_loadtile() +{ + if (rdp.skip_drawing) + { + LRDP("loadtile skipped\n"); + return; + } + rdp.timg.set_by = 1; // load tile + + wxUint32 tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07); + + rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr; + + wxUint16 ul_s = (wxUint16)((rdp.cmd0 >> 14) & 0x03FF); + wxUint16 ul_t = (wxUint16)((rdp.cmd0 >> 2 ) & 0x03FF); + wxUint16 lr_s = (wxUint16)((rdp.cmd1 >> 14) & 0x03FF); + wxUint16 lr_t = (wxUint16)((rdp.cmd1 >> 2 ) & 0x03FF); + + if (lr_s < ul_s || lr_t < ul_t) return; + + if (wrong_tile >= 0) //there was a tile with zero length + { + rdp.tiles[wrong_tile].lr_s = lr_s; + + if (rdp.tiles[tile].size > rdp.tiles[wrong_tile].size) + rdp.tiles[wrong_tile].lr_s <<= (rdp.tiles[tile].size - rdp.tiles[wrong_tile].size); + else if (rdp.tiles[tile].size < rdp.tiles[wrong_tile].size) + rdp.tiles[wrong_tile].lr_s >>= (rdp.tiles[wrong_tile].size - rdp.tiles[tile].size); + rdp.tiles[wrong_tile].lr_t = lr_t; + rdp.tiles[wrong_tile].mask_s = rdp.tiles[wrong_tile].mask_t = 0; + // wrong_tile = -1; + } + + if (rdp.tbuff_tex)// && (rdp.tiles[tile].format == 0)) + { + FRDP("loadtile: tbuff_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t); + rdp.tbuff_tex->tile_uls = ul_s; + rdp.tbuff_tex->tile_ult = ul_t; + } + + if ((settings.hacks&hack_Tonic) && tile == 7) + { + rdp.tiles[0].ul_s = ul_s; + rdp.tiles[0].ul_t = ul_t; + rdp.tiles[0].lr_s = lr_s; + rdp.tiles[0].lr_t = lr_t; + } + + wxUint32 height = lr_t - ul_t + 1; // get height + wxUint32 width = lr_s - ul_s + 1; + +#ifdef TEXTURE_FILTER + LOAD_TILE_INFO &info = rdp.load_info[rdp.tiles[tile].t_mem]; + info.tile_ul_s = ul_s; + info.tile_ul_t = ul_t; + info.tile_width = (rdp.tiles[tile].mask_s ? min((wxUint16)width, 1<> 1; + wxUint32 offs = ul_t * line_n; + offs += ul_s << rdp.tiles[tile].size >> 1; + offs += rdp.timg.addr; + if (offs >= BMASK) + return; + + if (rdp.timg.size == 3) + { + LoadTile32b(tile, ul_s, ul_t, width, height); + } + else + { + // check if points to bad location + if (offs + line_n*height > BMASK) + height = (BMASK - offs) / line_n; + if (height == 0) + return; + + wxUint32 wid_64 = rdp.tiles[tile].line; + unsigned char *dst = ((unsigned char *)rdp.tmem) + (rdp.tiles[tile].t_mem<<3); + unsigned char *end = ((unsigned char *)rdp.tmem) + 4096 - (wid_64<<3); + loadTile((uint32_t *)gfx.RDRAM, (uint32_t *)dst, wid_64, height, line_n, offs, (uint32_t *)end); + } + FRDP("loadtile: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n", tile, + ul_s, ul_t, lr_s, lr_t); + + if (fb_hwfbe_enabled) + setTBufTex(rdp.tiles[tile].t_mem, rdp.tiles[tile].line*height); +} + +static void rdp_settile() +{ + tile_set = 1; // used to check if we only load the first settilesize + + rdp.first = 0; + + rdp.last_tile = (wxUint32)((rdp.cmd1 >> 24) & 0x07); + TILE *tile = &rdp.tiles[rdp.last_tile]; + + tile->format = (wxUint8)((rdp.cmd0 >> 21) & 0x07); + tile->size = (wxUint8)((rdp.cmd0 >> 19) & 0x03); + tile->line = (wxUint16)((rdp.cmd0 >> 9) & 0x01FF); + tile->t_mem = (wxUint16)(rdp.cmd0 & 0x1FF); + tile->palette = (wxUint8)((rdp.cmd1 >> 20) & 0x0F); + tile->clamp_t = (wxUint8)((rdp.cmd1 >> 19) & 0x01); + tile->mirror_t = (wxUint8)((rdp.cmd1 >> 18) & 0x01); + tile->mask_t = (wxUint8)((rdp.cmd1 >> 14) & 0x0F); + tile->shift_t = (wxUint8)((rdp.cmd1 >> 10) & 0x0F); + tile->clamp_s = (wxUint8)((rdp.cmd1 >> 9) & 0x01); + tile->mirror_s = (wxUint8)((rdp.cmd1 >> 8) & 0x01); + tile->mask_s = (wxUint8)((rdp.cmd1 >> 4) & 0x0F); + tile->shift_s = (wxUint8)(rdp.cmd1 & 0x0F); + + rdp.update |= UPDATE_TEXTURE; + + FRDP ("settile: tile: %d, format: %s, size: %s, line: %d, " + "t_mem: %08lx, palette: %d, clamp_t/mirror_t: %s, mask_t: %d, " + "shift_t: %d, clamp_s/mirror_s: %s, mask_s: %d, shift_s: %d\n", + rdp.last_tile, str_format[tile->format], str_size[tile->size], tile->line, + tile->t_mem, tile->palette, str_cm[(tile->clamp_t<<1)|tile->mirror_t], tile->mask_t, + tile->shift_t, str_cm[(tile->clamp_s<<1)|tile->mirror_s], tile->mask_s, tile->shift_s); + + if (fb_hwfbe_enabled && rdp.last_tile < rdp.cur_tile + 2) + { + for (int i = 0; i < 2; i++) + { + if (rdp.aTBuffTex[i]) + { + if (rdp.aTBuffTex[i]->t_mem == tile->t_mem) + { + if (rdp.aTBuffTex[i]->size == tile->size) + { + rdp.aTBuffTex[i]->tile = rdp.last_tile; + rdp.aTBuffTex[i]->info.format = tile->format == 0 ? GR_TEXFMT_RGB_565 : GR_TEXFMT_ALPHA_INTENSITY_88; + FRDP("rdp.aTBuffTex[%d] tile=%d, format=%s\n", i, rdp.last_tile, tile->format == 0 ? "RGB565" : "Alpha88"); + } + else + rdp.aTBuffTex[i] = 0; + break; + } + else if (rdp.aTBuffTex[i]->tile == rdp.last_tile) //wrong! t_mem must be the same + rdp.aTBuffTex[i] = 0; + } + } + } +} + +// +// fillrect - fills a rectangle +// + +static void rdp_fillrect() +{ + wxUint32 ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14); + wxUint32 ul_y = (rdp.cmd1 & 0x00000FFF) >> 2; + wxUint32 lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1; + wxUint32 lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1; + if ((ul_x > lr_x) || (ul_y > lr_y)) + { + LRDP("Fillrect. Wrong coordinates. Skipped\n"); + return; + } + int pd_multiplayer = (settings.ucode == ucode_PerfectDark) && (rdp.cycle_mode == 3) && (rdp.fill_color == 0xFFFCFFFC); + if ((rdp.cimg == rdp.zimg) || (fb_emulation_enabled && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg) || pd_multiplayer) + { + LRDP("Fillrect - cleared the depth buffer\n"); + if (fullscreen) + { + if (!(settings.hacks&hack_Hyperbike) || rdp.ci_width > 64) //do not clear main depth buffer for aux depth buffers + { + update_scissor (); + grDepthMask (FXTRUE); + grColorMask (FXFALSE, FXFALSE); + grBufferClear (0, 0, rdp.fill_color ? rdp.fill_color&0xFFFF : 0xFFFF); + grColorMask (FXTRUE, FXTRUE); + rdp.update |= UPDATE_ZBUF_ENABLED; + } + //if (settings.frame_buffer&fb_depth_clear) + { + ul_x = min(max(ul_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x); + lr_x = min(max(lr_x, rdp.scissor_o.ul_x), rdp.scissor_o.lr_x); + ul_y = min(max(ul_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y); + lr_y = min(max(lr_y, rdp.scissor_o.ul_y), rdp.scissor_o.lr_y); + wxUint32 zi_width_in_dwords = rdp.ci_width >> 1; + ul_x >>= 1; + lr_x >>= 1; + wxUint32 * dst = (wxUint32*)(gfx.RDRAM+rdp.cimg); + dst += ul_y * zi_width_in_dwords; + for (wxUint32 y = ul_y; y < lr_y; y++) + { + for (wxUint32 x = ul_x; x < lr_x; x++) + { + dst[x] = rdp.fill_color; + } + dst += zi_width_in_dwords; + } + } + } + return; + } + + if (rdp.skip_drawing) + { + LRDP("Fillrect skipped\n"); + return; + } + + if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x - ul_x) && (rdp.cur_image->height == lr_y - ul_y)) + { + wxUint32 color = rdp.fill_color; + if (rdp.ci_size < 3) + { + color = ((color&1)?0xFF:0) | + ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | + ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | + ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8); + } + grDepthMask (FXFALSE); + grBufferClear (color, 0, 0xFFFF); + grDepthMask (FXTRUE); + rdp.update |= UPDATE_ZBUF_ENABLED; + LRDP("Fillrect - cleared the texture buffer\n"); + return; + } + + // Update scissor + if (fullscreen) + update_scissor (); + + if (settings.decrease_fillrect_edge && rdp.cycle_mode == 0) + { + lr_x--; lr_y--; + } + FRDP("fillrect (%d,%d) -> (%d,%d), cycle mode: %d, #%d, #%d\n", ul_x, ul_y, lr_x, lr_y, rdp.cycle_mode, + rdp.tri_n, rdp.tri_n+1); + + FRDP("scissor (%d,%d) -> (%d,%d)\n", rdp.scissor.ul_x, rdp.scissor.ul_y, rdp.scissor.lr_x, + rdp.scissor.lr_y); + + // KILL the floating point error with 0.01f + wxInt32 s_ul_x = (wxUint32)min(max(ul_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x); + wxInt32 s_lr_x = (wxUint32)min(max(lr_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x); + wxInt32 s_ul_y = (wxUint32)min(max(ul_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y); + wxInt32 s_lr_y = (wxUint32)min(max(lr_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y); + + if (s_lr_x < 0) s_lr_x = 0; + if (s_lr_y < 0) s_lr_y = 0; + if ((wxUint32)s_ul_x > settings.res_x) s_ul_x = settings.res_x; + if ((wxUint32)s_ul_y > settings.res_y) s_ul_y = settings.res_y; + + FRDP (" - %d, %d, %d, %d\n", s_ul_x, s_ul_y, s_lr_x, s_lr_y); + + if (fullscreen) + { + grFogMode (GR_FOG_DISABLE); + + const float Z = (rdp.cycle_mode == 3) ? 0.0f : set_sprite_combine_mode(); + + // Draw the rectangle + VERTEX v[4] = { + { (float)s_ul_x, (float)s_ul_y, Z, 1.0f, 0,0,0,0, {0,0,0,0}, 0,0, 0,0,0,0}, + { (float)s_lr_x, (float)s_ul_y, Z, 1.0f, 0,0,0,0, {0,0,0,0}, 0,0, 0,0,0,0}, + { (float)s_ul_x, (float)s_lr_y, Z, 1.0f, 0,0,0,0, {0,0,0,0}, 0,0, 0,0,0,0}, + { (float)s_lr_x, (float)s_lr_y, Z, 1.0f, 0,0,0,0, {0,0,0,0}, 0,0, 0,0,0,0} }; + + if (rdp.cycle_mode == 3) + { + wxUint32 color = rdp.fill_color; + + if ((settings.hacks&hack_PMario) && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) + { + //background of auxiliary frame buffers must have zero alpha. + //make it black, set 0 alpha to plack pixels on frame buffer read + color = 0; + } + else if (rdp.ci_size < 3) + { + color = ((color&1)?0xFF:0) | + ((wxUint32)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | + ((wxUint32)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | + ((wxUint32)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8); + } + + grConstantColorValue (color); + + grColorCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, + GR_COMBINE_OTHER_NONE, + FXFALSE); + + grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, + GR_COMBINE_OTHER_NONE, + FXFALSE); + + grAlphaBlendFunction (GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ONE, GR_BLEND_ZERO); + + grAlphaTestFunction (GR_CMP_ALWAYS); + if (grStippleModeExt) + grStippleModeExt(GR_STIPPLE_DISABLE); + + grCullMode(GR_CULL_DISABLE); + grFogMode (GR_FOG_DISABLE); + grDepthBufferFunction (GR_CMP_ALWAYS); + grDepthMask (FXFALSE); + + rdp.update |= UPDATE_COMBINE | UPDATE_CULL_MODE | UPDATE_FOG_ENABLED | UPDATE_ZBUF_ENABLED; + } + else + { + wxUint32 cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF); + wxUint32 cmb_mode_a = (rdp.cycle1 & 0x0FFF0000) | ((rdp.cycle2 >> 16) & 0x00000FFF); + if (cmb_mode_c == 0x9fff9fff || cmb_mode_a == 0x09ff09ff) //shade + { + AllowShadeMods (v, 4); + for (int k = 0; k < 4; k++) + apply_shade_mods (&v[k]); + } + if ((rdp.othermode_l & 0x4000) && ((rdp.othermode_l >> 16) == 0x0550)) //special blender mode for Bomberman64 + { + grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, + GR_COMBINE_OTHER_NONE, + FXFALSE); + grConstantColorValue((cmb.ccolor&0xFFFFFF00)|(rdp.fog_color&0xFF)); + rdp.update |= UPDATE_COMBINE; + } + } + + if (settings.wireframe) + { + SetWireframeCol (); + grDrawLine (&v[0], &v[2]); + grDrawLine (&v[2], &v[1]); + grDrawLine (&v[1], &v[0]); + grDrawLine (&v[2], &v[3]); + grDrawLine (&v[3], &v[1]); + //grDrawLine (&v[1], &v[2]); + } + else + { + grDrawTriangle (&v[0], &v[2], &v[1]); + grDrawTriangle (&v[2], &v[3], &v[1]); + } + + if (_debugger.capture) + { + VERTEX v1[3]; + v1[0] = v[0]; + v1[1] = v[2]; + v1[2] = v[1]; + add_tri (v1, 3, TRI_FILLRECT); + rdp.tri_n ++; + v1[0] = v[2]; + v1[1] = v[3]; + add_tri (v1, 3, TRI_FILLRECT); + rdp.tri_n ++; + } + else + rdp.tri_n += 2; + } + else + { + rdp.tri_n += 2; + } +} + +// +// setfillcolor - sets the filling color +// + +static void rdp_setfillcolor() +{ + rdp.fill_color = rdp.cmd1; + rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE; + + FRDP("setfillcolor: %08lx\n", rdp.cmd1); +} + +static void rdp_setfogcolor() +{ + rdp.fog_color = rdp.cmd1; + rdp.update |= UPDATE_COMBINE | UPDATE_FOG_ENABLED; + + FRDP("setfogcolor - %08lx\n", rdp.cmd1); +} + +static void rdp_setblendcolor() +{ + rdp.blend_color = rdp.cmd1; + rdp.update |= UPDATE_COMBINE; + + FRDP("setblendcolor: %08lx\n", rdp.cmd1); +} + +static void rdp_setprimcolor() +{ + rdp.prim_color = rdp.cmd1; + rdp.prim_lodmin = (rdp.cmd0 >> 8) & 0xFF; + rdp.prim_lodfrac = max(rdp.cmd0 & 0xFF, rdp.prim_lodmin); + rdp.update |= UPDATE_COMBINE; + + FRDP("setprimcolor: %08lx, lodmin: %d, lodfrac: %d\n", rdp.cmd1, rdp.prim_lodmin, + rdp.prim_lodfrac); +} + +static void rdp_setenvcolor() +{ + rdp.env_color = rdp.cmd1; + rdp.update |= UPDATE_COMBINE; + + FRDP("setenvcolor: %08lx\n", rdp.cmd1); +} + +static void rdp_setcombine() +{ + rdp.c_a0 = (wxUint8)((rdp.cmd0 >> 20) & 0xF); + rdp.c_b0 = (wxUint8)((rdp.cmd1 >> 28) & 0xF); + rdp.c_c0 = (wxUint8)((rdp.cmd0 >> 15) & 0x1F); + rdp.c_d0 = (wxUint8)((rdp.cmd1 >> 15) & 0x7); + rdp.c_Aa0 = (wxUint8)((rdp.cmd0 >> 12) & 0x7); + rdp.c_Ab0 = (wxUint8)((rdp.cmd1 >> 12) & 0x7); + rdp.c_Ac0 = (wxUint8)((rdp.cmd0 >> 9) & 0x7); + rdp.c_Ad0 = (wxUint8)((rdp.cmd1 >> 9) & 0x7); + + rdp.c_a1 = (wxUint8)((rdp.cmd0 >> 5) & 0xF); + rdp.c_b1 = (wxUint8)((rdp.cmd1 >> 24) & 0xF); + rdp.c_c1 = (wxUint8)((rdp.cmd0 >> 0) & 0x1F); + rdp.c_d1 = (wxUint8)((rdp.cmd1 >> 6) & 0x7); + rdp.c_Aa1 = (wxUint8)((rdp.cmd1 >> 21) & 0x7); + rdp.c_Ab1 = (wxUint8)((rdp.cmd1 >> 3) & 0x7); + rdp.c_Ac1 = (wxUint8)((rdp.cmd1 >> 18) & 0x7); + rdp.c_Ad1 = (wxUint8)((rdp.cmd1 >> 0) & 0x7); + + rdp.cycle1 = (rdp.c_a0<<0) | (rdp.c_b0<<4) | (rdp.c_c0<<8) | (rdp.c_d0<<13)| + (rdp.c_Aa0<<16)| (rdp.c_Ab0<<19)| (rdp.c_Ac0<<22)| (rdp.c_Ad0<<25); + rdp.cycle2 = (rdp.c_a1<<0) | (rdp.c_b1<<4) | (rdp.c_c1<<8) | (rdp.c_d1<<13)| + (rdp.c_Aa1<<16)| (rdp.c_Ab1<<19)| (rdp.c_Ac1<<22)| (rdp.c_Ad1<<25); + + rdp.update |= UPDATE_COMBINE; + + FRDP("setcombine\na0=%s b0=%s c0=%s d0=%s\nAa0=%s Ab0=%s Ac0=%s Ad0=%s\na1=%s b1=%s c1=%s d1=%s\nAa1=%s Ab1=%s Ac1=%s Ad1=%s\n", + Mode0[rdp.c_a0], Mode1[rdp.c_b0], Mode2[rdp.c_c0], Mode3[rdp.c_d0], + Alpha0[rdp.c_Aa0], Alpha1[rdp.c_Ab0], Alpha2[rdp.c_Ac0], Alpha3[rdp.c_Ad0], + Mode0[rdp.c_a1], Mode1[rdp.c_b1], Mode2[rdp.c_c1], Mode3[rdp.c_d1], + Alpha0[rdp.c_Aa1], Alpha1[rdp.c_Ab1], Alpha2[rdp.c_Ac1], Alpha3[rdp.c_Ad1]); +} + +// +// settextureimage - sets the source for an image copy +// + +static void rdp_settextureimage() +{ + static const char *format[] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" }; + static const char *size[] = { "4bit", "8bit", "16bit", "32bit" }; + + rdp.timg.format = (wxUint8)((rdp.cmd0 >> 21) & 0x07); + rdp.timg.size = (wxUint8)((rdp.cmd0 >> 19) & 0x03); + rdp.timg.width = (wxUint16)(1 + (rdp.cmd0 & 0x00000FFF)); + rdp.timg.addr = segoffset(rdp.cmd1); + if (ucode5_texshiftaddr) + { + if (rdp.timg.format == 0) + { + wxUint16 * t = (wxUint16*)(gfx.RDRAM+ucode5_texshiftaddr); + ucode5_texshift = t[ucode5_texshiftcount^1]; + rdp.timg.addr += ucode5_texshift; + } + else + { + ucode5_texshiftaddr = 0; + ucode5_texshift = 0; + ucode5_texshiftcount = 0; + } + } + rdp.s2dex_tex_loaded = TRUE; + rdp.update |= UPDATE_TEXTURE; + + if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self && (rdp.timg.addr >= rdp.cimg) && (rdp.timg.addr < rdp.ci_end)) + { + if (!rdp.fb_drawn) + { + if (!rdp.cur_image) + CopyFrameBuffer(); + else + CloseTextureBuffer(TRUE); + rdp.fb_drawn = TRUE; + } + } + + if (fb_hwfbe_enabled) //search this texture among drawn texture buffers + FindTextureBuffer(rdp.timg.addr, rdp.timg.width); + + FRDP("settextureimage: format: %s, size: %s, width: %d, addr: %08lx\n", + format[rdp.timg.format], size[rdp.timg.size], + rdp.timg.width, rdp.timg.addr); +} + +static void rdp_setdepthimage() +{ + rdp.zimg = segoffset(rdp.cmd1) & BMASK; + rdp.zi_width = rdp.ci_width; + FRDP("setdepthimage - %08lx\n", rdp.zimg); +} + +int SwapOK = TRUE; +static void RestoreScale() +{ + FRDP("Return to original scale: x = %f, y = %f\n", rdp.scale_x_bak, rdp.scale_y_bak); + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + // update_scissor(); + rdp.view_scale[0] *= rdp.scale_x; + rdp.view_scale[1] *= rdp.scale_y; + rdp.view_trans[0] *= rdp.scale_x; + rdp.view_trans[1] *= rdp.scale_y; + rdp.update |= UPDATE_VIEWPORT | UPDATE_SCISSOR; + //* + if (fullscreen) + { + grDepthMask (FXFALSE); + grBufferClear (0, 0, 0xFFFF); + grDepthMask (FXTRUE); + } + //*/ +} + +static wxUint32 swapped_addr = 0; + +static void rdp_setcolorimage() +{ +//unsigned int ticks = ticksGetTicks(); +//bool showdeb = false; + if (fb_emulation_enabled && (rdp.num_of_ci < NUMTEXBUF)) + { + COLOR_IMAGE & cur_fb = rdp.frame_buffers[rdp.ci_count]; + COLOR_IMAGE & prev_fb = rdp.frame_buffers[rdp.ci_count?rdp.ci_count-1:0]; + COLOR_IMAGE & next_fb = rdp.frame_buffers[rdp.ci_count+1]; +//if (cur_fb.status==ci_aux) showdeb = true; +//if (showdeb) printf("rp_setcolorimage, status=%i\n", cur_fb.status); + switch (cur_fb.status) + { + case ci_main: + { + + if (rdp.ci_count == 0) + { + if ((rdp.ci_status == ci_aux)) //for PPL + { + float sx = rdp.scale_x; + float sy = rdp.scale_y; + rdp.scale_x = 1.0f; + rdp.scale_y = 1.0f; + CopyFrameBuffer (); + rdp.scale_x = sx; + rdp.scale_y = sy; + } + if (!fb_hwfbe_enabled) + { + if ((rdp.num_of_ci > 1) && + (next_fb.status == ci_aux) && + (next_fb.width >= cur_fb.width)) + { + rdp.scale_x = 1.0f; + rdp.scale_y = 1.0f; + } + } + else if (rdp.copy_ci_index && (settings.hacks&hack_PMario)) //tidal wave + OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); + } + else if (!rdp.motionblur && fb_hwfbe_enabled && !SwapOK && (rdp.ci_count <= rdp.copy_ci_index)) + { + if (next_fb.status == ci_aux_copy) + OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); + else + OpenTextureBuffer(rdp.frame_buffers[rdp.copy_ci_index]); + } + else if (fb_hwfbe_enabled && prev_fb.status == ci_aux) + { + if (rdp.motionblur) + { + rdp.cur_image = &(rdp.texbufs[rdp.cur_tex_buf].images[0]); + grRenderBuffer( GR_BUFFER_TEXTUREBUFFER_EXT ); + grTextureBufferExt( rdp.cur_image->tmu, rdp.cur_image->tex_addr, rdp.cur_image->info.smallLodLog2, rdp.cur_image->info.largeLodLog2, + rdp.cur_image->info.aspectRatioLog2, rdp.cur_image->info.format, GR_MIPMAPLEVELMASK_BOTH ); + } + else if (rdp.read_whole_frame) + { + OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); + } + } + //else if (rdp.ci_status == ci_aux && !rdp.copy_ci_index) + // CloseTextureBuffer(); + + rdp.skip_drawing = FALSE; + } + break; + case ci_copy: + { + if (!rdp.motionblur || (settings.frame_buffer&fb_motionblur)) + { + if (cur_fb.width == rdp.ci_width) + { + if (CopyTextureBuffer(prev_fb, cur_fb)) + { + // if (CloseTextureBuffer(TRUE)) + //* + if ((settings.hacks&hack_Zelda) && (rdp.frame_buffers[rdp.ci_count+2].status == ci_aux) && !rdp.fb_drawn) //hack for photo camera in Zelda MM + { + CopyFrameBuffer (GR_BUFFER_TEXTUREBUFFER_EXT); + rdp.fb_drawn = TRUE; + memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<>1); + } + //*/ + } + else + { + if (!rdp.fb_drawn || prev_fb.status == ci_copy_self) + { + CopyFrameBuffer (); + rdp.fb_drawn = TRUE; + } + memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.cimg, (cur_fb.width*cur_fb.height)<>1); + } + } + else + { + CloseTextureBuffer(TRUE); + } + } + else + { + memset(gfx.RDRAM+cur_fb.addr, 0, cur_fb.width*cur_fb.height*rdp.ci_size); + } + rdp.skip_drawing = TRUE; + } + break; + case ci_aux_copy: + { + rdp.skip_drawing = FALSE; + if (CloseTextureBuffer(prev_fb.status != ci_aux_copy)) + ; + else if (!rdp.fb_drawn) + { + CopyFrameBuffer (); + rdp.fb_drawn = TRUE; + } + if (fb_hwfbe_enabled) + OpenTextureBuffer(cur_fb); + } + break; + case ci_old_copy: + { + if (!rdp.motionblur || (settings.frame_buffer&fb_motionblur)) + { + if (cur_fb.width == rdp.ci_width) + { + memcpy(gfx.RDRAM+cur_fb.addr,gfx.RDRAM+rdp.maincimg[1].addr, (cur_fb.width*cur_fb.height)<>1); + } + //rdp.skip_drawing = TRUE; + } + else + { + memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<>1); + } + } + break; + /* + else if (rdp.frame_buffers[rdp.ci_count].status == ci_main_i) + { + // CopyFrameBuffer (); + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + rdp.skip_drawing = FALSE; + } + */ + case ci_aux: + { +//unsigned int tticks = ticksGetTicks(); + if (!fb_hwfbe_enabled && cur_fb.format != 0) + rdp.skip_drawing = TRUE; + else + { + rdp.skip_drawing = FALSE; + if (fb_hwfbe_enabled && OpenTextureBuffer(cur_fb)) + ; + else + { + if (cur_fb.format != 0) + rdp.skip_drawing = TRUE; + if (rdp.ci_count == 0) + { + // if (rdp.num_of_ci > 1) + // { + rdp.scale_x = 1.0f; + rdp.scale_y = 1.0f; + // } + } + else if (!fb_hwfbe_enabled && (prev_fb.status == ci_main) && + (prev_fb.width == cur_fb.width)) // for Pokemon Stadium + CopyFrameBuffer (); + } + } + cur_fb.status = ci_aux; +//tticks = ticksGetTicks() - ticks; +//printf("intermediary: %u ms\n", tticks); + } + break; + case ci_zimg: + if (settings.ucode != ucode_PerfectDark) + { + if (fb_hwfbe_enabled && !rdp.copy_ci_index && (rdp.copy_zi_index || (settings.hacks&hack_BAR))) + { + GrLOD_t LOD = GR_LOD_LOG2_1024; + if (settings.scr_res_x > 1024) + LOD = GR_LOD_LOG2_2048; + grTextureAuxBufferExt( rdp.texbufs[0].tmu, rdp.texbufs[0].begin, LOD, LOD, + GR_ASPECT_LOG2_1x1, GR_TEXFMT_RGB_565, GR_MIPMAPLEVELMASK_BOTH ); + grAuxBufferExt( GR_BUFFER_TEXTUREAUXBUFFER_EXT ); + LRDP("rdp_setcolorimage - set texture depth buffer to TMU0\n"); + } + } + rdp.skip_drawing = TRUE; + break; + case ci_zcopy: + if (settings.ucode != ucode_PerfectDark) + { + if (fb_hwfbe_enabled && !rdp.copy_ci_index && rdp.copy_zi_index == rdp.ci_count) + { + CopyDepthBuffer(); + } + rdp.skip_drawing = TRUE; + } + break; + case ci_useless: + rdp.skip_drawing = TRUE; + break; + case ci_copy_self: + if (fb_hwfbe_enabled && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2)) + OpenTextureBuffer(cur_fb); + rdp.skip_drawing = FALSE; + break; + default: + rdp.skip_drawing = FALSE; + } + + if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium + { + if (!fb_hwfbe_enabled && prev_fb.format == 0) + CopyFrameBuffer (); + else if ((settings.hacks&hack_Knockout) && prev_fb.width < 100) + CopyFrameBuffer (GR_BUFFER_TEXTUREBUFFER_EXT); + } + if (!fb_hwfbe_enabled && cur_fb.status == ci_copy) + { + if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux)) + { + RestoreScale(); + } + } + if (!fb_hwfbe_enabled && cur_fb.status == ci_aux) + { + if (cur_fb.format == 0) + { + if ((settings.hacks&hack_PPL) && (rdp.scale_x < 1.1f)) //need to put current image back to frame buffer + { + int width = cur_fb.width; + int height = cur_fb.height; + wxUint16 *ptr_dst = new wxUint16[width*height]; + wxUint16 *ptr_src = (wxUint16*)(gfx.RDRAM+cur_fb.addr); + wxUint16 c; + + for (int y=0; y> 1) | 0x8000; + ptr_dst[x + y * width] = c; + } + } + grLfbWriteRegion(GR_BUFFER_BACKBUFFER, + (wxUint32)rdp.offset_x, + (wxUint32)rdp.offset_y, + GR_LFB_SRC_FMT_555, + width, + height, + FXFALSE, + width<<1, + ptr_dst); + delete[] ptr_dst; + } + /* + else //just clear buffer + { + + grColorMask(FXTRUE, FXTRUE); + grBufferClear (0, 0, 0xFFFF); + } + */ + } + } + + if ((cur_fb.status == ci_main) && (rdp.ci_count > 0)) + { + int to_org_res = TRUE; + for (int i = rdp.ci_count + 1; i < rdp.num_of_ci; i++) + { + if ((rdp.frame_buffers[i].status != ci_main) && (rdp.frame_buffers[i].status != ci_zimg) && (rdp.frame_buffers[i].status != ci_zcopy)) + { + to_org_res = FALSE; + break; + } + } + if (to_org_res) + { + LRDP("return to original scale\n"); + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + if (fb_hwfbe_enabled && !rdp.read_whole_frame) + CloseTextureBuffer(); + } + if (fb_hwfbe_enabled && !rdp.read_whole_frame && (prev_fb.status >= ci_aux) && (rdp.ci_count > rdp.copy_ci_index)) + CloseTextureBuffer(); + + } + rdp.ci_status = cur_fb.status; + rdp.ci_count++; + } + + rdp.ocimg = rdp.cimg; + rdp.cimg = segoffset(rdp.cmd1) & BMASK; + rdp.ci_width = (rdp.cmd0 & 0xFFF) + 1; + if (fb_emulation_enabled) + rdp.ci_height = rdp.frame_buffers[rdp.ci_count-1].height; + else if (rdp.ci_width == 32) + rdp.ci_height = 32; + else + rdp.ci_height = rdp.scissor_o.lr_y; + if (rdp.zimg == rdp.cimg) + { + rdp.zi_width = rdp.ci_width; + // int zi_height = min((int)rdp.zi_width*3/4, (int)rdp.vi_height); + // rdp.zi_words = rdp.zi_width * zi_height; + } + wxUint32 format = (rdp.cmd0 >> 21) & 0x7; + rdp.ci_size = (rdp.cmd0 >> 19) & 0x3; + rdp.ci_end = rdp.cimg + ((rdp.ci_width*rdp.ci_height)<<(rdp.ci_size-1)); + FRDP("setcolorimage - %08lx, width: %d, height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size); + FRDP("cimg: %08lx, ocimg: %08lx, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK); + +//if (showdeb) printf("setcolorimage - %08x, width: %d, height: %d, format: %d, size: %d\n", rdp.cmd1, rdp.ci_width, rdp.ci_height, format, rdp.ci_size); +//if (showdeb) printf("cimg: %08x, ocimg: %08x, SwapOK: %d\n", rdp.cimg, rdp.ocimg, SwapOK); + + if (format != 0) //can't draw into non RGBA buffer + { + if (!rdp.cur_image) + { + if (fb_hwfbe_enabled && rdp.ci_width <= 64) + OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]); + else if (format > 2) + rdp.skip_drawing = TRUE; + return; + } + } + else + { + if (!fb_emulation_enabled) + rdp.skip_drawing = FALSE; + } + + CI_SET = TRUE; + if (settings.swapmode > 0) + { + if (rdp.zimg == rdp.cimg) + rdp.updatescreen = 1; + + int viSwapOK = ((settings.swapmode == 2) && (rdp.vi_org_reg == *gfx.VI_ORIGIN_REG)) ? FALSE : TRUE; + if ((rdp.zimg != rdp.cimg) && (rdp.ocimg != rdp.cimg) && SwapOK && viSwapOK && !rdp.cur_image) + { + if (fb_emulation_enabled) + rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index]; + else + rdp.maincimg[0].addr = rdp.cimg; + rdp.last_drawn_ci_addr = (settings.swapmode == 2) ? swapped_addr : rdp.maincimg[0].addr; + swapped_addr = rdp.cimg; + newSwapBuffers(); + rdp.vi_org_reg = *gfx.VI_ORIGIN_REG; + SwapOK = FALSE; + if (fb_hwfbe_enabled) + { + if (rdp.copy_ci_index && (rdp.frame_buffers[rdp.ci_count-1].status != ci_zimg)) + { + int idx = (rdp.frame_buffers[rdp.ci_count].status == ci_aux_copy) ? rdp.main_ci_index : rdp.copy_ci_index; + FRDP("attempt open tex buffer. status: %s, addr: %08lx\n", CIStatus[rdp.frame_buffers[idx].status], rdp.frame_buffers[idx].addr); + OpenTextureBuffer(rdp.frame_buffers[idx]); + if (rdp.frame_buffers[rdp.copy_ci_index].status == ci_main) //tidal wave + rdp.copy_ci_index = 0; + } + else if (rdp.read_whole_frame && !rdp.cur_image) + { + OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); + } + } + } + } +//ticks = ticksGetTicks() - ticks; +//if (showdeb) printf("time = %u\n", ticks); +} + +static void rsp_reserved0() +{ + if (settings.ucode == ucode_DiddyKong) + { + ucode5_texshiftaddr = segoffset(rdp.cmd1); + ucode5_texshiftcount = 0; + FRDP("uc5_texshift. addr: %08lx\n", ucode5_texshiftaddr); + } + else + { + RDP_E("reserved0 - IGNORED\n"); + LRDP("reserved0 - IGNORED\n"); + } +} + +static void rsp_reserved1() +{ + LRDP("reserved1 - ignored\n"); +} + +static void rsp_reserved2() +{ + LRDP("reserved2\n"); +} + +static void rsp_reserved3() +{ + LRDP("reserved3 - ignored\n"); +} + +void SetWireframeCol () +{ + if (!fullscreen) return; + + switch (settings.wfmode) + { + //case 0: // normal colors, don't do anything + case 1: // vertex colors + grColorCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_NONE, + FXFALSE); + grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_ITERATED, + GR_COMBINE_OTHER_NONE, + FXFALSE); + grAlphaBlendFunction (GR_BLEND_ONE, + GR_BLEND_ZERO, + GR_BLEND_ZERO, + GR_BLEND_ZERO); + grTexCombine (GR_TMU0, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE); + grTexCombine (GR_TMU1, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE); + break; + case 2: // red only + grColorCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, + GR_COMBINE_OTHER_NONE, + FXFALSE); + grAlphaCombine (GR_COMBINE_FUNCTION_LOCAL, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_LOCAL_CONSTANT, + GR_COMBINE_OTHER_NONE, + FXFALSE); + grConstantColorValue (0xFF0000FF); + grAlphaBlendFunction (GR_BLEND_ONE, + GR_BLEND_ZERO, + GR_BLEND_ZERO, + GR_BLEND_ZERO); + grTexCombine (GR_TMU0, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE); + grTexCombine (GR_TMU1, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + GR_COMBINE_FUNCTION_ZERO, + GR_COMBINE_FACTOR_NONE, + FXFALSE, FXFALSE); + break; + } + + grAlphaTestFunction (GR_CMP_ALWAYS); + grCullMode (GR_CULL_DISABLE); + + rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE; +} + +/****************************************************************** +Function: FrameBufferRead +Purpose: This function is called to notify the dll that the +frame buffer memory is beening read at the given address. +DLL should copy content from its render buffer to the frame buffer +in N64 RDRAM +DLL is responsible to maintain its own frame buffer memory addr list +DLL should copy 4KB block content back to RDRAM frame buffer. +Emulator should not call this function again if other memory +is read within the same 4KB range +input: addr rdram address +val val +size 1 = wxUint8, 2 = wxUint16, 4 = wxUint32 +output: none +*******************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +EXPORT void CALL FBRead(wxUint32 addr) +{ + LOG ("FBRead ()\n"); + + if (cpu_fb_ignore) + return; + if (cpu_fb_write_called) + { + cpu_fb_ignore = TRUE; + cpu_fb_write = FALSE; + return; + } + cpu_fb_read_called = TRUE; + wxUint32 a = segoffset(addr); + FRDP("FBRead. addr: %08lx\n", a); + if (!rdp.fb_drawn && (a >= rdp.cimg) && (a < rdp.ci_end)) + { + fbreads_back++; + //if (fbreads_back > 2) //&& (rdp.ci_width <= 320)) + { + CopyFrameBuffer (); + rdp.fb_drawn = TRUE; + } + } + if (!rdp.fb_drawn_front && (a >= rdp.maincimg[1].addr) && (a < rdp.maincimg[1].addr + rdp.ci_width*rdp.ci_height*2)) + { + fbreads_front++; + //if (fbreads_front > 2)//&& (rdp.ci_width <= 320)) + { + wxUint32 cimg = rdp.cimg; + rdp.cimg = rdp.maincimg[1].addr; + if (fb_emulation_enabled) + { + rdp.ci_width = rdp.maincimg[1].width; + rdp.ci_count = 0; + wxUint32 h = rdp.frame_buffers[0].height; + rdp.frame_buffers[0].height = rdp.maincimg[1].height; + CopyFrameBuffer(GR_BUFFER_FRONTBUFFER); + rdp.frame_buffers[0].height = h; + } + else + { + CopyFrameBuffer(GR_BUFFER_FRONTBUFFER); + } + rdp.cimg = cimg; + rdp.fb_drawn_front = TRUE; + } + } +} + +#if 0 +/****************************************************************** +Function: FrameBufferWriteList +Purpose: This function is called to notify the dll that the +frame buffer has been modified by CPU at the given address. +input: FrameBufferModifyEntry *plist +size = size of the plist, max = 1024 +output: none +*******************************************************************/ +EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, wxUint32 size) +{ + LOG ("FBWList ()\n"); + FRDP("FBWList. size: %d\n", size); +} +#endif + +/****************************************************************** +Function: FrameBufferWrite +Purpose: This function is called to notify the dll that the +frame buffer has been modified by CPU at the given address. +input: addr rdram address +val val +size 1 = wxUint8, 2 = wxUint16, 4 = wxUint32 +output: none +*******************************************************************/ +EXPORT void CALL FBWrite(wxUint32 addr, wxUint32 size) +{ + LOG ("FBWrite ()\n"); + if (cpu_fb_ignore) + return; + if (cpu_fb_read_called) + { + cpu_fb_ignore = TRUE; + cpu_fb_write = FALSE; + return; + } + cpu_fb_write_called = TRUE; + wxUint32 a = segoffset(addr); + FRDP("FBWrite. addr: %08lx\n", a); + if (a < rdp.cimg || a > rdp.ci_end) + return; + cpu_fb_write = TRUE; + wxUint32 shift_l = (a-rdp.cimg) >> 1; + wxUint32 shift_r = shift_l+2; + + d_ul_x = min(d_ul_x, shift_l%rdp.ci_width); + d_ul_y = min(d_ul_y, shift_l/rdp.ci_width); + d_lr_x = max(d_lr_x, shift_r%rdp.ci_width); + d_lr_y = max(d_lr_y, shift_r/rdp.ci_width); +} + + +/************************************************************************ +Function: FBGetFrameBufferInfo +Purpose: This function is called by the emulator core to retrieve frame +buffer information from the video plugin in order to be able +to notify the video plugin about CPU frame buffer read/write +operations + +size: += 1 byte += 2 word (16 bit) <-- this is N64 default depth buffer format += 4 dword (32 bit) + +when frame buffer information is not available yet, set all values +in the FrameBufferInfo structure to 0 + +input: FrameBufferInfo pinfo[6] +pinfo is pointed to a FrameBufferInfo structure which to be +filled in by this function +output: Values are return in the FrameBufferInfo structure +Plugin can return up to 6 frame buffer info +************************************************************************/ +///* +#if 0 +typedef struct +{ + wxUint32 addr; + wxUint32 size; + wxUint32 width; + wxUint32 height; +} FrameBufferInfo; +#endif +EXPORT void CALL FBGetFrameBufferInfo(void *p) +{ + VLOG ("FBGetFrameBufferInfo ()\n"); + FrameBufferInfo * pinfo = (FrameBufferInfo *)p; + memset(pinfo,0,sizeof(FrameBufferInfo)*6); + if (!(settings.frame_buffer&fb_get_info)) + return; + LRDP("FBGetFrameBufferInfo ()\n"); + //* + if (fb_emulation_enabled) + { + pinfo[0].addr = rdp.maincimg[1].addr; + pinfo[0].size = rdp.maincimg[1].size; + pinfo[0].width = rdp.maincimg[1].width; + pinfo[0].height = rdp.maincimg[1].height; + int info_index = 1; + for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++) + { + COLOR_IMAGE & cur_fb = rdp.frame_buffers[i]; + if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self || + cur_fb.status == ci_old_copy) + { + pinfo[info_index].addr = cur_fb.addr; + pinfo[info_index].size = cur_fb.size; + pinfo[info_index].width = cur_fb.width; + pinfo[info_index].height = cur_fb.height; + info_index++; + } + } + } + else + { + pinfo[0].addr = rdp.maincimg[0].addr; + pinfo[0].size = rdp.ci_size; + pinfo[0].width = rdp.ci_width; + pinfo[0].height = rdp.ci_width*3/4; + pinfo[1].addr = rdp.maincimg[1].addr; + pinfo[1].size = rdp.ci_size; + pinfo[1].width = rdp.ci_width; + pinfo[1].height = rdp.ci_width*3/4; + } + //*/ +} +#ifdef __cplusplus +} +#endif +//*/ +#include "ucodeFB.h" + +void DetectFrameBufferUsage () +{ + LRDP("DetectFrameBufferUsage\n"); + + wxUint32 dlist_start = *(wxUint32*)(gfx.DMEM+0xFF0); + wxUint32 a; + + int tidal = FALSE; + if ((settings.hacks&hack_PMario) && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self)) + tidal = TRUE; + wxUint32 ci = rdp.cimg, zi = rdp.zimg; + wxUint32 ci_height = rdp.frame_buffers[(rdp.ci_count > 0)?rdp.ci_count-1:0].height; + rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0; + rdp.main_ci_index = rdp.copy_ci_index = rdp.copy_zi_index = 0; + rdp.zimg_end = 0; + rdp.tmpzimg = 0; + rdp.motionblur = FALSE; + rdp.main_ci_last_tex_addr = 0; + int previous_ci_was_read = rdp.read_previous_ci; + rdp.read_previous_ci = FALSE; + rdp.read_whole_frame = FALSE; + rdp.swap_ci_index = rdp.black_ci_index = -1; + SwapOK = TRUE; + + // Start executing at the start of the display list + rdp.pc_i = 0; + rdp.pc[rdp.pc_i] = dlist_start; + rdp.dl_count = -1; + rdp.halt = 0; + rdp.scale_x_bak = rdp.scale_x; + rdp.scale_y_bak = rdp.scale_y; + + // MAIN PROCESSING LOOP + do { + + // Get the address of the next command + a = rdp.pc[rdp.pc_i] & BMASK; + + // Load the next command and its input + rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit + rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // / + + // Output the address before the command + + // Go to the next instruction + rdp.pc[rdp.pc_i] = (a+8) & BMASK; + + if (wxPtrToUInt(reinterpret_cast(gfx_instruction_lite[settings.ucode][rdp.cmd0>>24]))) + gfx_instruction_lite[settings.ucode][rdp.cmd0>>24] (); + + // check DL counter + if (rdp.dl_count != -1) + { + rdp.dl_count --; + if (rdp.dl_count == 0) + { + rdp.dl_count = -1; + + LRDP("End of DL\n"); + rdp.pc_i --; + } + } + + } while (!rdp.halt); + SwapOK = TRUE; + if (rdp.ci_count > NUMTEXBUF) //overflow + { + rdp.cimg = ci; + rdp.zimg = zi; + rdp.num_of_ci = rdp.ci_count; + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + return; + } + + if (rdp.black_ci_index > 0 && rdp.black_ci_index < rdp.copy_ci_index) + rdp.frame_buffers[rdp.black_ci_index].status = ci_main; + + if (rdp.frame_buffers[rdp.ci_count-1].status == ci_unknown) + { + if (rdp.ci_count > 1) + rdp.frame_buffers[rdp.ci_count-1].status = ci_aux; + else + rdp.frame_buffers[rdp.ci_count-1].status = ci_main; + } + + if ((rdp.frame_buffers[rdp.ci_count-1].status == ci_aux) && + (rdp.frame_buffers[rdp.main_ci_index].width < 320) && + (rdp.frame_buffers[rdp.ci_count-1].width > rdp.frame_buffers[rdp.main_ci_index].width)) + { + for (int i = 0; i < rdp.ci_count; i++) + { + if (rdp.frame_buffers[i].status == ci_main) + rdp.frame_buffers[i].status = ci_aux; + else if (rdp.frame_buffers[i].addr == rdp.frame_buffers[rdp.ci_count-1].addr) + rdp.frame_buffers[i].status = ci_main; + // FRDP("rdp.frame_buffers[%d].status = %d\n", i, rdp.frame_buffers[i].status); + } + rdp.main_ci_index = rdp.ci_count-1; + } + + int all_zimg = TRUE; + int i; + for (i = 0; i < rdp.ci_count; i++) + { + if (rdp.frame_buffers[i].status != ci_zimg) + { + all_zimg = FALSE; + break; + } + } + if (all_zimg) + { + for (i = 0; i < rdp.ci_count; i++) + rdp.frame_buffers[i].status = ci_main; + } + + LRDP("detect fb final results: \n"); + for (i = 0; i < rdp.ci_count; i++) + { + FRDP("rdp.frame_buffers[%d].status = %s, addr: %08lx, height: %d\n", i, CIStatus[rdp.frame_buffers[i].status], rdp.frame_buffers[i].addr, rdp.frame_buffers[i].height); + } + + rdp.cimg = ci; + rdp.zimg = zi; + rdp.num_of_ci = rdp.ci_count; + if (rdp.read_previous_ci && previous_ci_was_read) + { + if (!fb_hwfbe_enabled || !rdp.copy_ci_index) + rdp.motionblur = TRUE; + } + if (rdp.motionblur || fb_hwfbe_enabled || (rdp.frame_buffers[rdp.copy_ci_index].status == ci_aux_copy)) + { + rdp.scale_x = rdp.scale_x_bak; + rdp.scale_y = rdp.scale_y_bak; + } + + if ((rdp.read_previous_ci || previous_ci_was_read) && !rdp.copy_ci_index) + rdp.read_whole_frame = TRUE; + if (rdp.read_whole_frame) + { + if (fb_hwfbe_enabled) + { + if (rdp.read_previous_ci && !previous_ci_was_read && (settings.swapmode != 2) && (settings.ucode != ucode_PerfectDark)) + { + int ind = (rdp.ci_count > 0)?rdp.ci_count-1:0; + wxUint32 height = rdp.frame_buffers[ind].height; + rdp.frame_buffers[ind].height = ci_height; + CopyFrameBuffer(); + rdp.frame_buffers[ind].height = height; + } + if (rdp.swap_ci_index < 0) + { + rdp.texbufs[0].clear_allowed = rdp.texbufs[1].clear_allowed = TRUE; + OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]); + } + } + else + { + if (rdp.motionblur) + { + if (settings.frame_buffer&fb_motionblur) + CopyFrameBuffer(); + else + memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size); + } + else //if (ci_width == rdp.frame_buffers[rdp.main_ci_index].width) + { + if (rdp.maincimg[0].height > 65) //for 1080 + { + rdp.cimg = rdp.maincimg[0].addr; + rdp.ci_width = rdp.maincimg[0].width; + rdp.ci_count = 0; + wxUint32 h = rdp.frame_buffers[0].height; + rdp.frame_buffers[0].height = rdp.maincimg[0].height; + CopyFrameBuffer(); + rdp.frame_buffers[0].height = h; + } + else //conker + { + CopyFrameBuffer(); + } + } + } + } + + if (fb_hwfbe_enabled) + { + for (i = 0; i < voodoo.num_tmu; i++) + { + rdp.texbufs[i].clear_allowed = TRUE; + for (int j = 0; j < 256; j++) + { + rdp.texbufs[i].images[j].drawn = FALSE; + rdp.texbufs[i].images[j].clear = TRUE; + } + } + if (tidal) + { + //LRDP("Tidal wave!\n"); + rdp.copy_ci_index = rdp.main_ci_index; + } + } + rdp.ci_count = 0; + if (settings.hacks&hack_Banjo2) + rdp.cur_tex_buf = 0; + rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index]; + // rdp.scale_x = rdp.scale_x_bak; + // rdp.scale_y = rdp.scale_y_bak; + LRDP("DetectFrameBufferUsage End\n"); +} + +/******************************************* + * ProcessRDPList * + ******************************************* + * based on sources of ziggy's z64 * + *******************************************/ + +static wxUint32 rdp_cmd_ptr = 0; +static wxUint32 rdp_cmd_cur = 0; +static wxUint32 rdp_cmd_data[0x1000]; + +void lle_triangle(wxUint32 w1, wxUint32 w2, int shade, int texture, int zbuffer, + wxUint32 * rdp_cmd) +{ + rdp.cur_tile = (w1 >> 16) & 0x7; + int j; + int xleft, xright, xleft_inc, xright_inc; + int r, g, b, a, z, s, t, w; + int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0; + int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0; + int flip = (w1 & 0x800000) ? 1 : 0; + + wxInt32 yl, ym, yh; + wxInt32 xl, xm, xh; + wxInt32 dxldy, dxhdy, dxmdy; + wxUint32 w3, w4, w5, w6, w7, w8; + + wxUint32 * shade_base = rdp_cmd + 8; + wxUint32 * texture_base = rdp_cmd + 8; + wxUint32 * zbuffer_base = rdp_cmd + 8; + + if (shade) + { + texture_base += 16; + zbuffer_base += 16; + } + if (texture) + { + zbuffer_base += 16; + } + + w3 = rdp_cmd[2]; + w4 = rdp_cmd[3]; + w5 = rdp_cmd[4]; + w6 = rdp_cmd[5]; + w7 = rdp_cmd[6]; + w8 = rdp_cmd[7]; + + yl = (w1 & 0x3fff); + ym = ((w2 >> 16) & 0x3fff); + yh = ((w2 >> 0) & 0x3fff); + xl = (wxInt32)(w3); + xh = (wxInt32)(w5); + xm = (wxInt32)(w7); + dxldy = (wxInt32)(w4); + dxhdy = (wxInt32)(w6); + dxmdy = (wxInt32)(w8); + + if (yl & (0x800<<2)) yl |= 0xfffff000<<2; + if (ym & (0x800<<2)) ym |= 0xfffff000<<2; + if (yh & (0x800<<2)) yh |= 0xfffff000<<2; + + yh &= ~3; + + r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0xffff0000; s = 0; t = 0; w = 0x30000; + + if (shade) + { + r = (shade_base[0] & 0xffff0000) | ((shade_base[+4 ] >> 16) & 0x0000ffff); + g = ((shade_base[0 ] << 16) & 0xffff0000) | (shade_base[4 ] & 0x0000ffff); + b = (shade_base[1 ] & 0xffff0000) | ((shade_base[5 ] >> 16) & 0x0000ffff); + a = ((shade_base[1 ] << 16) & 0xffff0000) | (shade_base[5 ] & 0x0000ffff); + drdx = (shade_base[2 ] & 0xffff0000) | ((shade_base[6 ] >> 16) & 0x0000ffff); + dgdx = ((shade_base[2 ] << 16) & 0xffff0000) | (shade_base[6 ] & 0x0000ffff); + dbdx = (shade_base[3 ] & 0xffff0000) | ((shade_base[7 ] >> 16) & 0x0000ffff); + dadx = ((shade_base[3 ] << 16) & 0xffff0000) | (shade_base[7 ] & 0x0000ffff); + drde = (shade_base[8 ] & 0xffff0000) | ((shade_base[12] >> 16) & 0x0000ffff); + dgde = ((shade_base[8 ] << 16) & 0xffff0000) | (shade_base[12] & 0x0000ffff); + dbde = (shade_base[9 ] & 0xffff0000) | ((shade_base[13] >> 16) & 0x0000ffff); + dade = ((shade_base[9 ] << 16) & 0xffff0000) | (shade_base[13] & 0x0000ffff); + } + if (texture) + { + s = (texture_base[0 ] & 0xffff0000) | ((texture_base[4 ] >> 16) & 0x0000ffff); + t = ((texture_base[0 ] << 16) & 0xffff0000) | (texture_base[4 ] & 0x0000ffff); + w = (texture_base[1 ] & 0xffff0000) | ((texture_base[5 ] >> 16) & 0x0000ffff); + // w = abs(w); + dsdx = (texture_base[2 ] & 0xffff0000) | ((texture_base[6 ] >> 16) & 0x0000ffff); + dtdx = ((texture_base[2 ] << 16) & 0xffff0000) | (texture_base[6 ] & 0x0000ffff); + dwdx = (texture_base[3 ] & 0xffff0000) | ((texture_base[7 ] >> 16) & 0x0000ffff); + dsde = (texture_base[8 ] & 0xffff0000) | ((texture_base[12] >> 16) & 0x0000ffff); + dtde = ((texture_base[8 ] << 16) & 0xffff0000) | (texture_base[12] & 0x0000ffff); + dwde = (texture_base[9 ] & 0xffff0000) | ((texture_base[13] >> 16) & 0x0000ffff); + } + if (zbuffer) + { + z = zbuffer_base[0]; + dzdx = zbuffer_base[1]; + dzde = zbuffer_base[2]; + } + + xh <<= 2; xm <<= 2; xl <<= 2; + r <<= 2; g <<= 2; b <<= 2; a <<= 2; + dsde >>= 2; dtde >>= 2; dsdx >>= 2; dtdx >>= 2; + dzdx >>= 2; dzde >>= 2; + dwdx >>= 2; dwde >>= 2; + +#define XSCALE(x) (float(x)/(1<<18)) +#define YSCALE(y) (float(y)/(1<<2)) +#define ZSCALE(z) ((rdp.zsrc == 1)? float(rdp.prim_depth) : float(wxUint32(z))/0xffff0000) + //#define WSCALE(w) (rdp.Persp_en? (float(wxUint32(w) + 0x10000)/0xffff0000) : 1.0f) + //#define WSCALE(w) (rdp.Persp_en? 4294901760.0/(w + 65536) : 1.0f) +#define WSCALE(w) (rdp.Persp_en? 65536.0f/float((w+ 0xffff)>>16) : 1.0f) +#define CSCALE(c) (((c)>0x3ff0000? 0x3ff0000:((c)<0? 0 : (c)))>>18) +#define _PERSP(w) ( w ) +#define PERSP(s, w) ( ((int64_t)(s) << 20) / (_PERSP(w)? _PERSP(w):1) ) +#define SSCALE(s, _w) (rdp.Persp_en? float(PERSP(s, _w))/(1 << 10) : float(s)/(1<<21)) +#define TSCALE(s, w) (rdp.Persp_en? float(PERSP(s, w))/(1 << 10) : float(s)/(1<<21)) + + int nbVtxs = 0; + VERTEX vtxbuf[12]; + VERTEX * vtx = &vtxbuf[nbVtxs++]; + + xleft = xm; + xright = xh; + xleft_inc = dxmdy; + xright_inc = dxhdy; + + while (yh xright-0x10000))) { + xleft += xleft_inc; + xright += xright_inc; + s += dsde; t += dtde; w += dwde; + r += drde; g += dgde; b += dbde; a += dade; + z += dzde; + yh++; + } + + j = ym-yh; + if (j > 0) + { + int dx = (xleft-xright)>>16; + if ((!flip && xleft < xright) || + (flip/* && xleft > xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(yh); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx = &vtxbuf[nbVtxs++]; + } + if ((!flip/* && xleft < xright*/) || + (flip && xleft > xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->ou = SSCALE(s, w); + vtx->ov = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(yh); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx = &vtxbuf[nbVtxs++]; + } + xleft += xleft_inc*j; xright += xright_inc*j; + s += dsde*j; t += dtde*j; + if (w + dwde*j) w += dwde*j; + else w += dwde*(j-1); + r += drde*j; g += dgde*j; b += dbde*j; a += dade*j; + z += dzde*j; + // render ... + } + + if (xl != xh) + xleft = xl; + + //if (yl-ym > 0) + { + int dx = (xleft-xright)>>16; + if ((!flip && xleft <= xright) || + (flip/* && xleft >= xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(ym); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx = &vtxbuf[nbVtxs++]; + } + if ((!flip/* && xleft <= xright*/) || + (flip && xleft >= xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->ou = SSCALE(s, w); + vtx->ov = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(ym); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx = &vtxbuf[nbVtxs++]; + } + } + xleft_inc = dxldy; + xright_inc = dxhdy; + + j = yl-ym; + //j--; // ? + xleft += xleft_inc*j; xright += xright_inc*j; + s += dsde*j; t += dtde*j; w += dwde*j; + r += drde*j; g += dgde*j; b += dbde*j; a += dade*j; + z += dzde*j; + + while (yl>ym && + !((!flip && xleft < xright+0x10000) || + (flip && xleft > xright-0x10000))) { + xleft -= xleft_inc; xright -= xright_inc; + s -= dsde; t -= dtde; w -= dwde; + r -= drde; g -= dgde; b -= dbde; a -= dade; + z -= dzde; + j--; + yl--; + } + + // render ... + if (j >= 0) { + int dx = (xleft-xright)>>16; + if ((!flip && xleft <= xright) || + (flip/* && xleft >= xright*/)) + { + if (shade) { + vtx->r = CSCALE(r+drdx*dx); + vtx->g = CSCALE(g+dgdx*dx); + vtx->b = CSCALE(b+dbdx*dx); + vtx->a = CSCALE(a+dadx*dx); + } + if (texture) { + vtx->ou = SSCALE(s+dsdx*dx, w+dwdx*dx); + vtx->ov = TSCALE(t+dtdx*dx, w+dwdx*dx); + } + vtx->x = XSCALE(xleft); + vtx->y = YSCALE(yl); + vtx->z = ZSCALE(z+dzdx*dx); + vtx->w = WSCALE(w+dwdx*dx); + vtx = &vtxbuf[nbVtxs++]; + } + if ((!flip/* && xleft <= xright*/) || + (flip && xleft >= xright)) + { + if (shade) { + vtx->r = CSCALE(r); + vtx->g = CSCALE(g); + vtx->b = CSCALE(b); + vtx->a = CSCALE(a); + } + if (texture) { + vtx->ou = SSCALE(s, w); + vtx->ov = TSCALE(t, w); + } + vtx->x = XSCALE(xright); + vtx->y = YSCALE(yl); + vtx->z = ZSCALE(z); + vtx->w = WSCALE(w); + vtx = &vtxbuf[nbVtxs++]; + } + } + + if (fullscreen) + { + update (); + for (int k = 0; k < nbVtxs-1; k++) + { + VERTEX * v = &vtxbuf[k]; + v->x = v->x * rdp.scale_x + rdp.offset_x; + v->y = v->y * rdp.scale_y + rdp.offset_y; + // v->z = 1.0f;///v->w; + v->q = 1.0f/v->w; + v->u1 = v->u0 = v->ou; + v->v1 = v->v0 = v->ov; + if (rdp.tex >= 1 && rdp.cur_cache[0]) + { + if (rdp.tiles[rdp.cur_tile].shift_s) + { + if (rdp.tiles[rdp.cur_tile].shift_s > 10) + v->u0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s)); + else + v->u0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_s); + } + if (rdp.tiles[rdp.cur_tile].shift_t) + { + if (rdp.tiles[rdp.cur_tile].shift_t > 10) + v->v0 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t)); + else + v->v0 /= (float)(1 << rdp.tiles[rdp.cur_tile].shift_t); + } + + v->u0 -= rdp.tiles[rdp.cur_tile].f_ul_s; + v->v0 -= rdp.tiles[rdp.cur_tile].f_ul_t; + v->u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * v->u0; + v->v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * v->v0; + v->u0 /= v->w; + v->v0 /= v->w; + } + + if (rdp.tex >= 2 && rdp.cur_cache[1]) + { + if (rdp.tiles[rdp.cur_tile+1].shift_s) + { + if (rdp.tiles[rdp.cur_tile+1].shift_s > 10) + v->u1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s)); + else + v->u1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_s); + } + if (rdp.tiles[rdp.cur_tile+1].shift_t) + { + if (rdp.tiles[rdp.cur_tile+1].shift_t > 10) + v->v1 *= (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t)); + else + v->v1 /= (float)(1 << rdp.tiles[rdp.cur_tile+1].shift_t); + } + + v->u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s; + v->v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t; + v->u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * v->u1; + v->v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * v->v1; + v->u1 /= v->w; + v->v1 /= v->w; + } + apply_shade_mods (v); + } + ConvertCoordsConvert (vtxbuf, nbVtxs); + grCullMode (GR_CULL_DISABLE); + grDrawVertexArrayContiguous (GR_TRIANGLE_STRIP, nbVtxs-1, vtxbuf, sizeof(VERTEX)); + if (_debugger.capture) + { + VERTEX vl[3]; + vl[0] = vtxbuf[0]; + vl[1] = vtxbuf[2]; + vl[2] = vtxbuf[1]; + add_tri (vl, 3, TRI_TRIANGLE); + rdp.tri_n++; + if (nbVtxs > 4) + { + vl[0] = vtxbuf[2]; + vl[1] = vtxbuf[3]; + vl[2] = vtxbuf[1]; + add_tri (vl, 3, TRI_TRIANGLE); + rdp.tri_n++; + } + } + } +} + +static void rdp_triangle(int shade, int texture, int zbuffer) +{ + lle_triangle(rdp.cmd0, rdp.cmd1, shade, texture, zbuffer, rdp_cmd_data + rdp_cmd_cur); +} + +static void rdp_trifill() +{ + rdp_triangle(0, 0, 0); + LRDP("trifill\n"); +} + +static void rdp_trishade() +{ + rdp_triangle(1, 0, 0); + LRDP("trishade\n"); +} + +static void rdp_tritxtr() +{ + rdp_triangle(0, 1, 0); + LRDP("tritxtr\n"); +} + +static void rdp_trishadetxtr() +{ + rdp_triangle(1, 1, 0); + LRDP("trishadetxtr\n"); +} + +static void rdp_trifillz() +{ + rdp_triangle(0, 0, 1); + LRDP("trifillz\n"); +} + +static void rdp_trishadez() +{ + rdp_triangle(1, 0, 1); + LRDP("trishadez\n"); +} + +static void rdp_tritxtrz() +{ + rdp_triangle(0, 1, 1); + LRDP("tritxtrz\n"); +} + +static void rdp_trishadetxtrz() +{ + rdp_triangle(1, 1, 1); + LRDP("trishadetxtrz\n"); +} + + +static rdp_instr rdp_command_table[64] = +{ + /* 0x00 */ + spnoop, undef, undef, undef, + undef, undef, undef, undef, + rdp_trifill, rdp_trifillz, rdp_tritxtr, rdp_tritxtrz, + rdp_trishade, rdp_trishadez, rdp_trishadetxtr, rdp_trishadetxtrz, + /* 0x10 */ + undef, undef, undef, undef, + undef, undef, undef, undef, + undef, undef, undef, undef, + undef, undef, undef, undef, + /* 0x20 */ + undef, undef, undef, undef, + rdp_texrect, rdp_texrect, rdp_loadsync, rdp_pipesync, + rdp_tilesync, rdp_fullsync, rdp_setkeygb, rdp_setkeyr, + rdp_setconvert, rdp_setscissor, rdp_setprimdepth, rdp_setothermode, + /* 0x30 */ + rdp_loadtlut, undef, rdp_settilesize, rdp_loadblock, + rdp_loadtile, rdp_settile, rdp_fillrect, rdp_setfillcolor, + rdp_setfogcolor, rdp_setblendcolor, rdp_setprimcolor, rdp_setenvcolor, + rdp_setcombine, rdp_settextureimage, rdp_setdepthimage, rdp_setcolorimage +}; + +static const wxUint32 rdp_command_length[64] = +{ + 8, // 0x00, No Op + 8, // 0x01, ??? + 8, // 0x02, ??? + 8, // 0x03, ??? + 8, // 0x04, ??? + 8, // 0x05, ??? + 8, // 0x06, ??? + 8, // 0x07, ??? + 32, // 0x08, Non-Shaded Triangle + 32+16, // 0x09, Non-Shaded, Z-Buffered Triangle + 32+64, // 0x0a, Textured Triangle + 32+64+16, // 0x0b, Textured, Z-Buffered Triangle + 32+64, // 0x0c, Shaded Triangle + 32+64+16, // 0x0d, Shaded, Z-Buffered Triangle + 32+64+64, // 0x0e, Shaded+Textured Triangle + 32+64+64+16,// 0x0f, Shaded+Textured, Z-Buffered Triangle + 8, // 0x10, ??? + 8, // 0x11, ??? + 8, // 0x12, ??? + 8, // 0x13, ??? + 8, // 0x14, ??? + 8, // 0x15, ??? + 8, // 0x16, ??? + 8, // 0x17, ??? + 8, // 0x18, ??? + 8, // 0x19, ??? + 8, // 0x1a, ??? + 8, // 0x1b, ??? + 8, // 0x1c, ??? + 8, // 0x1d, ??? + 8, // 0x1e, ??? + 8, // 0x1f, ??? + 8, // 0x20, ??? + 8, // 0x21, ??? + 8, // 0x22, ??? + 8, // 0x23, ??? + 16, // 0x24, Texture_Rectangle + 16, // 0x25, Texture_Rectangle_Flip + 8, // 0x26, Sync_Load + 8, // 0x27, Sync_Pipe + 8, // 0x28, Sync_Tile + 8, // 0x29, Sync_Full + 8, // 0x2a, Set_Key_GB + 8, // 0x2b, Set_Key_R + 8, // 0x2c, Set_Convert + 8, // 0x2d, Set_Scissor + 8, // 0x2e, Set_Prim_Depth + 8, // 0x2f, Set_Other_Modes + 8, // 0x30, Load_TLUT + 8, // 0x31, ??? + 8, // 0x32, Set_Tile_Size + 8, // 0x33, Load_Block + 8, // 0x34, Load_Tile + 8, // 0x35, Set_Tile + 8, // 0x36, Fill_Rectangle + 8, // 0x37, Set_Fill_Color + 8, // 0x38, Set_Fog_Color + 8, // 0x39, Set_Blend_Color + 8, // 0x3a, Set_Prim_Color + 8, // 0x3b, Set_Env_Color + 8, // 0x3c, Set_Combine + 8, // 0x3d, Set_Texture_Image + 8, // 0x3e, Set_Mask_Image + 8 // 0x3f, Set_Color_Image +}; + +#define rdram ((wxUint32*)gfx.RDRAM) +#define rsp_dmem ((wxUint32*)gfx.DMEM) + +#define dp_start (*(wxUint32*)gfx.DPC_START_REG) +#define dp_end (*(wxUint32*)gfx.DPC_END_REG) +#define dp_current (*(wxUint32*)gfx.DPC_CURRENT_REG) +#define dp_status (*(wxUint32*)gfx.DPC_STATUS_REG) + +inline wxUint32 READ_RDP_DATA(wxUint32 address) +{ + if (dp_status & 0x1) // XBUS_DMEM_DMA enabled + return rsp_dmem[(address & 0xfff)>>2]; + else + return rdram[address>>2]; +} + +static void rdphalf_1() +{ + wxUint32 cmd = rdp.cmd1 >> 24; + if (cmd >= 0xc8 && cmd <=0xcf) //triangle command + { + LRDP("rdphalf_1 - lle triangle\n"); + rdp_cmd_ptr = 0; + rdp_cmd_cur = 0; + wxUint32 a; + + do + { + rdp_cmd_data[rdp_cmd_ptr++] = rdp.cmd1; + // check DL counter + if (rdp.dl_count != -1) + { + rdp.dl_count --; + if (rdp.dl_count == 0) + { + rdp.dl_count = -1; + + LRDP("End of DL\n"); + rdp.pc_i --; + } + } + + // Get the address of the next command + a = rdp.pc[rdp.pc_i] & BMASK; + + // Load the next command and its input + rdp.cmd0 = ((wxUint32*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit + rdp.cmd1 = ((wxUint32*)gfx.RDRAM)[(a>>2)+1]; // / + + // Go to the next instruction + rdp.pc[rdp.pc_i] = (a+8) & BMASK; + + }while ((rdp.cmd0 >> 24) != 0xb3); + rdp_cmd_data[rdp_cmd_ptr++] = rdp.cmd1; + cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f; + rdp.cmd0 = rdp_cmd_data[rdp_cmd_cur+0]; + rdp.cmd1 = rdp_cmd_data[rdp_cmd_cur+1]; + /* + wxUint32 cmd3 = ((wxUint32*)gfx.RDRAM)[(a>>2)+2]; + if ((cmd3>>24) == 0xb4) + rglSingleTriangle = TRUE; + else + rglSingleTriangle = FALSE; + */ + rdp_command_table[cmd](); + } + else + { + LRDP("rdphalf_1 - IGNORED\n"); + } +} + +static void rdphalf_2() +{ + RDP_E("rdphalf_2 - IGNORED\n"); + LRDP("rdphalf_2 - IGNORED\n"); +} + +static void rdphalf_cont() +{ + RDP_E("rdphalf_cont - IGNORED\n"); + LRDP("rdphalf_cont - IGNORED\n"); +} + +/****************************************************************** +Function: ProcessRDPList +Purpose: This function is called when there is a Dlist to be +processed. (Low level GFX list) +input: none +output: none +*******************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +EXPORT void CALL ProcessRDPList(void) +{ + LOG ("ProcessRDPList ()\n"); + LRDP("ProcessRDPList ()\n"); + + // SoftLocker lock(mutexProcessDList); + if (/*!lock.IsOk()*/0) //mutex is busy + { + if (!fullscreen) + drawNoFullscreenMessage(); + // Set an interrupt to allow the game to continue + *gfx.MI_INTR_REG |= 0x20; + gfx.CheckInterrupts(); + return; + } + + wxUint32 i; + wxUint32 cmd, length, cmd_length; + rdp_cmd_ptr = 0; + rdp_cmd_cur = 0; + + if (dp_end <= dp_current) return; + length = dp_end - dp_current; + + // load command data + for (i=0; i < length; i += 4) + { + rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(dp_current + i); + if (rdp_cmd_ptr >= 0x1000) + { + FRDP("rdp_process_list: rdp_cmd_ptr overflow %x %x --> %x\n", length, dp_current, dp_end); + } + } + + dp_current = dp_end; + + cmd = (rdp_cmd_data[0] >> 24) & 0x3f; + cmd_length = (rdp_cmd_ptr + 1) * 4; + + // check if more data is needed + if (cmd_length < rdp_command_length[cmd]) + return; + rdp.LLE = TRUE; + while (rdp_cmd_cur < rdp_cmd_ptr) + { + cmd = (rdp_cmd_data[rdp_cmd_cur] >> 24) & 0x3f; + + if (((rdp_cmd_ptr-rdp_cmd_cur) * 4) < rdp_command_length[cmd]) + return; + + // execute the command + rdp.cmd0 = rdp_cmd_data[rdp_cmd_cur+0]; + rdp.cmd1 = rdp_cmd_data[rdp_cmd_cur+1]; + rdp.cmd2 = rdp_cmd_data[rdp_cmd_cur+2]; + rdp.cmd3 = rdp_cmd_data[rdp_cmd_cur+3]; + rdp_command_table[cmd](); + + rdp_cmd_cur += rdp_command_length[cmd] / 4; + }; + rdp.LLE = FALSE; + + dp_start = dp_end; + + dp_status &= ~0x0002; + + //} +} + +#ifdef __cplusplus +} +#endif +