2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
32 #include "Model_lwo.h"
35 ======================================================================
37 Converted from lwobject sample prog from LW 6.5 SDK.
39 ======================================================================
43 ======================================================================
46 Free memory used by an lwClip.
47 ====================================================================== */
49 void lwFreeClip( lwClip *clip )
52 lwListFree( clip->ifilter, (void (__cdecl *)(void *))lwFreePlugin );
53 lwListFree( clip->pfilter, (void (__cdecl *)(void *))lwFreePlugin );
54 switch( clip->type ) {
56 if ( clip->source.still.name ) Mem_Free( clip->source.still.name );
60 if ( clip->source.seq.suffix ) Mem_Free( clip->source.seq.suffix );
61 if ( clip->source.seq.prefix ) Mem_Free( clip->source.seq.prefix );
65 if ( clip->source.anim.server ) Mem_Free( clip->source.anim.server );
66 if ( clip->source.anim.name ) Mem_Free( clip->source.anim.name );
70 if ( clip->source.xref.string ) Mem_Free( clip->source.xref.string );
74 if ( clip->source.cycle.name ) Mem_Free( clip->source.cycle.name );
84 ======================================================================
87 Read image references from a CLIP chunk in an LWO2 file.
88 ====================================================================== */
90 lwClip *lwGetClip( idFile *fp, int cksize )
99 /* allocate the Clip structure */
101 clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
102 if ( !clip ) goto Fail;
104 clip->contrast.val = 1.0f;
105 clip->brightness.val = 1.0f;
106 clip->saturation.val = 1.0f;
107 clip->gamma.val = 1.0f;
109 /* remember where we started */
116 clip->index = getI4( fp );
118 /* first subchunk header */
120 clip->type = getU4( fp );
122 if ( 0 > get_flen() ) goto Fail;
127 switch ( clip->type ) {
129 clip->source.still.name = getS0( fp );
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 );
143 clip->source.anim.name = getS0( fp );
144 clip->source.anim.server = getS0( fp );
146 clip->source.anim.data = getbytes( fp, sz - rlen );
150 clip->source.xref.index = getI4( fp );
151 clip->source.xref.string = getS0( fp );
155 clip->source.cycle.lo = getI2( fp );
156 clip->source.cycle.hi = getI2( fp );
157 clip->source.cycle.name = getS0( fp );
164 /* error while reading current subchunk? */
167 if ( rlen < 0 || rlen > sz ) goto Fail;
169 /* skip unread parts of the current subchunk */
172 fp->Seek( sz - rlen, FS_SEEK_CUR );
174 /* end of the CLIP chunk? */
176 rlen = fp->Tell() - pos;
177 if ( cksize < rlen ) goto Fail;
178 if ( cksize == rlen )
181 /* process subchunks as they're encountered */
185 if ( 0 > get_flen() ) goto Fail;
193 clip->start_time = getF4( fp );
194 clip->duration = getF4( fp );
195 clip->frame_rate = getF4( fp );
199 clip->contrast.val = getF4( fp );
200 clip->contrast.eindex = getVX( fp );
204 clip->brightness.val = getF4( fp );
205 clip->brightness.eindex = getVX( fp );
209 clip->saturation.val = getF4( fp );
210 clip->saturation.eindex = getVX( fp );
214 clip->hue.val = getF4( fp );
215 clip->hue.eindex = getVX( fp );
219 clip->gamma.val = getF4( fp );
220 clip->gamma.eindex = getVX( fp );
224 clip->negative = getU2( fp );
229 filt = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
230 if ( !filt ) goto Fail;
232 filt->name = getS0( fp );
233 filt->flags = getU2( fp );
235 filt->data = getbytes( fp, sz - rlen );
237 if ( id == ID_IFLT ) {
238 lwListAdd( (void**)&clip->ifilter, filt );
242 lwListAdd( (void**)&clip->pfilter, filt );
251 /* error while reading current subchunk? */
254 if ( rlen < 0 || rlen > sz ) goto Fail;
256 /* skip unread parts of the current subchunk */
259 fp->Seek( sz - rlen, FS_SEEK_CUR );
261 /* end of the CLIP chunk? */
263 rlen = fp->Tell() - pos;
264 if ( cksize < rlen ) goto Fail;
265 if ( cksize == rlen ) break;
267 /* get the next chunk header */
272 if ( 6 != get_flen() ) goto Fail;
284 ======================================================================
287 Returns an lwClip pointer, given a clip index.
288 ====================================================================== */
290 lwClip *lwFindClip( lwClip *list, int index )
296 if ( clip->index == index ) break;
304 ======================================================================
307 Free the memory used by an lwEnvelope.
308 ====================================================================== */
310 void lwFree( void *ptr ) {
314 void lwFreeEnvelope( lwEnvelope *env )
317 if ( env->name ) Mem_Free( env->name );
318 lwListFree( env->key, lwFree );
319 lwListFree( env->cfilter, (void (__cdecl *)(void *))lwFreePlugin );
325 static int compare_keys( lwKey *k1, lwKey *k2 )
327 return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
332 ======================================================================
335 Read an ENVL chunk from an LWO2 file.
336 ====================================================================== */
338 lwEnvelope *lwGetEnvelope( idFile *fp, int cksize )
346 int i, nparams, pos, rlen;
349 /* allocate the Envelope structure */
351 env = (lwEnvelope*)Mem_ClearedAlloc( sizeof( lwEnvelope ) );
352 if ( !env ) goto Fail;
354 /* remember where we started */
361 env->index = getVX( fp );
363 /* first subchunk header */
367 if ( 0 > get_flen() ) goto Fail;
369 /* process subchunks as they're encountered */
377 env->type = getU2( fp );
381 env->name = getS0( fp );
385 env->behavior[ 0 ] = getU2( fp );
389 env->behavior[ 1 ] = getU2( fp );
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 );
402 if ( !key ) goto Fail;
403 key->shape = getU4( fp );
405 nparams = ( sz - 4 ) / 4;
406 if ( nparams > 4 ) nparams = 4;
407 for ( i = 0; i < nparams; i++ )
408 f[ i ] = getF4( fp );
410 switch ( key->shape ) {
412 key->tension = f[ 0 ];
413 key->continuity = f[ 1 ];
420 for ( i = 0; i < nparams; i++ )
421 key->param[ i ] = f[ i ];
427 plug = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
428 if ( !plug ) goto Fail;
430 plug->name = getS0( fp );
431 plug->flags = getU2( fp );
432 plug->data = getbytes( fp, sz - get_flen() );
434 lwListAdd( (void**)&env->cfilter, plug );
442 /* error while reading current subchunk? */
445 if ( rlen < 0 || rlen > sz ) goto Fail;
447 /* skip unread parts of the current subchunk */
450 fp->Seek( sz - rlen, FS_SEEK_CUR );
452 /* end of the ENVL chunk? */
454 rlen = fp->Tell() - pos;
455 if ( cksize < rlen ) goto Fail;
456 if ( cksize == rlen ) break;
458 /* get the next subchunk header */
463 if ( 6 != get_flen() ) goto Fail;
469 lwFreeEnvelope( env );
475 ======================================================================
478 Returns an lwEnvelope pointer, given an envelope index.
479 ====================================================================== */
481 lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index )
487 if ( env->index == index ) break;
495 ======================================================================
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.
502 v2 = v - i * (hi - lo)
504 For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
505 ====================================================================== */
507 static float range( float v, float lo, float hi, int *i )
509 float v2, r = hi - lo;
516 v2 = lo + v - r * ( float ) floor(( double ) v / r );
517 if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
524 ======================================================================
527 Calculate the Hermite coefficients.
528 ====================================================================== */
530 static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
537 *h2 = 3.0f * t2 - t3 - t3;
545 ======================================================================
548 Interpolate the value of a 1D Bezier curve.
549 ====================================================================== */
551 static float bezier( float x0, float x1, float x2, float x3, float t )
553 float a, b, c, t2, t3;
558 c = 3.0f * ( x1 - x0 );
559 b = 3.0f * ( x2 - x1 ) - c;
562 return a * t3 + b * t2 + c * t + x0;
567 ======================================================================
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 ====================================================================== */
576 static float bez2_time( float x0, float x1, float x2, float x3, float time,
577 float *t0, float *t1 )
581 t = *t0 + ( *t1 - *t0 ) * 0.5f;
582 v = bezier( x0, x1, x2, x3, t );
583 if ( idMath::Fabs( time - v ) > .0001f ) {
588 return bez2_time( x0, x1, x2, x3, time, t0, t1 );
596 ======================================================================
599 Interpolate the value of a BEZ2 curve.
600 ====================================================================== */
602 static float bez2( lwKey *key0, lwKey *key1, float time )
604 float x, y, t, t0 = 0.0f, t1 = 1.0f;
606 if ( key0->shape == ID_BEZ2 )
607 x = key0->time + key0->param[ 2 ];
609 x = key0->time + ( key1->time - key0->time ) / 3.0f;
611 t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
614 if ( key0->shape == ID_BEZ2 )
615 y = key0->value + key0->param[ 3 ];
617 y = key0->value + key0->param[ 1 ] / 3.0f;
619 return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
624 ======================================================================
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 ====================================================================== */
632 static float outgoing( lwKey *key0, lwKey *key1 )
634 float a, b, d, t, out;
636 switch ( key0->shape )
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;
648 t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
649 out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
656 d = key1->value - key0->value;
658 t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
659 out = t * ( key0->value - key0->prev->value + d );
667 out = key0->param[ 1 ];
669 out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
673 out = key0->param[ 3 ] * ( key1->time - key0->time );
674 if ( idMath::Fabs( key0->param[ 2 ] ) > 1e-5f )
675 out /= key0->param[ 2 ];
691 ======================================================================
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 ====================================================================== */
698 static float incoming( lwKey *key0, lwKey *key1 )
700 float a, b, d, t, in;
702 switch ( key1->shape )
705 d = key1->value - key0->value;
707 t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
708 in = t * ( key1->next->value - key1->value + d );
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;
724 t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
725 in = t * ( b * ( key1->next->value - key1->value ) + a * d );
733 in = key1->param[ 0 ];
735 in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
740 in = key1->param[ 1 ] * ( key1->time - key0->time );
741 if ( idMath::Fabs( key1->param[ 0 ] ) > 1e-5f )
742 in /= key1->param[ 0 ];
758 ======================================================================
761 Given a list of keys and a time, returns the interpolated value of the
762 envelope at that time.
763 ====================================================================== */
765 float evalEnvelope( lwEnvelope *env, float time )
767 lwKey *key0, *key1, *skey, *ekey;
768 float t, h1, h2, h3, h4, in, out, offset = 0.0f;
772 /* if there's no key, the value is 0 */
774 if ( env->nkeys == 0 ) return 0.0f;
776 /* if there's only one key, the value is constant */
778 if ( env->nkeys == 1 )
779 return env->key->value;
781 /* find the first and last keys */
783 skey = ekey = env->key;
784 while ( ekey->next ) ekey = ekey->next;
786 /* use pre-behavior if time is before first key time */
788 if ( time < skey->time ) {
789 switch ( env->behavior[ 0 ] )
798 time = range( time, skey->time, ekey->time, NULL );
802 time = range( time, skey->time, ekey->time, &noff );
804 time = ekey->time - skey->time - time;
808 time = range( time, skey->time, ekey->time, &noff );
809 offset = noff * ( ekey->value - skey->value );
813 out = outgoing( skey, skey->next )
814 / ( skey->next->time - skey->time );
815 return out * ( time - skey->time ) + skey->value;
819 /* use post-behavior if time is after last key time */
821 else if ( time > ekey->time ) {
822 switch ( env->behavior[ 1 ] )
831 time = range( time, skey->time, ekey->time, NULL );
835 time = range( time, skey->time, ekey->time, &noff );
837 time = ekey->time - skey->time - time;
841 time = range( time, skey->time, ekey->time, &noff );
842 offset = noff * ( ekey->value - skey->value );
846 in = incoming( ekey->prev, ekey )
847 / ( ekey->time - ekey->prev->time );
848 return in * ( time - ekey->time ) + ekey->value;
852 /* get the endpoints of the interval being evaluated */
855 while ( time > key0->next->time )
859 /* check for singularities first */
861 if ( time == key0->time )
862 return key0->value + offset;
863 else if ( time == key1->time )
864 return key1->value + offset;
866 /* get interval length, time in [0, 1] */
868 t = ( time - key0->time ) / ( key1->time - key0->time );
872 switch ( key1->shape )
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;
883 return bez2( key0, key1, time ) + offset;
886 return key0->value + t * ( key1->value - key0->value ) + offset;
889 return key0->value + offset;
899 ======================================================================
902 Free the items in a list.
903 ====================================================================== */
905 void lwListFree( void *list, void ( *freeNode )( void * ))
909 node = ( lwNode * ) list;
919 ======================================================================
922 Append a node to a list.
923 ====================================================================== */
925 void lwListAdd( void **list, void *node )
929 head = *(( lwNode ** ) list );
938 tail->next = ( lwNode * ) node;
939 (( lwNode * ) node )->prev = tail;
944 ======================================================================
947 Insert a node into a list in sorted order.
948 ====================================================================== */
950 void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * ))
952 lwNode **list, *item, *node, *prev;
959 list = ( lwNode ** ) vlist;
960 item = ( lwNode * ) vitem;
965 if ( 0 < compare( node, item )) break;
988 ======================================================================
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 ====================================================================== */
998 #define FLEN_ERROR -9999
1002 void set_flen( int i ) { flen = i; }
1004 int get_flen( void ) { return flen; }
1006 void *getbytes( idFile *fp, int size )
1010 if ( flen == FLEN_ERROR ) return NULL;
1015 data = Mem_ClearedAlloc( size );
1020 if ( size != fp->Read( data, size ) ) {
1031 void skipbytes( idFile *fp, int n )
1033 if ( flen == FLEN_ERROR ) return;
1034 if ( fp->Seek( n, FS_SEEK_CUR ))
1041 int getI1( idFile *fp )
1045 if ( flen == FLEN_ERROR ) return 0;
1047 i = fp->Read(&c, 1);
1052 if ( c > 127 ) c -= 256;
1058 short getI2( idFile *fp )
1062 if ( flen == FLEN_ERROR ) return 0;
1063 if ( 2 != fp->Read( &i, 2 )) {
1067 BigRevBytes( &i, 2, 1 );
1073 int getI4( idFile *fp )
1077 if ( flen == FLEN_ERROR ) return 0;
1078 if ( 4 != fp->Read( &i, 4 )) {
1082 BigRevBytes( &i, 4, 1 );
1088 unsigned char getU1( idFile *fp )
1092 if ( flen == FLEN_ERROR ) return 0;
1094 i = fp->Read(&c, 1);
1104 unsigned short getU2( idFile *fp )
1108 if ( flen == FLEN_ERROR ) return 0;
1109 if ( 2 != fp->Read( &i, 2 )) {
1113 BigRevBytes( &i, 2, 1 );
1119 unsigned int getU4( idFile *fp )
1123 if ( flen == FLEN_ERROR ) return 0;
1124 if ( 4 != fp->Read( &i, 4 )) {
1128 BigRevBytes( &i, 4, 1 );
1134 int getVX( idFile *fp )
1139 if ( flen == FLEN_ERROR ) return 0;
1142 if (fp->Read(&c, 1) == -1) {
1149 if (fp->Read(&c, 1) == -1) {
1157 if (fp->Read(&c, 1) == -1) {
1162 if (fp->Read(&c, 1) == -1) {
1167 if (fp->Read(&c, 1) == -1) {
1178 float getF4( idFile *fp )
1182 if ( flen == FLEN_ERROR ) return 0.0f;
1183 if ( 4 != fp->Read( &f, 4 ) ) {
1187 BigRevBytes( &f, 4, 1 );
1190 if ( FLOAT_IS_DENORMAL( f ) ) {
1197 char *getS0( idFile *fp )
1202 if ( flen == FLEN_ERROR ) return NULL;
1205 for ( i = 1; ; i++ ) {
1207 if (fp->Read(&c, 1) == -1) {
1211 if ( c == 0 ) break;
1215 if ( fp->Seek( pos + 2, FS_SEEK_SET ))
1222 len = i + ( i & 1 );
1223 s = (char*)Mem_ClearedAlloc( len );
1229 if ( fp->Seek( pos, FS_SEEK_SET )) {
1233 if ( len != fp->Read( s, len )) {
1243 int sgetI1( unsigned char **bp )
1247 if ( flen == FLEN_ERROR ) return 0;
1249 if ( i > 127 ) i -= 256;
1256 short sgetI2( unsigned char **bp )
1260 if ( flen == FLEN_ERROR ) return 0;
1261 memcpy( &i, *bp, 2 );
1262 BigRevBytes( &i, 2, 1 );
1269 int sgetI4( unsigned char **bp )
1273 if ( flen == FLEN_ERROR ) return 0;
1274 memcpy( &i, *bp, 4 );
1275 BigRevBytes( &i, 4, 1 );
1282 unsigned char sgetU1( unsigned char **bp )
1286 if ( flen == FLEN_ERROR ) return 0;
1294 unsigned short sgetU2( unsigned char **bp )
1296 unsigned char *buf = *bp;
1299 if ( flen == FLEN_ERROR ) return 0;
1300 i = ( buf[ 0 ] << 8 ) | buf[ 1 ];
1307 unsigned int sgetU4( unsigned char **bp )
1311 if ( flen == FLEN_ERROR ) return 0;
1312 memcpy( &i, *bp, 4 );
1313 BigRevBytes( &i, 4, 1 );
1320 int sgetVX( unsigned char **bp )
1322 unsigned char *buf = *bp;
1325 if ( flen == FLEN_ERROR ) return 0;
1327 if ( buf[ 0 ] != 0xFF ) {
1328 i = buf[ 0 ] << 8 | buf[ 1 ];
1333 i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ];
1341 float sgetF4( unsigned char **bp )
1345 if ( flen == FLEN_ERROR ) return 0.0f;
1346 memcpy( &f, *bp, 4 );
1347 BigRevBytes( &f, 4, 1 );
1351 if ( FLOAT_IS_DENORMAL( f ) ) {
1358 char *sgetS0( unsigned char **bp )
1361 unsigned char *buf = *bp;
1364 if ( flen == FLEN_ERROR ) return NULL;
1366 len = strlen( (const char*)buf ) + 1;
1373 s = (char*)Mem_ClearedAlloc( len );
1379 memcpy( s, buf, len );
1386 ======================================================================
1389 Free memory used by an lwLayer.
1390 ====================================================================== */
1392 void lwFreeLayer( lwLayer *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 );
1405 ======================================================================
1408 Free memory used by an lwObject.
1409 ====================================================================== */
1411 void lwFreeObject( lwObject *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 );
1425 ======================================================================
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.
1432 1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and
1433 failID will be unchanged.
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.
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.
1442 If you don't need this information, failID and failpos can be NULL.
1443 ====================================================================== */
1445 lwObject *lwGetObject( const char *filename, unsigned int *failID, int *failpos )
1451 int id, formsize, type, cksize;
1454 fp = fileSystem->OpenFileRead( filename );
1459 /* read the first 12 bytes */
1463 formsize = getU4( fp );
1465 if ( 12 != get_flen() ) {
1466 fileSystem->CloseFile( fp );
1470 /* is this a LW object? */
1472 if ( id != ID_FORM ) {
1473 fileSystem->CloseFile( fp );
1474 if ( failpos ) *failpos = 12;
1478 if ( type != ID_LWO2 ) {
1479 fileSystem->CloseFile( fp );
1480 if ( type == ID_LWOB )
1481 return lwGetObject5( filename, failID, failpos );
1483 if ( failpos ) *failpos = 12;
1488 /* allocate an object and a default layer */
1490 object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
1491 if ( !object ) goto Fail;
1493 layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
1494 if ( !layer ) goto Fail;
1495 object->layer = layer;
1497 object->timeStamp = fp->Timestamp();
1499 /* get the first chunk header */
1502 cksize = getU4( fp );
1503 if ( 0 > get_flen() ) goto Fail;
1505 /* process chunks as they're encountered */
1508 cksize += cksize & 1;
1513 if ( object->nlayers > 0 ) {
1514 layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
1515 if ( !layer ) goto Fail;
1516 lwListAdd( (void**)&object->layer, layer );
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 );
1529 if ( rlen < 0 || rlen > cksize ) goto Fail;
1530 if ( rlen <= cksize - 2 )
1531 layer->parent = getU2( fp );
1533 if ( rlen < cksize )
1534 fp->Seek( cksize - rlen, FS_SEEK_CUR );
1538 if ( !lwGetPoints( fp, cksize, &layer->point ))
1543 if ( !lwGetPolygons( fp, cksize, &layer->polygon,
1544 layer->point.offset ))
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 );
1558 if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
1565 for ( i = 0; i < 6; i++ )
1566 layer->bbox[ i ] = getF4( fp );
1568 if ( rlen < 0 || rlen > cksize ) goto Fail;
1569 if ( rlen < cksize )
1570 fp->Seek( cksize - rlen, FS_SEEK_CUR );
1574 if ( !lwGetTags( fp, cksize, &object->taglist ))
1579 node = ( lwNode * ) lwGetEnvelope( fp, cksize );
1580 if ( !node ) goto Fail;
1581 lwListAdd( (void**)&object->env, node );
1586 node = ( lwNode * ) lwGetClip( fp, cksize );
1587 if ( !node ) goto Fail;
1588 lwListAdd( (void**)&object->clip, node );
1593 node = ( lwNode * ) lwGetSurface( fp, cksize );
1594 if ( !node ) goto Fail;
1595 lwListAdd( (void**)&object->surf, node );
1603 fp->Seek( cksize, FS_SEEK_CUR );
1607 /* end of the file? */
1609 if ( formsize <= fp->Tell() - 8 ) break;
1611 /* get the next chunk header */
1615 cksize = getU4( fp );
1616 if ( 8 != get_flen() ) goto Fail;
1619 fileSystem->CloseFile( fp );
1622 if ( object->nlayers == 0 )
1623 object->nlayers = 1;
1625 layer = object->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;
1641 if ( failID ) *failID = id;
1643 if ( failpos ) *failpos = fp->Tell();
1644 fileSystem->CloseFile( fp );
1646 lwFreeObject( object );
1653 /* IDs specific to LWOB */
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')
1686 ======================================================================
1689 Add a clip to the clip list. Used to store the contents of an RIMG or
1690 TIMG surface subchunk.
1691 ====================================================================== */
1693 static int add_clip( char *s, lwClip **clist, int *nclips )
1698 clip = (lwClip*)Mem_ClearedAlloc( sizeof( lwClip ) );
1699 if ( !clip ) return 0;
1701 clip->contrast.val = 1.0f;
1702 clip->brightness.val = 1.0f;
1703 clip->saturation.val = 1.0f;
1704 clip->gamma.val = 1.0f;
1706 if ( p = strstr( s, "(sequence)" )) {
1708 clip->type = ID_ISEQ;
1709 clip->source.seq.prefix = s;
1710 clip->source.seq.digits = 3;
1713 clip->type = ID_STIL;
1714 clip->source.still.name = s;
1718 clip->index = *nclips;
1720 lwListAdd( (void**)clist, clip );
1727 ======================================================================
1730 Add a triple of envelopes to simulate the old texture velocity
1732 ====================================================================== */
1734 static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs )
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;
1747 key0->value = pos[ i ];
1750 key1->value = pos[ i ] + vel[ i ] * 30.0f;
1752 key0->shape = key1->shape = ID_LINE;
1754 env->index = *nenvs + i + 1;
1755 env->type = 0x0301 + i;
1756 env->name = (char*)Mem_ClearedAlloc( 11 );
1758 strcpy( env->name, "Position.X" );
1759 env->name[ 9 ] += i;
1763 env->behavior[ 0 ] = BEH_LINEAR;
1764 env->behavior[ 1 ] = BEH_LINEAR;
1766 lwListAdd( (void**)elist, env );
1770 return env->index - 2;
1775 ======================================================================
1778 Create a new texture for BTEX, CTEX, etc. subchunks.
1779 ====================================================================== */
1781 static lwTexture *get_texture( char *s )
1785 tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
1786 if ( !tex ) return NULL;
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;
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;
1806 tex->type = ID_PROC;
1807 tex->param.proc.name = s;
1815 ======================================================================
1818 Read an lwSurface from an LWOB file.
1819 ====================================================================== */
1821 lwSurface *lwGetSurface5( idFile *fp, int cksize, lwObject *obj )
1828 unsigned int id, flags;
1833 /* allocate the Surface structure */
1835 surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
1836 if ( !surf ) goto Fail;
1838 /* non-zero defaults */
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;
1849 /* remember where we started */
1856 surf->name = getS0( fp );
1858 /* first subchunk header */
1862 if ( 0 > get_flen() ) goto Fail;
1864 /* process subchunks as they're encountered */
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;
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;
1888 surf->luminosity.val = getI2( fp ) / 256.0f;
1892 surf->luminosity.val = getF4( fp );
1896 surf->diffuse.val = getI2( fp ) / 256.0f;
1900 surf->diffuse.val = getF4( fp );
1904 surf->specularity.val = getI2( fp ) / 256.0f;
1908 surf->specularity.val = getF4( fp );
1912 surf->glossiness.val = ( float ) logf( ( float) getU2( fp )) / 20.7944f;
1916 surf->smooth = getF4( fp );
1920 surf->reflection.val.val = getI2( fp ) / 256.0f;
1924 surf->reflection.options = getU2( fp );
1929 surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
1930 surf->reflection.options = 3;
1934 surf->reflection.seam_angle = getF4( fp );
1938 surf->transparency.val.val = getI2( fp ) / 256.0f;
1942 surf->eta.val = getF4( fp );
1946 s = (char*)getbytes( fp, sz );
1947 tex = get_texture( s );
1948 lwListAdd( (void**)&surf->bump.tex, tex );
1952 s = (char*)getbytes( fp, sz );
1953 tex = get_texture( s );
1954 lwListAdd( (void**)&surf->color.tex, tex );
1958 s = (char*)getbytes( fp, sz );
1959 tex = get_texture( s );
1960 lwListAdd( (void**)&surf->diffuse.tex, tex );
1964 s = (char*)getbytes( fp, sz );
1965 tex = get_texture( s );
1966 lwListAdd( (void**)&surf->luminosity.tex, tex );
1970 s = (char*)getbytes( fp, sz );
1971 tex = get_texture( s );
1972 lwListAdd( (void**)&surf->reflection.val.tex, tex );
1976 s = (char*)getbytes( fp, sz );
1977 tex = get_texture( s );
1978 lwListAdd( (void**)&surf->specularity.tex, tex );
1982 s = (char*)getbytes( fp, sz );
1983 tex = get_texture( s );
1984 lwListAdd( (void**)&surf->transparency.val.tex, tex );
1988 flags = getU2( fp );
1990 if ( flags & 1 ) i = 0;
1991 if ( flags & 2 ) i = 1;
1992 if ( flags & 4 ) i = 2;
1994 if ( tex->type == ID_IMAP )
1995 tex->param.imap.axis = i;
1997 tex->param.proc.axis = i;
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;
2003 tex->param.imap.aa_strength = 1.0f;
2004 tex->param.imap.aas_flags = 1;
2009 for ( i = 0; i < 3; i++ )
2010 tex->tmap.size.val[ i ] = getF4( fp );
2014 for ( i = 0; i < 3; i++ )
2015 tex->tmap.center.val[ i ] = getF4( fp );
2019 for ( i = 0; i < 3; i++ )
2020 tex->tmap.falloff.val[ i ] = getF4( fp );
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 );
2031 if ( tex->type == ID_PROC )
2032 for ( i = 0; i < 3; i++ )
2033 tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
2037 tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
2041 if ( tex->type == ID_IMAP )
2042 tex->param.imap.amplitude.val = getF4( fp );
2047 tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
2051 tex->param.imap.aa_strength = getF4( fp );
2052 tex->param.imap.aas_flags = 1;
2056 tex->tmap.ref_object = (char*)getbytes( fp, sz );
2060 tex->opacity.val = getF4( fp );
2064 if ( tex->type == ID_IMAP )
2065 tex->param.imap.wrapw.val = getF4( fp );
2069 if ( tex->type == ID_IMAP )
2070 tex->param.imap.wraph.val = getF4( fp );
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 );
2082 shdr->data = getbytes( fp, sz );
2089 /* error while reading current subchunk? */
2092 if ( rlen < 0 || rlen > sz ) goto Fail;
2094 /* skip unread parts of the current subchunk */
2097 fp->Seek( sz - rlen, FS_SEEK_CUR );
2099 /* end of the SURF chunk? */
2101 if ( cksize <= fp->Tell() - pos )
2104 /* get the next subchunk header */
2109 if ( 6 != get_flen() ) goto Fail;
2115 if ( surf ) lwFreeSurface( surf );
2121 ======================================================================
2124 Read polygon records from a POLS chunk in an LWOB file. The polygons
2125 are added to the array in the lwPolygonList.
2126 ====================================================================== */
2128 int lwGetPolygons5( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
2132 unsigned char *buf, *bp;
2133 int i, j, nv, nverts, npols;
2136 if ( cksize == 0 ) return 1;
2138 /* read the whole chunk */
2141 buf = (unsigned char*)getbytes( fp, cksize );
2142 if ( !buf ) goto Fail;
2144 /* count the polygons and vertices */
2150 while ( bp < buf + cksize ) {
2156 if ( i < 0 ) bp += 2; /* detail polygons */
2159 if ( !lwAllocPolygons( plist, npols, nverts ))
2162 /* fill in the new polygons */
2165 pp = plist->pol + plist->offset;
2166 pv = plist->pol[ 0 ].v + plist->voffset;
2168 for ( i = 0; i < npols; i++ ) {
2173 if ( !pp->v ) pp->v = pv;
2174 for ( j = 0; j < nv; j++ )
2175 pv[ j ].index = sgetU2( &bp ) + ptoffset;
2182 pp->surf = ( lwSurface * ) j;
2192 if ( buf ) Mem_Free( buf );
2193 lwFreePolygons( plist );
2199 ======================================================================
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.
2206 1. If the file isn't an LWOB, failpos will contain 12 and failID will
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.
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.
2216 If you don't need this information, failID and failpos can be NULL.
2217 ====================================================================== */
2219 lwObject *lwGetObject5( const char *filename, unsigned int *failID, int *failpos )
2225 int id, formsize, type, cksize;
2230 //fp = fopen( filename, "rb" );
2231 //if ( !fp ) return NULL;
2233 /* read the first 12 bytes */
2234 fp = fileSystem->OpenFileRead( filename );
2241 formsize = getU4( fp );
2243 if ( 12 != get_flen() ) {
2244 fileSystem->CloseFile( fp );
2250 if ( id != ID_FORM || type != ID_LWOB ) {
2251 fileSystem->CloseFile( fp );
2252 if ( failpos ) *failpos = 12;
2256 /* allocate an object and a default layer */
2258 object = (lwObject*)Mem_ClearedAlloc( sizeof( lwObject ) );
2259 if ( !object ) goto Fail2;
2261 layer = (lwLayer*)Mem_ClearedAlloc( sizeof( lwLayer ) );
2262 if ( !layer ) goto Fail2;
2263 object->layer = layer;
2264 object->nlayers = 1;
2266 /* get the first chunk header */
2269 cksize = getU4( fp );
2270 if ( 0 > get_flen() ) goto Fail2;
2272 /* process chunks as they're encountered */
2275 cksize += cksize & 1;
2280 if ( !lwGetPoints( fp, cksize, &layer->point ))
2285 if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
2286 layer->point.offset ))
2291 if ( !lwGetTags( fp, cksize, &object->taglist ))
2296 node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
2297 if ( !node ) goto Fail2;
2298 lwListAdd( (void**)&object->surf, node );
2303 fp->Seek( cksize, FS_SEEK_CUR );
2307 /* end of the file? */
2309 if ( formsize <= fp->Tell() - 8 ) break;
2311 /* get the next chunk header */
2315 cksize = getU4( fp );
2316 if ( 8 != get_flen() ) goto Fail2;
2319 fileSystem->CloseFile( fp );
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 );
2332 if ( failID ) *failID = id;
2334 if ( failpos ) *failpos = fp->Tell();
2335 fileSystem->CloseFile( fp );
2337 lwFreeObject( object );
2342 ======================================================================
2345 Free the memory used by an lwPointList.
2346 ====================================================================== */
2348 void lwFreePoints( lwPointList *point )
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 );
2358 Mem_Free( point->pt );
2360 memset( point, 0, sizeof( lwPointList ));
2366 ======================================================================
2369 Free the memory used by an lwPolygonList.
2370 ====================================================================== */
2372 void lwFreePolygons( lwPolygonList *plist )
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 );
2385 if ( plist->pol[ 0 ].v )
2386 Mem_Free( plist->pol[ 0 ].v );
2387 Mem_Free( plist->pol );
2389 memset( plist, 0, sizeof( lwPolygonList ));
2395 ======================================================================
2398 Read point records from a PNTS chunk in an LWO2 file. The points are
2399 added to the array in the lwPointList.
2400 ====================================================================== */
2402 int lwGetPoints( idFile *fp, int cksize, lwPointList *point )
2407 if ( cksize == 1 ) return 1;
2409 /* extend the point array to hold the new points */
2412 point->offset = point->count;
2414 lwPoint *oldpt = point->pt;
2415 point->pt = (lwPoint*)Mem_Alloc( point->count * sizeof( lwPoint ) );
2416 if ( !point->pt ) return 0;
2418 memcpy( point->pt, oldpt, point->offset * sizeof( lwPoint ) );
2421 memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint ) );
2423 /* read the whole chunk */
2425 f = ( float * ) getbytes( fp, cksize );
2427 BigRevBytes( f, 4, np * 3 );
2429 /* assign position values */
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 ];
2443 ======================================================================
2446 Calculate the bounding box for a point list, but only if the bounding
2447 box hasn't already been initialized.
2448 ====================================================================== */
2450 void lwGetBoundingBox( lwPointList *point, float bbox[] )
2454 if ( point->count == 0 ) return;
2456 for ( i = 0; i < 6; i++ )
2457 if ( bbox[ i ] != 0.0f ) return;
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 ];
2473 ======================================================================
2476 Allocate or extend the polygon arrays to hold new records.
2477 ====================================================================== */
2479 int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts )
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;
2489 memcpy( plist->pol, oldpol, plist->offset * sizeof( lwPolygon ) );
2492 memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon ) );
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;
2500 memcpy( plist->pol[0].v, oldpolv, plist->voffset * sizeof( lwPolVert ) );
2501 Mem_Free( oldpolv );
2503 memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert ) );
2505 /* fix up the old vertex pointers */
2507 for ( i = 1; i < plist->offset; i++ )
2508 plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts;
2515 ======================================================================
2518 Read polygon records from a POLS chunk in an LWO2 file. The polygons
2519 are added to the array in the lwPolygonList.
2520 ====================================================================== */
2522 int lwGetPolygons( idFile *fp, int cksize, lwPolygonList *plist, int ptoffset )
2526 unsigned char *buf, *bp;
2527 int i, j, flags, nv, nverts, npols;
2531 if ( cksize == 0 ) return 1;
2533 /* read the whole chunk */
2537 buf = (unsigned char*)getbytes( fp, cksize - 4 );
2538 if ( cksize != get_flen() ) goto Fail;
2540 /* count the polygons and vertices */
2546 while ( bp < buf + cksize - 4 ) {
2551 for ( i = 0; i < nv; i++ )
2555 if ( !lwAllocPolygons( plist, npols, nverts ))
2558 /* fill in the new polygons */
2561 pp = plist->pol + plist->offset;
2562 pv = plist->pol[ 0 ].v + plist->voffset;
2564 for ( i = 0; i < npols; i++ ) {
2566 flags = nv & 0xFC00;
2572 if ( !pp->v ) pp->v = pv;
2573 for ( j = 0; j < nv; j++ )
2574 pp->v[ j ].index = sgetVX( &bp ) + ptoffset;
2584 if ( buf ) Mem_Free( buf );
2585 lwFreePolygons( plist );
2591 ======================================================================
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 ====================================================================== */
2599 void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon )
2602 float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ];
2604 for ( i = 0; i < polygon->count; i++ ) {
2605 if ( polygon->pol[ i ].nverts < 3 ) continue;
2606 for ( j = 0; j < 3; j++ ) {
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 ];
2614 for ( j = 0; j < 3; j++ ) {
2615 v1[ j ] = p2[ j ] - p1[ j ];
2616 v2[ j ] = pn[ j ] - p1[ j ];
2619 cross( v1, v2, polygon->pol[ i ].norm );
2620 normalize( polygon->pol[ i ].norm );
2626 ======================================================================
2627 lwGetPointPolygons()
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
2632 ====================================================================== */
2634 int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon )
2638 /* count the number of polygons per point */
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;
2644 /* alloc per-point polygon arrays */
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;
2653 /* fill in polygon array for each point */
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;
2668 ======================================================================
2669 lwResolvePolySurfaces()
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 ====================================================================== */
2676 int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist,
2677 lwSurface **surf, int *nsurfs )
2682 if ( tlist->count == 0 ) return 1;
2684 s = (lwSurface**)Mem_ClearedAlloc( tlist->count * sizeof( lwSurface * ) );
2687 for ( i = 0; i < tlist->count; i++ ) {
2690 if ( !strcmp( st->name, tlist->tag[ i ] )) {
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;
2710 polygon->pol[ i ].surf = s[ index ];
2719 ======================================================================
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.
2729 Assumes that lwGetPointPolygons(), lwGetPolyNormals() and
2730 lwResolvePolySurfaces() have already been called.
2731 ====================================================================== */
2733 void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon )
2735 int j, k, n, g, h, p;
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 ];
2743 if ( polygon->pol[ j ].surf->smooth <= 0 ) continue;
2745 p = polygon->pol[ j ].v[ n ].index;
2747 for ( g = 0; g < point->pt[ p ].npols; g++ ) {
2748 h = point->pt[ p ].pol[ g ];
2749 if ( h == j ) continue;
2751 if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp )
2753 a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm );
2754 if ( a > polygon->pol[ j ].surf->smooth ) continue;
2756 for ( k = 0; k < 3; k++ )
2757 polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ];
2760 normalize( polygon->pol[ j ].v[ n ].norm );
2767 ======================================================================
2770 Free memory used by an lwTagList.
2771 ====================================================================== */
2773 void lwFreeTags( lwTagList *tlist )
2779 for ( i = 0; i < tlist->count; i++ )
2780 if ( tlist->tag[ i ] ) {
2781 Mem_Free( tlist->tag[ i ] );
2783 Mem_Free( tlist->tag );
2785 memset( tlist, 0, sizeof( lwTagList ));
2791 ======================================================================
2794 Read tag strings from a TAGS chunk in an LWO2 file. The tags are
2795 added to the lwTagList array.
2796 ====================================================================== */
2798 int lwGetTags( idFile *fp, int cksize, lwTagList *tlist )
2803 if ( cksize == 0 ) return 1;
2805 /* read the whole chunk */
2808 buf = (char*)getbytes( fp, cksize );
2809 if ( !buf ) return 0;
2811 /* count the strings */
2815 while ( bp < buf + cksize ) {
2816 len = strlen( bp ) + 1;
2822 /* expand the string array to hold the new tags */
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;
2830 memcpy( tlist->tag, oldtag, tlist->offset * sizeof( char * ) );
2833 memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * ) );
2835 /* copy the new tags to the tag array */
2838 for ( i = 0; i < ntags; i++ )
2839 tlist->tag[ i + tlist->offset ] = sgetS0( (unsigned char**)&bp );
2845 if ( buf ) Mem_Free( buf );
2851 ======================================================================
2854 Read polygon tags from a PTAG chunk in an LWO2 file.
2855 ====================================================================== */
2857 int lwGetPolygonTags( idFile *fp, int cksize, lwTagList *tlist, lwPolygonList *plist )
2865 if ( rlen < 0 ) return 0;
2867 if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) {
2868 fp->Seek( cksize - 4, FS_SEEK_CUR );
2872 while ( rlen < cksize ) {
2873 i = getVX( fp ) + plist->offset;
2874 j = getVX( fp ) + tlist->offset;
2876 if ( rlen < 0 || rlen > cksize ) return 0;
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;
2890 ======================================================================
2893 Free the memory used by an lwPlugin.
2894 ====================================================================== */
2896 void lwFreePlugin( lwPlugin *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 );
2908 ======================================================================
2911 Free the memory used by an lwTexture.
2912 ====================================================================== */
2914 void lwFreeTexture( lwTexture *t )
2917 if ( t->ord ) Mem_Free( t->ord );
2918 switch ( t->type ) {
2920 if ( t->param.imap.vmap_name ) Mem_Free( t->param.imap.vmap_name );
2923 if ( t->param.proc.name ) Mem_Free( t->param.proc.name );
2924 if ( t->param.proc.data ) Mem_Free( t->param.proc.data );
2927 if ( t->param.grad.key ) Mem_Free( t->param.grad.key );
2928 if ( t->param.grad.ikey ) Mem_Free( t->param.grad.ikey );
2931 if ( t->tmap.ref_object ) Mem_Free( t->tmap.ref_object );
2938 ======================================================================
2941 Free the memory used by an lwSurface.
2942 ====================================================================== */
2944 void lwFreeSurface( lwSurface *surf )
2947 if ( surf->name ) Mem_Free( surf->name );
2948 if ( surf->srcname ) Mem_Free( surf->srcname );
2950 lwListFree( surf->shader, (void (__cdecl *)(void *))lwFreePlugin );
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 );
2969 ======================================================================
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
2975 ====================================================================== */
2977 int lwGetTHeader( idFile *fp, int hsz, lwTexture *tex )
2984 /* remember where we started */
2989 /* ordinal string */
2991 tex->ord = getS0( fp );
2993 /* first subchunk header */
2997 if ( 0 > get_flen() ) return 0;
2999 /* process subchunks as they're encountered */
3007 tex->chan = getU4( fp );
3011 tex->opac_type = getU2( fp );
3012 tex->opacity.val = getF4( fp );
3013 tex->opacity.eindex = getVX( fp );
3017 tex->enabled = getU2( fp );
3021 tex->negative = getU2( fp );
3025 tex->axis = getU2( fp );
3032 /* error while reading current subchunk? */
3035 if ( rlen < 0 || rlen > sz ) return 0;
3037 /* skip unread parts of the current subchunk */
3040 fp->Seek( sz - rlen, FS_SEEK_CUR );
3042 /* end of the texture header subchunk? */
3044 if ( hsz <= fp->Tell() - pos )
3047 /* get the next subchunk header */
3052 if ( 6 != get_flen() ) return 0;
3055 set_flen( fp->Tell() - pos );
3061 ======================================================================
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 ====================================================================== */
3068 int lwGetTMap( idFile *fp, int tmapsz, lwTMap *tmap )
3077 if ( 0 > get_flen() ) return 0;
3085 for ( i = 0; i < 3; i++ )
3086 tmap->size.val[ i ] = getF4( fp );
3087 tmap->size.eindex = getVX( fp );
3091 for ( i = 0; i < 3; i++ )
3092 tmap->center.val[ i ] = getF4( fp );
3093 tmap->center.eindex = getVX( fp );
3097 for ( i = 0; i < 3; i++ )
3098 tmap->rotate.val[ i ] = getF4( fp );
3099 tmap->rotate.eindex = getVX( fp );
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 );
3110 tmap->ref_object = getS0( fp );
3114 tmap->coord_sys = getU2( fp );
3121 /* error while reading the current subchunk? */
3124 if ( rlen < 0 || rlen > sz ) return 0;
3126 /* skip unread parts of the current subchunk */
3129 fp->Seek( sz - rlen, FS_SEEK_CUR );
3131 /* end of the TMAP subchunk? */
3133 if ( tmapsz <= fp->Tell() - pos )
3136 /* get the next subchunk header */
3141 if ( 6 != get_flen() ) return 0;
3144 set_flen( fp->Tell() - pos );
3150 ======================================================================
3153 Read an lwImageMap from a SURF.BLOK in an LWO2 file.
3154 ====================================================================== */
3156 int lwGetImageMap( idFile *fp, int rsz, lwTexture *tex )
3165 if ( 0 > get_flen() ) return 0;
3173 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3177 tex->param.imap.projection = getU2( fp );
3181 tex->param.imap.vmap_name = getS0( fp );
3185 tex->param.imap.axis = getU2( fp );
3189 tex->param.imap.cindex = getVX( fp );
3193 tex->param.imap.wrapw_type = getU2( fp );
3194 tex->param.imap.wraph_type = getU2( fp );
3198 tex->param.imap.wrapw.val = getF4( fp );
3199 tex->param.imap.wrapw.eindex = getVX( fp );
3203 tex->param.imap.wraph.val = getF4( fp );
3204 tex->param.imap.wraph.eindex = getVX( fp );
3208 tex->param.imap.aas_flags = getU2( fp );
3209 tex->param.imap.aa_strength = getF4( fp );
3213 tex->param.imap.pblend = getU2( fp );
3217 tex->param.imap.stck.val = getF4( fp );
3218 tex->param.imap.stck.eindex = getVX( fp );
3222 tex->param.imap.amplitude.val = getF4( fp );
3223 tex->param.imap.amplitude.eindex = getVX( fp );
3230 /* error while reading the current subchunk? */
3233 if ( rlen < 0 || rlen > sz ) return 0;
3235 /* skip unread parts of the current subchunk */
3238 fp->Seek( sz - rlen, FS_SEEK_CUR );
3240 /* end of the image map? */
3242 if ( rsz <= fp->Tell() - pos )
3245 /* get the next subchunk header */
3250 if ( 6 != get_flen() ) return 0;
3253 set_flen( fp->Tell() - pos );
3259 ======================================================================
3262 Read an lwProcedural from a SURF.BLOK in an LWO2 file.
3263 ====================================================================== */
3265 int lwGetProcedural( idFile *fp, int rsz, lwTexture *tex )
3274 if ( 0 > get_flen() ) return 0;
3282 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3286 tex->param.proc.axis = getU2( fp );
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 );
3296 tex->param.proc.name = getS0( fp );
3298 tex->param.proc.data = getbytes( fp, sz - rlen );
3305 /* error while reading the current subchunk? */
3308 if ( rlen < 0 || rlen > sz ) return 0;
3310 /* skip unread parts of the current subchunk */
3313 fp->Seek( sz - rlen, FS_SEEK_CUR );
3315 /* end of the procedural block? */
3317 if ( rsz <= fp->Tell() - pos )
3320 /* get the next subchunk header */
3325 if ( 6 != get_flen() ) return 0;
3328 set_flen( fp->Tell() - pos );
3334 ======================================================================
3337 Read an lwGradient from a SURF.BLOK in an LWO2 file.
3338 ====================================================================== */
3340 int lwGetGradient( idFile *fp, int rsz, lwTexture *tex )
3344 int rlen, pos, i, j, nkeys;
3349 if ( 0 > get_flen() ) return 0;
3357 if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0;
3361 tex->param.grad.paramname = getS0( fp );
3365 tex->param.grad.itemname = getS0( fp );
3369 tex->param.grad.start = getF4( fp );
3373 tex->param.grad.end = getF4( fp );
3377 tex->param.grad.repeat = getU2( fp );
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 );
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 );
3403 /* error while reading the current subchunk? */
3406 if ( rlen < 0 || rlen > sz ) return 0;
3408 /* skip unread parts of the current subchunk */
3411 fp->Seek( sz - rlen, FS_SEEK_CUR );
3413 /* end of the gradient? */
3415 if ( rsz <= fp->Tell() - pos )
3418 /* get the next subchunk header */
3423 if ( 6 != get_flen() ) return 0;
3426 set_flen( fp->Tell() - pos );
3432 ======================================================================
3435 Read an lwTexture from a SURF.BLOK in an LWO2 file.
3436 ====================================================================== */
3438 lwTexture *lwGetTexture( idFile *fp, int bloksz, unsigned int type )
3444 tex = (lwTexture*)Mem_ClearedAlloc( sizeof( lwTexture ) );
3445 if ( !tex ) return NULL;
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;
3455 if ( !lwGetTHeader( fp, sz, tex )) {
3460 sz = bloksz - sz - 6;
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;
3466 ok = !fp->Seek( sz, FS_SEEK_CUR );
3470 lwFreeTexture( tex );
3480 ======================================================================
3483 Read a shader record from a SURF.BLOK in an LWO2 file.
3484 ====================================================================== */
3486 lwPlugin *lwGetShader( idFile *fp, int bloksz )
3493 shdr = (lwPlugin*)Mem_ClearedAlloc( sizeof( lwPlugin ) );
3494 if ( !shdr ) return NULL;
3499 shdr->ord = getS0( fp );
3502 if ( 0 > get_flen() ) goto Fail;
3507 if ( id == ID_ENAB ) {
3508 shdr->flags = getU2( fp );
3512 fp->Seek( sz, FS_SEEK_CUR );
3520 if ( 0 > get_flen() ) goto Fail;
3528 shdr->name = getS0( fp );
3530 shdr->data = getbytes( fp, sz - rlen );
3537 /* error while reading the current subchunk? */
3540 if ( rlen < 0 || rlen > sz ) goto Fail;
3542 /* skip unread parts of the current subchunk */
3545 fp->Seek( sz - rlen, FS_SEEK_CUR );
3547 /* end of the shader block? */
3549 if ( bloksz <= fp->Tell() - pos )
3552 /* get the next subchunk header */
3557 if ( 6 != get_flen() ) goto Fail;
3560 set_flen( fp->Tell() - pos );
3564 lwFreePlugin( shdr );
3570 ======================================================================
3574 Callbacks for the lwListInsert() function, which is called to add
3575 textures to surface channels and shaders to surfaces.
3576 ====================================================================== */
3578 static int compare_textures( lwTexture *a, lwTexture *b )
3580 return strcmp( a->ord, b->ord );
3584 static int compare_shaders( lwPlugin *a, lwPlugin *b )
3586 return strcmp( a->ord, b->ord );
3591 ======================================================================
3594 Finds the surface channel (lwTParam or lwCParam) to which a texture is
3595 applied, then calls lwListInsert().
3596 ====================================================================== */
3598 static int add_texture( lwSurface *surf, lwTexture *tex )
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;
3616 lwListInsert( (void**)list, tex, (int (__cdecl *)(void *,void *))compare_textures );
3622 ======================================================================
3625 Allocate and initialize a surface.
3626 ====================================================================== */
3628 lwSurface *lwDefaultSurface( void )
3632 surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
3633 if ( !surf ) return NULL;
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;
3649 ======================================================================
3652 Read an lwSurface from an LWO2 file.
3653 ====================================================================== */
3655 lwSurface *lwGetSurface( idFile *fp, int cksize )
3660 unsigned int id, type;
3665 /* allocate the Surface structure */
3667 surf = (lwSurface*)Mem_ClearedAlloc( sizeof( lwSurface ) );
3668 if ( !surf ) goto Fail;
3670 /* non-zero defaults */
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;
3681 /* remember where we started */
3688 surf->name = getS0( fp );
3689 surf->srcname = getS0( fp );
3691 /* first subchunk header */
3695 if ( 0 > get_flen() ) goto Fail;
3697 /* process subchunks as they're encountered */
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 );
3712 surf->luminosity.val = getF4( fp );
3713 surf->luminosity.eindex = getVX( fp );
3717 surf->diffuse.val = getF4( fp );
3718 surf->diffuse.eindex = getVX( fp );
3722 surf->specularity.val = getF4( fp );
3723 surf->specularity.eindex = getVX( fp );
3727 surf->glossiness.val = getF4( fp );
3728 surf->glossiness.eindex = getVX( fp );
3732 surf->reflection.val.val = getF4( fp );
3733 surf->reflection.val.eindex = getVX( fp );
3737 surf->reflection.options = getU2( fp );
3741 surf->reflection.cindex = getVX( fp );
3745 surf->reflection.seam_angle = getF4( fp );
3749 surf->transparency.val.val = getF4( fp );
3750 surf->transparency.val.eindex = getVX( fp );
3754 surf->transparency.options = getU2( fp );
3758 surf->transparency.cindex = getVX( fp );
3762 surf->eta.val = getF4( fp );
3763 surf->eta.eindex = getVX( fp );
3767 surf->translucency.val = getF4( fp );
3768 surf->translucency.eindex = getVX( fp );
3772 surf->bump.val = getF4( fp );
3773 surf->bump.eindex = getVX( fp );
3777 surf->smooth = getF4( fp );
3781 surf->sideflags = getU2( fp );
3785 surf->color_hilite.val = getF4( fp );
3786 surf->color_hilite.eindex = getVX( fp );
3790 surf->color_filter.val = getF4( fp );
3791 surf->color_filter.eindex = getVX( fp );
3795 surf->add_trans.val = getF4( fp );
3796 surf->add_trans.eindex = getVX( fp );
3800 surf->dif_sharp.val = getF4( fp );
3801 surf->dif_sharp.eindex = getVX( fp );
3805 surf->glow.val = getF4( fp );
3806 surf->glow.eindex = getVX( fp );
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 );
3817 surf->alpha_mode = getU2( fp );
3818 surf->alpha = getF4( fp );
3822 surf->alpha = getF4( fp );
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() );
3839 shdr = lwGetShader( fp, sz - 4 );
3840 if ( !shdr ) goto Fail;
3841 lwListInsert( (void**)&surf->shader, shdr, (int (__cdecl *)(void *,void *))compare_shaders );
3843 set_flen( 4 + get_flen() );
3852 /* error while reading current subchunk? */
3855 if ( rlen < 0 || rlen > sz ) goto Fail;
3857 /* skip unread parts of the current subchunk */
3860 fp->Seek( sz - rlen, FS_SEEK_CUR );
3862 /* end of the SURF chunk? */
3864 if ( cksize <= fp->Tell() - pos )
3867 /* get the next subchunk header */
3872 if ( 6 != get_flen() ) goto Fail;
3878 if ( surf ) lwFreeSurface( surf );
3883 float dot( float a[], float b[] )
3885 return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
3889 void cross( float a[], float b[], float c[] )
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 ];
3897 void normalize( float v[] )
3901 r = ( float ) idMath::Sqrt( dot( v, v ));
3910 ======================================================================
3913 Free memory used by an lwVMap.
3914 ====================================================================== */
3916 void lwFreeVMap( lwVMap *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 );
3923 if ( vmap->val[ 0 ] ) Mem_Free( vmap->val[ 0 ] );
3924 Mem_Free( vmap->val );
3932 ======================================================================
3935 Read an lwVMap from a VMAP or VMAD chunk in an LWO2.
3936 ====================================================================== */
3938 lwVMap *lwGetVMap( idFile *fp, int cksize, int ptoffset, int poloffset,
3941 unsigned char *buf, *bp;
3944 int i, j, npts, rlen;
3947 /* read the whole chunk */
3950 buf = (unsigned char*)getbytes( fp, cksize );
3951 if ( !buf ) return NULL;
3953 vmap = (lwVMap*)Mem_ClearedAlloc( sizeof( lwVMap ) );
3959 /* initialize the vmap */
3961 vmap->perpoly = perpoly;
3965 vmap->type = sgetU4( &bp );
3966 vmap->dim = sgetU2( &bp );
3967 vmap->name = sgetS0( &bp );
3970 /* count the vmap records */
3973 while ( bp < buf + cksize ) {
3977 bp += vmap->dim * sizeof( float );
3981 /* allocate the vmap */
3983 vmap->nverts = npts;
3984 vmap->vindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
3985 if ( !vmap->vindex ) goto Fail;
3987 vmap->pindex = (int*)Mem_ClearedAlloc( npts * sizeof( int ) );
3988 if ( !vmap->pindex ) goto Fail;
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;
4000 /* fill in the vmap values */
4003 for ( i = 0; i < npts; i++ ) {
4004 vmap->vindex[ i ] = sgetVX( &bp );
4006 vmap->pindex[ i ] = sgetVX( &bp );
4007 for ( j = 0; j < vmap->dim; j++ )
4008 vmap->val[ i ][ j ] = sgetF4( &bp );
4015 if ( buf ) Mem_Free( buf );
4022 ======================================================================
4025 Fill in the lwVMapPt structure for each point.
4026 ====================================================================== */
4028 int lwGetPointVMaps( lwPointList *point, lwVMap *vmap )
4033 /* count the number of vmap values for each point */
4038 for ( i = 0; i < vm->nverts; i++ )
4039 ++point->pt[ vm->vindex[ i ]].nvmaps;
4043 /* allocate vmap references for each mapped point */
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;
4053 /* fill in vmap references for each mapped point */
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;
4074 ======================================================================
4077 Fill in the lwVMapPt structure for each polygon vertex.
4078 ====================================================================== */
4080 int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap )
4086 /* count the number of vmap values for each polygon vertex */
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 ) {
4104 /* allocate vmap references for each mapped vertex */
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 ];
4110 pv->vm = (lwVMapPt*)Mem_ClearedAlloc( pv->nvmaps * sizeof( lwVMapPt ) );
4111 if ( !pv->vm ) return 0;
4117 /* fill in vmap references for each mapped point */
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;