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