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