doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Model_lwo.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Model_lwo.h"
33 
34 /*
35 ======================================================================
36 
37  Converted from lwobject sample prog from LW 6.5 SDK.
38 
39 ======================================================================
40 */
41 
42 /*
43 ======================================================================
44 lwFreeClip()
45 
46 Free memory used by an lwClip.
47 ====================================================================== */
48 
49 void lwFreeClip( lwClip *clip )
50 {
51  if ( clip ) {
52  lwListFree( clip->ifilter, (void (__cdecl *)(void *))lwFreePlugin );
53  lwListFree( clip->pfilter, (void (__cdecl *)(void *))lwFreePlugin );
54  switch( clip->type ) {
55  case ID_STIL: {
56  if ( clip->source.still.name ) Mem_Free( clip->source.still.name );
57  break;
58  }
59  case ID_ISEQ: {
60  if ( clip->source.seq.suffix ) Mem_Free( clip->source.seq.suffix );
61  if ( clip->source.seq.prefix ) Mem_Free( clip->source.seq.prefix );
62  break;
63  }
64  case ID_ANIM: {
65  if ( clip->source.anim.server ) Mem_Free( clip->source.anim.server );
66  if ( clip->source.anim.name ) Mem_Free( clip->source.anim.name );
67  break;
68  }
69  case ID_XREF: {
70  if ( clip->source.xref.string ) Mem_Free( clip->source.xref.string );
71  break;
72  }
73  case ID_STCC: {
74  if ( clip->source.cycle.name ) Mem_Free( clip->source.cycle.name );
75  break;
76  }
77  }
78  Mem_Free( clip );
79  }
80 }
81 
82 
83 /*
84 ======================================================================
85 lwGetClip()
86 
87 Read image references from a CLIP chunk in an LWO2 file.
88 ====================================================================== */
89 
90 lwClip *lwGetClip( idFile *fp, int cksize )
91 {
92  lwClip *clip;
93  lwPlugin *filt;
94  unsigned int id;
95  unsigned short sz;
96  int pos, rlen;
97 
98 
99  /* allocate the Clip structure */
100 
101  clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
102  if ( !clip ) goto Fail;
103 
104  clip->contrast.val = 1.0f;
105  clip->brightness.val = 1.0f;
106  clip->saturation.val = 1.0f;
107  clip->gamma.val = 1.0f;
108 
109  /* remember where we started */
110 
111  set_flen( 0 );
112  pos = fp->Tell();
113 
114  /* index */
115 
116  clip->index = getI4( fp );
117 
118  /* first subchunk header */
119 
120  clip->type = getU4( fp );
121  sz = getU2( fp );
122  if ( 0 > get_flen() ) goto Fail;
123 
124  sz += sz & 1;
125  set_flen( 0 );
126 
127  switch ( clip->type ) {
128  case ID_STIL:
129  clip->source.still.name = getS0( fp );
130  break;
131 
132  case ID_ISEQ:
133  clip->source.seq.digits = getU1( fp );
134  clip->source.seq.flags = getU1( fp );
135  clip->source.seq.offset = getI2( fp );
136  clip->source.seq.start = getI2( fp );
137  clip->source.seq.end = getI2( fp );
138  clip->source.seq.prefix = getS0( fp );
139  clip->source.seq.suffix = getS0( fp );
140  break;
141 
142  case ID_ANIM:
143  clip->source.anim.name = getS0( fp );
144  clip->source.anim.server = getS0( fp );
145  rlen = get_flen();
146  clip->source.anim.data = getbytes( fp, sz - rlen );
147  break;
148 
149  case ID_XREF:
150  clip->source.xref.index = getI4( fp );
151  clip->source.xref.string = getS0( fp );
152  break;
153 
154  case ID_STCC:
155  clip->source.cycle.lo = getI2( fp );
156  clip->source.cycle.hi = getI2( fp );
157  clip->source.cycle.name = getS0( fp );
158  break;
159 
160  default:
161  break;
162  }
163 
164  /* error while reading current subchunk? */
165 
166  rlen = get_flen();
167  if ( rlen < 0 || rlen > sz ) goto Fail;
168 
169  /* skip unread parts of the current subchunk */
170 
171  if ( rlen < sz )
172  fp->Seek( sz - rlen, FS_SEEK_CUR );
173 
174  /* end of the CLIP chunk? */
175 
176  rlen = fp->Tell() - pos;
177  if ( cksize < rlen ) goto Fail;
178  if ( cksize == rlen )
179  return clip;
180 
181  /* process subchunks as they're encountered */
182 
183  id = getU4( fp );
184  sz = getU2( fp );
185  if ( 0 > get_flen() ) goto Fail;
186 
187  while ( 1 ) {
188  sz += sz & 1;
189  set_flen( 0 );
190 
191  switch ( id ) {
192  case ID_TIME:
193  clip->start_time = getF4( fp );
194  clip->duration = getF4( fp );
195  clip->frame_rate = getF4( fp );
196  break;
197 
198  case ID_CONT:
199  clip->contrast.val = getF4( fp );
200  clip->contrast.eindex = getVX( fp );
201  break;
202 
203  case ID_BRIT:
204  clip->brightness.val = getF4( fp );
205  clip->brightness.eindex = getVX( fp );
206  break;
207 
208  case ID_SATR:
209  clip->saturation.val = getF4( fp );
210  clip->saturation.eindex = getVX( fp );
211  break;
212 
213  case ID_HUE:
214  clip->hue.val = getF4( fp );
215  clip->hue.eindex = getVX( fp );
216  break;
217 
218  case ID_GAMM:
219  clip->gamma.val = getF4( fp );
220  clip->gamma.eindex = getVX( fp );
221  break;
222 
223  case ID_NEGA:
224  clip->negative = getU2( fp );
225  break;
226 
227  case ID_IFLT:
228  case ID_PFLT:
229  filt = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
230  if ( !filt ) goto Fail;
231 
232  filt->name = getS0( fp );
233  filt->flags = getU2( fp );
234  rlen = get_flen();
235  filt->data = getbytes( fp, sz - rlen );
236 
237  if ( id == ID_IFLT ) {
238  lwListAdd( (void**)&clip->ifilter, filt );
239  clip->nifilters++;
240  }
241  else {
242  lwListAdd( (void**)&clip->pfilter, filt );
243  clip->npfilters++;
244  }
245  break;
246 
247  default:
248  break;
249  }
250 
251  /* error while reading current subchunk? */
252 
253  rlen = get_flen();
254  if ( rlen < 0 || rlen > sz ) goto Fail;
255 
256  /* skip unread parts of the current subchunk */
257 
258  if ( rlen < sz )
259  fp->Seek( sz - rlen, FS_SEEK_CUR );
260 
261  /* end of the CLIP chunk? */
262 
263  rlen = fp->Tell() - pos;
264  if ( cksize < rlen ) goto Fail;
265  if ( cksize == rlen ) break;
266 
267  /* get the next chunk header */
268 
269  set_flen( 0 );
270  id = getU4( fp );
271  sz = getU2( fp );
272  if ( 6 != get_flen() ) goto Fail;
273  }
274 
275  return clip;
276 
277 Fail:
278  lwFreeClip( clip );
279  return NULL;
280 }
281 
282 
283 /*
284 ======================================================================
285 lwFindClip()
286 
287 Returns an lwClip pointer, given a clip index.
288 ====================================================================== */
289 
291 {
292  lwClip *clip;
293 
294  clip = list;
295  while ( clip ) {
296  if ( clip->index == index ) break;
297  clip = clip->next;
298  }
299  return clip;
300 }
301 
302 
303 /*
304 ======================================================================
305 lwFreeEnvelope()
306 
307 Free the memory used by an lwEnvelope.
308 ====================================================================== */
309 
310 void lwFree( void *ptr ) {
311  Mem_Free( ptr );
312 }
313 
315 {
316  if ( env ) {
317  if ( env->name ) Mem_Free( env->name );
318  lwListFree( env->key, lwFree );
319  lwListFree( env->cfilter, (void (__cdecl *)(void *))lwFreePlugin );
320  Mem_Free( env );
321  }
322 }
323 
324 
325 static int compare_keys( lwKey *k1, lwKey *k2 )
326 {
327  return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
328 }
329 
330 
331 /*
332 ======================================================================
333 lwGetEnvelope()
334 
335 Read an ENVL chunk from an LWO2 file.
336 ====================================================================== */
337 
338 lwEnvelope *lwGetEnvelope( idFile *fp, int cksize )
339 {
340  lwEnvelope *env;
341  lwKey *key;
342  lwPlugin *plug;
343  unsigned int id;
344  unsigned short sz;
345  float f[ 4 ];
346  int i, nparams, pos, rlen;
347 
348 
349  /* allocate the Envelope structure */
350 
351  env = (lwEnvelope*)Mem_ClearedAlloc( sizeof( lwEnvelope ) );
352  if ( !env ) goto Fail;
353 
354  /* remember where we started */
355 
356  set_flen( 0 );
357  pos = fp->Tell();
358 
359  /* index */
360 
361  env->index = getVX( fp );
362 
363  /* first subchunk header */
364 
365  id = getU4( fp );
366  sz = getU2( fp );
367  if ( 0 > get_flen() ) goto Fail;
368 
369  /* process subchunks as they're encountered */
370 
371  while ( 1 ) {
372  sz += sz & 1;
373  set_flen( 0 );
374 
375  switch ( id ) {
376  case ID_TYPE:
377  env->type = getU2( fp );
378  break;
379 
380  case ID_NAME:
381  env->name = getS0( fp );
382  break;
383 
384  case ID_PRE:
385  env->behavior[ 0 ] = getU2( fp );
386  break;
387 
388  case ID_POST:
389  env->behavior[ 1 ] = getU2( fp );
390  break;
391 
392  case ID_KEY:
393  key = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
394  if ( !key ) goto Fail;
395  key->time = getF4( fp );
396  key->value = getF4( fp );
397  lwListInsert( (void**)&env->key, key, (int (__cdecl *)(void *,void *))compare_keys );
398  env->nkeys++;
399  break;
400 
401  case ID_SPAN:
402  if ( !key ) goto Fail;
403  key->shape = getU4( fp );
404 
405  nparams = ( sz - 4 ) / 4;
406  if ( nparams > 4 ) nparams = 4;
407  for ( i = 0; i < nparams; i++ )
408  f[ i ] = getF4( fp );
409 
410  switch ( key->shape ) {
411  case ID_TCB:
412  key->tension = f[ 0 ];
413  key->continuity = f[ 1 ];
414  key->bias = f[ 2 ];
415  break;
416 
417  case ID_BEZI:
418  case ID_HERM:
419  case ID_BEZ2:
420  for ( i = 0; i < nparams; i++ )
421  key->param[ i ] = f[ i ];
422  break;
423  }
424  break;
425 
426  case ID_CHAN:
427  plug = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
428  if ( !plug ) goto Fail;
429 
430  plug->name = getS0( fp );
431  plug->flags = getU2( fp );
432  plug->data = getbytes( fp, sz - get_flen() );
433 
434  lwListAdd( (void**)&env->cfilter, plug );
435  env->ncfilters++;
436  break;
437 
438  default:
439  break;
440  }
441 
442  /* error while reading current subchunk? */
443 
444  rlen = get_flen();
445  if ( rlen < 0 || rlen > sz ) goto Fail;
446 
447  /* skip unread parts of the current subchunk */
448 
449  if ( rlen < sz )
450  fp->Seek( sz - rlen, FS_SEEK_CUR );
451 
452  /* end of the ENVL chunk? */
453 
454  rlen = fp->Tell() - pos;
455  if ( cksize < rlen ) goto Fail;
456  if ( cksize == rlen ) break;
457 
458  /* get the next subchunk header */
459 
460  set_flen( 0 );
461  id = getU4( fp );
462  sz = getU2( fp );
463  if ( 6 != get_flen() ) goto Fail;
464  }
465 
466  return env;
467 
468 Fail:
469  lwFreeEnvelope( env );
470  return NULL;
471 }
472 
473 
474 /*
475 ======================================================================
476 lwFindEnvelope()
477 
478 Returns an lwEnvelope pointer, given an envelope index.
479 ====================================================================== */
480 
482 {
483  lwEnvelope *env;
484 
485  env = list;
486  while ( env ) {
487  if ( env->index == index ) break;
488  env = env->next;
489  }
490  return env;
491 }
492 
493 
494 /*
495 ======================================================================
496 range()
497 
498 Given the value v of a periodic function, returns the equivalent value
499 v2 in the principal interval [lo, hi]. If i isn't NULL, it receives
500 the number of wavelengths between v and v2.
501 
502  v2 = v - i * (hi - lo)
503 
504 For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
505 ====================================================================== */
506 
507 static float range( float v, float lo, float hi, int *i )
508 {
509  float v2, r = hi - lo;
510 
511  if ( r == 0.0 ) {
512  if ( i ) *i = 0;
513  return lo;
514  }
515 
516  v2 = lo + v - r * ( float ) floor(( double ) v / r );
517  if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
518 
519  return v2;
520 }
521 
522 
523 /*
524 ======================================================================
525 hermite()
526 
527 Calculate the Hermite coefficients.
528 ====================================================================== */
529 
530 static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
531 {
532  float t2, t3;
533 
534  t2 = t * t;
535  t3 = t * t2;
536 
537  *h2 = 3.0f * t2 - t3 - t3;
538  *h1 = 1.0f - *h2;
539  *h4 = t3 - t2;
540  *h3 = *h4 - t2 + t;
541 }
542 
543 
544 /*
545 ======================================================================
546 bezier()
547 
548 Interpolate the value of a 1D Bezier curve.
549 ====================================================================== */
550 
551 static float bezier( float x0, float x1, float x2, float x3, float t )
552 {
553  float a, b, c, t2, t3;
554 
555  t2 = t * t;
556  t3 = t2 * t;
557 
558  c = 3.0f * ( x1 - x0 );
559  b = 3.0f * ( x2 - x1 ) - c;
560  a = x3 - x0 - c - b;
561 
562  return a * t3 + b * t2 + c * t + x0;
563 }
564 
565 
566 /*
567 ======================================================================
568 bez2_time()
569 
570 Find the t for which bezier() returns the input time. The handle
571 endpoints of a BEZ2 curve represent the control points, and these have
572 (time, value) coordinates, so time is used as both a coordinate and a
573 parameter for this curve type.
574 ====================================================================== */
575 
576 static float bez2_time( float x0, float x1, float x2, float x3, float time,
577  float *t0, float *t1 )
578 {
579  float v, t;
580 
581  t = *t0 + ( *t1 - *t0 ) * 0.5f;
582  v = bezier( x0, x1, x2, x3, t );
583  if ( idMath::Fabs( time - v ) > .0001f ) {
584  if ( v > time )
585  *t1 = t;
586  else
587  *t0 = t;
588  return bez2_time( x0, x1, x2, x3, time, t0, t1 );
589  }
590  else
591  return t;
592 }
593 
594 
595 /*
596 ======================================================================
597 bez2()
598 
599 Interpolate the value of a BEZ2 curve.
600 ====================================================================== */
601 
602 static float bez2( lwKey *key0, lwKey *key1, float time )
603 {
604  float x, y, t, t0 = 0.0f, t1 = 1.0f;
605 
606  if ( key0->shape == ID_BEZ2 )
607  x = key0->time + key0->param[ 2 ];
608  else
609  x = key0->time + ( key1->time - key0->time ) / 3.0f;
610 
611  t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
612  time, &t0, &t1 );
613 
614  if ( key0->shape == ID_BEZ2 )
615  y = key0->value + key0->param[ 3 ];
616  else
617  y = key0->value + key0->param[ 1 ] / 3.0f;
618 
619  return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
620 }
621 
622 
623 /*
624 ======================================================================
625 outgoing()
626 
627 Return the outgoing tangent to the curve at key0. The value returned
628 for the BEZ2 case is used when extrapolating a linear pre behavior and
629 when interpolating a non-BEZ2 span.
630 ====================================================================== */
631 
632 static float outgoing( lwKey *key0, lwKey *key1 )
633 {
634  float a, b, d, t, out;
635 
636  switch ( key0->shape )
637  {
638  case ID_TCB:
639  a = ( 1.0f - key0->tension )
640  * ( 1.0f + key0->continuity )
641  * ( 1.0f + key0->bias );
642  b = ( 1.0f - key0->tension )
643  * ( 1.0f - key0->continuity )
644  * ( 1.0f - key0->bias );
645  d = key1->value - key0->value;
646 
647  if ( key0->prev ) {
648  t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
649  out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
650  }
651  else
652  out = b * d;
653  break;
654 
655  case ID_LINE:
656  d = key1->value - key0->value;
657  if ( key0->prev ) {
658  t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
659  out = t * ( key0->value - key0->prev->value + d );
660  }
661  else
662  out = d;
663  break;
664 
665  case ID_BEZI:
666  case ID_HERM:
667  out = key0->param[ 1 ];
668  if ( key0->prev )
669  out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
670  break;
671 
672  case ID_BEZ2:
673  out = key0->param[ 3 ] * ( key1->time - key0->time );
674  if ( idMath::Fabs( key0->param[ 2 ] ) > 1e-5f )
675  out /= key0->param[ 2 ];
676  else
677  out *= 1e5f;
678  break;
679 
680  case ID_STEP:
681  default:
682  out = 0.0f;
683  break;
684  }
685 
686  return out;
687 }
688 
689 
690 /*
691 ======================================================================
692 incoming()
693 
694 Return the incoming tangent to the curve at key1. The value returned
695 for the BEZ2 case is used when extrapolating a linear post behavior.
696 ====================================================================== */
697 
698 static float incoming( lwKey *key0, lwKey *key1 )
699 {
700  float a, b, d, t, in;
701 
702  switch ( key1->shape )
703  {
704  case ID_LINE:
705  d = key1->value - key0->value;
706  if ( key1->next ) {
707  t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
708  in = t * ( key1->next->value - key1->value + d );
709  }
710  else
711  in = d;
712  break;
713 
714  case ID_TCB:
715  a = ( 1.0f - key1->tension )
716  * ( 1.0f - key1->continuity )
717  * ( 1.0f + key1->bias );
718  b = ( 1.0f - key1->tension )
719  * ( 1.0f + key1->continuity )
720  * ( 1.0f - key1->bias );
721  d = key1->value - key0->value;
722 
723  if ( key1->next ) {
724  t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
725  in = t * ( b * ( key1->next->value - key1->value ) + a * d );
726  }
727  else
728  in = a * d;
729  break;
730 
731  case ID_BEZI:
732  case ID_HERM:
733  in = key1->param[ 0 ];
734  if ( key1->next )
735  in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
736  break;
737  return in;
738 
739  case ID_BEZ2:
740  in = key1->param[ 1 ] * ( key1->time - key0->time );
741  if ( idMath::Fabs( key1->param[ 0 ] ) > 1e-5f )
742  in /= key1->param[ 0 ];
743  else
744  in *= 1e5f;
745  break;
746 
747  case ID_STEP:
748  default:
749  in = 0.0f;
750  break;
751  }
752 
753  return in;
754 }
755 
756 
757 /*
758 ======================================================================
759 evalEnvelope()
760 
761 Given a list of keys and a time, returns the interpolated value of the
762 envelope at that time.
763 ====================================================================== */
764 
765 float evalEnvelope( lwEnvelope *env, float time )
766 {
767  lwKey *key0, *key1, *skey, *ekey;
768  float t, h1, h2, h3, h4, in, out, offset = 0.0f;
769  int noff;
770 
771 
772  /* if there's no key, the value is 0 */
773 
774  if ( env->nkeys == 0 ) return 0.0f;
775 
776  /* if there's only one key, the value is constant */
777 
778  if ( env->nkeys == 1 )
779  return env->key->value;
780 
781  /* find the first and last keys */
782 
783  skey = ekey = env->key;
784  while ( ekey->next ) ekey = ekey->next;
785 
786  /* use pre-behavior if time is before first key time */
787 
788  if ( time < skey->time ) {
789  switch ( env->behavior[ 0 ] )
790  {
791  case BEH_RESET:
792  return 0.0f;
793 
794  case BEH_CONSTANT:
795  return skey->value;
796 
797  case BEH_REPEAT:
798  time = range( time, skey->time, ekey->time, NULL );
799  break;
800 
801  case BEH_OSCILLATE:
802  time = range( time, skey->time, ekey->time, &noff );
803  if ( noff % 2 )
804  time = ekey->time - skey->time - time;
805  break;
806 
807  case BEH_OFFSET:
808  time = range( time, skey->time, ekey->time, &noff );
809  offset = noff * ( ekey->value - skey->value );
810  break;
811 
812  case BEH_LINEAR:
813  out = outgoing( skey, skey->next )
814  / ( skey->next->time - skey->time );
815  return out * ( time - skey->time ) + skey->value;
816  }
817  }
818 
819  /* use post-behavior if time is after last key time */
820 
821  else if ( time > ekey->time ) {
822  switch ( env->behavior[ 1 ] )
823  {
824  case BEH_RESET:
825  return 0.0f;
826 
827  case BEH_CONSTANT:
828  return ekey->value;
829 
830  case BEH_REPEAT:
831  time = range( time, skey->time, ekey->time, NULL );
832  break;
833 
834  case BEH_OSCILLATE:
835  time = range( time, skey->time, ekey->time, &noff );
836  if ( noff % 2 )
837  time = ekey->time - skey->time - time;
838  break;
839 
840  case BEH_OFFSET:
841  time = range( time, skey->time, ekey->time, &noff );
842  offset = noff * ( ekey->value - skey->value );
843  break;
844 
845  case BEH_LINEAR:
846  in = incoming( ekey->prev, ekey )
847  / ( ekey->time - ekey->prev->time );
848  return in * ( time - ekey->time ) + ekey->value;
849  }
850  }
851 
852  /* get the endpoints of the interval being evaluated */
853 
854  key0 = env->key;
855  while ( time > key0->next->time )
856  key0 = key0->next;
857  key1 = key0->next;
858 
859  /* check for singularities first */
860 
861  if ( time == key0->time )
862  return key0->value + offset;
863  else if ( time == key1->time )
864  return key1->value + offset;
865 
866  /* get interval length, time in [0, 1] */
867 
868  t = ( time - key0->time ) / ( key1->time - key0->time );
869 
870  /* interpolate */
871 
872  switch ( key1->shape )
873  {
874  case ID_TCB:
875  case ID_BEZI:
876  case ID_HERM:
877  out = outgoing( key0, key1 );
878  in = incoming( key0, key1 );
879  hermite( t, &h1, &h2, &h3, &h4 );
880  return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
881 
882  case ID_BEZ2:
883  return bez2( key0, key1, time ) + offset;
884 
885  case ID_LINE:
886  return key0->value + t * ( key1->value - key0->value ) + offset;
887 
888  case ID_STEP:
889  return key0->value + offset;
890 
891  default:
892  return offset;
893  }
894 }
895 
896 
897 
898 /*
899 ======================================================================
900 lwListFree()
901 
902 Free the items in a list.
903 ====================================================================== */
904 
905 void lwListFree( void *list, void ( *freeNode )( void * ))
906 {
907  lwNode *node, *next;
908 
909  node = ( lwNode * ) list;
910  while ( node ) {
911  next = node->next;
912  freeNode( node );
913  node = next;
914  }
915 }
916 
917 
918 /*
919 ======================================================================
920 lwListAdd()
921 
922 Append a node to a list.
923 ====================================================================== */
924 
925 void lwListAdd( void **list, void *node )
926 {
927  lwNode *head, *tail;
928 
929  head = *(( lwNode ** ) list );
930  if ( !head ) {
931  *list = node;
932  return;
933  }
934  while ( head ) {
935  tail = head;
936  head = head->next;
937  }
938  tail->next = ( lwNode * ) node;
939  (( lwNode * ) node )->prev = tail;
940 }
941 
942 
943 /*
944 ======================================================================
945 lwListInsert()
946 
947 Insert a node into a list in sorted order.
948 ====================================================================== */
949 
950 void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * ))
951 {
952  lwNode **list, *item, *node, *prev;
953 
954  if ( !*vlist ) {
955  *vlist = vitem;
956  return;
957  }
958 
959  list = ( lwNode ** ) vlist;
960  item = ( lwNode * ) vitem;
961  node = *list;
962  prev = NULL;
963 
964  while ( node ) {
965  if ( 0 < compare( node, item )) break;
966  prev = node;
967  node = node->next;
968  }
969 
970  if ( !prev ) {
971  *list = item;
972  node->prev = item;
973  item->next = node;
974  }
975  else if ( !node ) {
976  prev->next = item;
977  item->prev = prev;
978  }
979  else {
980  item->next = node;
981  item->prev = prev;
982  prev->next = item;
983  node->prev = item;
984  }
985 }
986 
987 /*
988 ======================================================================
989 flen
990 
991 This accumulates a count of the number of bytes read. Callers can set
992 it at the beginning of a sequence of reads and then retrieve it to get
993 the number of bytes actually read. If one of the I/O functions fails,
994 flen is set to an error code, after which the I/O functions ignore
995 read requests until flen is reset.
996 ====================================================================== */
997 
998 #define FLEN_ERROR -9999
999 
1000 static int flen;
1001 
1002 void set_flen( int i ) { flen = i; }
1003 
1004 int get_flen( void ) { return flen; }
1005 
1006 void *getbytes( idFile *fp, int size )
1007 {
1008  void *data;
1009 
1010  if ( flen == FLEN_ERROR ) return NULL;
1011  if ( size < 0 ) {
1012  flen = FLEN_ERROR;
1013  return NULL;
1014  }
1015  data = Mem_ClearedAlloc( size );
1016  if ( !data ) {
1017  flen = FLEN_ERROR;
1018  return NULL;
1019  }
1020  if ( size != fp->Read( data, size ) ) {
1021  flen = FLEN_ERROR;
1022  Mem_Free( data );
1023  return NULL;
1024  }
1025 
1026  flen += size;
1027  return data;
1028 }
1029 
1030 
1031 void skipbytes( idFile *fp, int n )
1032 {
1033  if ( flen == FLEN_ERROR ) return;
1034  if ( fp->Seek( n, FS_SEEK_CUR ))
1035  flen = FLEN_ERROR;
1036  else
1037  flen += n;
1038 }
1039 
1040 
1041 int getI1( idFile *fp )
1042 {
1043  int i, c;
1044 
1045  if ( flen == FLEN_ERROR ) return 0;
1046  c = 0;
1047  i = fp->Read(&c, 1);
1048  if ( i < 0 ) {
1049  flen = FLEN_ERROR;
1050  return 0;
1051  }
1052  if ( c > 127 ) c -= 256;
1053  flen += 1;
1054  return c;
1055 }
1056 
1057 
1058 short getI2( idFile *fp )
1059 {
1060  short i;
1061 
1062  if ( flen == FLEN_ERROR ) return 0;
1063  if ( 2 != fp->Read( &i, 2 )) {
1064  flen = FLEN_ERROR;
1065  return 0;
1066  }
1067  BigRevBytes( &i, 2, 1 );
1068  flen += 2;
1069  return i;
1070 }
1071 
1072 
1073 int getI4( idFile *fp )
1074 {
1075  int i;
1076 
1077  if ( flen == FLEN_ERROR ) return 0;
1078  if ( 4 != fp->Read( &i, 4 )) {
1079  flen = FLEN_ERROR;
1080  return 0;
1081  }
1082  BigRevBytes( &i, 4, 1 );
1083  flen += 4;
1084  return i;
1085 }
1086 
1087 
1088 unsigned char getU1( idFile *fp )
1089 {
1090  int i, c;
1091 
1092  if ( flen == FLEN_ERROR ) return 0;
1093  c = 0;
1094  i = fp->Read(&c, 1);
1095  if ( i < 0 ) {
1096  flen = FLEN_ERROR;
1097  return 0;
1098  }
1099  flen += 1;
1100  return c;
1101 }
1102 
1103 
1104 unsigned short getU2( idFile *fp )
1105 {
1106  unsigned short i;
1107 
1108  if ( flen == FLEN_ERROR ) return 0;
1109  if ( 2 != fp->Read( &i, 2 )) {
1110  flen = FLEN_ERROR;
1111  return 0;
1112  }
1113  BigRevBytes( &i, 2, 1 );
1114  flen += 2;
1115  return i;
1116 }
1117 
1118 
1119 unsigned int getU4( idFile *fp )
1120 {
1121  unsigned int i;
1122 
1123  if ( flen == FLEN_ERROR ) return 0;
1124  if ( 4 != fp->Read( &i, 4 )) {
1125  flen = FLEN_ERROR;
1126  return 0;
1127  }
1128  BigRevBytes( &i, 4, 1 );
1129  flen += 4;
1130  return i;
1131 }
1132 
1133 
1134 int getVX( idFile *fp )
1135 {
1136  byte c;
1137  int i;
1138 
1139  if ( flen == FLEN_ERROR ) return 0;
1140 
1141  c = 0;
1142  if (fp->Read(&c, 1) == -1) {
1143  return 0;
1144  }
1145 
1146  if ( c != 0xFF ) {
1147  i = c << 8;
1148  c = 0;
1149  if (fp->Read(&c, 1) == -1) {
1150  return 0;
1151  }
1152  i |= c;
1153  flen += 2;
1154  }
1155  else {
1156  c = 0;
1157  if (fp->Read(&c, 1) == -1) {
1158  return 0;
1159  }
1160  i = c << 16;
1161  c = 0;
1162  if (fp->Read(&c, 1) == -1) {
1163  return 0;
1164  }
1165  i |= c << 8;
1166  c = 0;
1167  if (fp->Read(&c, 1) == -1) {
1168  return 0;
1169  }
1170  i |= c;
1171  flen += 4;
1172  }
1173 
1174  return i;
1175 }
1176 
1177 
1178 float getF4( idFile *fp )
1179 {
1180  float f;
1181 
1182  if ( flen == FLEN_ERROR ) return 0.0f;
1183  if ( 4 != fp->Read( &f, 4 ) ) {
1184  flen = FLEN_ERROR;
1185  return 0.0f;
1186  }
1187  BigRevBytes( &f, 4, 1 );
1188  flen += 4;
1189 
1190  if ( FLOAT_IS_DENORMAL( f ) ) {
1191  f = 0.0f;
1192  }
1193  return f;
1194 }
1195 
1196 
1197 char *getS0( idFile *fp )
1198 {
1199  char *s;
1200  int i, c, len, pos;
1201 
1202  if ( flen == FLEN_ERROR ) return NULL;
1203 
1204  pos = fp->Tell();
1205  for ( i = 1; ; i++ ) {
1206  c = 0;
1207  if (fp->Read(&c, 1) == -1) {
1208  flen = FLEN_ERROR;
1209  return NULL;
1210  }
1211  if ( c == 0 ) break;
1212  }
1213 
1214  if ( i == 1 ) {
1215  if ( fp->Seek( pos + 2, FS_SEEK_SET ))
1216  flen = FLEN_ERROR;
1217  else
1218  flen += 2;
1219  return NULL;
1220  }
1221 
1222  len = i + ( i & 1 );
1223  s = (char*)Mem_ClearedAlloc( len );
1224  if ( !s ) {
1225  flen = FLEN_ERROR;
1226  return NULL;
1227  }
1228 
1229  if ( fp->Seek( pos, FS_SEEK_SET )) {
1230  flen = FLEN_ERROR;
1231  return NULL;
1232  }
1233  if ( len != fp->Read( s, len )) {
1234  flen = FLEN_ERROR;
1235  return NULL;
1236  }
1237 
1238  flen += len;
1239  return s;
1240 }
1241 
1242 
1243 int sgetI1( unsigned char **bp )
1244 {
1245  int i;
1246 
1247  if ( flen == FLEN_ERROR ) return 0;
1248  i = **bp;
1249  if ( i > 127 ) i -= 256;
1250  flen += 1;
1251  *bp++;
1252  return i;
1253 }
1254 
1255 
1256 short sgetI2( unsigned char **bp )
1257 {
1258  short i;
1259 
1260  if ( flen == FLEN_ERROR ) return 0;
1261  memcpy( &i, *bp, 2 );
1262  BigRevBytes( &i, 2, 1 );
1263  flen += 2;
1264  *bp += 2;
1265  return i;
1266 }
1267 
1268 
1269 int sgetI4( unsigned char **bp )
1270 {
1271  int i;
1272 
1273  if ( flen == FLEN_ERROR ) return 0;
1274  memcpy( &i, *bp, 4 );
1275  BigRevBytes( &i, 4, 1 );
1276  flen += 4;
1277  *bp += 4;
1278  return i;
1279 }
1280 
1281 
1282 unsigned char sgetU1( unsigned char **bp )
1283 {
1284  unsigned char c;
1285 
1286  if ( flen == FLEN_ERROR ) return 0;
1287  c = **bp;
1288  flen += 1;
1289  *bp++;
1290  return c;
1291 }
1292 
1293 
1294 unsigned short sgetU2( unsigned char **bp )
1295 {
1296  unsigned char *buf = *bp;
1297  unsigned short i;
1298 
1299  if ( flen == FLEN_ERROR ) return 0;
1300  i = ( buf[ 0 ] << 8 ) | buf[ 1 ];
1301  flen += 2;
1302  *bp += 2;
1303  return i;
1304 }
1305 
1306 
1307 unsigned int sgetU4( unsigned char **bp )
1308 {
1309  unsigned int i;
1310 
1311  if ( flen == FLEN_ERROR ) return 0;
1312  memcpy( &i, *bp, 4 );
1313  BigRevBytes( &i, 4, 1 );
1314  flen += 4;
1315  *bp += 4;
1316  return i;
1317 }
1318 
1319 
1320 int sgetVX( unsigned char **bp )
1321 {
1322  unsigned char *buf = *bp;
1323  int i;
1324 
1325  if ( flen == FLEN_ERROR ) return 0;
1326 
1327  if ( buf[ 0 ] != 0xFF ) {
1328  i = buf[ 0 ] << 8 | buf[ 1 ];
1329  flen += 2;
1330  *bp += 2;
1331  }
1332  else {
1333  i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ];
1334  flen += 4;
1335  *bp += 4;
1336  }
1337  return i;
1338 }
1339 
1340 
1341 float sgetF4( unsigned char **bp )
1342 {
1343  float f;
1344 
1345  if ( flen == FLEN_ERROR ) return 0.0f;
1346  memcpy( &f, *bp, 4 );
1347  BigRevBytes( &f, 4, 1 );
1348  flen += 4;
1349  *bp += 4;
1350 
1351  if ( FLOAT_IS_DENORMAL( f ) ) {
1352  f = 0.0f;
1353  }
1354  return f;
1355 }
1356 
1357 
1358 char *sgetS0( unsigned char **bp )
1359 {
1360  char *s;
1361  unsigned char *buf = *bp;
1362  int len;
1363 
1364  if ( flen == FLEN_ERROR ) return NULL;
1365 
1366  len = strlen( (const char*)buf ) + 1;
1367  if ( len == 1 ) {
1368  flen += 2;
1369  *bp += 2;
1370  return NULL;
1371  }
1372  len += len & 1;
1373  s = (char*)Mem_ClearedAlloc( len );
1374  if ( !s ) {
1375  flen = FLEN_ERROR;
1376  return NULL;
1377  }
1378 
1379  memcpy( s, buf, len );
1380  flen += len;
1381  *bp += len;
1382  return s;
1383 }
1384 
1385 /*
1386 ======================================================================
1387 lwFreeLayer()
1388 
1389 Free memory used by an lwLayer.
1390 ====================================================================== */
1391 
1392 void lwFreeLayer( lwLayer *layer )
1393 {
1394  if ( layer ) {
1395  if ( layer->name ) Mem_Free( layer->name );
1396  lwFreePoints( &layer->point );
1397  lwFreePolygons( &layer->polygon );
1398  lwListFree( layer->vmap, (void (__cdecl *)(void *))lwFreeVMap );
1399  Mem_Free( layer );
1400  }
1401 }
1402 
1403 
1404 /*
1405 ======================================================================
1406 lwFreeObject()
1407 
1408 Free memory used by an lwObject.
1409 ====================================================================== */
1410 
1411 void lwFreeObject( lwObject *object )
1412 {
1413  if ( object ) {
1414  lwListFree( object->layer, (void (__cdecl *)(void *))lwFreeLayer );
1415  lwListFree( object->env, (void (__cdecl *)(void *))lwFreeEnvelope );
1416  lwListFree( object->clip, (void (__cdecl *)(void *))lwFreeClip );
1417  lwListFree( object->surf, (void (__cdecl *)(void *))lwFreeSurface );
1418  lwFreeTags( &object->taglist );
1419  Mem_Free( object );
1420  }
1421 }
1422 
1423 
1424 /*
1425 ======================================================================
1426 lwGetObject()
1427 
1428 Returns the contents of a LightWave object, given its filename, or
1429 NULL if the file couldn't be loaded. On failure, failID and failpos
1430 can be used to diagnose the cause.
1431 
1432 1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and
1433  failID will be unchanged.
1434 
1435 2. If an error occurs while reading, failID will contain the most
1436  recently read IFF chunk ID, and failpos will contain the value
1437  returned by fp->Tell() at the time of the failure.
1438 
1439 3. If the file couldn't be opened, or an error occurs while reading
1440  the first 12 bytes, both failID and failpos will be unchanged.
1441 
1442 If you don't need this information, failID and failpos can be NULL.
1443 ====================================================================== */
1444 
1445 lwObject *lwGetObject( const char *filename, unsigned int *failID, int *failpos )
1446 {
1447  idFile *fp = NULL;
1448  lwObject *object;
1449  lwLayer *layer;
1450  lwNode *node;
1451  int id, formsize, type, cksize;
1452  int i, rlen;
1453 
1454  fp = fileSystem->OpenFileRead( filename );
1455  if ( !fp ) {
1456  return NULL;
1457  }
1458 
1459  /* read the first 12 bytes */
1460 
1461  set_flen( 0 );
1462  id = getU4( fp );
1463  formsize = getU4( fp );
1464  type = getU4( fp );
1465  if ( 12 != get_flen() ) {
1466  fileSystem->CloseFile( fp );
1467  return NULL;
1468  }
1469 
1470  /* is this a LW object? */
1471 
1472  if ( id != ID_FORM ) {
1473  fileSystem->CloseFile( fp );
1474  if ( failpos ) *failpos = 12;
1475  return NULL;
1476  }
1477 
1478  if ( type != ID_LWO2 ) {
1479  fileSystem->CloseFile( fp );
1480  if ( type == ID_LWOB )
1481  return lwGetObject5( filename, failID, failpos );
1482  else {
1483  if ( failpos ) *failpos = 12;
1484  return NULL;
1485  }
1486  }
1487 
1488  /* allocate an object and a default layer */
1489 
1490  object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
1491  if ( !object ) goto Fail;
1492 
1493  layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
1494  if ( !layer ) goto Fail;
1495  object->layer = layer;
1496 
1497  object->timeStamp = fp->Timestamp();
1498 
1499  /* get the first chunk header */
1500 
1501  id = getU4( fp );
1502  cksize = getU4( fp );
1503  if ( 0 > get_flen() ) goto Fail;
1504 
1505  /* process chunks as they're encountered */
1506 
1507  while ( 1 ) {
1508  cksize += cksize & 1;
1509 
1510  switch ( id )
1511  {
1512  case ID_LAYR:
1513  if ( object->nlayers > 0 ) {
1514  layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
1515  if ( !layer ) goto Fail;
1516  lwListAdd( (void**)&object->layer, layer );
1517  }
1518  object->nlayers++;
1519 
1520  set_flen( 0 );
1521  layer->index = getU2( fp );
1522  layer->flags = getU2( fp );
1523  layer->pivot[ 0 ] = getF4( fp );
1524  layer->pivot[ 1 ] = getF4( fp );
1525  layer->pivot[ 2 ] = getF4( fp );
1526  layer->name = getS0( fp );
1527 
1528  rlen = get_flen();
1529  if ( rlen < 0 || rlen > cksize ) goto Fail;
1530  if ( rlen <= cksize - 2 )
1531  layer->parent = getU2( fp );
1532  rlen = get_flen();
1533  if ( rlen < cksize )
1534  fp->Seek( cksize - rlen, FS_SEEK_CUR );
1535  break;
1536 
1537  case ID_PNTS:
1538  if ( !lwGetPoints( fp, cksize, &layer->point ))
1539  goto Fail;
1540  break;
1541 
1542  case ID_POLS:
1543  if ( !lwGetPolygons( fp, cksize, &layer->polygon,
1544  layer->point.offset ))
1545  goto Fail;
1546  break;
1547 
1548  case ID_VMAP:
1549  case ID_VMAD:
1550  node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset,
1551  layer->polygon.offset, id == ID_VMAD );
1552  if ( !node ) goto Fail;
1553  lwListAdd( (void**)&layer->vmap, node );
1554  layer->nvmaps++;
1555  break;
1556 
1557  case ID_PTAG:
1558  if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
1559  &layer->polygon ))
1560  goto Fail;
1561  break;
1562 
1563  case ID_BBOX:
1564  set_flen( 0 );
1565  for ( i = 0; i < 6; i++ )
1566  layer->bbox[ i ] = getF4( fp );
1567  rlen = get_flen();
1568  if ( rlen < 0 || rlen > cksize ) goto Fail;
1569  if ( rlen < cksize )
1570  fp->Seek( cksize - rlen, FS_SEEK_CUR );
1571  break;
1572 
1573  case ID_TAGS:
1574  if ( !lwGetTags( fp, cksize, &object->taglist ))
1575  goto Fail;
1576  break;
1577 
1578  case ID_ENVL:
1579  node = ( lwNode * ) lwGetEnvelope( fp, cksize );
1580  if ( !node ) goto Fail;
1581  lwListAdd( (void**)&object->env, node );
1582  object->nenvs++;
1583  break;
1584 
1585  case ID_CLIP:
1586  node = ( lwNode * ) lwGetClip( fp, cksize );
1587  if ( !node ) goto Fail;
1588  lwListAdd( (void**)&object->clip, node );
1589  object->nclips++;
1590  break;
1591 
1592  case ID_SURF:
1593  node = ( lwNode * ) lwGetSurface( fp, cksize );
1594  if ( !node ) goto Fail;
1595  lwListAdd( (void**)&object->surf, node );
1596  object->nsurfs++;
1597  break;
1598 
1599  case ID_DESC:
1600  case ID_TEXT:
1601  case ID_ICON:
1602  default:
1603  fp->Seek( cksize, FS_SEEK_CUR );
1604  break;
1605  }
1606 
1607  /* end of the file? */
1608 
1609  if ( formsize <= fp->Tell() - 8 ) break;
1610 
1611  /* get the next chunk header */
1612 
1613  set_flen( 0 );
1614  id = getU4( fp );
1615  cksize = getU4( fp );
1616  if ( 8 != get_flen() ) goto Fail;
1617  }
1618 
1619  fileSystem->CloseFile( fp );
1620  fp = NULL;
1621 
1622  if ( object->nlayers == 0 )
1623  object->nlayers = 1;
1624 
1625  layer = object->layer;
1626  while ( layer ) {
1627  lwGetBoundingBox( &layer->point, layer->bbox );
1628  lwGetPolyNormals( &layer->point, &layer->polygon );
1629  if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
1630  if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
1631  &object->surf, &object->nsurfs )) goto Fail;
1632  lwGetVertNormals( &layer->point, &layer->polygon );
1633  if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail;
1634  if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail;
1635  layer = layer->next;
1636  }
1637 
1638  return object;
1639 
1640 Fail:
1641  if ( failID ) *failID = id;
1642  if ( fp ) {
1643  if ( failpos ) *failpos = fp->Tell();
1644  fileSystem->CloseFile( fp );
1645  }
1646  lwFreeObject( object );
1647  return NULL;
1648 }
1649 
1650 
1651 
1652 
1653 /* IDs specific to LWOB */
1654 
1655 #define ID_SRFS LWID_('S','R','F','S')
1656 #define ID_FLAG LWID_('F','L','A','G')
1657 #define ID_VLUM LWID_('V','L','U','M')
1658 #define ID_VDIF LWID_('V','D','I','F')
1659 #define ID_VSPC LWID_('V','S','P','C')
1660 #define ID_RFLT LWID_('R','F','L','T')
1661 #define ID_BTEX LWID_('B','T','E','X')
1662 #define ID_CTEX LWID_('C','T','E','X')
1663 #define ID_DTEX LWID_('D','T','E','X')
1664 #define ID_LTEX LWID_('L','T','E','X')
1665 #define ID_RTEX LWID_('R','T','E','X')
1666 #define ID_STEX LWID_('S','T','E','X')
1667 #define ID_TTEX LWID_('T','T','E','X')
1668 #define ID_TFLG LWID_('T','F','L','G')
1669 #define ID_TSIZ LWID_('T','S','I','Z')
1670 #define ID_TCTR LWID_('T','C','T','R')
1671 #define ID_TFAL LWID_('T','F','A','L')
1672 #define ID_TVEL LWID_('T','V','E','L')
1673 #define ID_TCLR LWID_('T','C','L','R')
1674 #define ID_TVAL LWID_('T','V','A','L')
1675 #define ID_TAMP LWID_('T','A','M','P')
1676 #define ID_TIMG LWID_('T','I','M','G')
1677 #define ID_TAAS LWID_('T','A','A','S')
1678 #define ID_TREF LWID_('T','R','E','F')
1679 #define ID_TOPC LWID_('T','O','P','C')
1680 #define ID_SDAT LWID_('S','D','A','T')
1681 #define ID_TFP0 LWID_('T','F','P','0')
1682 #define ID_TFP1 LWID_('T','F','P','1')
1683 
1684 
1685 /*
1686 ======================================================================
1687 add_clip()
1688 
1689 Add a clip to the clip list. Used to store the contents of an RIMG or
1690 TIMG surface subchunk.
1691 ====================================================================== */
1692 
1693 static int add_clip( char *s, lwClip **clist, int *nclips )
1694 {
1695  lwClip *clip;
1696  char *p;
1697 
1698  clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
1699  if ( !clip ) return 0;
1700 
1701  clip->contrast.val = 1.0f;
1702  clip->brightness.val = 1.0f;
1703  clip->saturation.val = 1.0f;
1704  clip->gamma.val = 1.0f;
1705 
1706  if ( p = strstr( s, "(sequence)" )) {
1707  p[ -1 ] = 0;
1708  clip->type = ID_ISEQ;
1709  clip->source.seq.prefix = s;
1710  clip->source.seq.digits = 3;
1711  }
1712  else {
1713  clip->type = ID_STIL;
1714  clip->source.still.name = s;
1715  }
1716 
1717  *nclips++;
1718  clip->index = *nclips;
1719 
1720  lwListAdd( (void**)clist, clip );
1721 
1722  return clip->index;
1723 }
1724 
1725 
1726 /*
1727 ======================================================================
1728 add_tvel()
1729 
1730 Add a triple of envelopes to simulate the old texture velocity
1731 parameters.
1732 ====================================================================== */
1733 
1734 static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs )
1735 {
1736  lwEnvelope *env;
1737  lwKey *key0, *key1;
1738  int i;
1739 
1740  for ( i = 0; i < 3; i++ ) {
1741  env = (lwEnvelope*)Mem_ClearedAlloc( sizeof( lwEnvelope ) );
1742  key0 = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
1743  key1 = (lwKey*)Mem_ClearedAlloc( sizeof( lwKey ) );
1744  if ( !env || !key0 || !key1 ) return 0;
1745 
1746  key0->next = key1;
1747  key0->value = pos[ i ];
1748  key0->time = 0.0f;
1749  key1->prev = key0;
1750  key1->value = pos[ i ] + vel[ i ] * 30.0f;
1751  key1->time = 1.0f;
1752  key0->shape = key1->shape = ID_LINE;
1753 
1754  env->index = *nenvs + i + 1;
1755  env->type = 0x0301 + i;
1756  env->name = (char*)Mem_ClearedAlloc( 11 );
1757  if ( env->name ) {
1758  strcpy( env->name, "Position.X" );
1759  env->name[ 9 ] += i;
1760  }
1761  env->key = key0;
1762  env->nkeys = 2;
1763  env->behavior[ 0 ] = BEH_LINEAR;
1764  env->behavior[ 1 ] = BEH_LINEAR;
1765 
1766  lwListAdd( (void**)elist, env );
1767  }
1768 
1769  *nenvs += 3;
1770  return env->index - 2;
1771 }
1772 
1773 
1774 /*
1775 ======================================================================
1776 get_texture()
1777 
1778 Create a new texture for BTEX, CTEX, etc. subchunks.
1779 ====================================================================== */
1780 
1781 static lwTexture *get_texture( char *s )
1782 {
1783  lwTexture *tex;
1784 
1785  tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
1786  if ( !tex ) return NULL;
1787 
1788  tex->tmap.size.val[ 0 ] =
1789  tex->tmap.size.val[ 1 ] =
1790  tex->tmap.size.val[ 2 ] = 1.0f;
1791  tex->opacity.val = 1.0f;
1792  tex->enabled = 1;
1793 
1794  if ( strstr( s, "Image Map" )) {
1795  tex->type = ID_IMAP;
1796  if ( strstr( s, "Planar" )) tex->param.imap.projection = 0;
1797  else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1;
1798  else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2;
1799  else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3;
1800  else if ( strstr( s, "Front" )) tex->param.imap.projection = 4;
1801  tex->param.imap.aa_strength = 1.0f;
1802  tex->param.imap.amplitude.val = 1.0f;
1803  Mem_Free( s );
1804  }
1805  else {
1806  tex->type = ID_PROC;
1807  tex->param.proc.name = s;
1808  }
1809 
1810  return tex;
1811 }
1812 
1813 
1814 /*
1815 ======================================================================
1816 lwGetSurface5()
1817 
1818 Read an lwSurface from an LWOB file.
1819 ====================================================================== */
1820 
1822 {
1823  lwSurface *surf;
1824  lwTexture *tex;
1825  lwPlugin *shdr;
1826  char *s;
1827  float v[ 3 ];
1828  unsigned int id, flags;
1829  unsigned short sz;
1830  int pos, rlen, i;
1831 
1832 
1833  /* allocate the Surface structure */
1834 
1835  surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
1836  if ( !surf ) goto Fail;
1837 
1838  /* non-zero defaults */
1839 
1840  surf->color.rgb[ 0 ] = 0.78431f;
1841  surf->color.rgb[ 1 ] = 0.78431f;
1842  surf->color.rgb[ 2 ] = 0.78431f;
1843  surf->diffuse.val = 1.0f;
1844  surf->glossiness.val = 0.4f;
1845  surf->bump.val = 1.0f;
1846  surf->eta.val = 1.0f;
1847  surf->sideflags = 1;
1848 
1849  /* remember where we started */
1850 
1851  set_flen( 0 );
1852  pos = fp->Tell();
1853 
1854  /* name */
1855 
1856  surf->name = getS0( fp );
1857 
1858  /* first subchunk header */
1859 
1860  id = getU4( fp );
1861  sz = getU2( fp );
1862  if ( 0 > get_flen() ) goto Fail;
1863 
1864  /* process subchunks as they're encountered */
1865 
1866  while ( 1 ) {
1867  sz += sz & 1;
1868  set_flen( 0 );
1869 
1870  switch ( id ) {
1871  case ID_COLR:
1872  surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
1873  surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
1874  surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
1875  break;
1876 
1877  case ID_FLAG:
1878  flags = getU2( fp );
1879  if ( flags & 4 ) surf->smooth = 1.56207f;
1880  if ( flags & 8 ) surf->color_hilite.val = 1.0f;
1881  if ( flags & 16 ) surf->color_filter.val = 1.0f;
1882  if ( flags & 128 ) surf->dif_sharp.val = 0.5f;
1883  if ( flags & 256 ) surf->sideflags = 3;
1884  if ( flags & 512 ) surf->add_trans.val = 1.0f;
1885  break;
1886 
1887  case ID_LUMI:
1888  surf->luminosity.val = getI2( fp ) / 256.0f;
1889  break;
1890 
1891  case ID_VLUM:
1892  surf->luminosity.val = getF4( fp );
1893  break;
1894 
1895  case ID_DIFF:
1896  surf->diffuse.val = getI2( fp ) / 256.0f;
1897  break;
1898 
1899  case ID_VDIF:
1900  surf->diffuse.val = getF4( fp );
1901  break;
1902 
1903  case ID_SPEC:
1904  surf->specularity.val = getI2( fp ) / 256.0f;
1905  break;
1906 
1907  case ID_VSPC:
1908  surf->specularity.val = getF4( fp );
1909  break;
1910 
1911  case ID_GLOS:
1912  surf->glossiness.val = ( float ) logf( ( float) getU2( fp )) / 20.7944f;
1913  break;
1914 
1915  case ID_SMAN:
1916  surf->smooth = getF4( fp );
1917  break;
1918 
1919  case ID_REFL:
1920  surf->reflection.val.val = getI2( fp ) / 256.0f;
1921  break;
1922 
1923  case ID_RFLT:
1924  surf->reflection.options = getU2( fp );
1925  break;
1926 
1927  case ID_RIMG:
1928  s = getS0( fp );
1929  surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
1930  surf->reflection.options = 3;
1931  break;
1932 
1933  case ID_RSAN:
1934  surf->reflection.seam_angle = getF4( fp );
1935  break;
1936 
1937  case ID_TRAN:
1938  surf->transparency.val.val = getI2( fp ) / 256.0f;
1939  break;
1940 
1941  case ID_RIND:
1942  surf->eta.val = getF4( fp );
1943  break;
1944 
1945  case ID_BTEX:
1946  s = (char*)getbytes( fp, sz );
1947  tex = get_texture( s );
1948  lwListAdd( (void**)&surf->bump.tex, tex );
1949  break;
1950 
1951  case ID_CTEX:
1952  s = (char*)getbytes( fp, sz );
1953  tex = get_texture( s );
1954  lwListAdd( (void**)&surf->color.tex, tex );
1955  break;
1956 
1957  case ID_DTEX:
1958  s = (char*)getbytes( fp, sz );
1959  tex = get_texture( s );
1960  lwListAdd( (void**)&surf->diffuse.tex, tex );
1961  break;
1962 
1963  case ID_LTEX:
1964  s = (char*)getbytes( fp, sz );
1965  tex = get_texture( s );
1966  lwListAdd( (void**)&surf->luminosity.tex, tex );
1967  break;
1968 
1969  case ID_RTEX:
1970  s = (char*)getbytes( fp, sz );
1971  tex = get_texture( s );
1972  lwListAdd( (void**)&surf->reflection.val.tex, tex );
1973  break;
1974 
1975  case ID_STEX:
1976  s = (char*)getbytes( fp, sz );
1977  tex = get_texture( s );
1978  lwListAdd( (void**)&surf->specularity.tex, tex );
1979  break;
1980 
1981  case ID_TTEX:
1982  s = (char*)getbytes( fp, sz );
1983  tex = get_texture( s );
1984  lwListAdd( (void**)&surf->transparency.val.tex, tex );
1985  break;
1986 
1987  case ID_TFLG:
1988  flags = getU2( fp );
1989 
1990  if ( flags & 1 ) i = 0;
1991  if ( flags & 2 ) i = 1;
1992  if ( flags & 4 ) i = 2;
1993  tex->axis = i;
1994  if ( tex->type == ID_IMAP )
1995  tex->param.imap.axis = i;
1996  else
1997  tex->param.proc.axis = i;
1998 
1999  if ( flags & 8 ) tex->tmap.coord_sys = 1;
2000  if ( flags & 16 ) tex->negative = 1;
2001  if ( flags & 32 ) tex->param.imap.pblend = 1;
2002  if ( flags & 64 ) {
2003  tex->param.imap.aa_strength = 1.0f;
2004  tex->param.imap.aas_flags = 1;
2005  }
2006  break;
2007 
2008  case ID_TSIZ:
2009  for ( i = 0; i < 3; i++ )
2010  tex->tmap.size.val[ i ] = getF4( fp );
2011  break;
2012 
2013  case ID_TCTR:
2014  for ( i = 0; i < 3; i++ )
2015  tex->tmap.center.val[ i ] = getF4( fp );
2016  break;
2017 
2018  case ID_TFAL:
2019  for ( i = 0; i < 3; i++ )
2020  tex->tmap.falloff.val[ i ] = getF4( fp );
2021  break;
2022 
2023  case ID_TVEL:
2024  for ( i = 0; i < 3; i++ )
2025  v[ i ] = getF4( fp );
2026  tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
2027  &obj->env, &obj->nenvs );
2028  break;
2029 
2030  case ID_TCLR:
2031  if ( tex->type == ID_PROC )
2032  for ( i = 0; i < 3; i++ )
2033  tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
2034  break;
2035 
2036  case ID_TVAL:
2037  tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
2038  break;
2039 
2040  case ID_TAMP:
2041  if ( tex->type == ID_IMAP )
2042  tex->param.imap.amplitude.val = getF4( fp );
2043  break;
2044 
2045  case ID_TIMG:
2046  s = getS0( fp );
2047  tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
2048  break;
2049 
2050  case ID_TAAS:
2051  tex->param.imap.aa_strength = getF4( fp );
2052  tex->param.imap.aas_flags = 1;
2053  break;
2054 
2055  case ID_TREF:
2056  tex->tmap.ref_object = (char*)getbytes( fp, sz );
2057  break;
2058 
2059  case ID_TOPC:
2060  tex->opacity.val = getF4( fp );
2061  break;
2062 
2063  case ID_TFP0:
2064  if ( tex->type == ID_IMAP )
2065  tex->param.imap.wrapw.val = getF4( fp );
2066  break;
2067 
2068  case ID_TFP1:
2069  if ( tex->type == ID_IMAP )
2070  tex->param.imap.wraph.val = getF4( fp );
2071  break;
2072 
2073  case ID_SHDR:
2074  shdr = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
2075  if ( !shdr ) goto Fail;
2076  shdr->name = (char*)getbytes( fp, sz );
2077  lwListAdd( (void**)&surf->shader, shdr );
2078  surf->nshaders++;
2079  break;
2080 
2081  case ID_SDAT:
2082  shdr->data = getbytes( fp, sz );
2083  break;
2084 
2085  default:
2086  break;
2087  }
2088 
2089  /* error while reading current subchunk? */
2090 
2091  rlen = get_flen();
2092  if ( rlen < 0 || rlen > sz ) goto Fail;
2093 
2094  /* skip unread parts of the current subchunk */
2095 
2096  if ( rlen < sz )
2097  fp->Seek( sz - rlen, FS_SEEK_CUR );
2098 
2099  /* end of the SURF chunk? */
2100 
2101  if ( cksize <= fp->Tell() - pos )
2102  break;
2103 
2104  /* get the next subchunk header */
2105 
2106  set_flen( 0 );
2107  id = getU4( fp );
2108  sz = getU2( fp );
2109  if ( 6 != get_flen() ) goto Fail;
2110  }
2111 
2112  return surf;
2113 
2114 Fail:
2115  if ( surf ) lwFreeSurface( surf );
2116  return NULL;
2117 }
2118 
2119 
2120 /*
2121 ======================================================================
2122 lwGetPolygons5()
2123 
2124 Read polygon records from a POLS chunk in an LWOB file. The polygons
2125 are added to the array in the lwPolygonList.
2126 ====================================================================== */
2127 
2128 int lwGetPolygons5( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
2129 {
2130  lwPolygon *pp;
2131  lwPolVert *pv;
2132  unsigned char *buf, *bp;
2133  int i, j, nv, nverts, npols;
2134 
2135 
2136  if ( cksize == 0 ) return 1;
2137 
2138  /* read the whole chunk */
2139 
2140  set_flen( 0 );
2141  buf = (unsigned char*)getbytes( fp, cksize );
2142  if ( !buf ) goto Fail;
2143 
2144  /* count the polygons and vertices */
2145 
2146  nverts = 0;
2147  npols = 0;
2148  bp = buf;
2149 
2150  while ( bp < buf + cksize ) {
2151  nv = sgetU2( &bp );
2152  nverts += nv;
2153  npols++;
2154  bp += 2 * nv;
2155  i = sgetI2( &bp );
2156  if ( i < 0 ) bp += 2; /* detail polygons */
2157  }
2158 
2159  if ( !lwAllocPolygons( plist, npols, nverts ))
2160  goto Fail;
2161 
2162  /* fill in the new polygons */
2163 
2164  bp = buf;
2165  pp = plist->pol + plist->offset;
2166  pv = plist->pol[ 0 ].v + plist->voffset;
2167 
2168  for ( i = 0; i < npols; i++ ) {
2169  nv = sgetU2( &bp );
2170 
2171  pp->nverts = nv;
2172  pp->type = ID_FACE;
2173  if ( !pp->v ) pp->v = pv;
2174  for ( j = 0; j < nv; j++ )
2175  pv[ j ].index = sgetU2( &bp ) + ptoffset;
2176  j = sgetI2( &bp );
2177  if ( j < 0 ) {
2178  j = -j;
2179  bp += 2;
2180  }
2181  j -= 1;
2182  pp->surf = ( lwSurface * ) j;
2183 
2184  pp++;
2185  pv += nv;
2186  }
2187 
2188  Mem_Free( buf );
2189  return 1;
2190 
2191 Fail:
2192  if ( buf ) Mem_Free( buf );
2193  lwFreePolygons( plist );
2194  return 0;
2195 }
2196 
2197 
2198 /*
2199 ======================================================================
2200 getLWObject5()
2201 
2202 Returns the contents of an LWOB, given its filename, or NULL if the
2203 file couldn't be loaded. On failure, failID and failpos can be used
2204 to diagnose the cause.
2205 
2206 1. If the file isn't an LWOB, failpos will contain 12 and failID will
2207  be unchanged.
2208 
2209 2. If an error occurs while reading an LWOB, failID will contain the
2210  most recently read IFF chunk ID, and failpos will contain the
2211  value returned by fp->Tell() at the time of the failure.
2212 
2213 3. If the file couldn't be opened, or an error occurs while reading
2214  the first 12 bytes, both failID and failpos will be unchanged.
2215 
2216 If you don't need this information, failID and failpos can be NULL.
2217 ====================================================================== */
2218 
2219 lwObject *lwGetObject5( const char *filename, unsigned int *failID, int *failpos )
2220 {
2221  idFile *fp = NULL;
2222  lwObject *object;
2223  lwLayer *layer;
2224  lwNode *node;
2225  int id, formsize, type, cksize;
2226 
2227 
2228  /* open the file */
2229 
2230  //fp = fopen( filename, "rb" );
2231  //if ( !fp ) return NULL;
2232 
2233  /* read the first 12 bytes */
2234  fp = fileSystem->OpenFileRead( filename );
2235  if ( !fp ) {
2236  return NULL;
2237  }
2238 
2239  set_flen( 0 );
2240  id = getU4( fp );
2241  formsize = getU4( fp );
2242  type = getU4( fp );
2243  if ( 12 != get_flen() ) {
2244  fileSystem->CloseFile( fp );
2245  return NULL;
2246  }
2247 
2248  /* LWOB? */
2249 
2250  if ( id != ID_FORM || type != ID_LWOB ) {
2251  fileSystem->CloseFile( fp );
2252  if ( failpos ) *failpos = 12;
2253  return NULL;
2254  }
2255 
2256  /* allocate an object and a default layer */
2257 
2258  object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
2259  if ( !object ) goto Fail2;
2260 
2261  layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
2262  if ( !layer ) goto Fail2;
2263  object->layer = layer;
2264  object->nlayers = 1;
2265 
2266  /* get the first chunk header */
2267 
2268  id = getU4( fp );
2269  cksize = getU4( fp );
2270  if ( 0 > get_flen() ) goto Fail2;
2271 
2272  /* process chunks as they're encountered */
2273 
2274  while ( 1 ) {
2275  cksize += cksize & 1;
2276 
2277  switch ( id )
2278  {
2279  case ID_PNTS:
2280  if ( !lwGetPoints( fp, cksize, &layer->point ))
2281  goto Fail2;
2282  break;
2283 
2284  case ID_POLS:
2285  if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
2286  layer->point.offset ))
2287  goto Fail2;
2288  break;
2289 
2290  case ID_SRFS:
2291  if ( !lwGetTags( fp, cksize, &object->taglist ))
2292  goto Fail2;
2293  break;
2294 
2295  case ID_SURF:
2296  node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
2297  if ( !node ) goto Fail2;
2298  lwListAdd( (void**)&object->surf, node );
2299  object->nsurfs++;
2300  break;
2301 
2302  default:
2303  fp->Seek( cksize, FS_SEEK_CUR );
2304  break;
2305  }
2306 
2307  /* end of the file? */
2308 
2309  if ( formsize <= fp->Tell() - 8 ) break;
2310 
2311  /* get the next chunk header */
2312 
2313  set_flen( 0 );
2314  id = getU4( fp );
2315  cksize = getU4( fp );
2316  if ( 8 != get_flen() ) goto Fail2;
2317  }
2318 
2319  fileSystem->CloseFile( fp );
2320  fp = NULL;
2321 
2322  lwGetBoundingBox( &layer->point, layer->bbox );
2323  lwGetPolyNormals( &layer->point, &layer->polygon );
2324  if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail2;
2325  if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
2326  &object->surf, &object->nsurfs )) goto Fail2;
2327  lwGetVertNormals( &layer->point, &layer->polygon );
2328 
2329  return object;
2330 
2331 Fail2:
2332  if ( failID ) *failID = id;
2333  if ( fp ) {
2334  if ( failpos ) *failpos = fp->Tell();
2335  fileSystem->CloseFile( fp );
2336  }
2337  lwFreeObject( object );
2338  return NULL;
2339 }
2340 
2341 /*
2342 ======================================================================
2343 lwFreePoints()
2344 
2345 Free the memory used by an lwPointList.
2346 ====================================================================== */
2347 
2349 {
2350  int i;
2351 
2352  if ( point ) {
2353  if ( point->pt ) {
2354  for ( i = 0; i < point->count; i++ ) {
2355  if ( point->pt[ i ].pol ) Mem_Free( point->pt[ i ].pol );
2356  if ( point->pt[ i ].vm ) Mem_Free( point->pt[ i ].vm );
2357  }
2358  Mem_Free( point->pt );
2359  }
2360  memset( point, 0, sizeof( lwPointList ));
2361  }
2362 }
2363 
2364 
2365 /*
2366 ======================================================================
2367 lwFreePolygons()
2368 
2369 Free the memory used by an lwPolygonList.
2370 ====================================================================== */
2371 
2373 {
2374  int i, j;
2375 
2376  if ( plist ) {
2377  if ( plist->pol ) {
2378  for ( i = 0; i < plist->count; i++ ) {
2379  if ( plist->pol[ i ].v ) {
2380  for ( j = 0; j < plist->pol[ i ].nverts; j++ )
2381  if ( plist->pol[ i ].v[ j ].vm )
2382  Mem_Free( plist->pol[ i ].v[ j ].vm );
2383  }
2384  }
2385  if ( plist->pol[ 0 ].v )
2386  Mem_Free( plist->pol[ 0 ].v );
2387  Mem_Free( plist->pol );
2388  }
2389  memset( plist, 0, sizeof( lwPolygonList ));
2390  }
2391 }
2392 
2393 
2394 /*
2395 ======================================================================
2396 lwGetPoints()
2397 
2398 Read point records from a PNTS chunk in an LWO2 file. The points are
2399 added to the array in the lwPointList.
2400 ====================================================================== */
2401 
2402 int lwGetPoints( idFile *fp, int cksize, lwPointList *point )
2403 {
2404  float *f;
2405  int np, i, j;
2406 
2407  if ( cksize == 1 ) return 1;
2408 
2409  /* extend the point array to hold the new points */
2410 
2411  np = cksize / 12;
2412  point->offset = point->count;
2413  point->count += np;
2414  lwPoint *oldpt = point->pt;
2415  point->pt = (lwPoint*)Mem_Alloc( point->count * sizeof( lwPoint ) );
2416  if ( !point->pt ) return 0;
2417  if ( oldpt ) {
2418  memcpy( point->pt, oldpt, point->offset * sizeof( lwPoint ) );
2419  Mem_Free( oldpt );
2420  }
2421  memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint ) );
2422 
2423  /* read the whole chunk */
2424 
2425  f = ( float * ) getbytes( fp, cksize );
2426  if ( !f ) return 0;
2427  BigRevBytes( f, 4, np * 3 );
2428 
2429  /* assign position values */
2430 
2431  for ( i = 0, j = 0; i < np; i++, j += 3 ) {
2432  point->pt[ i ].pos[ 0 ] = f[ j ];
2433  point->pt[ i ].pos[ 1 ] = f[ j + 1 ];
2434  point->pt[ i ].pos[ 2 ] = f[ j + 2 ];
2435  }
2436 
2437  Mem_Free( f );
2438  return 1;
2439 }
2440 
2441 
2442 /*
2443 ======================================================================
2444 lwGetBoundingBox()
2445 
2446 Calculate the bounding box for a point list, but only if the bounding
2447 box hasn't already been initialized.
2448 ====================================================================== */
2449 
2450 void lwGetBoundingBox( lwPointList *point, float bbox[] )
2451 {
2452  int i, j;
2453 
2454  if ( point->count == 0 ) return;
2455 
2456  for ( i = 0; i < 6; i++ )
2457  if ( bbox[ i ] != 0.0f ) return;
2458 
2459  bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f;
2460  bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f;
2461  for ( i = 0; i < point->count; i++ ) {
2462  for ( j = 0; j < 3; j++ ) {
2463  if ( bbox[ j ] > point->pt[ i ].pos[ j ] )
2464  bbox[ j ] = point->pt[ i ].pos[ j ];
2465  if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] )
2466  bbox[ j + 3 ] = point->pt[ i ].pos[ j ];
2467  }
2468  }
2469 }
2470 
2471 
2472 /*
2473 ======================================================================
2474 lwAllocPolygons()
2475 
2476 Allocate or extend the polygon arrays to hold new records.
2477 ====================================================================== */
2478 
2479 int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts )
2480 {
2481  int i;
2482 
2483  plist->offset = plist->count;
2484  plist->count += npols;
2485  lwPolygon *oldpol = plist->pol;
2486  plist->pol = (lwPolygon*)Mem_Alloc( plist->count * sizeof( lwPolygon ) );
2487  if ( !plist->pol ) return 0;
2488  if ( oldpol ) {
2489  memcpy( plist->pol, oldpol, plist->offset * sizeof( lwPolygon ) );
2490  Mem_Free( oldpol );
2491  }
2492  memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon ) );
2493 
2494  plist->voffset = plist->vcount;
2495  plist->vcount += nverts;
2496  lwPolVert *oldpolv = plist->pol[0].v;
2497  plist->pol[0].v = (lwPolVert*)Mem_Alloc( plist->vcount * sizeof( lwPolVert ) );
2498  if ( !plist->pol[ 0 ].v ) return 0;
2499  if ( oldpolv ) {
2500  memcpy( plist->pol[0].v, oldpolv, plist->voffset * sizeof( lwPolVert ) );
2501  Mem_Free( oldpolv );
2502  }
2503  memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert ) );
2504 
2505  /* fix up the old vertex pointers */
2506 
2507  for ( i = 1; i < plist->offset; i++ )
2508  plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts;
2509 
2510  return 1;
2511 }
2512 
2513 
2514 /*
2515 ======================================================================
2516 lwGetPolygons()
2517 
2518 Read polygon records from a POLS chunk in an LWO2 file. The polygons
2519 are added to the array in the lwPolygonList.
2520 ====================================================================== */
2521 
2522 int lwGetPolygons( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
2523 {
2524  lwPolygon *pp;
2525  lwPolVert *pv;
2526  unsigned char *buf, *bp;
2527  int i, j, flags, nv, nverts, npols;
2528  unsigned int type;
2529 
2530 
2531  if ( cksize == 0 ) return 1;
2532 
2533  /* read the whole chunk */
2534 
2535  set_flen( 0 );
2536  type = getU4( fp );
2537  buf = (unsigned char*)getbytes( fp, cksize - 4 );
2538  if ( cksize != get_flen() ) goto Fail;
2539 
2540  /* count the polygons and vertices */
2541 
2542  nverts = 0;
2543  npols = 0;
2544  bp = buf;
2545 
2546  while ( bp < buf + cksize - 4 ) {
2547  nv = sgetU2( &bp );
2548  nv &= 0x03FF;
2549  nverts += nv;
2550  npols++;
2551  for ( i = 0; i < nv; i++ )
2552  j = sgetVX( &bp );
2553  }
2554 
2555  if ( !lwAllocPolygons( plist, npols, nverts ))
2556  goto Fail;
2557 
2558  /* fill in the new polygons */
2559 
2560  bp = buf;
2561  pp = plist->pol + plist->offset;
2562  pv = plist->pol[ 0 ].v + plist->voffset;
2563 
2564  for ( i = 0; i < npols; i++ ) {
2565  nv = sgetU2( &bp );
2566  flags = nv & 0xFC00;
2567  nv &= 0x03FF;
2568 
2569  pp->nverts = nv;
2570  pp->flags = flags;
2571  pp->type = type;
2572  if ( !pp->v ) pp->v = pv;
2573  for ( j = 0; j < nv; j++ )
2574  pp->v[ j ].index = sgetVX( &bp ) + ptoffset;
2575 
2576  pp++;
2577  pv += nv;
2578  }
2579 
2580  Mem_Free( buf );
2581  return 1;
2582 
2583 Fail:
2584  if ( buf ) Mem_Free( buf );
2585  lwFreePolygons( plist );
2586  return 0;
2587 }
2588 
2589 
2590 /*
2591 ======================================================================
2592 lwGetPolyNormals()
2593 
2594 Calculate the polygon normals. By convention, LW's polygon normals
2595 are found as the cross product of the first and last edges. It's
2596 undefined for one- and two-point polygons.
2597 ====================================================================== */
2598 
2600 {
2601  int i, j;
2602  float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ];
2603 
2604  for ( i = 0; i < polygon->count; i++ ) {
2605  if ( polygon->pol[ i ].nverts < 3 ) continue;
2606  for ( j = 0; j < 3; j++ ) {
2607 
2608  // FIXME: track down why indexes are way out of range
2609  p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ];
2610  p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ];
2611  pn[ j ] = point->pt[ polygon->pol[ i ].v[ polygon->pol[ i ].nverts - 1 ].index ].pos[ j ];
2612  }
2613 
2614  for ( j = 0; j < 3; j++ ) {
2615  v1[ j ] = p2[ j ] - p1[ j ];
2616  v2[ j ] = pn[ j ] - p1[ j ];
2617  }
2618 
2619  cross( v1, v2, polygon->pol[ i ].norm );
2620  normalize( polygon->pol[ i ].norm );
2621  }
2622 }
2623 
2624 
2625 /*
2626 ======================================================================
2627 lwGetPointPolygons()
2628 
2629 For each point, fill in the indexes of the polygons that share the
2630 point. Returns 0 if any of the memory allocations fail, otherwise
2631 returns 1.
2632 ====================================================================== */
2633 
2635 {
2636  int i, j, k;
2637 
2638  /* count the number of polygons per point */
2639 
2640  for ( i = 0; i < polygon->count; i++ )
2641  for ( j = 0; j < polygon->pol[ i ].nverts; j++ )
2642  ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols;
2643 
2644  /* alloc per-point polygon arrays */
2645 
2646  for ( i = 0; i < point->count; i++ ) {
2647  if ( point->pt[ i ].npols == 0 ) continue;
2648  point->pt[ i ].pol = (int*)Mem_ClearedAlloc( point->pt[ i ].npols * sizeof( int ) );
2649  if ( !point->pt[ i ].pol ) return 0;
2650  point->pt[ i ].npols = 0;
2651  }
2652 
2653  /* fill in polygon array for each point */
2654 
2655  for ( i = 0; i < polygon->count; i++ ) {
2656  for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
2657  k = polygon->pol[ i ].v[ j ].index;
2658  point->pt[ k ].pol[ point->pt[ k ].npols ] = i;
2659  ++point->pt[ k ].npols;
2660  }
2661  }
2662 
2663  return 1;
2664 }
2665 
2666 
2667 /*
2668 ======================================================================
2669 lwResolvePolySurfaces()
2670 
2671 Convert tag indexes into actual lwSurface pointers. If any polygons
2672 point to tags for which no corresponding surface can be found, a
2673 default surface is created.
2674 ====================================================================== */
2675 
2677  lwSurface **surf, int *nsurfs )
2678 {
2679  lwSurface **s, *st;
2680  int i, index;
2681 
2682  if ( tlist->count == 0 ) return 1;
2683 
2684  s = (lwSurface**)Mem_ClearedAlloc( tlist->count * sizeof( lwSurface * ) );
2685  if ( !s ) return 0;
2686 
2687  for ( i = 0; i < tlist->count; i++ ) {
2688  st = *surf;
2689  while ( st ) {
2690  if ( !strcmp( st->name, tlist->tag[ i ] )) {
2691  s[ i ] = st;
2692  break;
2693  }
2694  st = st->next;
2695  }
2696  }
2697 
2698  for ( i = 0; i < polygon->count; i++ ) {
2699  index = ( int ) polygon->pol[ i ].surf;
2700  if ( index < 0 || index > tlist->count ) return 0;
2701  if ( !s[ index ] ) {
2702  s[ index ] = lwDefaultSurface();
2703  if ( !s[ index ] ) return 0;
2704  s[ index ]->name = (char*)Mem_ClearedAlloc( strlen( tlist->tag[ index ] ) + 1 );
2705  if ( !s[ index ]->name ) return 0;
2706  strcpy( s[ index ]->name, tlist->tag[ index ] );
2707  lwListAdd( (void**)surf, s[ index ] );
2708  *nsurfs = *nsurfs + 1;
2709  }
2710  polygon->pol[ i ].surf = s[ index ];
2711  }
2712 
2713  Mem_Free( s );
2714  return 1;
2715 }
2716 
2717 
2718 /*
2719 ======================================================================
2720 lwGetVertNormals()
2721 
2722 Calculate the vertex normals. For each polygon vertex, sum the
2723 normals of the polygons that share the point. If the normals of the
2724 current and adjacent polygons form an angle greater than the max
2725 smoothing angle for the current polygon's surface, the normal of the
2726 adjacent polygon is excluded from the sum. It's also excluded if the
2727 polygons aren't in the same smoothing group.
2728 
2729 Assumes that lwGetPointPolygons(), lwGetPolyNormals() and
2730 lwResolvePolySurfaces() have already been called.
2731 ====================================================================== */
2732 
2734 {
2735  int j, k, n, g, h, p;
2736  float a;
2737 
2738  for ( j = 0; j < polygon->count; j++ ) {
2739  for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) {
2740  for ( k = 0; k < 3; k++ )
2741  polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ];
2742 
2743  if ( polygon->pol[ j ].surf->smooth <= 0 ) continue;
2744 
2745  p = polygon->pol[ j ].v[ n ].index;
2746 
2747  for ( g = 0; g < point->pt[ p ].npols; g++ ) {
2748  h = point->pt[ p ].pol[ g ];
2749  if ( h == j ) continue;
2750 
2751  if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp )
2752  continue;
2753  a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm );
2754  if ( a > polygon->pol[ j ].surf->smooth ) continue;
2755 
2756  for ( k = 0; k < 3; k++ )
2757  polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ];
2758  }
2759 
2760  normalize( polygon->pol[ j ].v[ n ].norm );
2761  }
2762  }
2763 }
2764 
2765 
2766 /*
2767 ======================================================================
2768 lwFreeTags()
2769 
2770 Free memory used by an lwTagList.
2771 ====================================================================== */
2772 
2773 void lwFreeTags( lwTagList *tlist )
2774 {
2775  int i;
2776 
2777  if ( tlist ) {
2778  if ( tlist->tag ) {
2779  for ( i = 0; i < tlist->count; i++ )
2780  if ( tlist->tag[ i ] ) {
2781  Mem_Free( tlist->tag[ i ] );
2782  }
2783  Mem_Free( tlist->tag );
2784  }
2785  memset( tlist, 0, sizeof( lwTagList ));
2786  }
2787 }
2788 
2789 
2790 /*
2791 ======================================================================
2792 lwGetTags()
2793 
2794 Read tag strings from a TAGS chunk in an LWO2 file. The tags are
2795 added to the lwTagList array.
2796 ====================================================================== */
2797 
2798 int lwGetTags( idFile *fp, int cksize, lwTagList *tlist )
2799 {
2800  char *buf, *bp;
2801  int i, len, ntags;
2802 
2803  if ( cksize == 0 ) return 1;
2804 
2805  /* read the whole chunk */
2806 
2807  set_flen( 0 );
2808  buf = (char*)getbytes( fp, cksize );
2809  if ( !buf ) return 0;
2810 
2811  /* count the strings */
2812 
2813  ntags = 0;
2814  bp = buf;
2815  while ( bp < buf + cksize ) {
2816  len = strlen( bp ) + 1;
2817  len += len & 1;
2818  bp += len;
2819  ++ntags;
2820  }
2821 
2822  /* expand the string array to hold the new tags */
2823 
2824  tlist->offset = tlist->count;
2825  tlist->count += ntags;
2826  char **oldtag = tlist->tag;
2827  tlist->tag = (char**)Mem_Alloc( tlist->count * sizeof( char * ) );
2828  if ( !tlist->tag ) goto Fail;
2829  if ( oldtag ) {
2830  memcpy( tlist->tag, oldtag, tlist->offset * sizeof( char * ) );
2831  Mem_Free( oldtag );
2832  }
2833  memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * ) );
2834 
2835  /* copy the new tags to the tag array */
2836 
2837  bp = buf;
2838  for ( i = 0; i < ntags; i++ )
2839  tlist->tag[ i + tlist->offset ] = sgetS0( (unsigned char**)&bp );
2840 
2841  Mem_Free( buf );
2842  return 1;
2843 
2844 Fail:
2845  if ( buf ) Mem_Free( buf );
2846  return 0;
2847 }
2848 
2849 
2850 /*
2851 ======================================================================
2852 lwGetPolygonTags()
2853 
2854 Read polygon tags from a PTAG chunk in an LWO2 file.
2855 ====================================================================== */
2856 
2857 int lwGetPolygonTags( idFile *fp, int cksize, lwTagList *tlist, lwPolygonList *plist )
2858 {
2859  unsigned int type;
2860  int rlen = 0, i, j;
2861 
2862  set_flen( 0 );
2863  type = getU4( fp );
2864  rlen = get_flen();
2865  if ( rlen < 0 ) return 0;
2866 
2867  if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) {
2868  fp->Seek( cksize - 4, FS_SEEK_CUR );
2869  return 1;
2870  }
2871 
2872  while ( rlen < cksize ) {
2873  i = getVX( fp ) + plist->offset;
2874  j = getVX( fp ) + tlist->offset;
2875  rlen = get_flen();
2876  if ( rlen < 0 || rlen > cksize ) return 0;
2877 
2878  switch ( type ) {
2879  case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break;
2880  case ID_PART: plist->pol[ i ].part = j; break;
2881  case ID_SMGP: plist->pol[ i ].smoothgrp = j; break;
2882  }
2883  }
2884 
2885  return 1;
2886 }
2887 
2888 
2889 /*
2890 ======================================================================
2891 lwFreePlugin()
2892 
2893 Free the memory used by an lwPlugin.
2894 ====================================================================== */
2895 
2897 {
2898  if ( p ) {
2899  if ( p->ord ) Mem_Free( p->ord );
2900  if ( p->name ) Mem_Free( p->name );
2901  if ( p->data ) Mem_Free( p->data );
2902  Mem_Free( p );
2903  }
2904 }
2905 
2906 
2907 /*
2908 ======================================================================
2909 lwFreeTexture()
2910 
2911 Free the memory used by an lwTexture.
2912 ====================================================================== */
2913 
2915 {
2916  if ( t ) {
2917  if ( t->ord ) Mem_Free( t->ord );
2918  switch ( t->type ) {
2919  case ID_IMAP:
2920  if ( t->param.imap.vmap_name ) Mem_Free( t->param.imap.vmap_name );
2921  break;
2922  case ID_PROC:
2923  if ( t->param.proc.name ) Mem_Free( t->param.proc.name );
2924  if ( t->param.proc.data ) Mem_Free( t->param.proc.data );
2925  break;
2926  case ID_GRAD:
2927  if ( t->param.grad.key ) Mem_Free( t->param.grad.key );
2928  if ( t->param.grad.ikey ) Mem_Free( t->param.grad.ikey );
2929  break;
2930  }
2931  if ( t->tmap.ref_object ) Mem_Free( t->tmap.ref_object );
2932  Mem_Free( t );
2933  }
2934 }
2935 
2936 
2937 /*
2938 ======================================================================
2939 lwFreeSurface()
2940 
2941 Free the memory used by an lwSurface.
2942 ====================================================================== */
2943 
2945 {
2946  if ( surf ) {
2947  if ( surf->name ) Mem_Free( surf->name );
2948  if ( surf->srcname ) Mem_Free( surf->srcname );
2949 
2950  lwListFree( surf->shader, (void (__cdecl *)(void *))lwFreePlugin );
2951 
2952  lwListFree( surf->color.tex, (void (__cdecl *)(void *))lwFreeTexture );
2953  lwListFree( surf->luminosity.tex, (void (__cdecl *)(void *))lwFreeTexture );
2954  lwListFree( surf->diffuse.tex, (void (__cdecl *)(void *))lwFreeTexture );
2955  lwListFree( surf->specularity.tex, (void (__cdecl *)(void *))lwFreeTexture );
2956  lwListFree( surf->glossiness.tex, (void (__cdecl *)(void *))lwFreeTexture );
2957  lwListFree( surf->reflection.val.tex, (void (__cdecl *)(void *))lwFreeTexture );
2958  lwListFree( surf->transparency.val.tex, (void (__cdecl *)(void *))lwFreeTexture );
2959  lwListFree( surf->eta.tex, (void (__cdecl *)(void *))lwFreeTexture );
2960  lwListFree( surf->translucency.tex, (void (__cdecl *)(void *))lwFreeTexture );
2961  lwListFree( surf->bump.tex, (void (__cdecl *)(void *))lwFreeTexture );
2962 
2963  Mem_Free( surf );
2964  }
2965 }
2966 
2967 
2968 /*
2969 ======================================================================
2970 lwGetTHeader()
2971 
2972 Read a texture map header from a SURF.BLOK in an LWO2 file. This is
2973 the first subchunk in a BLOK, and its contents are common to all three
2974 texture types.
2975 ====================================================================== */
2976 
2977 int lwGetTHeader( idFile *fp, int hsz, lwTexture *tex )
2978 {
2979  unsigned int id;
2980  unsigned short sz;
2981  int pos, rlen;
2982 
2983 
2984  /* remember where we started */
2985 
2986  set_flen( 0 );
2987  pos = fp->Tell();
2988 
2989  /* ordinal string */
2990 
2991  tex->ord = getS0( fp );
2992 
2993  /* first subchunk header */
2994 
2995  id = getU4( fp );
2996  sz = getU2( fp );
2997  if ( 0 > get_flen() ) return 0;
2998 
2999  /* process subchunks as they're encountered */
3000 
3001  while ( 1 ) {
3002  sz += sz & 1;
3003  set_flen( 0 );
3004 
3005  switch ( id ) {
3006  case ID_CHAN:
3007  tex->chan = getU4( fp );
3008  break;
3009 
3010  case ID_OPAC:
3011  tex->opac_type = getU2( fp );
3012  tex->opacity.val = getF4( fp );
3013  tex->opacity.eindex = getVX( fp );
3014  break;
3015 
3016  case ID_ENAB:
3017  tex->enabled = getU2( fp );
3018  break;
3019 
3020  case ID_NEGA:
3021  tex->negative = getU2( fp );
3022  break;
3023 
3024  case ID_AXIS:
3025  tex->axis = getU2( fp );
3026  break;
3027 
3028  default:
3029  break;
3030  }
3031 
3032  /* error while reading current subchunk? */
3033 
3034  rlen = get_flen();
3035  if ( rlen < 0 || rlen > sz ) return 0;
3036 
3037  /* skip unread parts of the current subchunk */
3038 
3039  if ( rlen < sz )
3040  fp->Seek( sz - rlen, FS_SEEK_CUR );
3041 
3042  /* end of the texture header subchunk? */
3043 
3044  if ( hsz <= fp->Tell() - pos )
3045  break;
3046 
3047  /* get the next subchunk header */
3048 
3049  set_flen( 0 );
3050  id = getU4( fp );
3051  sz = getU2( fp );
3052  if ( 6 != get_flen() ) return 0;
3053  }
3054 
3055  set_flen( fp->Tell() - pos );
3056  return 1;
3057 }
3058 
3059 
3060 /*
3061 ======================================================================
3062 lwGetTMap()
3063 
3064 Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP
3065 defines the mapping from texture to world or object coordinates.
3066 ====================================================================== */
3067 
3068 int lwGetTMap( idFile *fp, int tmapsz, lwTMap *tmap )
3069 {
3070  unsigned int id;
3071  unsigned short sz;
3072  int rlen, pos, i;
3073 
3074  pos = fp->Tell();
3075  id = getU4( fp );
3076  sz = getU2( fp );
3077  if ( 0 > get_flen() ) return 0;
3078 
3079  while ( 1 ) {
3080  sz += sz & 1;
3081  set_flen( 0 );
3082 
3083  switch ( id ) {
3084  case ID_SIZE:
3085  for ( i = 0; i < 3; i++ )
3086  tmap->size.val[ i ] = getF4( fp );
3087  tmap->size.eindex = getVX( fp );
3088  break;
3089 
3090  case ID_CNTR:
3091  for ( i = 0; i < 3; i++ )
3092  tmap->center.val[ i ] = getF4( fp );
3093  tmap->center.eindex = getVX( fp );
3094  break;
3095 
3096  case ID_ROTA:
3097  for ( i = 0; i < 3; i++ )
3098  tmap->rotate.val[ i ] = getF4( fp );
3099  tmap->rotate.eindex = getVX( fp );
3100  break;
3101 
3102  case ID_FALL:
3103  tmap->fall_type = getU2( fp );
3104  for ( i = 0; i < 3; i++ )
3105  tmap->falloff.val[ i ] = getF4( fp );
3106  tmap->falloff.eindex = getVX( fp );
3107  break;
3108 
3109  case ID_OREF:
3110  tmap->ref_object = getS0( fp );
3111  break;
3112 
3113  case ID_CSYS:
3114  tmap->coord_sys = getU2( fp );
3115  break;
3116 
3117  default:
3118  break;
3119  }
3120 
3121  /* error while reading the current subchunk? */
3122 
3123  rlen = get_flen();
3124  if ( rlen < 0 || rlen > sz ) return 0;
3125 
3126  /* skip unread parts of the current subchunk */
3127 
3128  if ( rlen < sz )
3129  fp->Seek( sz - rlen, FS_SEEK_CUR );
3130 
3131  /* end of the TMAP subchunk? */
3132 
3133  if ( tmapsz <= fp->Tell() - pos )
3134  break;
3135 
3136  /* get the next subchunk header */
3137 
3138  set_flen( 0 );
3139  id = getU4( fp );
3140  sz = getU2( fp );
3141  if ( 6 != get_flen() ) return 0;
3142  }
3143 
3144  set_flen( fp->Tell() - pos );
3145  return 1;
3146 }
3147 
3148 
3149 /*
3150 ======================================================================
3151 lwGetImageMap()
3152 
3153 Read an lwImageMap from a SURF.BLOK in an LWO2 file.
3154 ====================================================================== */
3155 
3156 int lwGetImageMap( idFile *fp, int rsz, lwTexture *tex )
3157 {
3158  unsigned int id;
3159  unsigned short sz;
3160  int rlen, pos;
3161 
3162  pos = fp->Tell();
3163  id = getU4( fp );
3164  sz = getU2( fp );
3165  if ( 0 > get_flen() ) return 0;
3166 
3167  while ( 1 ) {
3168  sz += sz & 1;
3169  set_flen( 0 );
3170 
3171  switch ( id ) {
3172  case ID_TMAP:
3173  if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3174  break;
3175 
3176  case ID_PROJ:
3177  tex->param.imap.projection = getU2( fp );
3178  break;
3179 
3180  case ID_VMAP:
3181  tex->param.imap.vmap_name = getS0( fp );
3182  break;
3183 
3184  case ID_AXIS:
3185  tex->param.imap.axis = getU2( fp );
3186  break;
3187 
3188  case ID_IMAG:
3189  tex->param.imap.cindex = getVX( fp );
3190  break;
3191 
3192  case ID_WRAP:
3193  tex->param.imap.wrapw_type = getU2( fp );
3194  tex->param.imap.wraph_type = getU2( fp );
3195  break;
3196 
3197  case ID_WRPW:
3198  tex->param.imap.wrapw.val = getF4( fp );
3199  tex->param.imap.wrapw.eindex = getVX( fp );
3200  break;
3201 
3202  case ID_WRPH:
3203  tex->param.imap.wraph.val = getF4( fp );
3204  tex->param.imap.wraph.eindex = getVX( fp );
3205  break;
3206 
3207  case ID_AAST:
3208  tex->param.imap.aas_flags = getU2( fp );
3209  tex->param.imap.aa_strength = getF4( fp );
3210  break;
3211 
3212  case ID_PIXB:
3213  tex->param.imap.pblend = getU2( fp );
3214  break;
3215 
3216  case ID_STCK:
3217  tex->param.imap.stck.val = getF4( fp );
3218  tex->param.imap.stck.eindex = getVX( fp );
3219  break;
3220 
3221  case ID_TAMP:
3222  tex->param.imap.amplitude.val = getF4( fp );
3223  tex->param.imap.amplitude.eindex = getVX( fp );
3224  break;
3225 
3226  default:
3227  break;
3228  }
3229 
3230  /* error while reading the current subchunk? */
3231 
3232  rlen = get_flen();
3233  if ( rlen < 0 || rlen > sz ) return 0;
3234 
3235  /* skip unread parts of the current subchunk */
3236 
3237  if ( rlen < sz )
3238  fp->Seek( sz - rlen, FS_SEEK_CUR );
3239 
3240  /* end of the image map? */
3241 
3242  if ( rsz <= fp->Tell() - pos )
3243  break;
3244 
3245  /* get the next subchunk header */
3246 
3247  set_flen( 0 );
3248  id = getU4( fp );
3249  sz = getU2( fp );
3250  if ( 6 != get_flen() ) return 0;
3251  }
3252 
3253  set_flen( fp->Tell() - pos );
3254  return 1;
3255 }
3256 
3257 
3258 /*
3259 ======================================================================
3260 lwGetProcedural()
3261 
3262 Read an lwProcedural from a SURF.BLOK in an LWO2 file.
3263 ====================================================================== */
3264 
3265 int lwGetProcedural( idFile *fp, int rsz, lwTexture *tex )
3266 {
3267  unsigned int id;
3268  unsigned short sz;
3269  int rlen, pos;
3270 
3271  pos = fp->Tell();
3272  id = getU4( fp );
3273  sz = getU2( fp );
3274  if ( 0 > get_flen() ) return 0;
3275 
3276  while ( 1 ) {
3277  sz += sz & 1;
3278  set_flen( 0 );
3279 
3280  switch ( id ) {
3281  case ID_TMAP:
3282  if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3283  break;
3284 
3285  case ID_AXIS:
3286  tex->param.proc.axis = getU2( fp );
3287  break;
3288 
3289  case ID_VALU:
3290  tex->param.proc.value[ 0 ] = getF4( fp );
3291  if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp );
3292  if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp );
3293  break;
3294 
3295  case ID_FUNC:
3296  tex->param.proc.name = getS0( fp );
3297  rlen = get_flen();
3298  tex->param.proc.data = getbytes( fp, sz - rlen );
3299  break;
3300 
3301  default:
3302  break;
3303  }
3304 
3305  /* error while reading the current subchunk? */
3306 
3307  rlen = get_flen();
3308  if ( rlen < 0 || rlen > sz ) return 0;
3309 
3310  /* skip unread parts of the current subchunk */
3311 
3312  if ( rlen < sz )
3313  fp->Seek( sz - rlen, FS_SEEK_CUR );
3314 
3315  /* end of the procedural block? */
3316 
3317  if ( rsz <= fp->Tell() - pos )
3318  break;
3319 
3320  /* get the next subchunk header */
3321 
3322  set_flen( 0 );
3323  id = getU4( fp );
3324  sz = getU2( fp );
3325  if ( 6 != get_flen() ) return 0;
3326  }
3327 
3328  set_flen( fp->Tell() - pos );
3329  return 1;
3330 }
3331 
3332 
3333 /*
3334 ======================================================================
3335 lwGetGradient()
3336 
3337 Read an lwGradient from a SURF.BLOK in an LWO2 file.
3338 ====================================================================== */
3339 
3340 int lwGetGradient( idFile *fp, int rsz, lwTexture *tex )
3341 {
3342  unsigned int id;
3343  unsigned short sz;
3344  int rlen, pos, i, j, nkeys;
3345 
3346  pos = fp->Tell();
3347  id = getU4( fp );
3348  sz = getU2( fp );
3349  if ( 0 > get_flen() ) return 0;
3350 
3351  while ( 1 ) {
3352  sz += sz & 1;
3353  set_flen( 0 );
3354 
3355  switch ( id ) {
3356  case ID_TMAP:
3357  if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3358  break;
3359 
3360  case ID_PNAM:
3361  tex->param.grad.paramname = getS0( fp );
3362  break;
3363 
3364  case ID_INAM:
3365  tex->param.grad.itemname = getS0( fp );
3366  break;
3367 
3368  case ID_GRST:
3369  tex->param.grad.start = getF4( fp );
3370  break;
3371 
3372  case ID_GREN:
3373  tex->param.grad.end = getF4( fp );
3374  break;
3375 
3376  case ID_GRPT:
3377  tex->param.grad.repeat = getU2( fp );
3378  break;
3379 
3380  case ID_FKEY:
3381  nkeys = sz / sizeof( lwGradKey );
3382  tex->param.grad.key = (lwGradKey*)Mem_ClearedAlloc( nkeys * sizeof( lwGradKey ) );
3383  if ( !tex->param.grad.key ) return 0;
3384  for ( i = 0; i < nkeys; i++ ) {
3385  tex->param.grad.key[ i ].value = getF4( fp );
3386  for ( j = 0; j < 4; j++ )
3387  tex->param.grad.key[ i ].rgba[ j ] = getF4( fp );
3388  }
3389  break;
3390 
3391  case ID_IKEY:
3392  nkeys = sz / 2;
3393  tex->param.grad.ikey = (short*)Mem_ClearedAlloc( nkeys * sizeof( short ) );
3394  if ( !tex->param.grad.ikey ) return 0;
3395  for ( i = 0; i < nkeys; i++ )
3396  tex->param.grad.ikey[ i ] = getU2( fp );
3397  break;
3398 
3399  default:
3400  break;
3401  }
3402 
3403  /* error while reading the current subchunk? */
3404 
3405  rlen = get_flen();
3406  if ( rlen < 0 || rlen > sz ) return 0;
3407 
3408  /* skip unread parts of the current subchunk */
3409 
3410  if ( rlen < sz )
3411  fp->Seek( sz - rlen, FS_SEEK_CUR );
3412 
3413  /* end of the gradient? */
3414 
3415  if ( rsz <= fp->Tell() - pos )
3416  break;
3417 
3418  /* get the next subchunk header */
3419 
3420  set_flen( 0 );
3421  id = getU4( fp );
3422  sz = getU2( fp );
3423  if ( 6 != get_flen() ) return 0;
3424  }
3425 
3426  set_flen( fp->Tell() - pos );
3427  return 1;
3428 }
3429 
3430 
3431 /*
3432 ======================================================================
3433 lwGetTexture()
3434 
3435 Read an lwTexture from a SURF.BLOK in an LWO2 file.
3436 ====================================================================== */
3437 
3438 lwTexture *lwGetTexture( idFile *fp, int bloksz, unsigned int type )
3439 {
3440  lwTexture *tex;
3441  unsigned short sz;
3442  int ok;
3443 
3444  tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
3445  if ( !tex ) return NULL;
3446 
3447  tex->type = type;
3448  tex->tmap.size.val[ 0 ] =
3449  tex->tmap.size.val[ 1 ] =
3450  tex->tmap.size.val[ 2 ] = 1.0f;
3451  tex->opacity.val = 1.0f;
3452  tex->enabled = 1;
3453 
3454  sz = getU2( fp );
3455  if ( !lwGetTHeader( fp, sz, tex )) {
3456  Mem_Free( tex );
3457  return NULL;
3458  }
3459 
3460  sz = bloksz - sz - 6;
3461  switch ( type ) {
3462  case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break;
3463  case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break;
3464  case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break;
3465  default:
3466  ok = !fp->Seek( sz, FS_SEEK_CUR );
3467  }
3468 
3469  if ( !ok ) {
3470  lwFreeTexture( tex );
3471  return NULL;
3472  }
3473 
3474  set_flen( bloksz );
3475  return tex;
3476 }
3477 
3478 
3479 /*
3480 ======================================================================
3481 lwGetShader()
3482 
3483 Read a shader record from a SURF.BLOK in an LWO2 file.
3484 ====================================================================== */
3485 
3486 lwPlugin *lwGetShader( idFile *fp, int bloksz )
3487 {
3488  lwPlugin *shdr;
3489  unsigned int id;
3490  unsigned short sz;
3491  int hsz, rlen, pos;
3492 
3493  shdr = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
3494  if ( !shdr ) return NULL;
3495 
3496  pos = fp->Tell();
3497  set_flen( 0 );
3498  hsz = getU2( fp );
3499  shdr->ord = getS0( fp );
3500  id = getU4( fp );
3501  sz = getU2( fp );
3502  if ( 0 > get_flen() ) goto Fail;
3503 
3504  while ( hsz > 0 ) {
3505  sz += sz & 1;
3506  hsz -= sz;
3507  if ( id == ID_ENAB ) {
3508  shdr->flags = getU2( fp );
3509  break;
3510  }
3511  else {
3512  fp->Seek( sz, FS_SEEK_CUR );
3513  id = getU4( fp );
3514  sz = getU2( fp );
3515  }
3516  }
3517 
3518  id = getU4( fp );
3519  sz = getU2( fp );
3520  if ( 0 > get_flen() ) goto Fail;
3521 
3522  while ( 1 ) {
3523  sz += sz & 1;
3524  set_flen( 0 );
3525 
3526  switch ( id ) {
3527  case ID_FUNC:
3528  shdr->name = getS0( fp );
3529  rlen = get_flen();
3530  shdr->data = getbytes( fp, sz - rlen );
3531  break;
3532 
3533  default:
3534  break;
3535  }
3536 
3537  /* error while reading the current subchunk? */
3538 
3539  rlen = get_flen();
3540  if ( rlen < 0 || rlen > sz ) goto Fail;
3541 
3542  /* skip unread parts of the current subchunk */
3543 
3544  if ( rlen < sz )
3545  fp->Seek( sz - rlen, FS_SEEK_CUR );
3546 
3547  /* end of the shader block? */
3548 
3549  if ( bloksz <= fp->Tell() - pos )
3550  break;
3551 
3552  /* get the next subchunk header */
3553 
3554  set_flen( 0 );
3555  id = getU4( fp );
3556  sz = getU2( fp );
3557  if ( 6 != get_flen() ) goto Fail;
3558  }
3559 
3560  set_flen( fp->Tell() - pos );
3561  return shdr;
3562 
3563 Fail:
3564  lwFreePlugin( shdr );
3565  return NULL;
3566 }
3567 
3568 
3569 /*
3570 ======================================================================
3571 compare_textures()
3572 compare_shaders()
3573 
3574 Callbacks for the lwListInsert() function, which is called to add
3575 textures to surface channels and shaders to surfaces.
3576 ====================================================================== */
3577 
3578 static int compare_textures( lwTexture *a, lwTexture *b )
3579 {
3580  return strcmp( a->ord, b->ord );
3581 }
3582 
3583 
3584 static int compare_shaders( lwPlugin *a, lwPlugin *b )
3585 {
3586  return strcmp( a->ord, b->ord );
3587 }
3588 
3589 
3590 /*
3591 ======================================================================
3592 add_texture()
3593 
3594 Finds the surface channel (lwTParam or lwCParam) to which a texture is
3595 applied, then calls lwListInsert().
3596 ====================================================================== */
3597 
3598 static int add_texture( lwSurface *surf, lwTexture *tex )
3599 {
3600  lwTexture **list;
3601 
3602  switch ( tex->chan ) {
3603  case ID_COLR: list = &surf->color.tex; break;
3604  case ID_LUMI: list = &surf->luminosity.tex; break;
3605  case ID_DIFF: list = &surf->diffuse.tex; break;
3606  case ID_SPEC: list = &surf->specularity.tex; break;
3607  case ID_GLOS: list = &surf->glossiness.tex; break;
3608  case ID_REFL: list = &surf->reflection.val.tex; break;
3609  case ID_TRAN: list = &surf->transparency.val.tex; break;
3610  case ID_RIND: list = &surf->eta.tex; break;
3611  case ID_TRNL: list = &surf->translucency.tex; break;
3612  case ID_BUMP: list = &surf->bump.tex; break;
3613  default: return 0;
3614  }
3615 
3616  lwListInsert( (void**)list, tex, (int (__cdecl *)(void *,void *))compare_textures );
3617  return 1;
3618 }
3619 
3620 
3621 /*
3622 ======================================================================
3623 lwDefaultSurface()
3624 
3625 Allocate and initialize a surface.
3626 ====================================================================== */
3627 
3629 {
3630  lwSurface *surf;
3631 
3632  surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
3633  if ( !surf ) return NULL;
3634 
3635  surf->color.rgb[ 0 ] = 0.78431f;
3636  surf->color.rgb[ 1 ] = 0.78431f;
3637  surf->color.rgb[ 2 ] = 0.78431f;
3638  surf->diffuse.val = 1.0f;
3639  surf->glossiness.val = 0.4f;
3640  surf->bump.val = 1.0f;
3641  surf->eta.val = 1.0f;
3642  surf->sideflags = 1;
3643 
3644  return surf;
3645 }
3646 
3647 
3648 /*
3649 ======================================================================
3650 lwGetSurface()
3651 
3652 Read an lwSurface from an LWO2 file.
3653 ====================================================================== */
3654 
3655 lwSurface *lwGetSurface( idFile *fp, int cksize )
3656 {
3657  lwSurface *surf;
3658  lwTexture *tex;
3659  lwPlugin *shdr;
3660  unsigned int id, type;
3661  unsigned short sz;
3662  int pos, rlen;
3663 
3664 
3665  /* allocate the Surface structure */
3666 
3667  surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
3668  if ( !surf ) goto Fail;
3669 
3670  /* non-zero defaults */
3671 
3672  surf->color.rgb[ 0 ] = 0.78431f;
3673  surf->color.rgb[ 1 ] = 0.78431f;
3674  surf->color.rgb[ 2 ] = 0.78431f;
3675  surf->diffuse.val = 1.0f;
3676  surf->glossiness.val = 0.4f;
3677  surf->bump.val = 1.0f;
3678  surf->eta.val = 1.0f;
3679  surf->sideflags = 1;
3680 
3681  /* remember where we started */
3682 
3683  set_flen( 0 );
3684  pos = fp->Tell();
3685 
3686  /* names */
3687 
3688  surf->name = getS0( fp );
3689  surf->srcname = getS0( fp );
3690 
3691  /* first subchunk header */
3692 
3693  id = getU4( fp );
3694  sz = getU2( fp );
3695  if ( 0 > get_flen() ) goto Fail;
3696 
3697  /* process subchunks as they're encountered */
3698 
3699  while ( 1 ) {
3700  sz += sz & 1;
3701  set_flen( 0 );
3702 
3703  switch ( id ) {
3704  case ID_COLR:
3705  surf->color.rgb[ 0 ] = getF4( fp );
3706  surf->color.rgb[ 1 ] = getF4( fp );
3707  surf->color.rgb[ 2 ] = getF4( fp );
3708  surf->color.eindex = getVX( fp );
3709  break;
3710 
3711  case ID_LUMI:
3712  surf->luminosity.val = getF4( fp );
3713  surf->luminosity.eindex = getVX( fp );
3714  break;
3715 
3716  case ID_DIFF:
3717  surf->diffuse.val = getF4( fp );
3718  surf->diffuse.eindex = getVX( fp );
3719  break;
3720 
3721  case ID_SPEC:
3722  surf->specularity.val = getF4( fp );
3723  surf->specularity.eindex = getVX( fp );
3724  break;
3725 
3726  case ID_GLOS:
3727  surf->glossiness.val = getF4( fp );
3728  surf->glossiness.eindex = getVX( fp );
3729  break;
3730 
3731  case ID_REFL:
3732  surf->reflection.val.val = getF4( fp );
3733  surf->reflection.val.eindex = getVX( fp );
3734  break;
3735 
3736  case ID_RFOP:
3737  surf->reflection.options = getU2( fp );
3738  break;
3739 
3740  case ID_RIMG:
3741  surf->reflection.cindex = getVX( fp );
3742  break;
3743 
3744  case ID_RSAN:
3745  surf->reflection.seam_angle = getF4( fp );
3746  break;
3747 
3748  case ID_TRAN:
3749  surf->transparency.val.val = getF4( fp );
3750  surf->transparency.val.eindex = getVX( fp );
3751  break;
3752 
3753  case ID_TROP:
3754  surf->transparency.options = getU2( fp );
3755  break;
3756 
3757  case ID_TIMG:
3758  surf->transparency.cindex = getVX( fp );
3759  break;
3760 
3761  case ID_RIND:
3762  surf->eta.val = getF4( fp );
3763  surf->eta.eindex = getVX( fp );
3764  break;
3765 
3766  case ID_TRNL:
3767  surf->translucency.val = getF4( fp );
3768  surf->translucency.eindex = getVX( fp );
3769  break;
3770 
3771  case ID_BUMP:
3772  surf->bump.val = getF4( fp );
3773  surf->bump.eindex = getVX( fp );
3774  break;
3775 
3776  case ID_SMAN:
3777  surf->smooth = getF4( fp );
3778  break;
3779 
3780  case ID_SIDE:
3781  surf->sideflags = getU2( fp );
3782  break;
3783 
3784  case ID_CLRH:
3785  surf->color_hilite.val = getF4( fp );
3786  surf->color_hilite.eindex = getVX( fp );
3787  break;
3788 
3789  case ID_CLRF:
3790  surf->color_filter.val = getF4( fp );
3791  surf->color_filter.eindex = getVX( fp );
3792  break;
3793 
3794  case ID_ADTR:
3795  surf->add_trans.val = getF4( fp );
3796  surf->add_trans.eindex = getVX( fp );
3797  break;
3798 
3799  case ID_SHRP:
3800  surf->dif_sharp.val = getF4( fp );
3801  surf->dif_sharp.eindex = getVX( fp );
3802  break;
3803 
3804  case ID_GVAL:
3805  surf->glow.val = getF4( fp );
3806  surf->glow.eindex = getVX( fp );
3807  break;
3808 
3809  case ID_LINE:
3810  surf->line.enabled = 1;
3811  if ( sz >= 2 ) surf->line.flags = getU2( fp );
3812  if ( sz >= 6 ) surf->line.size.val = getF4( fp );
3813  if ( sz >= 8 ) surf->line.size.eindex = getVX( fp );
3814  break;
3815 
3816  case ID_ALPH:
3817  surf->alpha_mode = getU2( fp );
3818  surf->alpha = getF4( fp );
3819  break;
3820 
3821  case ID_AVAL:
3822  surf->alpha = getF4( fp );
3823  break;
3824 
3825  case ID_BLOK:
3826  type = getU4( fp );
3827 
3828  switch ( type ) {
3829  case ID_IMAP:
3830  case ID_PROC:
3831  case ID_GRAD:
3832  tex = lwGetTexture( fp, sz - 4, type );
3833  if ( !tex ) goto Fail;
3834  if ( !add_texture( surf, tex ))
3835  lwFreeTexture( tex );
3836  set_flen( 4 + get_flen() );
3837  break;
3838  case ID_SHDR:
3839  shdr = lwGetShader( fp, sz - 4 );
3840  if ( !shdr ) goto Fail;
3841  lwListInsert( (void**)&surf->shader, shdr, (int (__cdecl *)(void *,void *))compare_shaders );
3842  ++surf->nshaders;
3843  set_flen( 4 + get_flen() );
3844  break;
3845  }
3846  break;
3847 
3848  default:
3849  break;
3850  }
3851 
3852  /* error while reading current subchunk? */
3853 
3854  rlen = get_flen();
3855  if ( rlen < 0 || rlen > sz ) goto Fail;
3856 
3857  /* skip unread parts of the current subchunk */
3858 
3859  if ( rlen < sz )
3860  fp->Seek( sz - rlen, FS_SEEK_CUR );
3861 
3862  /* end of the SURF chunk? */
3863 
3864  if ( cksize <= fp->Tell() - pos )
3865  break;
3866 
3867  /* get the next subchunk header */
3868 
3869  set_flen( 0 );
3870  id = getU4( fp );
3871  sz = getU2( fp );
3872  if ( 6 != get_flen() ) goto Fail;
3873  }
3874 
3875  return surf;
3876 
3877 Fail:
3878  if ( surf ) lwFreeSurface( surf );
3879  return NULL;
3880 }
3881 
3882 
3883 float dot( float a[], float b[] )
3884 {
3885  return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
3886 }
3887 
3888 
3889 void cross( float a[], float b[], float c[] )
3890 {
3891  c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
3892  c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
3893  c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
3894 }
3895 
3896 
3897 void normalize( float v[] )
3898 {
3899  float r;
3900 
3901  r = ( float ) idMath::Sqrt( dot( v, v ));
3902  if ( r > 0 ) {
3903  v[ 0 ] /= r;
3904  v[ 1 ] /= r;
3905  v[ 2 ] /= r;
3906  }
3907 }
3908 
3909 /*
3910 ======================================================================
3911 lwFreeVMap()
3912 
3913 Free memory used by an lwVMap.
3914 ====================================================================== */
3915 
3916 void lwFreeVMap( lwVMap *vmap )
3917 {
3918  if ( vmap ) {
3919  if ( vmap->name ) Mem_Free( vmap->name );
3920  if ( vmap->vindex ) Mem_Free( vmap->vindex );
3921  if ( vmap->pindex ) Mem_Free( vmap->pindex );
3922  if ( vmap->val ) {
3923  if ( vmap->val[ 0 ] ) Mem_Free( vmap->val[ 0 ] );
3924  Mem_Free( vmap->val );
3925  }
3926  Mem_Free( vmap );
3927  }
3928 }
3929 
3930 
3931 /*
3932 ======================================================================
3933 lwGetVMap()
3934 
3935 Read an lwVMap from a VMAP or VMAD chunk in an LWO2.
3936 ====================================================================== */
3937 
3938 lwVMap *lwGetVMap( idFile *fp, int cksize, int ptoffset, int poloffset,
3939  int perpoly )
3940 {
3941  unsigned char *buf, *bp;
3942  lwVMap *vmap;
3943  float *f;
3944  int i, j, npts, rlen;
3945 
3946 
3947  /* read the whole chunk */
3948 
3949  set_flen( 0 );
3950  buf = (unsigned char*)getbytes( fp, cksize );
3951  if ( !buf ) return NULL;
3952 
3953  vmap = (lwVMap*)Mem_ClearedAlloc( sizeof( lwVMap ) );
3954  if ( !vmap ) {
3955  Mem_Free( buf );
3956  return NULL;
3957  }
3958 
3959  /* initialize the vmap */
3960 
3961  vmap->perpoly = perpoly;
3962 
3963  bp = buf;
3964  set_flen( 0 );
3965  vmap->type = sgetU4( &bp );
3966  vmap->dim = sgetU2( &bp );
3967  vmap->name = sgetS0( &bp );
3968  rlen = get_flen();
3969 
3970  /* count the vmap records */
3971 
3972  npts = 0;
3973  while ( bp < buf + cksize ) {
3974  i = sgetVX( &bp );
3975  if ( perpoly )
3976  i = sgetVX( &bp );
3977  bp += vmap->dim * sizeof( float );
3978  ++npts;
3979  }
3980 
3981  /* allocate the vmap */
3982 
3983  vmap->nverts = npts;
3984  vmap->vindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
3985  if ( !vmap->vindex ) goto Fail;
3986  if ( perpoly ) {
3987  vmap->pindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
3988  if ( !vmap->pindex ) goto Fail;
3989  }
3990 
3991  if ( vmap->dim > 0 ) {
3992  vmap->val = (float**)Mem_ClearedAlloc( npts * sizeof( float * ) );
3993  if ( !vmap->val ) goto Fail;
3994  f = (float*)Mem_ClearedAlloc( npts * vmap->dim * sizeof( float ) );
3995  if ( !f ) goto Fail;
3996  for ( i = 0; i < npts; i++ )
3997  vmap->val[ i ] = f + i * vmap->dim;
3998  }
3999 
4000  /* fill in the vmap values */
4001 
4002  bp = buf + rlen;
4003  for ( i = 0; i < npts; i++ ) {
4004  vmap->vindex[ i ] = sgetVX( &bp );
4005  if ( perpoly )
4006  vmap->pindex[ i ] = sgetVX( &bp );
4007  for ( j = 0; j < vmap->dim; j++ )
4008  vmap->val[ i ][ j ] = sgetF4( &bp );
4009  }
4010 
4011  Mem_Free( buf );
4012  return vmap;
4013 
4014 Fail:
4015  if ( buf ) Mem_Free( buf );
4016  lwFreeVMap( vmap );
4017  return NULL;
4018 }
4019 
4020 
4021 /*
4022 ======================================================================
4023 lwGetPointVMaps()
4024 
4025 Fill in the lwVMapPt structure for each point.
4026 ====================================================================== */
4027 
4028 int lwGetPointVMaps( lwPointList *point, lwVMap *vmap )
4029 {
4030  lwVMap *vm;
4031  int i, j, n;
4032 
4033  /* count the number of vmap values for each point */
4034 
4035  vm = vmap;
4036  while ( vm ) {
4037  if ( !vm->perpoly )
4038  for ( i = 0; i < vm->nverts; i++ )
4039  ++point->pt[ vm->vindex[ i ]].nvmaps;
4040  vm = vm->next;
4041  }
4042 
4043  /* allocate vmap references for each mapped point */
4044 
4045  for ( i = 0; i < point->count; i++ ) {
4046  if ( point->pt[ i ].nvmaps ) {
4047  point->pt[ i ].vm = (lwVMapPt*)Mem_ClearedAlloc( point->pt[ i ].nvmaps * sizeof( lwVMapPt ) );
4048  if ( !point->pt[ i ].vm ) return 0;
4049  point->pt[ i ].nvmaps = 0;
4050  }
4051  }
4052 
4053  /* fill in vmap references for each mapped point */
4054 
4055  vm = vmap;
4056  while ( vm ) {
4057  if ( !vm->perpoly ) {
4058  for ( i = 0; i < vm->nverts; i++ ) {
4059  j = vm->vindex[ i ];
4060  n = point->pt[ j ].nvmaps;
4061  point->pt[ j ].vm[ n ].vmap = vm;
4062  point->pt[ j ].vm[ n ].index = i;
4063  ++point->pt[ j ].nvmaps;
4064  }
4065  }
4066  vm = vm->next;
4067  }
4068 
4069  return 1;
4070 }
4071 
4072 
4073 /*
4074 ======================================================================
4075 lwGetPolyVMaps()
4076 
4077 Fill in the lwVMapPt structure for each polygon vertex.
4078 ====================================================================== */
4079 
4080 int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap )
4081 {
4082  lwVMap *vm;
4083  lwPolVert *pv;
4084  int i, j;
4085 
4086  /* count the number of vmap values for each polygon vertex */
4087 
4088  vm = vmap;
4089  while ( vm ) {
4090  if ( vm->perpoly ) {
4091  for ( i = 0; i < vm->nverts; i++ ) {
4092  for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
4093  pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
4094  if ( vm->vindex[ i ] == pv->index ) {
4095  ++pv->nvmaps;
4096  break;
4097  }
4098  }
4099  }
4100  }
4101  vm = vm->next;
4102  }
4103 
4104  /* allocate vmap references for each mapped vertex */
4105 
4106  for ( i = 0; i < polygon->count; i++ ) {
4107  for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
4108  pv = &polygon->pol[ i ].v[ j ];
4109  if ( pv->nvmaps ) {
4110  pv->vm = (lwVMapPt*)Mem_ClearedAlloc( pv->nvmaps * sizeof( lwVMapPt ) );
4111  if ( !pv->vm ) return 0;
4112  pv->nvmaps = 0;
4113  }
4114  }
4115  }
4116 
4117  /* fill in vmap references for each mapped point */
4118 
4119  vm = vmap;
4120  while ( vm ) {
4121  if ( vm->perpoly ) {
4122  for ( i = 0; i < vm->nverts; i++ ) {
4123  for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
4124  pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
4125  if ( vm->vindex[ i ] == pv->index ) {
4126  pv->vm[ pv->nvmaps ].vmap = vm;
4127  pv->vm[ pv->nvmaps ].index = i;
4128  ++pv->nvmaps;
4129  break;
4130  }
4131  }
4132  }
4133  }
4134  vm = vm->next;
4135  }
4136 
4137  return 1;
4138 }
struct st_lwSurface * next
Definition: Model_lwo.h:435
#define ID_FKEY
Definition: Model_lwo.h:182
#define ID_PFLT
Definition: Model_lwo.h:104
#define BEH_REPEAT
Definition: Model_lwo.h:236
#define ID_ANIM
Definition: Model_lwo.h:93
GLubyte g
Definition: glext.h:4662
#define ID_SATR
Definition: Model_lwo.h:99
lwTParam bump
Definition: Model_lwo.h:447
unsigned short sgetU2(unsigned char **bp)
Definition: Model_lwo.cpp:1294
#define strcmp
Definition: Str.h:41
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
lwEParam brightness
Definition: Model_lwo.h:304
int lwGetProcedural(idFile *fp, int rsz, lwTexture *tex)
Definition: Model_lwo.cpp:3265
int sgetI4(unsigned char **bp)
Definition: Model_lwo.cpp:1269
unsigned int sgetU4(unsigned char **bp)
Definition: Model_lwo.cpp:1307
#define ID_PROC
Definition: Model_lwo.h:167
#define ID_PART
Definition: Model_lwo.h:75
char * ref_object
Definition: Model_lwo.h:324
#define ID_RTEX
Definition: Model_lwo.cpp:1665
int lwGetGradient(idFile *fp, int rsz, lwTexture *tex)
Definition: Model_lwo.cpp:3340
int lwGetPolyVMaps(lwPolygonList *polygon, lwVMap *vmap)
Definition: Model_lwo.cpp:4080
char * ord
Definition: Model_lwo.h:380
#define ID_ROTA
Definition: Model_lwo.h:151
unsigned short flags
Definition: Model_lwo.h:430
void cross(float a[], float b[], float c[])
Definition: Model_lwo.cpp:3889
#define ID_STEP
Definition: Model_lwo.h:88
lwRMap transparency
Definition: Model_lwo.h:444
lwCParam color
Definition: Model_lwo.h:438
#define ID_FALL
Definition: Model_lwo.h:153
int lwGetPointPolygons(lwPointList *point, lwPolygonList *polygon)
Definition: Model_lwo.cpp:2634
void lwFreeClip(lwClip *clip)
Definition: Model_lwo.cpp:49
#define ID_TRAN
Definition: Model_lwo.h:116
#define ID_TFP1
Definition: Model_lwo.cpp:1682
lwSurface * surf
Definition: Model_lwo.h:504
lwEParam dif_sharp
Definition: Model_lwo.h:455
#define ID_SMGP
Definition: Model_lwo.h:76
lwEParam stck
Definition: Model_lwo.h:340
short axis
Definition: Model_lwo.h:387
#define ID_FACE
Definition: Model_lwo.h:67
#define ID_TCLR
Definition: Model_lwo.cpp:1673
#define ID_TFAL
Definition: Model_lwo.cpp:1671
lwClipCycle cycle
Definition: Model_lwo.h:298
#define ID_WRPH
Definition: Model_lwo.h:161
lwVMap * lwGetVMap(idFile *fp, int cksize, int ptoffset, int poloffset, int perpoly)
Definition: Model_lwo.cpp:3938
#define ID_PIXB
Definition: Model_lwo.h:164
#define ID_TSIZ
Definition: Model_lwo.cpp:1669
void lwFreePoints(lwPointList *point)
Definition: Model_lwo.cpp:2348
char * name
Definition: Model_lwo.h:203
#define ID_PTAG
Definition: Model_lwo.h:58
#define ID_CSYS
Definition: Model_lwo.h:154
unsigned char sgetU1(unsigned char **bp)
Definition: Model_lwo.cpp:1282
lwTParam luminosity
Definition: Model_lwo.h:439
const GLdouble * v
Definition: glext.h:2936
GLdouble GLdouble x2
Definition: qgl.h:415
#define ID_OREF
Definition: Model_lwo.h:152
#define ID_TVEL
Definition: Model_lwo.cpp:1672
lwVParam falloff
Definition: Model_lwo.h:322
int negative
Definition: Model_lwo.h:308
char * srcname
Definition: Model_lwo.h:437
lwEParam saturation
Definition: Model_lwo.h:305
void * getbytes(idFile *fp, int size)
Definition: Model_lwo.cpp:1006
#define ID_GLOS
Definition: Model_lwo.h:111
int lwResolvePolySurfaces(lwPolygonList *polygon, lwTagList *tlist, lwSurface **surf, int *nsurfs)
Definition: Model_lwo.cpp:2676
lwClip * lwFindClip(lwClip *list, int index)
Definition: Model_lwo.cpp:290
void lwFreePlugin(lwPlugin *p)
Definition: Model_lwo.cpp:2896
lwKey * key
Definition: Model_lwo.h:227
#define ID_TCB
Definition: Model_lwo.h:83
void lwGetBoundingBox(lwPointList *point, float bbox[])
Definition: Model_lwo.cpp:2450
float value
Definition: Model_lwo.h:213
char * name
Definition: Model_lwo.h:533
char * sgetS0(unsigned char **bp)
Definition: Model_lwo.cpp:1358
lwClipXRef xref
Definition: Model_lwo.h:297
#define ID_BEZI
Definition: Model_lwo.h:85
GLenum GLint GLint y
Definition: glext.h:2849
lwGradient grad
Definition: Model_lwo.h:391
lwVMap * vmap
Definition: Model_lwo.h:542
GLenum GLsizei n
Definition: glext.h:3705
lwPlugin * shader
Definition: Model_lwo.h:458
#define ID_INAM
Definition: Model_lwo.h:180
short negative
Definition: Model_lwo.h:386
case const int
Definition: Callbacks.cpp:52
lwPolVert * v
Definition: Model_lwo.h:511
int lwGetTags(idFile *fp, int cksize, lwTagList *tlist)
Definition: Model_lwo.cpp:2798
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
#define ID_LAYR
Definition: Model_lwo.h:51
#define ID_ENAB
Definition: Model_lwo.h:139
#define ID_TCTR
Definition: Model_lwo.cpp:1670
float smooth
Definition: Model_lwo.h:448
lwVMapPt * vm
Definition: Model_lwo.h:493
union st_lwClip::@92 source
#define ID_NEGA
Definition: Model_lwo.h:102
#define ID_ADTR
Definition: Model_lwo.h:126
#define ID_RSAN
Definition: Model_lwo.h:115
float val[3]
Definition: Model_lwo.h:250
#define ID_POST
Definition: Model_lwo.h:80
#define BEH_RESET
Definition: Model_lwo.h:234
case const float
Definition: Callbacks.cpp:62
#define ID_DTEX
Definition: Model_lwo.cpp:1663
#define ID_CTEX
Definition: Model_lwo.cpp:1662
lwVMap * vmap
Definition: Model_lwo.h:481
static float Sqrt(float x)
Definition: Math.h:302
unsigned int type
Definition: Model_lwo.h:508
float val
Definition: Model_lwo.h:400
#define ID_CONT
Definition: Model_lwo.h:97
#define ID_VALU
Definition: Model_lwo.h:169
char * itemname
Definition: Model_lwo.h:370
unsigned char getU1(idFile *fp)
Definition: Model_lwo.cpp:1088
lwTParam eta
Definition: Model_lwo.h:445
struct st_lwLayer * next
Definition: Model_lwo.h:532
lwEParam contrast
Definition: Model_lwo.h:303
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
virtual int Tell(void)
Definition: File.cpp:217
lwEnvelope * env
Definition: Model_lwo.h:560
#define ID_GRST
Definition: Model_lwo.h:177
short sgetI2(unsigned char **bp)
Definition: Model_lwo.cpp:1256
lwClip * clip
Definition: Model_lwo.h:561
lwPoint * pt
Definition: Model_lwo.h:517
int nvmaps
Definition: Model_lwo.h:541
#define ID_CHAN
Definition: Model_lwo.h:137
#define ID_DESC
Definition: Model_lwo.h:62
GLdouble s
Definition: glext.h:2935
#define ID_LTEX
Definition: Model_lwo.cpp:1664
GLenum GLsizei len
Definition: glext.h:3472
struct st_lwClip * next
Definition: Model_lwo.h:290
GLhandleARB obj
Definition: glext.h:3602
lwEParam wraph
Definition: Model_lwo.h:336
lwTParam val
Definition: Model_lwo.h:422
lwGradKey * key
Definition: Model_lwo.h:374
lwEParam glow
Definition: Model_lwo.h:456
unsigned short getU2(idFile *fp)
Definition: Model_lwo.cpp:1104
GLenum GLint x
Definition: glext.h:2849
int i
Definition: process.py:33
char * name
Definition: Model_lwo.h:272
GLintptr offset
Definition: glext.h:3113
int get_flen(void)
Definition: Model_lwo.cpp:1004
#define ID_LUMI
Definition: Model_lwo.h:108
lwSurface * lwDefaultSurface(void)
Definition: Model_lwo.cpp:3628
#define BEH_CONSTANT
Definition: Model_lwo.h:235
#define ID_STEX
Definition: Model_lwo.cpp:1666
lwVParam rotate
Definition: Model_lwo.h:321
GLsizei range
Definition: glext.h:4368
lwClipStill still
Definition: Model_lwo.h:294
#define ID_BEZ2
Definition: Model_lwo.h:86
unsigned int type
Definition: Model_lwo.h:381
struct st_lwNode * next
Definition: Model_lwo.h:193
int index
Definition: Model_lwo.h:291
struct st_lwKey * prev
Definition: Model_lwo.h:212
lwPointList point
Definition: Model_lwo.h:539
#define ID_POLS
Definition: Model_lwo.h:57
int options
Definition: Model_lwo.h:423
#define ID_SPAN
Definition: Model_lwo.h:82
lwEParam wrapw
Definition: Model_lwo.h:335
lwTexture * tex
Definition: Model_lwo.h:408
lwEParam color_filter
Definition: Model_lwo.h:453
float duration
Definition: Model_lwo.h:301
lwTParam specularity
Definition: Model_lwo.h:441
void set_flen(int i)
Definition: Model_lwo.cpp:1002
#define ID_NAME
Definition: Model_lwo.h:138
#define ID_OPAC
Definition: Model_lwo.h:140
#define ID_TEXT
Definition: Model_lwo.h:63
lwPlugin * ifilter
Definition: Model_lwo.h:309
lwTParam translucency
Definition: Model_lwo.h:446
Definition: File.h:50
lwPolygon * pol
Definition: Model_lwo.h:525
lwObject * lwGetObject5(const char *filename, unsigned int *failID, int *failpos)
Definition: Model_lwo.cpp:2219
int fall_type
Definition: Model_lwo.h:323
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
#define ID_PRE
Definition: Model_lwo.h:79
#define ID_TAAS
Definition: Model_lwo.cpp:1677
#define ID_AAST
Definition: Model_lwo.h:163
lwPlugin * lwGetShader(idFile *fp, int bloksz)
Definition: Model_lwo.cpp:3486
int cindex
Definition: Model_lwo.h:424
#define ID_ICON
Definition: Model_lwo.h:64
#define ID_SHRP
Definition: Model_lwo.h:127
int lwGetPointVMaps(lwPointList *point, lwVMap *vmap)
Definition: Model_lwo.cpp:4028
void * data
Definition: Model_lwo.h:205
float val
Definition: Model_lwo.h:245
float bias
Definition: Model_lwo.h:218
float getF4(idFile *fp)
Definition: Model_lwo.cpp:1178
GLuint index
Definition: glext.h:3476
#define ID_PROJ
Definition: Model_lwo.h:142
const GLubyte * c
Definition: glext.h:4677
#define ID_XREF
Definition: Model_lwo.h:94
int coord_sys
Definition: Model_lwo.h:325
char ** tag
Definition: Model_lwo.h:551
#define FLEN_ERROR
Definition: Model_lwo.cpp:998
#define ID_AVAL
Definition: Model_lwo.h:131
#define ID_TMAP
Definition: Model_lwo.h:147
char * ord
Definition: Model_lwo.h:202
#define ID_TYPE
Definition: Model_lwo.h:136
#define ID_ALPH
Definition: Model_lwo.h:130
#define ID_VDIF
Definition: Model_lwo.cpp:1658
lwEnvelope * lwGetEnvelope(idFile *fp, int cksize)
Definition: Model_lwo.cpp:338
#define ID_BBOX
Definition: Model_lwo.h:54
static float Fabs(float f)
Definition: Math.h:779
struct st_lwNode * prev
Definition: Model_lwo.h:193
#define ID_WRPW
Definition: Model_lwo.h:160
lwSurface * lwGetSurface5(idFile *fp, int cksize, lwObject *obj)
Definition: Model_lwo.cpp:1821
#define BEH_OSCILLATE
Definition: Model_lwo.h:237
int getI1(idFile *fp)
Definition: Model_lwo.cpp:1041
#define NULL
Definition: Lib.h:88
lwEParam amplitude
Definition: Model_lwo.h:341
int lwGetTHeader(idFile *fp, int hsz, lwTexture *tex)
Definition: Model_lwo.cpp:2977
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
#define ID_BLOK
Definition: Model_lwo.h:133
int lwAllocPolygons(lwPolygonList *plist, int npols, int nverts)
Definition: Model_lwo.cpp:2479
lwEParam hue
Definition: Model_lwo.h:306
#define ID_KEY
Definition: Model_lwo.h:81
#define ID_GAMM
Definition: Model_lwo.h:101
lwLayer * layer
Definition: Model_lwo.h:559
struct st_lwEnvelope * next
Definition: Model_lwo.h:223
#define ID_SMAN
Definition: Model_lwo.h:122
#define ID_ENVL
Definition: Model_lwo.h:59
#define ID_ISEQ
Definition: Model_lwo.h:92
#define ID_TFP0
Definition: Model_lwo.cpp:1681
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
#define ID_STCC
Definition: Model_lwo.h:95
char * string
Definition: Model_lwo.h:278
int lwGetImageMap(idFile *fp, int rsz, lwTexture *tex)
Definition: Model_lwo.cpp:3156
#define ID_IFLT
Definition: Model_lwo.h:103
lwPolygonList polygon
Definition: Model_lwo.h:540
lwEnvelope * lwFindEnvelope(lwEnvelope *list, int index)
Definition: Model_lwo.cpp:481
#define ID_HUE
Definition: Model_lwo.h:100
lwEParam color_hilite
Definition: Model_lwo.h:452
lwEParam size
Definition: Model_lwo.h:431
void lwFreeLayer(lwLayer *layer)
Definition: Model_lwo.cpp:1392
float rgba[4]
Definition: Model_lwo.h:365
void lwFreeTexture(lwTexture *t)
Definition: Model_lwo.cpp:2914
#define ID_IMAP
Definition: Model_lwo.h:157
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void lwListFree(void *list, void(*freeNode)(void *))
Definition: Model_lwo.cpp:905
#define ID_FORM
Definition: Model_lwo.h:46
#define ID_GREN
Definition: Model_lwo.h:178
#define ID_CLRF
Definition: Model_lwo.h:125
lwEParam opacity
Definition: Model_lwo.h:383
#define ID_FUNC
Definition: Model_lwo.h:170
#define ID_REFL
Definition: Model_lwo.h:112
int perpoly
Definition: Model_lwo.h:471
#define ID_STIL
Definition: Model_lwo.h:91
lwProcedural proc
Definition: Model_lwo.h:390
lwTagList taglist
Definition: Model_lwo.h:563
int lwGetPolygonTags(idFile *fp, int cksize, lwTagList *tlist, lwPolygonList *plist)
Definition: Model_lwo.cpp:2857
unsigned int type
Definition: Model_lwo.h:292
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
lwClipSeq seq
Definition: Model_lwo.h:295
#define BEH_LINEAR
Definition: Model_lwo.h:239
#define ID_IKEY
Definition: Model_lwo.h:183
#define ID_TREF
Definition: Model_lwo.cpp:1678
#define ID_VMAP
Definition: Model_lwo.h:162
virtual int Seek(long offset, fsOrigin_t origin)
Definition: File.cpp:242
lwClipAnim anim
Definition: Model_lwo.h:296
virtual ID_TIME_T Timestamp(void)
Definition: File.cpp:208
int * vindex
Definition: Model_lwo.h:472
float frame_rate
Definition: Model_lwo.h:302
#define ID_RFOP
Definition: Model_lwo.h:113
GLfloat GLfloat v1
Definition: glext.h:3607
#define ID_RIMG
Definition: Model_lwo.h:114
float rgb[3]
Definition: Model_lwo.h:406
float sgetF4(unsigned char **bp)
Definition: Model_lwo.cpp:1341
lwPlugin * cfilter
Definition: Model_lwo.h:230
GLubyte GLubyte b
Definition: glext.h:4662
int nvmaps
Definition: Model_lwo.h:492
#define vecangle(a, b)
Definition: Model_lwo.h:649
#define ID_RFLT
Definition: Model_lwo.cpp:1660
void lwFreeTags(lwTagList *tlist)
Definition: Model_lwo.cpp:2773
#define ID_TIME
Definition: Model_lwo.h:96
lwTMap tmap
Definition: Model_lwo.h:393
lwVMapPt * vm
Definition: Model_lwo.h:500
int lwGetTMap(idFile *fp, int tmapsz, lwTMap *tmap)
Definition: Model_lwo.cpp:3068
#define ID_TAGS
Definition: Model_lwo.h:52
#define ID_LWO2
Definition: Model_lwo.h:47
#define BEH_OFFSET
Definition: Model_lwo.h:238
void lwFreeVMap(lwVMap *vmap)
Definition: Model_lwo.cpp:3916
#define ID_PNAM
Definition: Model_lwo.h:179
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
float value[3]
Definition: Model_lwo.h:357
char * name
Definition: Model_lwo.h:226
lwRMap reflection
Definition: Model_lwo.h:443
#define ID_LINE
Definition: Model_lwo.h:128
float continuity
Definition: Model_lwo.h:217
GLuint id
Definition: glext.h:3103
void lwGetPolyNormals(lwPointList *point, lwPolygonList *polygon)
Definition: Model_lwo.cpp:2599
#define ID_COLR
Definition: Model_lwo.h:168
lwSurface * surf
Definition: Model_lwo.h:562
#define ID_CLRH
Definition: Model_lwo.h:124
tuple f
Definition: idal.py:89
char * server
Definition: Model_lwo.h:273
void lwGetVertNormals(lwPointList *point, lwPolygonList *polygon)
Definition: Model_lwo.cpp:2733
float ** val
Definition: Model_lwo.h:474
void BigRevBytes(void *bp, int elsize, int elcount)
Definition: Lib.cpp:284
GLuint in
Definition: glext.h:5388
#define ID_TFLG
Definition: Model_lwo.cpp:1668
void lwFreeEnvelope(lwEnvelope *env)
Definition: Model_lwo.cpp:314
unsigned char byte
Definition: Lib.h:75
struct st_lwKey * next
Definition: Model_lwo.h:212
unsigned int type
Definition: Model_lwo.h:468
#define FLOAT_IS_DENORMAL(x)
Definition: Math.h:77
unsigned int shape
Definition: Model_lwo.h:215
#define ID_DIFF
Definition: Model_lwo.h:109
#define ID_SDAT
Definition: Model_lwo.cpp:1680
const GLcharARB * name
Definition: glext.h:3629
GLfloat * st
Definition: qgl.h:89
#define ID_GRAD
Definition: Model_lwo.h:176
GLsizeiptr size
Definition: glext.h:3112
int alpha_mode
Definition: Model_lwo.h:451
#define ID_TIMG
Definition: Model_lwo.cpp:1676
int nverts
Definition: Model_lwo.h:470
float start_time
Definition: Model_lwo.h:300
#define ID_TTEX
Definition: Model_lwo.cpp:1667
int behavior[2]
Definition: Model_lwo.h:229
lwEParam add_trans
Definition: Model_lwo.h:454
int * pindex
Definition: Model_lwo.h:473
void * data
Definition: Model_lwo.h:274
#define ID_VSPC
Definition: Model_lwo.cpp:1659
#define ID_AXIS
Definition: Model_lwo.h:148
float evalEnvelope(lwEnvelope *env, float time)
Definition: Model_lwo.cpp:765
#define ID_RIND
Definition: Model_lwo.h:119
lwClip * lwGetClip(idFile *fp, int cksize)
Definition: Model_lwo.cpp:90
lwTParam glossiness
Definition: Model_lwo.h:442
#define ID_STCK
Definition: Model_lwo.h:143
void * Mem_ClearedAlloc(const int size)
Definition: Heap.cpp:1149
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
float bbox[6]
Definition: Model_lwo.h:538
float norm[3]
Definition: Model_lwo.h:509
#define ID_WRAP
Definition: Model_lwo.h:159
unsigned int getU4(idFile *fp)
Definition: Model_lwo.cpp:1119
char * vmap_name
Definition: Model_lwo.h:331
#define ID_SRFS
Definition: Model_lwo.cpp:1655
#define ID_SIZE
Definition: Model_lwo.h:150
lwTexture * lwGetTexture(idFile *fp, int bloksz, unsigned int type)
Definition: Model_lwo.cpp:3438
#define ID_LWOB
Definition: Model_lwo.h:48
short * ikey
Definition: Model_lwo.h:375
char * name
Definition: Model_lwo.h:467
#define ID_TRNL
Definition: Model_lwo.h:120
int lwGetPoints(idFile *fp, int cksize, lwPointList *point)
Definition: Model_lwo.cpp:2402
#define ID_CNTR
Definition: Model_lwo.h:149
lwObject * lwGetObject(const char *filename, unsigned int *failID, int *failpos)
Definition: Model_lwo.cpp:1445
#define ID_SHDR
Definition: Model_lwo.h:186
short enabled
Definition: Model_lwo.h:429
#define ID_VLUM
Definition: Model_lwo.cpp:1657
char * paramname
Definition: Model_lwo.h:369
char * getS0(idFile *fp)
Definition: Model_lwo.cpp:1197
lwEParam gamma
Definition: Model_lwo.h:307
float aa_strength
Definition: Model_lwo.h:337
#define ID_IMAG
Definition: Model_lwo.h:158
char * prefix
Definition: Model_lwo.h:262
float pos[3]
Definition: Model_lwo.h:489
float tension
Definition: Model_lwo.h:216
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
short opac_type
Definition: Model_lwo.h:384
short enabled
Definition: Model_lwo.h:385
int sgetI1(unsigned char **bp)
Definition: Model_lwo.cpp:1243
union st_lwTexture::@93 param
GLint j
Definition: qgl.h:264
float dot(float a[], float b[])
Definition: Model_lwo.cpp:3883
int npfilters
Definition: Model_lwo.h:312
lwPlugin * pfilter
Definition: Model_lwo.h:311
void lwFreePolygons(lwPolygonList *plist)
Definition: Model_lwo.cpp:2372
#define ID_SURF
Definition: Model_lwo.h:74
int nifilters
Definition: Model_lwo.h:310
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
lwSurface * lwGetSurface(idFile *fp, int cksize)
Definition: Model_lwo.cpp:3655
int sgetVX(unsigned char **bp)
Definition: Model_lwo.cpp:1320
void lwFreeObject(lwObject *object)
Definition: Model_lwo.cpp:1411
#define ID_BUMP
Definition: Model_lwo.h:121
virtual void CloseFile(idFile *f)=0
short getI2(idFile *fp)
Definition: Model_lwo.cpp:1058
void lwFree(void *ptr)
Definition: Model_lwo.cpp:310
struct st_lwVMap * next
Definition: Model_lwo.h:466
lwVParam center
Definition: Model_lwo.h:320
lwImageMap imap
Definition: Model_lwo.h:389
float time
Definition: Model_lwo.h:214
#define ID_CLIP
Definition: Model_lwo.h:60
#define ID_FLAG
Definition: Model_lwo.cpp:1656
float pivot[3]
Definition: Model_lwo.h:537
GLfloat GLfloat p
Definition: glext.h:4674
#define ID_TAMP
Definition: Model_lwo.cpp:1675
lwTParam diffuse
Definition: Model_lwo.h:440
int getI4(idFile *fp)
Definition: Model_lwo.cpp:1073
#define ID_BRIT
Definition: Model_lwo.h:98
char * suffix
Definition: Model_lwo.h:263
lwTexture * tex
Definition: Model_lwo.h:402
int * pol
Definition: Model_lwo.h:491
unsigned int chan
Definition: Model_lwo.h:382
float value
Definition: Model_lwo.h:364
#define ID_TVAL
Definition: Model_lwo.cpp:1674
int getVX(idFile *fp)
Definition: Model_lwo.cpp:1134
#define ID_GVAL
Definition: Model_lwo.h:132
void lwListInsert(void **vlist, void *vitem, int(*compare)(void *, void *))
Definition: Model_lwo.cpp:950
#define ID_GRPT
Definition: Model_lwo.h:181
float alpha
Definition: Model_lwo.h:450
struct st_lwGradKey lwGradKey
int lwGetPolygons(idFile *fp, int cksize, lwPolygonList *plist, int ptoffset)
Definition: Model_lwo.cpp:2522
int parent
Definition: Model_lwo.h:535
#define ID_SIDE
Definition: Model_lwo.h:123
#define ID_TROP
Definition: Model_lwo.h:117
#define ID_TOPC
Definition: Model_lwo.cpp:1679
#define ID_PNTS
Definition: Model_lwo.h:53
#define ID_VMAD
Definition: Model_lwo.h:56
#define ID_BTEX
Definition: Model_lwo.cpp:1661
lwVParam size
Definition: Model_lwo.h:319
lwLine line
Definition: Model_lwo.h:457
int lwGetPolygons5(idFile *fp, int cksize, lwPolygonList *plist, int ptoffset)
Definition: Model_lwo.cpp:2128
float norm[3]
Definition: Model_lwo.h:498
#define ID_SPEC
Definition: Model_lwo.h:110
char * name
Definition: Model_lwo.h:436
float param[4]
Definition: Model_lwo.h:219
void lwListAdd(void **list, void *node)
Definition: Model_lwo.cpp:925
void lwFreeSurface(lwSurface *surf)
Definition: Model_lwo.cpp:2944
float seam_angle
Definition: Model_lwo.h:425
GLdouble GLdouble t
Definition: glext.h:2943
void skipbytes(idFile *fp, int n)
Definition: Model_lwo.cpp:1031
void normalize(float v[])
Definition: Model_lwo.cpp:3897
#define ID_HERM
Definition: Model_lwo.h:84