4021 lines
121 KiB
C++
4021 lines
121 KiB
C++
/*
|
|
* Glide64 - Glide video plugin for Nintendo 64 emulators.
|
|
* Copyright (c) 2002 Dave2001
|
|
* Copyright (c) 2008 Günther <guenther.emu@freenet.de>
|
|
*
|
|
* 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
|
|
* Licence along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
//****************************************************************
|
|
//
|
|
// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
|
|
// Project started on December 29th, 2001
|
|
//
|
|
// 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.
|
|
//
|
|
// Official Glide64 development channel: #Glide64 on EFnet
|
|
//
|
|
// Original author: Dave2001 (Dave2999@hotmail.com)
|
|
// Other authors: Gonetz, Gugaman
|
|
//
|
|
//****************************************************************
|
|
|
|
#define M64P_PLUGIN_PROTOTYPES 1
|
|
#include "m64p_types.h"
|
|
#include "m64p_plugin.h"
|
|
#include "m64p_config.h"
|
|
#include "m64p_vidext.h"
|
|
#include "3dmath.h"
|
|
#include "Util.h"
|
|
#include "Debugger.h"
|
|
#include "Combine.h"
|
|
#include "Util.h"
|
|
#include "Ini.h"
|
|
#include "Config.h"
|
|
#include "Tmem.h"
|
|
#include "TexCache.h"
|
|
#include "TexCache.h"
|
|
#include "TexBuffer.h"
|
|
#include "CRC.h"
|
|
#include "rdp.h"
|
|
|
|
#ifndef _WIN32
|
|
#include <sys/time.h>
|
|
#endif // _WIN32
|
|
|
|
char out_buf[2048];
|
|
|
|
DWORD frame_count; // frame counter
|
|
|
|
BOOL ucode_error_report = TRUE;
|
|
int wrong_tile = -1;
|
|
|
|
int drawFlag = 1; // draw flag for rendering callback
|
|
|
|
#if defined(__GNUC__)
|
|
#define bswap32(x) __builtin_bswap32(x)
|
|
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
#include <stdlib.h>
|
|
#define bswap32(x) _byteswap_ulong(x)
|
|
#else
|
|
static inline uint32_t bswap32(uint32_t val)
|
|
{
|
|
return (((val & 0xff000000) >> 24) |
|
|
((val & 0x00ff0000) >> 8) |
|
|
((val & 0x0000ff00) << 8) |
|
|
((val & 0x000000ff) << 24));
|
|
}
|
|
#endif
|
|
|
|
// global strings
|
|
const char *ACmp[4] = { "NONE", "THRESHOLD", "UNKNOWN", "DITHER" };
|
|
|
|
const char *Mode0[16] = { "COMBINED", "TEXEL0",
|
|
"TEXEL1", "PRIMITIVE",
|
|
"SHADE", "ENVIORNMENT",
|
|
"1", "NOISE",
|
|
"0", "0",
|
|
"0", "0",
|
|
"0", "0",
|
|
"0", "0" };
|
|
const char *Mode1[16] = { "COMBINED", "TEXEL0",
|
|
"TEXEL1", "PRIMITIVE",
|
|
"SHADE", "ENVIORNMENT",
|
|
"CENTER", "K4",
|
|
"0", "0",
|
|
"0", "0",
|
|
"0", "0",
|
|
"0", "0" };
|
|
const char *Mode2[32] = { "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[8] = { "COMBINED", "TEXEL0",
|
|
"TEXEL1", "PRIMITIVE",
|
|
"SHADE", "ENVIORNMENT",
|
|
"1", "0" };
|
|
|
|
const char *Alpha0[8] = { "COMBINED", "TEXEL0",
|
|
"TEXEL1", "PRIMITIVE",
|
|
"SHADE", "ENVIORNMENT",
|
|
"1", "0" };
|
|
const char *Alpha2[8] = { "LOD_FRACTION", "TEXEL0",
|
|
"TEXEL1", "PRIMITIVE",
|
|
"SHADE", "ENVIORNMENT",
|
|
"PRIM_LODFRAC", "0" };
|
|
|
|
//FIXME:unused?
|
|
//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[2] = { "G_ZS_PIXEL", "G_ZS_PRIM" };
|
|
|
|
const char *str_yn[2] = { "NO", "YES" };
|
|
const char *str_offon[2] = { "OFF", "ON" };
|
|
|
|
const char *str_cull[4] = { "DISABLE", "FRONT", "BACK", "BOTH" };
|
|
|
|
// I=intensity probably
|
|
const char *str_format[8] = { "RGBA", "YUV", "CI", "IA", "I", "?", "?", "?" };
|
|
const char *str_size[4] = { "4bit", "8bit", "16bit", "32bit" };
|
|
const char *str_cm[4] = { "WRAP/NO CLAMP", "MIRROR/NO CLAMP", "WRAP/CLAMP", "MIRROR/CLAMP" };
|
|
|
|
//const char *str_lod[] = { "1", "2", "4", "8", "16", "32", "64", "128", "256" };
|
|
//const char *str_aspect[] = { "1x8", "1x4", "1x2", "1x1", "2x1", "4x1", "8x1" };
|
|
|
|
const char *str_filter[3] = { "Point Sampled", "Average (box)", "Bilinear" };
|
|
|
|
const char *str_tlut[4] = { "TT_NONE", "TT_UNKNOWN", "TT_RGBA_16", "TT_IA_16" };
|
|
|
|
const char *CIStatus[10] = { "ci_main", "ci_zimg", "ci_unknown", "ci_useless",
|
|
"ci_old_copy", "ci_copy", "ci_copy_self",
|
|
"ci_zcopy", "ci_aux", "ci_aux_copy" };
|
|
|
|
typedef struct
|
|
{
|
|
int ucode;
|
|
int crc;
|
|
} UcodeData;
|
|
|
|
static UcodeData UcodeList[] =
|
|
{
|
|
{0, 0x006bd77f},
|
|
{2, 0x03044b84},
|
|
{2, 0x030f4b84},
|
|
{1, 0x05165579},
|
|
{1, 0x05777c62},
|
|
{1, 0x057e7c62},
|
|
{1, 0x07200895},
|
|
{2, 0x0bf36d36},
|
|
{-1, 0x0d7bbffb},
|
|
{5, 0x0d7cbffb},
|
|
{2, 0x0ff79527},
|
|
{-1, 0x0ff795bf},
|
|
{1, 0x1118b3e0},
|
|
{2, 0x168e9cd5},
|
|
{2, 0x1a1e18a0},
|
|
{2, 0x1a1e1920},
|
|
{2, 0x1a62dbaf},
|
|
{2, 0x1a62dc2f},
|
|
{1, 0x1de712ff},
|
|
{6, 0x1ea9e30f},
|
|
{2, 0x21f91834},
|
|
{2, 0x21f91874},
|
|
{2, 0x22099872},
|
|
{1, 0x24cd885b},
|
|
{1, 0x26a7879a},
|
|
{6, 0x299d5072},
|
|
{2, 0x2b291027},
|
|
{6, 0x2b5a89c2},
|
|
{1, 0x2c7975d6},
|
|
{2, 0x2f71d1d5},
|
|
{2, 0x2f7dd1d5},
|
|
{1, 0x327b933d},
|
|
{1, 0x339872a6},
|
|
{2, 0x377359b6},
|
|
{0, 0x3a1c2b34},
|
|
{0, 0x3a1cbac3},
|
|
{0, 0x3f7247fb},
|
|
{1, 0x3ff1a4ca},
|
|
{0, 0x4165e1fd},
|
|
{1, 0x4340ac9b},
|
|
{1, 0x440cfad6},
|
|
{7, 0x47d46e86},
|
|
{2, 0x485abff2},
|
|
{1, 0x4fe6df78},
|
|
{0, 0x5182f610},
|
|
{1, 0x5257cd2a},
|
|
{1, 0x5414030c},
|
|
{1, 0x5414030d},
|
|
{1, 0x559ff7d4},
|
|
{4, 0x5b5d36e3},
|
|
{3, 0x5b5d3763},
|
|
{0, 0x5d1d6f53},
|
|
{2, 0x5d3099f1},
|
|
{1, 0x5df1408c},
|
|
{1, 0x5ef4e34a},
|
|
{1, 0x6075e9eb},
|
|
{1, 0x60c1dcc4},
|
|
{2, 0x6124a508},
|
|
{2, 0x630a61fb},
|
|
{5, 0x63be08b1},
|
|
{5, 0x63be08b3},
|
|
{1, 0x64ed27e5},
|
|
{2, 0x65201989},
|
|
{2, 0x65201a09},
|
|
{1, 0x66c0b10a},
|
|
{2, 0x679e1205},
|
|
{6, 0x6bb745c9},
|
|
{2, 0x6d8f8f8a},
|
|
{0, 0x6e4d50af},
|
|
{1, 0x6eaa1da8},
|
|
{1, 0x72a4f34e},
|
|
{1, 0x73999a23},
|
|
{6, 0x74af0a74},
|
|
{2, 0x753be4a5},
|
|
{6, 0x794c3e28},
|
|
{1, 0x7df75834},
|
|
{1, 0x7f2d0a2e},
|
|
{1, 0x82f48073},
|
|
{1, 0x841ce10f},
|
|
{-1, 0x844b55b5},
|
|
{1, 0x863e1ca7},
|
|
{-1, 0x86b1593e},
|
|
{1, 0x8805ffea},
|
|
{1, 0x8d5735b2},
|
|
{1, 0x8d5735b3},
|
|
{-1, 0x8ec3e124},
|
|
{2, 0x93d11f7b},
|
|
{2, 0x93d11ffb},
|
|
{2, 0x93d1ff7b},
|
|
{2, 0x9551177b},
|
|
{2, 0x955117fb},
|
|
{2, 0x95cd0062},
|
|
{1, 0x97d1b58a},
|
|
{2, 0xa2d0f88e},
|
|
{1, 0xa346a5cc},
|
|
{2, 0xaa86cb1d},
|
|
{2, 0xaae4a5b9},
|
|
{2, 0xad0a6292},
|
|
{2, 0xad0a6312},
|
|
{0, 0xae08d5b9},
|
|
{1, 0xb1821ed3},
|
|
{1, 0xb4577b9c},
|
|
{0, 0xb54e7f93},
|
|
{2, 0xb62f900f},
|
|
{2, 0xba65ea1e},
|
|
{8, 0xba86cb1d},
|
|
{0, 0xbc03e969},
|
|
{2, 0xbc45382e},
|
|
{1, 0xbe78677c},
|
|
{1, 0xbed8b069},
|
|
{1, 0xc3704e41},
|
|
{1, 0xc46dbc3d},
|
|
{1, 0xc99a4c6c},
|
|
{2, 0xc901ce73},
|
|
{2, 0xc901cef3},
|
|
{2, 0xcb8c9b6c},
|
|
{1, 0xcee7920f},
|
|
{2, 0xcfa35a45},
|
|
{1, 0xd1663234},
|
|
{6, 0xd20dedbf},
|
|
{1, 0xd2a9f59c},
|
|
{1, 0xd41db5f7},
|
|
{0, 0xd5604971},
|
|
{1, 0xd57049a5},
|
|
{-1, 0xd5c4dc96},
|
|
{0, 0xd5d68b1f},
|
|
{1, 0xd802ec04},
|
|
{2, 0xda13ab96},
|
|
{2, 0xde7d67d4},
|
|
{2, 0xe1290fa2},
|
|
{0, 0xe41ec47e},
|
|
{2, 0xe65cb4ad},
|
|
{1, 0xe89c2b92},
|
|
{1, 0xe9231df2},
|
|
{1, 0xec040469},
|
|
{1, 0xee47381b},
|
|
{1, 0xef54ee35},
|
|
{-1, 0xf9893f70},
|
|
{1, 0xfb816260},
|
|
{-1, 0xff372492}
|
|
};
|
|
|
|
// ZIGGY
|
|
// depth save/restore variables
|
|
// 0 : normal mode
|
|
// 1 : writing in normal depth buffer
|
|
// 2 : writing in alternate depth buffer
|
|
static int render_depth_mode;
|
|
|
|
// ** 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 rsp_reserved0();
|
|
static void rsp_reserved1();
|
|
static void rsp_reserved2();
|
|
static void rsp_reserved3();
|
|
|
|
static void ys_memrect();
|
|
|
|
BYTE microcode[4096];
|
|
DWORD 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 "ucode.h"
|
|
|
|
static BOOL reset = 0;
|
|
static int old_ucode = -1;
|
|
|
|
// rdp_reset - resets the RDP_E
|
|
void rdp_reset ()
|
|
{
|
|
reset = 1;
|
|
|
|
rdp.model_i = 0;
|
|
|
|
rdp.n_cached[0] = 0;
|
|
rdp.n_cached[1] = 0;
|
|
rdp.cur_cache[0] = NULL;
|
|
rdp.cur_cache[1] = NULL;
|
|
/*
|
|
rdp.tmem_ptr[0] = offset_textures;
|
|
rdp.tmem_ptr[1] = offset_textures;
|
|
if (grTextureBufferExt)
|
|
rdp.tmem_ptr[1] = TEXMEM_2MB_EDGE * 2;
|
|
*/
|
|
rdp.c_a0 = 0;
|
|
rdp.c_b0 = 0;
|
|
rdp.c_c0 = 0;
|
|
rdp.c_d0 = 0;
|
|
rdp.c_Aa0 = 0;
|
|
rdp.c_Ab0 = 0;
|
|
rdp.c_Ac0 = 0;
|
|
rdp.c_Ad0 = 0;
|
|
|
|
rdp.c_a1 = 0;
|
|
rdp.c_b1 = 0;
|
|
rdp.c_c1 = 0;
|
|
rdp.c_d1 = 0;
|
|
rdp.c_Aa1 = 0;
|
|
rdp.c_Ab1 = 0;
|
|
rdp.c_Ac1 = 0;
|
|
rdp.c_Ad1 = 0;
|
|
|
|
// Clear the palette CRC
|
|
int i;
|
|
for (i=0; i<16; i++)
|
|
rdp.pal_8_crc[i] = 0;
|
|
|
|
// Clear the palettes
|
|
for (i=0; i<256; i++)
|
|
rdp.pal_8[i] = 0;
|
|
|
|
rdp.tlut_mode = 0;
|
|
|
|
// Clear all segments ** VERY IMPORTANT FOR ZELDA **
|
|
for (i=0; i<16; i++)
|
|
rdp.segment[i] = 0;
|
|
|
|
for (i=0; i<512; i++)
|
|
rdp.addr[i] = 0;
|
|
|
|
// set all vertex numbers
|
|
for (i=0; i<MAX_VTX; i++)
|
|
rdp.vtx[i].number = i;
|
|
|
|
rdp.scissor_o.ul_x = 0;
|
|
rdp.scissor_o.ul_y = 0;
|
|
rdp.scissor_o.lr_x = 320;
|
|
rdp.scissor_o.lr_y = 240;
|
|
rdp.num_lights = 0;
|
|
rdp.lookat[0][0] = rdp.lookat[1][1] = 1.0f;
|
|
rdp.lookat[0][1] = rdp.lookat[0][2] = rdp.lookat[1][0] = rdp.lookat[1][2] = 0.0f;
|
|
rdp.texrecting = 0;
|
|
rdp.rm = 0;
|
|
rdp.render_mode_changed = 0;
|
|
rdp.othermode_h = 0;
|
|
rdp.othermode_l = 0;
|
|
|
|
rdp.tex_ctr = 0;
|
|
|
|
rdp.tex = 0;
|
|
|
|
rdp.cimg = 0;
|
|
rdp.ocimg = 0;
|
|
rdp.zimg = 0;
|
|
rdp.ci_width = 0;
|
|
rdp.cycle_mode = 2;
|
|
|
|
rdp.allow_combine = 1;
|
|
|
|
rdp.fog_coord_enabled = FALSE;
|
|
rdp.skip_drawing = FALSE;
|
|
|
|
memset(rdp.frame_buffers, 0, sizeof(rdp.frame_buffers));
|
|
rdp.main_ci_index = 0;
|
|
rdp.maincimg[0].addr = rdp.maincimg[1].addr = rdp.last_drawn_ci_addr = 0x7FFFFFFF;
|
|
rdp.read_previous_ci = FALSE;
|
|
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
|
|
rdp.yuv_im_begin = 0x00FFFFFF;
|
|
rdp.yuv_image = FALSE;
|
|
rdp.cur_tex_buf = 0;
|
|
rdp.acc_tex_buf = 0;
|
|
rdp.cur_image = 0;
|
|
rdp.hires_tex = 0;
|
|
|
|
hotkey_info.fb_always = 0;
|
|
hotkey_info.fb_motionblur = (settings.buff_clear == 0)?0:60;
|
|
hotkey_info.filtering = hotkey_info.fb_motionblur;
|
|
hotkey_info.corona = hotkey_info.fb_motionblur;
|
|
#ifdef _WIN32
|
|
GetAsyncKeyState (VK_BACK);
|
|
GetAsyncKeyState(0x42);
|
|
GetAsyncKeyState(0x56);
|
|
GetAsyncKeyState(0x43);
|
|
#endif // _WIN32
|
|
for (i = 0; i < num_tmu; i++)
|
|
rdp.texbufs[i].count = 0;
|
|
rdp.vi_org_reg = *gfx.VI_ORIGIN_REG;
|
|
rdp.view_scale[0] = 160.0f * rdp.scale_x;
|
|
rdp.view_scale[1] = -120.0f * rdp.scale_y;
|
|
rdp.view_trans[0] = 160.0f * rdp.scale_x;
|
|
rdp.view_trans[1] = 120.0f * rdp.scale_y;
|
|
rdp.view_scale[2] = 32.0f * 511.0f;
|
|
rdp.view_trans[2] = 32.0f * 511.0f;
|
|
}
|
|
|
|
# define PCEndian
|
|
# ifdef PCEndian
|
|
# define ByteEndian(address) (address^3)
|
|
# define WordEndian(address) (address^2)
|
|
# endif
|
|
# define _Read8Endian(array, address) (*((BYTE *)(array+ByteEndian(address))))
|
|
__inline static DWORD searchrdram(const char *ct)
|
|
{
|
|
DWORD pos, pos2;
|
|
const char *t;
|
|
t = ct;
|
|
for (pos=0; pos<0x400000; pos++) {
|
|
for (pos2=pos, t=ct; *ct != 0; t++, pos2++) {
|
|
if (_Read8Endian(gfx.RDRAM, pos2) != *t)
|
|
break;
|
|
else
|
|
if (*(t + 1) == 0)
|
|
return pos;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int LookupUcode (int crc)
|
|
{
|
|
for (int i = 0; i < sizeof(UcodeList)/sizeof(UcodeData); i++)
|
|
{
|
|
if (crc == UcodeList[i].crc)
|
|
{
|
|
return UcodeList[i].ucode;
|
|
}
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
void microcheck ()
|
|
{
|
|
DWORD 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 += ((DWORD*)microcode)[i];
|
|
}
|
|
|
|
FRDP_E ("crc: %08lx\n", uc_crc);
|
|
|
|
#ifdef LOG_UCODE
|
|
std::ofstream ucf;
|
|
ucf.open ("ucode.txt", ios::out | ios::binary);
|
|
char d;
|
|
for (i=0; i<0x400000; i++)
|
|
{
|
|
d = ((char*)gfx.RDRAM)[i^3];
|
|
ucf.write (&d, 1);
|
|
}
|
|
ucf.close ();
|
|
#endif
|
|
|
|
char str[9];
|
|
sprintf (str, "%08lx", (unsigned long)uc_crc);
|
|
|
|
FRDP("ucode = %s\n", str);
|
|
int uc = LookupUcode(uc_crc);
|
|
WriteLog(M64MSG_INFO, "ucode = %d\n", uc);
|
|
if (uc == -2 && ucode_error_report)
|
|
{
|
|
Config_Open();
|
|
settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE);
|
|
|
|
ReleaseGfx ();
|
|
WriteLog(M64MSG_ERROR, "Error: uCode crc not found in INI, using currently selected uCode\n\n%08lx", (unsigned long)uc_crc);
|
|
|
|
ucode_error_report = FALSE; // don't report any more ucode errors from this game
|
|
}
|
|
else if (uc == -1 && ucode_error_report)
|
|
{
|
|
Config_Open();
|
|
settings.ucode = Config_ReadInt ("ucode", "Force microcode", 0, FALSE, FALSE);
|
|
|
|
ReleaseGfx ();
|
|
WriteLog(M64MSG_ERROR, "Error: Unsupported uCode!\n\ncrc: %08lx", (unsigned long)uc_crc);
|
|
|
|
ucode_error_report = FALSE; // don't report any more ucode errors from this game
|
|
}
|
|
else
|
|
{
|
|
old_ucode = settings.ucode;
|
|
settings.ucode = uc;
|
|
FRDP("microcheck: old ucode: %d, new ucode: %d\n", old_ucode, uc);
|
|
}
|
|
}
|
|
|
|
void drawNoFullscreenMessage()
|
|
{
|
|
LOG ("drawNoFullscreenMessage ()\n");
|
|
}
|
|
|
|
static WORD yuv_to_rgb(BYTE y, BYTE u, BYTE v)
|
|
{
|
|
float r = y + (1.370705f * (v-128));
|
|
float g = y - (0.698001f * (v-128)) - (0.337633f * (u-128));
|
|
float b = y + (1.732446f * (u-128));
|
|
r *= 0.125f;
|
|
g *= 0.125f;
|
|
b *= 0.125f;
|
|
//clipping the result
|
|
if (r > 32) r = 32;
|
|
if (g > 32) g = 32;
|
|
if (b > 32) b = 32;
|
|
if (r < 0) r = 0;
|
|
if (g < 0) g = 0;
|
|
if (b < 0) b = 0;
|
|
|
|
WORD c = (WORD)(((WORD)(r) << 11) |
|
|
((WORD)(g) << 6) |
|
|
((WORD)(b) << 1) | 1);
|
|
return c;
|
|
}
|
|
|
|
static void DrawYUVImageToFrameBuffer()
|
|
{
|
|
WORD width = (WORD)(rdp.yuv_lr_x - rdp.yuv_ul_x);
|
|
WORD height = (WORD)(rdp.yuv_lr_y - rdp.yuv_ul_y);
|
|
DWORD * mb = (DWORD*)(gfx.RDRAM+rdp.yuv_im_begin); //pointer to the first macro block
|
|
WORD * cimg = (WORD*)(gfx.RDRAM+rdp.cimg);
|
|
//yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg
|
|
for (WORD y = 0; y < height; y+=16)
|
|
{
|
|
for (WORD x = 0; x < width; x+=16)
|
|
{
|
|
WORD *dst = cimg + x + y * rdp.ci_width;
|
|
for (WORD h = 0; h < 16; h++)
|
|
{
|
|
for (WORD w = 0; w < 8; w++)
|
|
{
|
|
DWORD t = *(mb++); //each DWORD contains 2 pixels
|
|
if ((x < rdp.ci_width) && (y < rdp.ci_height)) //clipping. texture image may be larger than color image
|
|
{
|
|
BYTE y0 = (BYTE)t&0xFF;
|
|
BYTE v = (BYTE)(t>>8)&0xFF;
|
|
BYTE y1 = (BYTE)(t>>16)&0xFF;
|
|
BYTE u = (BYTE)(t>>24)&0xFF;
|
|
*(dst++) = yuv_to_rgb(y0, u, v);
|
|
*(dst++) = yuv_to_rgb(y1, u, v);
|
|
}
|
|
}
|
|
dst += rdp.ci_width - 16;
|
|
}
|
|
mb += 64; //macro block is 768 bytes long, last 256 bytes are useless
|
|
}
|
|
}
|
|
}
|
|
|
|
static DWORD d_ul_x, d_ul_y, d_lr_x, d_lr_y;
|
|
|
|
typedef struct {
|
|
int ul_x, ul_y, lr_x, lr_y;
|
|
} FB_PART;
|
|
|
|
static void DrawPart(int scr_ul_x, int scr_ul_y, int prt_ul_x, int prt_ul_y, int width, int height, float scale_x, float scale_y)
|
|
{
|
|
WORD * dst = new WORD[width*height];
|
|
DWORD shift = ((d_ul_y+prt_ul_y) * rdp.ci_width + d_ul_x + prt_ul_x) << 1;
|
|
WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
|
|
WORD c;
|
|
for (int y=0; y < height; y++)
|
|
{
|
|
for (int x=0; x < width; x++)
|
|
{
|
|
c = src[(int(x*scale_x)+int(y*scale_y)*rdp.ci_width)^1];
|
|
dst[x+y*width] = c?((c >> 1) | 0x8000):0;
|
|
}
|
|
}
|
|
|
|
grLfbWriteRegion(GR_BUFFER_BACKBUFFER,
|
|
scr_ul_x,
|
|
scr_ul_y,
|
|
GR_LFB_SRC_FMT_1555,
|
|
width,
|
|
height,
|
|
FXTRUE,
|
|
width<<1,
|
|
dst);
|
|
delete[] dst;
|
|
}
|
|
|
|
static void DrawFrameBufferToScreen()
|
|
{
|
|
FRDP("DrawFrameBufferToScreen. cimg: %08lx, ul_x: %d, uly: %d, lr_x: %d, lr_y: %d\n", rdp.cimg, d_ul_x, d_ul_y, d_lr_x, d_lr_y);
|
|
if (!fullscreen)
|
|
return;
|
|
grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE);
|
|
grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE);
|
|
grConstantColorValue (0xFFFFFFFF);
|
|
grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
|
|
GR_BLEND_ONE_MINUS_SRC_ALPHA,
|
|
GR_BLEND_ONE,
|
|
GR_BLEND_ZERO);
|
|
rdp.update |= UPDATE_COMBINE;
|
|
|
|
float scale_x_dst = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
|
|
float scale_y_dst = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
|
|
float scale_x_src = (float)rdp.vi_width / (float)settings.scr_res_x;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
|
|
float scale_y_src = (float)rdp.vi_height / (float)settings.scr_res_y;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
|
|
int src_width = d_lr_x - d_ul_x + 1;
|
|
int src_height = d_lr_y - d_ul_y + 1;
|
|
int dst_width, dst_height, ul_x, ul_y;
|
|
|
|
if (!settings.fb_optimize_write || ((src_width < 33) && (src_height < 33)))
|
|
{
|
|
dst_width = int(src_width*scale_x_dst);
|
|
dst_height = int(src_height*scale_y_dst);
|
|
ul_x = int(d_ul_x*scale_x_dst);
|
|
ul_y = int(d_ul_y*scale_y_dst);
|
|
DrawPart(ul_x, ul_y, 0, 0, dst_width, dst_height, scale_x_src, scale_y_src);
|
|
memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
|
|
return;
|
|
}
|
|
|
|
FB_PART parts[8];
|
|
int p;
|
|
for (p = 0; p < 8; p++)
|
|
{
|
|
parts[p].lr_x = parts[p].lr_y = 0;
|
|
parts[p].ul_x = parts[p].ul_y = 0xFFFF;
|
|
}
|
|
|
|
int num_of_parts = 0;
|
|
int cur_part = 0;
|
|
int most_left = d_ul_x;
|
|
int most_right = d_lr_x;
|
|
DWORD shift = (d_ul_y * rdp.ci_width + d_ul_x) << 1;
|
|
WORD * src = (WORD*)(gfx.RDRAM+rdp.cimg+shift);
|
|
for (int h = 0; h < src_height; h++)
|
|
{
|
|
cur_part = 0;
|
|
int w = 0;
|
|
while (w < src_width)
|
|
{
|
|
while (w < src_width)
|
|
{
|
|
if (src[(w+h*rdp.ci_width)^1] == 0)
|
|
w++;
|
|
else
|
|
break;
|
|
}
|
|
if (w == src_width)
|
|
break;
|
|
if (num_of_parts == 0) //first part
|
|
{
|
|
parts[0].ul_x = w;
|
|
most_left = w;
|
|
parts[0].ul_y = h;
|
|
cur_part = 0;
|
|
}
|
|
else if (w < most_left - 2) //new part
|
|
{
|
|
parts[num_of_parts].ul_x = w;
|
|
most_left = w;
|
|
parts[num_of_parts].ul_y = h;
|
|
cur_part = num_of_parts;
|
|
num_of_parts++;
|
|
}
|
|
else if (w > most_right + 2) //new part
|
|
{
|
|
parts[num_of_parts].ul_x = w;
|
|
most_right = w;
|
|
parts[num_of_parts].ul_y = h;
|
|
cur_part = num_of_parts;
|
|
num_of_parts++;
|
|
}
|
|
else
|
|
{
|
|
for (p = 0; p < num_of_parts; p++)
|
|
{
|
|
if ((w > parts[p].ul_x - 2) && (w < parts[p].lr_x+2))
|
|
{
|
|
if (w < parts[p].ul_x) parts[p].ul_x = w;
|
|
break;
|
|
}
|
|
}
|
|
cur_part = p;
|
|
}
|
|
while (w < src_width)
|
|
{
|
|
if (src[(w+h*rdp.ci_width)^1] != 0)
|
|
w++;
|
|
else
|
|
break;
|
|
}
|
|
if (num_of_parts == 0) //first part
|
|
{
|
|
parts[0].lr_x = w;
|
|
most_right = w;
|
|
num_of_parts++;
|
|
}
|
|
else
|
|
{
|
|
if (parts[cur_part].lr_x < w) parts[cur_part].lr_x = w;
|
|
if (most_right < w) most_right = w;
|
|
parts[cur_part].lr_y = h;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
for (p = 0; p < num_of_parts; p++)
|
|
{
|
|
FRDP("part#%d ul_x: %d, ul_y: %d, lr_x: %d, lr_y: %d\n", p, parts[p].ul_x, parts[p].ul_y, parts[p].lr_x, parts[p].lr_y);
|
|
}
|
|
*/
|
|
for (p = 0; p < num_of_parts; p++)
|
|
{
|
|
dst_width = int((parts[p].lr_x-parts[p].ul_x + 1)*scale_x_dst);
|
|
dst_height = int((parts[p].lr_y-parts[p].ul_y + 1)*scale_y_dst);
|
|
ul_x = int((d_ul_x+parts[p].ul_x)*scale_x_dst);
|
|
ul_y = int((d_ul_y+parts[p].ul_y)*scale_y_dst);
|
|
DrawPart(ul_x, ul_y, parts[p].ul_x, parts[p].ul_y, dst_width, dst_height, scale_x_src, scale_y_src);
|
|
}
|
|
memset(gfx.RDRAM+rdp.cimg, 0, rdp.ci_width*rdp.ci_height*rdp.ci_size);
|
|
}
|
|
|
|
#define RGBA16TO32(color) \
|
|
((color&1)?0xFF:0) | \
|
|
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) | \
|
|
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) | \
|
|
((DWORD)((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.
|
|
|
|
int width = rdp.ci_width;//*gfx.VI_WIDTH_REG;
|
|
int height;
|
|
if (settings.fb_smart && !settings.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.PPL)
|
|
height -= rdp.ci_upper_bound;
|
|
}
|
|
FRDP ("width: %d, height: %d... ", width, height);
|
|
|
|
if (rdp.scale_x < 1.1f)
|
|
{
|
|
WORD * ptr_src = new WORD[width*height];
|
|
if (grLfbReadRegion(buffer,
|
|
0,
|
|
0,//rdp.ci_upper_bound,
|
|
width,
|
|
height,
|
|
width<<1,
|
|
ptr_src))
|
|
{
|
|
WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
|
|
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
|
|
WORD c;
|
|
|
|
for (int y=0; y<height; y++)
|
|
{
|
|
for (int x=0; x<width; x++)
|
|
{
|
|
c = ptr_src[x + y * width];
|
|
if (settings.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);
|
|
}
|
|
}
|
|
/*
|
|
}
|
|
else //8bit I or CI
|
|
{
|
|
BYTE *ptr_dst = (BYTE*)(gfx.RDRAM+rdp.cimg);
|
|
WORD c;
|
|
|
|
for (int y=0; y<height; y++)
|
|
{
|
|
for (int x=0; x<width; x++)
|
|
{
|
|
c = ptr_src[x + y * width];
|
|
BYTE b = (BYTE)((float)(c&0x1F)/31.0f*85.0f);
|
|
BYTE g = (BYTE)((float)((c>>5)&0x3F)/63.0f*85.0f);
|
|
BYTE r = (BYTE)((float)((c>>11)&0x1F)/31.0f*85.0f);
|
|
c = (c&0xFFC0) | ((c&0x001F) << 1) | 1;
|
|
// FRDP("src: %08lx, dst: %d\n",c,(BYTE)(r+g+b));
|
|
ptr_dst[(x + y * width)^1] = (BYTE)(r+g+b);
|
|
// ptr_dst[(x + y * width)^1] = (BYTE)((c>>8)&0xFF);
|
|
}
|
|
}
|
|
} */
|
|
RDP ("ReadRegion. Framebuffer copy complete.\n");
|
|
}
|
|
else
|
|
{
|
|
RDP ("Framebuffer copy failed.\n");
|
|
}
|
|
delete[] ptr_src;
|
|
}
|
|
else
|
|
{
|
|
if (rdp.motionblur && settings.fb_hires)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
float scale_x = (float)settings.scr_res_x / rdp.vi_width;//(float)max(rdp.frame_buffers[rdp.main_ci_index].width, rdp.ci_width);
|
|
float scale_y = (float)settings.scr_res_y / rdp.vi_height;//(float)max(rdp.frame_buffers[rdp.main_ci_index].height, rdp.ci_lower_bound);
|
|
|
|
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);
|
|
|
|
|
|
// VP 888 disconnected for now
|
|
if (1||rdp.ci_size <= 2) {
|
|
if (grLfbLock (GR_LFB_READ_ONLY,
|
|
buffer,
|
|
GR_LFBWRITEMODE_565,
|
|
GR_ORIGIN_UPPER_LEFT,
|
|
FXFALSE,
|
|
&info))
|
|
{
|
|
WORD *ptr_src = (WORD*)info.lfbPtr;
|
|
WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
|
|
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
|
|
WORD c;
|
|
DWORD stride = info.strideInBytes>>1;
|
|
|
|
BOOL read_alpha = settings.fb_read_alpha;
|
|
if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status != ci_aux)
|
|
read_alpha = FALSE;
|
|
for (int y=0; y<height; y++)
|
|
{
|
|
for (int x=0; x<width; x++)
|
|
{
|
|
c = ptr_src[int(x*scale_x) + int(y * scale_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);
|
|
RDP ("LfbLock. Framebuffer copy complete.\n");
|
|
}
|
|
else
|
|
{
|
|
RDP ("Framebuffer copy failed.\n");
|
|
}
|
|
|
|
} else {
|
|
|
|
if (grLfbLock (GR_LFB_READ_ONLY,
|
|
buffer,
|
|
GR_LFBWRITEMODE_888,
|
|
GR_ORIGIN_UPPER_LEFT,
|
|
FXFALSE,
|
|
&info))
|
|
{
|
|
DWORD *ptr_src = (DWORD*)info.lfbPtr;
|
|
//FIXME: Why unused?
|
|
//WORD *ptr_dst = (WORD*)(gfx.RDRAM+rdp.cimg);
|
|
DWORD *ptr_dst32 = (DWORD*)(gfx.RDRAM+rdp.cimg);
|
|
DWORD c;
|
|
DWORD stride = info.strideInBytes>>1;
|
|
|
|
for (int y=0; y<height; y++)
|
|
{
|
|
for (int x=0; x<width; x++)
|
|
{
|
|
c = ptr_src[int(x*scale_x) + int(y * scale_y) * stride];
|
|
ptr_dst32[x + y * width] = c;
|
|
}
|
|
}
|
|
|
|
// Unlock the backbuffer
|
|
grLfbUnlock (GR_LFB_READ_ONLY, buffer);
|
|
RDP ("LfbLock. Framebuffer copy complete.\n");
|
|
}
|
|
else
|
|
{
|
|
RDP ("Framebuffer copy failed.\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************
|
|
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 ();
|
|
DWORD fbreads_front = 0;
|
|
DWORD fbreads_back = 0;
|
|
BOOL cpu_fb_read_called = FALSE;
|
|
BOOL cpu_fb_write_called = FALSE;
|
|
BOOL cpu_fb_write = FALSE;
|
|
BOOL cpu_fb_ignore = FALSE;
|
|
BOOL CI_SET = TRUE;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
EXPORT void CALL ProcessDList(void)
|
|
{
|
|
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;
|
|
|
|
memset (microcode, 0, 4096);
|
|
if (settings.autodetect_ucode)
|
|
{
|
|
// Thanks to ZeZu for ucode autodetection!!!
|
|
|
|
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
|
|
}
|
|
}
|
|
else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
|
|
{
|
|
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
}
|
|
|
|
if (exception) return;
|
|
|
|
// Switch to fullscreen?
|
|
if (to_fullscreen)
|
|
{
|
|
to_fullscreen = FALSE;
|
|
|
|
if (!InitGfx (FALSE))
|
|
{
|
|
LOG ("FAILED!!!\n");
|
|
return;
|
|
}
|
|
fullscreen = TRUE;
|
|
}
|
|
|
|
// 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, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
|
|
if (rdp.model_stack_size == 0)
|
|
rdp.model_stack_size = 32;
|
|
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;
|
|
fbreads_front = fbreads_back = 0;
|
|
rdp.fog_multiplier = rdp.fog_offset = 0;
|
|
rdp.zsrc = 0;
|
|
|
|
if (cpu_fb_write == TRUE)
|
|
DrawFrameBufferToScreen();
|
|
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;
|
|
|
|
//analize possible frame buffer usage
|
|
if (settings.fb_smart)
|
|
DetectFrameBufferUsage();
|
|
if (!settings.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
|
|
DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
|
|
DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
|
|
FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length);
|
|
FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
|
|
|
|
if (settings.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;
|
|
DWORD a;
|
|
|
|
// catches exceptions so that it doesn't freeze
|
|
#ifdef CATCH_EXCEPTIONS
|
|
try {
|
|
#endif
|
|
|
|
// 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 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
|
|
rdp.cmd1 = ((DWORD*)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
|
|
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
|
|
#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;
|
|
|
|
RDP ("End of DL\n");
|
|
rdp.pc_i --;
|
|
}
|
|
}
|
|
|
|
#ifdef PERFORMANCE
|
|
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
|
|
__int64 t = perf_next-perf_cur;
|
|
sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
|
|
rdp_log << out_buf;
|
|
#endif
|
|
|
|
} while (!rdp.halt);
|
|
#ifdef CATCH_EXCEPTIONS
|
|
} catch (...) {
|
|
|
|
if (fullscreen) ReleaseGfx ();
|
|
WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled.");
|
|
exception = TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (settings.fb_smart)
|
|
{
|
|
rdp.scale_x = rdp.scale_x_bak;
|
|
rdp.scale_y = rdp.scale_y_bak;
|
|
}
|
|
if (settings.fb_read_always)
|
|
{
|
|
CopyFrameBuffer ();
|
|
}
|
|
if (rdp.yuv_image)
|
|
{
|
|
DrawYUVImageToFrameBuffer();
|
|
rdp.yuv_image = FALSE;
|
|
// FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
|
|
// rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
|
|
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
|
|
rdp.yuv_im_begin = 0x00FFFFFF;
|
|
}
|
|
if (rdp.cur_image)
|
|
CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
|
|
|
|
if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
|
|
{
|
|
newSwapBuffers ();
|
|
CI_SET = FALSE;
|
|
}
|
|
RDP("ProcessDList end\n");
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
// undef - undefined instruction, always ignore
|
|
static void undef()
|
|
{
|
|
FRDP_E("** undefined ** (%08lx)\n", rdp.cmd0);
|
|
FRDP("** undefined ** (%08lx) - IGNORED\n", rdp.cmd0);
|
|
#ifdef _FINAL_RELEASE_
|
|
*gfx.MI_INTR_REG |= 0x20;
|
|
gfx.CheckInterrupts();
|
|
rdp.halt = 1;
|
|
#endif
|
|
}
|
|
|
|
// spnoop - no operation, always ignore
|
|
static void spnoop()
|
|
{
|
|
RDP("spnoop\n");
|
|
}
|
|
|
|
// noop - no operation, always ignore
|
|
static void rdp_noop()
|
|
{
|
|
RDP("noop\n");
|
|
}
|
|
|
|
static void ys_memrect ()
|
|
{
|
|
DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
|
|
|
|
DWORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
|
|
DWORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
|
|
DWORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
|
|
DWORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
|
|
|
|
rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
|
|
|
|
if (lr_y > rdp.scissor_o.lr_y) lr_y = rdp.scissor_o.lr_y;
|
|
|
|
FRDP ("memrect (%d, %d, %d, %d), ci_width: %d\n", ul_x, ul_y, lr_x, lr_y, rdp.ci_width);
|
|
|
|
DWORD y, width = lr_x - ul_x;
|
|
DWORD texaddr = rdp.addr[rdp.tiles[tile].t_mem];
|
|
DWORD tex_width = rdp.tiles[tile].line << 3;
|
|
|
|
for (y = ul_y; y < lr_y; y++) {
|
|
BYTE *src = gfx.RDRAM + texaddr + (y - ul_y) * tex_width;
|
|
BYTE *dst = gfx.RDRAM + rdp.cimg + ul_x + y * rdp.ci_width;
|
|
memcpy (dst, src, width);
|
|
}
|
|
}
|
|
|
|
static void pm_palette_mod ()
|
|
{
|
|
BYTE envr = (BYTE)((float)((rdp.env_color >> 24)&0xFF)/255.0f*31.0f);
|
|
BYTE envg = (BYTE)((float)((rdp.env_color >> 16)&0xFF)/255.0f*31.0f);
|
|
BYTE envb = (BYTE)((float)((rdp.env_color >> 8)&0xFF)/255.0f*31.0f);
|
|
WORD env16 = (WORD)((envr<<11)|(envg<<6)|(envb<<1)|1);
|
|
BYTE prmr = (BYTE)((float)((rdp.prim_color >> 24)&0xFF)/255.0f*31.0f);
|
|
BYTE prmg = (BYTE)((float)((rdp.prim_color >> 16)&0xFF)/255.0f*31.0f);
|
|
BYTE prmb = (BYTE)((float)((rdp.prim_color >> 8)&0xFF)/255.0f*31.0f);
|
|
WORD prim16 = (WORD)((prmr<<11)|(prmg<<6)|(prmb<<1)|1);
|
|
WORD * dst = (WORD*)(gfx.RDRAM+rdp.cimg);
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
dst[i^1] = (rdp.pal_8[i]&1) ? prim16 : env16;
|
|
}
|
|
RDP("Texrect palette modification\n");
|
|
}
|
|
|
|
static void rdp_texrect()
|
|
{
|
|
DWORD a = rdp.pc[rdp.pc_i];
|
|
rdp.cmd2 = ((DWORD*)gfx.RDRAM)[(a>>2)+1];
|
|
rdp.cmd3 = ((DWORD*)gfx.RDRAM)[(a>>2)+3];
|
|
|
|
if (settings.ASB) //modified Rice's hack for All-Star Baseball games
|
|
{
|
|
DWORD dwHalf1 = (((DWORD*)gfx.RDRAM)[(a>>2)+0]) >> 24;
|
|
if ((dwHalf1 != 0xF1) && (dwHalf1 != 0xb3))
|
|
{
|
|
rdp.pc[rdp.pc_i] += 16;
|
|
}
|
|
else
|
|
{
|
|
rdp.pc[rdp.pc_i] += 8;
|
|
rdp.cmd3 = rdp.cmd2;
|
|
rdp.cmd2 = 0;
|
|
}
|
|
}
|
|
else if (settings.yoshi && settings.ucode == 6)
|
|
{
|
|
ys_memrect();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
rdp.pc[rdp.pc_i] += 16; // texrect is 196-bit
|
|
}
|
|
|
|
if (rdp.skip_drawing || (!settings.fb_smart && (rdp.cimg == rdp.zimg)))
|
|
{
|
|
if (settings.PM && rdp.ci_status == ci_useless)
|
|
{
|
|
pm_palette_mod ();
|
|
}
|
|
else
|
|
{
|
|
RDP("Texrect skipped\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((settings.ucode == 8) && 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);
|
|
RDP("Shadow texrect is skipped.\n");
|
|
rdp.tri_n += 2;
|
|
return;
|
|
}
|
|
|
|
WORD ul_x = (WORD)((rdp.cmd1 & 0x00FFF000) >> 14);
|
|
WORD ul_y = (WORD)((rdp.cmd1 & 0x00000FFF) >> 2);
|
|
WORD lr_x = (WORD)((rdp.cmd0 & 0x00FFF000) >> 14);
|
|
WORD lr_y = (WORD)((rdp.cmd0 & 0x00000FFF) >> 2);
|
|
if (ul_x >= lr_x) return;
|
|
if (rdp.cycle_mode > 1 || settings.increase_texrect_edge)
|
|
{
|
|
lr_x++;
|
|
lr_y++;
|
|
}
|
|
if (ul_y == lr_y)
|
|
{
|
|
lr_y ++;
|
|
}
|
|
|
|
//*
|
|
if (rdp.hires_tex && settings.fb_optimize_texrect)
|
|
{
|
|
if (!rdp.hires_tex->drawn)
|
|
{
|
|
DRAWIMAGE d;
|
|
d.imageX = 0;
|
|
d.imageW = (WORD)rdp.hires_tex->width;
|
|
d.frameX = ul_x;
|
|
d.frameW = (WORD)(rdp.hires_tex->width);//(WORD)(ul_x + rdp.hires_tex->width);//lr_x;
|
|
|
|
d.imageY = 0;
|
|
d.imageH = (WORD)rdp.hires_tex->height;
|
|
d.frameY = ul_y;
|
|
d.frameH = (WORD)(rdp.hires_tex->height);//(ul_y + rdp.hires_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.hires_tex->width, rdp.hires_tex->height);
|
|
d.scaleX = 1.0f;
|
|
d.scaleY = 1.0f;
|
|
DrawHiresImage(&d, rdp.hires_tex->width == rdp.ci_width);
|
|
rdp.hires_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.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 (!settings.fb_hires && ((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 == 7) && (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 (settings.fb_smart)
|
|
if (rdp.frame_buffers[rdp.ci_count-1].status == ci_copy_self || !settings.fb_motionblur)
|
|
{
|
|
// 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);
|
|
RDP("Wrong Texrect.\n");
|
|
rdp.tri_n += 2;
|
|
return;
|
|
}
|
|
}
|
|
//*/
|
|
|
|
int i;
|
|
|
|
DWORD tile = (WORD)((rdp.cmd1 & 0x07000000) >> 24);
|
|
|
|
// update MUST be at the beginning, b/c of update_scissor
|
|
if (rdp.cycle_mode == 2)
|
|
{
|
|
rdp.tex = 1;
|
|
rdp.allow_combine = 0;
|
|
|
|
cmb.tmu1_func = cmb.tmu0_func = GR_COMBINE_FUNCTION_LOCAL;
|
|
cmb.tmu1_fac = cmb.tmu0_fac = GR_COMBINE_FACTOR_NONE;
|
|
cmb.tmu1_a_func = cmb.tmu0_a_func = GR_COMBINE_FUNCTION_LOCAL;
|
|
cmb.tmu1_a_fac = cmb.tmu0_a_fac = GR_COMBINE_FACTOR_NONE;
|
|
cmb.tmu1_invert = cmb.tmu0_invert = FXFALSE;
|
|
cmb.tmu1_a_invert = cmb.tmu0_a_invert = FXFALSE;
|
|
}
|
|
|
|
rdp.texrecting = 1;
|
|
|
|
DWORD prev_tile = rdp.cur_tile;
|
|
rdp.cur_tile = tile;
|
|
rdp.update |= UPDATE_COMBINE;
|
|
update ();
|
|
|
|
rdp.texrecting = 0;
|
|
rdp.allow_combine = 1;
|
|
|
|
if (!rdp.cur_cache[0])
|
|
{
|
|
rdp.cur_tile = prev_tile;
|
|
rdp.tri_n += 2;
|
|
return;
|
|
}
|
|
// ****
|
|
// ** Texrect offset by Gugaman **
|
|
float off_x = (float)((short)((rdp.cmd2 & 0xFFFF0000) >> 16)) / 32.0f;
|
|
if ((int(off_x) == 512) && (rdp.timg.width < 512)) off_x = 0.0f;
|
|
float off_y = (float)((short)(rdp.cmd2 & 0x0000FFFF)) / 32.0f;
|
|
float dsdx = (float)((short)((rdp.cmd3 & 0xFFFF0000) >> 16)) / 1024.0f;
|
|
float dtdy = (float)((short)(rdp.cmd3 & 0x0000FFFF)) / 1024.0f;
|
|
|
|
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 (%d, %d, %d, %d), 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, off_y, dsdx, dtdy);
|
|
|
|
float off_size_x;
|
|
float off_size_y;
|
|
|
|
if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
|
|
{
|
|
off_size_x = (float)((lr_y - ul_y - 1) * dsdx);
|
|
off_size_y = (float)((lr_x - ul_x - 1) * dtdy);
|
|
}
|
|
else
|
|
{
|
|
off_size_x = (float)((lr_x - ul_x - 1) * dsdx);
|
|
off_size_y = (float)((lr_y - ul_y - 1) * dtdy);
|
|
}
|
|
|
|
float lr_u0, lr_v0, ul_u0, ul_v0, lr_u1, lr_v1, ul_u1, ul_v1;
|
|
|
|
if (rdp.cur_cache[0] && (rdp.tex & 1))
|
|
{
|
|
float sx=1, sy=1;
|
|
if (rdp.tiles[rdp.cur_tile].shift_s)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile].shift_s > 10)
|
|
sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_s));
|
|
else
|
|
sx = (float)1.0f/(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)
|
|
sy = (float)(1 << (16 - rdp.tiles[rdp.cur_tile].shift_t));
|
|
else
|
|
sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile].shift_t);
|
|
}
|
|
if (rdp.hires_tex && rdp.hires_tex->tile == 0)
|
|
{
|
|
off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
|
|
off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
|
|
FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y);
|
|
ul_u0 = off_x * sx;
|
|
ul_v0 = off_y * sy;
|
|
|
|
lr_u0 = ul_u0 + off_size_x * sx;
|
|
lr_v0 = ul_v0 + off_size_y * sy;
|
|
|
|
ul_u0 *= rdp.hires_tex->u_scale;
|
|
ul_v0 *= rdp.hires_tex->v_scale;
|
|
lr_u0 *= rdp.hires_tex->u_scale;
|
|
lr_v0 *= rdp.hires_tex->v_scale;
|
|
FRDP("hires_tex ul_u0: %f, ul_v0: %f, lr_u0: %f, lr_v0: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
|
|
}
|
|
else
|
|
{
|
|
ul_u0 = off_x * sx;
|
|
ul_v0 = off_y * sy;
|
|
|
|
ul_u0 -= rdp.tiles[rdp.cur_tile].f_ul_s;
|
|
ul_v0 -= rdp.tiles[rdp.cur_tile].f_ul_t;
|
|
|
|
lr_u0 = ul_u0 + off_size_x * sx;
|
|
lr_v0 = ul_v0 + off_size_y * sy;
|
|
|
|
ul_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * ul_u0;
|
|
lr_u0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_x * lr_u0;
|
|
ul_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * ul_v0;
|
|
lr_v0 = rdp.cur_cache[0]->c_off + rdp.cur_cache[0]->c_scl_y * lr_v0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ul_u0 = ul_v0 = lr_u0 = lr_v0 = 0;
|
|
}
|
|
if (rdp.cur_cache[1] && (rdp.tex & 2))
|
|
{
|
|
float sx=1, sy=1;
|
|
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_s)
|
|
{
|
|
if (rdp.tiles[rdp.cur_tile+1].shift_s > 10)
|
|
sx = (float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_s));
|
|
else
|
|
sx = (float)1.0f/(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)
|
|
sy = 1;//(float)(1 << (16 - rdp.tiles[rdp.cur_tile+1].shift_t));
|
|
else
|
|
sy = (float)1.0f/(1 << rdp.tiles[rdp.cur_tile+1].shift_t);
|
|
}
|
|
|
|
if (rdp.hires_tex && rdp.hires_tex->tile == 1)
|
|
{
|
|
off_x += rdp.hires_tex->u_shift;// + rdp.tiles[0].ul_s; //commented for Paper Mario motion blur
|
|
off_y += rdp.hires_tex->v_shift;// + rdp.tiles[0].ul_t;
|
|
FRDP("hires_tex ul_s: %d, ul_t: %d, off_x: %f, off_y: %f\n", rdp.tiles[0].ul_s, rdp.tiles[0].ul_t, off_x, off_y);
|
|
ul_u1 = off_x * sx;
|
|
ul_v1 = off_y * sy;
|
|
|
|
lr_u1 = ul_u1 + off_size_x * sx;
|
|
lr_v1 = ul_v1 + off_size_y * sy;
|
|
|
|
ul_u1 *= rdp.hires_tex->u_scale;
|
|
ul_v1 *= rdp.hires_tex->v_scale;
|
|
lr_u1 *= rdp.hires_tex->u_scale;
|
|
lr_v1 *= rdp.hires_tex->v_scale;
|
|
FRDP("hires_tex ul_u1: %f, ul_v1: %f, lr_u1: %f, lr_v1: %f\n", ul_u0, ul_v0, lr_u0, lr_v0);
|
|
|
|
}
|
|
else
|
|
{
|
|
ul_u1 = off_x * sx;
|
|
ul_v1 = off_y * sy;
|
|
|
|
ul_u1 -= rdp.tiles[rdp.cur_tile+1].f_ul_s;
|
|
ul_v1 -= rdp.tiles[rdp.cur_tile+1].f_ul_t;
|
|
|
|
lr_u1 = ul_u1 + off_size_x * sx;
|
|
lr_v1 = ul_v1 + off_size_y * sy;
|
|
|
|
ul_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * ul_u1;
|
|
lr_u1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_x * lr_u1;
|
|
ul_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * ul_v1;
|
|
lr_v1 = rdp.cur_cache[1]->c_off + rdp.cur_cache[1]->c_scl_y * lr_v1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ul_u1 = ul_v1 = lr_u1 = lr_v1 = 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, ul_u0, lr_u0, ul_u1, lr_u1, (float)rdp.scissor.ul_x, (float)rdp.scissor.lr_x);
|
|
CCLIP2 (s_ul_y, s_lr_y, ul_v0, lr_v0, ul_v1, lr_v1, (float)rdp.scissor.ul_y, (float)rdp.scissor.lr_y);
|
|
// CCLIP2 (s_lr_y, s_ul_y, lr_v0, ul_v0, lr_v1, ul_v1, (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);
|
|
|
|
// DO NOT SET CLAMP MODE HERE
|
|
|
|
float Z = 1.0f;
|
|
if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030)) // othermode check makes sure it
|
|
// USES the z-buffer. Otherwise it returns bad (unset) values for lot and telescope
|
|
//in zelda:mm.
|
|
{
|
|
FRDP ("prim_depth = %d\n", rdp.prim_depth);
|
|
Z = rdp.prim_depth;
|
|
if (settings.increase_primdepth)
|
|
Z += 8.0f;
|
|
Z = ScaleZ(Z);
|
|
|
|
grDepthBufferFunction (GR_CMP_LEQUAL);
|
|
rdp.update |= UPDATE_ZBUF_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
RDP ("no prim_depth used, using 1.0\n");
|
|
}
|
|
|
|
VERTEX vstd[4] = {
|
|
{ s_ul_x, s_ul_y, Z, 1.0f, ul_u0, ul_v0, ul_u1, ul_v1, { 0, 0, 0, 0}, 255 },
|
|
{ s_lr_x, s_ul_y, Z, 1.0f, lr_u0, ul_v0, lr_u1, ul_v1, { 0, 0, 0, 0}, 255 },
|
|
{ s_ul_x, s_lr_y, Z, 1.0f, ul_u0, lr_v0, ul_u1, lr_v1, { 0, 0, 0, 0}, 255 },
|
|
{ s_lr_x, s_lr_y, Z, 1.0f, lr_u0, lr_v0, lr_u1, lr_v1, { 0, 0, 0, 0}, 255 } };
|
|
|
|
if ( ((rdp.cmd0>>24)&0xFF) == 0xE5 ) //texrectflip
|
|
{
|
|
vstd[1].u0 = ul_u0;
|
|
vstd[1].v0 = lr_v0;
|
|
vstd[1].u1 = ul_u1;
|
|
vstd[1].v1 = lr_v1;
|
|
|
|
vstd[2].u0 = lr_u0;
|
|
vstd[2].v0 = ul_v0;
|
|
vstd[2].u1 = lr_u1;
|
|
vstd[2].v1 = ul_v1;
|
|
}
|
|
|
|
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.hires_tex && 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;
|
|
|
|
if (settings.ucode == 7)
|
|
{
|
|
start_u_256 = 0;
|
|
end_u_256 = (lr_x - ul_x - 1)>>8;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
vnew = new VERTEX [num_verts_line << 1];
|
|
|
|
n_vertices = num_verts_line << 1;
|
|
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] = vnew[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] = vnew[1];
|
|
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;
|
|
}
|
|
}
|
|
|
|
AllowShadeMods (vptr, n_vertices);
|
|
for (i=0; i<n_vertices; i++)
|
|
{
|
|
VERTEX *z = &vptr[i];
|
|
|
|
z->u0 *= z->q;
|
|
z->v0 *= z->q;
|
|
z->u1 *= z->q;
|
|
z->v1 *= z->q;
|
|
|
|
apply_shade_mods (z);
|
|
}
|
|
|
|
if (fullscreen)
|
|
{
|
|
grFogMode (GR_FOG_DISABLE);
|
|
|
|
grClipWindow (0, 0, settings.res_x, settings.res_y);
|
|
|
|
grCullMode (GR_CULL_DISABLE);
|
|
|
|
if (rdp.cycle_mode == 2)
|
|
{
|
|
grColorCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE);
|
|
grAlphaCombine (GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE);
|
|
grAlphaBlendFunction (GR_BLEND_ONE,
|
|
GR_BLEND_ZERO,
|
|
GR_BLEND_ZERO,
|
|
GR_BLEND_ZERO);
|
|
if (rdp.othermode_l & 1)
|
|
{
|
|
grAlphaTestFunction (GR_CMP_GEQUAL);
|
|
grAlphaTestReferenceValue (0x80);
|
|
}
|
|
else
|
|
grAlphaTestFunction (GR_CMP_ALWAYS);
|
|
|
|
rdp.update |= UPDATE_ALPHA_COMPARE | UPDATE_COMBINE;
|
|
}
|
|
|
|
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 (debug.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;
|
|
|
|
if (settings.fog && (rdp.flags & FOG_ENABLED))
|
|
{
|
|
grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
|
|
}
|
|
rdp.update |= UPDATE_CULL_MODE | UPDATE_VIEWPORT;
|
|
}
|
|
else
|
|
{
|
|
rdp.tri_n += 2;
|
|
}
|
|
|
|
delete[] vnew;
|
|
}
|
|
|
|
static void rdp_loadsync()
|
|
{
|
|
RDP("loadsync - ignored\n");
|
|
}
|
|
|
|
static void rdp_pipesync()
|
|
{
|
|
RDP("pipesync - ignored\n");
|
|
}
|
|
|
|
static void rdp_tilesync()
|
|
{
|
|
RDP("tilesync - ignored\n");
|
|
}
|
|
|
|
static void rdp_fullsync()
|
|
{
|
|
// Set an interrupt to allow the game to continue
|
|
*gfx.MI_INTR_REG |= 0x20;
|
|
gfx.CheckInterrupts();
|
|
RDP("fullsync\n");
|
|
}
|
|
|
|
static void rdp_setkeygb()
|
|
{
|
|
RDP_E("setkeygb - IGNORED\n");
|
|
RDP("setkeygb - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_setkeyr()
|
|
{
|
|
RDP_E("setkeyr - IGNORED\n");
|
|
RDP("setkeyr - IGNORED\n");
|
|
}
|
|
|
|
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.K5 = (BYTE)(rdp.cmd1&0x1FF);
|
|
RDP_E("setconvert - IGNORED\n");
|
|
RDP("setconvert - IGNORED\n");
|
|
}
|
|
|
|
//
|
|
// 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(*/(DWORD)(((rdp.cmd0 & 0x00FFF000) >> 14))/*, 320)*/;
|
|
rdp.scissor_o.ul_y = /*min(*/(DWORD)(((rdp.cmd0 & 0x00000FFF) >> 2))/*, 240)*/;
|
|
rdp.scissor_o.lr_x = /*min(*/(DWORD)(((rdp.cmd1 & 0x00FFF000) >> 14))/*, 320)*/;
|
|
rdp.scissor_o.lr_y = /*min(*/(DWORD)(((rdp.cmd1 & 0x00000FFF) >> 2))/*, 240)*/;
|
|
|
|
rdp.ci_upper_bound = rdp.scissor_o.ul_y;
|
|
rdp.ci_lower_bound = rdp.scissor_o.lr_y;
|
|
|
|
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;
|
|
}
|
|
|
|
static void rdp_setprimdepth()
|
|
{
|
|
rdp.prim_depth = (WORD)((rdp.cmd1 >> 16) & 0x7FFF);
|
|
|
|
FRDP("setprimdepth: %d\n", rdp.prim_depth);
|
|
}
|
|
|
|
static void rdp_setothermode()
|
|
{
|
|
#define F3DEX2_SETOTHERMODE(cmd,sft,len,data) { \
|
|
rdp.cmd0 = (cmd<<24) | ((32-(sft)-(len))<<8) | (((len)-1)); \
|
|
rdp.cmd1 = data; \
|
|
gfx_instruction[settings.ucode][cmd] (); \
|
|
}
|
|
#define SETOTHERMODE(cmd,sft,len,data) { \
|
|
rdp.cmd0 = (cmd<<24) | ((sft)<<8) | (len); \
|
|
rdp.cmd1 = data; \
|
|
gfx_instruction[settings.ucode][cmd] (); \
|
|
}
|
|
|
|
RDP("rdp_setothermode\n");
|
|
|
|
if ((settings.ucode == 2) || (settings.ucode == 8))
|
|
{
|
|
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 (DWORD addr, WORD start, WORD count)
|
|
{
|
|
RDP ("Loading palette... ");
|
|
WORD *dpal = rdp.pal_8 + start;
|
|
WORD end = start+count;
|
|
// WORD *spal = (WORD*)(gfx.RDRAM + (addr & BMASK));
|
|
|
|
for (WORD i=start; i<end; i++)
|
|
{
|
|
*(dpal++) = *(WORD *)(gfx.RDRAM + (addr^2));
|
|
addr += 2;
|
|
|
|
#ifdef TLUT_LOGGING
|
|
FRDP ("%d: %08lx\n", i, *(WORD *)(gfx.RDRAM + (addr^2)));
|
|
#endif
|
|
}
|
|
start >>= 4;
|
|
end = start + (count >> 4);
|
|
for (WORD p = start; p < end; p++)
|
|
{
|
|
rdp.pal_8_crc[p] = CRC_Calculate( 0xFFFFFFFF, &rdp.pal_8[(p << 4)], 32 );
|
|
}
|
|
rdp.pal_256_crc = CRC_Calculate( 0xFFFFFFFF, rdp.pal_8_crc, 64 );
|
|
RDP ("Done.\n");
|
|
}
|
|
|
|
static void rdp_loadtlut()
|
|
{
|
|
DWORD tile = (rdp.cmd1 >> 24) & 0x07;
|
|
WORD start = rdp.tiles[tile].t_mem - 256; // starting location in the palettes
|
|
// WORD start = ((WORD)(rdp.cmd1 >> 2) & 0x3FF) + 1;
|
|
WORD count = ((WORD)(rdp.cmd1 >> 14) & 0x3FF) + 1; // number to copy
|
|
|
|
if (rdp.timg.addr + (count<<1) > BMASK)
|
|
count = (WORD)((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;
|
|
}
|
|
|
|
BOOL tile_set = 0;
|
|
static void rdp_settilesize()
|
|
{
|
|
DWORD 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 = (((WORD)(rdp.cmd0 >> 14)) & 0x03ff);
|
|
int ul_t = (((WORD)(rdp.cmd0 >> 2 )) & 0x03ff);
|
|
int lr_s = (((WORD)(rdp.cmd1 >> 14)) & 0x03ff);
|
|
int lr_t = (((WORD)(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;
|
|
|
|
if (tile == 0 && rdp.hires_tex)
|
|
//if ((rdp.tiles[tile].size != 2) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
|
|
if (((rdp.tiles[tile].format == 0) && (rdp.tiles[tile].size != 2)) || ((rdp.timg.width == 1) && (rdp.hires_tex->width != (DWORD)(lr_s+1))))
|
|
rdp.hires_tex = 0;
|
|
if (rdp.hires_tex)
|
|
{
|
|
if (rdp.tiles[tile].format == 0 && rdp.hires_tex->format == 0)
|
|
{
|
|
if (tile == 1 && (DWORD)rdp.hires_tex->tmu != tile)
|
|
SwapTextureBuffer();
|
|
rdp.hires_tex->tile = tile;
|
|
rdp.hires_tex->info.format = GR_TEXFMT_RGB_565;
|
|
FRDP ("hires_tex: tile: %d\n", tile);
|
|
}
|
|
else if (tile == 0)
|
|
{
|
|
rdp.hires_tex->info.format = GR_TEXFMT_ALPHA_INTENSITY_88;
|
|
}
|
|
}
|
|
FRDP ("settilesize: tile: %d, ul_s: %d, ul_t: %d, lr_s: %d, lr_t: %d\n",
|
|
tile, ul_s, ul_t, lr_s, lr_t);
|
|
}
|
|
|
|
static void CopyswapBlock(int *pDst, unsigned int cnt, unsigned int SrcOffs)
|
|
{
|
|
// copy and byteswap a block of 8-byte dwords
|
|
int rem = SrcOffs & 3;
|
|
if (rem == 0)
|
|
{
|
|
int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + SrcOffs);
|
|
for (unsigned int x = 0; x < cnt; x++)
|
|
{
|
|
int s1 = bswap32(*pSrc++);
|
|
int s2 = bswap32(*pSrc++);
|
|
*pDst++ = s1;
|
|
*pDst++ = s2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// set source pointer to 4-byte aligned RDRAM location before the start
|
|
int *pSrc = (int *) ((uintptr_t) gfx.RDRAM + (SrcOffs & 0xfffffffc));
|
|
// do the first partial 32-bit word
|
|
int s0 = bswap32(*pSrc++);
|
|
for (int x = 0; x < rem; x++)
|
|
s0 >>= 8;
|
|
for (int x = 4; x > rem; x--)
|
|
{
|
|
*((char *) pDst) = s0 & 0xff;
|
|
pDst = (int *) ((char *) pDst + 1);
|
|
s0 >>= 8;
|
|
}
|
|
// do one full 32-bit word
|
|
s0 = bswap32(*pSrc++);
|
|
*pDst++ = s0;
|
|
// do 'cnt-1' 64-bit dwords
|
|
for (unsigned int x = 0; x < cnt-1; x++)
|
|
{
|
|
int s1 = bswap32(*pSrc++);
|
|
int s2 = bswap32(*pSrc++);
|
|
*pDst++ = s1;
|
|
*pDst++ = s2;
|
|
}
|
|
// do last partial 32-bit word
|
|
s0 = bswap32(*pSrc++);
|
|
for (; rem > 0; rem--)
|
|
{
|
|
*((char *) pDst) = s0 & 0xff;
|
|
pDst = (int *) ((char *) pDst + 1);
|
|
s0 >>= 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void WordswapBlock(int *pDst, unsigned int cnt, unsigned int TileSize)
|
|
{
|
|
// Since it's not loading 32-bit textures as the N64 would, 32-bit textures need to
|
|
// be swapped by 64-bits, not 32.
|
|
if (TileSize == 3)
|
|
{
|
|
// swapblock64 dst, cnt
|
|
for (unsigned int x = 0; x < cnt / 2; x++, pDst += 4)
|
|
{
|
|
long long s1 = ((long long *) pDst)[0];
|
|
long long s2 = ((long long *) pDst)[1];
|
|
((long long *) pDst)[0] = s2;
|
|
((long long *) pDst)[1] = s1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// swapblock32 dst, cnt
|
|
for (unsigned int x = 0; x < cnt; x++, pDst += 2)
|
|
{
|
|
int s1 = pDst[0];
|
|
int s2 = pDst[1];
|
|
pDst[0] = s2;
|
|
pDst[1] = s1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void rdp_loadblock()
|
|
{
|
|
if (rdp.skip_drawing)
|
|
{
|
|
RDP("loadblock skipped\n");
|
|
return;
|
|
}
|
|
DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
|
|
DWORD dxt = (DWORD)(rdp.cmd1 & 0x0FFF);
|
|
|
|
rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
|
|
|
|
// ** DXT is used for swapping every other line
|
|
/* double fdxt = (double)0x8000000F/(double)((DWORD)(2047/(dxt-1))); // F for error
|
|
DWORD _dxt = (DWORD)fdxt;*/
|
|
|
|
// 0x00000800 -> 0x80000000 (so we can check the sign bit instead of the 11th bit)
|
|
DWORD _dxt = dxt << 20;
|
|
|
|
DWORD addr = segoffset(rdp.timg.addr) & BMASK;
|
|
|
|
// lr_s specifies number of 64-bit words to copy
|
|
// 10.2 format
|
|
WORD ul_s = (WORD)(rdp.cmd0 >> 14) & 0x3FF;
|
|
WORD ul_t = (WORD)(rdp.cmd0 >> 2) & 0x3FF;
|
|
WORD lr_s = (WORD)(rdp.cmd1 >> 14) & 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
|
|
|
|
// 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 = (WORD)((BMASK-addr)>>3);
|
|
|
|
DWORD offs = rdp.timg.addr;
|
|
DWORD cnt = lr_s+1;
|
|
if (rdp.tiles[tile].size == 3)
|
|
cnt <<= 1;
|
|
//FIXME: unused? DWORD start_line = 0;
|
|
|
|
// if (lr_s > 0)
|
|
rdp.timg.addr += cnt << 3;
|
|
|
|
int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
|
|
|
|
// Load the block from RDRAM and byteswap it as it loads
|
|
CopyswapBlock(pDst, cnt, offs);
|
|
|
|
// now do 32-bit or 64-bit word swapping on every other row of data
|
|
int dxt_accum = 0;
|
|
while (cnt > 0)
|
|
{
|
|
// skip over unswapped blocks
|
|
do
|
|
{
|
|
pDst += 2;
|
|
if (--cnt == 0)
|
|
break;
|
|
dxt_accum += _dxt;
|
|
} while (!(dxt_accum & 0x80000000));
|
|
// count number of blocks to swap
|
|
if (cnt == 0) break;
|
|
int swapcnt = 0;
|
|
do
|
|
{
|
|
swapcnt++;
|
|
if (--cnt == 0)
|
|
break;
|
|
dxt_accum += _dxt;
|
|
} while (dxt_accum & 0x80000000);
|
|
// do 32-bit or 64-bit swap operation on this block
|
|
WordswapBlock(pDst, swapcnt, rdp.tiles[tile].size);
|
|
pDst += swapcnt * 2;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static void rdp_loadtile()
|
|
{
|
|
if (rdp.skip_drawing)
|
|
return;
|
|
rdp.timg.set_by = 1; // load tile
|
|
|
|
DWORD tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
|
|
if (rdp.tiles[tile].format == 1)
|
|
{
|
|
rdp.yuv_image = TRUE;
|
|
if (rdp.timg.addr < rdp.yuv_im_begin) rdp.yuv_im_begin = rdp.timg.addr;
|
|
return;
|
|
}
|
|
|
|
rdp.addr[rdp.tiles[tile].t_mem] = rdp.timg.addr;
|
|
|
|
WORD ul_s = (WORD)((rdp.cmd0 >> 14) & 0x03FF);
|
|
WORD ul_t = (WORD)((rdp.cmd0 >> 2 ) & 0x03FF);
|
|
WORD lr_s = (WORD)((rdp.cmd1 >> 14) & 0x03FF);
|
|
WORD lr_t = (WORD)((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;
|
|
// wrong_tile = -1;
|
|
}
|
|
|
|
if (rdp.hires_tex)// && (rdp.tiles[tile].format == 0))
|
|
{
|
|
FRDP("loadtile: hires_tex ul_s: %d, ul_t:%d\n", ul_s, ul_t);
|
|
rdp.hires_tex->tile_uls = ul_s;
|
|
rdp.hires_tex->tile_ult = ul_t;
|
|
}
|
|
|
|
if (settings.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;
|
|
}
|
|
|
|
DWORD height = lr_t - ul_t + 1; // get height
|
|
DWORD width = lr_s - ul_s + 1;
|
|
|
|
DWORD wid_64 = rdp.tiles[tile].line;
|
|
|
|
// CHEAT: it's very unlikely that it loads more than 1 32-bit texture in one command,
|
|
// so i don't bother to write in two different places at once. Just load once with
|
|
// twice as much data.
|
|
if (rdp.tiles[tile].size == 3)
|
|
wid_64 <<= 1;
|
|
|
|
int line_n = rdp.timg.width;
|
|
if (rdp.tiles[tile].size == 0)
|
|
line_n >>= 1;
|
|
else
|
|
line_n <<= (rdp.tiles[tile].size-1);
|
|
|
|
int offs = ul_t * line_n;
|
|
offs += ul_s << rdp.tiles[tile].size >> 1;
|
|
offs += rdp.timg.addr;
|
|
if ((unsigned int) offs >= BMASK)
|
|
return;
|
|
|
|
// check if points to bad location
|
|
DWORD size = width * height;
|
|
if (rdp.tiles[tile].size == 0)
|
|
size >>= 1;
|
|
else
|
|
size <<= (rdp.tiles[tile].size-1);
|
|
|
|
if (offs + line_n*height > BMASK)
|
|
height = (BMASK - offs) / line_n;
|
|
|
|
int * pDst = (int *) ((uintptr_t)rdp.tmem+(rdp.tiles[tile].t_mem<<3));
|
|
int * pEnd = (int *) ((uintptr_t)rdp.tmem+4096 - (wid_64<<3));
|
|
|
|
for (unsigned int y = 0; y < height; y++)
|
|
{
|
|
if (pDst > pEnd) break;
|
|
CopyswapBlock(pDst, wid_64, offs);
|
|
if (y & 1)
|
|
{
|
|
WordswapBlock(pDst, wid_64, rdp.tiles[tile].size);
|
|
}
|
|
pDst += wid_64 * 2;
|
|
offs += line_n;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static void rdp_settile()
|
|
{
|
|
tile_set = 1; // used to check if we only load the first settilesize
|
|
|
|
rdp.first = 0;
|
|
|
|
//rdp.cur_tile_n = (DWORD)((rdp.cmd1 >> 24) & 0x07);
|
|
//rdp.cur_tile = &rdp.tiles[rdp.cur_tile_n];
|
|
|
|
rdp.last_tile = (DWORD)((rdp.cmd1 >> 24) & 0x07);
|
|
TILE *tile = &rdp.tiles[rdp.last_tile];
|
|
|
|
tile->format = (BYTE)((rdp.cmd0 >> 21) & 0x07);
|
|
tile->size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
|
|
tile->line = (WORD)((rdp.cmd0 >> 9) & 0x01FF);
|
|
tile->t_mem = (WORD)(rdp.cmd0 & 0x1FF);
|
|
tile->palette = (BYTE)((rdp.cmd1 >> 20) & 0x0F);
|
|
tile->clamp_t = (BYTE)((rdp.cmd1 >> 19) & 0x01);
|
|
tile->mirror_t = (BYTE)((rdp.cmd1 >> 18) & 0x01);
|
|
tile->mask_t = (BYTE)((rdp.cmd1 >> 14) & 0x0F);
|
|
tile->shift_t = (BYTE)((rdp.cmd1 >> 10) & 0x0F);
|
|
tile->clamp_s = (BYTE)((rdp.cmd1 >> 9) & 0x01);
|
|
tile->mirror_s = (BYTE)((rdp.cmd1 >> 8) & 0x01);
|
|
tile->mask_s = (BYTE)((rdp.cmd1 >> 4) & 0x0F);
|
|
tile->shift_s = (BYTE)(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);
|
|
}
|
|
|
|
//
|
|
// fillrect - fills a rectangle
|
|
//
|
|
|
|
static void rdp_fillrect()
|
|
{
|
|
DWORD ul_x = ((rdp.cmd1 & 0x00FFF000) >> 14);
|
|
DWORD ul_y = (rdp.cmd1 & 0x00000FFF) >> 2;
|
|
DWORD lr_x = ((rdp.cmd0 & 0x00FFF000) >> 14) + 1;
|
|
DWORD lr_y = ((rdp.cmd0 & 0x00000FFF) >> 2) + 1;
|
|
if ((rdp.cimg == rdp.zimg) || (settings.fb_smart && rdp.frame_buffers[rdp.ci_count-1].status == ci_zimg))
|
|
{
|
|
RDP ("Fillrect - cleared the depth buffer\n");
|
|
if (fullscreen)
|
|
{
|
|
|
|
grDepthMask (FXTRUE);
|
|
grColorMask (FXFALSE, FXFALSE);
|
|
grBufferClear (0, 0, 0xFFFF);
|
|
grColorMask (FXTRUE, FXTRUE);
|
|
rdp.update |= UPDATE_ZBUF_ENABLED;
|
|
if (settings.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);
|
|
//FIXME:unused? DWORD zi_height = lr_y - ul_y - 1;
|
|
// rdp.zi_nb_pixels = rdp.zi_width * zi_height;
|
|
rdp.zi_lry = lr_y - 1;
|
|
rdp.zi_lrx = lr_x - 1;
|
|
// FRDP ("zi_width: %d, zi_height: %d\n", rdp.zi_width, zi_height);
|
|
DWORD fillrect_width_in_dwords = (lr_x-ul_x) >> 1;
|
|
DWORD zi_width_in_dwords = rdp.zi_width >> 1;
|
|
ul_x >>= 1;
|
|
DWORD * dst = (DWORD*)(gfx.RDRAM+rdp.cimg);
|
|
dst += ul_y * zi_width_in_dwords;
|
|
for (DWORD y = ul_y; y < lr_y; y++)
|
|
{
|
|
for (DWORD x = ul_x; x < fillrect_width_in_dwords; x++)
|
|
{
|
|
dst[x] = rdp.fill_color;
|
|
}
|
|
dst += zi_width_in_dwords;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (rdp.skip_drawing)
|
|
{
|
|
RDP("Fillrect skipped\n");
|
|
return;
|
|
}
|
|
|
|
// Update scissor
|
|
update_scissor ();
|
|
|
|
if ((ul_x > lr_x) || (ul_y > lr_y)) return;
|
|
if (settings.bomberman64 && (lr_x == rdp.ci_width) && (rdp.cimg == rdp.ocimg)) //bomberman64 hack
|
|
return;
|
|
|
|
if (rdp.cur_image && (rdp.cur_image->format != 0) && (rdp.cycle_mode == 3) && (rdp.cur_image->width == lr_x))
|
|
{
|
|
DWORD color = rdp.fill_color;
|
|
color = ((color&1)?0xFF:0) |
|
|
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
|
|
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
|
|
((DWORD)((float)((color&0x003E) >> 1) / 31.0f * 255.0f) << 8);
|
|
grDepthMask (FXFALSE);
|
|
grBufferClear (color, 0, 0xFFFF);
|
|
grDepthMask (FXTRUE);
|
|
rdp.update |= UPDATE_ZBUF_ENABLED;
|
|
return;
|
|
}
|
|
|
|
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
|
|
DWORD s_ul_x = (DWORD)min(max(ul_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
|
|
DWORD s_lr_x = (DWORD)min(max(lr_x * rdp.scale_x + rdp.offset_x + 0.01f, rdp.scissor.ul_x), rdp.scissor.lr_x);
|
|
DWORD s_ul_y = (DWORD)min(max(ul_y * rdp.scale_y + rdp.offset_y + 0.01f, rdp.scissor.ul_y), rdp.scissor.lr_y);
|
|
DWORD s_lr_y = (DWORD)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.0f) s_lr_x = 0;
|
|
if (s_lr_y < 0.0f) s_lr_y = 0;
|
|
if (s_ul_x > (float)settings.res_x) s_ul_x = settings.res_x;
|
|
if (s_ul_y > (float)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);
|
|
|
|
grClipWindow (0, 0, settings.res_x, settings.res_y);
|
|
|
|
float Z = 1.0f;
|
|
if (rdp.zsrc == 1 && (rdp.othermode_l & 0x00000030))
|
|
{
|
|
Z = ScaleZ(rdp.prim_depth);
|
|
grDepthBufferFunction (GR_CMP_LEQUAL);
|
|
// grDepthMask (FXTRUE);
|
|
FRDP ("prim_depth = %d\n", rdp.prim_depth);
|
|
}
|
|
else
|
|
{
|
|
grDepthBufferFunction (GR_CMP_ALWAYS);
|
|
grDepthMask (FXFALSE);
|
|
RDP ("no prim_depth used, using 1.0\n");
|
|
}
|
|
// 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)
|
|
{
|
|
DWORD color = (settings.fillcolor_fix) ? rdp.fill_color : (rdp.fill_color >> 16);
|
|
|
|
if (settings.PM && rdp.frame_buffers[rdp.ci_count-1].status == ci_aux)
|
|
{
|
|
//background of auxilary frame buffers must have zero alpha.
|
|
//make it black, set 0 alpha to plack pixels on frame buffer read
|
|
color = 0;
|
|
}
|
|
else
|
|
{
|
|
color = ((color&1)?0xFF:0) |
|
|
((DWORD)((float)((color&0xF800) >> 11) / 31.0f * 255.0f) << 24) |
|
|
((DWORD)((float)((color&0x07C0) >> 6) / 31.0f * 255.0f) << 16) |
|
|
((DWORD)((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);
|
|
|
|
rdp.update |= UPDATE_COMBINE;
|
|
}
|
|
else
|
|
{
|
|
Combine ();
|
|
TexCache (); // (to update combiner)
|
|
DWORD cmb_mode_c = (rdp.cycle1 << 16) | (rdp.cycle2 & 0xFFFF);
|
|
DWORD 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]);
|
|
}
|
|
}
|
|
|
|
grAlphaTestFunction (GR_CMP_ALWAYS);
|
|
if (grStippleModeExt)
|
|
grStippleModeExt(GR_STIPPLE_DISABLE);
|
|
|
|
grCullMode(GR_CULL_DISABLE);
|
|
|
|
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 (debug.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;
|
|
|
|
if (settings.fog && (rdp.flags & FOG_ENABLED))
|
|
{
|
|
grFogMode (GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
|
|
}
|
|
|
|
rdp.update |= UPDATE_CULL_MODE | UPDATE_ALPHA_COMPARE | UPDATE_ZBUF_ENABLED;
|
|
}
|
|
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 = (BYTE)((rdp.cmd0 >> 20) & 0xF);
|
|
rdp.c_b0 = (BYTE)((rdp.cmd1 >> 28) & 0xF);
|
|
rdp.c_c0 = (BYTE)((rdp.cmd0 >> 15) & 0x1F);
|
|
rdp.c_d0 = (BYTE)((rdp.cmd1 >> 15) & 0x7);
|
|
rdp.c_Aa0 = (BYTE)((rdp.cmd0 >> 12) & 0x7);
|
|
rdp.c_Ab0 = (BYTE)((rdp.cmd1 >> 12) & 0x7);
|
|
rdp.c_Ac0 = (BYTE)((rdp.cmd0 >> 9) & 0x7);
|
|
rdp.c_Ad0 = (BYTE)((rdp.cmd1 >> 9) & 0x7);
|
|
|
|
rdp.c_a1 = (BYTE)((rdp.cmd0 >> 5) & 0xF);
|
|
rdp.c_b1 = (BYTE)((rdp.cmd1 >> 24) & 0xF);
|
|
rdp.c_c1 = (BYTE)((rdp.cmd0 >> 0) & 0x1F);
|
|
rdp.c_d1 = (BYTE)((rdp.cmd1 >> 6) & 0x7);
|
|
rdp.c_Aa1 = (BYTE)((rdp.cmd1 >> 21) & 0x7);
|
|
rdp.c_Ab1 = (BYTE)((rdp.cmd1 >> 3) & 0x7);
|
|
rdp.c_Ac1 = (BYTE)((rdp.cmd1 >> 18) & 0x7);
|
|
rdp.c_Ad1 = (BYTE)((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 = (BYTE)((rdp.cmd0 >> 21) & 0x07);
|
|
rdp.timg.size = (BYTE)((rdp.cmd0 >> 19) & 0x03);
|
|
rdp.timg.width = (WORD)(1 + (rdp.cmd0 & 0x00000FFF));
|
|
rdp.timg.addr = segoffset(rdp.cmd1);
|
|
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 if (rdp.frame_buffers[rdp.ci_count].status != ci_copy)
|
|
CloseTextureBuffer(TRUE);
|
|
rdp.fb_drawn = TRUE;
|
|
}
|
|
}
|
|
|
|
if (settings.fb_hires) //search this texture among drawn texture buffers
|
|
{
|
|
if (settings.zelda)
|
|
{
|
|
if (rdp.timg.size == 2)
|
|
FindTextureBuffer(rdp.timg.addr, rdp.timg.width);
|
|
}
|
|
else
|
|
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);
|
|
}
|
|
|
|
|
|
BOOL 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 DWORD swapped_addr = 0;
|
|
|
|
static void rdp_setcolorimage()
|
|
{
|
|
render_depth_mode = 0;
|
|
if (settings.fb_smart && (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-1];
|
|
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 (!settings.fb_hires)
|
|
{
|
|
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.PM) //tidal wave
|
|
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
|
|
}
|
|
else if (!rdp.motionblur && settings.fb_hires && !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 (settings.fb_hires && rdp.read_whole_frame && prev_fb.status == ci_aux)
|
|
{
|
|
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.fb_motionblur)
|
|
{
|
|
if (cur_fb.width == rdp.ci_width)
|
|
{
|
|
if (CopyTextureBuffer(prev_fb, cur_fb))
|
|
// if (CloseTextureBuffer(TRUE))
|
|
;
|
|
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 (settings.fb_hires)
|
|
OpenTextureBuffer(cur_fb);
|
|
}
|
|
break;
|
|
case ci_old_copy:
|
|
{
|
|
if (!rdp.motionblur || settings.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 (!settings.fb_hires && cur_fb.format != 0)
|
|
rdp.skip_drawing = TRUE;
|
|
else
|
|
{
|
|
rdp.skip_drawing = FALSE;
|
|
if (settings.fb_hires && 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 (!settings.fb_hires && (prev_fb.status == ci_main) &&
|
|
(prev_fb.width == cur_fb.width)) // for Pokemon Stadium
|
|
CopyFrameBuffer ();
|
|
}
|
|
}
|
|
cur_fb.status = ci_aux;
|
|
}
|
|
break;
|
|
case ci_zimg:
|
|
// ZIGGY
|
|
// Zelda LoT effect save/restore depth buffer
|
|
if (cur_fb.addr == rdp.zimg) {
|
|
render_depth_mode = 1;
|
|
} else {
|
|
render_depth_mode = 2;
|
|
}
|
|
rdp.skip_drawing = TRUE;
|
|
break;
|
|
case ci_useless:
|
|
//case ci_zcopy:
|
|
rdp.skip_drawing = TRUE;
|
|
break;
|
|
case ci_copy_self:
|
|
if (settings.fb_hires && (rdp.ci_count <= rdp.copy_ci_index) && (!SwapOK || settings.swapmode == 2))
|
|
OpenTextureBuffer(cur_fb);
|
|
rdp.skip_drawing = FALSE;
|
|
/*
|
|
if (settings.fb_hires)
|
|
{
|
|
if (SwapOK)
|
|
{
|
|
rdp.cimg = rdp.frame_buffers[rdp.ci_count].addr;
|
|
rdp.maincimg[0].addr = rdp.cimg;
|
|
newSwapBuffers();
|
|
SwapOK = FALSE;
|
|
OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count]);
|
|
}
|
|
}
|
|
*/
|
|
break;
|
|
default:
|
|
rdp.skip_drawing = FALSE;
|
|
}
|
|
|
|
if ((rdp.ci_count > 0) && (prev_fb.status >= ci_aux)) //for Pokemon Stadium
|
|
{
|
|
if (!settings.fb_hires && prev_fb.format == 0)
|
|
CopyFrameBuffer ();
|
|
}
|
|
if (!settings.fb_hires && cur_fb.status == ci_copy)
|
|
{
|
|
if (!rdp.motionblur && (rdp.num_of_ci > rdp.ci_count+1) && (next_fb.status != ci_aux))
|
|
{
|
|
RestoreScale();
|
|
}
|
|
}
|
|
if (!settings.fb_hires && cur_fb.status == ci_aux)
|
|
{
|
|
if (cur_fb.format == 0)
|
|
{
|
|
if (settings.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;
|
|
WORD *ptr_dst = new WORD[width*height];
|
|
WORD *ptr_src = (WORD*)(gfx.RDRAM+cur_fb.addr);
|
|
WORD 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,
|
|
0,
|
|
0,
|
|
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))
|
|
{
|
|
BOOL 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)
|
|
{
|
|
RDP("return to original scale\n");
|
|
rdp.scale_x = rdp.scale_x_bak;
|
|
rdp.scale_y = rdp.scale_y_bak;
|
|
if (settings.fb_hires && !rdp.read_whole_frame)
|
|
CloseTextureBuffer();
|
|
}
|
|
if (settings.fb_hires && !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 (settings.fb_smart)
|
|
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;
|
|
}
|
|
DWORD 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 && !rdp.cur_image) //can't draw into non RGBA buffer
|
|
{
|
|
if (settings.fb_hires && rdp.ci_width <= 64)
|
|
OpenTextureBuffer(rdp.frame_buffers[rdp.ci_count - 1]);
|
|
else if (format > 2)
|
|
rdp.skip_drawing = TRUE;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!settings.fb_smart)
|
|
rdp.skip_drawing = FALSE;
|
|
}
|
|
|
|
CI_SET = TRUE;
|
|
if (settings.swapmode > 0)
|
|
{
|
|
if (rdp.zimg == rdp.cimg)
|
|
rdp.updatescreen = 1;
|
|
|
|
BOOL 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 (settings.fb_smart)
|
|
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 (settings.fb_hires)
|
|
{
|
|
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 rdp_trifill()
|
|
{
|
|
RDP_E("trifill - IGNORED\n");
|
|
RDP("trifill - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_trishade()
|
|
{
|
|
RDP_E("trishade - IGNORED\n");
|
|
RDP("trishade - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_tritxtr()
|
|
{
|
|
RDP_E("tritxtr - IGNORED\n");
|
|
RDP("tritxtr - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_trishadetxtr()
|
|
{
|
|
RDP_E("trishadetxtr - IGNORED\n");
|
|
RDP("trishadetxtr - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_trifillz()
|
|
{
|
|
RDP_E("trifillz - IGNORED\n");
|
|
RDP("trifillz - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_trishadez()
|
|
{
|
|
RDP_E("trishadez - IGNORED\n");
|
|
RDP("trishadez - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_tritxtrz()
|
|
{
|
|
RDP_E("tritxtrz - IGNORED\n");
|
|
RDP("tritxtrz - IGNORED\n");
|
|
}
|
|
|
|
static void rdp_trishadetxtrz()
|
|
{
|
|
RDP_E("trishadetxtrz - IGNORED\n");
|
|
RDP("trishadetxtrz - IGNORED\n");
|
|
}
|
|
|
|
static void rsp_reserved0()
|
|
{
|
|
RDP_E("reserved0 - IGNORED\n");
|
|
RDP("reserved0 - IGNORED\n");
|
|
}
|
|
|
|
static void rsp_reserved1()
|
|
{
|
|
RDP("reserved1 - ignored\n");
|
|
}
|
|
|
|
static void rsp_reserved2()
|
|
{
|
|
RDP("reserved2\n");
|
|
}
|
|
|
|
static void rsp_reserved3()
|
|
{
|
|
RDP("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);
|
|
|
|
//grDepthBufferFunction (GR_CMP_ALWAYS);
|
|
//grDepthMask (FXFALSE);
|
|
|
|
rdp.update |= UPDATE_COMBINE | UPDATE_ALPHA_COMPARE;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/******************************************************************
|
|
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 = BYTE, 2 = WORD, 4 = DWORD
|
|
output: none
|
|
*******************************************************************/
|
|
EXPORT void CALL FBRead(unsigned int 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;
|
|
DWORD 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))
|
|
{
|
|
DWORD cimg = rdp.cimg;
|
|
rdp.cimg = rdp.maincimg[1].addr;
|
|
if (settings.fb_smart)
|
|
{
|
|
rdp.ci_width = rdp.maincimg[1].width;
|
|
rdp.ci_count = 0;
|
|
DWORD h = rdp.frame_buffers[0].height;
|
|
rdp.frame_buffers[0].height = rdp.maincimg[1].height;
|
|
CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
|
|
rdp.frame_buffers[0].height = h;
|
|
}
|
|
else
|
|
{
|
|
CopyFrameBuffer(GR_BUFFER_FRONTBUFFER);
|
|
}
|
|
rdp.cimg = cimg;
|
|
rdp.fb_drawn_front = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
//TODO: remove
|
|
/******************************************************************
|
|
Function: FrameBufferWriteList
|
|
Purpose: This function is called to notify the dll that the
|
|
frame buffer has been modified by CPU at the given address.
|
|
input: FrameBufferModifyEntry *plist
|
|
size = size of the plist, max = 1024
|
|
output: none
|
|
*******************************************************************/
|
|
EXPORT void CALL FBWList(FrameBufferModifyEntry *plist, DWORD size)
|
|
{
|
|
LOG ("FBWList ()\n");
|
|
FRDP("FBWList. size: %d\n", size);
|
|
printf("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 = BYTE, 2 = WORD, 4 = DWORD
|
|
output: none
|
|
*******************************************************************/
|
|
EXPORT void CALL FBWrite(unsigned int addr, unsigned int 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;
|
|
DWORD a = segoffset(addr);
|
|
FRDP("FBWrite. addr: %08lx\n", a);
|
|
// ZIGGY : added a test on ci_width, otherwise we crash on zero division below
|
|
if (!rdp.ci_width || a < rdp.cimg || a > rdp.ci_end)
|
|
return;
|
|
cpu_fb_write = TRUE;
|
|
DWORD shift_l = (a-rdp.cimg) >> 1;
|
|
DWORD shift_r = shift_l+2;
|
|
|
|
d_ul_x = min(d_ul_x, shift_l%rdp.ci_width);
|
|
d_ul_y = min(d_ul_y, shift_l/rdp.ci_width);
|
|
d_lr_x = max(d_lr_x, shift_r%rdp.ci_width);
|
|
d_lr_y = max(d_lr_y, shift_r/rdp.ci_width);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
Function: FBGetFrameBufferInfo
|
|
Purpose: This function is called by the emulator core to retrieve frame
|
|
buffer information from the video plugin in order to be able
|
|
to notify the video plugin about CPU frame buffer read/write
|
|
operations
|
|
|
|
size:
|
|
= 1 byte
|
|
= 2 word (16 bit) <-- this is N64 default depth buffer format
|
|
= 4 dword (32 bit)
|
|
|
|
when frame buffer information is not available yet, set all values
|
|
in the FrameBufferInfo structure to 0
|
|
|
|
input: FrameBufferInfo pinfo[6]
|
|
pinfo is pointed to a FrameBufferInfo structure which to be
|
|
filled in by this function
|
|
output: Values are return in the FrameBufferInfo structure
|
|
Plugin can return up to 6 frame buffer info
|
|
************************************************************************/
|
|
///*
|
|
#if 0
|
|
//TODO: remove
|
|
typedef struct
|
|
{
|
|
DWORD addr;
|
|
DWORD size;
|
|
DWORD width;
|
|
DWORD height;
|
|
} FrameBufferInfo;
|
|
#endif
|
|
|
|
EXPORT void CALL FBGetFrameBufferInfo(void *p)
|
|
{
|
|
LOG ("FBGetFrameBufferInfo ()\n");
|
|
FrameBufferInfo * pinfo = (FrameBufferInfo *)p;
|
|
memset(pinfo,0,sizeof(FrameBufferInfo)*6);
|
|
if (!settings.fb_get_info)
|
|
return;
|
|
RDP("FBGetFrameBufferInfo ()\n");
|
|
//*
|
|
if (settings.fb_smart)
|
|
{
|
|
pinfo[0].addr = rdp.maincimg[1].addr;
|
|
pinfo[0].size = rdp.maincimg[1].size;
|
|
pinfo[0].width = rdp.maincimg[1].width;
|
|
pinfo[0].height = rdp.maincimg[1].height;
|
|
int info_index = 1;
|
|
for (int i = 0; i < rdp.num_of_ci && info_index < 6; i++)
|
|
{
|
|
COLOR_IMAGE & cur_fb = rdp.frame_buffers[i];
|
|
if (cur_fb.status == ci_main || cur_fb.status == ci_copy_self ||
|
|
cur_fb.status == ci_old_copy)
|
|
{
|
|
pinfo[info_index].addr = cur_fb.addr;
|
|
pinfo[info_index].size = cur_fb.size;
|
|
pinfo[info_index].width = cur_fb.width;
|
|
pinfo[info_index].height = cur_fb.height;
|
|
info_index++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pinfo[0].addr = rdp.maincimg[0].addr;
|
|
pinfo[0].size = rdp.ci_size;
|
|
pinfo[0].width = rdp.ci_width;
|
|
pinfo[0].height = rdp.ci_width*3/4;
|
|
pinfo[1].addr = rdp.maincimg[1].addr;
|
|
pinfo[1].size = rdp.ci_size;
|
|
pinfo[1].width = rdp.ci_width;
|
|
pinfo[1].height = rdp.ci_width*3/4;
|
|
}
|
|
//*/
|
|
}
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
//*/
|
|
#include "UcodeFB.h"
|
|
|
|
void DetectFrameBufferUsage ()
|
|
{
|
|
RDP("DetectFrameBufferUsage\n");
|
|
|
|
DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
|
|
#ifdef _WIN32
|
|
DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
|
|
#endif // _WIN32
|
|
DWORD a;
|
|
|
|
BOOL tidal = FALSE;
|
|
if (settings.PM && (rdp.copy_ci_index || rdp.frame_buffers[rdp.copy_ci_index].status == ci_copy_self))
|
|
tidal = TRUE;
|
|
DWORD ci = rdp.cimg, zi = rdp.zimg; // ci_width = rdp.ci_width;
|
|
rdp.main_ci = rdp.main_ci_end = rdp.main_ci_bg = rdp.ci_count = 0;
|
|
rdp.main_ci_index = rdp.copy_ci_index = 0;
|
|
rdp.zimg_end = 0;
|
|
rdp.tmpzimg = 0;
|
|
rdp.motionblur = FALSE;
|
|
rdp.main_ci_last_tex_addr = 0;
|
|
BOOL 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 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
|
|
rdp.cmd1 = ((DWORD*)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 ((intptr_t)(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;
|
|
|
|
RDP ("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;
|
|
}
|
|
|
|
BOOL 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;
|
|
}
|
|
|
|
RDP("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 (!settings.fb_hires || !rdp.copy_ci_index)
|
|
rdp.motionblur = TRUE;
|
|
if (rdp.motionblur || settings.fb_hires || (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 (settings.fb_hires && !settings.fb_ignore_previous)
|
|
{
|
|
if (rdp.swap_ci_index < 0)
|
|
{
|
|
rdp.texbufs[0].clear_allowed = TRUE;
|
|
OpenTextureBuffer(rdp.frame_buffers[rdp.main_ci_index]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rdp.motionblur)
|
|
{
|
|
if (settings.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;
|
|
DWORD 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 (settings.fb_hires)
|
|
{
|
|
for (i = 0; i < 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)
|
|
{
|
|
//RDP("Tidal wave!\n");
|
|
rdp.copy_ci_index = rdp.main_ci_index;
|
|
}
|
|
}
|
|
rdp.ci_count = 0;
|
|
if (settings.fb_ignore_previous)
|
|
rdp.read_whole_frame = FALSE;
|
|
else
|
|
rdp.maincimg[0] = rdp.frame_buffers[rdp.main_ci_index];
|
|
// rdp.scale_x = rdp.scale_x_bak;
|
|
// rdp.scale_y = rdp.scale_y_bak;
|
|
RDP("DetectFrameBufferUsage End\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/******************************************************************
|
|
Function: ProcessRDPList
|
|
Purpose: This function is called when there is a Dlist to be
|
|
processed. (Low level GFX list)
|
|
input: none
|
|
output: none
|
|
*******************************************************************/
|
|
EXPORT void CALL ProcessRDPList(void)
|
|
{
|
|
if (settings.KI)
|
|
{
|
|
*gfx.MI_INTR_REG |= 0x20;
|
|
gfx.CheckInterrupts();
|
|
}
|
|
LOG ("ProcessRDPList ()\n");
|
|
|
|
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;
|
|
|
|
memset (microcode, 0, 4096);
|
|
if (settings.autodetect_ucode)
|
|
{
|
|
// Thanks to ZeZu for ucode autodetection!!!
|
|
|
|
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
|
|
}
|
|
}
|
|
else if ( ((old_ucode == 6) && (settings.ucode == 1)) || settings.force_microcheck)
|
|
{
|
|
DWORD startUcode = *(DWORD*)(gfx.DMEM+0xFD0);
|
|
memcpy (microcode, gfx.RDRAM+startUcode, 4096);
|
|
microcheck ();
|
|
}
|
|
|
|
if (exception) return;
|
|
|
|
// Switch to fullscreen?
|
|
if (to_fullscreen)
|
|
{
|
|
to_fullscreen = FALSE;
|
|
|
|
if (!InitGfx (FALSE))
|
|
{
|
|
LOG ("FAILED!!!\n");
|
|
return;
|
|
}
|
|
fullscreen = TRUE;
|
|
}
|
|
|
|
// 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, (*(DWORD*)(gfx.DMEM+0x0FE4))>>6);
|
|
if (rdp.model_stack_size == 0)
|
|
rdp.model_stack_size = 32;
|
|
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;
|
|
fbreads_front = fbreads_back = 0;
|
|
rdp.fog_multiplier = rdp.fog_offset = 0;
|
|
rdp.zsrc = 0;
|
|
|
|
if (cpu_fb_write == TRUE)
|
|
DrawFrameBufferToScreen();
|
|
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;
|
|
|
|
//analize possible frame buffer usage
|
|
if (settings.fb_smart)
|
|
DetectFrameBufferUsage();
|
|
if (!settings.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
|
|
// DWORD dlist_start = *(DWORD*)(gfx.DMEM+0xFF0);
|
|
// DWORD dlist_length = *(DWORD*)(gfx.DMEM+0xFF4);
|
|
DWORD dlist_start = *gfx.DPC_CURRENT_REG;
|
|
DWORD dlist_length = *gfx.DPC_END_REG - *gfx.DPC_CURRENT_REG;
|
|
FRDP("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx, fbuf_width: %d, dlist start: %08lx, dlist_lenght: %d\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG, *gfx.VI_WIDTH_REG, dlist_start, dlist_length);
|
|
FRDP_E("--- NEW DLIST --- crc: %08lx, ucode: %d, fbuf: %08lx\n", uc_crc, settings.ucode, *gfx.VI_ORIGIN_REG);
|
|
|
|
if (settings.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;
|
|
DWORD a;
|
|
|
|
// catches exceptions so that it doesn't freeze
|
|
#ifdef CATCH_EXCEPTIONS
|
|
try {
|
|
#endif
|
|
|
|
// 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 = ((DWORD*)gfx.RDRAM)[a>>2]; // \ Current command, 64 bit
|
|
rdp.cmd1 = ((DWORD*)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
|
|
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_cur);
|
|
#endif
|
|
// Process this instruction
|
|
gfx_instruction[settings.ucode][((rdp.cmd0>>24)&0x3f) + 0x100-0x40] ();
|
|
|
|
// check DL counter
|
|
if (rdp.dl_count != -1)
|
|
{
|
|
rdp.dl_count --;
|
|
if (rdp.dl_count == 0)
|
|
{
|
|
rdp.dl_count = -1;
|
|
|
|
RDP ("End of DL\n");
|
|
rdp.pc_i --;
|
|
}
|
|
}
|
|
|
|
#ifdef PERFORMANCE
|
|
QueryPerformanceCounter ((LARGE_INTEGER*)&perf_next);
|
|
__int64 t = perf_next-perf_cur;
|
|
sprintf (out_buf, "perf %08lx: %016I64d\n", a-8, t);
|
|
rdp_log << out_buf;
|
|
#endif
|
|
|
|
} while (0);
|
|
#ifdef CATCH_EXCEPTIONS
|
|
} catch (...) {
|
|
|
|
if (fullscreen) ReleaseGfx ();
|
|
WriteLog(M64MSG_ERROR, "The GFX plugin caused an exception and has been disabled.");
|
|
exception = TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (settings.fb_smart)
|
|
{
|
|
rdp.scale_x = rdp.scale_x_bak;
|
|
rdp.scale_y = rdp.scale_y_bak;
|
|
}
|
|
if (settings.fb_read_always)
|
|
{
|
|
CopyFrameBuffer ();
|
|
}
|
|
if (rdp.yuv_image)
|
|
{
|
|
DrawYUVImageToFrameBuffer();
|
|
rdp.yuv_image = FALSE;
|
|
// FRDP("yuv image draw. ul_x: %f, ul_y: %f, lr_x: %f, lr_y: %f, begin: %08lx\n",
|
|
// rdp.yuv_ul_x, rdp.yuv_ul_y, rdp.yuv_lr_x, rdp.yuv_lr_y, rdp.yuv_im_begin);
|
|
rdp.yuv_ul_x = rdp.yuv_ul_y = rdp.yuv_lr_x = rdp.yuv_lr_y = 0;
|
|
rdp.yuv_im_begin = 0x00FFFFFF;
|
|
}
|
|
if (rdp.cur_image)
|
|
CloseTextureBuffer(rdp.read_whole_frame && (settings.PM || rdp.swap_ci_index >= 0));
|
|
|
|
if (settings.TGR2 && rdp.vi_org_reg != *gfx.VI_ORIGIN_REG && CI_SET)
|
|
{
|
|
newSwapBuffers ();
|
|
CI_SET = FALSE;
|
|
}
|
|
RDP("ProcessDList end\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WriteLog(M64MSG_VERBOSE, "ProcessRPDList %x %x %x\n",
|
|
*gfx.DPC_START_REG,
|
|
*gfx.DPC_END_REG,
|
|
*gfx.DPC_CURRENT_REG);
|
|
//*gfx.DPC_STATUS_REG = 0xffffffff; // &= ~0x0002;
|
|
|
|
*gfx.DPC_START_REG = *gfx.DPC_END_REG;
|
|
*gfx.DPC_CURRENT_REG = *gfx.DPC_END_REG;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// Local Variables: ***
|
|
// tab-width:4 ***
|
|
// c-file-offset:4 ***
|
|
// End: ***
|
|
|