port from perforce
This commit is contained in:
465
4kgfx/mesh.cpp
Normal file
465
4kgfx/mesh.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
Mesh::Mesh()
|
||||
: IndexCount(0)
|
||||
, VertexCount(0)
|
||||
{
|
||||
glGenVertexArrays(1, &VertexArrayObject);
|
||||
glBindVertexArray(VertexArrayObject);
|
||||
|
||||
glGenBuffers(1, &VertexArrayBuffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexArrayBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, MaxVertexBuffer * sizeof(MeshVertex), 0, GL_STATIC_DRAW);
|
||||
|
||||
glGenBuffers(1, &IndexBufferObject);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObject);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MaxIndexBuffer * sizeof(unsigned short), NULL, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Render()
|
||||
{
|
||||
glBindVertexArray(VertexArrayObject);
|
||||
|
||||
unsigned int positionId = glGetAttribLocation(currentProgramId, "inPosition");
|
||||
unsigned int normalId = glGetAttribLocation(currentProgramId, "inNormal");
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObject);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexArrayBuffer);
|
||||
|
||||
glEnableVertexAttribArray(positionId);
|
||||
glVertexAttribPointer(positionId, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), (const GLvoid*)0);
|
||||
|
||||
glEnableVertexAttribArray(normalId);
|
||||
glVertexAttribPointer(normalId, 4, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), (const GLvoid*)16);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Lock()
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObject);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexArrayBuffer);
|
||||
|
||||
IndexBuffer = (unsigned short*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE);
|
||||
VertexBuffer = (MeshVertex*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Unlock()
|
||||
{
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||
}
|
||||
|
||||
|
||||
void Mesh::GenerateNormals()
|
||||
{
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
{
|
||||
VertexBuffer[i].Normal = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < IndexCount; )
|
||||
{
|
||||
int count = IndexBuffer[i];
|
||||
++i;
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
int index = IndexBuffer[i + j];
|
||||
int indexPrev = IndexBuffer[i + ((j + count - 1) % count)];
|
||||
int indexNext = IndexBuffer[i + ((j + 1) % count)];
|
||||
vec4 p1(VertexBuffer[indexPrev].Position - VertexBuffer[index].Position);
|
||||
vec4 p2(VertexBuffer[indexNext].Position - VertexBuffer[index].Position);
|
||||
VertexBuffer[index].Normal += cross(p1, p2);
|
||||
}
|
||||
i += count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::NormalizeNormals()
|
||||
{
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
{
|
||||
VertexBuffer[i].Normal = normalize(VertexBuffer[i].Normal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Triangulate() // Converts polygons into triangle fans
|
||||
{
|
||||
OP.Reset();
|
||||
OP.NextVertexCount = 0;
|
||||
OP.NextFaceCount = 0;
|
||||
for (int i = 0; i < IndexCount;)
|
||||
{
|
||||
int count = IndexBuffer[i++];
|
||||
int firstVertex = IndexBuffer[i++];
|
||||
int secondVertex = IndexBuffer[i++];
|
||||
int j = 0;
|
||||
do
|
||||
{
|
||||
OP.NextIB[OP.NextIndexCount++] = firstVertex;
|
||||
OP.NextIB[OP.NextIndexCount++] = secondVertex;
|
||||
OP.NextIB[OP.NextIndexCount++] = IndexBuffer[i + j];
|
||||
OP.NextFaceCount++;
|
||||
secondVertex = IndexBuffer[i + j++];
|
||||
} while (j < count - 2);
|
||||
i += count - 2;
|
||||
}
|
||||
|
||||
memcpy(IndexBuffer, OP.NextIB, MaxIndexBuffer * sizeof(unsigned short));
|
||||
IndexCount = OP.NextIndexCount;
|
||||
FaceCount = OP.NextFaceCount;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::CatmullClarkSubdivide()
|
||||
{
|
||||
if (IndexCount >= MaxIndexBuffer / 4 || VertexCount >= MaxVertexBuffer * 9 / 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// neuer VB ist so:
|
||||
// alter VB bzw. verschobene Originalpunkte
|
||||
// ein Vertex pro Face (FacePunkte)
|
||||
// ein Vertex pro Edge (EdgePunkte)
|
||||
|
||||
//neuer IB ist so:
|
||||
// 4 / alte Ecke0 / EdgePunkt / FaceFacePunkt / EdgePunkt
|
||||
// 4 / alte Ecke1 / EdgePunkt / FaceFacePunkt / EdgePunkt
|
||||
//...
|
||||
// 4 / alte EckeN / EdgePunkt / FaceFacePunkt / EdgePunkt (N = = Vertexcount)
|
||||
//beim kopieren dann ueberall noch 4
|
||||
|
||||
OP.Reset();
|
||||
OP.NextVertexCount = VertexCount + FaceCount; //Basis Vertices sind die alte Ecken und die neuen FacePunkte
|
||||
|
||||
int face = 0;
|
||||
for (int i = 0; i < IndexCount;)
|
||||
{
|
||||
int count = IndexBuffer[i++];
|
||||
vec4& fp = OP.NextVB[VertexCount + face].Position;
|
||||
unsigned short int* ib = OP.NextIB + OP.NextIndexCount;
|
||||
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
int index = IndexBuffer[i + j];
|
||||
fp += VertexBuffer[index].Position;
|
||||
ib[j * 5] = 4;
|
||||
ib[j * 5 + 1] = index;
|
||||
ib[j * 5 + 3] = VertexCount + face; // erste Haelfte IB fertig
|
||||
}
|
||||
fp /= (float)count; // jetzt ist der FacePunkt fertig
|
||||
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
int index = IndexBuffer[i + j];
|
||||
int indexNext = IndexBuffer[i + ((j + 1) % count)];
|
||||
int Edge = OP.MakeEdgeID(index, indexNext);
|
||||
OP.NextVB[OP.EdgeID[Edge]].Position += fp; // Summe aller FacePunkte zu dieser Ecke sind hier
|
||||
|
||||
ib[j * 5 + 2] = OP.EdgeID[Edge];
|
||||
ib[(j * 5 + 9) % (count * 5)] = OP.EdgeID[Edge]; // IB fertig!
|
||||
|
||||
OP.NextVB[index].Position += fp; //Summe aller FacePunkte die an diesen Originalpunkt grenzen
|
||||
}
|
||||
|
||||
i += count;
|
||||
face++;
|
||||
OP.NextIndexCount += count * 5;
|
||||
OP.NextFaceCount += count;
|
||||
}
|
||||
|
||||
// Originalpunkte verschieben
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
{
|
||||
bool openEdges = false; // gab es offene Kanten (d.h. einseitig benutze?)
|
||||
vec4 edgesVector(0,0,0,0);
|
||||
vec4 openEdgesVector(0,0,0,0);
|
||||
int edgeCount = 0;
|
||||
int openEdgeCount = 0;
|
||||
|
||||
for (int j = 0; j < OP.EdgeCount; ++j)
|
||||
{
|
||||
int V1 = (OP.EdgeConfiguration[j] & 0x0000ffff);
|
||||
int V2 = (OP.EdgeConfiguration[j] & 0xffff0000) >> 16;
|
||||
if (V1 == i || V2 == i)
|
||||
{
|
||||
vec4 mid = VertexBuffer[V1].Position + VertexBuffer[V2].Position;
|
||||
if (OP.EdgeUsage[j] == 1)
|
||||
{
|
||||
openEdges = true;
|
||||
openEdgeCount++;
|
||||
openEdgesVector += mid;
|
||||
}
|
||||
edgeCount++;
|
||||
edgesVector += mid;
|
||||
}
|
||||
}
|
||||
|
||||
if (openEdges)
|
||||
{
|
||||
OP.NextVB[i].Position = openEdgesVector / (float)(openEdgeCount * 4) + VertexBuffer[i].Position * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
OP.NextVB[i].Position =
|
||||
OP.NextVB[i].Position / (float)edgeCount +
|
||||
edgesVector / (float)edgeCount +
|
||||
VertexBuffer[i].Position * (float)(edgeCount - 3);
|
||||
OP.NextVB[i].Position /= (float)edgeCount;
|
||||
}
|
||||
}
|
||||
|
||||
//EdgePunkte anpassen
|
||||
for (int j = 0; j < OP.EdgeCount; ++j)
|
||||
{
|
||||
int V1 = (OP.EdgeConfiguration[j] & 0x0000ffff);
|
||||
int V2 = (OP.EdgeConfiguration[j] & 0xffff0000) >> 16;
|
||||
if (OP.EdgeUsage[j] < 2)
|
||||
{
|
||||
OP.NextVB[OP.EdgeID[j]].Position = vec4(0,0,0,0);
|
||||
OP.EdgeUsage[j] = 0;
|
||||
}
|
||||
|
||||
OP.NextVB[OP.EdgeID[j]].Position += VertexBuffer[V1].Position;
|
||||
OP.NextVB[OP.EdgeID[j]].Position += VertexBuffer[V2].Position;
|
||||
OP.NextVB[OP.EdgeID[j]].Position /= (float)(OP.EdgeUsage[j] + 2);
|
||||
}
|
||||
|
||||
memcpy(VertexBuffer, OP.NextVB, MaxVertexBuffer * sizeof(MeshVertex));
|
||||
memcpy(IndexBuffer, OP.NextIB, MaxIndexBuffer * sizeof(unsigned short));
|
||||
VertexCount = OP.NextVertexCount;
|
||||
IndexCount = OP.NextIndexCount;
|
||||
FaceCount = OP.NextFaceCount;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Extrude(float fExtend)
|
||||
{
|
||||
OP.Reset();
|
||||
|
||||
for (int i = 0; i < IndexCount;)
|
||||
{
|
||||
int count = IndexBuffer[i];
|
||||
IndexBuffer[i + IndexCount] = count;
|
||||
++i;
|
||||
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
int index = IndexBuffer[i + j];
|
||||
int indexNext = IndexBuffer[i + ((j + 1) % count)];
|
||||
int ID = OP.MakeEdgeID(index, indexNext);
|
||||
if (index > indexNext)
|
||||
{
|
||||
OP.EdgeUsage[ID] += 0x80;
|
||||
}
|
||||
IndexBuffer[i + IndexCount + count - j - 1] = index + VertexCount;
|
||||
}
|
||||
i += count;
|
||||
}
|
||||
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
{
|
||||
VertexBuffer[i + VertexCount].Position = VertexBuffer[i].Position;
|
||||
VertexBuffer[i].Position.z -= fExtend;
|
||||
VertexBuffer[i + VertexCount].Position.z += fExtend;
|
||||
}
|
||||
|
||||
IndexCount *= 2;
|
||||
FaceCount *= 2;
|
||||
|
||||
for (int i = 0; i < OP.EdgeCount; ++i)
|
||||
{
|
||||
if ((OP.EdgeUsage[i] & 0x7f) == 1)
|
||||
{
|
||||
int iAdd = OP.EdgeUsage[i] == 1 ? 0 : VertexCount;
|
||||
int V1 = (OP.EdgeConfiguration[i] & 0x0000ffff);
|
||||
int V2 = (OP.EdgeConfiguration[i] & 0xffff0000) >> 16;
|
||||
IndexBuffer[IndexCount++] = 4;
|
||||
IndexBuffer[IndexCount++] = V1 + iAdd;
|
||||
iAdd = VertexCount - iAdd;
|
||||
IndexBuffer[IndexCount++] = V1 + iAdd;
|
||||
IndexBuffer[IndexCount++] = V2 + iAdd;
|
||||
iAdd = VertexCount - iAdd;
|
||||
IndexBuffer[IndexCount++] = V2 + iAdd;
|
||||
FaceCount += 1;
|
||||
}
|
||||
}
|
||||
VertexCount *= 2;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::OpInfo::Reset()
|
||||
{
|
||||
memclear(NextVB, sizeof (NextVB));
|
||||
memclear(NextIB, sizeof (NextIB));
|
||||
memclear(EdgeConfiguration, sizeof (EdgeConfiguration));
|
||||
memclear(EdgeUsage, sizeof (EdgeUsage));
|
||||
memclear(EdgeID, sizeof (EdgeID));
|
||||
|
||||
NextVertexCount = 0;
|
||||
NextIndexCount = 0;
|
||||
NextFaceCount = 0;
|
||||
|
||||
EdgeCount = 0;
|
||||
}
|
||||
|
||||
|
||||
int Mesh::OpInfo::MakeEdgeID (unsigned short VertexA, unsigned short VertexB)
|
||||
{
|
||||
unsigned int edgeConfiguration = VertexA > VertexB ? (VertexA << 16 | VertexB) : (VertexB << 16 | VertexA);
|
||||
|
||||
for (int i = 0; i < EdgeCount; ++i)
|
||||
{
|
||||
if (EdgeConfiguration[i] == edgeConfiguration)
|
||||
{
|
||||
EdgeUsage[i]++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
EdgeConfiguration[EdgeCount] = edgeConfiguration;
|
||||
EdgeUsage[EdgeCount]++;
|
||||
EdgeID[EdgeCount] = NextVertexCount;
|
||||
NextVertexCount++;
|
||||
|
||||
return EdgeCount++;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::StandardSubdivide()
|
||||
{
|
||||
OP.Reset();
|
||||
memcpy(OP.NextVB, VertexBuffer, VertexCount * sizeof(MeshVertex));
|
||||
OP.NextVertexCount = VertexCount;
|
||||
|
||||
int face = 0;
|
||||
for (int i = 0; i < IndexCount; ++face)
|
||||
{
|
||||
int count = IndexBuffer[i++];
|
||||
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
int prevIndex = j - 1;
|
||||
if (prevIndex < 0)
|
||||
prevIndex += count;
|
||||
prevIndex = IndexBuffer[i + prevIndex];
|
||||
int index = IndexBuffer[i + j];
|
||||
int nextIndex = IndexBuffer[i + ((j + 1) % count)];
|
||||
int prevEdgeID = OP.EdgeID[OP.MakeEdgeID(prevIndex, index)];
|
||||
int nextEdgeID = OP.EdgeID[OP.MakeEdgeID(index, nextIndex)];
|
||||
OP.NextVB[prevEdgeID].Position = (VertexBuffer[prevIndex].Position + VertexBuffer[index].Position) / 2;
|
||||
OP.NextVB[nextEdgeID].Position = (VertexBuffer[nextIndex].Position + VertexBuffer[index].Position) / 2;
|
||||
OP.NextIB[OP.NextIndexCount + 0] = 4;
|
||||
OP.NextIB[OP.NextIndexCount + 1] = 0; // will be set later (face offset)
|
||||
OP.NextIB[OP.NextIndexCount + 2] = prevEdgeID;
|
||||
OP.NextIB[OP.NextIndexCount + 3] = index;
|
||||
OP.NextIB[OP.NextIndexCount + 4] = nextEdgeID;
|
||||
OP.NextIndexCount += 5;
|
||||
++OP.NextFaceCount;
|
||||
}
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
||||
int vbFaceOffset = OP.NextVertexCount;
|
||||
int ibIndex = 1;
|
||||
face = 0;
|
||||
for (int i = 0; i < IndexCount; ++face)
|
||||
{
|
||||
int count = IndexBuffer[i++];
|
||||
|
||||
vec4 fp;
|
||||
for (int j = 0; j < count; ++j)
|
||||
{
|
||||
fp += VertexBuffer[IndexBuffer[i + j]].Position;
|
||||
OP.NextIB[ibIndex] = vbFaceOffset + face;
|
||||
ibIndex += 5;
|
||||
}
|
||||
OP.NextVB[vbFaceOffset + face].Position = fp / (float)count;
|
||||
++OP.NextVertexCount;
|
||||
i += count;
|
||||
}
|
||||
|
||||
memcpy(VertexBuffer, OP.NextVB, MaxVertexBuffer * sizeof(MeshVertex));
|
||||
memcpy(IndexBuffer, OP.NextIB, MaxIndexBuffer * sizeof(unsigned short));
|
||||
VertexCount = OP.NextVertexCount;
|
||||
IndexCount = OP.NextIndexCount;
|
||||
FaceCount = OP.NextFaceCount;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::CreateCube()
|
||||
{
|
||||
Lock();
|
||||
VertexBuffer[0].Position = vec4(-2, -1, 0, 1);
|
||||
VertexBuffer[1].Position = vec4(-2, 1, 0, 1);
|
||||
VertexBuffer[2].Position = vec4(2, 1, 0, 1);
|
||||
VertexBuffer[3].Position = vec4(2, -1, 0, 1);
|
||||
VertexCount = 4;
|
||||
IndexBuffer[0] = 4;
|
||||
IndexBuffer[1] = 0;
|
||||
IndexBuffer[2] = 1;
|
||||
IndexBuffer[3] = 2;
|
||||
IndexBuffer[4] = 3;
|
||||
IndexCount = 5;
|
||||
FaceCount = 1;
|
||||
Extrude(1.0f);
|
||||
GenerateNormals();
|
||||
Triangulate();
|
||||
Homogenize();
|
||||
Unlock();
|
||||
}
|
||||
|
||||
|
||||
void Mesh::CreateSphere(unsigned int lod)
|
||||
{
|
||||
Lock();
|
||||
VertexBuffer[0].Position = vec4(-1, -1, 0, 1);
|
||||
VertexBuffer[1].Position = vec4(-1, 1, 0, 1);
|
||||
VertexBuffer[2].Position = vec4(1, 1, 0, 1);
|
||||
VertexBuffer[3].Position = vec4(1, -1, 0, 1);
|
||||
VertexCount = 4;
|
||||
IndexBuffer[0] = 4;
|
||||
IndexBuffer[1] = 0;
|
||||
IndexBuffer[2] = 1;
|
||||
IndexBuffer[3] = 2;
|
||||
IndexBuffer[4] = 3;
|
||||
IndexCount = 5;
|
||||
FaceCount = 1;
|
||||
Extrude(1.0f);
|
||||
for (unsigned int i = 0; i < lod; ++i)
|
||||
CatmullClarkSubdivide();
|
||||
GenerateNormals();
|
||||
Triangulate();
|
||||
Homogenize();
|
||||
Unlock();
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Homogenize()
|
||||
{
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
VertexBuffer[i].Position.w = 1;
|
||||
}
|
||||
|
||||
|
||||
void Mesh::Transform(const Matrix& transform)
|
||||
{
|
||||
Lock();
|
||||
for (int i = 0; i < VertexCount; ++i)
|
||||
{
|
||||
VertexBuffer[i].Position = transform * VertexBuffer[i].Position;
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
Reference in New Issue
Block a user