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.

This commit is contained in:
Ian Curtis 2016-06-16 20:05:29 +00:00
parent f31f06b42e
commit c2b1db11f8
9 changed files with 262 additions and 30 deletions

View file

@ -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:

View file

@ -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();
}

View file

@ -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<NodeAttribs> m_vecAttribs;
};

View file

@ -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
@ -402,22 +401,36 @@ void CNew3D::DescendCullingNode(UINT32 addr)
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

View file

@ -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

View file

@ -0,0 +1,23 @@
#ifndef _PLANE_H_
#define _PLANE_H_
#include <cmath>
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

View file

@ -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

View file

@ -535,6 +535,7 @@ xcopy /D /Y "$(ProjectDir)\SDL\$(Platform)\$(Configuration)\SDL.dll" "$(TargetDi
<ClInclude Include="..\Src\Graphics\New3D\Mat4.h" />
<ClInclude Include="..\Src\Graphics\New3D\Model.h" />
<ClInclude Include="..\Src\Graphics\New3D\New3D.h" />
<ClInclude Include="..\Src\Graphics\New3D\Plane.h" />
<ClInclude Include="..\Src\Graphics\New3D\PolyHeader.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DData.h" />
<ClInclude Include="..\Src\Graphics\New3D\R3DShader.h" />

View file

@ -784,6 +784,9 @@
<ClInclude Include="..\Src\Util\BMPFile.h">
<Filter>Header Files\Util</Filter>
</ClInclude>
<ClInclude Include="..\Src\Graphics\New3D\Plane.h">
<Filter>Source Files\Graphics\New</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\Src\Debugger\ReadMe.txt">