From c2b1db11f8b2777fa074366c203f93263acf6df7 Mon Sep 17 00:00:00 2001 From: Ian Curtis Date: Thu, 16 Jun 2016 20:05:29 +0000 Subject: [PATCH] Cull geometry based on the culling distances in the nodes. Should give some sort of speedup on lower end pcs where the CPU is predominantly the bottle neck. --- Src/Graphics/Legacy3D/Models.cpp | 4 +- Src/Graphics/New3D/Model.cpp | 29 +++-- Src/Graphics/New3D/Model.h | 4 + Src/Graphics/New3D/New3D.cpp | 208 +++++++++++++++++++++++++++--- Src/Graphics/New3D/New3D.h | 15 +++ Src/Graphics/New3D/Plane.h | 23 ++++ Src/Graphics/New3D/Vec.h | 5 + VS2008/Supermodel.vcxproj | 1 + VS2008/Supermodel.vcxproj.filters | 3 + 9 files changed, 262 insertions(+), 30 deletions(-) create mode 100644 Src/Graphics/New3D/Plane.h diff --git a/Src/Graphics/Legacy3D/Models.cpp b/Src/Graphics/Legacy3D/Models.cpp index aa7331c..3d952d2 100644 --- a/Src/Graphics/Legacy3D/Models.cpp +++ b/Src/Graphics/Legacy3D/Models.cpp @@ -473,8 +473,8 @@ void CLegacy3D::InsertVertex(ModelCache *Cache, const Vertex *V, const Poly *P, GLfloat texWidth = (GLfloat) (32<<((P->header[3]>>3)&7)); GLfloat texHeight = (GLfloat) (32<<((P->header[3]>>0)&7)); TexSheet *texSheet = fmtToTexSheet[texFormat]; // get X, Y offset of texture sheet within texture map - GLfloat texBaseX = texSheet->xOffset + GetTextureBaseX(P); - GLfloat texBaseY = texSheet->yOffset + GetTextureBaseY(P); + GLfloat texBaseX = (GLfloat)(texSheet->xOffset + GetTextureBaseX(P)); + GLfloat texBaseY = (GLfloat)(texSheet->yOffset + GetTextureBaseY(P)); /* * Lighting and Color Modulation: diff --git a/Src/Graphics/New3D/Model.cpp b/Src/Graphics/New3D/Model.cpp index 632ec29..a3a10fe 100644 --- a/Src/Graphics/New3D/Model.cpp +++ b/Src/Graphics/New3D/Model.cpp @@ -4,9 +4,10 @@ namespace New3D { NodeAttributes::NodeAttributes() { - currentTexOffsetX = 0; - currentTexOffsetY = 0; - currentPage = 0; + currentTexOffsetX = 0; + currentTexOffsetY = 0; + currentPage = 0; + currentClipStatus = Clip::INTERCEPT; } bool NodeAttributes::Push() @@ -20,9 +21,10 @@ bool NodeAttributes::Push() return false; } - na.page = currentPage; - na.texOffsetX = currentTexOffsetX; - na.texOffsetY = currentTexOffsetY; + na.page = currentPage; + na.texOffsetX = currentTexOffsetX; + na.texOffsetY = currentTexOffsetY; + na.clip = currentClipStatus; m_vecAttribs.push_back(na); @@ -37,9 +39,10 @@ bool NodeAttributes::Pop() auto last = &m_vecAttribs.back(); - currentPage = last->page; - currentTexOffsetX = last->texOffsetX; - currentTexOffsetY = last->texOffsetY; + currentPage = last->page; + currentTexOffsetX = last->texOffsetX; + currentTexOffsetY = last->texOffsetY; + currentClipStatus = last->clip; m_vecAttribs.pop_back(); @@ -53,9 +56,11 @@ bool NodeAttributes::StackLimit() void NodeAttributes::Reset() { - currentPage = 0; - currentTexOffsetX = 0; - currentTexOffsetY = 0; + currentPage = 0; + currentTexOffsetX = 0; + currentTexOffsetY = 0; + currentClipStatus = Clip::INTERCEPT; + m_vecAttribs.clear(); } diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index 0b89a8a..f61a27d 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -100,6 +100,8 @@ struct Viewport int priority; }; +enum class Clip { INSIDE, OUTSIDE, INTERCEPT }; + class NodeAttributes { public: @@ -114,6 +116,7 @@ public: int currentTexOffsetX; int currentTexOffsetY; int currentPage; + Clip currentClipStatus; private: @@ -122,6 +125,7 @@ private: int texOffsetX; int texOffsetY; int page; + Clip clip; }; std::vector m_vecAttribs; }; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index 18b598b..438ffd5 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -342,6 +342,7 @@ void CNew3D::DescendCullingNode(UINT32 addr) UINT32 matrixOffset, child1Ptr, sibling2Ptr; float x, y, z; int tx, ty; + BBox bbox; if (m_nodeAttribs.StackLimit()) { return; @@ -358,8 +359,6 @@ void CNew3D::DescendCullingNode(UINT32 addr) sibling2Ptr = node[0x08 - m_offset] & 0x1FFFFFF; // mask colour table bits matrixOffset = node[0x03 - m_offset] & 0xFFF; - float test = ToFloat(Convert16BitProFloat(node[9 - m_offset] >> 16)); - if ((node[0x00] & 0x07) != 0x06) { // colour table seems to indicate no siblings if (!(sibling2Ptr & 0x1000000) && sibling2Ptr) { DescendCullingNode(sibling2Ptr); // no need to mask bit, would already be zero @@ -400,24 +399,38 @@ void CNew3D::DescendCullingNode(UINT32 addr) // multiply matrix, if specified else if (matrixOffset) { MultMatrix(matrixOffset,m_modelMat); - } + } - // Descend down first link - if ((node[0x00] & 0x08)) // 4-element LOD table - { - lodTable = TranslateCullingAddress(child1Ptr); + if (m_nodeAttribs.currentClipStatus != Clip::INSIDE) { - if (NULL != lodTable) { - if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); - } - else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO + float distance = ToFloat(Convert16BitProFloat(node[9 - m_offset] & 0xFFFF)); + + CalcBox(distance, bbox); + TransformBox(m_modelMat, bbox); + + m_nodeAttribs.currentClipStatus = ClipBox(bbox, m_planes); + } + + if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE) { + + // Descend down first link + if ((node[0x00] & 0x08)) // 4-element LOD table + { + lodTable = TranslateCullingAddress(child1Ptr); + + if (NULL != lodTable) { + if ((node[0x03 - m_offset] & 0x20000000)) { + DescendCullingNode(lodTable[0] & 0xFFFFFF); + } + else { + DrawModel(lodTable[0] & 0xFFFFFF); //TODO + } } } - } - else { - DescendNodePtr(child1Ptr); + else { + DescendNodePtr(child1Ptr); + } + } m_modelMat.PopMatrix(); @@ -671,6 +684,9 @@ void CNew3D::RenderViewport(UINT32 addr) vp->projectionMatrix.Frustum(l, r, b, t, near, far); } + // calculate frustum planes + CalcFrustumPlanes(m_planes, vp->projectionMatrix); + // Lighting (note that sun vector points toward sun -- away from vertex) vp->lightingParams[0] = *(float *)&vpnode[0x05]; // sun X vp->lightingParams[1] = *(float *)&vpnode[0x06]; // sun Y @@ -1209,5 +1225,165 @@ float CNew3D::ToFloat(UINT32 a1) return *(float*)(&a1); } +void CNew3D::CalcFrustumPlanes(Plane p[6], const float* matrix) +{ + // Left Plane + p[0].a = matrix[3] + matrix[0]; + p[0].b = matrix[7] + matrix[4]; + p[0].c = matrix[11] + matrix[8]; + p[0].d = matrix[15] + matrix[12]; + p[0].Normalise(); + + // Right Plane + p[1].a = matrix[3] - matrix[0]; + p[1].b = matrix[7] - matrix[4]; + p[1].c = matrix[11] - matrix[8]; + p[1].d = matrix[15] - matrix[12]; + p[1].Normalise(); + + // Bottom Plane + p[2].a = matrix[3] + matrix[1]; + p[2].b = matrix[7] + matrix[5]; + p[2].c = matrix[11] + matrix[9]; + p[2].d = matrix[15] + matrix[13]; + p[2].Normalise(); + + // Top Plane + p[3].a = matrix[3] - matrix[1]; + p[3].b = matrix[7] - matrix[5]; + p[3].c = matrix[11] - matrix[9]; + p[3].d = matrix[15] - matrix[13]; + p[3].Normalise(); + + // Near Plane + p[4].a = matrix[3] + matrix[2]; + p[4].b = matrix[7] + matrix[6]; + p[4].c = matrix[11] + matrix[10]; + p[4].d = matrix[15] + matrix[14]; + p[4].Normalise(); + + // Far Plane + p[5].a = matrix[3] - matrix[2]; + p[5].b = matrix[7] - matrix[6]; + p[5].c = matrix[11] - matrix[10]; + p[5].d = matrix[15] - matrix[14]; + p[5].Normalise(); +} + +void CNew3D::CalcBox(float distance, BBox& box) +{ + //bottom left front + box.points[0][0] = -distance; + box.points[0][1] = -distance; + box.points[0][2] = distance; + box.points[0][3] = 1; + + //bottom left back + box.points[1][0] = -distance; + box.points[1][1] = -distance; + box.points[1][2] = -distance; + box.points[1][3] = 1; + + //bottom right back + box.points[2][0] = distance; + box.points[2][1] = -distance; + box.points[2][2] = -distance; + box.points[2][3] = 1; + + //bottom right front + box.points[3][0] = distance; + box.points[3][1] = -distance; + box.points[3][2] = distance; + box.points[3][3] = 1; + + //top left front + box.points[4][0] = -distance; + box.points[4][1] = distance; + box.points[4][2] = distance; + box.points[4][3] = 1; + + //top left back + box.points[5][0] = -distance; + box.points[5][1] = distance; + box.points[5][2] = -distance; + box.points[5][3] = 1; + + //top right back + box.points[6][0] = distance; + box.points[6][1] = distance; + box.points[6][2] = -distance; + box.points[6][3] = 1; + + //top right front + box.points[7][0] = distance; + box.points[7][1] = distance; + box.points[7][2] = distance; + box.points[7][3] = 1; +} + +void CNew3D::MultVec(const float matrix[16], const float in[4], float out[4]) +{ + for (int i = 0; i < 4; i++) { + out[i] = + in[0] * matrix[0 * 4 + i] + + in[1] * matrix[1 * 4 + i] + + in[2] * matrix[2 * 4 + i] + + in[3] * matrix[3 * 4 + i]; + } +} + +void CNew3D::TransformBox(const float *m, BBox& box) +{ + for (int i = 0; i < 8; i++) { + float v[4]; + MultVec(m, box.points[i], v); + box.points[i][0] = v[0]; + box.points[i][1] = v[1]; + box.points[i][2] = v[2]; + } +} + +Clip CNew3D::ClipBox(BBox& box, Plane planes[6]) +{ + int count = 0; + + for (int i = 0; i < 8; i++) { + + int temp = 0; + + for (int j = 0; j < 6; j++) { + if (planes[j].DistanceToPoint(box.points[i]) >= 0) { + temp++; + } + } + + if (temp == 6) count++; // point is inside all 6 frustum planes + } + + if (count == 8) return Clip::INSIDE; + if (count > 0) return Clip::INTERCEPT; + + //if we got here all points are outside of the view frustum + //check for all points being side same of any plane, means box outside of view + + for (int i = 0; i < 6; i++) { + + int temp = 0; + + for (int j = 0; j < 8; j++) { + if (planes[i].DistanceToPoint(box.points[j]) >= 0) { + float distance = planes[i].DistanceToPoint(box.points[j]); + temp++; + } + } + + if (temp == 0) return Clip::OUTSIDE; + } + + //if we got here, box is traversing view frustum + + return Clip::INTERCEPT; +} + } // New3D diff --git a/Src/Graphics/New3D/New3D.h b/Src/Graphics/New3D/New3D.h index c28206c..19888b5 100644 --- a/Src/Graphics/New3D/New3D.h +++ b/Src/Graphics/New3D/New3D.h @@ -37,6 +37,8 @@ #include "R3DShader.h" #include "VBO.h" #include "R3DData.h" +#include "Plane.h" +#include "Vec.h" namespace New3D { @@ -218,6 +220,19 @@ private: VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow R3DShader m_r3dShader; + + Plane m_planes[6]; + + struct BBox + { + V4::Vec4 points[8]; + }; + + void CalcFrustumPlanes (Plane p[6], const float* matrix); + void CalcBox (float distance, BBox& box); + void TransformBox (const float *m, BBox& box); + void MultVec (const float matrix[16], const float in[4], float out[4]); + Clip ClipBox (BBox& box, Plane planes[6]); }; } // New3D diff --git a/Src/Graphics/New3D/Plane.h b/Src/Graphics/New3D/Plane.h new file mode 100644 index 0000000..d54f15f --- /dev/null +++ b/Src/Graphics/New3D/Plane.h @@ -0,0 +1,23 @@ +#ifndef _PLANE_H_ +#define _PLANE_H_ + +#include + +struct Plane +{ + float a, b, c, d; + + void Normalise() { + float temp = std::sqrt((a * a) + (b * b) + (c * c)); + a /= temp; + b /= temp; + c /= temp; + d /= temp; + } + + float DistanceToPoint(const float v[3]) { + return a*v[0] + b*v[1] + c*v[2] + d; + } +}; + +#endif \ No newline at end of file diff --git a/Src/Graphics/New3D/Vec.h b/Src/Graphics/New3D/Vec.h index cc38bd6..75e0005 100644 --- a/Src/Graphics/New3D/Vec.h +++ b/Src/Graphics/New3D/Vec.h @@ -32,6 +32,11 @@ namespace V3 bool cmp (const Vec3 a, const Vec3 b); void clamp (Vec3 a, float _min, float _max); } + +namespace V4 +{ + typedef float Vec4[4]; +} } // New3D #endif \ No newline at end of file diff --git a/VS2008/Supermodel.vcxproj b/VS2008/Supermodel.vcxproj index adb0a86..a8d337f 100644 --- a/VS2008/Supermodel.vcxproj +++ b/VS2008/Supermodel.vcxproj @@ -535,6 +535,7 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi + diff --git a/VS2008/Supermodel.vcxproj.filters b/VS2008/Supermodel.vcxproj.filters index 7150f52..63c7437 100644 --- a/VS2008/Supermodel.vcxproj.filters +++ b/VS2008/Supermodel.vcxproj.filters @@ -784,6 +784,9 @@ Header Files\Util + + Source Files\Graphics\New +