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