mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-12 14:46:49 +01:00
Merge pull request #1095 from crudelios/sw-bbox
Reimplement Bounding Box calculation using the software renderer.
This commit is contained in:
commit
9551650c42
@ -64,7 +64,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
|||||||
static std::thread g_save_thread;
|
static std::thread g_save_thread;
|
||||||
|
|
||||||
// Don't forget to increase this after doing changes on the savestate system
|
// Don't forget to increase this after doing changes on the savestate system
|
||||||
static const u32 STATE_VERSION = 35;
|
static const u32 STATE_VERSION = 36;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "VideoBackends/Software/Rasterizer.h"
|
#include "VideoBackends/Software/Rasterizer.h"
|
||||||
#include "VideoBackends/Software/Tev.h"
|
#include "VideoBackends/Software/Tev.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/PixelEngine.h"
|
#include "VideoCommon/PixelEngine.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
@ -73,12 +74,12 @@ void SWBPWritten(int address, int newvalue)
|
|||||||
EfbCopy::CopyEfb();
|
EfbCopy::CopyEfb();
|
||||||
break;
|
break;
|
||||||
case BPMEM_CLEARBBOX1:
|
case BPMEM_CLEARBBOX1:
|
||||||
PixelEngine::bbox[0] = newvalue >> 10;
|
BoundingBox::coords[BoundingBox::LEFT] = newvalue >> 10;
|
||||||
PixelEngine::bbox[1] = newvalue & 0x3ff;
|
BoundingBox::coords[BoundingBox::RIGHT] = newvalue & 0x3ff;
|
||||||
break;
|
break;
|
||||||
case BPMEM_CLEARBBOX2:
|
case BPMEM_CLEARBBOX2:
|
||||||
PixelEngine::bbox[2] = newvalue >> 10;
|
BoundingBox::coords[BoundingBox::TOP] = newvalue >> 10;
|
||||||
PixelEngine::bbox[3] = newvalue & 0x3ff;
|
BoundingBox::coords[BoundingBox::BOTTOM] = newvalue & 0x3ff;
|
||||||
break;
|
break;
|
||||||
case BPMEM_CLEAR_PIXEL_PERF:
|
case BPMEM_CLEAR_PIXEL_PERF:
|
||||||
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
|
// TODO: I didn't test if the value written to this register affects the amount of cleared registers
|
||||||
|
@ -437,12 +437,6 @@ namespace EfbInterface
|
|||||||
{
|
{
|
||||||
SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]);
|
SetPixelAlphaOnly(offset, dstClrPtr[ALP_C]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// branchless bounding box update
|
|
||||||
PixelEngine::bbox[0] = std::min(x, PixelEngine::bbox[0]);
|
|
||||||
PixelEngine::bbox[1] = std::max(x, PixelEngine::bbox[1]);
|
|
||||||
PixelEngine::bbox[2] = std::min(y, PixelEngine::bbox[2]);
|
|
||||||
PixelEngine::bbox[3] = std::max(y, PixelEngine::bbox[3]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetColor(u16 x, u16 y, u8 *color)
|
void SetColor(u16 x, u16 y, u8 *color)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "VideoBackends/Software/SWVideoConfig.h"
|
#include "VideoBackends/Software/SWVideoConfig.h"
|
||||||
#include "VideoBackends/Software/Tev.h"
|
#include "VideoBackends/Software/Tev.h"
|
||||||
#include "VideoBackends/Software/XFMemLoader.h"
|
#include "VideoBackends/Software/XFMemLoader.h"
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
|
|
||||||
|
|
||||||
#define BLOCK_SIZE 2
|
#define BLOCK_SIZE 2
|
||||||
@ -130,7 +131,7 @@ inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
|
|||||||
if (z < 0 || z > 0x00ffffff)
|
if (z < 0 || z > 0x00ffffff)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
|
if (!BoundingBox::active && bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
|
||||||
{
|
{
|
||||||
// TODO: Test if perf regs are incremented even if test is disabled
|
// TODO: Test if perf regs are incremented even if test is disabled
|
||||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_INPUT_ZCOMPLOC);
|
||||||
@ -313,11 +314,27 @@ static void BuildBlock(s32 blockX, s32 blockY)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void PrepareBlock(s32 blockX, s32 blockY)
|
||||||
|
{
|
||||||
|
static s32 x = -1;
|
||||||
|
static s32 y = -1;
|
||||||
|
|
||||||
|
blockX &= ~(BLOCK_SIZE - 1);
|
||||||
|
blockY &= ~(BLOCK_SIZE - 1);
|
||||||
|
|
||||||
|
if (x != blockX || y != blockY)
|
||||||
|
{
|
||||||
|
x = blockX;
|
||||||
|
y = blockY;
|
||||||
|
BuildBlock(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVertexData *v2)
|
||||||
{
|
{
|
||||||
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
|
INCSTAT(swstats.thisFrame.numTrianglesDrawn);
|
||||||
|
|
||||||
if (g_SWVideoConfig.bHwRasterizer)
|
if (g_SWVideoConfig.bHwRasterizer && !BoundingBox::active)
|
||||||
{
|
{
|
||||||
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
|
HwRasterizer::DrawTriangleFrontFace(v0, v1, v2);
|
||||||
return;
|
return;
|
||||||
@ -400,10 +417,6 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
|
|||||||
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
InitSlope(&TexSlopes[i][comp], v0->texCoords[i][comp] * w[0], v1->texCoords[i][comp] * w[1], v2->texCoords[i][comp] * w[2], fltdx31, fltdx12, fltdy12, fltdy31);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start in corner of 8x8 block
|
|
||||||
minx &= ~(BLOCK_SIZE - 1);
|
|
||||||
miny &= ~(BLOCK_SIZE - 1);
|
|
||||||
|
|
||||||
// Half-edge constants
|
// Half-edge constants
|
||||||
s32 C1 = DY12 * X1 - DX12 * Y1;
|
s32 C1 = DY12 * X1 - DX12 * Y1;
|
||||||
s32 C2 = DY23 * X2 - DX23 * Y2;
|
s32 C2 = DY23 * X2 - DX23 * Y2;
|
||||||
@ -414,6 +427,13 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
|
|||||||
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
|
if (DY23 < 0 || (DY23 == 0 && DX23 > 0)) C2++;
|
||||||
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
if (DY31 < 0 || (DY31 == 0 && DX31 > 0)) C3++;
|
||||||
|
|
||||||
|
// If drawing, rasterize every block
|
||||||
|
if (!BoundingBox::active)
|
||||||
|
{
|
||||||
|
// Start in corner of 8x8 block
|
||||||
|
minx &= ~(BLOCK_SIZE - 1);
|
||||||
|
miny &= ~(BLOCK_SIZE - 1);
|
||||||
|
|
||||||
// Loop through blocks
|
// Loop through blocks
|
||||||
for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
|
for (s32 y = miny; y < maxy; y += BLOCK_SIZE)
|
||||||
{
|
{
|
||||||
@ -492,6 +512,196 @@ void DrawTriangleFrontFace(OutputVertexData *v0, OutputVertexData *v1, OutputVer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculating bbox
|
||||||
|
// First check for alpha channel - don't do anything it if always fails,
|
||||||
|
// Change bbox to primitive size if it always passes
|
||||||
|
AlphaTest::TEST_RESULT alphaRes = bpmem.alpha_test.TestResult();
|
||||||
|
|
||||||
|
if (alphaRes != AlphaTest::UNDETERMINED)
|
||||||
|
{
|
||||||
|
if (alphaRes == AlphaTest::PASS)
|
||||||
|
{
|
||||||
|
BoundingBox::coords[BoundingBox::TOP] = std::min(BoundingBox::coords[BoundingBox::TOP], (u16) miny);
|
||||||
|
BoundingBox::coords[BoundingBox::LEFT] = std::min(BoundingBox::coords[BoundingBox::LEFT], (u16) minx);
|
||||||
|
BoundingBox::coords[BoundingBox::BOTTOM] = std::max(BoundingBox::coords[BoundingBox::BOTTOM], (u16) maxy);
|
||||||
|
BoundingBox::coords[BoundingBox::RIGHT] = std::max(BoundingBox::coords[BoundingBox::RIGHT], (u16) maxx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are calculating bbox with alpha, we only need to find the
|
||||||
|
// topmost, leftmost, bottom most and rightmost pixels to be drawn.
|
||||||
|
// So instead of drawing every single one of the triangle's pixels,
|
||||||
|
// four loops are run: one for the top pixel, one for the left, one for
|
||||||
|
// the bottom and one for the right. As soon as a pixel that is to be
|
||||||
|
// drawn is found, the loop breaks. This enables a ~150% speedbost in
|
||||||
|
// bbox calculation, albeit at the cost of some ugly repetitive code.
|
||||||
|
const s32 FLEFT = minx << 4;
|
||||||
|
const s32 FRIGHT = maxx << 4;
|
||||||
|
s32 FTOP = miny << 4;
|
||||||
|
s32 FBOTTOM = maxy << 4;
|
||||||
|
|
||||||
|
// Start checking for bbox top
|
||||||
|
s32 CY1 = C1 + DX12 * FTOP - DY12 * FLEFT;
|
||||||
|
s32 CY2 = C2 + DX23 * FTOP - DY23 * FLEFT;
|
||||||
|
s32 CY3 = C3 + DX31 * FTOP - DY31 * FLEFT;
|
||||||
|
|
||||||
|
// Loop
|
||||||
|
for (s32 y = miny; y <= maxy; ++y)
|
||||||
|
{
|
||||||
|
if (y >= BoundingBox::coords[BoundingBox::TOP])
|
||||||
|
break;
|
||||||
|
|
||||||
|
s32 CX1 = CY1;
|
||||||
|
s32 CX2 = CY2;
|
||||||
|
s32 CX3 = CY3;
|
||||||
|
|
||||||
|
for (s32 x = minx; x <= maxx; ++x)
|
||||||
|
{
|
||||||
|
if (CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||||
|
{
|
||||||
|
// Build the new raster block every other pixel
|
||||||
|
PrepareBlock(x, y);
|
||||||
|
Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1));
|
||||||
|
|
||||||
|
if (y >= BoundingBox::coords[BoundingBox::TOP])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CX1 -= FDY12;
|
||||||
|
CX2 -= FDY23;
|
||||||
|
CX3 -= FDY31;
|
||||||
|
}
|
||||||
|
|
||||||
|
CY1 += FDX12;
|
||||||
|
CY2 += FDX23;
|
||||||
|
CY3 += FDX31;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update top limit
|
||||||
|
miny = std::max((s32) BoundingBox::coords[BoundingBox::TOP], miny);
|
||||||
|
FTOP = miny << 4;
|
||||||
|
|
||||||
|
// Checking for bbox left
|
||||||
|
s32 CX1 = C1 + DX12 * FTOP - DY12 * FLEFT;
|
||||||
|
s32 CX2 = C2 + DX23 * FTOP - DY23 * FLEFT;
|
||||||
|
s32 CX3 = C3 + DX31 * FTOP - DY31 * FLEFT;
|
||||||
|
|
||||||
|
// Loop
|
||||||
|
for (s32 x = minx; x <= maxx; ++x)
|
||||||
|
{
|
||||||
|
if (x >= BoundingBox::coords[BoundingBox::LEFT])
|
||||||
|
break;
|
||||||
|
|
||||||
|
CY1 = CX1;
|
||||||
|
CY2 = CX2;
|
||||||
|
CY3 = CX3;
|
||||||
|
|
||||||
|
for (s32 y = miny; y <= maxy; ++y)
|
||||||
|
{
|
||||||
|
if (CY1 > 0 && CY2 > 0 && CY3 > 0)
|
||||||
|
{
|
||||||
|
PrepareBlock(x, y);
|
||||||
|
Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1));
|
||||||
|
|
||||||
|
if (x >= BoundingBox::coords[BoundingBox::LEFT])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CY1 += FDX12;
|
||||||
|
CY2 += FDX23;
|
||||||
|
CY3 += FDX31;
|
||||||
|
}
|
||||||
|
|
||||||
|
CX1 -= FDY12;
|
||||||
|
CX2 -= FDY23;
|
||||||
|
CX3 -= FDY31;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update left limit
|
||||||
|
minx = std::max((s32) BoundingBox::coords[BoundingBox::LEFT], minx);
|
||||||
|
|
||||||
|
// Checking for bbox bottom
|
||||||
|
CY1 = C1 + DX12 * FBOTTOM - DY12 * FRIGHT;
|
||||||
|
CY2 = C2 + DX23 * FBOTTOM - DY23 * FRIGHT;
|
||||||
|
CY3 = C3 + DX31 * FBOTTOM - DY31 * FRIGHT;
|
||||||
|
|
||||||
|
// Loop
|
||||||
|
for (s32 y = maxy; y >= miny; --y)
|
||||||
|
{
|
||||||
|
CX1 = CY1;
|
||||||
|
CX2 = CY2;
|
||||||
|
CX3 = CY3;
|
||||||
|
|
||||||
|
if (y <= BoundingBox::coords[BoundingBox::BOTTOM])
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (s32 x = maxx; x >= minx; --x)
|
||||||
|
{
|
||||||
|
if (CX1 > 0 && CX2 > 0 && CX3 > 0)
|
||||||
|
{
|
||||||
|
// Build the new raster block every other pixel
|
||||||
|
PrepareBlock(x, y);
|
||||||
|
Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1));
|
||||||
|
|
||||||
|
if (y <= BoundingBox::coords[BoundingBox::BOTTOM])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CX1 += FDY12;
|
||||||
|
CX2 += FDY23;
|
||||||
|
CX3 += FDY31;
|
||||||
|
}
|
||||||
|
|
||||||
|
CY1 -= FDX12;
|
||||||
|
CY2 -= FDX23;
|
||||||
|
CY3 -= FDX31;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update bottom limit
|
||||||
|
maxy = std::min((s32) BoundingBox::coords[BoundingBox::BOTTOM], maxy);
|
||||||
|
FBOTTOM = maxy << 4;
|
||||||
|
|
||||||
|
// Checking for bbox right
|
||||||
|
CX1 = C1 + DX12 * FBOTTOM - DY12 * FRIGHT;
|
||||||
|
CX2 = C2 + DX23 * FBOTTOM - DY23 * FRIGHT;
|
||||||
|
CX3 = C3 + DX31 * FBOTTOM - DY31 * FRIGHT;
|
||||||
|
|
||||||
|
// Loop
|
||||||
|
for (s32 x = maxx; x >= minx; --x)
|
||||||
|
{
|
||||||
|
if (x <= BoundingBox::coords[BoundingBox::RIGHT])
|
||||||
|
break;
|
||||||
|
|
||||||
|
CY1 = CX1;
|
||||||
|
CY2 = CX2;
|
||||||
|
CY3 = CX3;
|
||||||
|
|
||||||
|
for (s32 y = maxy; y >= miny; --y)
|
||||||
|
{
|
||||||
|
if (CY1 > 0 && CY2 > 0 && CY3 > 0)
|
||||||
|
{
|
||||||
|
// Build the new raster block every other pixel
|
||||||
|
PrepareBlock(x, y);
|
||||||
|
Draw(x, y, x & (BLOCK_SIZE - 1), y & (BLOCK_SIZE - 1));
|
||||||
|
|
||||||
|
if (x <= BoundingBox::coords[BoundingBox::RIGHT])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CY1 -= FDX12;
|
||||||
|
CY2 -= FDX23;
|
||||||
|
CY3 -= FDX31;
|
||||||
|
}
|
||||||
|
|
||||||
|
CX1 += FDY12;
|
||||||
|
CX2 += FDY23;
|
||||||
|
CX3 += FDY31;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "VideoBackends/Software/Tev.h"
|
#include "VideoBackends/Software/Tev.h"
|
||||||
#include "VideoBackends/Software/TextureSampler.h"
|
#include "VideoBackends/Software/TextureSampler.h"
|
||||||
#include "VideoBackends/Software/XFMemLoader.h"
|
#include "VideoBackends/Software/XFMemLoader.h"
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define ALLOW_TEV_DUMPS 1
|
#define ALLOW_TEV_DUMPS 1
|
||||||
@ -649,6 +650,10 @@ void Tev::Draw()
|
|||||||
if (!TevAlphaTest(output[ALP_C]))
|
if (!TevAlphaTest(output[ALP_C]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// This part is only needed if we are not simply computing bbox
|
||||||
|
// (i. e., only needed when using the SW renderer)
|
||||||
|
if (!BoundingBox::active)
|
||||||
|
{
|
||||||
// z texture
|
// z texture
|
||||||
if (bpmem.ztex2.op)
|
if (bpmem.ztex2.op)
|
||||||
{
|
{
|
||||||
@ -764,6 +769,19 @@ void Tev::Draw()
|
|||||||
|
|
||||||
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
|
EfbInterface::IncPerfCounterQuadCount(PQ_ZCOMP_OUTPUT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// branchless bounding box update
|
||||||
|
BoundingBox::coords[BoundingBox::LEFT] = std::min((u16)Position[0], BoundingBox::coords[BoundingBox::LEFT]);
|
||||||
|
BoundingBox::coords[BoundingBox::RIGHT] = std::max((u16)Position[0], BoundingBox::coords[BoundingBox::RIGHT]);
|
||||||
|
BoundingBox::coords[BoundingBox::TOP] = std::min((u16)Position[1], BoundingBox::coords[BoundingBox::TOP]);
|
||||||
|
BoundingBox::coords[BoundingBox::BOTTOM] = std::max((u16)Position[1], BoundingBox::coords[BoundingBox::BOTTOM]);
|
||||||
|
|
||||||
|
// if we are only calculating the bounding box,
|
||||||
|
// there's no need to actually draw anything
|
||||||
|
if (BoundingBox::active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
#if ALLOW_TEV_DUMPS
|
#if ALLOW_TEV_DUMPS
|
||||||
if (g_SWVideoConfig.bDumpTevStages)
|
if (g_SWVideoConfig.bDumpTevStages)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/BPFunctions.h"
|
#include "VideoCommon/BPFunctions.h"
|
||||||
#include "VideoCommon/BPStructs.h"
|
#include "VideoCommon/BPStructs.h"
|
||||||
#include "VideoCommon/Fifo.h"
|
#include "VideoCommon/Fifo.h"
|
||||||
@ -231,7 +232,7 @@ static void BPWritten(const BPCmd& bp)
|
|||||||
// here. Not sure if there's a better spot to put this.
|
// here. Not sure if there's a better spot to put this.
|
||||||
// the number of lines copied is determined by the y scale * source efb height
|
// the number of lines copied is determined by the y scale * source efb height
|
||||||
|
|
||||||
PixelEngine::bbox_active = false;
|
BoundingBox::active = false;
|
||||||
|
|
||||||
float yScale;
|
float yScale;
|
||||||
if (PE_copy.scale_invert)
|
if (PE_copy.scale_invert)
|
||||||
@ -378,13 +379,13 @@ static void BPWritten(const BPCmd& bp)
|
|||||||
case BPMEM_CLEARBBOX2:
|
case BPMEM_CLEARBBOX2:
|
||||||
// Don't compute bounding box if this frame is being skipped!
|
// Don't compute bounding box if this frame is being skipped!
|
||||||
// Wrong but valid values are better than bogus values...
|
// Wrong but valid values are better than bogus values...
|
||||||
if (g_ActiveConfig.bUseBBox && !g_bSkipCurrentFrame)
|
if (!g_bSkipCurrentFrame)
|
||||||
{
|
{
|
||||||
u8 offset = bp.address & 2;
|
u8 offset = bp.address & 2;
|
||||||
|
|
||||||
PixelEngine::bbox[offset] = bp.newvalue & 0x3ff;
|
BoundingBox::coords[offset] = bp.newvalue & 0x3ff;
|
||||||
PixelEngine::bbox[offset | 1] = bp.newvalue >> 10;
|
BoundingBox::coords[offset + 1] = bp.newvalue >> 10;
|
||||||
PixelEngine::bbox_active = true;
|
BoundingBox::active = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case BPMEM_TEXINVALIDATE:
|
case BPMEM_TEXINVALIDATE:
|
||||||
|
150
Source/Core/VideoCommon/BoundingBox.cpp
Normal file
150
Source/Core/VideoCommon/BoundingBox.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "VideoBackends/Software/Clipper.h"
|
||||||
|
#include "VideoBackends/Software/Rasterizer.h"
|
||||||
|
#include "VideoBackends/Software/SetupUnit.h"
|
||||||
|
#include "VideoBackends/Software/TransformUnit.h"
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
|
#include "VideoCommon/PixelShaderManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BoundingBox
|
||||||
|
{
|
||||||
|
|
||||||
|
// External vars
|
||||||
|
bool active = false;
|
||||||
|
u16 coords[4] = { 0x80, 0xA0, 0x80, 0xA0 };
|
||||||
|
u8 posMtxIdx;
|
||||||
|
u8 texMtxIdx[8];
|
||||||
|
|
||||||
|
|
||||||
|
// Internal vars
|
||||||
|
SetupUnit vtxUnit;
|
||||||
|
VAT myVat;
|
||||||
|
u8 * bufferPos;
|
||||||
|
TVtxDesc vertexDesc;
|
||||||
|
PortableVertexDeclaration vertexDecl;
|
||||||
|
|
||||||
|
// Gets the pointer to the current buffer position
|
||||||
|
void LOADERDECL SetVertexBufferPosition()
|
||||||
|
{
|
||||||
|
bufferPos = VertexManager::s_pCurBufferPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepares the bounding box for new primitive data
|
||||||
|
void Prepare(const VAT & vat, int primitive, const TVtxDesc & vtxDesc, const PortableVertexDeclaration & vtxDecl)
|
||||||
|
{
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
myVat = vat;
|
||||||
|
vertexDesc = vtxDesc;
|
||||||
|
vertexDecl = vtxDecl;
|
||||||
|
|
||||||
|
vtxUnit.Init(primitive);
|
||||||
|
|
||||||
|
// Initialize the SW renderer
|
||||||
|
static bool SWinit = false;
|
||||||
|
|
||||||
|
if (!SWinit)
|
||||||
|
{
|
||||||
|
Clipper::Init();
|
||||||
|
Rasterizer::Init();
|
||||||
|
SWinit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update SW renderer values
|
||||||
|
Clipper::SetViewOffset();
|
||||||
|
Rasterizer::SetScissor();
|
||||||
|
|
||||||
|
for (u8 i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
Rasterizer::SetTevReg(i, 0, true, (s16)PixelShaderManager::constants.kcolors[i][0]);
|
||||||
|
Rasterizer::SetTevReg(i, 1, true, (s16)PixelShaderManager::constants.kcolors[i][1]);
|
||||||
|
Rasterizer::SetTevReg(i, 2, true, (s16)PixelShaderManager::constants.kcolors[i][2]);
|
||||||
|
Rasterizer::SetTevReg(i, 3, true, (s16)PixelShaderManager::constants.kcolors[i][3]);
|
||||||
|
|
||||||
|
Rasterizer::SetTevReg(i, 0, false, (s16)PixelShaderManager::constants.colors[i][0]);
|
||||||
|
Rasterizer::SetTevReg(i, 1, false, (s16)PixelShaderManager::constants.colors[i][1]);
|
||||||
|
Rasterizer::SetTevReg(i, 2, false, (s16)PixelShaderManager::constants.colors[i][2]);
|
||||||
|
Rasterizer::SetTevReg(i, 3, false, (s16)PixelShaderManager::constants.colors[i][3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the bounding box
|
||||||
|
void LOADERDECL Update()
|
||||||
|
{
|
||||||
|
if (!active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Grab vertex input data and transform to output vertex
|
||||||
|
InputVertexData myVertex;
|
||||||
|
OutputVertexData * outVertex = vtxUnit.GetVertex();
|
||||||
|
|
||||||
|
// Feed vertex position and matrix
|
||||||
|
myVertex.position = Vec3((const float *)bufferPos);
|
||||||
|
myVertex.posMtx = vertexDesc.PosMatIdx ? posMtxIdx : g_main_cp_state.matrix_index_a.PosNormalMtxIdx;
|
||||||
|
|
||||||
|
// Transform position
|
||||||
|
TransformUnit::TransformPosition(&myVertex, outVertex);
|
||||||
|
|
||||||
|
if (g_main_cp_state.vtx_desc.Normal != NOT_PRESENT)
|
||||||
|
{
|
||||||
|
// Feed normal input data and transform
|
||||||
|
memcpy((u8 *)myVertex.normal, bufferPos + vertexDecl.normals[0].offset, sizeof(float) * 3 * ((myVat.g0.NormalElements) ? 3 : 1));
|
||||||
|
|
||||||
|
TransformUnit::TransformNormal(&myVertex, myVat.g0.NormalElements, outVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed color input data
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
if (vertexDecl.colors[i].enable)
|
||||||
|
{
|
||||||
|
u32 color;
|
||||||
|
memcpy((u8 *)&color, bufferPos + vertexDecl.colors[i].offset, sizeof(u32));
|
||||||
|
*(u32*)myVertex.color[i] = Common::swap32(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform color
|
||||||
|
TransformUnit::TransformColor(&myVertex, outVertex);
|
||||||
|
|
||||||
|
// Feed texture matrices
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
myVertex.texMtx[0] = (vertexDesc.Tex0MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_a.Tex0MtxIdx;
|
||||||
|
myVertex.texMtx[1] = (vertexDesc.Tex1MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_a.Tex1MtxIdx;
|
||||||
|
myVertex.texMtx[2] = (vertexDesc.Tex2MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_a.Tex2MtxIdx;
|
||||||
|
myVertex.texMtx[3] = (vertexDesc.Tex3MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_a.Tex3MtxIdx;
|
||||||
|
myVertex.texMtx[4] = (vertexDesc.Tex4MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_b.Tex4MtxIdx;
|
||||||
|
myVertex.texMtx[5] = (vertexDesc.Tex5MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_b.Tex5MtxIdx;
|
||||||
|
myVertex.texMtx[6] = (vertexDesc.Tex6MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_b.Tex6MtxIdx;
|
||||||
|
myVertex.texMtx[7] = (vertexDesc.Tex7MatIdx) ? texMtxIdx[idx++] : g_main_cp_state.matrix_index_b.Tex7MtxIdx;
|
||||||
|
|
||||||
|
// Feed texture coordinate data
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
if (vertexDecl.texcoords[i].enable)
|
||||||
|
memcpy((u8 *)&myVertex.texCoords[i], bufferPos + vertexDecl.texcoords[i].offset, sizeof(float) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform texture coordinate
|
||||||
|
TransformUnit::TransformTexCoord(&myVertex, outVertex, false);
|
||||||
|
|
||||||
|
// Render the vertex in SW to calculate bbox
|
||||||
|
vtxUnit.SetupVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save state
|
||||||
|
void DoState(PointerWrap &p)
|
||||||
|
{
|
||||||
|
p.Do(active);
|
||||||
|
p.Do(coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace BoundingBox
|
41
Source/Core/VideoCommon/BoundingBox.h
Normal file
41
Source/Core/VideoCommon/BoundingBox.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VideoCommon/VertexLoader.h"
|
||||||
|
|
||||||
|
// Bounding Box manager
|
||||||
|
|
||||||
|
namespace BoundingBox
|
||||||
|
{
|
||||||
|
|
||||||
|
// Determines if bounding box is active
|
||||||
|
extern bool active;
|
||||||
|
|
||||||
|
// Bounding box current coordinates
|
||||||
|
extern u16 coords[4];
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
LEFT = 0,
|
||||||
|
RIGHT = 1,
|
||||||
|
TOP = 2,
|
||||||
|
BOTTOM = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Current position matrix index
|
||||||
|
extern u8 posMtxIdx;
|
||||||
|
|
||||||
|
// Texture matrix indexes
|
||||||
|
extern u8 texMtxIdx[8];
|
||||||
|
|
||||||
|
void LOADERDECL SetVertexBufferPosition();
|
||||||
|
void LOADERDECL Update();
|
||||||
|
void Prepare(const VAT & vat, int primitive, const TVtxDesc & vtxDesc, const PortableVertexDeclaration & vtxDecl);
|
||||||
|
|
||||||
|
// Save state
|
||||||
|
void DoState(PointerWrap &p);
|
||||||
|
|
||||||
|
}; // end of namespace BoundingBox
|
@ -1,4 +1,5 @@
|
|||||||
set(SRCS BPFunctions.cpp
|
set(SRCS BoundingBox.cpp
|
||||||
|
BPFunctions.cpp
|
||||||
BPMemory.cpp
|
BPMemory.cpp
|
||||||
BPStructs.cpp
|
BPStructs.cpp
|
||||||
CPMemory.cpp
|
CPMemory.cpp
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
#include "Core/HW/MMIO.h"
|
#include "Core/HW/MMIO.h"
|
||||||
#include "Core/HW/ProcessorInterface.h"
|
#include "Core/HW/ProcessorInterface.h"
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/CommandProcessor.h"
|
#include "VideoCommon/CommandProcessor.h"
|
||||||
#include "VideoCommon/PixelEngine.h"
|
#include "VideoCommon/PixelEngine.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
@ -106,9 +107,6 @@ static int et_SetFinishOnMainThread;
|
|||||||
static volatile u32 interruptSetToken = 0;
|
static volatile u32 interruptSetToken = 0;
|
||||||
static volatile u32 interruptSetFinish = 0;
|
static volatile u32 interruptSetFinish = 0;
|
||||||
|
|
||||||
u16 bbox[4];
|
|
||||||
bool bbox_active;
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
|
INT_CAUSE_PE_TOKEN = 0x200, // GP Token
|
||||||
@ -128,9 +126,6 @@ void DoState(PointerWrap &p)
|
|||||||
p.Do(g_bSignalFinishInterrupt);
|
p.Do(g_bSignalFinishInterrupt);
|
||||||
p.Do(interruptSetToken);
|
p.Do(interruptSetToken);
|
||||||
p.Do(interruptSetFinish);
|
p.Do(interruptSetFinish);
|
||||||
|
|
||||||
p.Do(bbox);
|
|
||||||
p.Do(bbox_active);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
@ -155,13 +150,6 @@ void Init()
|
|||||||
|
|
||||||
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
et_SetTokenOnMainThread = CoreTiming::RegisterEvent("SetToken", SetToken_OnMainThread);
|
||||||
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
et_SetFinishOnMainThread = CoreTiming::RegisterEvent("SetFinish", SetFinish_OnMainThread);
|
||||||
|
|
||||||
bbox[0] = 0x80;
|
|
||||||
bbox[1] = 0xA0;
|
|
||||||
bbox[2] = 0x80;
|
|
||||||
bbox[3] = 0xA0;
|
|
||||||
|
|
||||||
bbox_active = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||||
@ -244,8 +232,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
|||||||
{
|
{
|
||||||
mmio->Register(base | (PE_BBOX_LEFT + 2 * i),
|
mmio->Register(base | (PE_BBOX_LEFT + 2 * i),
|
||||||
MMIO::ComplexRead<u16>([i](u32) {
|
MMIO::ComplexRead<u16>([i](u32) {
|
||||||
bbox_active = false;
|
BoundingBox::active = false;
|
||||||
return bbox[i];
|
return BoundingBox::coords[i];
|
||||||
}),
|
}),
|
||||||
MMIO::InvalidWrite<u16>()
|
MMIO::InvalidWrite<u16>()
|
||||||
);
|
);
|
||||||
|
@ -18,10 +18,10 @@ enum
|
|||||||
PE_ALPHAREAD = 0x08, // Alpha Read
|
PE_ALPHAREAD = 0x08, // Alpha Read
|
||||||
PE_CTRL_REGISTER = 0x0a, // Control
|
PE_CTRL_REGISTER = 0x0a, // Control
|
||||||
PE_TOKEN_REG = 0x0e, // Token
|
PE_TOKEN_REG = 0x0e, // Token
|
||||||
PE_BBOX_LEFT = 0x10, // Flip Left
|
PE_BBOX_LEFT = 0x10, // Bounding Box Left Pixel
|
||||||
PE_BBOX_RIGHT = 0x12, // Flip Right
|
PE_BBOX_RIGHT = 0x12, // Bounding Box Right Pixel
|
||||||
PE_BBOX_TOP = 0x14, // Flip Top
|
PE_BBOX_TOP = 0x14, // Bounding Box Top Pixel
|
||||||
PE_BBOX_BOTTOM = 0x16, // Flip Bottom
|
PE_BBOX_BOTTOM = 0x16, // Bounding Box Bottom Pixel
|
||||||
|
|
||||||
// NOTE: Order not verified
|
// NOTE: Order not verified
|
||||||
// These indicate the number of quads that are being used as input/output for each particular stage
|
// These indicate the number of quads that are being used as input/output for each particular stage
|
||||||
@ -63,8 +63,4 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge);
|
|||||||
void SetFinish();
|
void SetFinish();
|
||||||
UPEAlphaReadReg GetAlphaReadMode();
|
UPEAlphaReadReg GetAlphaReadMode();
|
||||||
|
|
||||||
// Bounding box functionality. Paper Mario (both) are a couple of the few games that use it.
|
|
||||||
extern u16 bbox[4];
|
|
||||||
extern bool bbox_active;
|
|
||||||
|
|
||||||
} // end of namespace PixelEngine
|
} // end of namespace PixelEngine
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/DataReader.h"
|
#include "VideoCommon/DataReader.h"
|
||||||
#include "VideoCommon/LookUpTables.h"
|
#include "VideoCommon/LookUpTables.h"
|
||||||
#include "VideoCommon/PixelEngine.h"
|
#include "VideoCommon/PixelEngine.h"
|
||||||
@ -21,8 +22,6 @@
|
|||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
//BBox
|
|
||||||
#include "VideoCommon/XFMemory.h"
|
|
||||||
|
|
||||||
#define COMPILED_CODE_SIZE 4096
|
#define COMPILED_CODE_SIZE 4096
|
||||||
|
|
||||||
@ -45,21 +44,6 @@ int colElements[2];
|
|||||||
float posScale;
|
float posScale;
|
||||||
float tcScale[8];
|
float tcScale[8];
|
||||||
|
|
||||||
// bbox variables
|
|
||||||
// bbox must read vertex position, so convert it to this buffer
|
|
||||||
static float s_bbox_vertex_buffer[3];
|
|
||||||
static u8 *s_bbox_pCurBufferPointer_orig;
|
|
||||||
static int s_bbox_primitive;
|
|
||||||
static struct Point
|
|
||||||
{
|
|
||||||
s32 x;
|
|
||||||
s32 y;
|
|
||||||
float z;
|
|
||||||
} s_bbox_points[3];
|
|
||||||
static u8 s_bbox_currPoint;
|
|
||||||
static u8 s_bbox_loadedPoints;
|
|
||||||
static const u8 s_bbox_primitivePoints[8] = { 3, 0, 3, 3, 3, 2, 2, 1 };
|
|
||||||
|
|
||||||
static const float fractionTable[32] = {
|
static const float fractionTable[32] = {
|
||||||
1.0f / (1U << 0), 1.0f / (1U << 1), 1.0f / (1U << 2), 1.0f / (1U << 3),
|
1.0f / (1U << 0), 1.0f / (1U << 1), 1.0f / (1U << 2), 1.0f / (1U << 3),
|
||||||
1.0f / (1U << 4), 1.0f / (1U << 5), 1.0f / (1U << 6), 1.0f / (1U << 7),
|
1.0f / (1U << 4), 1.0f / (1U << 5), 1.0f / (1U << 6), 1.0f / (1U << 7),
|
||||||
@ -75,7 +59,7 @@ using namespace Gen;
|
|||||||
|
|
||||||
static void LOADERDECL PosMtx_ReadDirect_UByte()
|
static void LOADERDECL PosMtx_ReadDirect_UByte()
|
||||||
{
|
{
|
||||||
s_curposmtx = DataReadU8() & 0x3f;
|
BoundingBox::posMtxIdx = s_curposmtx = DataReadU8() & 0x3f;
|
||||||
PRIM_LOG("posmtx: %d, ", s_curposmtx);
|
PRIM_LOG("posmtx: %d, ", s_curposmtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,437 +69,12 @@ static void LOADERDECL PosMtx_Write()
|
|||||||
DataWrite<u8>(0);
|
DataWrite<u8>(0);
|
||||||
DataWrite<u8>(0);
|
DataWrite<u8>(0);
|
||||||
DataWrite<u8>(0);
|
DataWrite<u8>(0);
|
||||||
|
|
||||||
// Resetting current position matrix to default is needed for bbox to behave
|
|
||||||
s_curposmtx = (u8) g_main_cp_state.matrix_index_a.PosNormalMtxIdx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LOADERDECL UpdateBoundingBoxPrepare()
|
|
||||||
{
|
|
||||||
if (!PixelEngine::bbox_active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set our buffer as videodata buffer, so we will get a copy of the vertex positions
|
|
||||||
// this is a big hack, but so we can use the same converting function then without bbox
|
|
||||||
s_bbox_pCurBufferPointer_orig = VertexManager::s_pCurBufferPointer;
|
|
||||||
VertexManager::s_pCurBufferPointer = (u8*)s_bbox_vertex_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool UpdateBoundingBoxVars()
|
|
||||||
{
|
|
||||||
switch (s_bbox_primitive)
|
|
||||||
{
|
|
||||||
// Quads: fill 0,1,2 (check),1 (check, clear, repeat)
|
|
||||||
case 0:
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
if (s_bbox_loadedPoints == 3)
|
|
||||||
{
|
|
||||||
s_bbox_currPoint = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (s_bbox_loadedPoints == 4)
|
|
||||||
{
|
|
||||||
s_bbox_loadedPoints = 0;
|
|
||||||
s_bbox_currPoint = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++s_bbox_currPoint;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Triangles: 0,1,2 (check, clear, repeat)
|
|
||||||
case 2:
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
if (s_bbox_loadedPoints == 3)
|
|
||||||
{
|
|
||||||
s_bbox_loadedPoints = 0;
|
|
||||||
s_bbox_currPoint = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++s_bbox_currPoint;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Triangle strip: 0, 1, 2 (check), 0 (check), 1, (check), 2 (check, repeat checking 0, 1, 2)
|
|
||||||
case 3:
|
|
||||||
if (++s_bbox_currPoint == 3)
|
|
||||||
s_bbox_currPoint = 0;
|
|
||||||
|
|
||||||
if (s_bbox_loadedPoints == 2)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Triangle fan: 0,1,2 (check), 1 (check), 2 (check, repeat checking 1,2)
|
|
||||||
case 4:
|
|
||||||
s_bbox_currPoint ^= s_bbox_currPoint ? 3 : 1;
|
|
||||||
|
|
||||||
if (s_bbox_loadedPoints == 2)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Lines: 0,1 (check, clear, repeat)
|
|
||||||
case 5:
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
if (s_bbox_loadedPoints == 2)
|
|
||||||
{
|
|
||||||
s_bbox_loadedPoints = 0;
|
|
||||||
s_bbox_currPoint = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
++s_bbox_currPoint;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Line strip: 0,1 (check), 0 (check), 1 (check, repeat checking 0,1)
|
|
||||||
case 6:
|
|
||||||
s_bbox_currPoint ^= 1;
|
|
||||||
|
|
||||||
if (s_bbox_loadedPoints == 1)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
++s_bbox_loadedPoints;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Points: 0 (check, clear, repeat)
|
|
||||||
case 7:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// This should not happen!
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LOADERDECL UpdateBoundingBox()
|
|
||||||
{
|
|
||||||
if (!PixelEngine::bbox_active)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Reset videodata pointer
|
|
||||||
VertexManager::s_pCurBufferPointer = s_bbox_pCurBufferPointer_orig;
|
|
||||||
|
|
||||||
// Copy vertex pointers
|
|
||||||
memcpy(VertexManager::s_pCurBufferPointer, s_bbox_vertex_buffer, 12);
|
|
||||||
VertexManager::s_pCurBufferPointer += 12;
|
|
||||||
|
|
||||||
// We must transform the just loaded point by the current world and projection matrix - in software
|
|
||||||
float transformed[3];
|
|
||||||
float screenPoint[3];
|
|
||||||
|
|
||||||
// We need to get the raw projection values for the bounding box calculation
|
|
||||||
// to work properly. That means, no projection hacks!
|
|
||||||
const float * const orig_point = s_bbox_vertex_buffer;
|
|
||||||
const float * const world_matrix = (float*)xfmem.posMatrices + s_curposmtx * 4;
|
|
||||||
const float * const proj_matrix = xfmem.projection.rawProjection;
|
|
||||||
|
|
||||||
// Transform by world matrix
|
|
||||||
// Only calculate what we need, discard the rest
|
|
||||||
transformed[0] = orig_point[0] * world_matrix[0] + orig_point[1] * world_matrix[1] + orig_point[2] * world_matrix[2] + world_matrix[3];
|
|
||||||
transformed[1] = orig_point[0] * world_matrix[4] + orig_point[1] * world_matrix[5] + orig_point[2] * world_matrix[6] + world_matrix[7];
|
|
||||||
|
|
||||||
// Transform by projection matrix
|
|
||||||
switch (xfmem.projection.type)
|
|
||||||
{
|
|
||||||
// Perspective projection, we must divide by w
|
|
||||||
case GX_PERSPECTIVE:
|
|
||||||
transformed[2] = orig_point[0] * world_matrix[8] + orig_point[1] * world_matrix[9] + orig_point[2] * world_matrix[10] + world_matrix[11];
|
|
||||||
screenPoint[0] = (transformed[0] * proj_matrix[0] + transformed[2] * proj_matrix[1]) / (-transformed[2]);
|
|
||||||
screenPoint[1] = (transformed[1] * proj_matrix[2] + transformed[2] * proj_matrix[3]) / (-transformed[2]);
|
|
||||||
screenPoint[2] = ((transformed[2] * proj_matrix[4] + proj_matrix[5]) * (1.0f - (float) 1e-7)) / (-transformed[2]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Orthographic projection
|
|
||||||
case GX_ORTHOGRAPHIC:
|
|
||||||
screenPoint[0] = transformed[0] * proj_matrix[0] + proj_matrix[1];
|
|
||||||
screenPoint[1] = transformed[1] * proj_matrix[2] + proj_matrix[3];
|
|
||||||
|
|
||||||
// We don't really have to care about z here
|
|
||||||
screenPoint[2] = -0.2f;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR_LOG(VIDEO, "Unknown projection type: %d", xfmem.projection.type);
|
|
||||||
screenPoint[0] = screenPoint[1] = screenPoint[2] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to screen space and add the point to the list - round like the real hardware
|
|
||||||
s_bbox_points[s_bbox_currPoint].x = (((s32) (0.5f + (16.0f * (screenPoint[0] * xfmem.viewport.wd + (xfmem.viewport.xOrig - 342.0f))))) + 3) >> 4;
|
|
||||||
s_bbox_points[s_bbox_currPoint].y = (((s32) (0.5f + (16.0f * (screenPoint[1] * xfmem.viewport.ht + (xfmem.viewport.yOrig - 342.0f))))) + 3) >> 4;
|
|
||||||
s_bbox_points[s_bbox_currPoint].z = screenPoint[2];
|
|
||||||
|
|
||||||
// Update point list for primitive
|
|
||||||
bool check_bbox = UpdateBoundingBoxVars();
|
|
||||||
|
|
||||||
// If we do not have enough points to check the bounding box yet, we are done for now
|
|
||||||
if (!check_bbox)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// How many points does our primitive have?
|
|
||||||
const u8 numPoints = s_bbox_primitivePoints[s_bbox_primitive];
|
|
||||||
|
|
||||||
// If the primitive is a point, update the bounding box now
|
|
||||||
if (numPoints == 1)
|
|
||||||
{
|
|
||||||
Point & p = s_bbox_points[0];
|
|
||||||
|
|
||||||
// Point is out of bounds
|
|
||||||
if (p.x < 0 || p.x > 607 || p.y < 0 || p.y > 479 || p.z >= 0.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Point is in bounds. Update bounding box if necessary and return
|
|
||||||
PixelEngine::bbox[0] = (p.x < PixelEngine::bbox[0]) ? p.x : PixelEngine::bbox[0];
|
|
||||||
PixelEngine::bbox[1] = (p.x > PixelEngine::bbox[1]) ? p.x : PixelEngine::bbox[1];
|
|
||||||
PixelEngine::bbox[2] = (p.y < PixelEngine::bbox[2]) ? p.y : PixelEngine::bbox[2];
|
|
||||||
PixelEngine::bbox[3] = (p.y > PixelEngine::bbox[3]) ? p.y : PixelEngine::bbox[3];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now comes the fun part. We must clip the triangles/lines to the viewport - also in software
|
|
||||||
Point & p0 = s_bbox_points[0], &p1 = s_bbox_points[1], &p2 = s_bbox_points[2];
|
|
||||||
|
|
||||||
// Check for z-clip. This crude method is required for Mickey's Magical Mirror, at least
|
|
||||||
if ((p0.z > 0.0f) || (p1.z > 0.0f) || ((numPoints == 3) && (p2.z > 0.0f)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check points for bounds
|
|
||||||
u8 b0 = ((p0.x > 0) ? 1 : 0) | ((p0.y > 0) ? 2 : 0) | ((p0.x > 607) ? 4 : 0) | ((p0.y > 479) ? 8 : 0);
|
|
||||||
u8 b1 = ((p1.x > 0) ? 1 : 0) | ((p1.y > 0) ? 2 : 0) | ((p1.x > 607) ? 4 : 0) | ((p1.y > 479) ? 8 : 0);
|
|
||||||
|
|
||||||
// Let's be practical... If we only have a line, setting b2 to 3 saves an "if"-clause later on
|
|
||||||
u8 b2 = 3;
|
|
||||||
|
|
||||||
// Otherwise if we have a triangle, we need to check the third point
|
|
||||||
if (numPoints == 3)
|
|
||||||
b2 = ((p2.x > 0) ? 1 : 0) | ((p2.y > 0) ? 2 : 0) | ((p2.x > 607) ? 4 : 0) | ((p2.y > 479) ? 8 : 0);
|
|
||||||
|
|
||||||
// These are the internal bbox vars
|
|
||||||
s32 left = 608, right = -1, top = 480, bottom = -1;
|
|
||||||
|
|
||||||
// If the polygon is inside viewport, let's update the bounding box and be done with it
|
|
||||||
if ((b0 == 3) && (b0 == b1) && (b0 == b2))
|
|
||||||
{
|
|
||||||
left = std::min(p0.x, p1.x);
|
|
||||||
top = std::min(p0.y, p1.y);
|
|
||||||
right = std::max(p0.x, p1.x);
|
|
||||||
bottom = std::max(p0.y, p1.y);
|
|
||||||
|
|
||||||
// Triangle
|
|
||||||
if (numPoints == 3)
|
|
||||||
{
|
|
||||||
left = std::min(left, p2.x);
|
|
||||||
top = std::min(top, p2.y);
|
|
||||||
right = std::max(right, p2.x);
|
|
||||||
bottom = std::max(bottom, p2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update bounding box
|
|
||||||
PixelEngine::bbox[0] = (left < PixelEngine::bbox[0]) ? left : PixelEngine::bbox[0];
|
|
||||||
PixelEngine::bbox[1] = (right > PixelEngine::bbox[1]) ? right : PixelEngine::bbox[1];
|
|
||||||
PixelEngine::bbox[2] = (top < PixelEngine::bbox[2]) ? top : PixelEngine::bbox[2];
|
|
||||||
PixelEngine::bbox[3] = (bottom > PixelEngine::bbox[3]) ? bottom : PixelEngine::bbox[3];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is not inside, then either it is completely outside, or it needs clipping.
|
|
||||||
// Check the primitive's lines
|
|
||||||
u8 i0 = b0 ^ b1;
|
|
||||||
u8 i1 = (numPoints == 3) ? (b1 ^ b2) : i0;
|
|
||||||
u8 i2 = (numPoints == 3) ? (b0 ^ b2) : i0;
|
|
||||||
|
|
||||||
// Primitive out of bounds - return
|
|
||||||
if (!(i0 | i1 | i2))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// First point inside viewport - update internal bbox
|
|
||||||
if (b0 == 3)
|
|
||||||
{
|
|
||||||
left = p0.x;
|
|
||||||
top = p0.y;
|
|
||||||
right = p0.x;
|
|
||||||
bottom = p0.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second point inside
|
|
||||||
if (b1 == 3)
|
|
||||||
{
|
|
||||||
left = std::min(p1.x, left);
|
|
||||||
top = std::min(p1.y, top);
|
|
||||||
right = std::max(p1.x, right);
|
|
||||||
bottom = std::max(p1.y, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Third point inside
|
|
||||||
if ((b2 == 3) && (numPoints == 3))
|
|
||||||
{
|
|
||||||
left = std::min(p2.x, left);
|
|
||||||
top = std::min(p2.y, top);
|
|
||||||
right = std::max(p2.x, right);
|
|
||||||
bottom = std::max(p2.y, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Triangle equation vars
|
|
||||||
float m, c;
|
|
||||||
|
|
||||||
// Some definitions to help with rounding later on
|
|
||||||
const float highNum = 89374289734.0f;
|
|
||||||
const float roundUp = 0.001f;
|
|
||||||
|
|
||||||
// Intersection result
|
|
||||||
s32 s;
|
|
||||||
|
|
||||||
// First line intersects
|
|
||||||
if (i0)
|
|
||||||
{
|
|
||||||
m = (p1.x - p0.x) ? ((p1.y - p0.y) / (p1.x - p0.x)) : highNum;
|
|
||||||
c = p0.y - (m * p0.x);
|
|
||||||
if (i0 & 1)
|
|
||||||
{
|
|
||||||
s = (s32)(c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
left = 0;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i0 & 2)
|
|
||||||
{
|
|
||||||
s = (s32)((-c / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
top = 0;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i0 & 4)
|
|
||||||
{
|
|
||||||
s = (s32)((m * 607) + c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
right = 607;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i0 & 8)
|
|
||||||
{
|
|
||||||
s = (s32)(((479 - c) / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
bottom = 479;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only check other lines if we are dealing with a triangle
|
|
||||||
if (numPoints == 3)
|
|
||||||
{
|
|
||||||
// Second line intersects
|
|
||||||
if (i1)
|
|
||||||
{
|
|
||||||
m = (p2.x - p1.x) ? ((p2.y - p1.y) / (p2.x - p1.x)) : highNum;
|
|
||||||
c = p1.y - (m * p1.x);
|
|
||||||
if (i1 & 1)
|
|
||||||
{
|
|
||||||
s = (s32)(c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
left = 0;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i1 & 2)
|
|
||||||
{
|
|
||||||
s = (s32)((-c / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
top = 0;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i1 & 4)
|
|
||||||
{
|
|
||||||
s = (s32)((m * 607) + c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
right = 607;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i1 & 8)
|
|
||||||
{
|
|
||||||
s = (s32)(((479 - c) / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
bottom = 479;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Third line intersects
|
|
||||||
if (i2)
|
|
||||||
{
|
|
||||||
m = (p2.x - p0.x) ? ((p2.y - p0.y) / (p2.x - p0.x)) : highNum;
|
|
||||||
c = p0.y - (m * p0.x);
|
|
||||||
if (i2 & 1)
|
|
||||||
{
|
|
||||||
s = (s32)(c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
left = 0;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2 & 2)
|
|
||||||
{
|
|
||||||
s = (s32)((-c / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
top = 0;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2 & 4)
|
|
||||||
{
|
|
||||||
s = (s32)((m * 607) + c + roundUp);
|
|
||||||
if (s >= 0 && s <= 479)
|
|
||||||
right = 607;
|
|
||||||
top = std::min(s, top);
|
|
||||||
bottom = std::max(s, bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2 & 8)
|
|
||||||
{
|
|
||||||
s = (s32)(((479 - c) / m) + roundUp);
|
|
||||||
if (s >= 0 && s <= 607)
|
|
||||||
bottom = 479;
|
|
||||||
left = std::min(s, left);
|
|
||||||
right = std::max(s, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrong bounding box values, discard this polygon (it is outside)
|
|
||||||
if (left > 607 || top > 479 || right < 0 || bottom < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Trim bounding box to viewport
|
|
||||||
left = (left < 0) ? 0 : left;
|
|
||||||
top = (top < 0) ? 0 : top;
|
|
||||||
right = (right > 607) ? 607 : right;
|
|
||||||
bottom = (bottom > 479) ? 479 : bottom;
|
|
||||||
|
|
||||||
// Update bounding box
|
|
||||||
PixelEngine::bbox[0] = (left < PixelEngine::bbox[0]) ? left : PixelEngine::bbox[0];
|
|
||||||
PixelEngine::bbox[1] = (right > PixelEngine::bbox[1]) ? right : PixelEngine::bbox[1];
|
|
||||||
PixelEngine::bbox[2] = (top < PixelEngine::bbox[2]) ? top : PixelEngine::bbox[2];
|
|
||||||
PixelEngine::bbox[3] = (bottom > PixelEngine::bbox[3]) ? bottom : PixelEngine::bbox[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LOADERDECL TexMtx_ReadDirect_UByte()
|
static void LOADERDECL TexMtx_ReadDirect_UByte()
|
||||||
{
|
{
|
||||||
s_curtexmtx[s_texmtxread] = DataReadU8() & 0x3f;
|
BoundingBox::texMtxIdx[s_texmtxread] = s_curtexmtx[s_texmtxread] = DataReadU8() & 0x3f;
|
||||||
|
|
||||||
PRIM_LOG("texmtx%d: %d, ", s_texmtxread, s_curtexmtx[s_texmtxread]);
|
PRIM_LOG("texmtx%d: %d, ", s_texmtxread, s_curtexmtx[s_texmtxread]);
|
||||||
s_texmtxread++;
|
s_texmtxread++;
|
||||||
}
|
}
|
||||||
@ -611,6 +170,10 @@ void VertexLoader::CompileVertexTranslator()
|
|||||||
m_numPipelineStages = 0;
|
m_numPipelineStages = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Get the pointer to this vertex's buffer data for the bounding box
|
||||||
|
if (g_ActiveConfig.bUseBBox)
|
||||||
|
WriteCall(BoundingBox::SetVertexBufferPosition);
|
||||||
|
|
||||||
// Colors
|
// Colors
|
||||||
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
|
||||||
// TextureCoord
|
// TextureCoord
|
||||||
@ -643,16 +206,8 @@ void VertexLoader::CompileVertexTranslator()
|
|||||||
if (m_VtxDesc.Tex7MatIdx) {m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX7; WriteCall(TexMtx_ReadDirect_UByte); }
|
if (m_VtxDesc.Tex7MatIdx) {m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX7; WriteCall(TexMtx_ReadDirect_UByte); }
|
||||||
|
|
||||||
// Write vertex position loader
|
// Write vertex position loader
|
||||||
if (g_ActiveConfig.bUseBBox)
|
|
||||||
{
|
|
||||||
WriteCall(UpdateBoundingBoxPrepare);
|
|
||||||
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements));
|
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements));
|
||||||
WriteCall(UpdateBoundingBox);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteCall(VertexLoader_Position::GetFunction(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements));
|
|
||||||
}
|
|
||||||
m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements);
|
m_VertexSize += VertexLoader_Position::GetSize(m_VtxDesc.Position, m_VtxAttr.PosFormat, m_VtxAttr.PosElements);
|
||||||
nat_offset += 12;
|
nat_offset += 12;
|
||||||
m_native_vtx_decl.position.components = 3;
|
m_native_vtx_decl.position.components = 3;
|
||||||
@ -826,6 +381,10 @@ void VertexLoader::CompileVertexTranslator()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the bounding box
|
||||||
|
if (g_ActiveConfig.bUseBBox)
|
||||||
|
WriteCall(BoundingBox::Update);
|
||||||
|
|
||||||
if (m_VtxDesc.PosMatIdx)
|
if (m_VtxDesc.PosMatIdx)
|
||||||
{
|
{
|
||||||
WriteCall(PosMtx_Write);
|
WriteCall(PosMtx_Write);
|
||||||
@ -901,9 +460,7 @@ void VertexLoader::SetupRunVertices(const VAT& vat, int primitive, int const cou
|
|||||||
colElements[i] = m_VtxAttr.color[i].Elements;
|
colElements[i] = m_VtxAttr.color[i].Elements;
|
||||||
|
|
||||||
// Prepare bounding box
|
// Prepare bounding box
|
||||||
s_bbox_primitive = primitive;
|
BoundingBox::Prepare(vat, primitive, m_VtxDesc, m_native_vtx_decl);
|
||||||
s_bbox_currPoint = 0;
|
|
||||||
s_bbox_loadedPoints = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexLoader::ConvertVertices ( int count )
|
void VertexLoader::ConvertVertices ( int count )
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|x64">
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
@ -36,6 +36,7 @@
|
|||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="AVIDump.cpp" />
|
<ClCompile Include="AVIDump.cpp" />
|
||||||
|
<ClCompile Include="BoundingBox.cpp" />
|
||||||
<ClCompile Include="BPFunctions.cpp" />
|
<ClCompile Include="BPFunctions.cpp" />
|
||||||
<ClCompile Include="BPMemory.cpp" />
|
<ClCompile Include="BPMemory.cpp" />
|
||||||
<ClCompile Include="BPStructs.cpp" />
|
<ClCompile Include="BPStructs.cpp" />
|
||||||
@ -80,6 +81,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AVIDump.h" />
|
<ClInclude Include="AVIDump.h" />
|
||||||
|
<ClInclude Include="BoundingBox.h" />
|
||||||
<ClInclude Include="BPFunctions.h" />
|
<ClInclude Include="BPFunctions.h" />
|
||||||
<ClInclude Include="BPMemory.h" />
|
<ClInclude Include="BPMemory.h" />
|
||||||
<ClInclude Include="BPStructs.h" />
|
<ClInclude Include="BPStructs.h" />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Base">
|
<Filter Include="Base">
|
||||||
@ -140,6 +140,9 @@
|
|||||||
<ClCompile Include="TextureDecoder_x64.cpp">
|
<ClCompile Include="TextureDecoder_x64.cpp">
|
||||||
<Filter>Decoding</Filter>
|
<Filter>Decoding</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="BoundingBox.cpp">
|
||||||
|
<Filter>Util</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="CommandProcessor.h" />
|
<ClInclude Include="CommandProcessor.h" />
|
||||||
@ -269,6 +272,9 @@
|
|||||||
<ClInclude Include="VertexLoaderManager.h">
|
<ClInclude Include="VertexLoaderManager.h">
|
||||||
<Filter>Vertex Loading</Filter>
|
<Filter>Vertex Loading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="BoundingBox.h">
|
||||||
|
<Filter>Util</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/BPMemory.h"
|
#include "VideoCommon/BPMemory.h"
|
||||||
#include "VideoCommon/CommandProcessor.h"
|
#include "VideoCommon/CommandProcessor.h"
|
||||||
#include "VideoCommon/CPMemory.h"
|
#include "VideoCommon/CPMemory.h"
|
||||||
@ -52,6 +53,10 @@ static void DoState(PointerWrap &p)
|
|||||||
VertexManager::DoState(p);
|
VertexManager::DoState(p);
|
||||||
p.DoMarker("VertexManager");
|
p.DoMarker("VertexManager");
|
||||||
|
|
||||||
|
BoundingBox::DoState(p);
|
||||||
|
p.DoMarker("BoundingBox");
|
||||||
|
|
||||||
|
|
||||||
// TODO: search for more data that should be saved and add it here
|
// TODO: search for more data that should be saved and add it here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user