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