1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2002  Steve Baker
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Library General Public
7      License as published by the Free Software Foundation; either
8      version 2 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Library General Public License for more details.
14 
15      You should have received a copy of the GNU Library General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 
19      For further information visit http://plib.sourceforge.net
20 
21      $Id: ssgLoadFLT.cxx 1762 2003-04-17 13:10:12Z stromberg $
22 */
23 
24 //
25 //  $Id: ssgLoadFLT.cxx 1762 2003-04-17 13:10:12Z stromberg $
26 //
27 //
28 //    OpenFlight loader for SSG
29 //
30 //
31 //  The loading of FLT files can to some degree be controlled by
32 //  setting environment variables:
33 //
34 //     FLTNOCLEAN   - if set disables all kinds of scene graph optimisations
35 //     FLTNOEXT     - ignore external references
36 //     FLTNOTEX     - disables textures altogether
37 //     FLTNOMIPMAP  - configure textures for bilinear filtering (no mipmaps)
38 //
39 //
40 //  Some known issues:
41 //
42 //  1. The color table in v14.0 and earlier is defined differently and
43 //     cannot be parsed. It may consist of 16 colours of 16 brightnesses
44 //     each, and the RGB values are passed as shorts.
45 //
46 //  2. Geometry in v11.0 and earlier are defined using obsolete records
47 //     (opcodes 6, 7, 8 and 9). Need specifications to parse them.
48 //
49 //  3. How to find external files properly. Some loaders (most notably
50 //     IRIS Performer and MultiGen) uses the variable FLTEXTERNPATH.
51 //     (MultiGen also uses FLTPATH and TXTPATH I think).
52 //
53 //  4. How to do mmap on Mac and PS2.
54 //
55 //  5. No optimisations are done on the geometry. New triangle strip
56 //     generation code planned for SSG, and should be used when ready.
57 //
58 //  6. Optimisation done on the scene graph level are minimal.
59 //
60 //
61 //
62 /*
63  * Another OpenFlight loader for Performer
64  * Copyright (C) 1998-2000  Marten Stromberg
65  *
66  * This library is free software; you can redistribute it and/or
67  * modify it under the terms of the GNU Library General Public
68  * License as published by the Free Software Foundation; either
69  * version 2 of the License, or (at your option) any later version.
70  *
71  * This library is distributed in the hope that it will be useful,
72  * but WITHOUT ANY WARRANTY; without even the implied warranty of
73  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
74  * Library General Public License for more details.
75  *
76  * You should have received a copy of the GNU Library General Public
77  * License along with this library; if not, write to the Free
78  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
79  */
80 
81 #include "ssg.h"
82 #include "ssgLoaderWriterStuff.h"
83 
84 /* define this to compile against older versions of SSG */
85 /*#define NO_LOADER_OPTIONS*/
86 
87 /* debug */
88 /*#define NO_LIGHTING*/
89 /*#define NO_TEXTURES*/
90 /*#define NO_COLORS*/
91 
92 /* Try to figure out how to do mmap. */
93 #ifdef UL_WIN32
94 # define USE_WIN32_MMAP
95 #else
96 # include <unistd.h>
97 # ifdef _POSIX_MAPPED_FILES
98 #  define USE_POSIX_MMAP
99 # endif
100 #endif
101 
102 #include <stdlib.h>
103 #include <string.h>
104 #include <fcntl.h>
105 #include <stdio.h>
106 #ifdef UL_IRIX
107 # include <sys/endian.h>
108 #endif
109 #ifdef USE_POSIX_MMAP
110 # include <time.h>
111 # include <sys/time.h>   /* Need both for Mandrake 8.0 !! */
112 # include <sys/stat.h>
113 # include <sys/mman.h>
114 #endif
115 #ifdef UL_MSVC
116 # include <io.h>
117 #endif
118 
119 
120 #ifndef O_BINARY
121 # define O_BINARY 0
122 #endif
123 
124 #ifndef R_OK
125 # define R_OK 4
126 #endif
127 
128 #ifndef ABS
129 # define ABS(x) ((x)>=0?(x):-(x))
130 #endif
131 #ifndef MIN
132 # define MIN(a,b) ((a)<=(b)?(a):(b))
133 #endif
134 #ifndef MAX
135 # define MAX(a,b) ((a)>=(b)?(a):(b))
136 #endif
137 #define MIN3(a,b,c) ((a)<=(b)?MIN(a,c):MIN(b,c))
138 #define MAX3(a,b,c) ((a)>=(b)?MAX(a,c):MAX(b,c))
139 #define CLAMP(x,lo,hi) ((x)<=(lo)?(lo):(x)>=(hi)?(hi):(x))
140 
141 #define template _template /* trams */
142 
143 typedef unsigned char ubyte;
144 
145 #ifdef UL_WIN32
146 typedef unsigned short ushort;
147 typedef unsigned int uint;
148 #endif
149 
150 // 525 = negative identation, 539= did not expect positive identation
151 //lint -save -e525 -e539
152 
153 /*
154  * byte sex
155  */
156 
157 /* XXX what about PDP_ENDIAN? */
158 
159 /* Help! Is this correct? */
160 #if (!defined(BYTE_ORDER) && defined(UL_WIN32) && !defined(NOT_INTEL_BYTE_ORDER))
161 # define LITTLE_ENDIAN  1234
162 # define BIG_ENDIAN     4321
163 # define BYTE_ORDER     LITTLE_ENDIAN
164 #endif
165 
166 /* #undef BYTE_ORDER */
167 
168 #if !defined(BYTE_ORDER) || BYTE_ORDER != BIG_ENDIAN
169 
170 #if !defined(BYTE_ORDER)
_swab16(const void * src,void * dst,int n)171 static void _swab16(const void *src, void *dst, int n)
172 {
173    ushort *s = (ushort *)src;
174    ushort *d = (ushort *)dst;
175    while (n--) {
176       ushort t = *s++;
177       *d++ = (((t & 0xff00U) >> 8) |
178 	      ((t & 0x00ffU) << 8));
179    }
180 }
181 #endif
182 
_swab32(const void * src,void * dst,int n)183 static void _swab32(const void *src, void *dst, int n)
184 {
185    uint *s = (uint *)src;
186    uint *d = (uint *)dst;
187    while (n--) {
188       uint t = *s++;
189       *d++ = (((t & 0xff000000U) >> 24) |
190 	      ((t & 0x00ff0000U) >> 8) |
191 	      ((t & 0x0000ff00U) << 8) |
192 	      ((t & 0x000000ffU) << 24));
193    }
194 }
195 
_swab64(const void * src,void * dst,int n)196 static void _swab64(const void *src, void *dst, int n)
197 {
198    /* XXX how to check if 64-bit integers are available?? */
199    uint *s = (uint *)src;
200    uint *d = (uint *)dst;
201    while (n--) {
202       uint t0 = *s++;
203       uint t1 = *s++;
204       *d++ = (((t1 & 0xff000000U) >> 24) |
205 	      ((t1 & 0x00ff0000U) >> 8) |
206 	      ((t1 & 0x0000ff00U) << 8) |
207 	      ((t1 & 0x000000ffU) << 24));
208       *d++ = (((t0 & 0xff000000U) >> 24) |
209 	      ((t0 & 0x00ff0000U) >> 8) |
210 	      ((t0 & 0x0000ff00U) << 8) |
211 	      ((t0 & 0x000000ffU) << 24));
212    }
213 }
214 
215 #endif
216 
217 #if !defined(BYTE_ORDER) || BYTE_ORDER != LITTLE_ENDIAN
218 
_copy16(const void * src,void * dst,int n)219 static void _copy16(const void *src, void *dst, int n)
220 {
221    memcpy(dst, src, 2*n);
222 }
223 
_copy32(const void * src,void * dst,int n)224 static void _copy32(const void *src, void *dst, int n)
225 {
226    memcpy(dst, src, 4*n);
227 }
228 
_copy64(const void * src,void * dst,int n)229 static void _copy64(const void *src, void *dst, int n)
230 {
231    memcpy(dst, src, 8*n);
232 }
233 
234 #endif
235 
236 
237 #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
238 
239 /* big endian */
240 
get16u(const void * ptr)241 inline uint get16u(const void *ptr)
242 {
243    return *(ushort *)ptr;
244 }
245 
get32u(const void * ptr)246 inline uint get32u(const void *ptr)
247 {
248    return *(uint *)ptr;
249 }
250 
251 #define get16v _copy16
252 #define get32v _copy32
253 #define get64v _copy64
254 
255 #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
256 
257 /* little endian */
258 
get16u(const void * ptr)259 inline uint get16u(const void *ptr)
260 {
261    ushort tmp = *(ushort *)ptr;
262    return (((tmp & 0xff00U) >> 8) |
263 	   ((tmp & 0x00ffU) << 8));
264 }
265 
get32u(const void * ptr)266 inline uint get32u(const void *ptr)
267 {
268    uint tmp = *(uint *)ptr;
269    return (((tmp & 0xff000000U) >> 24) |
270 	   ((tmp & 0x00ff0000U) >> 8) |
271 	   ((tmp & 0x0000ff00U) << 8) |
272 	   ((tmp & 0x000000ffU) << 24));
273 }
274 
275 #define get16v _swab16
276 #define get32v _swab32
277 #define get64v _swab64
278 
279 #else
280 
281 /* any endian */
282 
get16u(const void * ptr)283 inline uint get16u(const void *ptr)
284 {
285    ubyte *u = (ubyte *)ptr;
286    return (((uint)u[0] << 8) |
287 	   ((uint)u[1] << 0));
288 }
289 
get32u(const void * ptr)290 inline uint get32u(const void *ptr)
291 {
292    ubyte *u = (ubyte *)ptr;
293    return (((uint)u[0] << 24) |
294 	   ((uint)u[1] << 16) |
295 	   ((uint)u[2] << 8) |
296 	   ((uint)u[3] << 0));
297 }
298 
299 static void (*get16v)(const void *, void *, int);
300 static void (*get32v)(const void *, void *, int);
301 static void (*get64v)(const void *, void *, int);
302 
303 #define PROBE_ENDIAN 1
304 
305 #endif
306 
307 #define get16i(ptr) (short)get16u(ptr)
308 #define get32i(ptr) (int)get32u(ptr)
309 
310 
311 /* splay trees
312  *
313  * for further details, see "Self-adjusting Binary Search Trees"
314  * by Sleator and Tarjan, JACM Volume 32, No 3, July 1985, pp 652-686.
315  */
316 
317 struct snode {
318    struct snode *left, *right;
319    void *key;
320    void *data;
321 };
322 
323 typedef int (*sfunc)(const void *key1, const void *key2);
324 
splay(struct snode * t,const void * key,sfunc comp)325 static struct snode *splay(struct snode *t, const void *key, sfunc comp)
326 {
327    struct snode N, *l, *r, *y;
328 
329    if (t == NULL) return t;
330    N.left = N.right = NULL;
331    l = r = &N;
332 
333    for (;;) {
334       if (comp(key, t->key) < 0) {
335 	 if (t->left == NULL) break;
336 	 if (comp(key, t->left->key) < 0) {
337 	    y = t->left;                           /* rotate right */
338 	    t->left = y->right;
339 	    y->right = t;
340 	    t = y;
341 	    if (t->left == NULL) break;
342 	 }
343 	 r->left = t;                               /* link right */
344 	 r = t;
345 	 t = t->left;
346       }
347       else if (comp(key, t->key) > 0) {
348 	 if (t->right == NULL) break;
349 	 if (comp(key, t->right->key) > 0) {
350 	    y = t->right;                           /* rotate left */
351 	    t->right = y->left;
352 	    y->left = t;
353 	    t = y;
354 	    if (t->right == NULL) break;
355 	 }
356 	 l->right = t;                              /* link left */
357 	 l = t;
358 	 t = t->right;
359       }
360       else {
361 	 break;
362       }
363    }
364 
365    l->right = t->left;                              /* assemble */
366    r->left = t->right;
367    t->left = N.right;
368    t->right = N.left;
369 
370    return t;
371 }
372 
sinsert(struct snode * root,void * key,size_t size,sfunc comp)373 static struct snode *sinsert(struct snode *root, void *key, size_t size, sfunc comp)
374 {
375    struct snode *t, *x;
376    t = splay(root, key, comp);
377    if (t != NULL && comp(t->key, key) == 0)
378       return t;
379    //x = (struct snode *)malloc(sizeof(struct snode));
380    x = new snode;
381    assert( x != NULL );
382    if (t == NULL) {
383       x->left = x->right = NULL;
384    }
385    else if (comp(key, t->key) < 0) {
386       x->left = t->left;
387       x->right = t;
388       t->left = NULL;
389    }
390    else {
391       x->right = t->right;
392       x->left = t;
393       t->right = NULL;
394    }
395    if (size > 0) {
396       //x->key = malloc(size);
397       x->key = new ubyte[size];
398       memcpy(x->key, key, size);
399    }
400    else {
401       x->key = key;
402    }
403    x->data = (void *)-1;
404    return x;
405 }
406 
407 #define S_KEY   1 /* free key */
408 #define S_DATA  2 /* free data */
409 #define S_TREE  4 /* delete scene graph (SSG special) */
410 
deltree(ssgEntity * node)411 static void deltree(ssgEntity *node)
412 {
413    if (node->getRef() <= 1 && node->isAKindOf(ssgTypeBranch())) {
414       ssgBranch *grp = (ssgBranch *)node;
415       int n = grp->getNumKids();
416       while (n--) {
417 	 deltree(grp->getKid(n));
418 	 grp->removeKid(n); // delete kid (iff ref == 0)
419       }
420    }
421 }
422 
sfree(struct snode * x,int flags)423 static void sfree(struct snode *x, int flags)
424 {
425    if (x) {
426       sfree(x->left, flags);
427       sfree(x->right, flags);
428       if ((flags & S_KEY))
429 	 //free(x->key);
430 	 delete [] (ubyte *)x->key;
431       if (x->data != (void *)-1 && x->data != 0) {
432 	 if ((flags & S_DATA))
433 	    //free(x->data);
434 	    delete [] (ubyte *)x->data;
435 	 if ((flags & S_TREE)) {
436 	    deltree((ssgEntity *)x->data);
437 	    ssgDeRefDelete((ssgEntity *)x->data);
438 	 }
439       }
440    }
441 }
442 
ptrcmp(const void * key1,const void * key2)443 static int ptrcmp(const void *key1, const void *key2)
444 {
445    return (const char *)key1 - (const char *)key2;
446 }
447 
448 
hexdump(enum ulSeverity severity,const ubyte * buf,int size,int offset)449 static void hexdump(enum ulSeverity severity, const ubyte *buf, int size, int offset)
450 {
451 #define COLS 16
452    char line[1024], *lp;
453    while (size > 0) {
454       int i, n = MIN(size, COLS);
455       lp = line;
456       lp += sprintf(lp, "%04x ", offset);
457       for (i = 0; i < n; i++)
458 	 lp += sprintf(lp, " %02x", buf[i]);
459       for (; i < COLS; i++)
460 	 lp += sprintf(lp, "   ");
461       *lp++ = ' ';
462       *lp++ = ' ';
463       for (i = 0; i < n; i++)
464 	 *lp++ = (buf[i] & 0x7f) < 0x20 ? '.' : buf[i];
465       *lp = 0;
466       ulSetError(severity, line);
467       buf += COLS;
468       offset += COLS;
469       size -= COLS;
470    }
471 }
472 
473 
474 
475 #define MAXDEPTH 256
476 
477 #define UNPACK_ABGR(dst, src) \
478      ((dst)[0] = (1.0f/255.0f)*(src)[3], \
479       (dst)[1] = (1.0f/255.0f)*(src)[2], \
480       (dst)[2] = (1.0f/255.0f)*(src)[1], \
481       (dst)[3] = 1.0f)
482 
483 #define UNPACK_ABGR2(dst, src, intensity) \
484      ((dst)[0] = (1.0f/255.0f/127.0f)*(src)[3]*(intensity), \
485       (dst)[1] = (1.0f/255.0f/127.0f)*(src)[2]*(intensity), \
486       (dst)[2] = (1.0f/255.0f/127.0f)*(src)[1]*(intensity), \
487       (dst)[3] = 1.0f)
488 
489 /* triangle flags */
490 #define TRI_COLOR_MATERIAL 0x01  /* --> apply material on vertex colors */
491 #define TRI_TRANSLUCENT    0x02
492 #define TRI_SUBFACE        0x04  /* offset geometry */
493 #define TRI_BBOARD_AXIAL   0x08
494 #define TRI_BBOARD_POINT   0x10
495 /*#define TRI_WIREFRAME      0x20*/
496 #define TRI_BBOARD (TRI_BBOARD_AXIAL | TRI_BBOARD_POINT)
497 
498 /* vertex bind */
499 #define BIND_COLOR        0x01
500 #define BIND_NORMAL       0x02
501 #define BIND_TEXCOORD     0x04
502 #define BIND_FLAT_COLOR   0x08
503 #define BIND_FLAT_NORMAL  0x10
504 #define BIND_FLAT (BIND_FLAT_COLOR | BIND_FLAT_NORMAL)
505 
506 struct fltTriangle {
507 
508    ssgState *state;
509 
510    ubyte flags;
511    ubyte bind;
512 
513 #if 0
514    short priority; /* affects the ordering within the geoset */
515    ushort transparency; /* eventually applied to colors when done */
516 #endif
517 
518    int index[3];
519    sgVec4 color; /* face color *or* material contributions to vertex colors */
520 
521 };
522 
523 struct fltTexture {
524    char *file;
525    ssgState *state; /* user-defined state */
526    ssgTexture *tex;
527    int alpha;
528 };
529 
530 struct fltState {
531 
fltStatefltState532    fltState() {
533       memset(this, 0, sizeof(*this));
534       notex_state = (ssgState *)-1;
535       atris = 256;
536       //tris = (fltTriangle *)malloc(sizeof(fltTriangle) * atris);
537       tris = new fltTriangle[atris];
538    }
539 
~fltStatefltState540    ~fltState() {
541       sfree(texs, S_DATA);
542       sfree(mtls, S_DATA);
543       sfree(refs, S_TREE);
544       if (vtab) {
545 	 delete [] offset;
546 	 delete [] bind;
547 	 delete [] coord;
548 	 delete [] color;
549 	 delete [] normal;
550 	 delete [] texcoord;
551       }
552       //free(tris);
553       delete [] tris;
554    }
555 
556    const char *filename;
557    int revision;
558    int major;
559    int minor;
560 
561    /* Vertex Table */
562    ubyte *vtab; /* start of vertex table */
563    int vnum;
564    int *offset; /* chunk offset (used as index) */
565    ubyte *bind; /* 1 - color, 2 - normal, 4 - texcoord */
566    sgVec3 *coord;
567    sgVec4 *color;
568    sgVec3 *normal;
569    sgVec2 *texcoord;
570 
571    /* Other Tables (these may be sparse, that is why arrays are not used) */
572    struct snode *mtls; /* index --> float[14] */
573    struct snode *texs; /* index --> fltTexture */
574    struct snode *refs; /* index --> ssgEntity */
575    ubyte (*ctab)[4]; /* packed ABGR color table */
576    int cnum;
577    ssgState *notex_state; /* special user-defined state if no texture */
578 
579    /* Collected Geometry */
580    fltTriangle *tris;
581    int ntris, atris;
582    fltTriangle *temp;
583    char *parent_name;
584 };
585 
586 struct fltNodeAttr {
587 
588    /* allocated using new/delete for convenience */
fltNodeAttrfltNodeAttr589    fltNodeAttr() {
590       memset(this, 0, sizeof(*this));
591    }
~fltNodeAttrfltNodeAttr592    ~fltNodeAttr() {
593       if (name) delete name;
594       if (mask_words) delete mask_words;
595    }
596 
597    /* properies that are not applied immediately */
598 
599    char *name;
600 
601    int replicate;
602    int transform;
603    int islod;
604 
605    sgMat4 mat;
606    sgVec2 range;
607    sgVec3 center;
608 
609    /* switch record info */
610    int num_masks;
611    int num_words;
612    uint *mask_words;
613    int current_mask;
614 
615 };
616 
617 static int Inited = 0;
618 static int NoTextures = 0;
619 static int NoMipmaps = 0;
620 static int NoExternals = 0;
621 static int NoClean = 0;
622 
623 #ifndef NO_LOADER_OPTIONS
624 static ssgLoaderOptions *LoaderOptions;
625 #endif
626 
627 static struct snode *TexCache; /* filename --> fltTexture */
628 
LoadTex(char * fname)629 static fltTexture *LoadTex(char *fname)
630 {
631    TexCache = sinsert(TexCache, fname, strlen(fname) + 1, (sfunc)strcmp);
632    if (TexCache->data == (void *)-1) {
633       //fltTexture *tex = (fltTexture *)malloc(sizeof(fltTexture));
634       fltTexture *tex = new fltTexture;
635       assert ( tex != NULL );
636       tex->file = fname;
637 #ifdef NO_LOADER_OPTIONS
638       tex->state = 0;
639       tex->tex = new ssgTexture(fname, 1, 1, !NoMipmaps);
640 #else
641       tex->state = LoaderOptions->createState(fname);
642       tex->tex = tex->state ? 0 : LoaderOptions->createTexture(fname, 1, 1, !NoMipmaps);
643 #endif
644       tex->alpha = tex->tex ? tex->tex->hasAlpha() : 0;
645       TexCache->data = tex;
646    }
647    return (fltTexture *)TexCache->data;
648 }
649 
650 struct StateInfo {
651    int cf; /* cull face */
652    int tr; /* translucent */
653    int cm; /* color material */
654    ssgTexture *tex;
655    float *mtl;
656    float alpha;
657 };
658 
StateCompare(const void * key1,const void * key2)659 static int StateCompare(const void *key1, const void *key2)
660 {
661    const StateInfo *s1 = (const StateInfo *)key1;
662    const StateInfo *s2 = (const StateInfo *)key2;
663    int d;
664    d = s1->cf - s2->cf;
665    if (d == 0) {
666       d = s1->tr - s2->tr;
667       if (d == 0) {
668 	 d = s1->cm - s2->cm;
669 	 if (d == 0) {
670 	    d = (char *)s1->tex - (char *)s2->tex;
671 	    if (d == 0) {
672 	       if (s1->mtl == 0 || s2->mtl == 0)
673 		  d = (char *)s1->mtl - (char *)s2->mtl;
674 	       else {
675 		  int i = s1->cm ? 6 : 0;
676 		  for (; i < 12 && d == 0; i++)
677 		     if (s1->mtl[i] < s2->mtl[i] - 0.01f)
678 			d = -1;
679 		     else if (s1->mtl[i] > s2->mtl[i] + 0.01f)
680 			d = 1;
681 		  if (d == 0) {
682 		     if (s1->alpha < s2->alpha - 0.01f)
683 			d = -1;
684 		     else if (s1->alpha > s2->alpha + 0.01f)
685 			d = 1;
686 		  }
687 	       }
688 	    }
689 	 }
690       }
691    }
692    return d;
693 }
694 
695 static struct snode *StateCache; /* StateInfo --> ssgSimpleState */
696 
ConstructState(StateInfo * key)697 static ssgSimpleState *ConstructState(StateInfo *key)
698 {
699    StateCache = sinsert(StateCache, key, sizeof(StateInfo), StateCompare);
700    if (StateCache->data == (void *)-1) {
701       ssgSimpleState *s;
702 
703       /*ulSetError(UL_DEBUG, "new state --");*/
704 
705       s = new ssgSimpleState;
706 
707       if (key->cf) {
708 	 s->enable(GL_CULL_FACE);
709       }
710       else {
711 	 s->disable(GL_CULL_FACE);
712 	 /*ulSetError(UL_DEBUG, "  two-sided");*/
713       }
714 
715       if (key->tr) {
716 	 s->setTranslucent();
717 	 s->enable(GL_BLEND); /* XXX what about multisampling? */
718 	 /*ulSetError(UL_DEBUG, "  transparent");*/
719       }
720       else {
721 	 s->setOpaque();
722 	 s->disable(GL_BLEND);
723       }
724       /* leave the alpha test to the application */
725 
726       if (key->mtl) {
727 	 float *m = key->mtl;
728 	 sgVec4 c;
729 	 /*ulSetError(UL_DEBUG, "%.2f %.2f %.2f  %.2f %.2f %.2f  %.2f %.2f %.2f  %.2f %.2f %.2f  %.2f %.2f  %d",
730 	   m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], key->cm);*/
731 	 if (key->cm) {
732 	    s->enable(GL_COLOR_MATERIAL);
733 	    s->setColourMaterial(GL_AMBIENT_AND_DIFFUSE);
734 	    //ulSetError(UL_DEBUG, "  color material");
735 	 }
736 	 else {
737 	    s->disable(GL_COLOR_MATERIAL);
738 	    sgSetVec4(c, m[0], m[1], m[2], key->alpha); s->setMaterial(GL_AMBIENT, c);
739 	    sgSetVec4(c, m[3], m[4], m[5], key->alpha); s->setMaterial(GL_DIFFUSE, c);
740 	    //ulSetError(UL_DEBUG, "  ambient   %.2f %.2f %.2f", m[0], m[1], m[2]);
741 	    //ulSetError(UL_DEBUG, "  diffuse   %.2f %.2f %.2f", m[3], m[4], m[5]);
742 	 }
743 	 sgSetVec4(c, m[6], m[7], m[8], key->alpha); s->setMaterial(GL_SPECULAR, c);
744 	 sgSetVec4(c, m[9], m[10], m[11], key->alpha); s->setMaterial(GL_EMISSION, c);
745 	 //ulSetError(UL_DEBUG, "  specular  %.2f %.2f %.2f", m[6], m[7], m[8]);
746 	 //ulSetError(UL_DEBUG, "  emission  %.2f %.2f %.2f", m[9], m[10], m[11]);
747 	 //ulSetError(UL_DEBUG, "  alpha %.2f", key->alpha);
748 	 s->setShininess(m[12]);
749 	 s->enable(GL_LIGHTING);
750       }
751       else {
752 	 s->disable(GL_LIGHTING);
753 	 /*ulSetError(UL_DEBUG, "  no lighting");*/
754       }
755 
756       if (key->tex) {
757 	 s->enable(GL_TEXTURE_2D);
758 	 s->setTexture(key->tex);
759 	 /*ulSetError(UL_DEBUG, "  texture %s", key->tex->getFilename());*/
760       }
761       else {
762 	 s->disable(GL_TEXTURE_2D);
763       }
764 
765       s->setShadeModel(GL_SMOOTH);
766 
767       s->ref();
768 
769       StateCache->data = s;
770    }
771    return (ssgSimpleState *)StateCache->data;
772 }
773 
tricmp(const void * a,const void * b)774 static int tricmp(const void *a, const void *b)
775 {
776    /* this comparison is used to sort the list of triangles in order to
777     * generate as few geosets as possible.
778     */
779    fltTriangle *ta = (fltTriangle *)a;
780    fltTriangle *tb = (fltTriangle *)b;
781    int d = (char *)ta->state - (char *)tb->state;
782    if (d == 0) {
783       d = ta->flags - tb->flags;
784       if (d == 0)
785 	 d = ta->bind - tb->bind;
786    }
787    return d;
788 }
789 
790 #if 0 /* no longer needed since this is now the default blend equation */
791 static int PreDrawTranslucent(ssgEntity *)
792 {
793    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
794    return 1;
795 }
796 #endif
797 
PreDrawSubface(ssgEntity *)798 static int PreDrawSubface(ssgEntity *)
799 {
800 #ifdef GL_VERSION_1_1
801    glPolygonOffset(-2.0f, -1.0f);
802    glEnable(GL_POLYGON_OFFSET_FILL);
803 #else
804    glPolygonOffsetEXT(-0.1f, -0.002f);
805    glEnable(GL_POLYGON_OFFSET_EXT);
806 #endif
807    return 1;
808 }
809 
PostDrawSubface(ssgEntity *)810 static int PostDrawSubface(ssgEntity *)
811 {
812 #ifdef GL_VERSION_1_1
813    glDisable(GL_POLYGON_OFFSET_FILL);
814 #else
815    glDisable(GL_POLYGON_OFFSET_EXT);
816 #endif
817    return 1;
818 }
819 
820 /* convert a list of triangles to geosets using the pfdMesher
821  * need a seperate geostate for each comb of tex/mtl/bind
822  */
Build(fltState * state)823 static ssgEntity *Build(fltState *state)
824 {
825    /*const char t[9] = "plsTQSfFP";*/
826    ssgBranch *grp = 0;
827    ssgCutout *bboard1 = 0;
828    ssgCutout *bboard2 = 0;
829    ssgLeaf *leaf = 0;
830    fltTriangle *arr;
831    int num, i, j, k, m, n;
832 
833    //int *index;
834    //int *vertex;
835 
836    arr = state->tris;
837    num = state->ntris;
838    state->ntris = 0;
839    if (num == 0)
840       return 0;
841 
842    /* sort the triangles (put them in bins according to their attributes)
843     * one geoset will be generated for each such bin
844     */
845    qsort(arr, num, sizeof(fltTriangle), tricmp);
846 
847    int *index = new int [ state->vnum ];
848    int *vertex = new int [ 32768 ];
849 
850    for (i = 0; i < num; ) {
851 
852       ssgVertexArray *va;
853       ssgColourArray *ca = 0;
854       ssgNormalArray *na = 0;
855       ssgTexCoordArray *ta = 0;
856       ssgVtxTable *geom;
857 
858       int flags = arr[i].flags;
859       int bind = arr[i].bind;
860 
861       /* see how many tris that belong to this group */
862       for (j = i + 1; (j < num &&
863                        arr[j].state == arr[i].state &&
864                        arr[j].flags == flags &&
865 		       arr[j].bind == bind
866                        ); j++)
867          ;
868       /*fprintf(stderr, " %d", j - i);*/
869 
870       /* simply construct a triangle soup */
871       /* XXX fixme! */
872 
873       if ((bind & BIND_FLAT) || (flags & TRI_COLOR_MATERIAL)) {
874 
875 	 n = 3*(j - i);
876 
877 	 va = new ssgVertexArray(n);
878 	 for (k = i; k < j; k++) {
879 	    va->add(state->coord[arr[k].index[0]]);
880 	    va->add(state->coord[arr[k].index[1]]);
881 	    va->add(state->coord[arr[k].index[2]]);
882 	 }
883 
884 	 if ((bind & BIND_FLAT_COLOR)) {
885 	    ca = new ssgColourArray(n);
886 	    for (k = i; k < j; k++) {
887 	       ca->add(arr[k].color);
888 	       ca->add(arr[k].color);
889 	       ca->add(arr[k].color);
890 	    }
891 	 }
892 	 else if ((bind & BIND_COLOR)) {
893 	    ca = new ssgColourArray(n);
894 	    if ((flags & TRI_COLOR_MATERIAL)) {
895 	       for (k = i; k < j; k++) {
896 		  for (m = 0; m < 3; m++) {
897 		     sgVec4 color;
898 		     float *mtl_color = arr[k].color;
899 		     float *vtx_color = state->color[arr[k].index[m]];
900 		     color[0] = mtl_color[0] * vtx_color[0];
901 		     color[1] = mtl_color[1] * vtx_color[1];
902 		     color[2] = mtl_color[2] * vtx_color[2];
903 		     color[3] = mtl_color[3] * vtx_color[3];
904 		     ca->add(color);
905 		  }
906 	       }
907 	    }
908 	    else {
909 	       for (k = i; k < j; k++) {
910 		  ca->add(state->color[arr[k].index[0]]);
911 		  ca->add(state->color[arr[k].index[1]]);
912 		  ca->add(state->color[arr[k].index[2]]);
913 	       }
914 	    }
915 	 }
916 	 else if ((flags & TRI_TRANSLUCENT)) {
917 	    ca = new ssgColourArray(1);
918 	    ca->add(arr[i].color);
919 	 }
920 
921 	 if ((bind & BIND_FLAT_NORMAL)) {
922 	    na = new ssgNormalArray(n);
923 	    for (k = i; k < j; k++) {
924 	       sgVec3 a, b, normal;
925 	       int *w = arr[k].index;
926 	       sgSubVec3(a, state->coord[w[1]], state->coord[w[0]]);
927 	       sgSubVec3(b, state->coord[w[2]], state->coord[w[0]]);
928 	       sgVectorProductVec3(normal, a, b);
929 	       sgNormalizeVec3(normal);
930 	       na->add(normal);
931 	       na->add(normal);
932 	       na->add(normal);
933 	    }
934 	 }
935 	 else if ((bind & BIND_NORMAL)) {
936 	    na = new ssgNormalArray(n);
937 	    for (k = i; k < j; k++) {
938 	       na->add(state->normal[arr[k].index[0]]);
939 	       na->add(state->normal[arr[k].index[1]]);
940 	       na->add(state->normal[arr[k].index[2]]);
941 	    }
942 	 }
943 
944 	 if ((bind & BIND_TEXCOORD)) {
945 	    ta = new ssgTexCoordArray(n);
946 	    for (k = i; k < j; k++) {
947 	       ta->add(state->texcoord[arr[k].index[0]]);
948 	       ta->add(state->texcoord[arr[k].index[1]]);
949 	       ta->add(state->texcoord[arr[k].index[2]]);
950 	    }
951 	 }
952 
953 	 geom = new ssgVtxTable(GL_TRIANGLES, va, na, ta, ca);
954 
955       }
956       else {
957 
958 	 ssgIndexArray *ia = new ssgIndexArray(3*(j - i));
959 
960 	 memset(index, -1, sizeof(index[0]) * state->vnum);
961 	 n = 0;
962 	 for (k = i; k < j; k++) {
963 	    int *tri = arr[k].index;
964 	    int save = n;
965 	    for (m = 0; m < 3; m++) {
966 	       if (index[tri[m]] == -1) {
967 		  if (n == 65536) {
968 		     ulSetError(UL_DEBUG, "[flt] More than 65536 vertices, split forced.");
969 		     n = save;
970 		     j = k;
971 		     //goto hopp;
972 		     break;
973 		  }
974 		  vertex[n] = tri[m];
975 		  index[tri[m]] = n++;
976 	       }
977 	       ia->add((short)index[tri[m]]);
978 	    }
979 	    if (m < 3) break;
980 	 }
981 	 //hopp:
982 
983 	 va = new ssgVertexArray(n);
984 	 for (k = 0; k < n; k++)
985 	    va->add(state->coord[vertex[k]]);
986 
987 	 if ((bind & BIND_COLOR)) {
988 	    ca = new ssgColourArray(n);
989 	    for (k = 0; k < n; k++)
990 	       ca->add(state->color[vertex[k]]);
991 	 }
992 	 else if ((flags & TRI_TRANSLUCENT)) {
993 	    ca = new ssgColourArray(1);
994 	    ca->add(arr[i].color);
995 	 }
996 
997 	 if ((bind & BIND_NORMAL)) {
998 	    na = new ssgNormalArray(n);
999 	    for (k = 0; k < n; k++)
1000 	       na->add(state->normal[vertex[k]]);
1001 	 }
1002 
1003 	 if ((bind & BIND_TEXCOORD)) {
1004 	    ta = new ssgTexCoordArray(n);
1005 	    for (k = 0; k < n; k++)
1006 	       ta->add(state->texcoord[vertex[k]]);
1007 	 }
1008 
1009 	 if (n == 3*(j - i)) {
1010 
1011 	    delete ia;
1012 
1013 	    geom = new ssgVtxTable(GL_TRIANGLES, va, na, ta, ca);
1014 	 }
1015 	 else {
1016 
1017 	    geom = new ssgVtxArray(GL_TRIANGLES, va, na, ta, ca, ia);
1018 	 }
1019 
1020       }
1021 
1022       geom->setState(arr[i].state);
1023 
1024       /*ulSetError(UL_DEBUG, "build: [%d..%d] %02x %d indices, %d vertices",
1025 	     i, j - 1, bind,
1026 	     3*(j - i), n);*/
1027 
1028       if (leaf) {
1029 	 if (grp == 0)
1030 	    grp = new ssgBranch;
1031 	 grp->addKid(leaf);
1032       }
1033 
1034       leaf = geom;
1035 
1036 #if 0
1037       if ((flags & TRI_TRANSLUCENT)) {
1038 	 leaf->setCallback(SSG_CALLBACK_PREDRAW, PreDrawTranslucent);
1039       }
1040       else
1041 #endif
1042       if ((flags & TRI_SUBFACE)) {
1043 	 leaf->setCallback(SSG_CALLBACK_PREDRAW, PreDrawSubface);
1044 	 leaf->setCallback(SSG_CALLBACK_POSTDRAW, PostDrawSubface);
1045       }
1046 
1047 #ifndef NO_LOADER_OPTIONS
1048       leaf = LoaderOptions->createLeaf(leaf, state->parent_name);
1049 #endif
1050 
1051       if ((flags & TRI_BBOARD)) {
1052 	 if ((flags & TRI_BBOARD_AXIAL)) {
1053 	    if (bboard1 == 0)
1054 	       bboard1 = new ssgCutout(0);
1055 	    bboard1->addKid(leaf);
1056 	 }
1057 	 else {
1058 	    if (bboard2 == 0)
1059 	       bboard2 = new ssgCutout(1);
1060 	    bboard2->addKid(leaf);
1061 	 }
1062 	 leaf = 0;
1063       }
1064 
1065       i = j;
1066    }
1067 
1068    delete [] vertex;
1069    delete [] index;
1070 
1071    if (((leaf != 0) + (bboard1 != 0) + (bboard2 != 0)) > 1 && !grp) //lint !e514 Lint warning "unusual use of a boolean"
1072       grp = new ssgBranch;
1073 
1074    if (grp) {
1075       if (bboard1)
1076 	 grp->addKid(bboard1);
1077       if (bboard2)
1078 	 grp->addKid(bboard2);
1079       if (leaf)
1080 	 grp->addKid(leaf);
1081       return grp;
1082    }
1083 
1084    if (bboard1)
1085       return bboard1;
1086 
1087    if (bboard2)
1088       return bboard2;
1089 
1090    return leaf;
1091 }
1092 
1093 /* add a triangle */
AddTri(fltState * state,int v0,int v1,int v2)1094 static void AddTri(fltState *state, int v0, int v1, int v2)
1095 {
1096    fltTriangle *tri;
1097    if (state->ntris == state->atris) {
1098       state->atris += state->atris;
1099       //state->tris = (fltTriangle *)realloc(state->tris, sizeof(fltTriangle) * state->atris);
1100       fltTriangle *old = state->tris;
1101       state->tris = new fltTriangle[state->atris];
1102       memcpy(state->tris, old, sizeof(fltTriangle) * state->atris / 2);
1103       delete [] old;
1104    }
1105    tri = state->tris + state->ntris++;
1106    memcpy(tri, state->temp, sizeof(fltTriangle));
1107    tri->index[0] = v0;
1108    tri->index[1] = v1;
1109    tri->index[2] = v2;
1110 }
1111 
Triangulate(int * w,int n,fltState * state)1112 static void Triangulate(int *w, int n, fltState *state)
1113 {
1114    int buf[3 * (16 - 2)];
1115    int *tris = (n > 16) ? new int [ 3 * (n - 2) ] : buf;
1116    int num_tris = _ssgTriangulate(state->coord, w, n, tris);
1117    for (int i = 0; i < num_tris; i++)
1118       AddTri(state, tris[3*i + 0], tris[3*i + 1], tris[3*i + 2]);
1119    if (tris != buf)
1120      delete [] tris;
1121 }
1122 
1123 static int ObsoleteFlag;
1124 static int NotImplementedFlag;
1125 
Obsolete(int op)1126 static void Obsolete(int op)
1127 {
1128    if (!ObsoleteFlag) {
1129       ulSetError(UL_WARNING, "[flt] This file is probably rather old (obsolete opcodes ignored).");
1130       ObsoleteFlag = 1;
1131    }
1132    //printf("op %d obsolete\n", op);
1133 }
1134 
NotImplemented(int op)1135 static void NotImplemented(int op)
1136 {
1137    if (!NotImplementedFlag) {
1138       ulSetError(UL_WARNING, "[flt] This file contains opcodes that are not implemented.");
1139       NotImplementedFlag = 1;
1140    }
1141    //printf("op %d not implemented\n", op);
1142 }
1143 
ReportBadChunk(const ubyte * ptr,const char * name)1144 static void ReportBadChunk(const ubyte *ptr, const char *name)
1145 {
1146    int op = get16u(ptr);
1147    int len = get16u(ptr + 2);
1148    ulSetError(UL_WARNING, "[flt] Bad record, opcode %d (%s), length %d:", op, name, len);
1149    hexdump(UL_WARNING, ptr, len, 0);
1150    ulSetError(UL_WARNING, "Please report this, either at http://plib.sourceforge.net/,");
1151    ulSetError(UL_WARNING, "or by email to plib-devel@lists.sourceforge.net. Thanks.");
1152 }
1153 
1154 #define BAD_CHUNK(ptr, name)\
1155    do {\
1156       static int first = 1;\
1157       if (first) {\
1158 	 ReportBadChunk(ptr, name);\
1159 	 first = 0;\
1160       }\
1161    } while (0)
1162 
intcmp(const void * a,const void * b)1163 static int intcmp(const void *a, const void *b)
1164 {
1165    return *(int *)a - *(int *)b;
1166 }
1167 
1168 /* polygon chunks */
GeomChunks(ubyte * ptr0,ubyte * end,fltState * state,ssgEntity ** nodep,int objflags,int objtrans)1169 static int GeomChunks(ubyte *ptr0, ubyte *end, fltState *state, ssgEntity **nodep, int objflags, int objtrans)
1170 {
1171    ubyte *ptr = ptr0;
1172    int sp = 0, op, len, done = 0, triflg = 0;
1173    int w[512]; /* enough? */
1174    fltTriangle tri;
1175    StateInfo info;
1176    int subface = 0;
1177    char long_id[256] = {0};
1178 
1179    state->temp = &tri;
1180    memset(&tri, 0, sizeof(tri));
1181 
1182    /* read as many polygon chunks as possible.
1183     * can be done since objects may not contain groups.
1184     * color table etc should also be defined before any polygon.
1185     * (the purpose is to keep the switch(op) relatively small to speed up this "inner loop")
1186     */
1187 
1188    do {
1189 
1190       if (ptr + 4 > end)
1191          break;
1192       op = get16u(ptr);
1193       len = get16u(ptr+2);
1194       if (len < 4 || (len & 3) != 0 || ptr + len > end)
1195          break;
1196 
1197       switch (op) {
1198 
1199       case 5: { /* Face (appearence) */
1200 
1201          /*
1202           * Face Record Format
1203           *
1204           * Int         0  2  Face Opcode 5
1205           * Unsigned    2  2  Length of the record
1206           * Char        4  8  7 char ASCII ID; 0 terminates
1207           * Int        12  4  IR color code
1208           * Int        16  2  Relative priority
1209           * Int        18  1  Draw type
1210           *                      0 = Draw solid with backface culling
1211           *                      1 = Draw solid, no backface culling
1212           *                      2 = Draw wireframe
1213           *                      3 = Draw wireframe and close
1214           *                      4 = Surround with wireframe in alternate color
1215           *                      8 = Omnidirectional light
1216           *                      9 = Unidirectional light
1217           *                      10 = Bidirectional light
1218           * Int        19  1  Texture white = if TRUE, draw textured face white
1219           * Unsigned   20  2  Color name index
1220           * Unsigned   22  2  Alternate color name index
1221           * Int        24  1  Reserved
1222           * Int        25  1  Template (billboard)
1223           *                      0 = Fixed, no alpha blending
1224           *                      1 = Fixed, alpha blending
1225           *                      2 = Axial rotate
1226           *                      4 = Point rotate
1227           * Int        26  2  Detail texture pattern index, -1 if none
1228           * Int        28  2  Texture pattern index, -1 if none
1229           * Int        30  2  Material index, -1 if none
1230           * Int        32  2  Surface material code (for DFAD)
1231           * Int        34  2  Feature ID (for DFAD)
1232           * Int        36  4  IR material code
1233           * Unsigned   40  2  Transparency 0 = Opaque 65535 = Totally clear
1234           * Unsigned   42  1  LOD generation control
1235           * Unsigned   43  1  Line style index
1236           * Boolean    44  4  Flags (bits from left to right)
1237           *                      0 = Terrain
1238           *                      1 = No color
1239           *                      2 = No alternate color
1240           *                      3 = Packed color
1241           *                      4 = Terrain culture cutout (footprint)
1242           *                      5 = Hidden, not drawn
1243           *                      6-31 = Spare
1244           * Unsigned   48  1  Light mode
1245           *                      0 = Use face color, not illuminated
1246           *                      1 = Use vertex colors, not illuminated
1247           *                      2 = Use face color and vertex normal
1248           *                      3 = Use vertex color and vertex normal
1249           * Unsigned   49  1  Reserved
1250           * Unsigned   50  2  Reserved
1251           * Boolean    52  4  Reserved
1252           * Unsigned   56  4  Packed color, primary (A, B, G, R)
1253           * Unsigned   60  4  Packed color, alternate (A, B, G, R)
1254           * Int        64  2  Texture mapping index
1255           * Int        66  2  Reserved
1256           * Unsigned   68  4  Primary color index
1257           * Unsigned   72  4  Alternate color index
1258           * Int        76  2  Reserved
1259           * Int        78  2  Reserved
1260           *
1261           */
1262 
1263 	 static float default_mtl[14] = {
1264 	    1.0f, 1.0f, 1.0f,
1265 	    1.0f, 1.0f, 1.0f,
1266 	    0.0f, 0.0f, 0.0f,
1267 	    0.0f, 0.0f, 0.0f,
1268 	    8.0f, 1.0f
1269 	 };
1270          int flags = len < 48 ? 0 : get32i(ptr + 44);
1271 	 int drawtype = ptr[18];
1272 
1273          if (drawtype > 4 || (flags & (1 << 5)) || len < 32) {
1274             triflg = 0;
1275          }
1276          else {
1277             int index;
1278 	    struct snode *t;
1279 	    int tex_alpha = 0;
1280 
1281 	    tri.state = 0;
1282 	    tri.flags = 0;
1283 
1284 #ifdef NO_TEXTURES
1285 	    info.tex = 0;
1286 #else
1287             /* texture */
1288 	    info.tex = 0;
1289             index = get16i(ptr + 28); /* texture index */
1290 	    t = 0;
1291 	    if (index != -1) {
1292 	       state->texs = t = splay(state->texs, (void *)index, ptrcmp);
1293 	       if (t == 0 || t->key != (void *)index) {
1294 		  /*ulSetError(UL_DEBUG, "[flt] undefined texture %d", index);*/
1295 		  t = 0;
1296 	       }
1297 	    }
1298 	    if (t) {
1299 	       fltTexture *tex = (fltTexture *)t->data;
1300 	       if (tex->state == (ssgState *)-1) {
1301 		  fltTexture *tmp = LoadTex(tex->file);
1302 		  tex->state = tmp->state;
1303 		  tex->tex = tmp->tex;
1304 		  tex->alpha = tmp->alpha;
1305 	       }
1306 	       tri.state = tex->state;
1307 	       info.tex = tex->tex;
1308 	       tex_alpha = tex->alpha;
1309 	    }
1310 #ifndef NO_LOADER_OPTIONS
1311 	    else {
1312 	       if (state->notex_state == (ssgState *)-1)
1313 		  state->notex_state = LoaderOptions->createState(0);
1314 	       tri.state = state->notex_state;
1315 	    }
1316 #endif
1317 #endif
1318 
1319 	    if (tri.state) {
1320 
1321 	       tri.bind = BIND_COLOR | BIND_NORMAL | BIND_TEXCOORD;
1322 
1323 	    }
1324 	    else {
1325 
1326 	       int template = ptr[25];
1327 	       int white = ptr[19] || template > 1; /* OK ?? */
1328 	       int lmode = len >= 49 ? ptr[48] : 3;
1329 	       int trans = get16u(ptr + 40);
1330 
1331 	       //ulSetError(UL_DEBUG, "light mode %d", lmode);
1332 
1333 	       /*lmode = 0;*/
1334 
1335 	       /* wireframe */
1336 	       /*tri.wireframe = (drawtype > 1);*/
1337 
1338 	       /* backface culling */
1339 	       info.cf = (drawtype == 0);
1340 
1341 	       /* alpha component */
1342 #if 0
1343 	       if (state->major >= 15) {
1344 		  /* this is according to the spec, but it sure is suspicious */
1345 		  int a = trans >> 1;
1346 		  int b = objtrans >> 1;
1347 		  info.alpha = 1.0f - 1.0f/(32767*32767) * (a * b);
1348 	       }
1349 	       else
1350 #endif
1351                {
1352 		  info.alpha = 1.0f - 1.0f/65535.0f * trans;
1353 	       }
1354 	       sgSetVec4(tri.color, 1, 1, 1, info.alpha);
1355 
1356 #ifdef NO_LIGHTING
1357 	       info.mtl = 0;
1358 #else
1359 	       /* material */
1360 	       if (/*lmode < 2 ||*/ /* (objflags & (1 << 3)) || */ white) {
1361 		  info.mtl = 0;
1362 	       }
1363 	       else {
1364 		  index = get16i(ptr + 30); /* material index */
1365 		  state->mtls = t = splay(state->mtls, (void *)index, ptrcmp);
1366 		  if (t && t->key == (void *)index) {
1367 		     info.mtl = (float *)t->data;
1368 		  }
1369 		  else {
1370 		     info.mtl = default_mtl;
1371 		  }
1372 		  info.alpha *= info.mtl[13];
1373 		  tri.color[3] = 1.0f;
1374 	       }
1375 #endif
1376 
1377 	       /* transparency */
1378 	       info.tr = (tex_alpha > 0 || info.alpha < 0.999f); /* && template > 0 */
1379 	       if (info.tr)
1380 		  tri.flags |= TRI_TRANSLUCENT;
1381 
1382 	       /* initial bindings */
1383 	       tri.bind = 0;
1384 	       if ((lmode & 1) && !white)
1385 		  tri.bind |= BIND_COLOR;
1386 	       if (info.mtl) {
1387 		  tri.bind |= BIND_NORMAL;
1388 		  if (!(lmode & 2) || (objflags & (1 << 4)))
1389 		     tri.bind |= BIND_FLAT_NORMAL;
1390 	       }
1391 	       if (info.tex)
1392 		  tri.bind |= BIND_TEXCOORD;
1393 
1394 #ifdef NO_COLORS
1395 	       tri.bind &= ~BIND_COLOR;
1396 #else
1397 
1398 	       /* face color */
1399 	       if (!(lmode & 1) && !(flags & 2) && !white && state->major >= 14) { /* will probably not work with old files */
1400 		  if ((flags & 8) && len >= 60) {
1401 		     UNPACK_ABGR(tri.color, ptr + 56); /* packed ABGR */
1402 		     tri.bind |= BIND_FLAT_COLOR;
1403 		  }
1404 		  else if (state->revision > 1400) {
1405 		     int color;
1406 		     if (state->revision > 1500 && len >= 72)
1407 			color = get32i(ptr + 68);
1408 		     else {
1409 			color = get16u(ptr + 20);
1410 			if (color == 65535)
1411 			   color = -1;
1412 		     }
1413 		     int index = color / 128;
1414 		     int intensity = color % 128;
1415 		     if (color >= 0 && state->ctab && index < state->cnum) {
1416 			UNPACK_ABGR2(tri.color, state->ctab[index], intensity);
1417 			tri.bind |= BIND_FLAT_COLOR;
1418 		     }
1419 		     else if (color != -1)
1420 			ulSetError(UL_DEBUG, "[flt] Bad face color %d.", color);
1421 		  }
1422 		  tri.color[3] = info.alpha;
1423 	       }
1424 #endif
1425 
1426 	       /*
1427 		 if (tri.bind & BIND_COLOR)
1428 		   ulSetError(UL_DEBUG, "use vertex colors");
1429 		 if (tri.bind & BIND_FLAT_COLOR)
1430 		   ulSetError(UL_DEBUG, "face color %.2f %.2f %.2f",
1431 			      tri.color[0], tri.color[1], tri.color[2]);
1432 	        */
1433 
1434 	       /* billboard */
1435 	       if (template == 4)
1436 		  tri.flags |= TRI_BBOARD_POINT;
1437 	       else if (template == 2)
1438 		  tri.flags |= TRI_BBOARD_AXIAL;
1439 
1440 	       /* cannot create the state yet,
1441 		* need to know the vertex bindings. */
1442 	    }
1443 
1444             triflg = 1;
1445          }
1446          ptr += len;
1447          break;
1448       }
1449 
1450       case 72: /* Vertex List (aka polygon) */
1451          if (triflg) {
1452             int i, n = (len - 4) >> 2;
1453             if (state->vtab && n > 2 && n < 512) { /* silently ignore if suspicious.. */
1454 	       int bind = tri.bind;
1455                ubyte *p = ptr + 4;
1456                for (i = 0; i < n; ++i) {
1457 		  /* could this be done any faster? */
1458 		  /* it is tempting to reparse the vertex at the given offset */
1459                   int offset = get32i(p), *ptr;
1460 		  ptr = (int *)bsearch(&offset, state->offset, state->vnum,
1461 				       sizeof(int), intcmp);
1462                   if (!ptr) {
1463 		     ulSetError(UL_DEBUG, "[flt] Bad vertex offset %i.", offset);
1464 		     break;
1465 		  }
1466                   w[i] = ptr - state->offset;
1467 		  bind &= state->bind[w[i]] | BIND_FLAT;
1468                   p += 4;
1469                }
1470                if (i == n) {
1471 
1472 		  tri.bind = bind;
1473 
1474 		  if (subface)
1475 		     tri.flags |= TRI_SUBFACE;
1476 		  else
1477 		     tri.flags &= ~TRI_SUBFACE;
1478 
1479 		  if (tri.state) {
1480 
1481 		     Triangulate(w, n, state);
1482 
1483 		  }
1484 		  else {
1485 		     /* finalize state */
1486 
1487 		     /* setup color material */
1488 		     if ((bind & (BIND_COLOR | BIND_FLAT_COLOR)) &&
1489 			 (bind & (BIND_NORMAL | BIND_FLAT_NORMAL))) {
1490 			sgVec4 color;
1491 			color[0] = 0.2f*info.mtl[0] + 0.8f*info.mtl[3];
1492 			color[1] = 0.2f*info.mtl[1] + 0.8f*info.mtl[4];
1493 			color[2] = 0.2f*info.mtl[2] + 0.8f*info.mtl[5];
1494 			color[3] = info.alpha;
1495  			if ((tri.bind & BIND_FLAT_COLOR)) {
1496 			   tri.color[0] *= color[0];
1497 			   tri.color[1] *= color[1];
1498 			   tri.color[2] *= color[2];
1499 			   tri.color[3] *= color[3];
1500 			}
1501 			else {
1502 			   sgCopyVec4(tri.color, color); /* apply to vertex colors */
1503 			}
1504 			info.cm = 1;
1505 			tri.flags |= TRI_COLOR_MATERIAL;
1506 		     }
1507 		     else {
1508 			info.cm = 0;
1509 			tri.flags &= ~TRI_COLOR_MATERIAL;
1510 		     }
1511 
1512 		     tri.state = ConstructState(&info);
1513 
1514 		     Triangulate(w, n, state);
1515 
1516 		     tri.state = 0;
1517 		  }
1518                }
1519             }
1520          }
1521          ptr += len;
1522          break;
1523 
1524       case 89: /* Morph Vertex List */
1525          ptr += len;
1526          break;
1527 
1528       case 10: /* Push */
1529          sp++;
1530          ptr += len;
1531          break;
1532 
1533       case 11: /* Pop */
1534          if (sp == 0) {
1535             done = 1;
1536             break;
1537          }
1538          sp--;
1539          ptr += len;
1540          /*if (sp == 0)
1541 	   done = 1;*/
1542          break;
1543 
1544       case 19: /* Push Subface */
1545 	 subface++;
1546          ptr += len;
1547          break;
1548 
1549       case 20: /* Pop Subface */
1550 	 subface--;
1551          ptr += len;
1552          break;
1553 
1554       case 33: /* Long ID */
1555          if (long_id[0] == 0) {
1556             int n = CLAMP(len - 4, 0, 255);
1557             memcpy(long_id, ptr + 4, n);
1558             long_id[n] = 0;
1559          }
1560          ptr += len;
1561          break;
1562 
1563       case 31: /* Text Comment */
1564       case 50: /* Vector (for light points) */
1565       case 21: /* Push Extension */
1566       case 22: /* Pop Extension */
1567       case 97: /* Line Style Record */
1568       case 122: /* Push Attribute */
1569       case 123: /* Pop Attribute */
1570          ptr += len;
1571          break;
1572 
1573       case 6: /* Vertex with ID (obsolete) */
1574       case 7: /* Short Vertex (obsolete) */
1575       case 8: /* Vertex with Color (obsolete) */
1576       case 9: /* Vertex with Color and Normal (obsolete) */
1577 	 Obsolete(op);
1578 	 ptr += len;
1579 	 break;
1580 
1581       default:
1582          if (sp == 0) { /* you never know what this might be. better let someone else take car of it. */
1583             done = 1;
1584             break;
1585          }
1586 	 NotImplemented(op);
1587          ptr += len;
1588       }
1589 
1590    } while (!done);
1591 
1592    *nodep = Build(state);
1593 
1594    if (long_id[0] != 0 && *nodep != NULL)
1595      (*nodep)->setName(long_id);
1596 
1597    return ptr - ptr0;
1598 }
1599 
1600 struct LODInfo {
1601    ssgTransform *scs;
1602    ssgRangeSelector *lod;
1603 };
1604 
LODCompare(const void * a,const void * b)1605 static int LODCompare(const void *a, const void *b)
1606 {
1607    float d = ((LODInfo *)a)->lod->getRange(0) - ((LODInfo *)b)->lod->getRange(0);
1608    return d < 0 ? -1 : d > 0 ? 1 : 0;
1609 }
1610 
MergeLODs(ssgBranch * grp)1611 static void MergeLODs(ssgBranch *grp)
1612 {
1613    LODInfo info[64];
1614    int i, j, k, m, n;
1615 
1616    n = grp->getNumKids();
1617    if (n <= 1)
1618       return;
1619 
1620    m = 0;
1621    for (i = 0; i < n && m < 64; i++) {
1622       ssgEntity *kid;
1623       kid = grp->getKid(i);
1624       info[m].scs = 0;
1625       if (kid->isA(ssgTypeTransform()) && kid->getNumParents() == 1) {
1626 	 info[m].scs = (ssgTransform *)kid;
1627 	 if (info[m].scs->getNumKids() != 1)
1628 	    continue;
1629 	 kid = info[m].scs->getKid(0);
1630       }
1631       if (!kid->isA(ssgTypeRangeSelector()) || kid->getNumParents() != 1)
1632 	 continue;
1633       info[m].lod = (ssgRangeSelector *)kid;
1634       m++;
1635    }
1636 
1637    if (m > 1) {
1638 
1639       qsort(info, m, sizeof(info[0]), LODCompare);
1640 
1641       //grp->print();
1642 
1643       for (i = 0; i < m; i++) {
1644 	 sgMat4 mat1, mat2;
1645 	 float ranges[33], range2;
1646 	 int num1, num2;
1647 	 int flag = 0;
1648 
1649 	 if (info[i].lod == 0)
1650 	    continue;
1651 
1652 	 if (info[i].scs)
1653 	    info[i].scs->getTransform(mat1);
1654 	 else
1655 	    sgMakeIdentMat4(mat1);
1656 	 num1 = info[i].lod->getNumKids();
1657 	 for (k = 0; k <= num1; k++)
1658 	    ranges[k] = info[i].lod->getRange(k);
1659 
1660 	 for (j = i + 1; j < m; j++) {
1661 
1662 	    if (info[j].lod == 0)
1663 	       continue;
1664 
1665 	    if (info[j].scs)
1666 	       info[j].scs->getTransform(mat2);
1667 	    else
1668 	       sgMakeIdentMat4(mat2);
1669 	    num2 = info[j].lod->getNumKids();
1670 	    range2 = info[j].lod->getRange(0);
1671 
1672 	    if (sgDistanceVec3(mat1[3], mat2[3]) > 0.1f * range2) /* XXX */
1673 	       continue;
1674 	    if (num1 + num2 > 32) /* XXX */
1675 	       continue;
1676 	    if (ABS(ranges[num1] - range2) > 0.1f * range2) /* XXX */
1677 	       continue;
1678 
1679 	    for (k = 0; k < num2; k++) {
1680 	       info[i].lod->addKid(info[j].lod->getKid(k));
1681 	       ranges[num1 + k + 1] = info[j].lod->getRange(k + 1);
1682 	       num1++;
1683 	    }
1684 
1685 	    if (info[j].scs == 0 || info[j].scs->getRef() == 1) {
1686 	       if (info[j].lod->getRef() == 1) {
1687 		  while (num2--)
1688 		     info[j].lod->removeKid(num2);
1689 	       }
1690 	       if (info[j].scs)
1691 		  info[j].scs->removeKid(info[j].lod); // delete info[j].lod
1692 	       else
1693 		  grp->removeKid(info[j].lod);
1694 	    }
1695 	    if (info[j].scs)
1696 	       grp->removeKid(info[j].scs); // delete info[j].scs
1697 
1698 	    info[j].lod = 0;
1699 	    flag = 1;
1700 	 }
1701 
1702 	 if (flag) {
1703 	    info[i].lod->setRanges(ranges, num1 + 1);
1704 	    assert(info[i].scs == 0 || !info[i].scs->isA(0xDeadBeef));
1705 	    assert(!info[i].lod->isA(0xDeadBeef));
1706 	 }
1707       }
1708    }
1709 }
1710 
PostClean(ssgEntity * node,fltNodeAttr * attr)1711 static ssgEntity *PostClean(ssgEntity *node, fltNodeAttr *attr)
1712 {
1713 
1714   if (node && attr && attr->name)
1715     node->setName(attr->name);
1716 
1717 #if 1
1718    /* remove empty or redundant groups */
1719    while (!NoClean && node && node->isA(ssgTypeBranch())) {
1720       ssgBranch *grp = (ssgBranch *)node;
1721       int num = grp->getNumKids();
1722       if (num > 1)
1723 	 break;
1724       if (num == 1) {
1725 	 ssgEntity *kid = grp->getKid(0);
1726 	 if (grp->getName()) {
1727 	    if (kid->getName())
1728 	       break;
1729 	    kid->setName(grp->getName());
1730 	 }
1731 	 if (grp->getRef() == 0) {
1732 	    kid->ref();
1733 	    grp->removeKid(0);
1734 	    kid->deRef();
1735 	    delete grp;
1736 	 }
1737 	 node = kid;
1738 	 assert(!node->isA(0xDeadBeef));
1739       }
1740       else {
1741 	 if (grp->getRef() == 0)
1742 	    delete grp;
1743 	 node = 0;
1744       }
1745    }
1746 #endif
1747 
1748 #if 1
1749    /* see if we can merge LOD nodes */
1750    if (node && node->isAKindOf(ssgTypeBranch()) &&
1751        !node->isAKindOf(ssgTypeSelector())) {
1752       MergeLODs((ssgBranch *)node);
1753       assert(!node->isA(0xDeadBeef));
1754    }
1755 #endif
1756 
1757    /* set limits on animated nodes */
1758    if (node && node->isA(ssgTypeTimedSelector())) {
1759       ssgTimedSelector *sw = (ssgTimedSelector *) node;
1760       if (sw->getNumKids() > 1) {
1761 	 sw->setDuration(30.0f);
1762 	 sw->setLimits(0, sw->getNumKids() - 1);
1763 	 sw->control(SSG_ANIM_START);
1764       }
1765    }
1766 
1767    /* apply node attributes */
1768    if (node && attr) {
1769 
1770       if (attr->transform) {
1771 
1772 	 ssgTransform *scs = new ssgTransform;
1773 	 scs->setTransform(attr->mat);
1774 	 scs->addKid(node);
1775 
1776 	 if (attr->replicate > 0) {
1777 	    ssgBranch *grp;
1778 	    sgMat4 mat;
1779 	    int i;
1780 	    grp = new ssgBranch;
1781 	    grp->addKid(scs);
1782 	    sgCopyMat4(mat, attr->mat);
1783 #if 0
1784 	    ulSetError(UL_DEBUG, "replicating %d times", attr->replicate);
1785 	    for (i = 0; i < 4; i++)
1786 	       ulSetError(UL_DEBUG, "  %6.2f %6.2f %6.2f %6.2f", mat[i][0], mat[i][1], mat[i][2], mat[i][3]);
1787 #endif
1788 	    for (i = 0; i < attr->replicate; ++i) {
1789 	       sgPostMultMat4(mat, attr->mat);
1790 	       scs = new ssgTransform;
1791 	       scs->setTransform(mat);
1792 	       scs->addKid(node);
1793 	       grp->addKid(scs);
1794 	    }
1795 	    node = grp; /* there's no point in cleaning this construction */
1796 	    /*ulSetError(UL_DEBUG, "[flt] replicated %d times", attr->replicate);*/
1797 	 }
1798 	 else {
1799 	    node = scs; // PostClean(scs, 0);
1800 	    /*ulSetError(UL_DEBUG, "[flt] added transformation");*/
1801 	 }
1802       }
1803 
1804       /* apply level of detail */
1805       if (attr->islod) {
1806 	 float ranges[2];
1807 	 ranges[0] = MIN(attr->range[0], attr->range[1]);
1808 	 ranges[1] = MAX(attr->range[0], attr->range[1]);
1809 	 if (ranges[1] > MAX(0, ranges[0])) {
1810 	    ssgRangeSelector *lod = new ssgRangeSelector;
1811 	    lod->setRanges(ranges, 2);
1812 
1813 	    if (sgLengthVec3(attr->center) > 0.01f) { /* XXX */
1814 	       ssgTransform *t1, *t2;
1815 	       sgMat4 mat;
1816 	       sgMakeTransMat4(mat, attr->center[0], attr->center[1], attr->center[2]);
1817 	       t1 = new ssgTransform;
1818 	       t1->setTransform(mat);
1819 	       sgMakeTransMat4(mat, -attr->center[0], -attr->center[1], -attr->center[2]);
1820 	       t2 = new ssgTransform;
1821 	       t2->setTransform(mat);
1822 	       t1->addKid(lod);
1823 	       lod->addKid(t2);
1824 	       t2->addKid(node);
1825 	       node = t1;
1826 	    }
1827 	    else {
1828 	       lod->addKid(node);
1829 	       node = lod;
1830 	    }
1831 	 }
1832       }
1833 
1834       /* setup switch records */
1835       if (attr->num_masks > 0) {
1836 	ssgTimedSelector *sw = new ssgTimedSelector;
1837 	int n = ((ssgBranch *) node) -> getNumKids();
1838 	if (n > 32 * attr->num_words) n = 32 * attr->num_words;
1839 	for (int i = 0; i < attr->num_masks; i++) {
1840 	  ssgBranch *br = new ssgBranch;
1841 	  for (int j = 0; j < n; j++) {
1842 	    if (attr->mask_words[j / 32] & (1u << (j % 32)))
1843 	      br -> addKid(((ssgBranch *) node) -> getKid(j));
1844 	  }
1845 	  sw -> addKid(br);
1846 	}
1847 	if (node->getRef() == 0) {
1848 	  ((ssgBranch *) node) -> removeAllKids();
1849 	  delete node;
1850 	}
1851 	sw->setMode(SSG_ANIM_SHUTTLE);
1852 	sw->setDuration(30.0f);
1853 	sw->setLimits(0, attr->num_masks - 1);
1854 	sw->control(SSG_ANIM_START);
1855 	node = sw;
1856       }
1857    }
1858 
1859    if (attr)
1860       delete attr;
1861 
1862    assert(node == 0 || !node->isA(0xDeadBeef));
1863 
1864    return node;
1865 }
1866 
1867 /* link nodes while removing crap (post traversal) */
PostLink(ssgEntity ** stack,fltNodeAttr ** attr,int instance,fltState * state)1868 static void PostLink(ssgEntity **stack, fltNodeAttr **attr,
1869 		     int instance, fltState *state)
1870 {
1871 #if 0
1872    ulSetError(UL_DEBUG, "PostLink: %s %s <-- %s %s",
1873            stack[0] ? pfGetTypeName(stack[0]) : "0", stack[0] ? pfGetNodeName(stack[0]) : "0",
1874            stack[1] ? pfGetTypeName(stack[1]) : "0", stack[1] ? pfGetNodeName(stack[1]) : "0");
1875 #endif
1876 
1877    if (stack[1] == 0) {
1878       if (attr[1]) {
1879          delete attr[1];
1880 	 attr[1] = 0;
1881       }
1882       return;
1883    }
1884    assert(!stack[1]->isA(0xDeadBeef));
1885 
1886    stack[1] = PostClean(stack[1], attr[1]);
1887 
1888    if (stack[1] && instance >= 0) {
1889        state->refs = sinsert(state->refs, (void *)instance, 0, ptrcmp);
1890        if (state->refs->data != (void *)-1) {
1891 	   ulSetError(UL_WARNING, "[flt] Instance %d redefined.", instance);
1892 	   ssgDeRefDelete((ssgEntity *) state->refs->data);
1893        }
1894        state->refs->data = stack[1];
1895        stack[1]->ref();
1896    }
1897 
1898    if (stack[0] == 0) {
1899       stack[0] = stack[1];
1900       if (attr[0]) {
1901 	  delete attr[0];
1902 	  attr[0] = 0;
1903       }
1904    }
1905    else {
1906       assert(!stack[0]->isA(0xDeadBeef));
1907       if (stack[1]) {
1908          if (stack[0]->isAKindOf(ssgTypeBranch())) {
1909 	    ((ssgBranch *)stack[0])->addKid(stack[1]);
1910 	 }
1911 	 else {
1912             ssgBranch *grp = new ssgBranch;
1913             grp->addKid(stack[0]);
1914             grp->addKid(stack[1]);
1915             stack[0] = PostClean(grp, 0);
1916          }
1917       }
1918    }
1919 
1920    stack[1] = 0;
1921    attr[1] = 0;
1922 }
1923 
1924 /* group/object ancillary chunks */
AttrChunks(ubyte * ptr0,ubyte * end,fltNodeAttr ** attrp)1925 static int AttrChunks(ubyte *ptr0, ubyte *end, fltNodeAttr **attrp)
1926 {
1927    ubyte *ptr = ptr0;
1928    int op, len, done = 0;
1929    fltNodeAttr *attr;
1930 
1931    attr = *attrp;
1932 
1933    while (!done) {
1934 
1935       if (ptr + 4 > end)
1936          break;
1937       op = get16u(ptr);
1938       len = get16u(ptr + 2);
1939       if (len < 4 || (len & 3) != 0 || ptr + len > end)
1940          break;
1941 
1942       switch (op) {
1943 
1944       case 31: /* Comment */
1945          ptr += len;
1946          break;
1947 
1948       case 33: { /* Long ID */
1949 	 int n = len - 4;
1950 	 if (n > 0 && n < 256) {
1951 	    if (attr == 0)
1952 	       attr = new fltNodeAttr;
1953 	    //attr->name = (char *)malloc(n + 1);
1954 	    attr->name = new char[n + 1];
1955 	    memcpy(attr->name, ptr + 4, n);
1956 	    attr->name[n] = 0;
1957 	 }
1958          ptr += len;
1959          break;
1960       }
1961 
1962       case 60: { /* Replicate */
1963 	 if (attr == 0)
1964 	    attr = new fltNodeAttr;
1965 	 attr->replicate = get16u(ptr + 4);
1966          ptr += len;
1967          break;
1968       }
1969 
1970       case 49: { /* Transfomation Matrix */
1971 	 sgMat4 mat;
1972 	 int i, j;
1973 	 get32v(ptr + 4, mat, 16);
1974 	 for (i = 0; i < 4; i++) {
1975 	    for (j = 0; j < 4; j++) {
1976 	       float d = mat[i][j] - (i == j ? 1.0f : 0.0f);
1977 	       if (ABS(d) > 0.001f)
1978 		  break;
1979 	    }
1980 	    if (j < 4)
1981 	       break;
1982 	 }
1983 	 if (i < 4) {
1984 	    if (attr == 0)
1985 	       attr = new fltNodeAttr;
1986 	    attr->transform = 1;
1987 	    sgCopyMat4(attr->mat, mat);
1988 	 }
1989          ptr += len;
1990          break;
1991       }
1992 
1993       case 12: /* Translate (obsolete) */
1994       case 40: /* Translate (obsolete) */
1995       case 41: /* Rotate about Point (obsolete) */
1996       case 42: /* Rotate about Edge (obsolete) */
1997       case 43: /* Scale (obsolete) */
1998       case 44: /* Translate (obsolete) */
1999       case 45: /* Scale (obsolete) */
2000       case 46: /* Rotate about Point (obsolete) */
2001       case 47: /* Rotate and/or Scale about Point (obsolete) */
2002       case 48: /* Put Transform (obsolete) */
2003       case 51: /* Bounding Box (obsolete) */
2004       case 77: /* Scale (obsolete) */
2005       case 110: /* Histogram Bounding Volume (obsolete) */
2006 	 Obsolete(op);
2007 	 ptr += len;
2008 	 break;
2009 
2010       case 74: /* Bounding Box */
2011       case 76: /* Rotate about Edge */
2012       case 78: /* Translate */
2013       case 79: /* Scale */
2014       case 80: /* Rotate about Point */
2015       case 81: /* Rotate and/or Scale */
2016       case 82: /* Put */
2017       case 88: /* Road Zone */
2018       case 94: /* General Matrix */
2019       case 100: /* Extension Attribute */
2020       case 105: /* Bounding Sphere */
2021       case 106: /* Bounding Cylinder */
2022       case 108: /* Bounding Volume Center */
2023       case 109: /* Bounding Volume Orientation */
2024       case 116: /* CAT Data */
2025 	 /* these are safe to ignore */
2026          ptr += len;
2027          break;
2028 
2029       default:
2030          done = 1;
2031          break;
2032       }
2033    }
2034 
2035    *attrp = attr;
2036 
2037    return ptr - ptr0;
2038 }
2039 
2040 static ssgEntity *LoadFLT(const char *path);
2041 
2042 /* object hierarchy chunks */
HierChunks(ubyte * ptr,ubyte * end,fltState * state)2043 static ssgEntity *HierChunks(ubyte *ptr, ubyte *end, fltState *state)
2044 {
2045    ssgEntity *stack[MAXDEPTH + 1];
2046    fltNodeAttr *attr[MAXDEPTH + 1];
2047    int instance[MAXDEPTH + 1];
2048    int sp, op, len, k;
2049 
2050    stack[0] = new ssgBranch;
2051    stack[0]->setName("reserved");
2052    attr[0] = 0;
2053    instance[0] = -1;
2054    stack[1] = 0;
2055    attr[1] = 0;
2056    instance[1] = -1;
2057    sp = 1;
2058 
2059    for (;;) {
2060 
2061       if (ptr + 4 > end)
2062          break;
2063       op = get16u(ptr);
2064       if (op < 1 || op > 150)
2065          break;
2066       len = get16u(ptr + 2);
2067       if (len < 4 || (len & 3) != 0 || ptr + len > end)
2068          break;
2069 
2070 #if 0
2071       for (int i = 0; i < sp; i++)
2072 	  putchar('\t');
2073       printf("op %d\n", op);
2074 #endif
2075 
2076       switch (op) {
2077 
2078       case 10: /* Push */
2079          if (stack[sp] && !stack[sp]->isAKindOf(ssgTypeBranch())) {
2080             /* shouldn't happen */
2081             ulSetError(UL_DEBUG, "[flt] Objects are not allowed to contain other objects or groups.");
2082             PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2083 	    instance[sp] = -1;
2084          }
2085 	 if (sp >= MAXDEPTH) {
2086 	    ulSetError(UL_WARNING, "[flt] Stack overflow.");
2087 	 }
2088 	 else {
2089 	    sp++;
2090 	    stack[sp] = 0;
2091 	    attr[sp] = 0;
2092 	    instance[sp] = -1;
2093 	 }
2094 	 ptr += len;
2095          break;
2096 
2097       case 11: /* Pop */
2098          if (sp == 1)
2099             ulSetError(UL_WARNING, "[flt] Stack underflow.");
2100          else {
2101             PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2102             sp--;
2103          }
2104          ptr += len;
2105          break;
2106 
2107       case 4: { /* Object */
2108 
2109          /*
2110           * Object Record Format
2111           *
2112           * Int        0  2  Object Opcode 4
2113           * Unsigned   2  2  Length of the record
2114           * Char       4  8  7 char ASCII ID; 0 terminates
2115           * Boolean   12  4  Flags (bits from to right)
2116           *                     0 = Don't display in daylight
2117           *                     1 = Don't display at dusk
2118           *                     2 = Don't display at night
2119           *                     3 = Don't illuminate
2120           *                     4 = Flat shaded
2121           *                     5 = Group's shadow object
2122           *                     6-31 = Spare
2123           * Int       16  2  Relative priority
2124           * Unsigned  18  2  Transparency
2125           *                     0 = Opaque
2126           *                     65535 = Totally clear
2127           * Int       20  2  Special effect ID1 - application defined
2128           * Int       22  2  Special effect ID2 - application defined
2129           * Int       24  2  Significance
2130           * Int       26  2  Spare
2131           *
2132           */
2133 
2134 	 int flags = get32i(ptr + 12);
2135 	 int trans = get16u(ptr + 18);
2136          PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2137 	 instance[sp] = -1;
2138          ptr += len;
2139          ptr += AttrChunks(ptr, end, &attr[sp]);
2140 	 state->parent_name = (char *)ptr + 4; /* OK?? */
2141          ptr += GeomChunks(ptr, end, state, &stack[sp], flags, trans);
2142 	 state->parent_name = 0;
2143 	 if (stack[sp] && stack[sp]->getName() == 0 && ptr[4])
2144 	    stack[sp]->setName((char *)ptr + 4);
2145          break;
2146       }
2147 
2148       case 5: /* Face */
2149          /* polygons are not allowed to be outside objects, but this rule is not always respected */
2150 	 //ulSetError(UL_DEBUG, "[flt] Implicit object.");
2151          PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2152 	 instance[sp] = -1;
2153          ptr += GeomChunks(ptr, end, state, &stack[sp], 0, 0);
2154          break;
2155 
2156       case 2: /* Group */
2157       case 14: /* Degree of Freedom */
2158       case 73: /* Level of Detail */
2159       case 96: /* Switch */
2160       case 98: /* Clip Region */
2161 
2162          PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2163 	 instance[sp] = -1;
2164 
2165 	 switch (op) {
2166 
2167 	 case 2: { /* Group */
2168 #if 0 /* group animation - seems wrong... */
2169 	    int flags = (len >= 20) ? get32i(ptr + 16) : 0;
2170 	    if ((flags & 3) != 0) {
2171 	       ssgTimedSelector *sw = new ssgTimedSelector;
2172 	       sw->setMode((flags & 2) ? SSG_ANIM_SWING : SSG_ANIM_SHUTTLE);
2173 	       stack[sp] = sw;
2174 	    }
2175 	    else
2176 #endif
2177             {
2178 	       stack[sp] = new ssgBranch;
2179 	    }
2180 	    break;
2181 	 }
2182 
2183 	 case 14: { /* Degree of Freedom */
2184 	    stack[sp] = new ssgTransform;
2185 	    break;
2186 	 }
2187 
2188 	 case 73: { /* Level of Detail */
2189 	    fltNodeAttr *a;
2190 	    double v[3];
2191 	    attr[sp] = a = new fltNodeAttr;
2192 	    a->islod = 1;
2193 	    get64v(ptr + 16, v, 2);
2194 	    sgSetVec2(a->range, (float)v[0], (float)v[1]);
2195 	    get64v(ptr + 40, v, 3);
2196 	    sgSetVec3(a->center, (float)v[0], (float)v[1], (float)v[2]);
2197             stack[sp] = new ssgBranch;
2198 	    break;
2199 	 }
2200 
2201 	 case 96: { /* Switch */
2202 	    int num_words = (len > 28) ? get32i(ptr + 20) : -1;
2203 	    int num_masks = (len > 28) ? get32i(ptr + 24) : -1;
2204 	    if (num_words <= 0 || num_masks <= 0 || len < 28 + 4 * num_words * num_masks) {
2205  	       ulSetError(UL_DEBUG, "[flt] Incomplete switch record.");
2206 	    }
2207 	    else {
2208  	       fltNodeAttr *a = new fltNodeAttr;
2209 	       a->current_mask = get32i(ptr + 16);
2210 	       a->num_masks = num_masks;
2211 	       a->num_words = num_words;
2212 	       a->mask_words = new uint [ num_masks * num_words ];
2213 	       get32v(ptr + 28, a->mask_words, num_masks * num_words);
2214 	       attr[sp] = a;
2215 	    }
2216 	    stack[sp] = new ssgBranch;
2217 	    break;
2218 	 }
2219 
2220 	 default: { /* Others (i.e. 98 Clip Region) */
2221 	    stack[sp] = new ssgBranch;
2222 	    break;
2223 	 }
2224 
2225          }
2226 
2227 	 if (ptr[4])
2228 	    stack[sp]->setName((char *)ptr + 4);
2229 
2230          ptr += len;
2231          ptr += AttrChunks(ptr, end, &attr[sp]);
2232 
2233          break;
2234 
2235       case 61: /* Instance Reference */
2236          k = get16u(ptr + 6);
2237 	 if (k != instance[sp]) { // current instance inserted by default
2238 	     PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2239 	     instance[sp] = -1;
2240 	     if (state->refs) {
2241 		 state->refs = splay(state->refs, (void *)k, ptrcmp);
2242 		 if (state->refs->key == (void *)k) {
2243 		     stack[sp] = (ssgEntity *)state->refs->data;
2244 		 }
2245 	     }
2246 	 }
2247 	 ptr += len;
2248          ptr += AttrChunks(ptr, end, &attr[sp]);
2249          break;
2250 
2251       case 62: /* Instance Definition */
2252          k = get16u(ptr + 6);
2253 #if 0
2254          if (stack[sp]) {
2255 	    state->refs = sinsert(state->refs, (void *)k, 0, ptrcmp);
2256 	    if (state->refs->data == (void *)-1) {
2257 	       state->refs->data = stack[sp];
2258 	       stack[sp]->ref();
2259 	    }
2260 	 }
2261 	 else
2262 	 {
2263 	     ulSetError(UL_DEBUG, "[flt] yeah, but the node is empty!");
2264 	 }
2265 #else
2266 	 instance[sp] = k;
2267 #endif
2268          ptr += len;
2269          break;
2270 
2271       case 63: /* External Reference */
2272          /*ulSetError(UL_DEBUG, "external reference %s", ptr + 4);*/
2273          PostLink(stack + sp - 1, attr + sp - 1, instance[sp], state);
2274 	 instance[sp] = -1;
2275          if (!NoExternals) {
2276             char *file = (char *)ptr + 4, *p;
2277 	    if ((p = strrchr(file, '/')))
2278 		file = p + 1;
2279 	    //stack[sp] = LoadFLT(file);
2280 	    stack[sp] = ssgLoad (file);
2281          }
2282          ptr += len;
2283          ptr += AttrChunks(ptr, end, &attr[sp]);
2284          break;
2285 
2286       case 31: /* Text Comment */
2287       case 21: /* Push Extension */
2288       case 22: /* Pop Extension */
2289       case 55: /* Binary Separating Plane */
2290       case 87: /* Road Segment */
2291       case 90: /* Linkage */
2292       case 91: /* Sound Bead */
2293       case 92: /* Path Bead */
2294       case 95: /* Text */
2295       case 101: /* Light Source Bead */
2296       case 122: /* Push Attribute */
2297       case 123: /* Pop Attribute */
2298 	//printf("op %d ignored\n", op);
2299 	 ptr += len;
2300 	 break;
2301 
2302       case 3:  /* Level of Detail (obsolete) */
2303       case 13: /* Degree of Freedom (obsolete) */
2304       case 16: /* Instance Reference (obsolete) */
2305       case 17: /* Instance Definition (obsolete) */
2306 	 Obsolete(op);
2307          ptr += len;
2308          break;
2309 
2310       default:
2311 	 NotImplemented(op);
2312          ptr += len;
2313       }
2314    }
2315 
2316    /* pop stack (expected one iteration but may be more for incomplete databases) */
2317    while (sp-- > 0)
2318       PostLink(stack + sp, attr + sp, -1, 0);
2319 
2320    if (stack[0])
2321       stack[0] = PostClean(stack[0], attr[0]);
2322    else if (attr[0])
2323       delete attr[0]; // possible?
2324 
2325    return stack[0];
2326 }
2327 
2328 /* parse the vertex table */
VertexTable(ubyte * ptr0,ubyte * end,fltState * state)2329 static int VertexTable(ubyte *ptr0, ubyte *end, fltState *state)
2330 {
2331    int len, size, num, i;
2332    ubyte *ptr = ptr0;
2333 
2334    assert(get16u(ptr) == 67); /* vtx tab op code */
2335    len = get16u(ptr + 2);
2336 
2337    size = get32i(ptr + 4);
2338    /*ulSetError(UL_DEBUG, "vertex table header len %d, total size %d", len, size);*/
2339    num = (size - len)/40; /* max # of vertices */
2340    if (num <= 0 || state->vtab) {
2341       if (state->vtab)
2342 	 ulSetError(UL_WARNING, "[flt] Multiple vertex tables not allowed.");
2343       return size;
2344    }
2345    state->vtab = ptr;
2346    end = MIN(end, ptr + size);
2347    ptr += len;
2348 
2349    state->offset   = new int [num];
2350    state->bind     = new ubyte [num];
2351    state->coord    = new sgVec3 [num];
2352    state->color    = new sgVec4 [num];
2353    state->normal   = new sgVec3 [num];
2354    state->texcoord = new sgVec2 [num];
2355 
2356    for (i = 0; i < num && ptr + 40 <= end; ++i) {
2357       double tmp[3];
2358       ubyte *p = ptr;
2359       int op = get16u(p);
2360       int len = get16u(p + 2);
2361       int flags = get16u(p + 6);
2362       int bind = 0;
2363       if (ptr + len > end)
2364          break;
2365       state->offset[i] = ptr - ptr0;
2366       get64v(p + 8, tmp, 3);
2367       sgSetVec3(state->coord[i], (float)tmp[0], (float)tmp[1], (float)tmp[2]);
2368       sgSetVec4(state->color[i], 1, 1, 1, 1);
2369       sgSetVec3(state->normal[i], 0, 0, 1);
2370       sgSetVec2(state->texcoord[i], 0, 0);
2371       p += 32;
2372       if (op == 69 || op == 70) {
2373 	 get32v(p, state->normal[i], 3);
2374 	 sgNormalizeVec3(state->normal[i]);
2375 	 p += 12;
2376 	 bind |= BIND_NORMAL;
2377       }
2378       if (op == 70 || op == 71) {
2379          get32v(p, state->texcoord[i], 2);
2380          p += 8;
2381          bind |= BIND_TEXCOORD;
2382       }
2383       if (!(flags & 4)) {
2384 	 if ((flags & 8) && p + 4 <= ptr + len) {
2385 	    UNPACK_ABGR(state->color[i], p);
2386 	    //ulSetError(UL_DEBUG, "packed ABGR: %d %d %d %d", p[0], p[1], p[2], p[3]);
2387 	    bind |= BIND_COLOR;
2388 	 }
2389 	 else if (state->revision > 1400) {
2390 	    int color;
2391 	    if (state->revision > 1500 && p + 8 <= ptr + len) {
2392 	       color = get32i(p + 4);
2393 	    }
2394 	    else {
2395 	       color = get16u(ptr + 4);
2396 	       if (color == 65535)
2397 		  color = -1;
2398 	    }
2399 	    int index = color / 128;
2400 	    int intensity = color % 128;
2401 	    if (color >= 0 && state->ctab && index < state->cnum) {
2402 	       //ulSetError(UL_DEBUG, "colour %d: index %d, intensity %d", color, index, intensity);
2403 	       UNPACK_ABGR2(state->color[i], state->ctab[index], intensity);
2404 	       bind |= BIND_COLOR;
2405 	    }
2406 	 }
2407       }
2408       /*
2409        if (bind & BIND_COLOR)
2410 	 ulSetError(UL_DEBUG, "vertex #%d color %.2f %.2f %.2f", i,
2411 		state->color[i][0],
2412 		state->color[i][1],
2413 		state->color[i][2]);
2414       */
2415       state->bind[i] = bind;
2416       ptr += len;
2417    }
2418    /*ulSetError(UL_DEBUG, "got %d vertices", i);*/
2419 
2420    state->vnum = i;
2421 
2422    return size;
2423 }
2424 
2425 /* header ancillary chunks */
TableChunks(ubyte * ptr0,ubyte * end,fltState * state)2426 static int TableChunks(ubyte *ptr0, ubyte *end, fltState *state)
2427 {
2428    ubyte *ptr = ptr0;
2429    int op, len, index, done = 0;
2430 
2431    while (!done) {
2432 
2433       if (ptr + 4 > end)
2434          break;
2435       op = get16u(ptr);
2436       len = get16u(ptr + 2);
2437       if (len < 4 || (len & 3) != 0 || ptr + len > end)
2438          break;
2439 
2440       switch (op) {
2441 
2442       case 32: /* Color Table */
2443 	 if (len < 132 + 4 * 512) {
2444 	    /* note: in older files it appears that the
2445 	     * color table is stored as 16-bit integers.
2446 	     * i have no documentation on this.
2447 	     * maybe 16 x 16 colors (rather than 512 or 1024 x 128).
2448 	     */
2449 	    if (state->revision <= 1400) {
2450 	       ulSetError(UL_WARNING, "[flt] Color table ignored (unknown format).");
2451 	       /*hexdump(UL_DEBUG, ptr, len, 0);*/
2452 	    }
2453 	    else
2454 	       BAD_CHUNK(ptr, "Color Table");
2455 	 }
2456 	 else  if (state->ctab == 0) {
2457 	    int max = (len - 132) / 4;
2458             state->ctab = (ubyte (*)[4])(ptr + 132);
2459 	    state->cnum = MIN(state->revision > 1500 ? 1024 : 512, max);
2460 #if 0
2461 	    int i;
2462 	    for (i = 0; i < state->cnum; i++)
2463 	       ulSetError(UL_DEBUG, "%d %02x %02x %02x %02x", i,
2464 		                    state->ctab[i][0], state->ctab[i][1],
2465 		                    state->ctab[i][2], state->ctab[i][3]);
2466 #endif
2467 	 }
2468 	 else {
2469 	    ulSetError(UL_WARNING, "[flt] Multiple color tables are not allowed.");
2470 	 }
2471          ptr += len;
2472          break;
2473 
2474       case 64: /* Texture Reference */
2475          if (!NoTextures) {
2476 	    if (len == 96 || len == 216) {
2477 	       char *file = (char *)ptr + 4, *p;
2478 	       if ((p = strrchr(file, '/')))
2479 		  file = p + 1;
2480 	       index = get32i(ptr + len - 12);
2481 	       state->texs = sinsert(state->texs, (void *)index, 0, ptrcmp);
2482 	       if (state->texs->data == (void *)-1) {
2483 		  //fltTexture *tex = (fltTexture *)malloc(sizeof(fltTexture));
2484 		  fltTexture *tex = new fltTexture;
2485 		  assert ( tex != NULL );
2486 		  tex->file = file;
2487 		  tex->state = (ssgState *)-1;
2488 		  tex->tex = (ssgTexture *)-1;
2489 		  state->texs->data = tex;
2490 	       }
2491 	    }
2492 	    else {
2493 	       BAD_CHUNK(ptr, "Texture Reference");
2494 	    }
2495 	 }
2496          ptr += len;
2497          break;
2498 
2499       case 66: /* Material Table */
2500 	 if ((len - 4) % 184 != 0) {
2501 	    BAD_CHUNK(ptr, "Material Table");
2502 	 }
2503 	 else if (state->mtls == 0) {
2504 	    ubyte *p = ptr + 4;
2505             int i, j, n = (len - 4) / 184;
2506             for (i = 0; i < n; ++i) {
2507 	       float *mtl;
2508 	       state->mtls = sinsert(state->mtls, (void *)i, 0, ptrcmp);
2509 	       //state->mtls->data = malloc(sizeof(float)*14);
2510 	       state->mtls->data = new float[14];
2511 	       mtl = (float *)state->mtls->data;
2512                get32v(p, mtl, 14);
2513 	       for (j = 0; j < 12; j++)
2514 		  mtl[j] = CLAMP(mtl[j], 0, 1);
2515 	       mtl[12] = CLAMP(mtl[12], 8, 128);
2516 	       mtl[13] = CLAMP(mtl[13], 0, 1);
2517 #if 0
2518 	       float r, g, b, s;
2519 	       r = mtl[0] + mtl[3] + mtl[6] + mtl[9];
2520 	       g = mtl[1] + mtl[4] + mtl[7] + mtl[10];
2521 	       b = mtl[2] + mtl[5] + mtl[8] + mtl[11];
2522 	       s = MAX3(r, g, b);
2523 	       if (s > 1.0f) {
2524 		  s = 1.0f/s;
2525 		  for (j = 0; j < 12; j++)
2526 		     mtl[j] *= s;
2527 	       }
2528 #endif
2529                p += 184;
2530             }
2531          }
2532 	 else {
2533 	    ulSetError(UL_WARNING, "[flt] Multiple material tables are not allowed");
2534 	 }
2535 	 ptr += len;
2536          break;
2537 
2538       case 67: /* Vertex Table (header) */
2539          ptr += VertexTable(ptr, end, state);
2540          break;
2541 
2542       case 113: /* Material */
2543 	 index = get32i(ptr + 4);
2544 	 state->mtls = sinsert(state->mtls, (void *)index, 0, ptrcmp);
2545 	 if (state->mtls->data == (void *)-1) {
2546 	    float *mtl;
2547 	    int i;
2548 	    //state->mtls->data = malloc(sizeof(float)*14);
2549 	    state->mtls->data = new float[14];
2550 	    mtl = (float *)state->mtls->data;
2551 	    get32v(ptr + 24, mtl, 14);
2552 	    for (i = 0; i < 12; i++)
2553 	       mtl[i] = CLAMP(mtl[i], 0, 1);
2554 	    mtl[12] = CLAMP(mtl[12], 8, 128);
2555 	    mtl[13] = CLAMP(mtl[13], 0, 1);
2556 #if 0
2557 	    float r, g, b, s;
2558 	    r = mtl[0] + mtl[3] + mtl[6] + mtl[9];
2559 	    g = mtl[1] + mtl[4] + mtl[7] + mtl[10];
2560 	    b = mtl[2] + mtl[5] + mtl[8] + mtl[11];
2561 	    s = MAX3(r, g, b);
2562 	    if (s > 1.0f) {
2563 	       s = 1.0f/s;
2564 	       for (i = 0; i < 12; i++)
2565 		  mtl[i] *= s;
2566 	    }
2567 #endif
2568 	 }
2569          ptr += len;
2570          break;
2571 
2572       case 65: /* Eyepoint Palette (obsolete) */
2573 	 Obsolete(op);
2574 	 ptr += len;
2575 	 break;
2576 
2577       case 31: /* Text Comment */
2578       case 83: /* Eyepoint and Trackplane */
2579       case 90: /* Linkage Palette */
2580       case 93: /* Sound Palette */
2581       case 97: /* Line Style Palette */
2582       case 102: /* Light Source Palette */
2583       case 103: /* Reserved */
2584       case 104: /* Reserved */
2585       case 112: /* Texture Mapping */
2586       case 114: /* Name Table */
2587 	 /* these are safe to ignore */
2588 	 ptr += len;
2589 	 break;
2590 
2591       default:
2592 	//printf("op %d: end of table chunks\n", op);
2593          done = 1;
2594       }
2595    }
2596 
2597    return ptr - ptr0;
2598 }
2599 
CheckHeader(ubyte * ptr,ubyte * end,fltState * state)2600 static int CheckHeader(ubyte *ptr, ubyte *end, fltState *state)
2601 {
2602    /*const char *unit[9] = {"meters", "kilometers", "", "", "feet", "inches", "", "", "nautical miles"};*/
2603    int len, k;
2604    if (get16u(ptr) != 1) {
2605       ulSetError(UL_WARNING, "[flt] Wrong header opcode (%d).", get16i(ptr));
2606       return -1;
2607    }
2608    len = get16u(ptr + 2);
2609    if (len < 128 || len > 1024) {
2610       ulSetError(UL_WARNING, "[flt] Suspicious header record length (%d).", len);
2611       return -1;
2612    }
2613    k = get32i(ptr + 12);
2614    if (k < 100) {
2615       state->revision = 100 * k;
2616       state->major = k;
2617       state->minor = 0;
2618    }
2619    else {
2620       state->revision = k;
2621       state->major = k / 100;
2622       state->minor = k % 100;
2623    }
2624    if (state->major < 11 || state->major > 16) {
2625       ulSetError(UL_WARNING, "[flt] Suspicious format revision number (%d).", k);
2626       return -1;
2627    }
2628 /*
2629    ulSetError(UL_DEBUG, "[flt] Loading %s %sFlight v%d.%d",
2630 	   state->filename,
2631 	   state->major > 13 ? "Open" : "",
2632 	   state->major,
2633 	   state->minor);
2634 */
2635    return len;
2636 }
2637 
2638 #if 0
2639 struct snode *refs;
2640 static int nrefs;
2641 
2642 static void ptree(ssgEntity *node, FILE *f, int d)
2643 {
2644    int i;
2645    for (i = 0; i < d; ++i)
2646       fprintf(f, "   ");
2647    {
2648       const char *p = node->getName();
2649       fprintf(f, "%s \"%s\"", node->getTypeName(), p ? p : "");
2650    }
2651    if (node->getNumParents() > 1) {
2652       refs = sinsert(refs, node, 0, ptrcmp);
2653       if (refs->data == (void *)-1) {
2654          fprintf(f, " (%d)", nrefs);
2655 	 refs->data = (void *)nrefs++;
2656       }
2657       else {
2658          fprintf(f, " (%d) ...\n", (int)refs->data);
2659          return;
2660       }
2661    }
2662    assert(!node->isA(0xDeadBeef));
2663    if (node->isAKindOf(ssgTypeLeaf())) {
2664       ssgLeaf *leaf = (ssgLeaf *)node;
2665       ssgState *st = leaf->getState();
2666       fprintf(f, " %d tris", leaf->getNumTriangles());
2667       if (st && st->isAKindOf(ssgTypeSimpleState())) {
2668 	 ssgSimpleState *ss = (ssgSimpleState *)st;
2669 	 char *file = ss->getTextureFilename();
2670 	 if (file) {
2671 	    char *p;
2672 	    if ((p = strrchr(file, '/')))
2673 	       file = p + 1;
2674 	    fprintf(f, " %s", file);
2675 	 }
2676       }
2677    }
2678    if (node->isAKindOf(ssgTypeTransform())) {
2679       sgMat4 mat;
2680       ((ssgTransform *)node)->getTransform(mat);
2681       fprintf(f, " pos %.2f %.2f %.2f", mat[3][0], mat[3][1], mat[3][2]);
2682    }
2683    if (node->isAKindOf(ssgTypeRangeSelector())) {
2684       ssgRangeSelector *lod = (ssgRangeSelector *)node;
2685       fprintf(f, " ranges");
2686       for (i = 0; i <= lod->getNumKids(); i++)
2687 	 fprintf(f, " %.2f", lod->getRange(i));
2688    }
2689    putc('\n', f);
2690    if (node->isAKindOf(ssgTypeBranch())) {
2691       ssgBranch *grp = (ssgBranch *)node;
2692       int n = grp->getNumKids();
2693       for (i = 0; i < n; ++i)
2694 	 ptree(grp->getKid(i), f, d+1);
2695    }
2696 }
2697 #endif
2698 
FindFile(const char * file)2699 static const char *FindFile(const char *file)
2700 {
2701    /* XXX fixme! */
2702    static char path[1024];
2703 
2704    if (ulFileExists((char *)file))
2705       return file;
2706 
2707    ssgGetCurrentOptions () -> makeModelPath ( path, file ) ;
2708    if (ulFileExists(path))
2709       return path;
2710 
2711    ulSetError(UL_WARNING, "[flt] %s not found.", file);
2712 
2713    return 0;
2714 }
2715 
2716 static struct snode *FltCache;
2717 
2718 #ifdef UL_WIN32
2719 
win32_perror(const char * s)2720 static void win32_perror(const char *s)
2721 {
2722    LPVOID lpMsgBuf;
2723    FormatMessage(
2724         FORMAT_MESSAGE_ALLOCATE_BUFFER |
2725         FORMAT_MESSAGE_FROM_SYSTEM |
2726         FORMAT_MESSAGE_IGNORE_INSERTS,
2727         NULL,
2728         GetLastError(),
2729         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2730         (LPTSTR) &lpMsgBuf,
2731         0,
2732         NULL
2733     );
2734     fprintf(stderr, "%s: %s\n", s, lpMsgBuf);
2735     LocalFree( lpMsgBuf );
2736 }
2737 
2738 #endif
2739 
LoadFLT(const char * file)2740 static ssgEntity *LoadFLT(const char *file)
2741 {
2742    struct snode *cache;
2743    cache = FltCache = sinsert(FltCache, (void *)file, strlen(file) + 1, (sfunc)strcmp);
2744    if (cache->data == (void *)-1) {
2745       cache->data = NULL; /* avoid looping */
2746 
2747       fltState *state = 0;
2748       int size = 0, len;
2749       ubyte *ptr = 0, *end;
2750       ssgEntity *node = 0;
2751 
2752 #ifdef USE_WIN32_MMAP
2753 
2754       HANDLE fd = INVALID_HANDLE_VALUE;
2755       HANDLE map = 0;
2756 
2757 #else
2758 
2759       int fd = -1;
2760 #ifdef USE_POSIX_MMAP
2761       struct stat st;
2762 #else
2763       ubyte buf[256];
2764 #endif
2765 
2766 #endif
2767 
2768       do { /* dummy loop */
2769 
2770 	 const char *path, *name;
2771 
2772 	 path = FindFile(file);
2773 	 if (path == 0)
2774 	    break;
2775 
2776 #ifdef USE_WIN32_MMAP
2777 
2778 	 fd = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
2779 			 FILE_ATTRIBUTE_NORMAL, 0);
2780 	 if (fd == INVALID_HANDLE_VALUE) {
2781 	    win32_perror(path);
2782 	    break;
2783 	 }
2784 
2785 	 size = GetFileSize(fd, NULL);
2786 	 if (size < 256)
2787 	    break;
2788 
2789 	 map = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL);
2790 	 if (map == 0) {
2791 	    win32_perror(path);
2792 	    break;
2793 	 }
2794 
2795 	 ptr = (ubyte *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
2796 	 if (ptr == 0) {
2797 	    win32_perror(path);
2798 	    break;
2799 	 }
2800 
2801 #else /* USE_WIN32_MAP */
2802 
2803 	 if ((fd = open(path, O_RDONLY|O_BINARY)) == -1) {
2804 	    perror(path);
2805 	    break;
2806 	 }
2807 
2808 #ifdef USE_POSIX_MMAP
2809 	 if (fstat(fd, &st)) {
2810 	    perror(file);
2811 	    break;
2812 	 }
2813 	 size = st.st_size;
2814 	 if (size < 256)
2815 	    break;
2816 	 ptr = (ubyte *)mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
2817 	 if (ptr == (ubyte *)-1) {
2818 	    perror(file);
2819 	    break;
2820 	 }
2821 	 close(fd);
2822 	 fd = -1;
2823 #else /* USE_POSIX_MMAP */
2824 	 if (read(fd, buf, 256) != 256) {
2825 	    perror(file);
2826 	    break;
2827 	 }
2828 	 ptr = buf;
2829 #endif /* ! USE_POSIX_MMAP */
2830 
2831 #endif /* ! USE_WIN32_MMAP */
2832 
2833 	 /*putc('\n', stderr);*/
2834 
2835 	 name = strrchr(file, '/');
2836 	 if (name)
2837 	    name++;
2838 	 else
2839 	    name = file;
2840 
2841 	 state = new fltState;
2842 	 state->filename = name;
2843 
2844 	 len = CheckHeader(ptr, ptr + 256, state);
2845 	 if (len == -1)
2846 	    break;
2847 
2848 #if !defined(USE_POSIX_MMAP) && !defined(USE_WIN32_MMAP)
2849 
2850 	 if ((size = lseek(fd, 0, SEEK_END)) == -1) {
2851 	    perror(file);
2852 	    break;
2853 	 }
2854 	 //ptr = (ubyte *)malloc(size);
2855 	 ptr = new ubyte[size];
2856 	 lseek(fd, 0, SEEK_SET);
2857 	 if (read(fd, ptr, size) != size) {
2858 	    perror(file);
2859 	    break;
2860 	 }
2861 	 close(fd);
2862 	 fd = -1;
2863 
2864 #endif
2865 
2866 	 end = ptr + size;
2867 	 len += TableChunks(ptr + len, end, state);
2868 	 node = HierChunks(ptr + len, end, state);
2869 
2870 	 if (node)
2871 	    node->setName((char *)name);
2872 
2873       } while (0);
2874 
2875       delete state;
2876 
2877 #ifdef USE_WIN32_MMAP
2878 
2879       if (ptr)
2880 	 UnmapViewOfFile(ptr);
2881       if (map)
2882 	 CloseHandle(map);
2883       if (fd != INVALID_HANDLE_VALUE)
2884 	 CloseHandle(fd);
2885 
2886 #else /* USE_WIN32_MMAP */
2887 
2888       if (fd != -1)
2889 	 close(fd);
2890 
2891 #ifdef USE_POSIX_MMAP
2892       if (ptr != 0 && ptr != (ubyte *)-1)
2893 	 munmap((char *)ptr, size);
2894 #else
2895       if (ptr != 0 && ptr != buf)
2896 	 //free(ptr);
2897 	 delete [] ptr;
2898 #endif
2899 
2900 #endif /* ! USE_WIN32_MMAP */
2901 
2902       cache->data = node;
2903       if (node) node->ref();
2904    }
2905 
2906    return (ssgEntity *)cache->data;
2907 }
2908 
2909 #if 0
2910 static struct snode *Flattened;
2911 
2912 static ssgEntity *Flatten(ssgEntity *node, float (*mat)[4])
2913 {
2914    if (node == 0)
2915       return 0;
2916 
2917    assert(!node->isA(0xDeadBeef));
2918 
2919    /* some nodes cannot be flattened. only types that may be
2920     * generated by the loader are considered here.
2921     */
2922    if (node->getRef() > 0 ||
2923        node->isAKindOf(ssgTypeRangeSelector()) ||
2924        node->isAKindOf(ssgTypeCutout())) {
2925       if (node->isAKindOf(ssgTypeBranch())) {
2926 	 /* see if we have flattened beyond this node already */
2927 	 int completed = 0;
2928 	 if (node->getNumParents() > 0) {
2929 	    Flattened = sinsert(Flattened, node, 0, ptrcmp);
2930 	    if (Flattened->data == (void *)-1) {
2931 	       Flattened->data = 0;
2932 	    }
2933 	    else {
2934 	       completed = 1;
2935 	    }
2936 	 }
2937 	 if (!completed) {
2938 	    /* traverse */
2939 	    ssgBranch *grp = (ssgBranch *)node;
2940 	    int i, n = grp->getNumKids();
2941 	    if (n > 0) {
2942 	       ssgEntity *kids[32];
2943 	       for (i = n; i--;) {
2944 		  kids[i] = grp->getKid(i);
2945 		  kids[i]->ref(); grp->removeKid(i); kids[i]->deRef();
2946 		  kids[i] = Flatten(kids[i], 0);
2947 		  assert(kids[i] == 0 || !kids[i]->isA(0xDeadBeef));
2948 	       }
2949 	       for (i = 0; i < n; i++)
2950 		  if (kids[i])
2951 		     grp->addKid(kids[i]);
2952 	       grp->recalcBSphere();
2953 	    }
2954 	 }
2955       }
2956       /* insert a transform if required */
2957       if (mat) {
2958 	 ssgTransform *scs = new ssgTransform;
2959 	 scs->setTransform(mat);
2960 	 scs->addKid(node);
2961 	 node = scs;
2962       }
2963       return node;
2964    }
2965 
2966    assert(node->getNumParents() == 0);
2967 
2968    /* accumulate transformations */
2969    if (node->isAKindOf(ssgTypeTransform())) {
2970       ssgTransform *scs = (ssgTransform *)node;
2971       int i, n = scs->getNumKids();
2972       if (n <= 0) {
2973 	 delete scs;
2974 	 return 0;
2975       }
2976       else {
2977 	 sgMat4 tmp;
2978 	 scs->getTransform(tmp);
2979 	 if (mat)
2980 	    sgPostMultMat4(tmp, mat);
2981 	 if (n == 1) {
2982 	    node = scs->getKid(0);
2983 	    node->ref(); scs->removeKid(0); node->deRef();
2984 	    delete scs;
2985 	    assert(!node->isA(0xDeadBeef));
2986 	    return Flatten(node, tmp);
2987 	 }
2988 	 else {
2989 	    ssgBranch *grp = new ssgBranch;
2990 	    grp->setName(scs->getName());
2991 	    for (i = 0; i < n; i++)
2992 	       grp->addKid(scs->getKid(i));
2993 	    while (n--)
2994 	       scs->removeKid(n);
2995 	    delete scs;
2996 	    return Flatten(grp, tmp);
2997 	 }
2998       }
2999    }
3000 
3001    /* recurse the scene graph */
3002    if (node->isAKindOf(ssgTypeBranch())) {
3003       ssgBranch *grp = (ssgBranch *)node;
3004       int i, n = grp->getNumKids();
3005       if (n <= 0) {
3006 	 delete grp;
3007 	 return 0;
3008       }
3009       else if (n == 1 && grp->isA(ssgTypeBranch())) {
3010 	 ssgEntity *kid = grp->getKid(0);
3011 	 kid->ref(); grp->removeKid(0); kid->deRef();
3012 	 delete grp;
3013 	 assert(!kid->isA(0xDeadBeef));
3014 	 return Flatten(kid, mat);
3015       }
3016       else {
3017 	 ssgEntity *kids[32];
3018 	 for (i = n; i--;) {
3019 	    kids[i] = grp->getKid(i);
3020 	    kids[i]->ref(); grp->removeKid(i); kids[i]->deRef();
3021 	    kids[i] = Flatten(kids[i], mat);
3022 	    assert(kids[i] == 0 || !kids[i]->isA(0xDeadBeef));
3023 	 }
3024 	 assert(!grp->isA(0xDeadBeef));
3025 	 for (i = 0; i < n; i++) {
3026 	    if (kids[i]) {
3027 	       assert(!kids[i]->isA(0xDeadBeef));
3028 	       grp->addKid(kids[i]);
3029 	    }
3030 	 }
3031 	 grp->recalcBSphere();
3032 	 return grp;
3033       }
3034    }
3035 
3036    /* transform geometry */
3037    if (node->isAKindOf(ssgTypeVtxTable()) && mat) {
3038       ssgVtxTable *g = (ssgVtxTable *)node;
3039       sgVec3 *a;
3040       int i, n;
3041       n = g->getNumVertices();
3042       if (n > 0) {
3043 	 g->getVertexList((void **)&a);
3044 	 for (i = 0; i < n; i++)
3045 	    sgXformPnt3(a[i], a[i], mat);
3046       }
3047       n = g->getNumNormals();
3048       if (n > 0) {
3049 	 g->getNormalList((void **)&a);
3050 	 for (i = 0; i < n; i++)
3051 	    sgXformVec3(a[i], a[i], mat);
3052       }
3053       g->recalcBSphere();
3054    }
3055    assert(!node->isA(0xDeadBeef));
3056    return node;
3057 }
3058 #endif
3059 
Init(void)3060 static void Init(void)
3061 {
3062    if (Inited)
3063       return;
3064    Inited = 1;
3065 
3066 #if !defined(USE_POSIX_MMAP) && !defined(USE_WIN32_MMAP)
3067    ulSetError(UL_DEBUG, "[flt] Memory mapped files not enabled, please check source code.");
3068 #endif
3069 
3070 #ifdef PROBE_ENDIAN
3071    {
3072       short tmp = 42;
3073       if (*(char *)&tmp == 42) {
3074          /* little endian */
3075          get16v = _swab16;
3076          get32v = _swab32;
3077          get64v = _swab64;
3078 	 ulSetError(UL_DEBUG, "[flt] Little endian architecture.");
3079       }
3080       else {
3081          /* big endian */
3082          get16v = _copy16;
3083          get32v = _copy32;
3084          get64v = _copy64;
3085 	 ulSetError(UL_DEBUG, "[flt] Big endian architecture.");
3086       }
3087    }
3088 #endif
3089 
3090    if (getenv("FLTNOTEX"))    NoTextures = 1;
3091    if (getenv("FLTNOMIPMAP")) NoMipmaps = 1;
3092    if (getenv("FLTNOEXT"))    NoExternals = 1;
3093    if (getenv("FLTNOCLEAN"))  NoClean = 1;
3094 
3095    return;
3096 }
3097 
ssgLoadFLT(const char * filename,ssgHookFunc)3098 ssgEntity *ssgLoadFLT(const char *filename,
3099 #ifdef NO_LOADER_OPTIONS
3100 		      ssgHookFunc
3101 #else
3102 		      const ssgLoaderOptions *options
3103 #endif
3104 		      )
3105 {
3106    static int depth = 0;
3107    ssgEntity *node;
3108 
3109    if (depth == 0) {
3110 
3111       Init();
3112 
3113       ObsoleteFlag = 0;
3114       NotImplementedFlag = 0;
3115 
3116       TexCache = 0;
3117       StateCache = 0;
3118       FltCache = 0;
3119 
3120 #ifndef NO_LOADER_OPTIONS
3121       ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
3122       LoaderOptions = ssgGetCurrentOptions () ;
3123 #endif
3124 
3125    }
3126 
3127    // no longjmp()'s please! (or this recursion test will fail)
3128 
3129    depth++;
3130 
3131    node = LoadFLT(filename);
3132 
3133    depth--;
3134 
3135    if (depth == 0) {
3136 
3137      sfree(TexCache, S_KEY | S_DATA);
3138      sfree(StateCache, S_KEY);
3139 
3140      if (node) node->ref(); // prevent this node from being deleted!
3141      sfree(FltCache, S_KEY | S_TREE);
3142      if (node) node->deRef();
3143 
3144    }
3145 
3146 #if 0
3147    if (node && !NoClean) {
3148       Flattened = 0;
3149       node = Flatten(node, 0);
3150       sfree(Flattened, 0);
3151    }
3152 #endif
3153 
3154 #if 0 /* debug */
3155    if (node && getenv("FLTDUMP")) {
3156       const char *file = "/tmp/tree.txt";
3157       FILE *f = fopen(file, "w");
3158       if (f == 0)
3159 	 perror(file);
3160       else {
3161 	 refs = 0;
3162 	 nrefs = 0;
3163 	 ptree(node, f, 0);
3164 	 sfree(refs, 0);
3165 	 fclose(f);
3166 	 ulSetError(UL_DEBUG, "wrote %s", file);
3167       }
3168    }
3169 #endif
3170 
3171    return node;
3172 }
3173 //lint -restore
3174