port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

465
4kgfx/mesh.cpp Normal file
View 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();
}