]> git.mxchange.org Git - flightgear.git/blob - Scenery/obj.c
6ebaf113bf579e0b712f57348ae8e2365540140a
[flightgear.git] / Scenery / obj.c
1 /**************************************************************************
2  * obj.c -- routines to handle WaveFront .obj format files.
3  *
4  * Written by Curtis Olson, started October 1997.
5  *
6  * Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * $Id$
23  * (Log is kept at end of this file)
24  **************************************************************************/
25
26
27 #ifdef WIN32
28 #  include <windows.h>
29 #endif
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <GL/glut.h>
34 #include <XGL/xgl.h>
35
36 #include <Main/fg_debug.h>
37 #include <Math/mat3.h>
38 #include <Scenery/obj.h>
39 #include <Scenery/scenery.h>
40
41
42
43 #define MAXNODES 100000
44
45 double nodes[MAXNODES][3];
46 double normals[MAXNODES][3];
47
48
49 /* given three points defining a triangle, calculate the normal */
50 void calc_normal(double p1[3], double p2[3], double p3[3], double normal[3])
51 {
52     double v1[3], v2[3];
53     double temp;
54
55     v1[0] = p2[0] - p1[0]; v1[1] = p2[1] - p1[1]; v1[2] = p2[2] - p1[2];
56     v2[0] = p3[0] - p1[0]; v2[1] = p3[1] - p1[1]; v2[2] = p3[2] - p1[2];
57
58     MAT3cross_product(normal, v1, v2);
59     MAT3_NORMALIZE_VEC(normal,temp);
60
61     /* fgPrintf( FG_TERRAIN, FG_DEBUG, "  Normal = %.2f %.2f %.2f\n", 
62                  normal[0], normal[1], normal[2]);*/
63 }
64
65
66 /* Load a .obj file and generate the GL call list */
67 GLint fgObjLoad(char *path, struct fgCartesianPoint *ref, double *radius) {
68     char line[256], winding_str[256];
69     double approx_normal[3], normal[3], scale;
70     double x, y, z, xmax, xmin, ymax, ymin, zmax, zmin;
71     GLint tile;
72     FILE *f;
73     int first, ncount, vncount, n1, n2, n3, n4;
74     static int use_vertex_norms = 1;
75     int winding;
76     int last1, last2, odd;
77
78     if ( (f = fopen(path, "r")) == NULL ) {
79         fgPrintf(FG_TERRAIN, FG_ALERT, "Cannot open file: %s\n", path);
80         /* exit(-1); */
81         return(0);
82     }
83
84     tile = xglGenLists(1);
85     xglNewList(tile, GL_COMPILE);
86
87     first = 1;
88     ncount = 1;
89     vncount = 1;
90
91     while ( fgets(line, 250, f) != NULL ) {
92         if ( line[0] == '#' ) {
93             /* comment -- ignore */
94         } else if ( line[0] == '\n' ) {
95             /* empty line -- ignore */
96         } else if ( strncmp(line, "v ", 2) == 0 ) {
97             /* node (vertex) */
98             if ( ncount < MAXNODES ) {
99                 /* fgPrintf( FG_TERRAIN, FG_DEBUG, "vertex = %s", line); */
100                 sscanf(line, "v %lf %lf %lf\n", &x, &y, &z);
101                 nodes[ncount][0] = x;
102                 nodes[ncount][1] = y;
103                 nodes[ncount][2] = z;
104
105                 /* first time through set min's and max'es */
106                 if ( ncount == 1 ) {
107                     xmin = x;
108                     xmax = x;
109                     ymin = y;
110                     ymax = y;
111                     zmin = z;
112                     zmax = z;
113                 }
114     
115                 /* keep track of min/max vertex values */
116                 if ( x < xmin ) xmin = x;
117                 if ( x > xmax ) xmax = x;
118                 if ( y < ymin ) ymin = y;
119                 if ( y > ymax ) ymax = y;
120                 if ( z < zmin ) zmin = z;
121                 if ( z > zmax ) zmax = z;               
122
123                 /* reference point is the "center" */
124                 /* this is overkill to calculate it everytime we get a
125                  * new node, but it's hard to know with the .obj
126                  * format when we are done with vertices */
127                 ref->x = (xmin + xmax) / 2;
128                 ref->y = (ymin + ymax) / 2;
129                 ref->z = (zmin + zmax) / 2;
130
131                 ncount++;
132             } else {
133                 fgPrintf( FG_TERRAIN, FG_EXIT, 
134                           "Read too many nodes ... dying :-(\n");
135             }
136         } else if ( strncmp(line, "vn ", 3) == 0 ) {
137             /* vertex normal */
138             if ( vncount < MAXNODES ) {
139                 /* fgPrintf( FG_TERRAIN, FG_DEBUG, "vertex normal = %s", line); */
140                 sscanf(line, "vn %lf %lf %lf\n", 
141                        &normals[vncount][0], &normals[vncount][1], 
142                        &normals[vncount][2]);
143                 vncount++;
144             } else {
145                 fgPrintf( FG_TERRAIN, FG_EXIT, 
146                           "Read too many vertex normals ... dying :-(\n");
147             }
148         } else if ( strncmp(line, "winding ", 8) == 0 ) {
149             sscanf(line+8, "%s", winding_str);
150             fgPrintf( FG_TERRAIN, FG_DEBUG, "    WINDING = %s\n", winding_str);
151
152             /* can't call xglFrontFace() between xglBegin() & xglEnd() */
153             xglEnd();
154             first = 1;
155
156             if ( strcmp(winding_str, "cw") == 0 ) {
157                 xglFrontFace( GL_CW );
158                 winding = 0;
159             } else {
160                 glFrontFace ( GL_CCW );
161                 winding = 1;
162             }
163         } else if ( line[0] == 't' ) {
164             /* start a new triangle strip */
165
166             n1 = n2 = n3 = n4 = 0;
167
168             if ( !first ) {
169                 /* close out the previous structure and start the next */
170                 xglEnd();
171             } else {
172                 first = 0;
173             }
174
175             /* fgPrintf( FG_TERRAIN, FG_DEBUG, "    new tri strip = %s", 
176                line); */
177             sscanf(line, "t %d %d %d %d\n", &n1, &n2, &n3, &n4);
178
179             /* fgPrintf( FG_TERRAIN, FG_DEBUG, "(t) = "); */
180
181             xglBegin(GL_TRIANGLE_STRIP);
182
183             if ( winding ) {
184                 odd = 1; 
185                 scale = 1.0;
186             } else {
187                 odd = 0;
188                 scale = 1.0;
189             }
190
191             if ( use_vertex_norms ) {
192                 MAT3_SCALE_VEC(normal, normals[n1], scale);
193                 xglNormal3dv(normal);
194                 xglVertex3d(nodes[n1][0] - ref->x, nodes[n1][1] - ref->y, 
195                             nodes[n1][2] - ref->z);
196
197                 MAT3_SCALE_VEC(normal, normals[n2], scale);
198                 xglNormal3dv(normal);
199                 xglVertex3d(nodes[n2][0] - ref->x, nodes[n2][1] - ref->y, 
200                             nodes[n2][2] - ref->z);
201
202                 MAT3_SCALE_VEC(normal, normals[n3], scale);
203                 xglNormal3dv(normal);
204                 xglVertex3d(nodes[n3][0] - ref->x, nodes[n3][1] - ref->y, 
205                             nodes[n3][2] - ref->z);
206             } else {
207                 if ( odd ) {
208                     calc_normal(nodes[n1], nodes[n2], nodes[n3], approx_normal);
209                 } else {
210                     calc_normal(nodes[n2], nodes[n1], nodes[n3], approx_normal);
211                 }
212                 MAT3_SCALE_VEC(normal, approx_normal, scale);
213                 xglNormal3dv(normal);
214
215                 xglVertex3d(nodes[n1][0] - ref->x, nodes[n1][1] - ref->y, 
216                             nodes[n1][2] - ref->z);
217                 xglVertex3d(nodes[n2][0] - ref->x, nodes[n2][1] - ref->y, 
218                             nodes[n2][2] - ref->z);
219                 xglVertex3d(nodes[n3][0] - ref->x, nodes[n3][1] - ref->y, 
220                             nodes[n3][2] - ref->z);
221             }
222
223             odd = 1 - odd;
224             last1 = n2;
225             last2 = n3;
226
227             if ( n4 > 0 ) {
228                 if ( use_vertex_norms ) {
229                     MAT3_SCALE_VEC(normal, normals[n4], scale);
230                 } else {
231                     calc_normal(nodes[n3], nodes[n2], nodes[n4], approx_normal);
232                     MAT3_SCALE_VEC(normal, approx_normal, scale);
233                 }
234                 xglNormal3dv(normal);
235                 xglVertex3d(nodes[n4][0] - ref->x, nodes[n4][1] - ref->y, 
236                             nodes[n4][2] - ref->z);
237
238                 odd = 1 - odd;
239                 last1 = n3;
240                 last2 = n4;
241             }
242         } else if ( line[0] == 'f' ) {
243             /* unoptimized face */
244
245             if ( !first ) {
246                 /* close out the previous structure and start the next */
247                 xglEnd();
248             } else {
249                 first = 0;
250             }
251
252             xglBegin(GL_TRIANGLES);
253
254             /* fgPrintf( FG_TERRAIN, FG_DEBUG, "new triangle = %s", line);*/
255             sscanf(line, "f %d %d %d\n", &n1, &n2, &n3);
256
257             xglNormal3d(normals[n1][0], normals[n1][1], normals[n1][2]);
258             xglVertex3d(nodes[n1][0] - ref->x, nodes[n1][1] - ref->y, 
259                         nodes[n1][2] - ref->z);
260
261             xglNormal3d(normals[n2][0], normals[n2][1], normals[n2][2]);
262             xglVertex3d(nodes[n2][0] - ref->x, nodes[n2][1] - ref->y, 
263                         nodes[n2][2] - ref->z);
264
265             xglNormal3d(normals[n3][0], normals[n3][1], normals[n3][2]);
266             xglVertex3d(nodes[n3][0] - ref->x, nodes[n3][1] - ref->y, 
267                         nodes[n3][2] - ref->z);
268         } else if ( line[0] == 'q' ) {
269             /* continue a triangle strip */
270             n1 = n2 = 0;
271
272             /* fgPrintf( FG_TERRAIN, FG_DEBUG, "continued tri strip = %s ", 
273                line); */
274             sscanf(line, "q %d %d\n", &n1, &n2);
275             /* fgPrintf( FG_TERRAIN, FG_DEBUG, "read %d %d\n", n1, n2); */
276
277             if ( use_vertex_norms ) {
278                 MAT3_SCALE_VEC(normal, normals[n1], scale);
279                 xglNormal3dv(normal);
280             } else {
281                 if ( odd ) {
282                     calc_normal(nodes[last1], nodes[last2], nodes[n1], 
283                                 approx_normal);
284                 } else {
285                     calc_normal(nodes[last2], nodes[last1], nodes[n1], 
286                                 approx_normal);
287                 }
288                 MAT3_SCALE_VEC(normal, approx_normal, scale);
289                 xglNormal3dv(normal);
290             }
291
292             xglVertex3d(nodes[n1][0] - ref->x, nodes[n1][1] - ref->y, 
293                         nodes[n1][2] - ref->z);
294             
295             odd = 1 - odd;
296             last1 = last2;
297             last2 = n1;
298
299             if ( n2 > 0 ) {
300                 /* fgPrintf( FG_TERRAIN, FG_DEBUG, " (cont)\n"); */
301
302                 if ( use_vertex_norms ) {
303                     MAT3_SCALE_VEC(normal, normals[n2], scale);
304                     xglNormal3dv(normal);
305                 } else {
306                     if ( odd ) {
307                         calc_normal(nodes[last1], nodes[last2], nodes[n2], 
308                                     approx_normal);
309                     } else {
310                         calc_normal(nodes[last2], nodes[last1], nodes[n2], 
311                                     approx_normal);
312                     }
313                     MAT3_SCALE_VEC(normal, approx_normal, scale);
314                     xglNormal3dv(normal);
315                 }
316
317                 xglVertex3d(nodes[n2][0] - ref->x, nodes[n2][1] - ref->y, 
318                             nodes[n2][2] - ref->z);
319
320                 odd = 1 -odd;
321                 last1 = last2;
322                 last2 = n2;
323             }
324         } else {
325             fgPrintf( FG_TERRAIN, FG_WARN, "Unknown line in %s = %s\n", 
326                       path, line);
327         }
328     }
329
330     xglEnd();
331
332     /* Draw normal vectors (for visually verifying normals)*/
333     /*
334     xglBegin(GL_LINES);
335     xglColor3f(0.0, 0.0, 0.0);
336     for ( i = 0; i < ncount; i++ ) {
337         xglVertex3d(nodes[i][0] - ref->x,
338                     nodes[i][1] - ref->y,
339                     nodes[i][2] - ref->z);
340         xglVertex3d(nodes[i][0] - ref->x + 500*normals[i][0],
341                     nodes[i][1] - ref->y + 500*normals[i][1],
342                     nodes[i][2] - ref->z + 500*normals[i][2]);
343     } 
344     xglEnd();
345     */
346
347     xglFrontFace ( GL_CCW );
348
349     xglEndList();
350
351     fclose(f);
352
353     return(tile);
354 }
355
356
357 /* $Log$
358 /* Revision 1.21  1998/01/31 00:43:25  curt
359 /* Added MetroWorks patches from Carmen Volpe.
360 /*
361  * Revision 1.20  1998/01/29 00:51:39  curt
362  * First pass at tile cache, dynamic tile loading and tile unloading now works.
363  *
364  * Revision 1.19  1998/01/27 03:26:42  curt
365  * Playing with new fgPrintf command.
366  *
367  * Revision 1.18  1998/01/19 19:27:16  curt
368  * Merged in make system changes from Bob Kuehne <rpk@sgi.com>
369  * This should simplify things tremendously.
370  *
371  * Revision 1.17  1998/01/13 00:23:10  curt
372  * Initial changes to support loading and management of scenery tiles.  Note,
373  * there's still a fair amount of work left to be done.
374  *
375  * Revision 1.16  1997/12/30 23:09:40  curt
376  * Worked on winding problem without luck, so back to calling glFrontFace()
377  * 3 times for each scenery area.
378  *
379  * Revision 1.15  1997/12/30 20:47:51  curt
380  * Integrated new event manager with subsystem initializations.
381  *
382  * Revision 1.14  1997/12/30 01:38:46  curt
383  * Switched back to per vertex normals and smooth shading for terrain.
384  *
385  * Revision 1.13  1997/12/18 23:32:36  curt
386  * First stab at sky dome actually starting to look reasonable. :-)
387  *
388  * Revision 1.12  1997/12/17 23:13:47  curt
389  * Began working on rendering the sky.
390  *
391  * Revision 1.11  1997/12/15 23:55:01  curt
392  * Add xgl wrappers for debugging.
393  * Generate terrain normals on the fly.
394  *
395  * Revision 1.10  1997/12/12 21:41:28  curt
396  * More light/material property tweaking ... still a ways off.
397  *
398  * Revision 1.9  1997/12/12 19:52:57  curt
399  * Working on lightling and material properties.
400  *
401  * Revision 1.8  1997/12/10 01:19:51  curt
402  * Tweaks for verion 0.15 release.
403  *
404  * Revision 1.7  1997/12/08 22:51:17  curt
405  * Enhanced to handle ccw and cw tri-stripe winding.  This is a temporary
406  * admission of defeat.  I will eventually go back and get all the stripes
407  * wound the same way (ccw).
408  *
409  * Revision 1.6  1997/11/25 19:25:35  curt
410  * Changes to integrate Durk's moon/sun code updates + clean up.
411  *
412  * Revision 1.5  1997/11/15 18:16:39  curt
413  * minor tweaks.
414  *
415  * Revision 1.4  1997/11/14 00:26:49  curt
416  * Transform scenery coordinates earlier in pipeline when scenery is being
417  * created, not when it is being loaded.  Precalculate normals for each node
418  * as average of the normals of each containing polygon so Garoude shading is
419  * now supportable.
420  *
421  * Revision 1.3  1997/10/31 04:49:12  curt
422  * Tweaking vertex orders.
423  *
424  * Revision 1.2  1997/10/30 12:38:45  curt
425  * Working on new scenery subsystem.
426  *
427  * Revision 1.1  1997/10/28 21:14:54  curt
428  * Initial revision.
429  *
430  */