-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathobjfile.c
176 lines (159 loc) · 4.27 KB
/
objfile.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include "common.h"
#include "math3d.h"
#include "objfile.h"
#define LINEBUF_SIZE 1024
static
bool read_line(char* to, const char** data)
{
char* wp = to;
const char* buf = *data;
while (wp == to) {
if (!*buf)
return false;
// skip whitespace
while (*buf && isspace(*buf))
++buf;
// skip comments
if (*buf == '#') {
while (*buf && *buf != '\n')
++buf;
continue;
}
// copy line data
while (*buf && *buf != '\n') {
*wp++ = *buf++;
if (wp - to >= LINEBUF_SIZE)
fatal_error("objLoad: Line too long");
}
}
*data = buf;
*wp = '\0';
return true;
}
/*
Based on stb.h: stb_strtok_raw()
*/
static
char* strtok_x(char* output, char* tokens, const char* delim)
{
while (*tokens && strchr(delim, *tokens) != NULL)
tokens++;
while (*tokens && strchr(delim, *tokens) == NULL)
*output++ = *tokens++;
*output = '\0';
return *tokens ? tokens + 1 : tokens;
}
// this data
static
void push_vert(obj_t* m, float* v, size_t n)
{
if (n != 3)
fatal_error("Only 3D vertices allowed in obj: n = %zu", n);
while (m->nverts + n > m->vcap) {
m->vcap *= 2;
m->verts = realloc(m->verts, m->vcap * sizeof(float));
}
memcpy(m->verts + m->nverts, v, n * sizeof(float));
m->nverts += n;
}
static
void push_face(obj_t* m, uint32_t* f, size_t n)
{
if (n != 3)
fatal_error("Only triangles allowed in obj: n = %zu", n);
while (m->nindices + n > m->fcap) {
m->fcap *= 2;
m->indices = realloc(m->indices, m->fcap * sizeof(uint32_t));
}
memcpy(m->indices + m->nindices, f, n * sizeof(uint32_t));
m->nindices += n;
}
void obj_load(obj_t* mesh, const char* data, float vscale)
{
char linebuf[LINEBUF_SIZE];
char tokbuf[LINEBUF_SIZE];
const char* delim = " \t\r\n";
float tmpvert[4];
uint32_t tmpindex[3];
size_t i;
memset(mesh, 0, sizeof(obj_t));
mesh->vcap = 1024;
mesh->fcap = 1024;
mesh->verts = malloc(mesh->vcap * sizeof(float));
mesh->indices = malloc(mesh->fcap * sizeof(uint32_t));
while (read_line(linebuf, &data)) {
char* tok = strtok_x(tokbuf, linebuf, delim);
if (strcmp(tokbuf, "v") == 0) {
// vertex
i = 0;
do {
tok = strtok_x(tokbuf, tok, delim);
tmpvert[i++] = atof(tokbuf) * vscale;
if (i > 4)
fatal_error("Too many dimensions (%d) in .obj vertex", i);
} while (*tok != '\0');
push_vert(mesh, tmpvert, i);
} else if (strcmp(tokbuf, "f") == 0) {
i = 0;
do {
tok = strtok_x(tokbuf, tok, delim);
// - 1 because .obj indices are 1-based
tmpindex[i++] = (uint32_t)atol(tokbuf) - 1;
if (i > 3)
fatal_error("Too many vertices in face (%d)", i);
} while (*tok != '\0');
push_face(mesh, tmpindex, i);
} else {
// TODO: vt, vn, f v/vt/vn
fatal_error("Unhandled token: '%s'", tokbuf);
}
}
}
void obj_free(obj_t* mesh)
{
free(mesh->verts);
free(mesh->indices);
memset(mesh, 0, sizeof(obj_t));
}
void obj_normals(obj_t* obj, void** vertexdata, size_t* vertexsize, GLenum* meshflags)
{
size_t i;
size_t nvertices = obj->nverts / 3;
posnormalvert_t* verts = malloc(sizeof(posnormalvert_t) * nvertices);
for (i = 0; i < nvertices; ++i) {
memcpy(&verts[i].pos.x, obj->verts + (i * 3), sizeof(float) * 3);
}
for (i = 0; i < obj->nindices; i += 3) {
if (obj->indices[i + 0] > nvertices)
fatal_error("index out of bound: %u", obj->indices[i + 0]);
if (obj->indices[i + 1] > nvertices)
fatal_error("index out of bound: %u", obj->indices[i + 1]);
if (obj->indices[i + 2] > nvertices)
fatal_error("index out of bound: %u", obj->indices[i + 2]);
vec3_t t1 = verts[obj->indices[i + 0]].pos;
vec3_t t2 = verts[obj->indices[i + 1]].pos;
vec3_t t3 = verts[obj->indices[i + 2]].pos;
vec3_t n = m_vec3normalize(m_vec3cross(m_vec3sub(t2, t1), m_vec3sub(t3, t1)));
verts[obj->indices[i + 0]].n = n;
verts[obj->indices[i + 1]].n = n;
verts[obj->indices[i + 2]].n = n;
}
*vertexsize = sizeof(posnormalvert_t);
*vertexdata = verts;
*meshflags = ML_POS_3F | ML_N_3F;
}
void obj_createmesh(mesh_t* mesh, obj_t* obj, obj_meshgenfn fn)
{
void* vtxdata;
GLenum meshflags;
size_t vertexsize;
(*fn)(obj, &vtxdata, &vertexsize, &meshflags);
m_create_indexed_mesh(mesh,
obj->nverts / 3,
vtxdata,
obj->nindices,
GL_UNSIGNED_INT,
obj->indices,
meshflags);
free(vtxdata);
}