mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
1230 lines
38 KiB
C++
1230 lines
38 KiB
C++
/*
|
|
Copyright (C) 2001 StrmnNrmn
|
|
|
|
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 (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include "BuildOptions.h"
|
|
#include "Base/Types.h"
|
|
|
|
|
|
#include "Config/ConfigOptions.h"
|
|
#include "Core/CPU.h"
|
|
#include "Core/Memory.h"
|
|
#include "Core/ROM.h"
|
|
#include "Debug/DBGConsole.h"
|
|
#include "Debug/Dump.h"
|
|
#include "Graphics/GraphicsContext.h"
|
|
#include "Graphics/NativePixelFormat.h"
|
|
#include "HLEGraphics/ConvertFormats.h" // YUVtoRGBA
|
|
#include "HLEGraphics/DLDebug.h"
|
|
#include "HLEGraphics/DLParser.h"
|
|
#include "HLEGraphics/BaseRenderer.h"
|
|
#include "HLEGraphics/Microcode.h"
|
|
#include "HLEGraphics/N64PixelFormat.h"
|
|
#include "HLEGraphics/TextureCache.h"
|
|
#include "HLEGraphics/RDP.h"
|
|
#include "HLEGraphics/RDPStateManager.h"
|
|
#include "Base/MathUtil.h"
|
|
#include "Ultra/ultra_gbi.h"
|
|
#include "Ultra/ultra_rcp.h"
|
|
#include "Ultra/ultra_sptask.h"
|
|
#include "HLEGraphics/GraphicsPlugin.h"
|
|
#include "Test/BatchTest.h"
|
|
#include "uCodes/UcodeDefs.h"
|
|
#include "uCodes/Ucode.h"
|
|
#include "System/IO.h"
|
|
#include "Utility/Profiler.h"
|
|
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
#define DL_UNIMPLEMENTED_ERROR( msg ) \
|
|
{ \
|
|
static bool shown = false; \
|
|
if (!shown ) \
|
|
{ \
|
|
DL_PF( "~*Not Implemented %s", msg ); \
|
|
DAEDALUS_DL_ERROR( "%s: %08x %08x", (msg), command.inst.cmd0, command.inst.cmd1 ); \
|
|
shown = true; \
|
|
} \
|
|
}
|
|
#else
|
|
#define DL_UNIMPLEMENTED_ERROR( msg )
|
|
#endif
|
|
|
|
#define MAX_DL_STACK_SIZE 32
|
|
|
|
#define RDPSegAddr(seg) ( (gSegments[(seg >> 24) & 0x0F] + (seg & (MAX_RAM_ADDRESS-1))) & (MAX_RAM_ADDRESS-1))
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////
|
|
// GFX State //
|
|
//////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////
|
|
|
|
struct N64Viewport
|
|
{
|
|
s16 scale_y, scale_x, scale_w, scale_z;
|
|
s16 trans_y, trans_x, trans_w, trans_z;
|
|
};
|
|
|
|
DAEDALUS_STATIC_ASSERT( sizeof(N64Viewport) == 16 );
|
|
|
|
struct N64mat
|
|
{
|
|
struct _s16
|
|
{
|
|
s16 y, x, w, z;
|
|
};
|
|
|
|
struct _u16
|
|
{
|
|
u16 y, x, w, z;
|
|
};
|
|
|
|
_s16 h[4];
|
|
_u16 l[4];
|
|
};
|
|
|
|
DAEDALUS_STATIC_ASSERT( sizeof(N64mat) == 64 );
|
|
|
|
struct N64Light
|
|
{
|
|
u8 ca, b, g, r; // Colour and ca (ca is different for conker)
|
|
u8 la, b2, g2, r2;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
s8 pad0, dir_z, dir_y, dir_x; // Direction
|
|
u8 pad1, qa, pad2, nonzero;
|
|
};
|
|
struct
|
|
{
|
|
s16 y1, x1, w1, z1; // Position, GBI2 ex Majora's Mask
|
|
};
|
|
};
|
|
s32 pad4, pad5, pad6, pad7; // Padding..
|
|
s16 y, x, w, z; // Position, Conker
|
|
};
|
|
|
|
DAEDALUS_STATIC_ASSERT( sizeof(N64Light) == 40 );
|
|
|
|
struct RDP_Scissor
|
|
{
|
|
u32 left, top, right, bottom;
|
|
};
|
|
|
|
// The display list PC stack. Before this was an array of 10
|
|
// items, but this way we can nest as deeply as necessary.
|
|
struct DList
|
|
{
|
|
u32 address[MAX_DL_STACK_SIZE];
|
|
s32 limit;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void RDP_MoveMemViewport(u32 address);
|
|
void MatrixFromN64FixedPoint( Matrix4x4 & mat, u32 address );
|
|
void DLParser_InitMicrocode( u32 code_base, u32 code_size, u32 data_base, u32 data_size );
|
|
|
|
enum LightSource
|
|
{
|
|
POINT_LIGHT_NONE = 0, // No Point Light
|
|
POINT_LIGHT_MM, // Majora's Mask Point Light
|
|
POINT_LIGHT_CBFD, // Conker's Point Light
|
|
POINT_LIGHT_ACCLAIM // Acclaim's Point Light (unsupported ATM)
|
|
};
|
|
template< LightSource Source, u32 LightSize >
|
|
void RDP_MoveMemLight(u32 address, u32 light_idx);
|
|
|
|
|
|
// Used to keep track of when we're processing the first display list
|
|
static bool gFirstCall = true;
|
|
|
|
static u32 gSegments[16];
|
|
static RDP_Scissor scissors;
|
|
static RDP_GeometryMode gGeometryMode;
|
|
static DList gDlistStack;
|
|
static s32 gDlistStackPointer = -1;
|
|
static u32 gRDPHalf1 = 0;
|
|
|
|
SImageDescriptor g_TI = { G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, 0 };
|
|
static SImageDescriptor g_CI = { G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, 0 };
|
|
static SImageDescriptor g_DI = { G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, 0 };
|
|
|
|
const MicroCodeInstruction *gUcodeFunc = gNormalInstruction[ GBI_0 ];
|
|
static const char ** gUcodeName = gNormalInstructionName[ GBI_0 ];
|
|
|
|
bool gFrameskipActive = false;
|
|
|
|
// Define this to validate an address before referencing an N64 ram location
|
|
#ifndef DAEDALUS_PSP
|
|
#define VALIDATE_ADDRESS_SEG
|
|
#endif
|
|
|
|
// Always call this function before referencing an N64 ram location
|
|
// In most cases we are already in range, see RDPSegAddr. No need to call this when size its 0
|
|
static inline bool IsAddressValid(u32 address, u32 size, const char * name)
|
|
{
|
|
#ifdef VALIDATE_ADDRESS_SEG
|
|
if ((address + size) > MAX_RAM_ADDRESS)
|
|
{
|
|
DBGConsole_Msg(0,"%s: Address is out of range (0x%08x)", name, address);
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
// Same as above but adds coverage for n (vert num) and checks the vertex index
|
|
// We call this earlier on the pipeline to prevent passing an invalid vertex info to the Dlist debugger!
|
|
static inline bool IsVertexInfoValid(u32 address, u32 size, u32 v0, u32 n)
|
|
{
|
|
#ifdef VALIDATE_ADDRESS_SEG
|
|
if ((address + (n * size)) > MAX_RAM_ADDRESS)
|
|
{
|
|
DBGConsole_Msg(0,"VertexInfo: Address is out of range (0x%08x)", address);
|
|
return false;
|
|
}
|
|
#endif
|
|
if ((n + v0) > kMaxN64Vertices)
|
|
{
|
|
DAEDALUS_ERROR("VertexInfo: Vertex index is out of bounds (%d)", (n + v0));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
inline void FinishRDPJob()
|
|
{
|
|
Memory_MI_SetRegisterBits(MI_INTR_REG, MI_INTR_DP);
|
|
gCPUState.AddJob(CPU_CHECK_INTERRUPTS);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// Reads the next command from the display list, updates the PC.
|
|
//*****************************************************************************
|
|
inline bool DLParser_FetchNextCommand( MicroCodeCommand * p_command )
|
|
{
|
|
// Current PC is the last value on the stack
|
|
u32 & pc( gDlistStack.address[gDlistStackPointer] );
|
|
if( !IsAddressValid(pc, 8, "FetchNextCommand") )
|
|
return false;
|
|
|
|
*p_command = *(MicroCodeCommand*)(g_pu8RamBase + pc);
|
|
pc += 8;
|
|
|
|
return true;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
inline void DLParser_PopDL()
|
|
{
|
|
DL_PF(" Returning from DisplayList: level=%d", gDlistStackPointer+1);
|
|
DL_PF(" ############################################");
|
|
DL_PF(" /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\ /\\");
|
|
DL_PF(" ");
|
|
|
|
gDlistStackPointer--;
|
|
}
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
//////////////////////////////////////////////////////////
|
|
// Debug vars //
|
|
//////////////////////////////////////////////////////////
|
|
void DLParser_DumpVtxInfo(u32 address, u32 v0_idx, u32 num_verts);
|
|
|
|
u32 gNumDListsCulled;
|
|
u32 gNumVertices;
|
|
u32 gNumRectsClipped;
|
|
u32 gNumInstructionsExecuted = 0;
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
u32 gRDPFrame = 0;
|
|
u32 gAuxAddr = 0;
|
|
|
|
extern u32 uViWidth;
|
|
extern u32 uViHeight;
|
|
//*****************************************************************************
|
|
// Include ucode header files
|
|
//*****************************************************************************
|
|
#include "uCodes/Ucode_GBI0.h"
|
|
#include "uCodes/Ucode_GBI1.h"
|
|
#include "uCodes/Ucode_GBI2.h"
|
|
#include "uCodes/Ucode_DKR.h"
|
|
#include "uCodes/Ucode_FB.h"
|
|
#include "uCodes/Ucode_GE.h"
|
|
#include "uCodes/Ucode_PD.h"
|
|
#include "uCodes/Ucode_Conker.h"
|
|
#include "uCodes/Ucode_LL.h"
|
|
#include "uCodes/Ucode_Beta.h"
|
|
#include "uCodes/Ucode_Sprite2D.h"
|
|
#include "uCodes/Ucode_S2DEX.h"
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////
|
|
// Strings //
|
|
//////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////
|
|
|
|
static const char * const gFormatNames[8] = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"};
|
|
|
|
static const char * const gSizeNames[4] = {"4bpp", "8bpp", "16bpp", "32bpp"};
|
|
static const char * const gOnOffNames[2] = {"Off", "On"};
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_DumpVtxInfo(u32 address, u32 v0_idx, u32 num_verts)
|
|
{
|
|
if (DLDebug_IsActive())
|
|
{
|
|
s8 *pcSrc = (s8 *)(g_pu8RamBase + address);
|
|
s16 *psSrc = (s16 *)(g_pu8RamBase + address);
|
|
|
|
for ( u32 idx = v0_idx; idx < v0_idx + num_verts; idx++ )
|
|
{
|
|
f32 x = f32(psSrc[0^0x1]);
|
|
f32 y = f32(psSrc[1^0x1]);
|
|
f32 z = f32(psSrc[2^0x1]);
|
|
|
|
u16 wFlags = u16(gRenderer->GetVtxFlags( idx )); //(u16)psSrc[3^0x1];
|
|
|
|
u8 a = pcSrc[12^0x3];
|
|
u8 b = pcSrc[13^0x3];
|
|
u8 c = pcSrc[14^0x3];
|
|
u8 d = pcSrc[15^0x3];
|
|
|
|
s16 nTU = psSrc[4^0x1];
|
|
s16 nTV = psSrc[5^0x1];
|
|
|
|
f32 tu = f32(nTU) * (1.0f / 32.0f);
|
|
f32 tv = f32(nTV) * (1.0f / 32.0f);
|
|
|
|
const v4 & t = gRenderer->GetTransformedVtxPos( idx );
|
|
const v4 & p = gRenderer->GetProjectedVtxPos( idx );
|
|
|
|
psSrc += 8; // Increase by 16 bytes
|
|
pcSrc += 16;
|
|
|
|
DL_PF(" #%02d Flags: 0x%04x Pos:{% 0.1f,% 0.1f,% 0.1f} Tex:{% 7.2f,% 7.2f} Extra: %02x %02x %02x %02x Tran:{% 0.3f,% 0.3f,% 0.3f,% 0.3f} Proj:{% 6f,% 6f,% 6f,% 6f}",
|
|
idx, wFlags, x, y, z, tu, tv, a, b, c, d, t.x, t.y, t.z, t.w, p.x/p.w, p.y/p.w, p.z/p.w, p.w);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
bool DLParser_Initialise()
|
|
{
|
|
gFirstCall = true;
|
|
gRDPFrame = 0;
|
|
gAuxAddr = 0;
|
|
gRDPHalf1 = 0;
|
|
|
|
// Reset scissor to default
|
|
scissors.top = 0;
|
|
scissors.left = 0;
|
|
scissors.right = 320;
|
|
scissors.bottom = 240;
|
|
|
|
// Clear ucode cache
|
|
GBIMicrocode_Reset();
|
|
|
|
// Init with Fast 3D ucode incase of a failure to start the ucode detection
|
|
gUcodeFunc = gNormalInstruction[ GBI_0 ];
|
|
gUcodeName = gNormalInstructionName[ GBI_0 ];
|
|
|
|
//Clear pointers in TMEM block //Corn
|
|
#ifdef DAEDALUS_ACCURATE_TMEM
|
|
memset(gTlutLoadAddresses, 0, sizeof(gTlutLoadAddresses));
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_Finalise()
|
|
{
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_InitMicrocode( u32 code_base, u32 code_size, u32 data_base, u32 data_size )
|
|
{
|
|
if( !IsAddressValid(code_base, code_size, "InitMicrocode: ucode code")
|
|
|| !IsAddressValid(data_base, data_size, "InitMicrocode: ucode data") )
|
|
{
|
|
return;
|
|
}
|
|
const UcodeInfo& ucode_info( GBIMicrocode_DetectVersion(code_base, code_size, data_base, data_size) );
|
|
gUcodeFunc = ucode_info.func;
|
|
gUcodeName = ucode_info.name;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
#ifdef DAEDALUS_ENABLE_PROFILING
|
|
SProfileItemHandle * gpProfileItemHandles[ 256 ];
|
|
|
|
#define PROFILE_DL_CMD( cmd ) \
|
|
if(gpProfileItemHandles[ (cmd) ] == NULL) \
|
|
{ \
|
|
gpProfileItemHandles[ (cmd) ] = new SProfileItemHandle( CProfiler::Get()->AddItem( gUcodeName[ cmd ] )); \
|
|
} \
|
|
CAutoProfile _auto_profile( *gpProfileItemHandles[ (cmd) ] )
|
|
|
|
#else
|
|
|
|
#define PROFILE_DL_CMD( cmd ) do { } while(0)
|
|
|
|
#endif
|
|
|
|
//*****************************************************************************
|
|
// Process the entire display list in one go
|
|
//*****************************************************************************
|
|
static u32 DLParser_ProcessDList(u32 instruction_limit)
|
|
{
|
|
MicroCodeCommand command;
|
|
|
|
u32 current_instruction_count = 0;
|
|
|
|
while(gDlistStackPointer >= 0)
|
|
{
|
|
if (!DLParser_FetchNextCommand( &command ))
|
|
break;
|
|
|
|
DL_BEGIN_INSTR(current_instruction_count, command.inst.cmd0, command.inst.cmd1, gDlistStackPointer, gUcodeName[command.inst.cmd]);
|
|
|
|
PROFILE_DL_CMD( command.inst.cmd );
|
|
|
|
gUcodeFunc[ command.inst.cmd ]( command );
|
|
|
|
DL_END_INSTR();
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
// Note: make sure have frame skip disabled for the dlist debugger to work
|
|
if( instruction_limit != kUnlimitedInstructionCount )
|
|
{
|
|
if( current_instruction_count >= instruction_limit )
|
|
{
|
|
return current_instruction_count;
|
|
}
|
|
}
|
|
current_instruction_count++;
|
|
#endif
|
|
|
|
// Check limit
|
|
if (gDlistStack.limit >= 0)
|
|
{
|
|
if (--gDlistStack.limit < 0)
|
|
{
|
|
DL_PF("**EndDLInMem");
|
|
gDlistStackPointer--;
|
|
// limit is already reset to default -1 at this point
|
|
//gDlistStack.limit = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return current_instruction_count;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
u32 DLParser_Process(u32 instruction_limit, DLDebugOutput * debug_output)
|
|
{
|
|
DAEDALUS_PROFILE( "DLParser_Process" );
|
|
|
|
if ( !CGraphicsContext::Get()->IsInitialised() || !gRenderer )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Shut down the debug console when we start rendering
|
|
// TODO: Clear the front/backbuffer the first time this function is called
|
|
// to remove any stuff lingering on the screen.
|
|
if(gFirstCall)
|
|
{
|
|
CGraphicsContext::Get()->ClearAllSurfaces();
|
|
|
|
gFirstCall = false;
|
|
}
|
|
|
|
// Update Screen only when something is drawn, otherwise several games ex Army Men will flash or shake.
|
|
if( g_ROM.GameHacks != CHAMELEON_TWIST_2 ) gGraphicsPlugin->UpdateScreen();
|
|
|
|
OSTask * pTask = (OSTask *)(g_pu8SpMemBase + 0x0FC0);
|
|
u32 code_base = (u32)pTask->t.ucode & 0x1fffffff;
|
|
//u32 code_size = pTask->t.ucode_size; // Conker sets this to 0..
|
|
u32 code_size = 0x1000;
|
|
u32 data_base = (u32)pTask->t.ucode_data & 0x1fffffff;
|
|
u32 data_size = pTask->t.ucode_data_size;
|
|
u32 stack_size = pTask->t.dram_stack_size >> 6;
|
|
|
|
DLParser_InitMicrocode( code_base, code_size, data_base, data_size );
|
|
|
|
//
|
|
// Not sure what to init this with. We should probably read it from the dmem
|
|
//
|
|
gRDPOtherMode.L = 0x00500001;
|
|
gRDPOtherMode.H = 0;
|
|
|
|
gRDPFrame++;
|
|
|
|
CTextureCache::Get()->PurgeOldTextures();
|
|
|
|
// Initialise stack
|
|
gDlistStackPointer=0;
|
|
gDlistStack.address[0] = (u32)pTask->t.data_ptr;
|
|
gDlistStack.limit = -1;
|
|
|
|
gRDPStateManager.Reset();
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
gNumDListsCulled = 0;
|
|
gNumVertices = 0;
|
|
gNumRectsClipped = 0;
|
|
if (debug_output)
|
|
DLDebug_SetOutput(debug_output);
|
|
DLDebug_DumpTaskInfo( pTask );
|
|
#endif
|
|
|
|
DL_PF("DP: Firing up RDP!");
|
|
|
|
u32 count = 0;
|
|
|
|
if(!gFrameskipActive)
|
|
{
|
|
gRenderer->SetVIScales();
|
|
gRenderer->ResetMatrices(stack_size);
|
|
gRenderer->Reset();
|
|
gRenderer->BeginScene();
|
|
count = DLParser_ProcessDList(instruction_limit);
|
|
gRenderer->EndScene();
|
|
}
|
|
else
|
|
{
|
|
FinishRDPJob();
|
|
}
|
|
|
|
// Hack for Chameleon Twist 2, only works if screen is update at last
|
|
if( g_ROM.GameHacks == CHAMELEON_TWIST_2 )
|
|
gGraphicsPlugin->UpdateScreen();
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
DLDebug_SetOutput(NULL);
|
|
|
|
// NB: only update gNumInstructionsExecuted when we rendered something.
|
|
// I'd really like to get rid of gNumInstructionsExecuted.
|
|
if (!gFrameskipActive)
|
|
gNumInstructionsExecuted = count;
|
|
#endif
|
|
|
|
#ifdef DAEDALUS_BATCH_TEST_ENABLED
|
|
CBatchTestEventHandler * handler( BatchTest_GetHandler() );
|
|
if( handler )
|
|
handler->OnDisplayListComplete();
|
|
#endif
|
|
|
|
return count;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void MatrixFromN64FixedPoint( Matrix4x4 & mat, u32 address )
|
|
{
|
|
if( !IsAddressValid(address, 64, "MatrixFromN64FixedPoint") )
|
|
return;
|
|
|
|
const f32 fRecip = 1.0f / 65536.0f;
|
|
const N64mat *Imat = (N64mat *)( g_pu8RamBase + address );
|
|
|
|
for (u32 i = 0; i < 4; i++)
|
|
{
|
|
mat.m[i][0] = ((Imat->h[i].x << 16) | Imat->l[i].x) * fRecip;
|
|
mat.m[i][1] = ((Imat->h[i].y << 16) | Imat->l[i].y) * fRecip;
|
|
mat.m[i][2] = ((Imat->h[i].z << 16) | Imat->l[i].z) * fRecip;
|
|
mat.m[i][3] = ((Imat->h[i].w << 16) | Imat->l[i].w) * fRecip;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
template< LightSource Source, u32 LightSize >
|
|
void RDP_MoveMemLight(u32 address, u32 light_idx)
|
|
{
|
|
if( Source == POINT_LIGHT_ACCLAIM )
|
|
{
|
|
DAEDALUS_ERROR("ACCLAIM Lightning not supported");
|
|
return;
|
|
|
|
}
|
|
|
|
if( light_idx >= LightSize )
|
|
{
|
|
DBGConsole_Msg(0, "Warning: invalid light # = %d, Max light # = %d", light_idx, LightSize);
|
|
}
|
|
else
|
|
{
|
|
if( !IsAddressValid(address, 40, "RDP_MoveMemLight") )
|
|
return;
|
|
|
|
const N64Light *light = (const N64Light*)(g_pu8RamBase + address);
|
|
|
|
u8 r = light->r;
|
|
u8 g = light->g;
|
|
u8 b = light->b;
|
|
|
|
s8 dir_x = light->dir_x;
|
|
s8 dir_y = light->dir_y;
|
|
s8 dir_z = light->dir_z;
|
|
|
|
DL_PF(" Light[%d] RGB[%d, %d, %d] x[%d] y[%d] z[%d]", light_idx, r, g, b, dir_x, dir_y, dir_z);
|
|
|
|
//Color
|
|
gRenderer->SetLightCol( light_idx, r, g, b );
|
|
|
|
//Direction
|
|
gRenderer->SetLightDirection( light_idx, dir_x, dir_y, dir_z );
|
|
|
|
//Position and Ambient light for Majora's Mask
|
|
if( Source == POINT_LIGHT_MM )
|
|
{
|
|
gRenderer->SetLightPosition(light_idx, light->x1, light->y1, light->z1, 1.0f);
|
|
gRenderer->SetLightEx(light_idx, light->ca, light->la, light->qa);
|
|
}
|
|
|
|
//Position and Ambient light for Conker
|
|
if( Source == POINT_LIGHT_CBFD )
|
|
{
|
|
gRenderer->SetLightPosition( light_idx, light->x, light->y, light->z , light->w);
|
|
gRenderer->SetLightCBFD( light_idx, light->nonzero);
|
|
}
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
//0x000b46b0: dc080008 800b46a0 G_GBI2_MOVEMEM
|
|
// Type: 08 Len: 08 Off: 0000
|
|
// Scale: 640 480 511 0 = 160,120
|
|
// Trans: 640 480 511 0 = 160,120
|
|
//vscale is the scale applied to the normalized homogeneous coordinates after 4x4 projection transformation
|
|
//vtrans is the offset added to the scaled number
|
|
|
|
void RDP_MoveMemViewport(u32 address)
|
|
{
|
|
if( !IsAddressValid(address, 16, "RDP_MoveMemViewport") )
|
|
return;
|
|
|
|
// address is offset into RD_RAM of 8 x 16bits of data...
|
|
N64Viewport *vp = (N64Viewport*)(g_pu8RamBase + address);
|
|
|
|
// With D3D we had to ensure that the vp coords are positive, so
|
|
// we truncated them to 0. This happens a lot, as things
|
|
// seem to specify the scale as the screen w/2 h/2
|
|
|
|
v2 vec_scale( vp->scale_x * 0.25f, vp->scale_y * 0.25f );
|
|
v2 vec_trans( vp->trans_x * 0.25f, vp->trans_y * 0.25f );
|
|
|
|
gRenderer->SetN64Viewport( vec_scale, vec_trans );
|
|
|
|
DL_PF(" Scale: %d %d", vp->scale_x, vp->scale_y);
|
|
DL_PF(" Trans: %d %d", vp->trans_x, vp->trans_y);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
//Nintro64 uses Sprite2d
|
|
void DLParser_Nothing( MicroCodeCommand command )
|
|
{
|
|
DAEDALUS_DL_ERROR( "RDP Command %08x Does not exist...", command.inst.cmd0 );
|
|
|
|
// Terminate!
|
|
// DBGConsole_Msg(0, "Warning, DL cut short with unknown command: 0x%08x 0x%08x", command.inst.cmd0, command.inst.cmd1);
|
|
DLParser_PopDL();
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetKeyGB( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " SetKeyGB (Ignored)" );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetKeyR( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " SetKeyR (Ignored)" );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetConvert( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " SetConvert (Ignored)" );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetPrimDepth( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" SetPrimDepth z[0x%04x] dz[0x%04x]",
|
|
command.primdepth.z, command.primdepth.dz);
|
|
|
|
gRenderer->SetPrimitiveDepth( command.primdepth.z );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_RDPSetOtherMode( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " RDPSetOtherMode: 0x%08x 0x%08x", command.inst.cmd0, command.inst.cmd1 );
|
|
|
|
gRDPOtherMode.H = command.inst.cmd0;
|
|
gRDPOtherMode.L = command.inst.cmd1;
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
DLDebug_DumpRDPOtherMode(gRDPOtherMode);
|
|
#endif
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_RDPLoadSync( MicroCodeCommand command ) { /*DL_PF(" LoadSync: (Ignored)");*/ }
|
|
void DLParser_RDPPipeSync( MicroCodeCommand command ) { /*DL_PF(" PipeSync: (Ignored)");*/ }
|
|
void DLParser_RDPTileSync( MicroCodeCommand command ) { /*DL_PF(" TileSync: (Ignored)");*/ }
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_RDPFullSync( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" FullSync: (Generating Interrupt)");
|
|
FinishRDPJob();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetScissor( MicroCodeCommand command )
|
|
{
|
|
// The coords are all in 10:2 fixed point
|
|
// Set up scissoring zone, we'll use it to scissor other stuff ex Texrect
|
|
//
|
|
scissors.left = command.scissor.x0>>2;
|
|
scissors.top = command.scissor.y0>>2;
|
|
scissors.right = command.scissor.x1>>2;
|
|
scissors.bottom = command.scissor.y1>>2;
|
|
|
|
// Hack to correct Super Bowling's right and left screens
|
|
if ( g_ROM.GameHacks == SUPER_BOWLING && g_CI.Address%0x100 != 0 )
|
|
{
|
|
scissors.left += 160;
|
|
scissors.right += 160;
|
|
v2 vec_trans( 240, 120 );
|
|
v2 vec_scale( 80, 120 );
|
|
gRenderer->SetN64Viewport( vec_scale, vec_trans );
|
|
}
|
|
|
|
DL_PF(" x0=%d y0=%d x1=%d y1=%d mode=%d", scissors.left, scissors.top, scissors.right, scissors.bottom, command.scissor.mode);
|
|
|
|
// Set the cliprect now...
|
|
if ( scissors.left < scissors.right && scissors.top < scissors.bottom )
|
|
{
|
|
gRenderer->SetScissor( scissors.left, scissors.top, scissors.right, scissors.bottom );
|
|
}
|
|
}
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetTile( MicroCodeCommand command )
|
|
{
|
|
RDP_Tile tile;
|
|
tile.cmd0 = command.inst.cmd0;
|
|
tile.cmd1 = command.inst.cmd1;
|
|
|
|
gRDPStateManager.SetTile( tile );
|
|
|
|
DL_PF( " Tile[%d] Format[%s/%s] Line[%d] TMEM[0x%03x] Palette[%d]", tile.tile_idx, gFormatNames[tile.format], gSizeNames[tile.size], tile.line, tile.tmem, tile.palette);
|
|
DL_PF( " S: Clamp[%s] Mirror[%s] Mask[0x%x] Shift[0x%x]", gOnOffNames[tile.clamp_s],gOnOffNames[tile.mirror_s], tile.mask_s, tile.shift_s );
|
|
DL_PF( " T: Clamp[%s] Mirror[%s] Mask[0x%x] Shift[0x%x]", gOnOffNames[tile.clamp_t],gOnOffNames[tile.mirror_t], tile.mask_t, tile.shift_t );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetTileSize( MicroCodeCommand command )
|
|
{
|
|
RDP_TileSize tile;
|
|
tile.cmd0 = command.inst.cmd0;
|
|
tile.cmd1 = command.inst.cmd1;
|
|
|
|
DL_PF(" Tile[%d] (%d,%d) -> (%d,%d) [%d x %d]",
|
|
tile.tile_idx, tile.left/4, tile.top/4,
|
|
tile.right/4, tile.bottom/4,
|
|
((tile.right/4) - (tile.left/4)) + 1,
|
|
((tile.bottom/4) - (tile.top/4)) + 1);
|
|
|
|
gRDPStateManager.SetTileSize( tile );
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetTImg( MicroCodeCommand command )
|
|
{
|
|
g_TI.Format = command.img.fmt;
|
|
g_TI.Size = command.img.siz;
|
|
g_TI.Width = command.img.width + 1;
|
|
g_TI.Address = RDPSegAddr(command.img.addr);
|
|
|
|
DL_PF(" TImg Adr[0x%08x] Format[%s/%s] Width[%d] Pitch[%d]",
|
|
g_TI.Address, gFormatNames[g_TI.Format], gSizeNames[g_TI.Size], g_TI.Width, g_TI.GetPitch());
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_LoadBlock( MicroCodeCommand command )
|
|
{
|
|
gRDPStateManager.LoadBlock( command.loadtile );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_LoadTile( MicroCodeCommand command )
|
|
{
|
|
gRDPStateManager.LoadTile( command.loadtile );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_LoadTLut( MicroCodeCommand command )
|
|
{
|
|
gRDPStateManager.LoadTlut( command.loadtile );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_TexRect( MicroCodeCommand command )
|
|
{
|
|
MicroCodeCommand command2;
|
|
MicroCodeCommand command3;
|
|
|
|
if( !DLParser_FetchNextCommand( &command2 ) ||
|
|
!DLParser_FetchNextCommand( &command3 ) )
|
|
return;
|
|
|
|
RDP_TexRect tex_rect;
|
|
tex_rect.cmd0 = command.inst.cmd0;
|
|
tex_rect.cmd1 = command.inst.cmd1;
|
|
tex_rect.cmd2 = command2.inst.cmd1;
|
|
tex_rect.cmd3 = command3.inst.cmd1;
|
|
|
|
DAEDALUS_DL_ASSERT(gRDPOtherMode.cycle_type != CYCLE_COPY || tex_rect.dsdx == (4<<10), "Expecting dsdx of 4<<10 in copy mode, got %d", tex_rect.dsdx);
|
|
|
|
// NB: In FILL and COPY mode, rectangles are scissored to the nearest four pixel boundary.
|
|
// This isn't currently handled, but I don't know of any games that depend on it.
|
|
|
|
//Keep integers for as long as possible //Corn
|
|
|
|
// X for upper left corner should be less than X for lower right corner else skip rendering it, seems to happen in Rayman 2 and Star Soldier
|
|
//if( tex_rect.x0 >= tex_rect.x1 )
|
|
|
|
// Hack for Banjo Tooie shadow
|
|
if (g_ROM.GameHacks == BANJO_TOOIE && gRDPOtherMode.L == 0x00504241)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Fixes black box in SSB when moving far way from the screen and offscreen in Conker
|
|
if (g_DI.Address == g_CI.Address || g_CI.Format != G_IM_FMT_RGBA)
|
|
{
|
|
DL_PF(" Ignoring Texrect");
|
|
return;
|
|
}
|
|
|
|
// Removes offscreen texrect, also fixes several glitches like in John Romero's Daikatana
|
|
if( tex_rect.x0 >= (scissors.right<<2) ||
|
|
tex_rect.y0 >= (scissors.bottom<<2) ||
|
|
tex_rect.x1 < (scissors.left<<2) ||
|
|
tex_rect.y1 < (scissors.top<<2) )
|
|
{
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
++gNumRectsClipped;
|
|
#endif
|
|
return;
|
|
};
|
|
|
|
s16 rect_s0 = tex_rect.s;
|
|
s16 rect_t0 = tex_rect.t;
|
|
|
|
s32 rect_dsdx = tex_rect.dsdx;
|
|
s32 rect_dtdy = tex_rect.dtdy;
|
|
|
|
rect_s0 += (((u32)rect_dsdx >> 31) << 5); //Fixes California Speed, if(rect_dsdx<0) rect_s0 += 32;
|
|
rect_t0 += (((u32)rect_dtdy >> 31) << 5);
|
|
|
|
// In Fill/Copy mode the coordinates are inclusive (i.e. add 1<<2 to the w/h)
|
|
u32 cycle_mode = gRDPOtherMode.cycle_type;
|
|
if ( cycle_mode >= CYCLE_COPY )
|
|
{
|
|
// In copy mode 4 pixels are copied at once.
|
|
if ( cycle_mode == CYCLE_COPY )
|
|
rect_dsdx = rect_dsdx >> 2;
|
|
|
|
tex_rect.x1 += 4;
|
|
tex_rect.y1 += 4;
|
|
}
|
|
|
|
s16 rect_s1 = rect_s0 + (rect_dsdx * ( tex_rect.x1 - tex_rect.x0 ) >> 7); // 7 = (>>10)=1/1024, (>>2)=1/4 and (<<5)=32
|
|
s16 rect_t1 = rect_t0 + (rect_dtdy * ( tex_rect.y1 - tex_rect.y0 ) >> 7);
|
|
|
|
TexCoord st0( rect_s0, rect_t0 );
|
|
TexCoord st1( rect_s1, rect_t1 );
|
|
|
|
v2 xy0( tex_rect.x0 / 4.0f, tex_rect.y0 / 4.0f );
|
|
v2 xy1( tex_rect.x1 / 4.0f, tex_rect.y1 / 4.0f );
|
|
|
|
DL_PF(" Screen(%.1f,%.1f) -> (%.1f,%.1f) Tile[%d]", xy0.x, xy0.y, xy1.x, xy1.y, tex_rect.tile_idx);
|
|
DL_PF(" Tex:(%#5.3f,%#5.3f) -> (%#5.3f,%#5.3f) (DSDX:%#5f DTDY:%#5f)", rect_s0/32.f, rect_t0/32.f, rect_s1/32.f, rect_t1/32.f, rect_dsdx/1024.f, rect_dtdy/1024.f);
|
|
|
|
gRenderer->TexRect( tex_rect.tile_idx, xy0, xy1, st0, st1 );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_TexRectFlip( MicroCodeCommand command )
|
|
{
|
|
MicroCodeCommand command2;
|
|
MicroCodeCommand command3;
|
|
|
|
if( !DLParser_FetchNextCommand( &command2 ) ||
|
|
!DLParser_FetchNextCommand( &command3 ) )
|
|
return;
|
|
|
|
RDP_TexRect tex_rect;
|
|
tex_rect.cmd0 = command.inst.cmd0;
|
|
tex_rect.cmd1 = command.inst.cmd1;
|
|
tex_rect.cmd2 = command2.inst.cmd1;
|
|
tex_rect.cmd3 = command3.inst.cmd1;
|
|
|
|
DAEDALUS_DL_ASSERT(gRDPOtherMode.cycle_type != CYCLE_COPY || tex_rect.dsdx == (4<<10), "Expecting dsdx of 4<<10 in copy mode, got %d", tex_rect.dsdx);
|
|
|
|
//Keep integers for as long as possible //Corn
|
|
|
|
s16 rect_s0 = tex_rect.s;
|
|
s16 rect_t0 = tex_rect.t;
|
|
|
|
s32 rect_dsdx = tex_rect.dsdx;
|
|
s32 rect_dtdy = tex_rect.dtdy;
|
|
|
|
rect_s0 += (((u32)rect_dsdx >> 31) << 5); // For Wetrix
|
|
rect_t0 += (((u32)rect_dtdy >> 31) << 5);
|
|
|
|
// In Fill/Copy mode the coordinates are inclusive (i.e. add 1<<2 to the w/h)
|
|
u32 cycle_mode = gRDPOtherMode.cycle_type;
|
|
if ( cycle_mode >= CYCLE_COPY )
|
|
{
|
|
// In copy mode 4 pixels are copied at once.
|
|
if ( cycle_mode == CYCLE_COPY )
|
|
rect_dsdx = rect_dsdx >> 2;
|
|
|
|
tex_rect.x1 += 4;
|
|
tex_rect.y1 += 4;
|
|
}
|
|
|
|
s16 rect_s1 = rect_s0 + (rect_dsdx * ( tex_rect.y1 - tex_rect.y0 ) >> 7); // Flip - use y
|
|
s16 rect_t1 = rect_t0 + (rect_dtdy * ( tex_rect.x1 - tex_rect.x0 ) >> 7); // Flip - use x
|
|
|
|
TexCoord st0( rect_s0, rect_t0 );
|
|
TexCoord st1( rect_s1, rect_t1 );
|
|
|
|
v2 xy0( tex_rect.x0 / 4.0f, tex_rect.y0 / 4.0f );
|
|
v2 xy1( tex_rect.x1 / 4.0f, tex_rect.y1 / 4.0f );
|
|
|
|
DL_PF(" Screen(%.1f,%.1f) -> (%.1f,%.1f) Tile[%d]", xy0.x, xy0.y, xy1.x, xy1.y, tex_rect.tile_idx);
|
|
DL_PF(" FlipTex:(%#5.3f,%#5.3f) -> (%#5.3f,%#5.3f) (DSDX:%#5f DTDY:%#5f)", rect_s0/32.f, rect_t0/32.f, rect_s1/32.f, rect_t1/32.f, rect_dsdx/1024.f, rect_dtdy/1024.f);
|
|
|
|
gRenderer->TexRectFlip( tex_rect.tile_idx, xy0, xy1, st0, st1 );
|
|
}
|
|
|
|
//Clear framebuffer, thanks Gonetz! http://www.emutalk.net/threads/15818-How-to-implement-quot-emulate-clear-quot-Answer-and-Question
|
|
//This fixes the jumpy camera in DK64, also the sun and flames glare in Zelda
|
|
void Clear_N64DepthBuffer( MicroCodeCommand command )
|
|
{
|
|
u32 x0 = command.fillrect.x0 + 1;
|
|
u32 x1 = command.fillrect.x1 + 1;
|
|
u32 y1 = command.fillrect.y1;
|
|
u32 y0 = command.fillrect.y0;
|
|
|
|
// Using s32 to force min/max to be done in a single op code for the PSP
|
|
x0 = std::min(std::max(x0, scissors.left), scissors.right);
|
|
x1 = std::min(std::max(x0, scissors.left), scissors.right);
|
|
y0 = std::min(std::max(y0, scissors.top), scissors.bottom);
|
|
y1 = std::min(std::max(y1, scissors.top), scissors.bottom);
|
|
|
|
//x0 = Min<s32>(Max<s32>(x0, scissors.left), scissors.right);
|
|
// x1 = Min<s32>(Max<s32>(x1, scissors.left), scissors.right);
|
|
// y1 = Min<s32>(Max<s32>(y1, scissors.top), scissors.bottom);
|
|
// y0 = Min<s32>(Max<s32>(y0, scissors.top), scissors.bottom);
|
|
x0 >>= 1;
|
|
x1 >>= 1;
|
|
u32 zi_width_in_dwords = g_CI.Width >> 1;
|
|
u32 fill_colour = gRenderer->GetFillColour();
|
|
u32 * dst = (u32*)(g_pu8RamBase + g_CI.Address) + y0 * zi_width_in_dwords;
|
|
|
|
for( u32 y = y0; y <y1; y++ )
|
|
{
|
|
for( u32 x = x0; x < x1; x++ )
|
|
{
|
|
dst[x] = fill_colour;
|
|
}
|
|
dst += zi_width_in_dwords;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_FillRect( MicroCodeCommand command )
|
|
{
|
|
//Always clear Zbuffer if Depthbuffer is selected //Corn
|
|
if (g_DI.Address == g_CI.Address)
|
|
{
|
|
CGraphicsContext::Get()->ClearZBuffer();
|
|
|
|
#ifdef DAEDALUS_PSP
|
|
if(gClearDepthFrameBuffer)
|
|
#else
|
|
if(true) //This always enabled for PC, this should be optional once we have a GUI to disable it!
|
|
#endif
|
|
{
|
|
Clear_N64DepthBuffer(command);
|
|
}
|
|
DL_PF(" Clearing ZBuffer");
|
|
return;
|
|
}
|
|
|
|
// Removes annoying rect that appears in Conker and fillrects that cover screen in banjo tooie
|
|
if( g_CI.Format != G_IM_FMT_RGBA )
|
|
{
|
|
DL_PF(" Ignoring Fillrect ");
|
|
return;
|
|
}
|
|
|
|
u32 x0 = command.fillrect.x0;
|
|
u32 x1 = command.fillrect.x1;
|
|
u32 y1 = command.fillrect.y1;
|
|
u32 y0 = command.fillrect.y0;
|
|
|
|
// Note, in some modes, the right/bottom lines aren't drawn
|
|
// TODO - Check colour image format to work out how this should be decoded!
|
|
// Should we init with Prim or Blend colour? Doesn't work well see Mk64 transition before a race
|
|
c32 colour = c32(0);
|
|
u32 cycle_mode = gRDPOtherMode.cycle_type;
|
|
//
|
|
// In Fill/Copy mode the coordinates are inclusive (i.e. add 1.0f to the w/h)
|
|
//
|
|
if ( cycle_mode >= CYCLE_COPY )
|
|
{
|
|
x1++;
|
|
y1++;
|
|
|
|
if ( cycle_mode == CYCLE_FILL )
|
|
{
|
|
u32 fill_colour = gRenderer->GetFillColour();
|
|
if(g_CI.Size == G_IM_SIZ_16b)
|
|
{
|
|
const N64Pf5551 c( (u16)fill_colour );
|
|
colour = ConvertPixelFormat< c32, N64Pf5551 >( c );
|
|
}
|
|
else
|
|
{
|
|
const N64Pf8888 c( (u32)fill_colour );
|
|
colour = ConvertPixelFormat< c32, N64Pf8888 >( c );
|
|
}
|
|
|
|
// Clear the screen if its just a large rectangle
|
|
if( (x1 - x0) == uViWidth && (y1 - y0) == uViHeight )
|
|
{
|
|
CGraphicsContext::Get()->ClearColBuffer( colour );
|
|
DL_PF(" Clearing Colour Buffer");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
DL_PF(" Filling Rectangle (%d,%d)->(%d,%d)", x0, y0, x1, y1);
|
|
|
|
v2 xy0( (f32)x0, (f32)y0 );
|
|
v2 xy1( (f32)x1, (f32)y1 );
|
|
|
|
// TODO - In 1/2cycle mode, skip bottom/right edges!?
|
|
// This is done in BaseRenderer.
|
|
|
|
gRenderer->FillRect( xy0, xy1, colour.GetColour() );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetZImg( MicroCodeCommand command )
|
|
{
|
|
g_DI.Address = RDPSegAddr(command.inst.cmd1);
|
|
DL_PF(" ZImg Adr[0x%08x]", g_DI.Address);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetCImg( MicroCodeCommand command )
|
|
{
|
|
g_CI.Format = command.img.fmt;
|
|
g_CI.Size = command.img.siz;
|
|
g_CI.Width = command.img.width + 1;
|
|
g_CI.Address = RDPSegAddr(command.img.addr);
|
|
//g_CI.Bpl = g_CI.Width << g_CI.Size >> 1;
|
|
|
|
DL_PF(" CImg Adr[0x%08x] Format[%s] Size[%s] Width[%d]", g_CI.Address, gFormatNames[ g_CI.Format ], gSizeNames[ g_CI.Size ], g_CI.Width);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetCombine( MicroCodeCommand command )
|
|
{
|
|
//Swap the endian
|
|
REG64 Mux;
|
|
Mux._u32_0 = command.inst.cmd1;
|
|
Mux._u32_1 = command.inst.arg0;
|
|
|
|
gRenderer->SetMux( Mux._u64 );
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
if (DLDebug_IsActive())
|
|
{
|
|
DLDebug_DumpMux( Mux._u64 );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetFillColor( MicroCodeCommand command )
|
|
{
|
|
u32 fill_colour = command.inst.cmd1;
|
|
|
|
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
|
|
N64Pf5551 n64col( (u16)fill_colour );
|
|
DL_PF( " Color5551=0x%04x", n64col.Bits );
|
|
#endif
|
|
|
|
gRenderer->SetFillColour( fill_colour );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetFogColor( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" RGBA: %d %d %d %d", command.color.r, command.color.g, command.color.b, command.color.a);
|
|
|
|
//c32 fog_colour( command.color.r, command.color.g, command.color.b, command.color.a );
|
|
c32 fog_colour( command.color.r, command.color.g, command.color.b, 0 ); //alpha is always 0
|
|
|
|
gRenderer->SetFogColour( fog_colour );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetBlendColor( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" RGBA: %d %d %d %d", command.color.r, command.color.g, command.color.b, command.color.a);
|
|
|
|
c32 blend_colour( command.color.r, command.color.g, command.color.b, command.color.a );
|
|
|
|
gRenderer->SetBlendColour( blend_colour );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetPrimColor( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" M:%d L:%d RGBA: %d %d %d %d", command.color.prim_min_level, command.color.prim_level, command.color.r, command.color.g, command.color.b, command.color.a);
|
|
|
|
c32 prim_colour( command.color.r, command.color.g, command.color.b, command.color.a );
|
|
|
|
gRenderer->SetPrimitiveLODFraction(command.color.prim_level / 256.f);
|
|
gRenderer->SetPrimitiveColour( prim_colour );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_SetEnvColor( MicroCodeCommand command )
|
|
{
|
|
DL_PF(" RGBA: %d %d %d %d", command.color.r, command.color.g, command.color.b, command.color.a);
|
|
|
|
c32 env_colour( command.color.r, command.color.g,command.color.b, command.color.a );
|
|
|
|
gRenderer->SetEnvColour( env_colour );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//RSP TRI commands..
|
|
//In HLE emulation you NEVER see these commands !
|
|
//*****************************************************************************
|
|
void DLParser_TriRSP( MicroCodeCommand command ){ DL_PF(" RSP Tri: (Ignored)"); }
|