diff options
Diffstat (limited to 'Source/Core/VideoCommon/VertexLoader.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/VertexLoader.cpp | 473 |
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 ) |
