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