Skip to content

Commit

Permalink
Tesselate faces for OBJ, reuse vertices
Browse files Browse the repository at this point in the history
  • Loading branch information
vanjac committed Aug 31, 2023
1 parent ac51dc0 commit 086581b
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
74 changes: 58 additions & 16 deletions src/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <unordered_set>
#include "winchroma.h"
#include <atlbase.h>
#include "rendermesh.h"
#include "stdutil.h"

using namespace chroma;
Expand All @@ -20,16 +21,28 @@ struct std::hash<std::pair<winged::vert_id, winged::vert_id>> {
}
};

template<>
struct std::hash<glm::vec2> {
std::size_t operator() (const glm::vec2 &key) const {
return hashCombine(hashCombine(0, key.x), key.y);
}
};

template<>
struct std::hash<glm::vec3> {
std::size_t operator() (const glm::vec3 &key) const {
return hashCombine(hashCombine(hashCombine(0, key.x), key.y), key.z);
}
};

template<>
struct std::hash<winged::Paint> {
std::size_t operator() (const winged::Paint &key) const {
auto hash = hashCombine(0, key.material);
for (int r = 0; r < 2; r++) {
for (int c = 0; c < 4; c++)
hash = hashCombine(hash, key.texAxes[c][r]);
for (int c = 0; c < 3; c++)
hash = hashCombine(hash, key.texTF[c][r]);
}
for (int c = 0; c < 4; c++)
hash = hashCombine(hash, key.texAxes[c]);
for (int c = 0; c < 3; c++)
hash = hashCombine(hash, key.texTF[c]);
return hash;
}
};
Expand Down Expand Up @@ -274,6 +287,10 @@ std::tuple<EditorState, ViewState, Library> readFile(const wchar_t *file,
}


struct ObjFaceVert {
int v, vt;
};

void writeObj(const wchar_t *file, const Surface &surf) {
CHandle handle(CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL));
Expand All @@ -282,26 +299,51 @@ void writeObj(const wchar_t *file, const Surface &surf) {
char buf[256];

std::unordered_map<vert_id, int> vertIndices;
int i = 1;
int v = 1;
for (auto &vert : surf.verts) {
auto pos = vert.second.pos;
write(handle, buf, sprintf(buf, "v %f %f %f\n", pos.x, pos.y, pos.z));
vertIndices[vert.first] = i++;
vertIndices[vert.first] = v++;
}

int vn = 1, vt = 1;
std::unordered_map<glm::vec3, int> normalIndices;
std::unordered_map<glm::vec2, int> texCoordIndices;
std::vector<ObjFaceVert> faceVerts;
std::vector<index_t> faceIndices;
for (auto &face : surf.faces) {
glm::vec3 normal = faceNormal(surf, face.second);
int vn;
if (auto vnPtr = tryGet(normalIndices, normal)) {
vn = *vnPtr;
} else {
vn = (int)normalIndices.size() + 1;
normalIndices[normal] = vn;
write(handle, buf, sprintf(buf, "\nvn %f %f %f", normal.x, normal.y, normal.z));
}

glm::mat4x2 texMat = faceTexMat(face.second.paint, normal);
write(handle, buf, sprintf(buf, "\nvn %f %f %f", normal.x, normal.y, normal.z));
faceVerts.clear();
for (auto &edge : FaceEdges(surf, face.second)) {
glm::vec2 uv = texMat * glm::vec4(edge.second.vert.in(surf).pos, 1);
write(handle, buf, sprintf(buf, "\nvt %f %f", uv.x, uv.y));
glm::vec2 texCoord = texMat * glm::vec4(edge.second.vert.in(surf).pos, 1);
int vt;
if (auto vtPtr = tryGet(texCoordIndices, texCoord)) {
vt = *vtPtr;
} else {
vt = (int)texCoordIndices.size() + 1;
texCoordIndices[texCoord] = vt;
write(handle, buf, sprintf(buf, "\nvt %f %f", texCoord.x, texCoord.y));
}
faceVerts.push_back({vertIndices[edge.second.vert], vt});
}
write(handle, "\nf", 2);
for (auto &edge : FaceEdges(surf, face.second)) {
int v = vertIndices[edge.second.vert];
write(handle, buf, sprintf(buf, " %d/%d/%d", v, vt++, vn));

faceIndices.clear();
tesselateFace(faceIndices, surf, face.second, normal);
for (size_t i = 0; i < faceIndices.size(); ) {
write(handle, "\nf", 2);
for (size_t j = 0; j < 3; j++, i++) {
const ObjFaceVert &ofv = faceVerts[faceIndices[i]];
write(handle, buf, sprintf(buf, " %d/%d/%d", ofv.v, ofv.vt, vn));
}
}
vn++;
}
Expand Down
19 changes: 17 additions & 2 deletions src/rendermesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct FaceTessState {
std::vector<index_t> *indices;
GLenum mode;
size_t startI;
GLenum error;
GLenum error = 0;
};

static GLUtesselator *g_tess;
Expand Down Expand Up @@ -53,7 +53,6 @@ static void tesselateFace(std::vector<index_t> &faceIsOut, std::vector<index_t>
size_t initialSize = faceIsOut.size();
FaceTessState state;
state.indices = &faceIsOut;
state.error = 0;
gluTessNormal(g_tess, normal.x, normal.y, normal.z);
gluTessBeginPolygon(g_tess, &state);
gluTessBeginContour(g_tess);
Expand All @@ -80,6 +79,22 @@ static void tesselateFace(std::vector<index_t> &faceIsOut, std::vector<index_t>
}
}

void tesselateFace(std::vector<index_t> &faceIsOut, const Surface &surf,
const Face &face, glm::vec3 normal) {
FaceTessState state;
state.indices = &faceIsOut;
gluTessNormal(g_tess, normal.x, normal.y, normal.z);
gluTessBeginPolygon(g_tess, &state);
gluTessBeginContour(g_tess);
index_t vertI = 0;
for (auto &ep : FaceEdges(surf, face)) {
glm::dvec3 dPos = ep.second.vert.in(surf).pos;
gluTessVertex(g_tess, glm::value_ptr(dPos), (void *)vertI++);
}
gluTessEndContour(g_tess);
gluTessEndPolygon(g_tess);
}

void initRenderMesh() {
g_tess = gluNewTess();
gluTessCallback(g_tess, GLU_TESS_BEGIN_DATA, (GLvoid (CALLBACK*) ())tessBeginCallback);
Expand Down
2 changes: 2 additions & 0 deletions src/rendermesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ struct RenderMesh {

void initRenderMesh();
void generateRenderMesh(RenderMesh *mesh, const EditorState &state);
void tesselateFace(std::vector<index_t> &faceIsOut, const Surface &surf,
const Face &face, glm::vec3 normal);

} // namespace

0 comments on commit 086581b

Please sign in to comment.