summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/VertexLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoCommon/VertexLoader.cpp')
-rw-r--r--Source/Core/VideoCommon/VertexLoader.cpp473
1 files changed, 15 insertions, 458 deletions
diff --git a/Source/Core/VideoCommon/VertexLoader.cpp b/Source/Core/VideoCommon/VertexLoader.cpp
index b2f3cd7a4e..8bef28cc90 100644
--- a/Source/Core/VideoCommon/VertexLoader.cpp
+++ b/Source/Core/VideoCommon/VertexLoader.cpp
@@ -14,6 +14,7 @@
#include "VideoCommon/LookUpTables.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/VertexLoader.h"
+#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/VertexLoader_Color.h"
#include "VideoCommon/VertexLoader_Normal.h"
#include "VideoCommon/VertexLoader_Position.h"
@@ -21,8 +22,6 @@
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
-//BBox
-#include "VideoCommon/XFMemory.h"
#define COMPILED_CODE_SIZE 4096
@@ -45,21 +44,6 @@ int colElements[2];
float posScale;
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] = {
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),
@@ -75,7 +59,7 @@ using namespace Gen;
static void LOADERDECL PosMtx_ReadDirect_UByte()
{
- s_curposmtx = DataReadU8() & 0x3f;
+ BoundingBox::posMtxIdx = s_curposmtx = DataReadU8() & 0x3f;
PRIM_LOG("posmtx: %d, ", s_curposmtx);
}
@@ -85,437 +69,12 @@ static void LOADERDECL PosMtx_Write()
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()
{
- 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]);
s_texmtxread++;
}
@@ -611,6 +170,10 @@ void VertexLoader::CompileVertexTranslator()
m_numPipelineStages = 0;
#endif
+ // Get the pointer to this vertex's buffer data for the bounding box
+ if (g_ActiveConfig.bUseBBox)
+ WriteCall(BoundingBox::SetVertexBufferPosition);
+
// Colors
const u64 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1};
// TextureCoord
@@ -643,16 +206,8 @@ void VertexLoader::CompileVertexTranslator()
if (m_VtxDesc.Tex7MatIdx) {m_VertexSize += 1; components |= VB_HAS_TEXMTXIDX7; WriteCall(TexMtx_ReadDirect_UByte); }
// Write vertex position loader
- if (g_ActiveConfig.bUseBBox)
- {
- WriteCall(UpdateBoundingBoxPrepare);
- 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));
- }
+ 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);
nat_offset += 12;
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)
{
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;
// Prepare bounding box
- s_bbox_primitive = primitive;
- s_bbox_currPoint = 0;
- s_bbox_loadedPoints = 0;
+ BoundingBox::Prepare(vat, primitive, m_VtxDesc, m_native_vtx_decl);
}
void VertexLoader::ConvertVertices ( int count )