4030 lines
122 KiB
C++
4030 lines
122 KiB
C++
/*
|
|
* 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 "Gfx #1.3.h"
|
|
#include <wx/confbase.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"
|
|
|
|
extern "C" void SwapBlock32 ();
|
|
extern "C" void SwapBlock64 ();
|
|
|
|
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 ();
|
|
|
|
// ** 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<MAX_VTX; i++)
|
|
vtx[i].number = i;
|
|
|
|
scissor_o.ul_x = 0;
|
|
scissor_o.ul_y = 0;
|
|
scissor_o.lr_x = 320;
|
|
scissor_o.lr_y = 240;
|
|
|
|
vi_org_reg = *gfx.VI_ORIGIN_REG;
|
|
view_scale[2] = 32.0f * 511.0f;
|
|
view_trans[2] = 32.0f * 511.0f;
|
|
clip_ratio = 1.0f;
|
|
|
|
lookat[0][0] = lookat[1][1] = 1.0f;
|
|
|
|
cycle_mode = 2;
|
|
allow_combine = 1;
|
|
rdp.update = UPDATE_SCISSOR | UPDATE_COMBINE | UPDATE_ZBUF_ENABLED | UPDATE_CULL_MODE;
|
|
fog_mode = RDP::fog_enabled;
|
|
maincimg[0].addr = maincimg[1].addr = last_drawn_ci_addr = 0x7FFFFFFF;
|
|
|
|
hotkey_info.hk_ref = 90;
|
|
hotkey_info.hk_motionblur = (settings.buff_clear == 0)?0:90;
|
|
hotkey_info.hk_filtering = hotkey_info.hk_motionblur;
|
|
|
|
CheckKeyPressed(G64_VK_BACK, 1); //BACK
|
|
CheckKeyPressed(G64_VK_B, 1);
|
|
CheckKeyPressed(G64_VK_V, 1);
|
|
}
|
|
|
|
RDP::RDP()
|
|
{
|
|
vtx1 = new VERTEX[256];
|
|
memset(vtx1, 0, sizeof(VERTEX)*256);
|
|
vtx2 = new VERTEX[256];
|
|
memset(vtx2, 0, sizeof(VERTEX)*256);
|
|
vtxbuf = vtxbuf2 = 0;
|
|
vtx_buffer = n_global = 0;
|
|
|
|
for (int i = 0; i < MAX_TMU; i++)
|
|
{
|
|
cache[i] = new CACHE_LUT[MAX_CACHE];
|
|
cur_cache[i] = 0;
|
|
cur_cache_n[i] = 0;
|
|
};
|
|
|
|
vtx = new VERTEX[MAX_VTX];
|
|
memset(vtx, 0, sizeof(VERTEX)*MAX_VTX);
|
|
v0 = vn = 0;
|
|
|
|
frame_buffers = new COLOR_IMAGE[NUMTEXBUF+2];
|
|
}
|
|
|
|
RDP::~RDP()
|
|
{
|
|
delete[] vtx1;
|
|
delete[] vtx2;
|
|
for (int i = 0; i < MAX_TMU; i++)
|
|
delete[] cache[i];
|
|
|
|
delete[] vtx;
|
|
delete[] frame_buffers;
|
|
}
|
|
|
|
void rdp_reset ()
|
|
{
|
|
reset = 1;
|
|
rdp.Reset();
|
|
}
|
|
|
|
void microcheck ()
|
|
{
|
|
wxUint32 i;
|
|
uc_crc = 0;
|
|
|
|
// Check first 3k of ucode, because the last 1k sometimes contains trash
|
|
for (i=0; i<3072>>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);
|
|
|
|
wxString str;
|
|
str.Printf(wxT("%08lx"), uc_crc);
|
|
RegisterSetting(Set_ucodeLookup,Data_DWORD_RDB_Setting,str,"ucode",(unsigned int)-2,NULL);
|
|
int uc = GetSetting(Set_ucodeLookup);
|
|
|
|
if (uc == -2 && ucode_error_report)
|
|
{
|
|
settings.ucode = GetSetting(Set_ucode);
|
|
|
|
ReleaseGfx ();
|
|
str.Printf(_T("Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx"), uc_crc);
|
|
wxMessageBox(str, _T("Error"), wxOK | wxICON_EXCLAMATION, GFXWindow);
|
|
|
|
ucode_error_report = FALSE; // don't report any more ucode errors from this game
|
|
}
|
|
else if (uc == -1 && ucode_error_report)
|
|
{
|
|
settings.ucode = GetSetting(Set_ucode);
|
|
|
|
ReleaseGfx ();
|
|
str.Printf(_T("Error: Unsupported uCode!\n\ncrc: %08lx"), uc_crc);
|
|
wxMessageBox(str, _T("Error"), wxOK | wxICON_EXCLAMATION, GFXWindow);
|
|
|
|
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("Glide64");
|
|
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)<<rdp.ci_size>>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);
|
|
|
|
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<height; y++)
|
|
{
|
|
for (wxUint32 x=0; x<width; x++)
|
|
{
|
|
c = ptr_src[x + y * width];
|
|
if (settings.frame_buffer&fb_read_alpha)
|
|
{
|
|
if (c > 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);
|
|
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<y_end; y++)
|
|
{
|
|
for (int x=x_start; x<x_end; x++)
|
|
{
|
|
c = ptr_src[int(x*scale_x + rdp.offset_x) + int(y * scale_y + rdp.offset_y) * stride];
|
|
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
|
|
if (read_alpha && c == 1)
|
|
c = 0;
|
|
if (rdp.ci_size <= 2)
|
|
ptr_dst[(x + y * width)^1] = c;
|
|
else
|
|
ptr_dst32[x + y * width] = RGBA16TO32(c);
|
|
}
|
|
}
|
|
|
|
// Unlock the backbuffer
|
|
grLfbUnlock (GR_LFB_READ_ONLY, buffer);
|
|
LRDP("LfbLock. Framebuffer copy complete.\n");
|
|
}
|
|
else
|
|
{
|
|
LRDP("Framebuffer copy failed.\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GoToFullScreen()
|
|
{
|
|
if (!InitGfx ())
|
|
{
|
|
LOG ("FAILED!!!\n");
|
|
return;
|
|
}
|
|
#ifdef __WINDOWS__
|
|
if (gfx.hStatusBar)
|
|
ShowWindow( gfx.hStatusBar, SW_HIDE );
|
|
ShowCursor( FALSE );
|
|
#endif
|
|
}
|
|
|
|
class SoftLocker
|
|
{
|
|
public:
|
|
// lock the mutex in the ctor
|
|
SoftLocker(wxMutex* mutex)
|
|
: _isOk(false), _mutex(mutex)
|
|
{ _isOk = ( _mutex->TryLock() == wxMUTEX_NO_ERROR ); }
|
|
|
|
// returns true if mutex was successfully locked in ctor
|
|
bool IsOk() const
|
|
{ return _isOk; }
|
|
|
|
// unlock the mutex in dtor
|
|
~SoftLocker()
|
|
{ if ( IsOk() ) _mutex->Unlock(); }
|
|
|
|
private:
|
|
bool _isOk;
|
|
wxMutex* _mutex;
|
|
};
|
|
|
|
/******************************************************************
|
|
Function: ProcessDList
|
|
Purpose: This function is called when there is a Dlist to be
|
|
processed. (High level GFX list)
|
|
input: none
|
|
output: none
|
|
*******************************************************************/
|
|
void DetectFrameBufferUsage ();
|
|
wxUint32 fbreads_front = 0;
|
|
wxUint32 fbreads_back = 0;
|
|
int cpu_fb_read_called = FALSE;
|
|
int cpu_fb_write_called = FALSE;
|
|
int cpu_fb_write = FALSE;
|
|
int cpu_fb_ignore = FALSE;
|
|
int CI_SET = TRUE;
|
|
wxUint32 ucode5_texshiftaddr = 0;
|
|
wxUint32 ucode5_texshiftcount = 0;
|
|
wxUint16 ucode5_texshift = 0;
|
|
int depth_buffer_fog;
|
|
|
|
EXPORT void CALL ProcessDList(void)
|
|
{
|
|
SoftLocker lock(mutexProcessDList);
|
|
if (!lock.IsOk()) //mutex is busy
|
|
{
|
|
if (!fullscreen)
|
|
drawNoFullscreenMessage();
|
|
// Set an interrupt to allow the game to continue
|
|
*gfx.MI_INTR_REG |= 0x20;
|
|
gfx.CheckInterrupts();
|
|
return;
|
|
}
|
|
|
|
no_dlist = false;
|
|
update_screen_count = 0;
|
|
ChangeSize ();
|
|
|
|
#ifdef ALTTAB_FIX
|
|
if (!hhkLowLevelKybd)
|
|
{
|
|
hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL,
|
|
LowLevelKeyboardProc, hInstance, 0);
|
|
}
|
|
#endif
|
|
|
|
LOG ("ProcessDList ()\n");
|
|
|
|
if (!fullscreen)
|
|
{
|
|
drawNoFullscreenMessage();
|
|
// Set an interrupt to allow the game to continue
|
|
*gfx.MI_INTR_REG |= 0x20;
|
|
gfx.CheckInterrupts();
|
|
}
|
|
|
|
if (reset)
|
|
{
|
|
reset = 0;
|
|
if (settings.autodetect_ucode)
|
|
{
|
|
// Thanks to ZeZu for ucode autodetection!!!
|
|
wxUint32 startUcode = *(wxUint32*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
}
|
|
else
|
|
memset (microcode, 0, 4096);
|
|
}
|
|
else if ( ((old_ucode == ucode_S2DEX) && (settings.ucode == ucode_F3DEX)) || settings.force_microcheck)
|
|
{
|
|
wxUint32 startUcode = *(wxUint32*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
}
|
|
|
|
if (exception)
|
|
return;
|
|
|
|
// Switch to fullscreen?
|
|
if (to_fullscreen)
|
|
GoToFullScreen();
|
|
|
|
if (!fullscreen && !settings.run_in_window)
|
|
return;
|
|
|
|
// Clear out the RDP log
|
|
#ifdef RDP_LOGGING
|
|
if (settings.logging && settings.log_clear)
|
|
{
|
|
CLOSE_RDP_LOG ();
|
|
OPEN_RDP_LOG ();
|
|
}
|
|
#endif
|
|
|
|
#ifdef UNIMP_LOG
|
|
if (settings.log_unk && settings.unk_clear)
|
|
{
|
|
std::ofstream unimp;
|
|
unimp.open("unimp.txt");
|
|
unimp.close();
|
|
}
|
|
#endif
|
|
|
|
//* Set states *//
|
|
if (settings.swapmode > 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;
|
|
|
|
//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 = wxDateTime::UNow();
|
|
#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 = wxDateTime::UNow();
|
|
sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, (perf_next-perf_cur).Format(_T("%l")).mb_str());
|
|
rdp_log << out_buf;
|
|
#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
|
|
}
|
|
if (wxMessageBox(_T("The GFX plugin caused an exception and has been disabled.\nWould you like to turn it back on and attempt to continue?"), _T("Glide64 Exception"), wxYES_NO|wxICON_EXCLAMATION, GFXWindow) == wxNO)
|
|
exception = TRUE;
|
|
else
|
|
to_fullscreen = TRUE;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (fb_emulation_enabled)
|
|
{
|
|
rdp.scale_x = rdp.scale_x_bak;
|
|
rdp.scale_y = rdp.scale_y_bak;
|
|
}
|
|
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");
|
|
}
|
|
|
|
// 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<width; x++)
|
|
{
|
|
c = ptr_src[x];
|
|
c = ((c<<8)&0xFF00) | (c >> 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<end_u_256; i++)
|
|
{
|
|
// Find where x = current 256 multiple
|
|
float x = m * ((i<<8)+256) + b;
|
|
|
|
int vn = 2 + ((i-start_u_256)<<2);
|
|
vnew[vn] = vstd[0];
|
|
vnew[vn].x = x;
|
|
vnew[vn].u0 = 255.5f;
|
|
vnew[vn].v0 += (float)splitheight * i;
|
|
vnew[vn].u1 = 255.5f;
|
|
vnew[vn].v1 += (float)splitheight * i;
|
|
|
|
vn ++;
|
|
vnew[vn] = vstd[2];
|
|
vnew[vn].x = x;
|
|
vnew[vn].u0 = 255.5f;
|
|
vnew[vn].v0 += (float)splitheight * i;
|
|
vnew[vn].u1 = 255.5f;
|
|
vnew[vn].v1 += (float)splitheight * i;
|
|
|
|
vn ++;
|
|
vnew[vn] = vnew[vn-2];
|
|
vnew[vn].u0 = 0.5f;
|
|
vnew[vn].v0 += (float)splitheight;
|
|
vnew[vn].u1 = 0.5f;
|
|
vnew[vn].v1 += (float)splitheight;
|
|
|
|
vn ++;
|
|
vnew[vn] = vnew[vn-2];
|
|
vnew[vn].u0 = 0.5f;
|
|
vnew[vn].v0 += (float)splitheight;
|
|
vnew[vn].u1 = 0.5f;
|
|
vnew[vn].v1 += (float)splitheight;
|
|
}
|
|
//*
|
|
if (n_vertices > 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<n_vertices; i++)
|
|
{
|
|
apply_shade_mods (&vptr[i]);
|
|
}
|
|
|
|
if (fullscreen)
|
|
{
|
|
if (rdp.fog_mode >= 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 = (wxUint32)(((cmd)<<24) | ((32-(sft)-(len))<<8) | (((len)-1))); \
|
|
rdp.cmd1 = (wxUint32)(data); \
|
|
gfx_instruction[settings.ucode][cmd] (); \
|
|
}
|
|
#define SETOTHERMODE(cmd,sft,len,data) { \
|
|
rdp.cmd0 = (wxUint32)(((cmd)<<24) | ((sft)<<8) | (len)); \
|
|
rdp.cmd1 = (wxUint32)(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<end; i++)
|
|
{
|
|
*(dpal++) = *(wxUint16 *)(gfx.RDRAM + (addr^2));
|
|
addr += 2;
|
|
|
|
#ifdef TLUT_LOGGING
|
|
FRDP ("%d: %08lx\n", i, *(wxUint16 *)(gfx.RDRAM + (addr^2)));
|
|
#endif
|
|
}
|
|
#ifdef TEXTURE_FILTER
|
|
if (settings.ghq_hirs)
|
|
memcpy((wxUint8*)(rdp.pal_8_rice+start), spal, count<<1);
|
|
#endif
|
|
start >>= 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 = (rdp.cmd0 >> 14) & 0x03ff;
|
|
int ul_t = (rdp.cmd0 >> 2 ) & 0x03ff;
|
|
int lr_s = (rdp.cmd1 >> 14) & 0x03ff;
|
|
int lr_t = (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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void asmLoadBlock(int src, int dst, int off, int dxt, int cnt, int swp);
|
|
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);
|
|
wxUIntPtr dst = wxPtrToUInt(rdp.tmem)+(rdp.tiles[tile].t_mem<<3);
|
|
wxUint32 cnt = lr_s-ul_s+1;
|
|
if (rdp.tiles[tile].size == 3)
|
|
cnt <<= 1;
|
|
|
|
wxUIntPtr SwapMethod = wxPtrToUInt(reinterpret_cast<void*>(SwapBlock32));
|
|
|
|
if (rdp.timg.size == 3)
|
|
LoadBlock32b(tile, ul_s, ul_t, lr_s, dxt);
|
|
else
|
|
asmLoadBlock(wxPtrToUInt(gfx.RDRAM), dst, off, _dxt, cnt, SwapMethod);
|
|
|
|
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);
|
|
}
|
|
|
|
extern "C" void asmLoadTile(int src, int dst, int width, int height, int line, int off, int end);
|
|
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<<rdp.tiles[tile].mask_s) : (wxUint16)width);
|
|
info.tile_height = (rdp.tiles[tile].mask_t ? min((wxUint16)height, 1<<rdp.tiles[tile].mask_t) : (wxUint16)height);
|
|
if (settings.hacks&hack_MK64) {
|
|
if (info.tile_width%2)
|
|
info.tile_width--;
|
|
if (info.tile_height%2)
|
|
info.tile_height--;
|
|
}
|
|
info.tex_width = rdp.timg.width;
|
|
info.tex_size = rdp.timg.size;
|
|
#endif
|
|
|
|
int line_n = rdp.timg.width << rdp.tiles[tile].size >> 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;
|
|
wxUIntPtr dst = wxPtrToUInt(rdp.tmem) + (rdp.tiles[tile].t_mem<<3);
|
|
wxUIntPtr end = wxPtrToUInt(rdp.tmem) + 4096 - (wid_64<<3);
|
|
asmLoadTile(wxPtrToUInt(gfx.RDRAM), dst, wid_64, height, line_n, offs, 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()
|
|
{
|
|
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];
|
|
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)<<cur_fb.size>>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)<<cur_fb.size>>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)<<cur_fb.size>>1);
|
|
}
|
|
//rdp.skip_drawing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
memset(gfx.RDRAM+cur_fb.addr, 0, (cur_fb.width*cur_fb.height)<<rdp.ci_size>>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:
|
|
{
|
|
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;
|
|
}
|
|
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<height; y++)
|
|
{
|
|
for (int x=0; x<width; x++)
|
|
{
|
|
c = ((ptr_src[(x + y * width)^1]) >> 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 (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]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
*******************************************************************/
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************
|
|
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
|
|
*******************************************************************/
|
|
#ifdef RDP_LOGGING
|
|
EXPORT void CALL FBWList(FrameBufferModifyEntry* /*plist*/, wxUint32 size)
|
|
#else
|
|
EXPORT void CALL FBWList(FrameBufferModifyEntry* /*plist*/, wxUint32)
|
|
#endif
|
|
{
|
|
LOG ("FBWList ()\n");
|
|
#ifdef RDP_LOGGING
|
|
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
|
|
************************************************************************/
|
|
///*
|
|
typedef struct
|
|
{
|
|
wxUint32 addr;
|
|
wxUint32 size;
|
|
wxUint32 width;
|
|
wxUint32 height;
|
|
} FrameBufferInfo;
|
|
EXPORT void CALL FBGetFrameBufferInfo(void *p)
|
|
{
|
|
LOG ("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;
|
|
}
|
|
//*/
|
|
}
|
|
//*/
|
|
#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<void*>(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)(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<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;
|
|
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
|
|
*******************************************************************/
|
|
void CALL ProcessRDPList(void)
|
|
{
|
|
LOG ("ProcessRDPList ()\n");
|
|
LRDP("ProcessRDPList ()\n");
|
|
|
|
SoftLocker lock(mutexProcessDList);
|
|
if (!lock.IsOk()) //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;
|
|
|
|
//}
|
|
}
|
|
|