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