1 /*
2 * Copyright (C) 1998,1999 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 Lesser 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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "old_lw.h"
20
21 #include "lwo2read.h"
22
23 #include <stdio.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <osgDB/FileUtils>
29
30 #define MK_ID(a,b,c,d) ((((guint32)(a))<<24)| \
31 (((guint32)(b))<<16)| \
32 (((guint32)(c))<< 8)| \
33 (((guint32)(d)) ))
34
35 #define ID_FORM MK_ID('F','O','R','M')
36 #define ID_LWOB MK_ID('L','W','O','B')
37 #define ID_PNTS MK_ID('P','N','T','S')
38 #define ID_SRFS MK_ID('S','R','F','S')
39 #define ID_SURF MK_ID('S','U','R','F')
40 #define ID_POLS MK_ID('P','O','L','S')
41 #define ID_COLR MK_ID('C','O','L','R')
42
43 #define ID_CTEX MK_ID('C','T','E','X')
44 #define ID_DTEX MK_ID('D','T','E','X')
45 #define ID_STEX MK_ID('S','T','E','X')
46 #define ID_RTEX MK_ID('R','T','E','X')
47 #define ID_TTEX MK_ID('T','T','E','X')
48 #define ID_BTEX MK_ID('B','T','E','X')
49
50 #define ID_TIMG MK_ID('T','I','M','G')
51 #define ID_TFLG MK_ID('T','F','L','G')
52 #define ID_TSIZ MK_ID('T','S','I','Z')
53 #define ID_TCTR MK_ID('T','C','T','R')
54 #define ID_TFAL MK_ID('T','F','A','L')
55 #define ID_TVEL MK_ID('T','V','E','L')
56 #define ID_TWRP MK_ID('T','W','R','P')
57
58
59 #define FALSE 0
60 #define TRUE 1
61
62 #define g_return_val_if_fail(expr,val) if (!(expr)) return val;
63 #define g_return_if_fail(expr) if (!(expr)) return;
64 #define g_realloc(exp1,exp2) realloc(exp1,exp2)
65 #define g_malloc0(exp) malloc(exp)
66 #define g_warning printf
67 #define g_free free
68
read_char(FILE * f)69 static gint32 read_char(FILE *f)
70 {
71 int c = fgetc(f);
72 g_return_val_if_fail(c != EOF, 0);
73 return c;
74 }
75
read_short(FILE * f)76 static gint32 read_short(FILE *f)
77 {
78 return (read_char(f)<<8) | read_char(f);
79 }
80
read_long(FILE * f)81 static gint32 read_long(FILE *f)
82 {
83 return (read_char(f)<<24) | (read_char(f)<<16) | (read_char(f)<<8) | read_char(f);
84 }
85
86
read_float(FILE * f)87 static GLfloat read_float(FILE *f)
88 {
89 return lwo2::changeType4<GLfloat, gint32>(read_long(f));
90 }
91
read_string(FILE * f,char * s)92 static gint read_string(FILE *f, char *s)
93 {
94 gint c;
95 gint cnt = 0;
96 do {
97 c = read_char(f);
98 if (cnt < LW_MAX_NAME_LEN)
99 s[cnt] = c;
100 else
101 s[LW_MAX_NAME_LEN-1] = 0;
102 cnt++;
103 } while (c != 0);
104 /* if length of string (including \0) is odd skip another byte */
105 if (cnt%2) {
106 read_char(f);
107 cnt++;
108 }
109 return cnt;
110 }
111
read_srfs(FILE * f,gint nbytes,lwObject * lwo)112 static void read_srfs(FILE *f, gint nbytes, lwObject *lwo)
113 {
114 int guess_cnt = lwo->material_cnt;
115
116 while (nbytes > 0) {
117 lwMaterial *material;
118
119 /* allocate more memory for materials if needed */
120 if (guess_cnt <= lwo->material_cnt) {
121 guess_cnt += guess_cnt/2 + 4;
122 lwo->material = (lwMaterial*) g_realloc(lwo->material, sizeof(lwMaterial)*guess_cnt);
123 }
124 material = lwo->material + lwo->material_cnt++;
125
126 /* read name */
127 nbytes -= read_string(f,material->name);
128
129 /* defaults */
130 material->r = 0.7f;
131 material->g = 0.7f;
132 material->b = 0.7f;
133 }
134 lwo->material = (lwMaterial*) g_realloc(lwo->material, sizeof(lwMaterial)*lwo->material_cnt);
135 }
136
137
read_surf(FILE * f,gint nbytes,lwObject * lwo)138 static void read_surf(FILE *f, gint nbytes, lwObject *lwo)
139 {
140 int i;
141 char name[LW_MAX_NAME_LEN];
142 lwMaterial *material = NULL;
143
144 /* read surface name */
145 nbytes -= read_string(f,name);
146
147 /* find material */
148 for (i=0; i< lwo->material_cnt; i++) {
149 if (strcmp(lwo->material[i].name,name) == 0) {
150 material = &lwo->material[i];
151 break;
152 }
153 }
154 g_return_if_fail(material != NULL);
155
156 lwTexture* tex = NULL;
157
158 /* read values */
159 while (nbytes > 0) {
160 gint id = read_long(f);
161 gint len = read_short(f);
162 nbytes -= 6 + len + (len%2);
163
164 switch (id) {
165 case ID_COLR:
166 material->r = read_char(f) / 255.0f;
167 material->g = read_char(f) / 255.0f;
168 material->b = read_char(f) / 255.0f;
169 read_char(f); /* dummy */
170 break;
171 case ID_CTEX:
172 case ID_DTEX:
173 case ID_STEX:
174 case ID_RTEX:
175 case ID_TTEX:
176 case ID_BTEX:
177 len -= read_string(f, name);
178 if (id == ID_CTEX) {
179 tex = &material->ctex;
180 }
181 else
182 tex = NULL;
183 break;
184 case ID_TIMG: {
185 len -= read_string(f, name);
186 if (tex) {
187 /* last component of path */
188 char* slash = strrchr(name, '/');
189 if (!slash)
190 slash = strrchr(name, '\\');
191 if (slash)
192 strncpy(tex->name, slash+1, LW_MAX_NAME_LEN-1);
193 else
194 strncpy(tex->name, name, LW_MAX_NAME_LEN-1);
195
196 tex->name[LW_MAX_NAME_LEN-1] = '\0';
197 //printf("tex name=%s\n", tex->name);
198 }
199 } break;
200 case ID_TFLG:
201 if (tex) {
202 tex->flags = read_short(f);
203 }
204 else
205 fseek(f, len+(len%2), SEEK_CUR);
206 break;
207 case ID_TSIZ:
208 if (tex) {
209 tex->sx = read_float(f);
210 tex->sy = read_float(f);
211 tex->sz = read_float(f);
212 }
213 else
214 fseek(f, len+(len%2), SEEK_CUR);
215 break;
216 case ID_TCTR:
217 if (tex) {
218 tex->cx = read_float(f);
219 tex->cy = read_float(f);
220 tex->cz = read_float(f);
221 }
222 else
223 fseek(f, len+(len%2), SEEK_CUR);
224 break;
225 case ID_TFAL:
226 if (tex) {
227 //float vx,vy,vz;
228 /*vx =*/ read_float(f);
229 /*vy =*/ read_float(f);
230 /*vz =*/ read_float(f);
231 //printf("fal %.2f %.2f %.2f\n", vx,vy,vz);
232 }
233 else
234 fseek(f, len+(len%2), SEEK_CUR);
235 break;
236 case ID_TVEL:
237 if (tex) {
238 //float vx,vy,vz;
239 /*vx =*/ read_float(f);
240 /*vy =*/ read_float(f);
241 /*vz =*/ read_float(f);
242 //printf("vel %.2f %.2f %.2f\n", vx,vy,vz);
243 }
244 else
245 fseek(f, len+(len%2), SEEK_CUR);
246 break;
247 case ID_TWRP:
248 if (tex) {
249 tex->u_wrap = (lwTextureWrap) read_short(f);
250 tex->v_wrap = (lwTextureWrap) read_short(f);
251 }
252 else
253 fseek(f, len+(len%2), SEEK_CUR);
254 break;
255 default:
256 fseek(f, len+(len%2), SEEK_CUR);
257 }
258 }
259 }
260
261
read_pols(FILE * f,int nbytes,lwObject * lwo)262 static void read_pols(FILE *f, int nbytes, lwObject *lwo)
263 {
264 int guess_cnt = lwo->face_cnt;
265
266 while (nbytes > 0) {
267 lwFace *face;
268 int i;
269
270 /* allocate more memory for polygons if necessary */
271 if (guess_cnt <= lwo->face_cnt) {
272 guess_cnt += guess_cnt + 4;
273 lwo->face = (lwFace*) g_realloc(lwo->face, sizeof(lwFace)*guess_cnt);
274 }
275 face = lwo->face + lwo->face_cnt++;
276
277 face->init();
278
279 /* number of points in this face */
280 face->index_cnt = read_short(f);
281 nbytes -= 2;
282
283 /* allocate space for points */
284 face->index = (int*) g_malloc0(sizeof(int)*face->index_cnt);
285
286 /* read points in */
287 for (i=0; i<face->index_cnt; i++) {
288 face->index[i] = read_short(f);
289 nbytes -= 2;
290 }
291
292 /* read surface material */
293 face->material = read_short(f);
294 nbytes -= 2;
295
296 /* skip over detail polygons */
297 if (face->material < 0) {
298 printf("face->material=%i ",face->material);
299 int det_cnt;
300 face->material = -face->material;
301 det_cnt = read_short(f);
302 nbytes -= 2;
303 while (det_cnt-- > 0) {
304 int cnt = read_short(f);
305 fseek(f, cnt*2+2, SEEK_CUR);
306 nbytes -= cnt*2+2;
307 }
308 }
309 face->material -= 1;
310 }
311 /* readjust to true size */
312 lwo->face = (lwFace*) g_realloc(lwo->face, sizeof(lwFace)*lwo->face_cnt);
313 }
314
315
316
read_pnts(FILE * f,gint nbytes,lwObject * lwo)317 static void read_pnts(FILE *f, gint nbytes, lwObject *lwo)
318 {
319 int i;
320 lwo->vertex_cnt = nbytes / 12;
321 lwo->vertex = (GLfloat*) g_malloc0(sizeof(GLfloat)*lwo->vertex_cnt*3);
322 for (i=0; i<lwo->vertex_cnt; i++) {
323 lwo->vertex[i*3+0] = read_float(f);
324 lwo->vertex[i*3+1] = read_float(f);
325 lwo->vertex[i*3+2] = read_float(f);
326 }
327 }
328
329
330
331
332
333
lw_is_lwobject(const char * lw_file)334 gint lw_is_lwobject(const char *lw_file)
335 {
336 FILE *f = osgDB::fopen(lw_file, "rb");
337 if (f) {
338 gint32 form = read_long(f);
339 gint32 nlen = read_long(f);
340 gint32 lwob = read_long(f);
341 fclose(f);
342 if (form == ID_FORM && nlen != 0 && lwob == ID_LWOB)
343 return TRUE;
344 }
345 return FALSE;
346 }
347
348
lw_object_read(const char * lw_file,std::ostream & output)349 lwObject *lw_object_read(const char *lw_file, std::ostream& output)
350 {
351 FILE *f = NULL;
352 lwObject *lw_object = NULL;
353
354 gint32 form_bytes = 0;
355 gint32 read_bytes = 0;
356
357 /* open file */
358 f = osgDB::fopen(lw_file, "rb");
359 if (f == NULL) {
360 output << "can't open file "<<lw_file<<std::endl;
361 return NULL;
362 }
363
364 /* check for headers */
365 if (read_long(f) != ID_FORM) {
366 output << "file "<<lw_file<<" is not an IFF file"<<std::endl;
367 fclose(f);
368 return NULL;
369 }
370 form_bytes = read_long(f);
371 read_bytes += 4;
372
373 if (read_long(f) != ID_LWOB) {
374 output << "file "<<lw_file<<" is not a LWOB file"<<std::endl;
375 fclose(f);
376 return NULL;
377 }
378
379 /* create new lwObject */
380 lw_object = (lwObject*) g_malloc0(sizeof(lwObject));
381 lw_object->init();
382
383 /* read chunks */
384 while (read_bytes < form_bytes) {
385 gint32 id = read_long(f);
386 gint32 nbytes = read_long(f);
387 read_bytes += 8 + nbytes + (nbytes%2);
388
389 switch (id) {
390 case ID_PNTS:
391 read_pnts(f, nbytes, lw_object);
392 break;
393 case ID_POLS:
394 read_pols(f, nbytes, lw_object);
395 break;
396 case ID_SRFS:
397 read_srfs(f, nbytes, lw_object);
398 break;
399 case ID_SURF:
400 read_surf(f, nbytes, lw_object);
401 break;
402 default:
403 fseek(f, nbytes + (nbytes%2), SEEK_CUR);
404 }
405 }
406
407 fclose(f);
408
409 for (int i = 0; i < lw_object->face_cnt; i++) {
410 int mati = lw_object->face[i].material;
411 if (mati == 0)
412 continue;
413
414 /* fetch material */
415 lwMaterial* mat = &lw_object->material[mati];
416 unsigned int flags = mat->ctex.flags;
417 if (flags == 0)
418 continue;
419
420 /* calculate texture coordinates */
421 lwFace* face = &lw_object->face[i];
422 face->texcoord = (float*) g_malloc0(face->index_cnt * sizeof(float) * 2);
423 for (int j = 0; j < face->index_cnt; j++) {
424 int vi = face->index[j];
425 GLfloat* vtx = &lw_object->vertex[vi*3];
426
427 GLfloat u,v;
428 u = v = 0.0f;
429 if (flags & X_AXIS) {
430 u = (vtx[1] - mat->ctex.cy) / mat->ctex.sy;
431 v = (vtx[2] - mat->ctex.cz) / mat->ctex.sz;
432 }
433 else if (flags & Y_AXIS) {
434 u = (vtx[0] - mat->ctex.cx) / mat->ctex.sx;
435 v = (vtx[2] - mat->ctex.cz) / mat->ctex.sz;
436 }
437 else if (flags & Z_AXIS) {
438 u = (vtx[0] - mat->ctex.cx) / mat->ctex.sx;
439 v = (vtx[1] - mat->ctex.cy) / mat->ctex.sy;
440 }
441 face->texcoord[j*2] = u + 0.5f;
442 face->texcoord[j*2+1] = v + 0.5f;
443 //printf("%.2f %.2f\n", u,v);
444 }
445 }
446
447 return lw_object;
448 }
449
450
451
452
453
454
455
lw_object_free(lwObject * lw_object)456 void lw_object_free(lwObject *lw_object)
457 {
458 g_return_if_fail(lw_object != NULL);
459
460 if (lw_object->face) {
461 int i;
462 for (i=0; i<lw_object->face_cnt; i++) {
463 g_free(lw_object->face[i].index);
464 if (lw_object->face[i].texcoord)
465 g_free(lw_object->face[i].texcoord);
466 }
467 g_free(lw_object->face);
468 }
469 g_free(lw_object->material);
470 g_free(lw_object->vertex);
471 g_free(lw_object);
472 }
473
474
lw_object_radius(const lwObject * lwo)475 GLfloat lw_object_radius(const lwObject *lwo)
476 {
477 int i;
478 double max_radius = 0.0;
479
480 g_return_val_if_fail(lwo != NULL, 0.0);
481
482 for (i=0; i<lwo->vertex_cnt; i++) {
483 GLfloat *v = &lwo->vertex[i*3];
484 double r = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
485 if (r > max_radius)
486 max_radius = r;
487 }
488 return (float)sqrt(max_radius);
489 }
490
lw_object_scale(lwObject * lwo,GLfloat scale)491 void lw_object_scale(lwObject *lwo, GLfloat scale)
492 {
493 int i;
494
495 g_return_if_fail(lwo != NULL);
496
497 for (i=0; i<lwo->vertex_cnt; i++) {
498 lwo->vertex[i*3+0] *= scale;
499 lwo->vertex[i*3+1] *= scale;
500 lwo->vertex[i*3+2] *= scale;
501 }
502 }
503
504
505