1 /*
2  * Copyright (C) 1998 Janne L�f <jlof@mail.student.oulu.fi>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 /*
20 Got it from GTKglExt
21 Modified by CJP
22 */
23 
24 #include "lw.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 
31 #include "usmacros.h"
32 
33 #define MK_ID(a,b,c,d) ((((Uint32)(a))<<24)| \
34 			(((Uint32)(b))<<16)| \
35 			(((Uint32)(c))<< 8)| \
36 			(((Uint32)(d))    ))
37 
38 #define ID_FORM MK_ID('F','O','R','M')
39 #define ID_LWOB MK_ID('L','W','O','B')
40 #define ID_PNTS MK_ID('P','N','T','S')
41 #define ID_SRFS MK_ID('S','R','F','S')
42 #define ID_SURF MK_ID('S','U','R','F')
43 #define ID_POLS MK_ID('P','O','L','S')
44 #define ID_COLR MK_ID('C','O','L','R')
45 
read_char(FILE * f)46 static int read_char(FILE *f)
47 {
48   int c = fgetc(f);
49   if(c == EOF) return 0;
50   /*g_return_val_if_fail(c != EOF, 0);*/
51   return c;
52 }
53 
read_short(FILE * f)54 static int read_short(FILE *f)
55 {
56   return (read_char(f)<<8) | read_char(f);
57 }
58 
read_long(FILE * f)59 static Uint32 read_long(FILE *f)
60 {
61   return (read_char(f)<<24) | (read_char(f)<<16) | (read_char(f)<<8) | read_char(f);
62 }
63 
read_float(FILE * f)64 static float read_float(FILE *f)
65 {
66   Uint32 x = read_long(f);
67   return *((float*)(void*)(&x)); /* CJP note: possibly doesn't work on every architecture */
68 }
69 
read_string(FILE * f,char * s)70 static int read_string(FILE *f, char *s)
71 {
72   int c;
73   int cnt = 0;
74   do {
75     c = read_char(f);
76     if (cnt < LW_MAX_NAME_LEN)
77       s[cnt] = c;
78     else
79       s[LW_MAX_NAME_LEN-1] = 0;
80     cnt++;
81   } while (c != 0);
82   /* if length of string (including \0) is odd skip another byte */
83   if (cnt%2) {
84     read_char(f);
85     cnt++;
86   }
87   return cnt;
88 }
89 
read_srfs(FILE * f,int nbytes,lwObject * lwo)90 static void read_srfs(FILE *f, int nbytes, lwObject *lwo)
91 {
92   int guess_cnt = lwo->material_cnt;
93   printf("initial guess_cnt = %d\n", guess_cnt);
94 
95   while (nbytes > 0) {
96     lwMaterial *material;
97 
98     /* allocate more memory for materials if needed */
99     if (guess_cnt <= lwo->material_cnt) {
100       guess_cnt += guess_cnt/2 + 4;
101       printf("guess_cnt = %d\n", guess_cnt);
102       lwo->material = realloc(lwo->material, sizeof(lwMaterial)*guess_cnt);
103     }
104     printf("we have enough materials\n");
105 
106     material = lwo->material + lwo->material_cnt++;
107     printf("material_cnt = %d\n", lwo->material_cnt);
108 
109     /* read name */
110     nbytes -= read_string(f,material->name);
111 
112     /* defaults */
113     material->r = 0.7;
114     material->g = 0.7;
115     material->b = 0.7;
116   }
117   printf("changing back to %d materials\n", lwo->material_cnt);
118   lwo->material = realloc(lwo->material, sizeof(lwMaterial)*lwo->material_cnt);
119 }
120 
121 
read_surf(FILE * f,int nbytes,lwObject * lwo)122 static void read_surf(FILE *f, int nbytes, lwObject *lwo)
123 {
124   int i;
125   char name[LW_MAX_NAME_LEN];
126   lwMaterial *material = NULL;
127 
128   /* read surface name */
129   nbytes -= read_string(f,name);
130 
131   /* find material */
132   for (i=0; i< lwo->material_cnt; i++) {
133     if (strcmp(lwo->material[i].name,name) == 0) {
134       material = &lwo->material[i];
135       break;
136     }
137   }
138   if(material == NULL) return;
139   /*g_return_if_fail(material != NULL);*/
140 
141   /* read values */
142   while (nbytes > 0) {
143     int id = read_long(f);
144     int len = read_short(f);
145     nbytes -= 6 + len + (len%2);
146 
147     switch (id) {
148     case ID_COLR:
149       material->r = read_char(f) / 255.0;
150       material->g = read_char(f) / 255.0;
151       material->b = read_char(f) / 255.0;
152       read_char(f); /* dummy */
153       break;
154     default:
155       fseek(f, len+(len%2), SEEK_CUR);
156     }
157   }
158 }
159 
160 
read_pols(FILE * f,int nbytes,lwObject * lwo)161 static void read_pols(FILE *f, int nbytes, lwObject *lwo)
162 {
163   int guess_cnt = lwo->face_cnt;
164 
165   while (nbytes > 0) {
166     lwFace *face;
167     int i;
168 
169     /* allocate more memory for polygons if necessary */
170     if (guess_cnt <= lwo->face_cnt) {
171       guess_cnt += guess_cnt + 4;
172       lwo->face = realloc(lwo->face, sizeof(lwFace)*guess_cnt);
173     }
174     face = lwo->face + lwo->face_cnt++;
175 
176     /* number of points in this face */
177     face->index_cnt = read_short(f);
178     nbytes -= 2;
179 
180     /* allocate space for points */
181     face->index = malloc(sizeof(int)*face->index_cnt);
182 
183     /* read points in */
184     for (i=0; i<face->index_cnt; i++) {
185       face->index[i] = read_short(f);
186       nbytes -= 2;
187     }
188 
189     /* read surface material */
190     face->material = read_short(f);
191     nbytes -= 2;
192 
193     /* skip over detail  polygons */
194     if (face->material < 0) {
195       int det_cnt;
196       face->material = -face->material;
197       det_cnt = read_short(f);
198       nbytes -= 2;
199       while (det_cnt-- > 0) {
200 	int cnt = read_short(f);
201 	fseek(f, cnt*2+2, SEEK_CUR);
202 	nbytes -= cnt*2+2;
203       }
204     }
205     face->material -= 1;
206   }
207   /* readjust to true size */
208   lwo->face = realloc(lwo->face, sizeof(lwFace)*lwo->face_cnt);
209 }
210 
211 
212 
read_pnts(FILE * f,int nbytes,lwObject * lwo)213 static void read_pnts(FILE *f, int nbytes, lwObject *lwo)
214 {
215   int i;
216   lwo->vertex_cnt = nbytes / 12;
217   lwo->vertex = malloc(sizeof(float)*lwo->vertex_cnt*3);
218   for (i=0; i<lwo->vertex_cnt; i++) {
219     lwo->vertex[i*3+0] = read_float(f);
220     lwo->vertex[i*3+1] = read_float(f);
221     lwo->vertex[i*3+2] = read_float(f);
222   }
223 }
224 
225 
226 
227 
228 
229 
lw_is_lwobject(const char * lw_file)230 int lw_is_lwobject(const char *lw_file)
231 {
232   FILE *f = fopen(lw_file, "rb");
233   if (f) {
234     Uint32 form = read_long(f);
235     Uint32 nlen = read_long(f);
236     Uint32 lwob = read_long(f);
237     fclose(f);
238     if (form == ID_FORM && nlen != 0 && lwob == ID_LWOB)
239       return 1;
240   }
241   return 0;
242 }
243 
244 
lw_object_read(const char * lw_file)245 lwObject *lw_object_read(const char *lw_file)
246 {
247   FILE *f = NULL;
248   lwObject *lw_object = NULL;
249 
250   Uint32 form_bytes = 0;
251   Uint32 read_bytes = 0;
252 
253   /* open file */
254   f = fopen(lw_file, "rb");
255   if (f == NULL) {
256     fprintf(stderr, "can't open file %s\n", lw_file);
257     return NULL;
258   }
259 
260   /* check for headers */
261   if (read_long(f) != ID_FORM) {
262     fprintf(stderr, "file %s is not an IFF file\n", lw_file);
263     fclose(f);
264     return NULL;
265   }
266   form_bytes = read_long(f);
267   read_bytes += 4;
268 
269   if (read_long(f) != ID_LWOB) {
270     fprintf(stderr, "file %s is not a LWOB file\n", lw_file);
271     fclose(f);
272     return NULL;
273   }
274 
275   /* create new lwObject */
276   lw_object = malloc(sizeof(lwObject));
277 
278   /* fill with zeroes */
279   lw_object->face = NULL;
280   lw_object->face_cnt = 0;
281   lw_object->material = NULL;
282   lw_object->material_cnt = 0;
283   lw_object->vertex = 0;
284   lw_object->vertex_cnt = 0;
285 
286   /* read chunks */
287   while (read_bytes < form_bytes) {
288     Uint32  id     = read_long(f);
289     Uint32  nbytes = read_long(f);
290     read_bytes += 8 + nbytes + (nbytes%2);
291 
292     switch (id) {
293     case ID_PNTS:
294       read_pnts(f, nbytes, lw_object);
295       break;
296     case ID_POLS:
297       read_pols(f, nbytes, lw_object);
298       break;
299     case ID_SRFS:
300       read_srfs(f, nbytes, lw_object);
301       break;
302     case ID_SURF:
303       read_surf(f, nbytes, lw_object);
304       break;
305     default:
306       fseek(f, nbytes + (nbytes%2), SEEK_CUR);
307     }
308   }
309 
310   fclose(f);
311   return lw_object;
312 }
313 
314 
315 
316 
317 
318 
319 
lw_object_free(lwObject * lw_object)320 void lw_object_free(lwObject *lw_object)
321 {
322   if(lw_object == NULL) return;
323   /*g_return_if_fail(lw_object != NULL);*/
324 
325   if (lw_object->face) {
326     int i;
327     for (i=0; i<lw_object->face_cnt; i++)
328       free(lw_object->face[i].index);
329     free(lw_object->face);
330   }
331   free(lw_object->material);
332   free(lw_object->vertex);
333   free(lw_object);
334 }
335 
336 
337 
338 
339 
340 #define PX(i) (lw_object->vertex[face->index[i]*3+0])
341 #define PY(i) (lw_object->vertex[face->index[i]*3+1])
342 #define PZ(i) (lw_object->vertex[face->index[i]*3+2])
343 /*
344 void lw_object_show(const lwObject *lw_object)
345 {
346   int i,j;
347   int prev_index_cnt = -1;
348   int prev_material  = -1;
349   float prev_nx = 0;
350   float prev_ny = 0;
351   float prev_nz = 0;
352 
353   if(lw_object == NULL) return;
354   //g_return_if_fail(lw_object != NULL);
355 
356   for (i=0; i<lw_object->face_cnt; i++) {
357     float ax,ay,az,bx,by,bz,nx,ny,nz,r;
358     const lwFace *face = lw_object->face+i;
359 
360     / * ignore faces with less than 3 points * /
361     if (face->index_cnt < 3)
362       continue;
363 
364     / * calculate normal * /
365     ax = PX(1) - PX(0);
366     ay = PY(1) - PY(0);
367     az = PZ(1) - PZ(0);
368 
369     bx = PX(face->index_cnt-1) - PX(0);
370     by = PY(face->index_cnt-1) - PY(0);
371     bz = PZ(face->index_cnt-1) - PZ(0);
372 
373     nx = ay * bz - az * by;
374     ny = az * bx - ax * bz;
375     nz = ax * by - ay * bx;
376 
377     r = sqrt(nx*nx + ny*ny + nz*nz);
378     if (r < 0.000001) / * avoid division by zero * /
379       continue;
380     nx /= r;
381     ny /= r;
382     nz /= r;
383 
384     / * glBegin/glEnd * /
385     if (prev_index_cnt != face->index_cnt || prev_index_cnt > 4) {
386       if (prev_index_cnt > 0) glEnd();
387       prev_index_cnt = face->index_cnt;
388       switch (face->index_cnt) {
389       case 3:
390 	glBegin(GL_TRIANGLES);
391 	break;
392       case 4:
393 	glBegin(GL_QUADS);
394 	break;
395       default:
396 	glBegin(GL_POLYGON);
397       }
398     }
399 
400     / * update material if necessary * /
401     if (prev_material != face->material) {
402       prev_material = face->material;
403       glColor3f(lw_object->material[face->material].r,
404 		lw_object->material[face->material].g,
405 		lw_object->material[face->material].b);
406     }
407 
408     / * update normal if necessary * /
409     if (nx != prev_nx || ny != prev_ny || nz != prev_nz) {
410       prev_nx = nx;
411       prev_ny = ny;
412       prev_nz = nz;
413       glNormal3f(nx,ny,nz);
414     }
415 
416     / * draw polygon/triangle/quad * /
417     for (j=0; j<face->index_cnt; j++)
418       glVertex3f(PX(j),PY(j),PZ(j));
419 
420   }
421 
422   / * if glBegin was called call glEnd * /
423   if (prev_index_cnt > 0)
424     glEnd();
425 }
426 */
427 
lw_object_radius(const lwObject * lwo)428 float lw_object_radius(const lwObject *lwo)
429 {
430   int i;
431   double max_radius = 0.0;
432 
433   if(lwo == NULL) return 0.0;
434   /*g_return_val_if_fail(lwo != NULL, 0.0);*/
435 
436   for (i=0; i<lwo->vertex_cnt; i++) {
437     float *v = &lwo->vertex[i*3];
438     double r = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
439     if (r > max_radius)
440       max_radius = r;
441   }
442   return sqrt(max_radius);
443 }
444 
lw_object_scale(lwObject * lwo,float scale)445 void lw_object_scale(lwObject *lwo, float scale)
446 {
447   int i;
448 
449   if(lwo == NULL) return;
450   /*g_return_if_fail(lwo != NULL);*/
451 
452   for (i=0; i<lwo->vertex_cnt; i++) {
453     lwo->vertex[i*3+0] *= scale;
454     lwo->vertex[i*3+1] *= scale;
455     lwo->vertex[i*3+2] *= scale;
456   }
457 }
458 
459 
460