1 /*
2 GL-117
3 Copyright 2001, 2002 Thomas A. Drexl aka heptargon
4
5 This file is part of GL-117.
6
7 GL-117 is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GL-117 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GL-117; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /* This file includes a wavefront obj loader. */
23
24 #ifndef IS_OBJLOAD_H
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include "objload.h"
30
CFile(char * filename)31 CFile::CFile (char *filename)
32 {
33 char buf [STDSIZE];
34 in = fopen (filename, "rb");
35 if (in == NULL)
36 {
37 sprintf (buf, "Cannot open file %s", filename);
38 display (buf, LOG_FATAL);
39 exit (EXIT_LOADFILE);
40 }
41 fseek (in, 0, SEEK_END);
42 size = ftell (in);
43 fseek (in, 0, SEEK_SET);
44 data = new char [size];
45 int32 z = 0;
46 while (!feof (in))
47 {
48 fread (&data [z], 4096, sizeof (char), in);
49 z += 4096;
50 }
51 fclose (in);
52 filepointer = 0;
53 }
54
~CFile()55 CFile::~CFile ()
56 {
57 delete data;
58 }
59
readFloat(int32 offset)60 float CFile::readFloat (int32 offset)
61 {
62 int32 i = offset;
63 while (data [i] == ' ' || data [i] == '\t' || data [i] == 0) i ++;
64 offset = i;
65 while ((data [i] >= '0' && data [i] <= '9') || data [i] == '.' || data [i] == '-') i ++;
66 data [i] = 0;
67 filepointer = i + 1;
68 char *p1;
69 char **p2 = &p1;
70 return (float) strtod (&data [offset], p2);
71 }
72
readFloat()73 float CFile::readFloat ()
74 {
75 return readFloat (filepointer);
76 }
77
readInteger(int32 offset)78 int CFile::readInteger (int32 offset)
79 {
80 int32 i = offset;
81 while (data [i] == ' ' || data [i] == '\t' || data [i] == 0) i ++;
82 offset = i;
83 while ((data [i] >= '0' && data [i] <= '9') || data [i] == '-') i ++;
84 data [i] = 0;
85 filepointer = i + 1;
86 // char *p1;
87 // char **p2 = &p1;
88 return (int) atoi (&data [offset]);
89 }
readInteger()90 int CFile::readInteger ()
91 {
92 return readInteger (filepointer);
93 }
94
readWord(int32 offset)95 char *CFile::readWord (int32 offset)
96 {
97 int32 i = offset;
98 while (data [i] == ' ' || data [i] == '\t' || data [i] == 0) i ++;
99 offset = i;
100 while (data [i] > ' ' && data [i] <= 'z') i ++;
101 data [i] = 0;
102 filepointer = i + 1;
103 return &data [offset];
104 }
105
readWord()106 char *CFile::readWord ()
107 {
108 return readWord (filepointer);
109 }
110
getChar()111 char *CFile::getChar ()
112 {
113 return &data [filepointer];
114 }
115
nextWhite()116 void CFile::nextWhite ()
117 {
118 int32 i = filepointer;
119 while (data [i] != ' ' && data [i] != '\t' && data [i] != '\n' && i < size) i ++;
120 filepointer = i;
121 }
122
skipWhite()123 void CFile::skipWhite ()
124 {
125 int32 i = filepointer;
126 while (data [i] == ' ' || data [i] == '\t') i ++;
127 filepointer = i;
128 }
129
130
131
CLoadOBJ()132 CLoadOBJ::CLoadOBJ ()
133 {
134 }
135
ComputeColors(CModel * model)136 void CLoadOBJ::ComputeColors (CModel *model)
137 {
138 int i, i2;
139
140 if (model->numObjects <= 0)
141 return;
142
143 CVector3 n;
144 CVector3 light (1.0, 1.0, 1.0);
145 light.norm ();
146 for (i = 0; i < model->numObjects; i ++)
147 {
148 CObject *object = (model->object [i]);
149 for (i2 = 0; i2 < object->numVertices; i2 ++)
150 {
151 n.take (&object->vertex [i2].normal);
152 int lum = (int) (255.0 - 255.0 * acos (n.dotproduct (&light)));
153 object->vertex [i2].color.c [0] = lum;
154 object->vertex [i2].color.c [1] = lum;
155 object->vertex [i2].color.c [2] = lum;
156 }
157 }
158 }
159
ComputeNormals(CModel * model)160 void CLoadOBJ::ComputeNormals (CModel *model)
161 {
162 int i, i2, i3;
163
164 if (model->numObjects <= 0)
165 return;
166
167 CVector3 n;
168 for (i = 0; i < model->numObjects; i ++)
169 {
170 CObject *object = (model->object [i]);
171 for (i2 = 0; i2 < object->numTriangles; i2 ++)
172 {
173 object->triangle [i2].getNormal (&n);
174 if (n.x == 0 && n.y == 0 && n.z == 0) n.z = 1;
175 for (i3 = 0; i3 < 3; i3 ++)
176 {
177 object->triangle [i2].v [i3]->addNormal (&n);
178 }
179 }
180 for (i2 = 0; i2 < object->numQuads; i2 ++)
181 {
182 object->quad [i2].getNormal (&n);
183 for (i3 = 0; i3 < 4; i3 ++)
184 {
185 object->quad [i2].v [i3]->addNormal (&n);
186 }
187 }
188 for (i2 = 0; i2 < object->numTriangles; i2 ++)
189 {
190 for (i3 = 0; i3 < 3; i3 ++)
191 {
192 object->triangle [i2].v [i3]->normal.norm ();
193 }
194 }
195 for (i2 = 0; i2 < object->numQuads; i2 ++)
196 {
197 for (i3 = 0; i3 < 4; i3 ++)
198 {
199 object->quad [i2].v [i3]->normal.norm ();
200 }
201 }
202 }
203 }
204
Normalize(CModel * model)205 void CLoadOBJ::Normalize (CModel *model)
206 {
207 int i, i2;
208 float minx = 1E10, miny = 1E10, minz = 1E10;
209 float maxx = -1E10, maxy = -1E10, maxz = -1E10;
210 for (i = 0; i < model->numObjects; i ++)
211 {
212 CObject *object = (model->object [i]);
213 for (i2 = 0; i2 < object->numVertices; i2 ++)
214 {
215 CVertex *v = &object->vertex [i2];
216 if (v->vector.x > maxx) maxx = v->vector.x;
217 if (v->vector.y > maxy) maxy = v->vector.y;
218 if (v->vector.z > maxz) maxz = v->vector.z;
219 if (v->vector.x < minx) minx = v->vector.x;
220 if (v->vector.y < miny) miny = v->vector.y;
221 if (v->vector.z < minz) minz = v->vector.z;
222 }
223 }
224
225 float tlx = (float) (maxx + minx) / 2.0F;
226 float tly = (float) (maxy + miny) / 2.0F;
227 float tlz = (float) (maxz + minz) / 2.0F;
228 float scx = (float) (maxx - minx) * 0.5F;
229 float scy = (float) (maxy - miny) * 0.5F;
230 float scz = (float) (maxz - minz) * 0.5F;
231 float sc = scx > scy ? scx : scy;
232 sc = scz > sc ? scz : sc;
233
234 for (i = 0; i < model->numObjects; i ++)
235 {
236 CObject *object = (model->object [i]);
237 for (i2 = 0; i2 < object->numVertices; i2 ++)
238 {
239 CVertex *v = &object->vertex [i2];
240 v->vector.x -= tlx;
241 v->vector.x /= sc;
242 v->vector.y -= tly;
243 v->vector.y /= sc;
244 v->vector.z -= tlz;
245 v->vector.z /= sc;
246 }
247 }
248
249 // model->scale = sc;
250 }
251
ImportOBJ(CModel * model,char * filename)252 bool CLoadOBJ::ImportOBJ (CModel *model, char *filename)
253 {
254 file = new CFile (filename);
255 int32 i = 0;
256 int i2;
257 int vertices = 0, faces = 0;
258
259 // precalculate number of vertices and number of triangles
260 while (i < file->size - 1)
261 {
262 // one vertex
263 if (file->data [i] == 'v' && (file->data [i + 1] == ' ' || file->data [i + 1] == '\t'))
264 vertices ++;
265 // read number of vertices in this face
266 if (file->data [i] == 'f' && (file->data [i + 1] == ' ' || file->data [i + 1] == '\t'))
267 {
268 file->filepointer = i + 1;
269 file->skipWhite ();
270 char *p;
271 int z = 0;
272 do
273 {
274 (void) file->readInteger ();
275 file->nextWhite ();
276 file->skipWhite ();
277 p = file->getChar ();
278 z ++;
279 } while (*p >= '0' && *p <= '9');
280 faces += (z - 2);
281 }
282 i ++;
283 }
284
285 // create new object
286 model->object [model->numObjects] = new CObject;
287 CObject *object = model->object [model->numObjects];
288 model->numObjects ++;
289 object->numVertices = vertices;
290 object->numTriangles = faces;
291 object->numQuads = 0;
292
293 // create array of vertices and faces (triangles, quads)
294 object->vertex = new CVertex [object->numVertices];
295 object->triangle = new CTriangle [object->numTriangles];
296 object->quad = new CQuad [object->numQuads];
297
298 int vn = 0, tn = 0;
299 i = 0;
300 while (i < file->size - 1)
301 {
302 // read vertex
303 if (file->data [i] == 'v' && (file->data [i + 1] == ' ' || file->data [i + 1] == '\t'))
304 {
305 object->vertex [vn].vector.x = file->readFloat (i + 2);
306 object->vertex [vn].vector.y = file->readFloat ();
307 object->vertex [vn].vector.z = file->readFloat ();
308 i = file->filepointer - 2;
309 vn ++;
310 }
311 // read face
312 if (file->data [i] == 'f' && (file->data [i + 1] == ' ' || file->data [i + 1] == '\t'))
313 {
314 file->filepointer = i + 1;
315 file->skipWhite ();
316 char *p;
317 int z = 0;
318 int a [100];
319 // read vertex indices
320 do
321 {
322 a [z] = file->readInteger ();
323 file->nextWhite ();
324 file->skipWhite ();
325 p = file->getChar ();
326 z ++;
327 } while (*p >= '0' && *p <= '9' && z < 100);
328 // create triangles (triangulation)
329 for (i2 = 2; i2 < z; i2 ++)
330 {
331 object->triangle [tn].v [0] = &object->vertex [a [0] - 1];
332 object->triangle [tn].v [1] = &object->vertex [a [i2 - 1] - 1];
333 object->triangle [tn].v [2] = &object->vertex [a [i2] - 1];
334 tn ++;
335 }
336 }
337 i ++;
338 }
339
340 delete file;
341
342 ComputeNormals (model);
343 ComputeColors (model);
344 Normalize (model);
345
346 return true;
347 }
348
349 #endif
350