2013-06-15 13:46:48 +00:00
|
|
|
#include <assert.h>
|
2014-09-01 16:19:20 +00:00
|
|
|
#include <algorithm>
|
2013-04-21 14:28:50 +00:00
|
|
|
#include "GLideN64.h"
|
2013-04-05 06:13:26 +00:00
|
|
|
#include "N64.h"
|
|
|
|
#include "GBI.h"
|
|
|
|
#include "RSP.h"
|
2014-10-07 10:59:54 +00:00
|
|
|
#include "RDP.h"
|
2013-04-05 06:13:26 +00:00
|
|
|
#include "gDP.h"
|
|
|
|
#include "gSP.h"
|
|
|
|
#include "Types.h"
|
|
|
|
#include "Debug.h"
|
|
|
|
#include "convert.h"
|
|
|
|
#include "OpenGL.h"
|
|
|
|
#include "CRC.h"
|
|
|
|
#include "FrameBuffer.h"
|
|
|
|
#include "DepthBuffer.h"
|
|
|
|
#include "VI.h"
|
2014-04-05 02:57:00 +00:00
|
|
|
#include "Config.h"
|
2014-10-24 11:00:42 +00:00
|
|
|
#include "Combiner.h"
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-06-09 11:54:14 +00:00
|
|
|
#define DEPTH_CLEAR_COLOR 0xfffcfffc // The value usually used to clear depth buffer
|
|
|
|
|
2014-09-01 16:19:20 +00:00
|
|
|
using namespace std;
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
gDPInfo gDP;
|
|
|
|
|
|
|
|
void gDPSetOtherMode( u32 mode0, u32 mode1 )
|
|
|
|
{
|
|
|
|
gDP.otherMode.h = mode0;
|
|
|
|
gDP.otherMode.l = mode1;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_RENDERMODE | CHANGED_CYCLETYPE | CHANGED_ALPHACOMPARE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetOtherMode( %s | %s | %s | %s | %s | %s | %s | %s | %s | %s | %s, %s | %s | %s%s%s%s%s | %s | %s%s%s );\n",
|
|
|
|
AlphaDitherText[gDP.otherMode.alphaDither],
|
|
|
|
ColorDitherText[gDP.otherMode.colorDither],
|
|
|
|
CombineKeyText[gDP.otherMode.combineKey],
|
|
|
|
TextureConvertText[gDP.otherMode.textureConvert],
|
|
|
|
TextureFilterText[gDP.otherMode.textureFilter],
|
|
|
|
TextureLUTText[gDP.otherMode.textureLUT],
|
|
|
|
TextureLODText[gDP.otherMode.textureLOD],
|
|
|
|
TextureDetailText[gDP.otherMode.textureDetail],
|
|
|
|
TexturePerspText[gDP.otherMode.texturePersp],
|
|
|
|
CycleTypeText[gDP.otherMode.cycleType],
|
|
|
|
PipelineModeText[gDP.otherMode.pipelineMode],
|
|
|
|
AlphaCompareText[gDP.otherMode.alphaCompare],
|
|
|
|
DepthSourceText[gDP.otherMode.depthSource],
|
|
|
|
gDP.otherMode.AAEnable ? "AA_EN | " : "",
|
|
|
|
gDP.otherMode.depthCompare ? "Z_CMP | " : "",
|
|
|
|
gDP.otherMode.depthUpdate ? "Z_UPD | " : "",
|
|
|
|
gDP.otherMode.imageRead ? "IM_RD | " : "",
|
|
|
|
CvgDestText[gDP.otherMode.cvgDest],
|
|
|
|
DepthModeText[gDP.otherMode.depthMode],
|
|
|
|
gDP.otherMode.cvgXAlpha ? "CVG_X_ALPHA | " : "",
|
|
|
|
gDP.otherMode.alphaCvgSel ? "ALPHA_CVG_SEL | " : "",
|
|
|
|
gDP.otherMode.forceBlender ? "FORCE_BL" : "" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetPrimDepth( u16 z, u16 dz )
|
|
|
|
{
|
2014-10-23 12:50:50 +00:00
|
|
|
gDP.primDepth.z = min(1.0f, max(0.0f, (_FIXED2FLOAT(_SHIFTR(z, 0, 15), 15) - gSP.viewport.vtrans[2]) / gSP.viewport.vscale[2]));
|
2013-04-05 06:13:26 +00:00
|
|
|
gDP.primDepth.deltaZ = dz;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetPrimDepth( %f, %f );\n",
|
|
|
|
gDP.primDepth.z,
|
|
|
|
gDP.primDepth.deltaZ);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPPipelineMode( u32 mode )
|
|
|
|
{
|
|
|
|
gDP.otherMode.pipelineMode = mode;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPPipelineMode( %s );\n",
|
|
|
|
PipelineModeText[gDP.otherMode.pipelineMode] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetCycleType( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.cycleType = type;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_CYCLETYPE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetCycleType( %s );\n",
|
|
|
|
CycleTypeText[gDP.otherMode.cycleType] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTexturePersp( u32 enable )
|
|
|
|
{
|
|
|
|
gDP.otherMode.texturePersp = enable;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTexturePersp( %s );\n",
|
|
|
|
TexturePerspText[gDP.otherMode.texturePersp] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTextureDetail( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.textureDetail = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureDetail( %s );\n",
|
|
|
|
TextureDetailText[gDP.otherMode.textureDetail] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTextureLOD( u32 mode )
|
|
|
|
{
|
|
|
|
gDP.otherMode.textureLOD = mode;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureLOD( %s );\n",
|
|
|
|
TextureLODText[gDP.otherMode.textureLOD] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTextureLUT( u32 mode )
|
|
|
|
{
|
|
|
|
gDP.otherMode.textureLUT = mode;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureLUT( %s );\n",
|
|
|
|
TextureLUTText[gDP.otherMode.textureLUT] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTextureFilter( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.textureFilter = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureFilter( %s );\n",
|
|
|
|
TextureFilterText[gDP.otherMode.textureFilter] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTextureConvert( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.textureConvert = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureConvert( %s );\n",
|
|
|
|
TextureConvertText[gDP.otherMode.textureConvert] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetCombineKey( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.combineKey = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_COMBINE, "gDPSetCombineKey( %s );\n",
|
|
|
|
CombineKeyText[gDP.otherMode.combineKey] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetColorDither( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.colorDither = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetColorDither( %s );\n",
|
|
|
|
ColorDitherText[gDP.otherMode.colorDither] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetAlphaDither( u32 type )
|
|
|
|
{
|
|
|
|
gDP.otherMode.alphaDither = type;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetAlphaDither( %s );\n",
|
|
|
|
AlphaDitherText[gDP.otherMode.alphaDither] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetAlphaCompare( u32 mode )
|
|
|
|
{
|
|
|
|
gDP.otherMode.alphaCompare = mode;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_ALPHACOMPARE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetAlphaCompare( %s );\n",
|
|
|
|
AlphaCompareText[gDP.otherMode.alphaCompare] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetDepthSource( u32 source )
|
|
|
|
{
|
|
|
|
gDP.otherMode.depthSource = source;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetDepthSource( %s );\n",
|
|
|
|
DepthSourceText[gDP.otherMode.depthSource] );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetRenderMode( u32 mode1, u32 mode2 )
|
|
|
|
{
|
|
|
|
gDP.otherMode.l &= 0x00000007;
|
|
|
|
gDP.otherMode.l |= mode1 | mode2;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_RENDERMODE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
// THIS IS INCOMPLETE!!!
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetRenderMode( %s%s%s%s%s | %s | %s%s%s );\n",
|
|
|
|
gDP.otherMode.AAEnable ? "AA_EN | " : "",
|
|
|
|
gDP.otherMode.depthCompare ? "Z_CMP | " : "",
|
|
|
|
gDP.otherMode.depthUpdate ? "Z_UPD | " : "",
|
|
|
|
gDP.otherMode.imageRead ? "IM_RD | " : "",
|
|
|
|
CvgDestText[gDP.otherMode.cvgDest],
|
|
|
|
DepthModeText[gDP.otherMode.depthMode],
|
|
|
|
gDP.otherMode.cvgXAlpha ? "CVG_X_ALPHA | " : "",
|
|
|
|
gDP.otherMode.alphaCvgSel ? "ALPHA_CVG_SEL | " : "",
|
|
|
|
gDP.otherMode.forceBlender ? "FORCE_BL" : "" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetCombine( s32 muxs0, s32 muxs1 )
|
|
|
|
{
|
|
|
|
gDP.combine.muxs0 = muxs0;
|
|
|
|
gDP.combine.muxs1 = muxs1;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_COMBINE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_COMBINE, "gDPSetCombine( %s, %s, %s, %s, %s, %s, %s, %s,\n",
|
|
|
|
saRGBText[gDP.combine.saRGB0],
|
|
|
|
sbRGBText[gDP.combine.sbRGB0],
|
|
|
|
mRGBText[gDP.combine.mRGB0],
|
|
|
|
aRGBText[gDP.combine.aRGB0],
|
|
|
|
saAText[gDP.combine.saA0],
|
|
|
|
sbAText[gDP.combine.sbA0],
|
|
|
|
mAText[gDP.combine.mA0],
|
|
|
|
aAText[gDP.combine.aA0] );
|
|
|
|
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_COMBINE, " %s, %s, %s, %s, %s, %s, %s, %s );\n",
|
|
|
|
saRGBText[gDP.combine.saRGB1],
|
|
|
|
sbRGBText[gDP.combine.sbRGB1],
|
|
|
|
mRGBText[gDP.combine.mRGB1],
|
|
|
|
aRGBText[gDP.combine.aRGB1],
|
|
|
|
saAText[gDP.combine.saA1],
|
|
|
|
sbAText[gDP.combine.sbA1],
|
|
|
|
mAText[gDP.combine.mA1],
|
|
|
|
aAText[gDP.combine.aA1] );
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetColorImage( u32 format, u32 size, u32 width, u32 address )
|
|
|
|
{
|
|
|
|
address = RSP_SegmentToPhysical( address );
|
|
|
|
|
2014-09-22 14:52:59 +00:00
|
|
|
if (gDP.colorImage.address != address || gDP.colorImage.width != width || gDP.colorImage.size != size) {
|
2013-06-29 15:46:27 +00:00
|
|
|
u32 height = 1;
|
2014-09-29 08:50:32 +00:00
|
|
|
if (width == VI.width)
|
|
|
|
height = VI.height;
|
2014-10-03 06:28:11 +00:00
|
|
|
else if (width == gDP.scissor.lrx && width == gSP.viewport.width) {
|
2013-06-29 15:46:27 +00:00
|
|
|
height = max(gDP.scissor.lry, gSP.viewport.height);
|
2014-10-03 06:28:11 +00:00
|
|
|
height = min(height, VI.height);
|
|
|
|
} else if (width == gDP.scissor.lrx)
|
2013-06-29 15:46:27 +00:00
|
|
|
height = gDP.scissor.lry;
|
2014-10-21 08:28:03 +00:00
|
|
|
else if (width <= 64)
|
|
|
|
height = width;
|
2013-06-04 16:00:03 +00:00
|
|
|
else
|
2013-06-29 15:46:27 +00:00
|
|
|
height = gSP.viewport.height;
|
2013-06-02 15:20:44 +00:00
|
|
|
|
2014-09-22 14:52:59 +00:00
|
|
|
if (config.frameBufferEmulation.enable) // && address != gDP.depthImageAddress)
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
2013-06-01 13:10:30 +00:00
|
|
|
//if (gDP.colorImage.changed)
|
2014-09-28 06:09:03 +00:00
|
|
|
frameBufferList().saveBuffer(address, (u16)format, (u16)size, (u16)width, height, false);
|
2014-10-17 04:51:09 +00:00
|
|
|
gDP.colorImage.height = 0;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
//OGL_ClearDepthBuffer();
|
2013-06-29 15:46:27 +00:00
|
|
|
} else
|
|
|
|
gDP.colorImage.height = height;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gDP.colorImage.format = format;
|
|
|
|
gDP.colorImage.size = size;
|
|
|
|
gDP.colorImage.width = width;
|
2013-06-01 13:10:30 +00:00
|
|
|
gDP.colorImage.address = address;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetColorImage( %s, %s, %i, 0x%08X );\n",
|
|
|
|
ImageFormatText[gDP.colorImage.format],
|
|
|
|
ImageSizeText[gDP.colorImage.size],
|
|
|
|
gDP.colorImage.width,
|
|
|
|
gDP.colorImage.address );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-10-10 15:04:08 +00:00
|
|
|
void gDPSetTextureImage(u32 format, u32 size, u32 width, u32 address)
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
|
|
|
gDP.textureImage.format = format;
|
|
|
|
gDP.textureImage.size = size;
|
|
|
|
gDP.textureImage.width = width;
|
2014-10-10 15:04:08 +00:00
|
|
|
gDP.textureImage.address = RSP_SegmentToPhysical(address);
|
2013-04-05 06:13:26 +00:00
|
|
|
gDP.textureImage.bpl = gDP.textureImage.width << gDP.textureImage.size >> 1;
|
2014-10-10 15:04:08 +00:00
|
|
|
if (gSP.DMAOffsets.tex_offset != 0) {
|
|
|
|
if (format == G_IM_FMT_RGBA) {
|
|
|
|
u16 * t = (u16*)(RDRAM + gSP.DMAOffsets.tex_offset);
|
|
|
|
gSP.DMAOffsets.tex_shift = t[gSP.DMAOffsets.tex_count ^ 1];
|
|
|
|
gDP.textureImage.address += gSP.DMAOffsets.tex_shift;
|
|
|
|
} else {
|
|
|
|
gSP.DMAOffsets.tex_offset = 0;
|
|
|
|
gSP.DMAOffsets.tex_shift = 0;
|
|
|
|
gSP.DMAOffsets.tex_count = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 06:13:26 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTextureImage( %s, %s, %i, 0x%08X );\n",
|
|
|
|
ImageFormatText[gDP.textureImage.format],
|
|
|
|
ImageSizeText[gDP.textureImage.size],
|
|
|
|
gDP.textureImage.width,
|
|
|
|
gDP.textureImage.address );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetDepthImage( u32 address )
|
|
|
|
{
|
2013-06-04 16:00:03 +00:00
|
|
|
address = RSP_SegmentToPhysical( address );
|
2014-09-08 11:00:13 +00:00
|
|
|
depthBufferList().saveBuffer(address);
|
2013-06-04 16:00:03 +00:00
|
|
|
gDP.depthImageAddress = address;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetDepthImage( 0x%08X );\n", gDP.depthImageAddress );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetEnvColor( u32 r, u32 g, u32 b, u32 a )
|
|
|
|
{
|
|
|
|
gDP.envColor.r = r * 0.0039215689f;
|
|
|
|
gDP.envColor.g = g * 0.0039215689f;
|
|
|
|
gDP.envColor.b = b * 0.0039215689f;
|
|
|
|
gDP.envColor.a = a * 0.0039215689f;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_COMBINE_COLORS;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_COMBINE, "gDPSetEnvColor( %i, %i, %i, %i );\n",
|
|
|
|
r, g, b, a );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetBlendColor( u32 r, u32 g, u32 b, u32 a )
|
|
|
|
{
|
|
|
|
gDP.blendColor.r = r * 0.0039215689f;
|
|
|
|
gDP.blendColor.g = g * 0.0039215689f;
|
|
|
|
gDP.blendColor.b = b * 0.0039215689f;
|
|
|
|
gDP.blendColor.a = a * 0.0039215689f;
|
|
|
|
|
2014-05-01 17:35:16 +00:00
|
|
|
gDP.changed |= CHANGED_BLENDCOLOR;
|
2013-04-05 06:13:26 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetBlendColor( %i, %i, %i, %i );\n",
|
|
|
|
r, g, b, a );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetFogColor( u32 r, u32 g, u32 b, u32 a )
|
|
|
|
{
|
|
|
|
gDP.fogColor.r = r * 0.0039215689f;
|
|
|
|
gDP.fogColor.g = g * 0.0039215689f;
|
|
|
|
gDP.fogColor.b = b * 0.0039215689f;
|
|
|
|
gDP.fogColor.a = a * 0.0039215689f;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_FOGCOLOR;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetFogColor( %i, %i, %i, %i );\n",
|
|
|
|
r, g, b, a );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetFillColor( u32 c )
|
|
|
|
{
|
2013-06-04 15:41:56 +00:00
|
|
|
gDP.fillColor.color = c;
|
2013-04-22 05:19:52 +00:00
|
|
|
gDP.fillColor.z = (f32)_SHIFTR( c, 2, 14 );
|
|
|
|
gDP.fillColor.dz = (f32)_SHIFTR( c, 0, 2 );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPSetFillColor( 0x%08X );\n", c );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-06-04 15:41:56 +00:00
|
|
|
void gDPGetFillColor(f32 _fillColor[4])
|
|
|
|
{
|
|
|
|
const u32 c = gDP.fillColor.color;
|
|
|
|
if (gDP.colorImage.size < 3) {
|
|
|
|
_fillColor[0] = _SHIFTR( c, 11, 5 ) * 0.032258064f;
|
|
|
|
_fillColor[1] = _SHIFTR( c, 6, 5 ) * 0.032258064f;
|
|
|
|
_fillColor[2] = _SHIFTR( c, 1, 5 ) * 0.032258064f;
|
|
|
|
_fillColor[3] = (f32)_SHIFTR( c, 0, 1 );
|
|
|
|
} else {
|
|
|
|
_fillColor[0] = _SHIFTR( c, 24, 8 ) * 0.0039215686f;
|
|
|
|
_fillColor[1] = _SHIFTR( c, 16, 8 ) * 0.0039215686f;
|
|
|
|
_fillColor[2] = _SHIFTR( c, 8, 8 ) * 0.0039215686f;
|
|
|
|
_fillColor[3] = _SHIFTR( c, 0, 8 ) * 0.0039215686f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
void gDPSetPrimColor( u32 m, u32 l, u32 r, u32 g, u32 b, u32 a )
|
|
|
|
{
|
2013-05-21 04:12:11 +00:00
|
|
|
gDP.primColor.m = m * 0.0039215689f;
|
2013-04-05 06:13:26 +00:00
|
|
|
gDP.primColor.l = l * 0.0039215689f;
|
|
|
|
gDP.primColor.r = r * 0.0039215689f;
|
|
|
|
gDP.primColor.g = g * 0.0039215689f;
|
|
|
|
gDP.primColor.b = b * 0.0039215689f;
|
|
|
|
gDP.primColor.a = a * 0.0039215689f;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_COMBINE_COLORS;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_COMBINE, "gDPSetPrimColor( %i, %i, %i, %i, %i, %i );\n",
|
|
|
|
m, l, r, g, b, a );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetTile( u32 format, u32 size, u32 line, u32 tmem, u32 tile, u32 palette, u32 cmt, u32 cms, u32 maskt, u32 masks, u32 shiftt, u32 shifts )
|
|
|
|
{
|
|
|
|
if (((size == G_IM_SIZ_4b) || (size == G_IM_SIZ_8b)) && (format == G_IM_FMT_RGBA))
|
|
|
|
format = G_IM_FMT_CI;
|
|
|
|
|
|
|
|
gDP.tiles[tile].format = format;
|
|
|
|
gDP.tiles[tile].size = size;
|
|
|
|
gDP.tiles[tile].line = line;
|
|
|
|
gDP.tiles[tile].tmem = tmem;
|
|
|
|
gDP.tiles[tile].palette = palette;
|
|
|
|
gDP.tiles[tile].cmt = cmt;
|
|
|
|
gDP.tiles[tile].cms = cms;
|
|
|
|
gDP.tiles[tile].maskt = maskt;
|
|
|
|
gDP.tiles[tile].masks = masks;
|
|
|
|
gDP.tiles[tile].shiftt = shiftt;
|
|
|
|
gDP.tiles[tile].shifts = shifts;
|
|
|
|
|
|
|
|
if (!gDP.tiles[tile].masks) gDP.tiles[tile].clamps = 1;
|
2014-09-01 16:21:40 +00:00
|
|
|
if (!gDP.tiles[tile].maskt) gDP.tiles[tile].clampt = 1;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-06-08 08:05:04 +00:00
|
|
|
if (tile == gSP.texture.tile || tile == gSP.texture.tile + 1) {
|
2013-06-15 13:46:48 +00:00
|
|
|
u32 nTile = 7;
|
|
|
|
while(gDP.tiles[nTile].tmem != tmem && nTile > gSP.texture.tile + 1)
|
|
|
|
--nTile;
|
|
|
|
if (nTile > gSP.texture.tile + 1) {
|
|
|
|
gDP.tiles[tile].textureMode = gDP.tiles[nTile].textureMode;
|
|
|
|
gDP.tiles[tile].loadType = gDP.tiles[nTile].loadType;
|
|
|
|
gDP.tiles[tile].frameBuffer = gDP.tiles[nTile].frameBuffer;
|
|
|
|
gDP.tiles[tile].imageAddress = gDP.tiles[nTile].imageAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTile( %s, %s, %i, %i, %i, %i, %s%s, %s%s, %i, %i, %i, %i );\n",
|
|
|
|
ImageFormatText[format],
|
|
|
|
ImageSizeText[size],
|
|
|
|
line,
|
|
|
|
tmem,
|
|
|
|
tile,
|
|
|
|
palette,
|
|
|
|
cmt & G_TX_MIRROR ? "G_TX_MIRROR" : "G_TX_NOMIRROR",
|
|
|
|
cmt & G_TX_CLAMP ? " | G_TX_CLAMP" : "",
|
|
|
|
cms & G_TX_MIRROR ? "G_TX_MIRROR" : "G_TX_NOMIRROR",
|
|
|
|
cms & G_TX_CLAMP ? " | G_TX_CLAMP" : "",
|
|
|
|
maskt,
|
|
|
|
masks,
|
|
|
|
shiftt,
|
|
|
|
shifts );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void gDPSetTileSize( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt )
|
|
|
|
{
|
|
|
|
gDP.tiles[tile].uls = _SHIFTR( uls, 2, 10 );
|
|
|
|
gDP.tiles[tile].ult = _SHIFTR( ult, 2, 10 );
|
|
|
|
gDP.tiles[tile].lrs = _SHIFTR( lrs, 2, 10 );
|
|
|
|
gDP.tiles[tile].lrt = _SHIFTR( lrt, 2, 10 );
|
|
|
|
|
|
|
|
gDP.tiles[tile].fuls = _FIXED2FLOAT( uls, 2 );
|
|
|
|
gDP.tiles[tile].fult = _FIXED2FLOAT( ult, 2 );
|
|
|
|
gDP.tiles[tile].flrs = _FIXED2FLOAT( lrs, 2 );
|
|
|
|
gDP.tiles[tile].flrt = _FIXED2FLOAT( lrt, 2 );
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_TILE;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPSetTileSize( %i, %.2f, %.2f, %.2f, %.2f );\n",
|
|
|
|
tile,
|
|
|
|
gDP.tiles[tile].fuls,
|
|
|
|
gDP.tiles[tile].fult,
|
|
|
|
gDP.tiles[tile].flrs,
|
|
|
|
gDP.tiles[tile].flrt );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-06-15 13:46:48 +00:00
|
|
|
static
|
2013-08-10 11:10:44 +00:00
|
|
|
bool CheckForFrameBufferTexture(u32 _address, u32 _bytes)
|
2013-06-15 13:46:48 +00:00
|
|
|
{
|
2013-08-10 11:10:44 +00:00
|
|
|
gDP.loadTile->textureMode = TEXTUREMODE_NORMAL;
|
|
|
|
gDP.loadTile->frameBuffer = NULL;
|
|
|
|
gDP.changed |= CHANGED_TMEM;
|
2014-04-05 15:36:20 +00:00
|
|
|
if (!config.frameBufferEmulation.enable)
|
2013-08-10 11:10:44 +00:00
|
|
|
return false;
|
|
|
|
|
2014-09-08 11:01:22 +00:00
|
|
|
FrameBuffer *pBuffer = frameBufferList().findBuffer(_address);
|
2013-08-10 11:10:44 +00:00
|
|
|
bool bRes = pBuffer != NULL;
|
|
|
|
if ((bRes)
|
|
|
|
//&& ((*(u32*)&RDRAM[pBuffer->startAddress] & 0xFFFEFFFE) == (pBuffer->startAddress & 0xFFFEFFFE)) // Does not work for Jet Force Gemini
|
|
|
|
)
|
|
|
|
{
|
|
|
|
const u32 texEndAddress = _address + _bytes - 1;
|
2014-09-08 11:01:22 +00:00
|
|
|
const u32 bufEndAddress = pBuffer->m_startAddress + (((pBuffer->m_width * (int)gDP.scissor.lry) << pBuffer->m_size >> 1) - 1);
|
|
|
|
if (_address > pBuffer->m_startAddress && texEndAddress > bufEndAddress) {
|
2013-08-10 11:10:44 +00:00
|
|
|
// FrameBuffer_RemoveBuffer(pBuffer->startAddress);
|
|
|
|
bRes = false;
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:01:22 +00:00
|
|
|
if (bRes && gDP.loadTile->loadType == LOADTYPE_TILE && gDP.textureImage.width != pBuffer->m_width && gDP.textureImage.size != pBuffer->m_size) {
|
2013-08-10 11:10:44 +00:00
|
|
|
//FrameBuffer_RemoveBuffer(pBuffer->startAddress); // Does not work with Zelda MM
|
|
|
|
bRes = false;
|
|
|
|
}
|
|
|
|
|
2014-09-08 11:01:22 +00:00
|
|
|
if (bRes && pBuffer->m_cleared && pBuffer->m_size == 2
|
2014-06-26 15:12:32 +00:00
|
|
|
&& !config.frameBufferEmulation.copyToRDRAM
|
2014-09-08 11:01:22 +00:00
|
|
|
&& (!config.frameBufferEmulation.copyDepthToRDRAM || pBuffer->m_fillcolor != DEPTH_CLEAR_COLOR)
|
2014-06-26 15:12:32 +00:00
|
|
|
) {
|
2014-09-08 11:01:22 +00:00
|
|
|
const u32 endAddress = min(texEndAddress, pBuffer->m_endAddress);
|
|
|
|
const u32 color = pBuffer->m_fillcolor&0xFFFEFFFE;
|
2013-08-10 11:10:44 +00:00
|
|
|
for (u32 i = _address + 4; i < endAddress; i+=4) {
|
|
|
|
if (((*(u32*)&RDRAM[i])&0xFFFEFFFE) != color) {
|
2014-09-08 11:01:22 +00:00
|
|
|
frameBufferList().removeBuffer(pBuffer->m_startAddress);
|
2013-08-10 11:10:44 +00:00
|
|
|
bRes = false;
|
|
|
|
break;
|
|
|
|
}
|
2013-06-25 17:18:01 +00:00
|
|
|
}
|
2013-08-10 11:10:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bRes) {
|
2014-09-08 11:01:22 +00:00
|
|
|
pBuffer->m_pLoadTile = gDP.loadTile;
|
2013-06-15 13:46:48 +00:00
|
|
|
gDP.loadTile->frameBuffer = pBuffer;
|
|
|
|
gDP.loadTile->textureMode = TEXTUREMODE_FRAMEBUFFER;
|
2013-08-10 11:10:44 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-15 13:46:48 +00:00
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
for (int nTile = gSP.texture.tile; nTile < 6; ++nTile) {
|
|
|
|
if (gDP.tiles[nTile].tmem == gDP.loadTile->tmem) {
|
|
|
|
gDPTile & curTile = gDP.tiles[nTile];
|
|
|
|
curTile.textureMode = gDP.loadTile->textureMode;
|
|
|
|
curTile.loadType = gDP.loadTile->loadType;
|
|
|
|
curTile.frameBuffer = gDP.loadTile->frameBuffer;
|
|
|
|
curTile.imageAddress = gDP.loadTile->imageAddress;
|
2013-06-15 13:46:48 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-10 11:10:44 +00:00
|
|
|
return bRes;
|
2013-06-15 13:46:48 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
//****************************************************************
|
|
|
|
// LoadTile for 32bit RGBA texture
|
|
|
|
// Based on sources of angrylion's software plugin.
|
|
|
|
//
|
|
|
|
void gDPLoadTile32b(u32 uls, u32 ult, u32 lrs, u32 lrt)
|
|
|
|
{
|
|
|
|
const u32 width = lrs - uls + 1;
|
|
|
|
const u32 height = lrt - ult + 1;
|
|
|
|
const u32 line = gDP.loadTile->line << 2;
|
|
|
|
const u32 tbase = gDP.loadTile->tmem << 2;
|
|
|
|
const u32 addr = gDP.textureImage.address >> 2;
|
|
|
|
const u32 * src = (const u32*)RDRAM;
|
|
|
|
u16 * tmem16 = (u16*)TMEM;
|
|
|
|
u32 c, ptr, tline, s, xorval;
|
|
|
|
|
|
|
|
for (u32 j = 0; j < height; ++j) {
|
|
|
|
tline = tbase + line * j;
|
|
|
|
s = ((j + ult) * gDP.textureImage.width) + uls;
|
|
|
|
xorval = (j & 1) ? 3 : 1;
|
|
|
|
for (u32 i = 0; i < width; ++i) {
|
|
|
|
c = src[addr + s + i];
|
|
|
|
ptr = ((tline + i) ^ xorval) & 0x3ff;
|
|
|
|
tmem16[ptr] = c >> 16;
|
|
|
|
tmem16[ptr | 0x400] = c & 0xffff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
void gDPLoadTile(u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt)
|
|
|
|
{
|
2013-04-05 06:13:26 +00:00
|
|
|
u32 address, height, bpl, line, y;
|
|
|
|
u64 *dest;
|
|
|
|
u8 *src;
|
|
|
|
|
|
|
|
gDPSetTileSize( tile, uls, ult, lrs, lrt );
|
|
|
|
gDP.loadTile = &gDP.tiles[tile];
|
2013-06-15 13:46:48 +00:00
|
|
|
gDP.loadTile->loadType = LOADTYPE_TILE;
|
|
|
|
gDP.loadTile->imageAddress = gDP.textureImage.address;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
if (gDP.loadTile->line == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
address = gDP.textureImage.address + gDP.loadTile->ult * gDP.textureImage.bpl + (gDP.loadTile->uls << gDP.textureImage.size >> 1);
|
|
|
|
dest = &TMEM[gDP.loadTile->tmem];
|
|
|
|
bpl = (gDP.loadTile->lrs - gDP.loadTile->uls + 1) << gDP.loadTile->size >> 1;
|
|
|
|
height = gDP.loadTile->lrt - gDP.loadTile->ult + 1;
|
2013-08-10 11:10:44 +00:00
|
|
|
const u32 bytes = height * bpl;
|
2013-04-05 06:13:26 +00:00
|
|
|
src = &RDRAM[address];
|
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
if (((address + bytes) > RDRAMSize) ||
|
|
|
|
(((gDP.loadTile->tmem << 3) + bytes) > 4096)) // Stay within TMEM
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_ERROR | DEBUG_TEXTURE, "// Attempting to load texture tile out of range\n" );
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadTile( %i, %i, %i, %i, %i );\n",
|
|
|
|
tile, gDP.loadTile->uls, gDP.loadTile->ult, gDP.loadTile->lrs, gDP.loadTile->lrt );
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
if (CheckForFrameBufferTexture(address, bytes))
|
2013-06-15 13:46:48 +00:00
|
|
|
return;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
if (gDP.loadTile->size == G_IM_SIZ_32b)
|
|
|
|
gDPLoadTile32b(gDP.loadTile->uls, gDP.loadTile->ult, gDP.loadTile->lrs, gDP.loadTile->lrt);
|
|
|
|
else {
|
2013-04-05 06:13:26 +00:00
|
|
|
line = gDP.loadTile->line;
|
2014-10-28 05:26:45 +00:00
|
|
|
for (y = 0; y < height; ++y) {
|
|
|
|
UnswapCopy(src, dest, bpl);
|
|
|
|
if (y & 1) DWordInterleave(dest, line);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
src += gDP.textureImage.bpl;
|
|
|
|
dest += line;
|
|
|
|
}
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadTile( %i, %i, %i, %i, %i );\n",
|
|
|
|
tile, gDP.loadTile->uls, gDP.loadTile->ult, gDP.loadTile->lrs, gDP.loadTile->lrt );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
//****************************************************************
|
|
|
|
// LoadBlock for 32bit RGBA texture
|
|
|
|
// Based on sources of angrylion's software plugin.
|
|
|
|
//
|
2014-11-10 15:22:58 +00:00
|
|
|
void gDPLoadBlock32(u32 uls,u32 lrs, u32 dxt)
|
2014-10-28 05:26:45 +00:00
|
|
|
{
|
|
|
|
const u32 * src = (const u32*)RDRAM;
|
|
|
|
const u32 tb = gDP.loadTile->tmem << 2;
|
|
|
|
const u32 line = gDP.loadTile->line << 2;
|
|
|
|
|
|
|
|
u16 *tmem16 = (u16*)TMEM;
|
|
|
|
u32 addr = gDP.loadTile->imageAddress >> 2;
|
|
|
|
u32 width = (lrs - uls + 1) << 2;
|
2014-11-04 12:59:53 +00:00
|
|
|
if (width == 4) // lr_s == 0, 1x1 texture
|
|
|
|
width = 1;
|
|
|
|
else if (width & 7)
|
2014-10-28 05:26:45 +00:00
|
|
|
width = (width & (~7)) + 8;
|
|
|
|
|
|
|
|
if (dxt != 0) {
|
|
|
|
u32 j = 0;
|
|
|
|
u32 t = 0;
|
|
|
|
u32 oldt = 0;
|
|
|
|
u32 ptr;
|
|
|
|
|
|
|
|
u32 c = 0;
|
|
|
|
for (u32 i = 0; i < width; i += 2) {
|
|
|
|
oldt = t;
|
|
|
|
t = ((j >> 11) & 1) ? 3 : 1;
|
|
|
|
if (t != oldt)
|
|
|
|
i += line;
|
|
|
|
ptr = ((tb + i) ^ t) & 0x3ff;
|
|
|
|
c = src[addr + i];
|
|
|
|
tmem16[ptr] = c >> 16;
|
|
|
|
tmem16[ptr | 0x400] = c & 0xffff;
|
|
|
|
ptr = ((tb + i + 1) ^ t) & 0x3ff;
|
|
|
|
c = src[addr + i + 1];
|
|
|
|
tmem16[ptr] = c >> 16;
|
|
|
|
tmem16[ptr | 0x400] = c & 0xffff;
|
|
|
|
j += dxt;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
u32 c, ptr;
|
|
|
|
for (u32 i = 0; i < width; i++) {
|
|
|
|
ptr = ((tb + i) ^ 1) & 0x3ff;
|
|
|
|
c = src[addr + i];
|
|
|
|
tmem16[ptr] = c >> 16;
|
|
|
|
tmem16[ptr | 0x400] = c & 0xffff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPLoadBlock(u32 tile, u32 uls, u32 ult, u32 lrs, u32 dxt)
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
|
|
|
gDPSetTileSize( tile, uls, ult, lrs, dxt );
|
|
|
|
gDP.loadTile = &gDP.tiles[tile];
|
2013-06-15 13:46:48 +00:00
|
|
|
gDP.loadTile->loadType = LOADTYPE_BLOCK;
|
2014-10-10 15:04:08 +00:00
|
|
|
|
|
|
|
if (gSP.DMAOffsets.tex_offset != 0) {
|
|
|
|
if (gSP.DMAOffsets.tex_shift % (((lrs>>2) + 1) << 3)) {
|
|
|
|
gDP.textureImage.address -= gSP.DMAOffsets.tex_shift;
|
|
|
|
gSP.DMAOffsets.tex_offset = 0;
|
|
|
|
gSP.DMAOffsets.tex_shift = 0;
|
|
|
|
gSP.DMAOffsets.tex_count = 0;
|
|
|
|
} else
|
|
|
|
++gSP.DMAOffsets.tex_count;
|
|
|
|
}
|
2013-06-15 13:46:48 +00:00
|
|
|
gDP.loadTile->imageAddress = gDP.textureImage.address;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-09-01 16:21:40 +00:00
|
|
|
u32 bytes = (lrs + 1) << gDP.loadTile->size >> 1;
|
2013-04-05 06:13:26 +00:00
|
|
|
u32 address = gDP.textureImage.address + ult * gDP.textureImage.bpl + (uls << gDP.textureImage.size >> 1);
|
|
|
|
|
2014-09-01 16:21:40 +00:00
|
|
|
if ((bytes == 0) ||
|
|
|
|
((address + bytes) > RDRAMSize) ||
|
2013-04-05 06:13:26 +00:00
|
|
|
(((gDP.loadTile->tmem << 3) + bytes) > 4096))
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_ERROR | DEBUG_TEXTURE, "// Attempting to load texture block out of range\n" );
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadBlock( %i, %i, %i, %i, %i );\n",
|
|
|
|
tile, uls, ult, lrs, dxt );
|
|
|
|
#endif
|
|
|
|
// bytes = min( bytes, min( RDRAMSize - gDP.textureImage.address, 4096 - (gDP.loadTile->tmem << 3) ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
gDP.loadTile->textureMode = TEXTUREMODE_NORMAL;
|
|
|
|
gDP.loadTile->frameBuffer = NULL;
|
|
|
|
gDP.changed |= CHANGED_TMEM;
|
2014-10-18 11:04:30 +00:00
|
|
|
CheckForFrameBufferTexture(address, bytes); // Load data to TMEM even if FB texture is found. See comment to texturedRectDepthBufferCopy
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
if (gDP.loadTile->size == G_IM_SIZ_32b)
|
2014-11-10 15:22:58 +00:00
|
|
|
gDPLoadBlock32(gDP.loadTile->uls, gDP.loadTile->lrs, dxt);
|
2014-10-28 06:12:30 +00:00
|
|
|
else if (gDP.loadTile->format == G_IM_FMT_YUV)
|
|
|
|
memcpy(TMEM, &RDRAM[address], bytes); // HACK!
|
2014-10-28 05:26:45 +00:00
|
|
|
else {
|
|
|
|
u64* src = (u64*)&RDRAM[address];
|
|
|
|
u64* dest = &TMEM[gDP.loadTile->tmem];
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
if (dxt > 0) {
|
|
|
|
u32 line = (2047 + dxt) / dxt;
|
|
|
|
u32 bpl = line << 3;
|
|
|
|
u32 height = bytes / bpl;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
for (u32 y = 0; y < height; ++y) {
|
|
|
|
UnswapCopy(src, dest, bpl);
|
|
|
|
if (y & 1) DWordInterleave(dest, line);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2014-10-28 05:26:45 +00:00
|
|
|
src += line;
|
|
|
|
dest += line;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
UnswapCopy(src, dest, bytes);
|
|
|
|
}
|
2013-04-05 06:13:26 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadBlock( %i, %i, %i, %i, %i );\n",
|
|
|
|
tile, uls, ult, lrs, dxt );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPLoadTLUT( u32 tile, u32 uls, u32 ult, u32 lrs, u32 lrt )
|
|
|
|
{
|
|
|
|
gDPSetTileSize( tile, uls, ult, lrs, lrt );
|
2014-10-25 08:37:44 +00:00
|
|
|
const u16 count = (u16)((gDP.tiles[tile].lrs - gDP.tiles[tile].uls + 1) * (gDP.tiles[tile].lrt - gDP.tiles[tile].ult + 1));
|
2014-09-01 16:21:40 +00:00
|
|
|
u32 address = gDP.textureImage.address + gDP.tiles[tile].ult * gDP.textureImage.bpl + (gDP.tiles[tile].uls << gDP.textureImage.size >> 1);
|
2013-04-22 05:19:52 +00:00
|
|
|
u16 pal = (u16)((gDP.tiles[tile].tmem - 256) >> 4);
|
2014-10-25 08:37:44 +00:00
|
|
|
u16 *dest = (u16*)&TMEM[gDP.tiles[tile].tmem];
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
int i = 0;
|
2014-09-22 14:52:59 +00:00
|
|
|
while (i < count) {
|
|
|
|
for (u16 j = 0; (j < 16) && (i < count); ++j, ++i) {
|
2014-10-25 08:37:44 +00:00
|
|
|
*dest = swapword(*(u16*)(RDRAM + (address ^ 2)));
|
|
|
|
address += 2;
|
2013-04-05 06:13:26 +00:00
|
|
|
dest += 4;
|
|
|
|
}
|
2014-09-01 16:21:40 +00:00
|
|
|
|
2014-09-22 14:52:59 +00:00
|
|
|
gDP.paletteCRC16[pal] = CRC_CalculatePalette(0xFFFFFFFF, &TMEM[256 + (pal << 4)], 16);
|
2014-10-25 08:37:44 +00:00
|
|
|
++pal;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
2014-09-22 14:52:59 +00:00
|
|
|
gDP.paletteCRC256 = CRC_Calculate(0xFFFFFFFF, gDP.paletteCRC16, 64);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
gDP.changed |= CHANGED_TMEM;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED | DEBUG_TEXTURE, "gDPLoadTLUT( %i, %i, %i, %i, %i );\n",
|
|
|
|
tile, gDP.tiles[tile].uls, gDP.tiles[tile].ult, gDP.tiles[tile].lrs, gDP.tiles[tile].lrt );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetScissor( u32 mode, f32 ulx, f32 uly, f32 lrx, f32 lry )
|
|
|
|
{
|
|
|
|
gDP.scissor.mode = mode;
|
|
|
|
gDP.scissor.ulx = ulx;
|
|
|
|
gDP.scissor.uly = uly;
|
|
|
|
gDP.scissor.lrx = lrx;
|
|
|
|
gDP.scissor.lry = lry;
|
|
|
|
|
|
|
|
gDP.changed |= CHANGED_SCISSOR;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_IGNORED, "gDPSetScissor( %s, %.2f, %.2f, %.2f, %.2f );\n",
|
|
|
|
ScissorModeText[gDP.scissor.mode],
|
|
|
|
gDP.scissor.ulx,
|
|
|
|
gDP.scissor.uly,
|
|
|
|
gDP.scissor.lrx,
|
|
|
|
gDP.scissor.lry );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
const bool g_bDepthClearOnly = false;
|
|
|
|
void gDPFillRDRAM(u32 address, s32 ulx, s32 uly, s32 lrx, s32 lry, u32 width, u32 size, u32 color )
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
2013-08-10 11:10:44 +00:00
|
|
|
if (g_bDepthClearOnly && color != DEPTH_CLEAR_COLOR)
|
|
|
|
return;
|
2014-09-08 11:01:22 +00:00
|
|
|
FrameBufferList & fbList = frameBufferList();
|
|
|
|
if (fbList.isFboMode()) {
|
|
|
|
fbList.getCurrent()->m_cleared = true;
|
|
|
|
fbList.getCurrent()->m_fillcolor = color;
|
2013-08-10 11:10:44 +00:00
|
|
|
}
|
2014-09-01 16:19:20 +00:00
|
|
|
ulx = min(max((float)ulx, gDP.scissor.ulx), gDP.scissor.lrx);
|
|
|
|
lrx = min(max((float)lrx, gDP.scissor.ulx), gDP.scissor.lrx);
|
|
|
|
uly = min(max((float)uly, gDP.scissor.uly), gDP.scissor.lry);
|
|
|
|
lry = min(max((float)lry, gDP.scissor.uly), gDP.scissor.lry);
|
2014-09-20 06:29:39 +00:00
|
|
|
const u32 stride = width << size >> 1;
|
|
|
|
const u32 lowerBound = address + lry*stride;
|
|
|
|
if (lowerBound > RDRAMSize)
|
|
|
|
lry -= (lowerBound - RDRAMSize) / stride;
|
2013-08-10 11:10:44 +00:00
|
|
|
u32 ci_width_in_dwords = width >> (3 - size);
|
|
|
|
ulx >>= (3 - size);
|
|
|
|
lrx >>= (3 - size);
|
|
|
|
u32 * dst = (u32*)(RDRAM + address);
|
|
|
|
dst += uly * ci_width_in_dwords;
|
|
|
|
for (u32 y = uly; y < lry; ++y) {
|
|
|
|
for (u32 x = ulx; x < lrx; ++x)
|
|
|
|
dst[x] = color;
|
|
|
|
dst += ci_width_in_dwords;
|
|
|
|
}
|
|
|
|
*(u32*)&RDRAM[address] = address;
|
|
|
|
}
|
2013-06-30 15:03:16 +00:00
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
void gDPFillRectangle( s32 ulx, s32 uly, s32 lrx, s32 lry )
|
|
|
|
{
|
2014-09-21 12:15:22 +00:00
|
|
|
OGLRender & render = video().getRender();
|
|
|
|
if (gDP.otherMode.cycleType == G_CYC_FILL) {
|
2014-09-22 14:52:59 +00:00
|
|
|
++lrx;
|
|
|
|
++lry;
|
2013-08-10 11:10:44 +00:00
|
|
|
}
|
2013-06-04 14:05:56 +00:00
|
|
|
if (gDP.depthImageAddress == gDP.colorImage.address) {
|
2013-06-30 15:03:16 +00:00
|
|
|
// Game may use depth texture as auxilary color texture. Example: Mario Tennis
|
|
|
|
// If color is not depth clear color, that is most likely the case
|
2013-08-10 11:10:44 +00:00
|
|
|
if (gDP.fillColor.color == DEPTH_CLEAR_COLOR) {
|
|
|
|
gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color);
|
2014-09-21 12:15:22 +00:00
|
|
|
render.clearDepthBuffer();
|
2013-06-30 15:03:16 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-10-24 13:49:07 +00:00
|
|
|
} else if (gDP.fillColor.color == DEPTH_CLEAR_COLOR && gDP.otherMode.cycleType == G_CYC_FILL) {
|
2014-09-08 11:00:13 +00:00
|
|
|
depthBufferList().saveBuffer(gDP.colorImage.address);
|
2013-08-10 11:10:44 +00:00
|
|
|
gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color);
|
2014-09-21 12:15:22 +00:00
|
|
|
render.clearDepthBuffer();
|
2013-04-05 06:13:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-04 15:41:56 +00:00
|
|
|
f32 fillColor[4];
|
|
|
|
gDPGetFillColor(fillColor);
|
2014-09-21 12:15:22 +00:00
|
|
|
if (gDP.otherMode.cycleType == G_CYC_FILL) {
|
|
|
|
if ((ulx == 0) && (uly == 0) && (lrx == gDP.scissor.lrx) && (lry == gDP.scissor.lry)) {
|
2013-08-10 11:10:44 +00:00
|
|
|
gDPFillRDRAM(gDP.colorImage.address, ulx, uly, lrx, lry, gDP.colorImage.width, gDP.colorImage.size, gDP.fillColor.color);
|
2014-09-21 12:15:22 +00:00
|
|
|
render.clearColorBuffer(fillColor);
|
2013-04-05 06:13:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-24 11:00:42 +00:00
|
|
|
f32 * pColor = fillColor;
|
|
|
|
if (gDP.otherMode.cycleType != G_CYC_FILL) {
|
|
|
|
if (gDP.combine.mux == EncodeCombineMode(0, 0, 0, SHADE, 0, 0, 0, SHADE, 0, 0, 0, SHADE, 0, 0, 0, SHADE))
|
|
|
|
memset(pColor, 0, sizeof(f32)* 4);
|
|
|
|
else
|
|
|
|
pColor = &gDP.blendColor.r;
|
|
|
|
}
|
|
|
|
render.drawRect(ulx, uly, lrx, lry, pColor);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
gDP.colorImage.changed = TRUE;
|
2014-09-26 04:32:40 +00:00
|
|
|
if (gDP.otherMode.cycleType == G_CYC_FILL) {
|
2014-10-21 09:22:23 +00:00
|
|
|
if (lry > (u32)gDP.scissor.lry)
|
|
|
|
gDP.colorImage.height = (u32)max(gDP.colorImage.height, (u32)gDP.scissor.lry);
|
2014-09-26 04:32:40 +00:00
|
|
|
else
|
|
|
|
gDP.colorImage.height = (u32)max((s32)gDP.colorImage.height, lry);
|
|
|
|
} else
|
2013-12-12 15:29:17 +00:00
|
|
|
gDP.colorImage.height = max( gDP.colorImage.height, (u32)gDP.scissor.lry );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPFillRectangle( %i, %i, %i, %i );\n",
|
|
|
|
ulx, uly, lrx, lry );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetConvert( s32 k0, s32 k1, s32 k2, s32 k3, s32 k4, s32 k5 )
|
|
|
|
{
|
2014-10-28 04:09:43 +00:00
|
|
|
// angrylion's macro
|
|
|
|
#define SRA(exp, sa) ((signed)(exp) >> (sa))
|
|
|
|
#define SIGN(i, b) SRA((i) << (32 - (b)), (32 - (b)))
|
|
|
|
|
|
|
|
gDP.convert.k0 = SIGN(k0, 9);
|
|
|
|
gDP.convert.k1 = SIGN(k1, 9);
|
|
|
|
gDP.convert.k2 = SIGN(k2, 9);
|
|
|
|
gDP.convert.k3 = SIGN(k3, 9);
|
|
|
|
gDP.convert.k4 = SIGN(k4, 9);
|
|
|
|
gDP.convert.k5 = SIGN(k5, 9);
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetKeyR( u32 cR, u32 sR, u32 wR )
|
|
|
|
{
|
|
|
|
gDP.key.center.r = cR * 0.0039215689f;;
|
|
|
|
gDP.key.scale.r = sR * 0.0039215689f;;
|
|
|
|
gDP.key.width.r = wR * 0.0039215689f;;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPSetKeyGB(u32 cG, u32 sG, u32 wG, u32 cB, u32 sB, u32 wB )
|
|
|
|
{
|
|
|
|
gDP.key.center.g = cG * 0.0039215689f;;
|
|
|
|
gDP.key.scale.g = sG * 0.0039215689f;;
|
|
|
|
gDP.key.width.g = wG * 0.0039215689f;;
|
|
|
|
gDP.key.center.b = cB * 0.0039215689f;;
|
|
|
|
gDP.key.scale.b = sB * 0.0039215689f;;
|
|
|
|
gDP.key.width.b = wB * 0.0039215689f;;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTextureRectangle( f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, f32 s, f32 t, f32 dsdx, f32 dtdy )
|
|
|
|
{
|
2014-09-22 14:52:59 +00:00
|
|
|
if (gDP.otherMode.cycleType == G_CYC_COPY) {
|
2013-04-05 06:13:26 +00:00
|
|
|
dsdx = 1.0f;
|
|
|
|
lrx += 1.0f;
|
|
|
|
lry += 1.0f;
|
|
|
|
}
|
|
|
|
|
2013-12-02 06:10:33 +00:00
|
|
|
gDPTile *textureTileOrg[2];
|
|
|
|
textureTileOrg[0] = gSP.textureTile[0];
|
|
|
|
textureTileOrg[1] = gSP.textureTile[1];
|
2013-04-05 06:13:26 +00:00
|
|
|
gSP.textureTile[0] = &gDP.tiles[tile];
|
2014-11-03 15:01:12 +00:00
|
|
|
gSP.textureTile[1] = &gDP.tiles[(tile + 1) & 7];
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2013-06-15 13:46:48 +00:00
|
|
|
if (gSP.textureTile[0]->textureMode == TEXTUREMODE_NORMAL)
|
|
|
|
gSP.textureTile[0]->textureMode = TEXTUREMODE_TEXRECT;
|
|
|
|
if (gSP.textureTile[1]->textureMode == TEXTUREMODE_NORMAL)
|
|
|
|
gSP.textureTile[1]->textureMode = TEXTUREMODE_TEXRECT;
|
|
|
|
|
2013-06-13 18:55:51 +00:00
|
|
|
// HACK ALERT!
|
|
|
|
if ((int(s) == 512) && (gDP.colorImage.width < 512))
|
|
|
|
s = 0.0f;
|
|
|
|
|
2013-12-02 06:10:33 +00:00
|
|
|
f32 lrs, lrt;
|
2014-09-22 14:52:59 +00:00
|
|
|
if (RSP.cmd == G_TEXRECTFLIP) {
|
2013-12-02 06:10:33 +00:00
|
|
|
lrs = s + (lry - uly - 1) * dtdy;
|
|
|
|
lrt = t + (lrx - ulx - 1) * dsdx;
|
2014-09-22 14:52:59 +00:00
|
|
|
} else {
|
2013-12-02 06:10:33 +00:00
|
|
|
lrs = s + (lrx - ulx - 1) * dsdx;
|
|
|
|
lrt = t + (lry - uly - 1) * dtdy;
|
|
|
|
}
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2013-04-22 05:19:52 +00:00
|
|
|
gDP.texRect.width = (u32)(max( lrs, s ) + dsdx);
|
|
|
|
gDP.texRect.height = (u32)(max( lrt, t ) + dtdy);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
2013-12-02 06:10:33 +00:00
|
|
|
float tmp;
|
2014-09-22 14:52:59 +00:00
|
|
|
if (lrs < s) {
|
2013-12-02 06:10:33 +00:00
|
|
|
tmp = ulx; ulx = lrx; lrx = tmp;
|
|
|
|
tmp = s; s = lrs; lrs = tmp;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
2014-09-22 14:52:59 +00:00
|
|
|
if (lrt < t) {
|
2013-12-02 06:10:33 +00:00
|
|
|
tmp = uly; uly = lry; lry = tmp;
|
|
|
|
tmp = t; t = lrt; lrt = tmp;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 15:06:19 +00:00
|
|
|
OGLRender::TexturedRectParams params(ulx, uly, lrx, lry, s, t, lrs, lrt, (RSP.cmd == G_TEXRECTFLIP));
|
|
|
|
video().getRender().drawTexturedRect(params);
|
2013-12-02 06:10:33 +00:00
|
|
|
|
|
|
|
gSP.textureTile[0] = textureTileOrg[0];
|
|
|
|
gSP.textureTile[1] = textureTileOrg[1];
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
gDP.colorImage.changed = TRUE;
|
2014-09-29 08:43:22 +00:00
|
|
|
if (gDP.colorImage.width < 64)
|
|
|
|
gDP.colorImage.height = (u32)max( (f32)gDP.colorImage.height, lry );
|
2013-08-10 11:10:44 +00:00
|
|
|
else
|
|
|
|
gDP.colorImage.height = max( gDP.colorImage.height, (u32)gDP.scissor.lry );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPTextureRectangle( %f, %f, %f, %f, %i, %i, %f, %f, %f, %f );\n",
|
|
|
|
ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTextureRectangleFlip( f32 ulx, f32 uly, f32 lrx, f32 lry, s32 tile, f32 s, f32 t, f32 dsdx, f32 dtdy )
|
|
|
|
{
|
2013-12-02 06:10:33 +00:00
|
|
|
gDPTextureRectangle( ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2013-12-02 06:10:33 +00:00
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPTextureRectangleFlip( %f, %f, %f, %f, %i, %f, %f, %f, %f);\n",
|
|
|
|
ulx, uly, lrx, lry, tile, s, t, dsdx, dtdy );
|
2013-04-05 06:13:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPFullSync()
|
|
|
|
{
|
|
|
|
*REG.MI_INTR |= MI_INTR_DP;
|
|
|
|
|
|
|
|
CheckInterrupts();
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "gDPFullSync();\n" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTileSync()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_IGNORED | DEBUG_TEXTURE, "gDPTileSync();\n" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPPipeSync()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_IGNORED, "gDPPipeSync();\n" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPLoadSync()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_IGNORED, "gDPLoadSync();\n" );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPNoOp()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_IGNORED, "gDPNoOp();\n" );
|
|
|
|
#endif
|
|
|
|
}
|
2014-10-07 10:59:54 +00:00
|
|
|
|
|
|
|
/*******************************************
|
|
|
|
* Low level triangle *
|
|
|
|
*******************************************
|
|
|
|
* based on sources of ziggy's z64 *
|
|
|
|
*******************************************/
|
|
|
|
|
|
|
|
void gDPLLETriangle(u32 _w1, u32 _w2, int _shade, int _texture, int _zbuffer, u32 * _pRdpCmd)
|
|
|
|
{
|
|
|
|
const u32 tile = _SHIFTR(_w1, 16, 3);
|
|
|
|
gDPTile *textureTileOrg[2];
|
|
|
|
textureTileOrg[0] = gSP.textureTile[0];
|
|
|
|
textureTileOrg[1] = gSP.textureTile[1];
|
|
|
|
gSP.textureTile[0] = &gDP.tiles[tile];
|
2014-11-03 15:01:12 +00:00
|
|
|
gSP.textureTile[1] = &gDP.tiles[(tile + 1) & 7];
|
2014-10-07 10:59:54 +00:00
|
|
|
|
|
|
|
int j;
|
|
|
|
int xleft, xright, xleft_inc, xright_inc;
|
|
|
|
int r, g, b, a, z, s, t, w;
|
|
|
|
int drdx = 0, dgdx = 0, dbdx = 0, dadx = 0, dzdx = 0, dsdx = 0, dtdx = 0, dwdx = 0;
|
|
|
|
int drde = 0, dgde = 0, dbde = 0, dade = 0, dzde = 0, dsde = 0, dtde = 0, dwde = 0;
|
|
|
|
int flip = (_w1 & 0x800000) ? 1 : 0;
|
|
|
|
|
|
|
|
s32 yl, ym, yh;
|
|
|
|
s32 xl, xm, xh;
|
|
|
|
s32 dxldy, dxhdy, dxmdy;
|
|
|
|
u32 w3, w4, w5, w6, w7, w8;
|
|
|
|
|
|
|
|
u32 * shade_base = _pRdpCmd + 8;
|
|
|
|
u32 * texture_base = _pRdpCmd + 8;
|
|
|
|
u32 * zbuffer_base = _pRdpCmd + 8;
|
|
|
|
|
|
|
|
if (_shade != 0) {
|
|
|
|
texture_base += 16;
|
|
|
|
zbuffer_base += 16;
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
zbuffer_base += 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
w3 = _pRdpCmd[2];
|
|
|
|
w4 = _pRdpCmd[3];
|
|
|
|
w5 = _pRdpCmd[4];
|
|
|
|
w6 = _pRdpCmd[5];
|
|
|
|
w7 = _pRdpCmd[6];
|
|
|
|
w8 = _pRdpCmd[7];
|
|
|
|
|
|
|
|
yl = (_w1 & 0x3fff);
|
|
|
|
ym = ((_w2 >> 16) & 0x3fff);
|
|
|
|
yh = ((_w2 >> 0) & 0x3fff);
|
|
|
|
xl = (s32)(w3);
|
|
|
|
xh = (s32)(w5);
|
|
|
|
xm = (s32)(w7);
|
|
|
|
dxldy = (s32)(w4);
|
|
|
|
dxhdy = (s32)(w6);
|
|
|
|
dxmdy = (s32)(w8);
|
|
|
|
|
|
|
|
if (yl & (0x800<<2)) yl |= 0xfffff000<<2;
|
|
|
|
if (ym & (0x800<<2)) ym |= 0xfffff000<<2;
|
|
|
|
if (yh & (0x800<<2)) yh |= 0xfffff000<<2;
|
|
|
|
|
|
|
|
yh &= ~3;
|
|
|
|
|
|
|
|
r = 0xff; g = 0xff; b = 0xff; a = 0xff; z = 0xffff0000; s = 0; t = 0; w = 0x30000;
|
|
|
|
|
|
|
|
if (_shade != 0) {
|
|
|
|
r = (shade_base[0] & 0xffff0000) | ((shade_base[+4 ] >> 16) & 0x0000ffff);
|
|
|
|
g = ((shade_base[0 ] << 16) & 0xffff0000) | (shade_base[4 ] & 0x0000ffff);
|
|
|
|
b = (shade_base[1 ] & 0xffff0000) | ((shade_base[5 ] >> 16) & 0x0000ffff);
|
|
|
|
a = ((shade_base[1 ] << 16) & 0xffff0000) | (shade_base[5 ] & 0x0000ffff);
|
|
|
|
drdx = (shade_base[2 ] & 0xffff0000) | ((shade_base[6 ] >> 16) & 0x0000ffff);
|
|
|
|
dgdx = ((shade_base[2 ] << 16) & 0xffff0000) | (shade_base[6 ] & 0x0000ffff);
|
|
|
|
dbdx = (shade_base[3 ] & 0xffff0000) | ((shade_base[7 ] >> 16) & 0x0000ffff);
|
|
|
|
dadx = ((shade_base[3 ] << 16) & 0xffff0000) | (shade_base[7 ] & 0x0000ffff);
|
|
|
|
drde = (shade_base[8 ] & 0xffff0000) | ((shade_base[12] >> 16) & 0x0000ffff);
|
|
|
|
dgde = ((shade_base[8 ] << 16) & 0xffff0000) | (shade_base[12] & 0x0000ffff);
|
|
|
|
dbde = (shade_base[9 ] & 0xffff0000) | ((shade_base[13] >> 16) & 0x0000ffff);
|
|
|
|
dade = ((shade_base[9 ] << 16) & 0xffff0000) | (shade_base[13] & 0x0000ffff);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
s = (texture_base[0 ] & 0xffff0000) | ((texture_base[4 ] >> 16) & 0x0000ffff);
|
|
|
|
t = ((texture_base[0 ] << 16) & 0xffff0000) | (texture_base[4 ] & 0x0000ffff);
|
|
|
|
w = (texture_base[1 ] & 0xffff0000) | ((texture_base[5 ] >> 16) & 0x0000ffff);
|
|
|
|
// w = abs(w);
|
|
|
|
dsdx = (texture_base[2 ] & 0xffff0000) | ((texture_base[6 ] >> 16) & 0x0000ffff);
|
|
|
|
dtdx = ((texture_base[2 ] << 16) & 0xffff0000) | (texture_base[6 ] & 0x0000ffff);
|
|
|
|
dwdx = (texture_base[3 ] & 0xffff0000) | ((texture_base[7 ] >> 16) & 0x0000ffff);
|
|
|
|
dsde = (texture_base[8 ] & 0xffff0000) | ((texture_base[12] >> 16) & 0x0000ffff);
|
|
|
|
dtde = ((texture_base[8 ] << 16) & 0xffff0000) | (texture_base[12] & 0x0000ffff);
|
|
|
|
dwde = (texture_base[9 ] & 0xffff0000) | ((texture_base[13] >> 16) & 0x0000ffff);
|
|
|
|
}
|
|
|
|
if (_zbuffer != 0) {
|
|
|
|
z = zbuffer_base[0];
|
|
|
|
dzdx = zbuffer_base[1];
|
|
|
|
dzde = zbuffer_base[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
xh <<= 2; xm <<= 2; xl <<= 2;
|
|
|
|
r <<= 2; g <<= 2; b <<= 2; a <<= 2;
|
|
|
|
dsde >>= 2; dtde >>= 2; dsdx >>= 2; dtdx >>= 2;
|
|
|
|
dzdx >>= 2; dzde >>= 2;
|
|
|
|
dwdx >>= 2; dwde >>= 2;
|
|
|
|
|
|
|
|
#define XSCALE(x) (float(x)/(1<<18))
|
|
|
|
#define YSCALE(y) (float(y)/(1<<2))
|
|
|
|
#define ZSCALE(z) ((gDP.otherMode.depthSource == G_ZS_PRIM)? gDP.primDepth.z : float(u32(z))/0xffff0000)
|
|
|
|
//#define WSCALE(w) (bPerspEnabled? (float(u32(w) + 0x10000)/0xffff0000) : 1.0f)
|
|
|
|
//#define WSCALE(w) (bPerspEnabled? 4294901760.0/(w + 65536) : 1.0f)
|
|
|
|
#define PERSP_EN (gDP.otherMode.texturePersp != 0)
|
|
|
|
#define WSCALE(w) (PERSP_EN? 65536.0f/float((w+ 0xffff)>>16) : 1.0f)
|
|
|
|
#define CSCALE(c) ((((c)>0x3ff0000? 0x3ff0000:((c)<0? 0 : (c)))>>18)*0.0039215689f)
|
|
|
|
#define _PERSP(w) ( w )
|
|
|
|
#define PERSP(s, w) ( ((s64)(s) << 20) / (_PERSP(w)? _PERSP(w):1) )
|
|
|
|
#define SSCALE(s, _w) (PERSP_EN? float(PERSP(s, _w))/(1 << 10) : float(s)/(1<<21))
|
|
|
|
#define TSCALE(s, w) (PERSP_EN? float(PERSP(s, w))/(1 << 10) : float(s)/(1<<21))
|
|
|
|
|
|
|
|
u32 nbVtxs = 0;
|
|
|
|
OGLRender & render = video().getRender();
|
|
|
|
SPVertex * vtx = &render.getVertex(nbVtxs++);
|
|
|
|
|
|
|
|
xleft = xm;
|
|
|
|
xright = xh;
|
|
|
|
xleft_inc = dxmdy;
|
|
|
|
xright_inc = dxhdy;
|
|
|
|
|
|
|
|
while (yh<ym &&
|
|
|
|
!((!flip && xleft < xright+0x10000) ||
|
|
|
|
(flip && xleft > xright-0x10000))) {
|
|
|
|
xleft += xleft_inc;
|
|
|
|
xright += xright_inc;
|
|
|
|
s += dsde; t += dtde; w += dwde;
|
|
|
|
r += drde; g += dgde; b += dbde; a += dade;
|
|
|
|
z += dzde;
|
|
|
|
yh++;
|
|
|
|
}
|
|
|
|
|
|
|
|
j = ym-yh;
|
|
|
|
if (j > 0) {
|
|
|
|
int dx = (xleft-xright)>>16;
|
|
|
|
if ((!flip && xleft < xright) ||
|
|
|
|
(flip/* && xleft > xright*/))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r+drdx*dx);
|
|
|
|
vtx->g = CSCALE(g+dgdx*dx);
|
|
|
|
vtx->b = CSCALE(b+dbdx*dx);
|
|
|
|
vtx->a = CSCALE(a+dadx*dx);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx);
|
|
|
|
vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xleft);
|
|
|
|
vtx->y = YSCALE(yh);
|
|
|
|
vtx->z = ZSCALE(z+dzdx*dx);
|
|
|
|
vtx->w = WSCALE(w+dwdx*dx);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
if ((!flip/* && xleft < xright*/) ||
|
|
|
|
(flip && xleft > xright))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r);
|
|
|
|
vtx->g = CSCALE(g);
|
|
|
|
vtx->b = CSCALE(b);
|
|
|
|
vtx->a = CSCALE(a);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s, w);
|
|
|
|
vtx->t = TSCALE(t, w);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xright);
|
|
|
|
vtx->y = YSCALE(yh);
|
|
|
|
vtx->z = ZSCALE(z);
|
|
|
|
vtx->w = WSCALE(w);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
xleft += xleft_inc*j; xright += xright_inc*j;
|
|
|
|
s += dsde*j; t += dtde*j;
|
|
|
|
if (w + dwde*j) w += dwde*j;
|
|
|
|
else w += dwde*(j-1);
|
|
|
|
r += drde*j; g += dgde*j; b += dbde*j; a += dade*j;
|
|
|
|
z += dzde*j;
|
|
|
|
// render ...
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xl != xh)
|
|
|
|
xleft = xl;
|
|
|
|
|
|
|
|
//if (yl-ym > 0)
|
|
|
|
{
|
|
|
|
int dx = (xleft-xright)>>16;
|
|
|
|
if ((!flip && xleft <= xright) ||
|
|
|
|
(flip/* && xleft >= xright*/))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r+drdx*dx);
|
|
|
|
vtx->g = CSCALE(g+dgdx*dx);
|
|
|
|
vtx->b = CSCALE(b+dbdx*dx);
|
|
|
|
vtx->a = CSCALE(a+dadx*dx);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx);
|
|
|
|
vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xleft);
|
|
|
|
vtx->y = YSCALE(ym);
|
|
|
|
vtx->z = ZSCALE(z+dzdx*dx);
|
|
|
|
vtx->w = WSCALE(w+dwdx*dx);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
if ((!flip/* && xleft <= xright*/) ||
|
|
|
|
(flip && xleft >= xright))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r);
|
|
|
|
vtx->g = CSCALE(g);
|
|
|
|
vtx->b = CSCALE(b);
|
|
|
|
vtx->a = CSCALE(a);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s, w);
|
|
|
|
vtx->t = TSCALE(t, w);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xright);
|
|
|
|
vtx->y = YSCALE(ym);
|
|
|
|
vtx->z = ZSCALE(z);
|
|
|
|
vtx->w = WSCALE(w);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xleft_inc = dxldy;
|
|
|
|
xright_inc = dxhdy;
|
|
|
|
|
|
|
|
j = yl-ym;
|
|
|
|
//j--; // ?
|
|
|
|
xleft += xleft_inc*j; xright += xright_inc*j;
|
|
|
|
s += dsde*j; t += dtde*j; w += dwde*j;
|
|
|
|
r += drde*j; g += dgde*j; b += dbde*j; a += dade*j;
|
|
|
|
z += dzde*j;
|
|
|
|
|
|
|
|
while (yl>ym &&
|
|
|
|
!((!flip && xleft < xright+0x10000) ||
|
|
|
|
(flip && xleft > xright-0x10000))) {
|
|
|
|
xleft -= xleft_inc; xright -= xright_inc;
|
|
|
|
s -= dsde; t -= dtde; w -= dwde;
|
|
|
|
r -= drde; g -= dgde; b -= dbde; a -= dade;
|
|
|
|
z -= dzde;
|
|
|
|
--j;
|
|
|
|
--yl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// render ...
|
|
|
|
if (j >= 0) {
|
|
|
|
int dx = (xleft-xright)>>16;
|
|
|
|
if ((!flip && xleft <= xright) ||
|
|
|
|
(flip/* && xleft >= xright*/))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r+drdx*dx);
|
|
|
|
vtx->g = CSCALE(g+dgdx*dx);
|
|
|
|
vtx->b = CSCALE(b+dbdx*dx);
|
|
|
|
vtx->a = CSCALE(a+dadx*dx);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s+dsdx*dx, w+dwdx*dx);
|
|
|
|
vtx->t = TSCALE(t+dtdx*dx, w+dwdx*dx);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xleft);
|
|
|
|
vtx->y = YSCALE(yl);
|
|
|
|
vtx->z = ZSCALE(z+dzdx*dx);
|
|
|
|
vtx->w = WSCALE(w+dwdx*dx);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
if ((!flip/* && xleft <= xright*/) ||
|
|
|
|
(flip && xleft >= xright))
|
|
|
|
{
|
|
|
|
if (_shade != 0) {
|
|
|
|
vtx->r = CSCALE(r);
|
|
|
|
vtx->g = CSCALE(g);
|
|
|
|
vtx->b = CSCALE(b);
|
|
|
|
vtx->a = CSCALE(a);
|
|
|
|
}
|
|
|
|
if (_texture != 0) {
|
|
|
|
vtx->s = SSCALE(s, w);
|
|
|
|
vtx->t = TSCALE(t, w);
|
|
|
|
}
|
|
|
|
vtx->x = XSCALE(xright);
|
|
|
|
vtx->y = YSCALE(yl);
|
|
|
|
vtx->z = ZSCALE(z);
|
|
|
|
vtx->w = WSCALE(w);
|
|
|
|
vtx = &render.getVertex(nbVtxs++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-22 17:45:42 +00:00
|
|
|
if (_texture != 0)
|
|
|
|
gSP.changed |= CHANGED_TEXTURE;
|
2014-11-22 17:45:18 +00:00
|
|
|
if (_zbuffer != 0)
|
|
|
|
gSP.geometryMode |= G_ZBUFFER;
|
|
|
|
|
2014-10-07 10:59:54 +00:00
|
|
|
render.drawLLETriangle(nbVtxs - 1);
|
|
|
|
gSP.textureTile[0] = textureTileOrg[0];
|
|
|
|
gSP.textureTile[1] = textureTileOrg[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gDPTriangle(u32 _w1, u32 _w2, int shade, int texture, int zbuffer)
|
|
|
|
{
|
|
|
|
gDPLLETriangle(_w1, _w2, shade, texture, zbuffer, RDP.cmd_data + RDP.cmd_cur);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriFill(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 0, 0, 0);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trifill\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriShade(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 1, 0, 0);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trishade\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriTxtr(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 0, 1, 0);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "tritxtr\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriShadeTxtr(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 1, 1, 0);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trishadetxtr\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriFillZ(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 0, 0, 1);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trifillz\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriShadeZ(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 1, 0, 1);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trishadez\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriTxtrZ(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 0, 1, 1);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "tritxtrz\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void gDPTriShadeTxtrZ(u32 w0, u32 w1)
|
|
|
|
{
|
|
|
|
gDPTriangle(w0, w1, 1, 1, 1);
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "trishadetxtrz\n");
|
|
|
|
}
|