The GtkRadiant sources as originally released under the GPL license.

This commit is contained in:
Travis Bradshaw
2012-01-31 15:20:35 -06:00
commit 0991a5ce8b
1590 changed files with 431941 additions and 0 deletions

278
libs/picomodel/lwo/clip.c Normal file
View File

@@ -0,0 +1,278 @@
/*
======================================================================
clip.c
Functions for LWO2 image references.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
lwFreeClip()
Free memory used by an lwClip.
====================================================================== */
void lwFreeClip( lwClip *clip )
{
if ( clip ) {
lwListFree( clip->ifilter, (void *) lwFreePlugin );
lwListFree( clip->pfilter, (void *) lwFreePlugin );
switch ( clip->type ) {
case ID_STIL:
_pico_free( clip->source.still.name);
break;
case ID_ISEQ:
_pico_free( clip->source.seq.prefix );
_pico_free( clip->source.seq.suffix );
break;
case ID_ANIM:
_pico_free( clip->source.anim.name );
_pico_free( clip->source.anim.server );
_pico_free( clip->source.anim.data );
break;
case ID_XREF:
_pico_free( clip->source.xref.string );
break;
case ID_STCC:
_pico_free( clip->source.cycle.name );
break;
default:
break;
}
_pico_free( clip );
}
}
/*
======================================================================
lwGetClip()
Read image references from a CLIP chunk in an LWO2 file.
====================================================================== */
lwClip *lwGetClip( picoMemStream_t *fp, int cksize )
{
lwClip *clip;
lwPlugin *filt;
unsigned int id;
unsigned short sz;
int pos, rlen;
/* allocate the Clip structure */
clip = _pico_calloc( 1, sizeof( lwClip ));
if ( !clip ) goto Fail;
clip->contrast.val = 1.0f;
clip->brightness.val = 1.0f;
clip->saturation.val = 1.0f;
clip->gamma.val = 1.0f;
/* remember where we started */
set_flen( 0 );
pos = _pico_memstream_tell( fp );
/* index */
clip->index = getI4( fp );
/* first subchunk header */
clip->type = getU4( fp );
sz = getU2( fp );
if ( 0 > get_flen() ) goto Fail;
sz += sz & 1;
set_flen( 0 );
switch ( clip->type ) {
case ID_STIL:
clip->source.still.name = getS0( fp );
break;
case ID_ISEQ:
clip->source.seq.digits = getU1( fp );
clip->source.seq.flags = getU1( fp );
clip->source.seq.offset = getI2( fp );
getU2( fp ); /* not sure what this is yet */
clip->source.seq.start = getI2( fp );
clip->source.seq.end = getI2( fp );
clip->source.seq.prefix = getS0( fp );
clip->source.seq.suffix = getS0( fp );
break;
case ID_ANIM:
clip->source.anim.name = getS0( fp );
clip->source.anim.server = getS0( fp );
rlen = get_flen();
clip->source.anim.data = getbytes( fp, sz - rlen );
break;
case ID_XREF:
clip->source.xref.index = getI4( fp );
clip->source.xref.string = getS0( fp );
break;
case ID_STCC:
clip->source.cycle.lo = getI2( fp );
clip->source.cycle.hi = getI2( fp );
clip->source.cycle.name = getS0( fp );
break;
default:
break;
}
/* error while reading current subchunk? */
rlen = get_flen();
if ( rlen < 0 || rlen > sz ) goto Fail;
/* skip unread parts of the current subchunk */
if ( rlen < sz )
_pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
/* end of the CLIP chunk? */
rlen = _pico_memstream_tell( fp ) - pos;
if ( cksize < rlen ) goto Fail;
if ( cksize == rlen )
return clip;
/* process subchunks as they're encountered */
id = getU4( fp );
sz = getU2( fp );
if ( 0 > get_flen() ) goto Fail;
while ( 1 ) {
sz += sz & 1;
set_flen( 0 );
switch ( id ) {
case ID_TIME:
clip->start_time = getF4( fp );
clip->duration = getF4( fp );
clip->frame_rate = getF4( fp );
break;
case ID_CONT:
clip->contrast.val = getF4( fp );
clip->contrast.eindex = getVX( fp );
break;
case ID_BRIT:
clip->brightness.val = getF4( fp );
clip->brightness.eindex = getVX( fp );
break;
case ID_SATR:
clip->saturation.val = getF4( fp );
clip->saturation.eindex = getVX( fp );
break;
case ID_HUE:
clip->hue.val = getF4( fp );
clip->hue.eindex = getVX( fp );
break;
case ID_GAMM:
clip->gamma.val = getF4( fp );
clip->gamma.eindex = getVX( fp );
break;
case ID_NEGA:
clip->negative = getU2( fp );
break;
case ID_IFLT:
case ID_PFLT:
filt = _pico_calloc( 1, sizeof( lwPlugin ));
if ( !filt ) goto Fail;
filt->name = getS0( fp );
filt->flags = getU2( fp );
rlen = get_flen();
filt->data = getbytes( fp, sz - rlen );
if ( id == ID_IFLT ) {
lwListAdd( (void *) &clip->ifilter, filt );
clip->nifilters++;
}
else {
lwListAdd( (void *) &clip->pfilter, filt );
clip->npfilters++;
}
break;
default:
break;
}
/* error while reading current subchunk? */
rlen = get_flen();
if ( rlen < 0 || rlen > sz ) goto Fail;
/* skip unread parts of the current subchunk */
if ( rlen < sz )
_pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
/* end of the CLIP chunk? */
rlen = _pico_memstream_tell( fp ) - pos;
if ( cksize < rlen ) goto Fail;
if ( cksize == rlen ) break;
/* get the next chunk header */
set_flen( 0 );
id = getU4( fp );
sz = getU2( fp );
if ( 6 != get_flen() ) goto Fail;
}
return clip;
Fail:
lwFreeClip( clip );
return NULL;
}
/*
======================================================================
lwFindClip()
Returns an lwClip pointer, given a clip index.
====================================================================== */
lwClip *lwFindClip( lwClip *list, int index )
{
lwClip *clip;
clip = list;
while ( clip ) {
if ( clip->index == index ) break;
clip = clip->next;
}
return clip;
}

View File

@@ -0,0 +1,600 @@
/*
======================================================================
envelope.c
Envelope functions for an LWO2 reader.
Ernie Wright 16 Nov 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
lwFreeEnvelope()
Free the memory used by an lwEnvelope.
====================================================================== */
void lwFreeEnvelope( lwEnvelope *env )
{
if ( env ) {
if ( env->name ) _pico_free( env->name );
lwListFree( env->key, _pico_free );
lwListFree( env->cfilter, (void *) lwFreePlugin );
_pico_free( env );
}
}
static int compare_keys( lwKey *k1, lwKey *k2 )
{
return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
}
/*
======================================================================
lwGetEnvelope()
Read an ENVL chunk from an LWO2 file.
====================================================================== */
lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize )
{
lwEnvelope *env;
lwKey *key;
lwPlugin *plug;
unsigned int id;
unsigned short sz;
float f[ 4 ];
int i, nparams, pos, rlen;
/* allocate the Envelope structure */
env = _pico_calloc( 1, sizeof( lwEnvelope ));
if ( !env ) goto Fail;
/* remember where we started */
set_flen( 0 );
pos = _pico_memstream_tell( fp );
/* index */
env->index = getVX( fp );
/* first subchunk header */
id = getU4( fp );
sz = getU2( fp );
if ( 0 > get_flen() ) goto Fail;
/* process subchunks as they're encountered */
while ( 1 ) {
sz += sz & 1;
set_flen( 0 );
switch ( id ) {
case ID_TYPE:
env->type = getU2( fp );
break;
case ID_NAME:
env->name = getS0( fp );
break;
case ID_PRE:
env->behavior[ 0 ] = getU2( fp );
break;
case ID_POST:
env->behavior[ 1 ] = getU2( fp );
break;
case ID_KEY:
key = _pico_calloc( 1, sizeof( lwKey ));
if ( !key ) goto Fail;
key->time = getF4( fp );
key->value = getF4( fp );
lwListInsert( (void **) &env->key, key, (void *) compare_keys );
env->nkeys++;
break;
case ID_SPAN:
if ( !key ) goto Fail;
key->shape = getU4( fp );
nparams = ( sz - 4 ) / 4;
if ( nparams > 4 ) nparams = 4;
for ( i = 0; i < nparams; i++ )
f[ i ] = getF4( fp );
switch ( key->shape ) {
case ID_TCB:
key->tension = f[ 0 ];
key->continuity = f[ 1 ];
key->bias = f[ 2 ];
break;
case ID_BEZI:
case ID_HERM:
case ID_BEZ2:
for ( i = 0; i < nparams; i++ )
key->param[ i ] = f[ i ];
break;
}
break;
case ID_CHAN:
plug = _pico_calloc( 1, sizeof( lwPlugin ));
if ( !plug ) goto Fail;
plug->name = getS0( fp );
plug->flags = getU2( fp );
plug->data = getbytes( fp, sz - get_flen() );
lwListAdd( (void *) &env->cfilter, plug );
env->ncfilters++;
break;
default:
break;
}
/* error while reading current subchunk? */
rlen = get_flen();
if ( rlen < 0 || rlen > sz ) goto Fail;
/* skip unread parts of the current subchunk */
if ( rlen < sz )
_pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
/* end of the ENVL chunk? */
rlen = _pico_memstream_tell( fp ) - pos;
if ( cksize < rlen ) goto Fail;
if ( cksize == rlen ) break;
/* get the next subchunk header */
set_flen( 0 );
id = getU4( fp );
sz = getU2( fp );
if ( 6 != get_flen() ) goto Fail;
}
return env;
Fail:
lwFreeEnvelope( env );
return NULL;
}
/*
======================================================================
lwFindEnvelope()
Returns an lwEnvelope pointer, given an envelope index.
====================================================================== */
lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index )
{
lwEnvelope *env;
env = list;
while ( env ) {
if ( env->index == index ) break;
env = env->next;
}
return env;
}
/*
======================================================================
range()
Given the value v of a periodic function, returns the equivalent value
v2 in the principal interval [lo, hi]. If i isn't NULL, it receives
the number of wavelengths between v and v2.
v2 = v - i * (hi - lo)
For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
====================================================================== */
static float range( float v, float lo, float hi, int *i )
{
float v2, r = hi - lo;
if ( r == 0.0 ) {
if ( i ) *i = 0;
return lo;
}
v2 = lo + v - r * ( float ) floor(( double ) v / r );
if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
return v2;
}
/*
======================================================================
hermite()
Calculate the Hermite coefficients.
====================================================================== */
static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
{
float t2, t3;
t2 = t * t;
t3 = t * t2;
*h2 = 3.0f * t2 - t3 - t3;
*h1 = 1.0f - *h2;
*h4 = t3 - t2;
*h3 = *h4 - t2 + t;
}
/*
======================================================================
bezier()
Interpolate the value of a 1D Bezier curve.
====================================================================== */
static float bezier( float x0, float x1, float x2, float x3, float t )
{
float a, b, c, t2, t3;
t2 = t * t;
t3 = t2 * t;
c = 3.0f * ( x1 - x0 );
b = 3.0f * ( x2 - x1 ) - c;
a = x3 - x0 - c - b;
return a * t3 + b * t2 + c * t + x0;
}
/*
======================================================================
bez2_time()
Find the t for which bezier() returns the input time. The handle
endpoints of a BEZ2 curve represent the control points, and these have
(time, value) coordinates, so time is used as both a coordinate and a
parameter for this curve type.
====================================================================== */
static float bez2_time( float x0, float x1, float x2, float x3, float time,
float *t0, float *t1 )
{
float v, t;
t = *t0 + ( *t1 - *t0 ) * 0.5f;
v = bezier( x0, x1, x2, x3, t );
if ( fabs( time - v ) > .0001f ) {
if ( v > time )
*t1 = t;
else
*t0 = t;
return bez2_time( x0, x1, x2, x3, time, t0, t1 );
}
else
return t;
}
/*
======================================================================
bez2()
Interpolate the value of a BEZ2 curve.
====================================================================== */
static float bez2( lwKey *key0, lwKey *key1, float time )
{
float x, y, t, t0 = 0.0f, t1 = 1.0f;
if ( key0->shape == ID_BEZ2 )
x = key0->time + key0->param[ 2 ];
else
x = key0->time + ( key1->time - key0->time ) / 3.0f;
t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
time, &t0, &t1 );
if ( key0->shape == ID_BEZ2 )
y = key0->value + key0->param[ 3 ];
else
y = key0->value + key0->param[ 1 ] / 3.0f;
return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
}
/*
======================================================================
outgoing()
Return the outgoing tangent to the curve at key0. The value returned
for the BEZ2 case is used when extrapolating a linear pre behavior and
when interpolating a non-BEZ2 span.
====================================================================== */
static float outgoing( lwKey *key0, lwKey *key1 )
{
float a, b, d, t, out;
switch ( key0->shape )
{
case ID_TCB:
a = ( 1.0f - key0->tension )
* ( 1.0f + key0->continuity )
* ( 1.0f + key0->bias );
b = ( 1.0f - key0->tension )
* ( 1.0f - key0->continuity )
* ( 1.0f - key0->bias );
d = key1->value - key0->value;
if ( key0->prev ) {
t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
}
else
out = b * d;
break;
case ID_LINE:
d = key1->value - key0->value;
if ( key0->prev ) {
t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
out = t * ( key0->value - key0->prev->value + d );
}
else
out = d;
break;
case ID_BEZI:
case ID_HERM:
out = key0->param[ 1 ];
if ( key0->prev )
out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
break;
case ID_BEZ2:
out = key0->param[ 3 ] * ( key1->time - key0->time );
if ( fabs( key0->param[ 2 ] ) > 1e-5f )
out /= key0->param[ 2 ];
else
out *= 1e5f;
break;
case ID_STEP:
default:
out = 0.0f;
break;
}
return out;
}
/*
======================================================================
incoming()
Return the incoming tangent to the curve at key1. The value returned
for the BEZ2 case is used when extrapolating a linear post behavior.
====================================================================== */
static float incoming( lwKey *key0, lwKey *key1 )
{
float a, b, d, t, in;
switch ( key1->shape )
{
case ID_LINE:
d = key1->value - key0->value;
if ( key1->next ) {
t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
in = t * ( key1->next->value - key1->value + d );
}
else
in = d;
break;
case ID_TCB:
a = ( 1.0f - key1->tension )
* ( 1.0f - key1->continuity )
* ( 1.0f + key1->bias );
b = ( 1.0f - key1->tension )
* ( 1.0f + key1->continuity )
* ( 1.0f - key1->bias );
d = key1->value - key0->value;
if ( key1->next ) {
t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
in = t * ( b * ( key1->next->value - key1->value ) + a * d );
}
else
in = a * d;
break;
case ID_BEZI:
case ID_HERM:
in = key1->param[ 0 ];
if ( key1->next )
in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
break;
return in;
case ID_BEZ2:
in = key1->param[ 1 ] * ( key1->time - key0->time );
if ( fabs( key1->param[ 0 ] ) > 1e-5f )
in /= key1->param[ 0 ];
else
in *= 1e5f;
break;
case ID_STEP:
default:
in = 0.0f;
break;
}
return in;
}
/*
======================================================================
evalEnvelope()
Given a list of keys and a time, returns the interpolated value of the
envelope at that time.
====================================================================== */
float evalEnvelope( lwEnvelope *env, float time )
{
lwKey *key0, *key1, *skey, *ekey;
float t, h1, h2, h3, h4, in, out, offset = 0.0f;
int noff;
/* if there's no key, the value is 0 */
if ( env->nkeys == 0 ) return 0.0f;
/* if there's only one key, the value is constant */
if ( env->nkeys == 1 )
return env->key->value;
/* find the first and last keys */
skey = ekey = env->key;
while ( ekey->next ) ekey = ekey->next;
/* use pre-behavior if time is before first key time */
if ( time < skey->time ) {
switch ( env->behavior[ 0 ] )
{
case BEH_RESET:
return 0.0f;
case BEH_CONSTANT:
return skey->value;
case BEH_REPEAT:
time = range( time, skey->time, ekey->time, NULL );
break;
case BEH_OSCILLATE:
time = range( time, skey->time, ekey->time, &noff );
if ( noff % 2 )
time = ekey->time - skey->time - time;
break;
case BEH_OFFSET:
time = range( time, skey->time, ekey->time, &noff );
offset = noff * ( ekey->value - skey->value );
break;
case BEH_LINEAR:
out = outgoing( skey, skey->next )
/ ( skey->next->time - skey->time );
return out * ( time - skey->time ) + skey->value;
}
}
/* use post-behavior if time is after last key time */
else if ( time > ekey->time ) {
switch ( env->behavior[ 1 ] )
{
case BEH_RESET:
return 0.0f;
case BEH_CONSTANT:
return ekey->value;
case BEH_REPEAT:
time = range( time, skey->time, ekey->time, NULL );
break;
case BEH_OSCILLATE:
time = range( time, skey->time, ekey->time, &noff );
if ( noff % 2 )
time = ekey->time - skey->time - time;
break;
case BEH_OFFSET:
time = range( time, skey->time, ekey->time, &noff );
offset = noff * ( ekey->value - skey->value );
break;
case BEH_LINEAR:
in = incoming( ekey->prev, ekey )
/ ( ekey->time - ekey->prev->time );
return in * ( time - ekey->time ) + ekey->value;
}
}
/* get the endpoints of the interval being evaluated */
key0 = env->key;
while ( time > key0->next->time )
key0 = key0->next;
key1 = key0->next;
/* check for singularities first */
if ( time == key0->time )
return key0->value + offset;
else if ( time == key1->time )
return key1->value + offset;
/* get interval length, time in [0, 1] */
t = ( time - key0->time ) / ( key1->time - key0->time );
/* interpolate */
switch ( key1->shape )
{
case ID_TCB:
case ID_BEZI:
case ID_HERM:
out = outgoing( key0, key1 );
in = incoming( key0, key1 );
hermite( t, &h1, &h2, &h3, &h4 );
return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
case ID_BEZ2:
return bez2( key0, key1, time ) + offset;
case ID_LINE:
return key0->value + t * ( key1->value - key0->value ) + offset;
case ID_STEP:
return key0->value + offset;
default:
return offset;
}
}

101
libs/picomodel/lwo/list.c Normal file
View File

@@ -0,0 +1,101 @@
/*
======================================================================
list.c
Generic linked list operations.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
lwListFree()
Free the items in a list.
====================================================================== */
void lwListFree( void *list, void ( *freeNode )( void * ))
{
lwNode *node, *next;
node = ( lwNode * ) list;
while ( node ) {
next = node->next;
freeNode( node );
node = next;
}
}
/*
======================================================================
lwListAdd()
Append a node to a list.
====================================================================== */
void lwListAdd( void **list, void *node )
{
lwNode *head, *tail;
head = *(( lwNode ** ) list );
if ( !head ) {
*list = node;
return;
}
while ( head ) {
tail = head;
head = head->next;
}
tail->next = ( lwNode * ) node;
(( lwNode * ) node )->prev = tail;
}
/*
======================================================================
lwListInsert()
Insert a node into a list in sorted order.
====================================================================== */
void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * ))
{
lwNode **list, *item, *node, *prev;
if ( !*vlist ) {
*vlist = vitem;
return;
}
list = ( lwNode ** ) vlist;
item = ( lwNode * ) vitem;
node = *list;
prev = NULL;
while ( node ) {
if ( 0 < compare( node, item )) break;
prev = node;
node = node->next;
}
if ( !prev ) {
*list = item;
node->prev = item;
item->next = node;
}
else if ( !node ) {
prev->next = item;
item->prev = prev;
}
else {
item->next = node;
item->prev = prev;
prev->next = item;
node->prev = item;
}
}

442
libs/picomodel/lwo/lwio.c Normal file
View File

@@ -0,0 +1,442 @@
/*
======================================================================
lwio.c
Functions for reading basic LWO2 data types.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
flen
This accumulates a count of the number of bytes read. Callers can set
it at the beginning of a sequence of reads and then retrieve it to get
the number of bytes actually read. If one of the I/O functions fails,
flen is set to an error code, after which the I/O functions ignore
read requests until flen is reset.
====================================================================== */
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
#define FLEN_ERROR INT_MIN
static int flen;
void set_flen( int i ) { flen = i; }
int get_flen( void ) { return flen; }
#ifndef __BIG_ENDIAN__
/*
=====================================================================
revbytes()
Reverses byte order in place.
INPUTS
bp bytes to reverse
elsize size of the underlying data type
elcount number of elements to swap
RESULTS
Reverses the byte order in each of elcount elements.
This only needs to be defined on little-endian platforms, most
notably Windows. lwo2.h replaces this with a #define on big-endian
platforms.
===================================================================== */
void revbytes( void *bp, int elsize, int elcount )
{
register unsigned char *p, *q;
p = ( unsigned char * ) bp;
if ( elsize == 2 ) {
q = p + 1;
while ( elcount-- ) {
*p ^= *q;
*q ^= *p;
*p ^= *q;
p += 2;
q += 2;
}
return;
}
while ( elcount-- ) {
q = p + elsize - 1;
while ( p < q ) {
*p ^= *q;
*q ^= *p;
*p ^= *q;
++p;
--q;
}
p += elsize >> 1;
}
}
#endif
void *getbytes( picoMemStream_t *fp, int size )
{
void *data;
if ( flen == FLEN_ERROR ) return NULL;
if ( size < 0 ) {
flen = FLEN_ERROR;
return NULL;
}
data = _pico_alloc( size );
if ( !data ) {
flen = FLEN_ERROR;
return NULL;
}
if ( 1 != _pico_memstream_read( fp, data, size )) {
flen = FLEN_ERROR;
_pico_free( data );
return NULL;
}
flen += size;
return data;
}
void skipbytes( picoMemStream_t *fp, int n )
{
if ( flen == FLEN_ERROR ) return;
if ( _pico_memstream_seek( fp, n, PICO_SEEK_CUR ))
flen = FLEN_ERROR;
else
flen += n;
}
int getI1( picoMemStream_t *fp )
{
int i;
if ( flen == FLEN_ERROR ) return 0;
i = _pico_memstream_getc( fp );
if ( i < 0 ) {
flen = FLEN_ERROR;
return 0;
}
if ( i > 127 ) i -= 256;
flen += 1;
return i;
}
short getI2( picoMemStream_t *fp )
{
short i;
if ( flen == FLEN_ERROR ) return 0;
if ( 1 != _pico_memstream_read( fp, &i, 2 )) {
flen = FLEN_ERROR;
return 0;
}
revbytes( &i, 2, 1 );
flen += 2;
return i;
}
int getI4( picoMemStream_t *fp )
{
int i;
if ( flen == FLEN_ERROR ) return 0;
if ( 1 != _pico_memstream_read( fp, &i, 4 )) {
flen = FLEN_ERROR;
return 0;
}
revbytes( &i, 4, 1 );
flen += 4;
return i;
}
unsigned char getU1( picoMemStream_t *fp )
{
int i;
if ( flen == FLEN_ERROR ) return 0;
i = _pico_memstream_getc( fp );
if ( i < 0 ) {
flen = FLEN_ERROR;
return 0;
}
flen += 1;
return i;
}
unsigned short getU2( picoMemStream_t *fp )
{
unsigned short i;
if ( flen == FLEN_ERROR ) return 0;
if ( 1 != _pico_memstream_read( fp, &i, 2 )) {
flen = FLEN_ERROR;
return 0;
}
revbytes( &i, 2, 1 );
flen += 2;
return i;
}
unsigned int getU4( picoMemStream_t *fp )
{
unsigned int i;
if ( flen == FLEN_ERROR ) return 0;
if ( 1 != _pico_memstream_read( fp, &i, 4 )) {
flen = FLEN_ERROR;
return 0;
}
revbytes( &i, 4, 1 );
flen += 4;
return i;
}
int getVX( picoMemStream_t *fp )
{
int i, c;
if ( flen == FLEN_ERROR ) return 0;
c = _pico_memstream_getc( fp );
if ( c != 0xFF ) {
i = c << 8;
c = _pico_memstream_getc( fp );
i |= c;
flen += 2;
}
else {
c = _pico_memstream_getc( fp );
i = c << 16;
c = _pico_memstream_getc( fp );
i |= c << 8;
c = _pico_memstream_getc( fp );
i |= c;
flen += 4;
}
if ( _pico_memstream_error( fp )) {
flen = FLEN_ERROR;
return 0;
}
return i;
}
float getF4( picoMemStream_t *fp )
{
float f;
if ( flen == FLEN_ERROR ) return 0.0f;
if ( 1 != _pico_memstream_read( fp, &f, 4 )) {
flen = FLEN_ERROR;
return 0.0f;
}
revbytes( &f, 4, 1 );
flen += 4;
return f;
}
char *getS0( picoMemStream_t *fp )
{
char *s;
int i, c, len, pos;
if ( flen == FLEN_ERROR ) return NULL;
pos = _pico_memstream_tell( fp );
for ( i = 1; ; i++ ) {
c = _pico_memstream_getc( fp );
if ( c <= 0 ) break;
}
if ( c < 0 ) {
flen = FLEN_ERROR;
return NULL;
}
if ( i == 1 ) {
if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET ))
flen = FLEN_ERROR;
else
flen += 2;
return NULL;
}
len = i + ( i & 1 );
s = _pico_alloc( len );
if ( !s ) {
flen = FLEN_ERROR;
return NULL;
}
if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) {
flen = FLEN_ERROR;
return NULL;
}
if ( 1 != _pico_memstream_read( fp, s, len )) {
flen = FLEN_ERROR;
return NULL;
}
flen += len;
return s;
}
int sgetI1( unsigned char **bp )
{
int i;
if ( flen == FLEN_ERROR ) return 0;
i = **bp;
if ( i > 127 ) i -= 256;
flen += 1;
*bp++;
return i;
}
short sgetI2( unsigned char **bp )
{
short i;
if ( flen == FLEN_ERROR ) return 0;
memcpy( &i, *bp, 2 );
revbytes( &i, 2, 1 );
flen += 2;
*bp += 2;
return i;
}
int sgetI4( unsigned char **bp )
{
int i;
if ( flen == FLEN_ERROR ) return 0;
memcpy( &i, *bp, 4 );
revbytes( &i, 4, 1 );
flen += 4;
*bp += 4;
return i;
}
unsigned char sgetU1( unsigned char **bp )
{
unsigned char c;
if ( flen == FLEN_ERROR ) return 0;
c = **bp;
flen += 1;
*bp++;
return c;
}
unsigned short sgetU2( unsigned char **bp )
{
unsigned char *buf = *bp;
unsigned short i;
if ( flen == FLEN_ERROR ) return 0;
i = ( buf[ 0 ] << 8 ) | buf[ 1 ];
flen += 2;
*bp += 2;
return i;
}
unsigned int sgetU4( unsigned char **bp )
{
unsigned int i;
if ( flen == FLEN_ERROR ) return 0;
memcpy( &i, *bp, 4 );
revbytes( &i, 4, 1 );
flen += 4;
*bp += 4;
return i;
}
int sgetVX( unsigned char **bp )
{
unsigned char *buf = *bp;
int i;
if ( flen == FLEN_ERROR ) return 0;
if ( buf[ 0 ] != 0xFF ) {
i = buf[ 0 ] << 8 | buf[ 1 ];
flen += 2;
*bp += 2;
}
else {
i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ];
flen += 4;
*bp += 4;
}
return i;
}
float sgetF4( unsigned char **bp )
{
float f;
if ( flen == FLEN_ERROR ) return 0.0f;
memcpy( &f, *bp, 4 );
revbytes( &f, 4, 1 );
flen += 4;
*bp += 4;
return f;
}
char *sgetS0( unsigned char **bp )
{
char *s;
unsigned char *buf = *bp;
int len;
if ( flen == FLEN_ERROR ) return NULL;
len = strlen( buf ) + 1;
if ( len == 1 ) {
flen += 2;
*bp += 2;
return NULL;
}
len += len & 1;
s = _pico_alloc( len );
if ( !s ) {
flen = FLEN_ERROR;
return NULL;
}
memcpy( s, buf, len );
flen += len;
*bp += len;
return s;
}

308
libs/picomodel/lwo/lwo2.c Normal file
View File

@@ -0,0 +1,308 @@
/*
======================================================================
lwo2.c
The entry point for loading LightWave object files.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/* disable warnings */
#ifdef WIN32
#pragma warning( disable:4018 ) /* signed/unsigned mismatch */
#endif
/*
======================================================================
lwFreeLayer()
Free memory used by an lwLayer.
====================================================================== */
void lwFreeLayer( lwLayer *layer )
{
if ( layer ) {
if ( layer->name ) _pico_free( layer->name );
lwFreePoints( &layer->point );
lwFreePolygons( &layer->polygon );
lwListFree( layer->vmap, (void *) lwFreeVMap );
_pico_free( layer );
}
}
/*
======================================================================
lwFreeObject()
Free memory used by an lwObject.
====================================================================== */
void lwFreeObject( lwObject *object )
{
if ( object ) {
lwListFree( object->layer, (void *) lwFreeLayer );
lwListFree( object->env, (void *) lwFreeEnvelope );
lwListFree( object->clip, (void *) lwFreeClip );
lwListFree( object->surf, (void *) lwFreeSurface );
lwFreeTags( &object->taglist );
_pico_free( object );
}
}
/*
======================================================================
lwGetObject()
Returns the contents of a LightWave object, given its filename, or
NULL if the file couldn't be loaded. On failure, failID and failpos
can be used to diagnose the cause.
1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and
failID will be unchanged.
2. If an error occurs while reading, failID will contain the most
recently read IFF chunk ID, and failpos will contain the value
returned by _pico_memstream_tell() at the time of the failure.
3. If the file couldn't be opened, or an error occurs while reading
the first 12 bytes, both failID and failpos will be unchanged.
If you don't need this information, failID and failpos can be NULL.
====================================================================== */
lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
{
lwObject *object;
lwLayer *layer;
lwNode *node;
unsigned int id, formsize, type, cksize;
int i, rlen;
/* open the file */
if ( !fp ) return NULL;
/* read the first 12 bytes */
set_flen( 0 );
id = getU4( fp );
formsize = getU4( fp );
type = getU4( fp );
if ( 12 != get_flen() ) {
return NULL;
}
/* is this a LW object? */
if ( id != ID_FORM ) {
if ( failpos ) *failpos = 12;
return NULL;
}
if ( type != ID_LWO2 ) {
if ( type == ID_LWOB )
return lwGetObject5( filename, fp, failID, failpos );
else {
if ( failpos ) *failpos = 12;
return NULL;
}
}
/* allocate an object and a default layer */
object = _pico_calloc( 1, sizeof( lwObject ));
if ( !object ) goto Fail;
layer = _pico_calloc( 1, sizeof( lwLayer ));
if ( !layer ) goto Fail;
object->layer = layer;
/* get the first chunk header */
id = getU4( fp );
cksize = getU4( fp );
if ( 0 > get_flen() ) goto Fail;
/* process chunks as they're encountered */
while ( 1 ) {
cksize += cksize & 1;
switch ( id )
{
case ID_LAYR:
if ( object->nlayers > 0 ) {
layer = _pico_calloc( 1, sizeof( lwLayer ));
if ( !layer ) goto Fail;
lwListAdd( (void **) &object->layer, layer );
}
object->nlayers++;
set_flen( 0 );
layer->index = getU2( fp );
layer->flags = getU2( fp );
layer->pivot[ 0 ] = getF4( fp );
layer->pivot[ 1 ] = getF4( fp );
layer->pivot[ 2 ] = getF4( fp );
layer->name = getS0( fp );
rlen = get_flen();
if ( rlen < 0 || rlen > cksize ) goto Fail;
if ( rlen <= cksize - 2 )
layer->parent = getU2( fp );
rlen = get_flen();
if ( rlen < cksize )
_pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
break;
case ID_PNTS:
if ( !lwGetPoints( fp, cksize, &layer->point ))
goto Fail;
break;
case ID_POLS:
if ( !lwGetPolygons( fp, cksize, &layer->polygon,
layer->point.offset ))
goto Fail;
break;
case ID_VMAP:
case ID_VMAD:
node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset,
layer->polygon.offset, id == ID_VMAD );
if ( !node ) goto Fail;
lwListAdd( (void **) &layer->vmap, node );
layer->nvmaps++;
break;
case ID_PTAG:
if ( !lwGetPolygonTags( fp, cksize, &object->taglist,
&layer->polygon ))
goto Fail;
break;
case ID_BBOX:
set_flen( 0 );
for ( i = 0; i < 6; i++ )
layer->bbox[ i ] = getF4( fp );
rlen = get_flen();
if ( rlen < 0 || rlen > cksize ) goto Fail;
if ( rlen < cksize )
_pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR );
break;
case ID_TAGS:
if ( !lwGetTags( fp, cksize, &object->taglist ))
goto Fail;
break;
case ID_ENVL:
node = ( lwNode * ) lwGetEnvelope( fp, cksize );
if ( !node ) goto Fail;
lwListAdd( (void **) &object->env, node );
object->nenvs++;
break;
case ID_CLIP:
node = ( lwNode * ) lwGetClip( fp, cksize );
if ( !node ) goto Fail;
lwListAdd( (void **) &object->clip, node );
object->nclips++;
break;
case ID_SURF:
node = ( lwNode * ) lwGetSurface( fp, cksize );
if ( !node ) goto Fail;
lwListAdd( (void **) &object->surf, node );
object->nsurfs++;
break;
case ID_DESC:
case ID_TEXT:
case ID_ICON:
default:
_pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
break;
}
/* end of the file? */
if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break;
/* get the next chunk header */
set_flen( 0 );
id = getU4( fp );
cksize = getU4( fp );
if ( 8 != get_flen() ) goto Fail;
}
if ( object->nlayers == 0 )
object->nlayers = 1;
layer = object->layer;
while ( layer ) {
lwGetBoundingBox( &layer->point, layer->bbox );
lwGetPolyNormals( &layer->point, &layer->polygon );
if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
&object->surf, &object->nsurfs )) goto Fail;
lwGetVertNormals( &layer->point, &layer->polygon );
if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail;
if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail;
layer = layer->next;
}
return object;
Fail:
if ( failID ) *failID = id;
if ( fp ) {
if ( failpos ) *failpos = _pico_memstream_tell( fp );
}
lwFreeObject( object );
return NULL;
}
int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
{
unsigned int id, formsize, type;
/* open the file */
if ( !fp ) return PICO_PMV_ERROR_MEMORY;
/* read the first 12 bytes */
set_flen( 0 );
id = getU4( fp );
formsize = getU4( fp );
type = getU4( fp );
if ( 12 != get_flen() ) {
return PICO_PMV_ERROR_SIZE;
}
/* is this a LW object? */
if ( id != ID_FORM ) {
if ( failpos ) *failpos = 12;
return PICO_PMV_ERROR_SIZE;
}
if ( type != ID_LWO2 ) {
if ( type == ID_LWOB )
return lwValidateObject5( filename, fp, failID, failpos );
else {
if ( failpos ) *failpos = 12;
return PICO_PMV_ERROR_IDENT;
}
}
return PICO_PMV_OK;
}

651
libs/picomodel/lwo/lwo2.h Normal file
View File

@@ -0,0 +1,651 @@
/*
======================================================================
lwo2.h
Definitions and typedefs for LWO2 files.
Ernie Wright 17 Sep 00
====================================================================== */
#ifndef LWO2_H
#define LWO2_H
/* chunk and subchunk IDs */
#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d))
#define ID_FORM LWID_('F','O','R','M')
#define ID_LWO2 LWID_('L','W','O','2')
#define ID_LWOB LWID_('L','W','O','B')
/* top-level chunks */
#define ID_LAYR LWID_('L','A','Y','R')
#define ID_TAGS LWID_('T','A','G','S')
#define ID_PNTS LWID_('P','N','T','S')
#define ID_BBOX LWID_('B','B','O','X')
#define ID_VMAP LWID_('V','M','A','P')
#define ID_VMAD LWID_('V','M','A','D')
#define ID_POLS LWID_('P','O','L','S')
#define ID_PTAG LWID_('P','T','A','G')
#define ID_ENVL LWID_('E','N','V','L')
#define ID_CLIP LWID_('C','L','I','P')
#define ID_SURF LWID_('S','U','R','F')
#define ID_DESC LWID_('D','E','S','C')
#define ID_TEXT LWID_('T','E','X','T')
#define ID_ICON LWID_('I','C','O','N')
/* polygon types */
#define ID_FACE LWID_('F','A','C','E')
#define ID_CURV LWID_('C','U','R','V')
#define ID_PTCH LWID_('P','T','C','H')
#define ID_MBAL LWID_('M','B','A','L')
#define ID_BONE LWID_('B','O','N','E')
/* polygon tags */
#define ID_SURF LWID_('S','U','R','F')
#define ID_PART LWID_('P','A','R','T')
#define ID_SMGP LWID_('S','M','G','P')
/* envelopes */
#define ID_PRE LWID_('P','R','E',' ')
#define ID_POST LWID_('P','O','S','T')
#define ID_KEY LWID_('K','E','Y',' ')
#define ID_SPAN LWID_('S','P','A','N')
#define ID_TCB LWID_('T','C','B',' ')
#define ID_HERM LWID_('H','E','R','M')
#define ID_BEZI LWID_('B','E','Z','I')
#define ID_BEZ2 LWID_('B','E','Z','2')
#define ID_LINE LWID_('L','I','N','E')
#define ID_STEP LWID_('S','T','E','P')
/* clips */
#define ID_STIL LWID_('S','T','I','L')
#define ID_ISEQ LWID_('I','S','E','Q')
#define ID_ANIM LWID_('A','N','I','M')
#define ID_XREF LWID_('X','R','E','F')
#define ID_STCC LWID_('S','T','C','C')
#define ID_TIME LWID_('T','I','M','E')
#define ID_CONT LWID_('C','O','N','T')
#define ID_BRIT LWID_('B','R','I','T')
#define ID_SATR LWID_('S','A','T','R')
#define ID_HUE LWID_('H','U','E',' ')
#define ID_GAMM LWID_('G','A','M','M')
#define ID_NEGA LWID_('N','E','G','A')
#define ID_IFLT LWID_('I','F','L','T')
#define ID_PFLT LWID_('P','F','L','T')
/* surfaces */
#define ID_COLR LWID_('C','O','L','R')
#define ID_LUMI LWID_('L','U','M','I')
#define ID_DIFF LWID_('D','I','F','F')
#define ID_SPEC LWID_('S','P','E','C')
#define ID_GLOS LWID_('G','L','O','S')
#define ID_REFL LWID_('R','E','F','L')
#define ID_RFOP LWID_('R','F','O','P')
#define ID_RIMG LWID_('R','I','M','G')
#define ID_RSAN LWID_('R','S','A','N')
#define ID_TRAN LWID_('T','R','A','N')
#define ID_TROP LWID_('T','R','O','P')
#define ID_TIMG LWID_('T','I','M','G')
#define ID_RIND LWID_('R','I','N','D')
#define ID_TRNL LWID_('T','R','N','L')
#define ID_BUMP LWID_('B','U','M','P')
#define ID_SMAN LWID_('S','M','A','N')
#define ID_SIDE LWID_('S','I','D','E')
#define ID_CLRH LWID_('C','L','R','H')
#define ID_CLRF LWID_('C','L','R','F')
#define ID_ADTR LWID_('A','D','T','R')
#define ID_SHRP LWID_('S','H','R','P')
#define ID_LINE LWID_('L','I','N','E')
#define ID_LSIZ LWID_('L','S','I','Z')
#define ID_ALPH LWID_('A','L','P','H')
#define ID_AVAL LWID_('A','V','A','L')
#define ID_GVAL LWID_('G','V','A','L')
#define ID_BLOK LWID_('B','L','O','K')
/* texture layer */
#define ID_TYPE LWID_('T','Y','P','E')
#define ID_CHAN LWID_('C','H','A','N')
#define ID_NAME LWID_('N','A','M','E')
#define ID_ENAB LWID_('E','N','A','B')
#define ID_OPAC LWID_('O','P','A','C')
#define ID_FLAG LWID_('F','L','A','G')
#define ID_PROJ LWID_('P','R','O','J')
#define ID_STCK LWID_('S','T','C','K')
#define ID_TAMP LWID_('T','A','M','P')
/* texture coordinates */
#define ID_TMAP LWID_('T','M','A','P')
#define ID_AXIS LWID_('A','X','I','S')
#define ID_CNTR LWID_('C','N','T','R')
#define ID_SIZE LWID_('S','I','Z','E')
#define ID_ROTA LWID_('R','O','T','A')
#define ID_OREF LWID_('O','R','E','F')
#define ID_FALL LWID_('F','A','L','L')
#define ID_CSYS LWID_('C','S','Y','S')
/* image map */
#define ID_IMAP LWID_('I','M','A','P')
#define ID_IMAG LWID_('I','M','A','G')
#define ID_WRAP LWID_('W','R','A','P')
#define ID_WRPW LWID_('W','R','P','W')
#define ID_WRPH LWID_('W','R','P','H')
#define ID_VMAP LWID_('V','M','A','P')
#define ID_AAST LWID_('A','A','S','T')
#define ID_PIXB LWID_('P','I','X','B')
/* procedural */
#define ID_PROC LWID_('P','R','O','C')
#define ID_COLR LWID_('C','O','L','R')
#define ID_VALU LWID_('V','A','L','U')
#define ID_FUNC LWID_('F','U','N','C')
#define ID_FTPS LWID_('F','T','P','S')
#define ID_ITPS LWID_('I','T','P','S')
#define ID_ETPS LWID_('E','T','P','S')
/* gradient */
#define ID_GRAD LWID_('G','R','A','D')
#define ID_GRST LWID_('G','R','S','T')
#define ID_GREN LWID_('G','R','E','N')
#define ID_PNAM LWID_('P','N','A','M')
#define ID_INAM LWID_('I','N','A','M')
#define ID_GRPT LWID_('G','R','P','T')
#define ID_FKEY LWID_('F','K','E','Y')
#define ID_IKEY LWID_('I','K','E','Y')
/* shader */
#define ID_SHDR LWID_('S','H','D','R')
#define ID_DATA LWID_('D','A','T','A')
/* generic linked list */
typedef struct st_lwNode {
struct st_lwNode *next, *prev;
void *data;
} lwNode;
/* plug-in reference */
typedef struct st_lwPlugin {
struct st_lwPlugin *next, *prev;
char *ord;
char *name;
int flags;
void *data;
} lwPlugin;
/* envelopes */
typedef struct st_lwKey {
struct st_lwKey *next, *prev;
float value;
float time;
unsigned int shape; /* ID_TCB, ID_BEZ2, etc. */
float tension;
float continuity;
float bias;
float param[ 4 ];
} lwKey;
typedef struct st_lwEnvelope {
struct st_lwEnvelope *next, *prev;
int index;
int type;
char *name;
lwKey *key; /* linked list of keys */
int nkeys;
int behavior[ 2 ]; /* pre and post (extrapolation) */
lwPlugin *cfilter; /* linked list of channel filters */
int ncfilters;
} lwEnvelope;
#define BEH_RESET 0
#define BEH_CONSTANT 1
#define BEH_REPEAT 2
#define BEH_OSCILLATE 3
#define BEH_OFFSET 4
#define BEH_LINEAR 5
/* values that can be enveloped */
typedef struct st_lwEParam {
float val;
int eindex;
} lwEParam;
typedef struct st_lwVParam {
float val[ 3 ];
int eindex;
} lwVParam;
/* clips */
typedef struct st_lwClipStill {
char *name;
} lwClipStill;
typedef struct st_lwClipSeq {
char *prefix; /* filename before sequence digits */
char *suffix; /* after digits, e.g. extensions */
int digits;
int flags;
int offset;
int start;
int end;
} lwClipSeq;
typedef struct st_lwClipAnim {
char *name;
char *server; /* anim loader plug-in */
void *data;
} lwClipAnim;
typedef struct st_lwClipXRef {
char *string;
int index;
struct st_lwClip *clip;
} lwClipXRef;
typedef struct st_lwClipCycle {
char *name;
int lo;
int hi;
} lwClipCycle;
typedef struct st_lwClip {
struct st_lwClip *next, *prev;
int index;
unsigned int type; /* ID_STIL, ID_ISEQ, etc. */
union {
lwClipStill still;
lwClipSeq seq;
lwClipAnim anim;
lwClipXRef xref;
lwClipCycle cycle;
} source;
float start_time;
float duration;
float frame_rate;
lwEParam contrast;
lwEParam brightness;
lwEParam saturation;
lwEParam hue;
lwEParam gamma;
int negative;
lwPlugin *ifilter; /* linked list of image filters */
int nifilters;
lwPlugin *pfilter; /* linked list of pixel filters */
int npfilters;
} lwClip;
/* textures */
typedef struct st_lwTMap {
lwVParam size;
lwVParam center;
lwVParam rotate;
lwVParam falloff;
int fall_type;
char *ref_object;
int coord_sys;
} lwTMap;
typedef struct st_lwImageMap {
int cindex;
int projection;
char *vmap_name;
int axis;
int wrapw_type;
int wraph_type;
lwEParam wrapw;
lwEParam wraph;
float aa_strength;
int aas_flags;
int pblend;
lwEParam stck;
lwEParam amplitude;
} lwImageMap;
#define PROJ_PLANAR 0
#define PROJ_CYLINDRICAL 1
#define PROJ_SPHERICAL 2
#define PROJ_CUBIC 3
#define PROJ_FRONT 4
#define WRAP_NONE 0
#define WRAP_EDGE 1
#define WRAP_REPEAT 2
#define WRAP_MIRROR 3
typedef struct st_lwProcedural {
int axis;
float value[ 3 ];
char *name;
void *data;
} lwProcedural;
typedef struct st_lwGradKey {
struct st_lwGradKey *next, *prev;
float value;
float rgba[ 4 ];
} lwGradKey;
typedef struct st_lwGradient {
char *paramname;
char *itemname;
float start;
float end;
int repeat;
lwGradKey *key; /* array of gradient keys */
short *ikey; /* array of interpolation codes */
} lwGradient;
typedef struct st_lwTexture {
struct st_lwTexture *next, *prev;
char *ord;
unsigned int type;
unsigned int chan;
lwEParam opacity;
short opac_type;
short enabled;
short negative;
short axis;
union {
lwImageMap imap;
lwProcedural proc;
lwGradient grad;
} param;
lwTMap tmap;
} lwTexture;
/* values that can be textured */
typedef struct st_lwTParam {
float val;
int eindex;
lwTexture *tex; /* linked list of texture layers */
} lwTParam;
typedef struct st_lwCParam {
float rgb[ 3 ];
int eindex;
lwTexture *tex; /* linked list of texture layers */
} lwCParam;
/* surfaces */
typedef struct st_lwGlow {
short enabled;
short type;
lwEParam intensity;
lwEParam size;
} Glow;
typedef struct st_lwRMap {
lwTParam val;
int options;
int cindex;
float seam_angle;
} lwRMap;
typedef struct st_lwLine {
short enabled;
unsigned short flags;
lwEParam size;
} lwLine;
typedef struct st_lwSurface {
struct st_lwSurface *next, *prev;
char *name;
char *srcname;
lwCParam color;
lwTParam luminosity;
lwTParam diffuse;
lwTParam specularity;
lwTParam glossiness;
lwRMap reflection;
lwRMap transparency;
lwTParam eta;
lwTParam translucency;
lwTParam bump;
float smooth;
int sideflags;
float alpha;
int alpha_mode;
lwEParam color_hilite;
lwEParam color_filter;
lwEParam add_trans;
lwEParam dif_sharp;
lwEParam glow;
lwLine line;
lwPlugin *shader; /* linked list of shaders */
int nshaders;
} lwSurface;
/* vertex maps */
typedef struct st_lwVMap {
struct st_lwVMap *next, *prev;
char *name;
unsigned int type;
int dim;
int nverts;
int perpoly;
int *vindex; /* array of point indexes */
int *pindex; /* array of polygon indexes */
float **val;
} lwVMap;
typedef struct st_lwVMapPt {
lwVMap *vmap;
int index; /* vindex or pindex element */
} lwVMapPt;
/* points and polygons */
typedef struct st_lwPoint {
float pos[ 3 ];
int npols; /* number of polygons sharing the point */
int *pol; /* array of polygon indexes */
int nvmaps;
lwVMapPt *vm; /* array of vmap references */
} lwPoint;
typedef struct st_lwPolVert {
int index; /* index into the point array */
float norm[ 3 ];
int nvmaps;
lwVMapPt *vm; /* array of vmap references */
} lwPolVert;
typedef struct st_lwPolygon {
lwSurface *surf;
int part; /* part index */
int smoothgrp; /* smoothing group */
int flags;
unsigned int type;
float norm[ 3 ];
int nverts;
lwPolVert *v; /* array of vertex records */
} lwPolygon;
typedef struct st_lwPointList {
int count;
int offset; /* only used during reading */
lwPoint *pt; /* array of points */
} lwPointList;
typedef struct st_lwPolygonList {
int count;
int offset; /* only used during reading */
int vcount; /* total number of vertices */
int voffset; /* only used during reading */
lwPolygon *pol; /* array of polygons */
} lwPolygonList;
/* geometry layers */
typedef struct st_lwLayer {
struct st_lwLayer *next, *prev;
char *name;
int index;
int parent;
int flags;
float pivot[ 3 ];
float bbox[ 6 ];
lwPointList point;
lwPolygonList polygon;
int nvmaps;
lwVMap *vmap; /* linked list of vmaps */
} lwLayer;
/* tag strings */
typedef struct st_lwTagList {
int count;
int offset; /* only used during reading */
char **tag; /* array of strings */
} lwTagList;
/* an object */
typedef struct st_lwObject {
lwLayer *layer; /* linked list of layers */
lwEnvelope *env; /* linked list of envelopes */
lwClip *clip; /* linked list of clips */
lwSurface *surf; /* linked list of surfaces */
lwTagList taglist;
int nlayers;
int nenvs;
int nclips;
int nsurfs;
} lwObject;
/* lwo2.c */
void lwFreeLayer( lwLayer *layer );
void lwFreeObject( lwObject *object );
lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos );
int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos );
/* pntspols.c */
void lwFreePoints( lwPointList *point );
void lwFreePolygons( lwPolygonList *plist );
int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point );
void lwGetBoundingBox( lwPointList *point, float bbox[] );
int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts );
int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset );
void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon );
int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon );
int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist,
lwSurface **surf, int *nsurfs );
void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon );
void lwFreeTags( lwTagList *tlist );
int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist );
int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist,
lwPolygonList *plist );
/* vmap.c */
void lwFreeVMap( lwVMap *vmap );
lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset,
int perpoly );
int lwGetPointVMaps( lwPointList *point, lwVMap *vmap );
int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap );
/* clip.c */
void lwFreeClip( lwClip *clip );
lwClip *lwGetClip( picoMemStream_t *fp, int cksize );
lwClip *lwFindClip( lwClip *list, int index );
/* envelope.c */
void lwFreeEnvelope( lwEnvelope *env );
lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize );
lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index );
float lwEvalEnvelope( lwEnvelope *env, float time );
/* surface.c */
void lwFreePlugin( lwPlugin *p );
void lwFreeTexture( lwTexture *t );
void lwFreeSurface( lwSurface *surf );
int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex );
int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap );
int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex );
int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex );
int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex );
lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type );
lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz );
lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize );
lwSurface *lwDefaultSurface( void );
/* lwob.c */
lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj );
int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset );
lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos );
int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos );
/* list.c */
void lwListFree( void *list, void ( *freeNode )( void * ));
void lwListAdd( void **list, void *node );
void lwListInsert( void **vlist, void *vitem,
int ( *compare )( void *, void * ));
/* vecmath.c */
float dot( float a[], float b[] );
void cross( float a[], float b[], float c[] );
void normalize( float v[] );
#define vecangle( a, b ) ( float ) acos( dot( a, b ))
/* lwio.c */
void set_flen( int i );
int get_flen( void );
void *getbytes( picoMemStream_t *fp, int size );
void skipbytes( picoMemStream_t *fp, int n );
int getI1( picoMemStream_t *fp );
short getI2( picoMemStream_t *fp );
int getI4( picoMemStream_t *fp );
unsigned char getU1( picoMemStream_t *fp );
unsigned short getU2( picoMemStream_t *fp );
unsigned int getU4( picoMemStream_t *fp );
int getVX( picoMemStream_t *fp );
float getF4( picoMemStream_t *fp );
char *getS0( picoMemStream_t *fp );
int sgetI1( unsigned char **bp );
short sgetI2( unsigned char **bp );
int sgetI4( unsigned char **bp );
unsigned char sgetU1( unsigned char **bp );
unsigned short sgetU2( unsigned char **bp );
unsigned int sgetU4( unsigned char **bp );
int sgetVX( unsigned char **bp );
float sgetF4( unsigned char **bp );
char *sgetS0( unsigned char **bp );
#ifndef __BIG_ENDIAN__
void revbytes( void *bp, int elsize, int elcount );
#else
#define revbytes( b, s, c )
#endif
#endif

723
libs/picomodel/lwo/lwob.c Normal file
View File

@@ -0,0 +1,723 @@
/*
======================================================================
lwob.c
Functions for an LWOB reader. LWOB is the LightWave object format
for versions of LW prior to 6.0.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/* disable warnings */
#ifdef WIN32
#pragma warning( disable:4018 ) /* signed/unsigned mismatch */
#endif
/* IDs specific to LWOB */
#define ID_SRFS LWID_('S','R','F','S')
#define ID_FLAG LWID_('F','L','A','G')
#define ID_VLUM LWID_('V','L','U','M')
#define ID_VDIF LWID_('V','D','I','F')
#define ID_VSPC LWID_('V','S','P','C')
#define ID_RFLT LWID_('R','F','L','T')
#define ID_BTEX LWID_('B','T','E','X')
#define ID_CTEX LWID_('C','T','E','X')
#define ID_DTEX LWID_('D','T','E','X')
#define ID_LTEX LWID_('L','T','E','X')
#define ID_RTEX LWID_('R','T','E','X')
#define ID_STEX LWID_('S','T','E','X')
#define ID_TTEX LWID_('T','T','E','X')
#define ID_TFLG LWID_('T','F','L','G')
#define ID_TSIZ LWID_('T','S','I','Z')
#define ID_TCTR LWID_('T','C','T','R')
#define ID_TFAL LWID_('T','F','A','L')
#define ID_TVEL LWID_('T','V','E','L')
#define ID_TCLR LWID_('T','C','L','R')
#define ID_TVAL LWID_('T','V','A','L')
#define ID_TAMP LWID_('T','A','M','P')
#define ID_TIMG LWID_('T','I','M','G')
#define ID_TAAS LWID_('T','A','A','S')
#define ID_TREF LWID_('T','R','E','F')
#define ID_TOPC LWID_('T','O','P','C')
#define ID_SDAT LWID_('S','D','A','T')
#define ID_TFP0 LWID_('T','F','P','0')
#define ID_TFP1 LWID_('T','F','P','1')
/*
======================================================================
add_clip()
Add a clip to the clip list. Used to store the contents of an RIMG or
TIMG surface subchunk.
====================================================================== */
static int add_clip( char *s, lwClip **clist, int *nclips )
{
lwClip *clip;
char *p;
clip = _pico_calloc( 1, sizeof( lwClip ));
if ( !clip ) return 0;
clip->contrast.val = 1.0f;
clip->brightness.val = 1.0f;
clip->saturation.val = 1.0f;
clip->gamma.val = 1.0f;
if ( p = strstr( s, "(sequence)" )) {
p[ -1 ] = 0;
clip->type = ID_ISEQ;
clip->source.seq.prefix = s;
clip->source.seq.digits = 3;
}
else {
clip->type = ID_STIL;
clip->source.still.name = s;
}
*nclips++;
clip->index = *nclips;
lwListAdd( (void *) clist, clip );
return clip->index;
}
/*
======================================================================
add_tvel()
Add a triple of envelopes to simulate the old texture velocity
parameters.
====================================================================== */
static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs )
{
lwEnvelope *env;
lwKey *key0, *key1;
int i;
for ( i = 0; i < 3; i++ ) {
env = _pico_calloc( 1, sizeof( lwEnvelope ));
key0 = _pico_calloc( 1, sizeof( lwKey ));
key1 = _pico_calloc( 1, sizeof( lwKey ));
if ( !env || !key0 || !key1 ) return 0;
key0->next = key1;
key0->value = pos[ i ];
key0->time = 0.0f;
key1->prev = key0;
key1->value = pos[ i ] + vel[ i ] * 30.0f;
key1->time = 1.0f;
key0->shape = key1->shape = ID_LINE;
env->index = *nenvs + i + 1;
env->type = 0x0301 + i;
env->name = _pico_alloc( 11 );
if ( env->name ) {
strcpy( env->name, "Position.X" );
env->name[ 9 ] += i;
}
env->key = key0;
env->nkeys = 2;
env->behavior[ 0 ] = BEH_LINEAR;
env->behavior[ 1 ] = BEH_LINEAR;
lwListAdd( (void *) elist, env );
}
*nenvs += 3;
return env->index - 2;
}
/*
======================================================================
get_texture()
Create a new texture for BTEX, CTEX, etc. subchunks.
====================================================================== */
static lwTexture *get_texture( char *s )
{
lwTexture *tex;
tex = _pico_calloc( 1, sizeof( lwTexture ));
if ( !tex ) return NULL;
tex->tmap.size.val[ 0 ] =
tex->tmap.size.val[ 1 ] =
tex->tmap.size.val[ 2 ] = 1.0f;
tex->opacity.val = 1.0f;
tex->enabled = 1;
if ( strstr( s, "Image Map" )) {
tex->type = ID_IMAP;
if ( strstr( s, "Planar" )) tex->param.imap.projection = 0;
else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1;
else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2;
else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3;
else if ( strstr( s, "Front" )) tex->param.imap.projection = 4;
tex->param.imap.aa_strength = 1.0f;
tex->param.imap.amplitude.val = 1.0f;
_pico_free( s );
}
else {
tex->type = ID_PROC;
tex->param.proc.name = s;
}
return tex;
}
/*
======================================================================
lwGetSurface5()
Read an lwSurface from an LWOB file.
====================================================================== */
lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj )
{
lwSurface *surf;
lwTexture *tex;
lwPlugin *shdr;
char *s;
float v[ 3 ];
unsigned int id, flags;
unsigned short sz;
int pos, rlen, i;
/* allocate the Surface structure */
surf = _pico_calloc( 1, sizeof( lwSurface ));
if ( !surf ) goto Fail;
/* non-zero defaults */
surf->color.rgb[ 0 ] = 0.78431f;
surf->color.rgb[ 1 ] = 0.78431f;
surf->color.rgb[ 2 ] = 0.78431f;
surf->diffuse.val = 1.0f;
surf->glossiness.val = 0.4f;
surf->bump.val = 1.0f;
surf->eta.val = 1.0f;
surf->sideflags = 1;
/* remember where we started */
set_flen( 0 );
pos = _pico_memstream_tell( fp );
/* name */
surf->name = getS0( fp );
/* first subchunk header */
id = getU4( fp );
sz = getU2( fp );
if ( 0 > get_flen() ) goto Fail;
/* process subchunks as they're encountered */
while ( 1 ) {
sz += sz & 1;
set_flen( 0 );
switch ( id ) {
case ID_COLR:
surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f;
surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f;
surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f;
break;
case ID_FLAG:
flags = getU2( fp );
if ( flags & 4 ) surf->smooth = 1.56207f;
if ( flags & 8 ) surf->color_hilite.val = 1.0f;
if ( flags & 16 ) surf->color_filter.val = 1.0f;
if ( flags & 128 ) surf->dif_sharp.val = 0.5f;
if ( flags & 256 ) surf->sideflags = 3;
if ( flags & 512 ) surf->add_trans.val = 1.0f;
break;
case ID_LUMI:
surf->luminosity.val = getI2( fp ) / 256.0f;
break;
case ID_VLUM:
surf->luminosity.val = getF4( fp );
break;
case ID_DIFF:
surf->diffuse.val = getI2( fp ) / 256.0f;
break;
case ID_VDIF:
surf->diffuse.val = getF4( fp );
break;
case ID_SPEC:
surf->specularity.val = getI2( fp ) / 256.0f;
break;
case ID_VSPC:
surf->specularity.val = getF4( fp );
break;
case ID_GLOS:
surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f;
break;
case ID_SMAN:
surf->smooth = getF4( fp );
break;
case ID_REFL:
surf->reflection.val.val = getI2( fp ) / 256.0f;
break;
case ID_RFLT:
surf->reflection.options = getU2( fp );
break;
case ID_RIMG:
s = getS0( fp );
surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips );
surf->reflection.options = 3;
break;
case ID_RSAN:
surf->reflection.seam_angle = getF4( fp );
break;
case ID_TRAN:
surf->transparency.val.val = getI2( fp ) / 256.0f;
break;
case ID_RIND:
surf->eta.val = getF4( fp );
break;
case ID_BTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->bump.tex, tex );
break;
case ID_CTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->color.tex, tex );
break;
case ID_DTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->diffuse.tex, tex );
break;
case ID_LTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->luminosity.tex, tex );
break;
case ID_RTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->reflection.val.tex, tex );
break;
case ID_STEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->specularity.tex, tex );
break;
case ID_TTEX:
s = getbytes( fp, sz );
tex = get_texture( s );
lwListAdd( (void *) &surf->transparency.val.tex, tex );
break;
case ID_TFLG:
flags = getU2( fp );
if ( flags & 1 ) i = 0;
if ( flags & 2 ) i = 1;
if ( flags & 4 ) i = 2;
tex->axis = i;
if ( tex->type == ID_IMAP )
tex->param.imap.axis = i;
else
tex->param.proc.axis = i;
if ( flags & 8 ) tex->tmap.coord_sys = 1;
if ( flags & 16 ) tex->negative = 1;
if ( flags & 32 ) tex->param.imap.pblend = 1;
if ( flags & 64 ) {
tex->param.imap.aa_strength = 1.0f;
tex->param.imap.aas_flags = 1;
}
break;
case ID_TSIZ:
for ( i = 0; i < 3; i++ )
tex->tmap.size.val[ i ] = getF4( fp );
break;
case ID_TCTR:
for ( i = 0; i < 3; i++ )
tex->tmap.center.val[ i ] = getF4( fp );
break;
case ID_TFAL:
for ( i = 0; i < 3; i++ )
tex->tmap.falloff.val[ i ] = getF4( fp );
break;
case ID_TVEL:
for ( i = 0; i < 3; i++ )
v[ i ] = getF4( fp );
tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v,
&obj->env, &obj->nenvs );
break;
case ID_TCLR:
if ( tex->type == ID_PROC )
for ( i = 0; i < 3; i++ )
tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
break;
case ID_TVAL:
tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
break;
case ID_TAMP:
if ( tex->type == ID_IMAP )
tex->param.imap.amplitude.val = getF4( fp );
break;
case ID_TIMG:
s = getS0( fp );
tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
break;
case ID_TAAS:
tex->param.imap.aa_strength = getF4( fp );
tex->param.imap.aas_flags = 1;
break;
case ID_TREF:
tex->tmap.ref_object = getbytes( fp, sz );
break;
case ID_TOPC:
tex->opacity.val = getF4( fp );
break;
case ID_TFP0:
if ( tex->type == ID_IMAP )
tex->param.imap.wrapw.val = getF4( fp );
break;
case ID_TFP1:
if ( tex->type == ID_IMAP )
tex->param.imap.wraph.val = getF4( fp );
break;
case ID_SHDR:
shdr = _pico_calloc( 1, sizeof( lwPlugin ));
if ( !shdr ) goto Fail;
shdr->name = getbytes( fp, sz );
lwListAdd( (void *) &surf->shader, shdr );
surf->nshaders++;
break;
case ID_SDAT:
shdr->data = getbytes( fp, sz );
break;
default:
break;
}
/* error while reading current subchunk? */
rlen = get_flen();
if ( rlen < 0 || rlen > sz ) goto Fail;
/* skip unread parts of the current subchunk */
if ( rlen < sz )
_pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
/* end of the SURF chunk? */
if ( cksize <= _pico_memstream_tell( fp ) - pos )
break;
/* get the next subchunk header */
set_flen( 0 );
id = getU4( fp );
sz = getU2( fp );
if ( 6 != get_flen() ) goto Fail;
}
return surf;
Fail:
if ( surf ) lwFreeSurface( surf );
return NULL;
}
/*
======================================================================
lwGetPolygons5()
Read polygon records from a POLS chunk in an LWOB file. The polygons
are added to the array in the lwPolygonList.
====================================================================== */
int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset )
{
lwPolygon *pp;
lwPolVert *pv;
unsigned char *buf, *bp;
int i, j, nv, nverts, npols;
if ( cksize == 0 ) return 1;
/* read the whole chunk */
set_flen( 0 );
buf = getbytes( fp, cksize );
if ( !buf ) goto Fail;
/* count the polygons and vertices */
nverts = 0;
npols = 0;
bp = buf;
while ( bp < buf + cksize ) {
nv = sgetU2( &bp );
nverts += nv;
npols++;
bp += 2 * nv;
i = sgetI2( &bp );
if ( i < 0 ) bp += 2; /* detail polygons */
}
if ( !lwAllocPolygons( plist, npols, nverts ))
goto Fail;
/* fill in the new polygons */
bp = buf;
pp = plist->pol + plist->offset;
pv = plist->pol[ 0 ].v + plist->voffset;
for ( i = 0; i < npols; i++ ) {
nv = sgetU2( &bp );
pp->nverts = nv;
pp->type = ID_FACE;
if ( !pp->v ) pp->v = pv;
for ( j = 0; j < nv; j++ )
pv[ j ].index = sgetU2( &bp ) + ptoffset;
j = sgetI2( &bp );
if ( j < 0 ) {
j = -j;
bp += 2;
}
j -= 1;
pp->surf = ( lwSurface * ) j;
pp++;
pv += nv;
}
_pico_free( buf );
return 1;
Fail:
if ( buf ) _pico_free( buf );
lwFreePolygons( plist );
return 0;
}
/*
======================================================================
getLWObject5()
Returns the contents of an LWOB, given its filename, or NULL if the
file couldn't be loaded. On failure, failID and failpos can be used
to diagnose the cause.
1. If the file isn't an LWOB, failpos will contain 12 and failID will
be unchanged.
2. If an error occurs while reading an LWOB, failID will contain the
most recently read IFF chunk ID, and failpos will contain the
value returned by _pico_memstream_tell() at the time of the failure.
3. If the file couldn't be opened, or an error occurs while reading
the first 12 bytes, both failID and failpos will be unchanged.
If you don't need this information, failID and failpos can be NULL.
====================================================================== */
lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
{
lwObject *object;
lwLayer *layer;
lwNode *node;
unsigned int id, formsize, type, cksize;
/* open the file */
if ( !fp ) return NULL;
/* read the first 12 bytes */
set_flen( 0 );
id = getU4( fp );
formsize = getU4( fp );
type = getU4( fp );
if ( 12 != get_flen() ) {
return NULL;
}
/* LWOB? */
if ( id != ID_FORM || type != ID_LWOB ) {
if ( failpos ) *failpos = 12;
return NULL;
}
/* allocate an object and a default layer */
object = _pico_calloc( 1, sizeof( lwObject ));
if ( !object ) goto Fail;
layer = _pico_calloc( 1, sizeof( lwLayer ));
if ( !layer ) goto Fail;
object->layer = layer;
object->nlayers = 1;
/* get the first chunk header */
id = getU4( fp );
cksize = getU4( fp );
if ( 0 > get_flen() ) goto Fail;
/* process chunks as they're encountered */
while ( 1 ) {
cksize += cksize & 1;
switch ( id )
{
case ID_PNTS:
if ( !lwGetPoints( fp, cksize, &layer->point ))
goto Fail;
break;
case ID_POLS:
if ( !lwGetPolygons5( fp, cksize, &layer->polygon,
layer->point.offset ))
goto Fail;
break;
case ID_SRFS:
if ( !lwGetTags( fp, cksize, &object->taglist ))
goto Fail;
break;
case ID_SURF:
node = ( lwNode * ) lwGetSurface5( fp, cksize, object );
if ( !node ) goto Fail;
lwListAdd( (void *) &object->surf, node );
object->nsurfs++;
break;
default:
_pico_memstream_seek( fp, cksize, PICO_SEEK_CUR );
break;
}
/* end of the file? */
if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break;
/* get the next chunk header */
set_flen( 0 );
id = getU4( fp );
cksize = getU4( fp );
if ( 8 != get_flen() ) goto Fail;
}
lwGetBoundingBox( &layer->point, layer->bbox );
lwGetPolyNormals( &layer->point, &layer->polygon );
if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail;
if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist,
&object->surf, &object->nsurfs )) goto Fail;
lwGetVertNormals( &layer->point, &layer->polygon );
return object;
Fail:
if ( failID ) *failID = id;
if ( fp ) {
if ( failpos ) *failpos = _pico_memstream_tell( fp );
}
lwFreeObject( object );
return NULL;
}
int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos )
{
unsigned int id, formsize, type;
/* open the file */
if ( !fp ) return PICO_PMV_ERROR_MEMORY;
/* read the first 12 bytes */
set_flen( 0 );
id = getU4( fp );
formsize = getU4( fp );
type = getU4( fp );
if ( 12 != get_flen() ) {
return PICO_PMV_ERROR_SIZE;
}
/* LWOB? */
if ( id != ID_FORM || type != ID_LWOB ) {
if ( failpos ) *failpos = 12;
return PICO_PMV_ERROR_IDENT;
}
return PICO_PMV_OK;
}

View File

@@ -0,0 +1,537 @@
/*
======================================================================
pntspols.c
Point and polygon functions for an LWO2 reader.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
lwFreePoints()
Free the memory used by an lwPointList.
====================================================================== */
void lwFreePoints( lwPointList *point )
{
int i;
if ( point ) {
if ( point->pt ) {
for ( i = 0; i < point->count; i++ ) {
if ( point->pt[ i ].pol ) _pico_free( point->pt[ i ].pol );
if ( point->pt[ i ].vm ) _pico_free( point->pt[ i ].vm );
}
_pico_free( point->pt );
}
memset( point, 0, sizeof( lwPointList ));
}
}
/*
======================================================================
lwFreePolygons()
Free the memory used by an lwPolygonList.
====================================================================== */
void lwFreePolygons( lwPolygonList *plist )
{
int i, j;
if ( plist ) {
if ( plist->pol ) {
for ( i = 0; i < plist->count; i++ ) {
if ( plist->pol[ i ].v ) {
for ( j = 0; j < plist->pol[ i ].nverts; j++ )
if ( plist->pol[ i ].v[ j ].vm )
_pico_free( plist->pol[ i ].v[ j ].vm );
}
}
if ( plist->pol[ 0 ].v )
_pico_free( plist->pol[ 0 ].v );
_pico_free( plist->pol );
}
memset( plist, 0, sizeof( lwPolygonList ));
}
}
/*
======================================================================
lwGetPoints()
Read point records from a PNTS chunk in an LWO2 file. The points are
added to the array in the lwPointList.
====================================================================== */
int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point )
{
float *f;
int np, i, j;
if ( cksize == 1 ) return 1;
/* extend the point array to hold the new points */
np = cksize / 12;
point->offset = point->count;
point->count += np;
if ( !_pico_realloc( (void *) &point->pt, (point->count - np) * sizeof( lwPoint ), point->count * sizeof( lwPoint )) )
return 0;
memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint ));
/* read the whole chunk */
f = ( float * ) getbytes( fp, cksize );
if ( !f ) return 0;
revbytes( f, 4, np * 3 );
/* assign position values */
for ( i = 0, j = 0; i < np; i++, j += 3 ) {
point->pt[ i ].pos[ 0 ] = f[ j ];
point->pt[ i ].pos[ 1 ] = f[ j + 1 ];
point->pt[ i ].pos[ 2 ] = f[ j + 2 ];
}
_pico_free( f );
return 1;
}
/*
======================================================================
lwGetBoundingBox()
Calculate the bounding box for a point list, but only if the bounding
box hasn't already been initialized.
====================================================================== */
void lwGetBoundingBox( lwPointList *point, float bbox[] )
{
int i, j;
if ( point->count == 0 ) return;
for ( i = 0; i < 6; i++ )
if ( bbox[ i ] != 0.0f ) return;
bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f;
bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f;
for ( i = 0; i < point->count; i++ ) {
for ( j = 0; j < 3; j++ ) {
if ( bbox[ j ] > point->pt[ i ].pos[ j ] )
bbox[ j ] = point->pt[ i ].pos[ j ];
if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] )
bbox[ j + 3 ] = point->pt[ i ].pos[ j ];
}
}
}
/*
======================================================================
lwAllocPolygons()
Allocate or extend the polygon arrays to hold new records.
====================================================================== */
int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts )
{
int i;
plist->offset = plist->count;
plist->count += npols;
if ( !_pico_realloc( (void *) &plist->pol, (plist->count - npols) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon )) )
return 0;
memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon ));
plist->voffset = plist->vcount;
plist->vcount += nverts;
if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, (plist->vcount - nverts) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert )) )
return 0;
memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert ));
/* fix up the old vertex pointers */
for ( i = 1; i < plist->offset; i++ )
plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts;
return 1;
}
/*
======================================================================
lwGetPolygons()
Read polygon records from a POLS chunk in an LWO2 file. The polygons
are added to the array in the lwPolygonList.
====================================================================== */
int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset )
{
lwPolygon *pp;
lwPolVert *pv;
unsigned char *buf, *bp;
int i, j, flags, nv, nverts, npols;
unsigned int type;
if ( cksize == 0 ) return 1;
/* read the whole chunk */
set_flen( 0 );
type = getU4( fp );
buf = getbytes( fp, cksize - 4 );
if ( cksize != get_flen() ) goto Fail;
/* count the polygons and vertices */
nverts = 0;
npols = 0;
bp = buf;
while ( bp < buf + cksize - 4 ) {
nv = sgetU2( &bp );
nv &= 0x03FF;
nverts += nv;
npols++;
for ( i = 0; i < nv; i++ )
j = sgetVX( &bp );
}
if ( !lwAllocPolygons( plist, npols, nverts ))
goto Fail;
/* fill in the new polygons */
bp = buf;
pp = plist->pol + plist->offset;
pv = plist->pol[ 0 ].v + plist->voffset;
for ( i = 0; i < npols; i++ ) {
nv = sgetU2( &bp );
flags = nv & 0xFC00;
nv &= 0x03FF;
pp->nverts = nv;
pp->flags = flags;
pp->type = type;
if ( !pp->v ) pp->v = pv;
for ( j = 0; j < nv; j++ )
pp->v[ j ].index = sgetVX( &bp ) + ptoffset;
pp++;
pv += nv;
}
_pico_free( buf );
return 1;
Fail:
if ( buf ) _pico_free( buf );
lwFreePolygons( plist );
return 0;
}
/*
======================================================================
lwGetPolyNormals()
Calculate the polygon normals. By convention, LW's polygon normals
are found as the cross product of the first and last edges. It's
undefined for one- and two-point polygons.
====================================================================== */
void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon )
{
int i, j;
float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ];
for ( i = 0; i < polygon->count; i++ ) {
if ( polygon->pol[ i ].nverts < 3 ) continue;
for ( j = 0; j < 3; j++ ) {
p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ];
p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ];
pn[ j ] = point->pt[ polygon->pol[ i ].v[
polygon->pol[ i ].nverts - 1 ].index ].pos[ j ];
}
for ( j = 0; j < 3; j++ ) {
v1[ j ] = p2[ j ] - p1[ j ];
v2[ j ] = pn[ j ] - p1[ j ];
}
cross( v1, v2, polygon->pol[ i ].norm );
normalize( polygon->pol[ i ].norm );
}
}
/*
======================================================================
lwGetPointPolygons()
For each point, fill in the indexes of the polygons that share the
point. Returns 0 if any of the memory allocations fail, otherwise
returns 1.
====================================================================== */
int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon )
{
int i, j, k;
/* count the number of polygons per point */
for ( i = 0; i < polygon->count; i++ )
for ( j = 0; j < polygon->pol[ i ].nverts; j++ )
++point->pt[ polygon->pol[ i ].v[ j ].index ].npols;
/* alloc per-point polygon arrays */
for ( i = 0; i < point->count; i++ ) {
if ( point->pt[ i ].npols == 0 ) continue;
point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int ));
if ( !point->pt[ i ].pol ) return 0;
point->pt[ i ].npols = 0;
}
/* fill in polygon array for each point */
for ( i = 0; i < polygon->count; i++ ) {
for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
k = polygon->pol[ i ].v[ j ].index;
point->pt[ k ].pol[ point->pt[ k ].npols ] = i;
++point->pt[ k ].npols;
}
}
return 1;
}
/*
======================================================================
lwResolvePolySurfaces()
Convert tag indexes into actual lwSurface pointers. If any polygons
point to tags for which no corresponding surface can be found, a
default surface is created.
====================================================================== */
int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist,
lwSurface **surf, int *nsurfs )
{
lwSurface **s, *st;
int i, index;
if ( tlist->count == 0 ) return 1;
s = _pico_calloc( tlist->count, sizeof( lwSurface * ));
if ( !s ) return 0;
for ( i = 0; i < tlist->count; i++ ) {
st = *surf;
while ( st ) {
if ( !strcmp( st->name, tlist->tag[ i ] )) {
s[ i ] = st;
break;
}
st = st->next;
}
}
for ( i = 0; i < polygon->count; i++ ) {
index = ( int ) polygon->pol[ i ].surf;
if ( index < 0 || index > tlist->count ) return 0;
if ( !s[ index ] ) {
s[ index ] = lwDefaultSurface();
if ( !s[ index ] ) return 0;
s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 );
if ( !s[ index ]->name ) return 0;
strcpy( s[ index ]->name, tlist->tag[ index ] );
lwListAdd( (void *) surf, s[ index ] );
*nsurfs = *nsurfs + 1;
}
polygon->pol[ i ].surf = s[ index ];
}
_pico_free( s );
return 1;
}
/*
======================================================================
lwGetVertNormals()
Calculate the vertex normals. For each polygon vertex, sum the
normals of the polygons that share the point. If the normals of the
current and adjacent polygons form an angle greater than the max
smoothing angle for the current polygon's surface, the normal of the
adjacent polygon is excluded from the sum. It's also excluded if the
polygons aren't in the same smoothing group.
Assumes that lwGetPointPolygons(), lwGetPolyNormals() and
lwResolvePolySurfaces() have already been called.
====================================================================== */
void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon )
{
int j, k, n, g, h, p;
float a;
for ( j = 0; j < polygon->count; j++ ) {
for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) {
for ( k = 0; k < 3; k++ )
polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ];
if ( polygon->pol[ j ].surf->smooth <= 0 ) continue;
p = polygon->pol[ j ].v[ n ].index;
for ( g = 0; g < point->pt[ p ].npols; g++ ) {
h = point->pt[ p ].pol[ g ];
if ( h == j ) continue;
if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp )
continue;
a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm );
if ( a > polygon->pol[ j ].surf->smooth ) continue;
for ( k = 0; k < 3; k++ )
polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ];
}
normalize( polygon->pol[ j ].v[ n ].norm );
}
}
}
/*
======================================================================
lwFreeTags()
Free memory used by an lwTagList.
====================================================================== */
void lwFreeTags( lwTagList *tlist )
{
int i;
if ( tlist ) {
if ( tlist->tag ) {
for ( i = 0; i < tlist->count; i++ )
if ( tlist->tag[ i ] ) _pico_free( tlist->tag[ i ] );
_pico_free( tlist->tag );
}
memset( tlist, 0, sizeof( lwTagList ));
}
}
/*
======================================================================
lwGetTags()
Read tag strings from a TAGS chunk in an LWO2 file. The tags are
added to the lwTagList array.
====================================================================== */
int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist )
{
char *buf, *bp;
int i, len, ntags;
if ( cksize == 0 ) return 1;
/* read the whole chunk */
set_flen( 0 );
buf = getbytes( fp, cksize );
if ( !buf ) return 0;
/* count the strings */
ntags = 0;
bp = buf;
while ( bp < buf + cksize ) {
len = strlen( bp ) + 1;
len += len & 1;
bp += len;
++ntags;
}
/* expand the string array to hold the new tags */
tlist->offset = tlist->count;
tlist->count += ntags;
if ( !_pico_realloc( (void *) &tlist->tag, (tlist->count - ntags) * sizeof( char * ), tlist->count * sizeof( char * )) )
goto Fail;
memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * ));
/* copy the new tags to the tag array */
bp = buf;
for ( i = 0; i < ntags; i++ )
tlist->tag[ i + tlist->offset ] = sgetS0( (unsigned char **) &bp );
_pico_free( buf );
return 1;
Fail:
if ( buf ) _pico_free( buf );
return 0;
}
/*
======================================================================
lwGetPolygonTags()
Read polygon tags from a PTAG chunk in an LWO2 file.
====================================================================== */
int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist,
lwPolygonList *plist )
{
unsigned int type;
int rlen = 0, i, j;
set_flen( 0 );
type = getU4( fp );
rlen = get_flen();
if ( rlen < 0 ) return 0;
if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) {
_pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR );
return 1;
}
while ( rlen < cksize ) {
i = getVX( fp ) + plist->offset;
j = getVX( fp ) + tlist->offset;
rlen = get_flen();
if ( rlen < 0 || rlen > cksize ) return 0;
switch ( type ) {
case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break;
case ID_PART: plist->pol[ i ].part = j; break;
case ID_SMGP: plist->pol[ i ].smoothgrp = j; break;
}
}
return 1;
}

1005
libs/picomodel/lwo/surface.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/*
======================================================================
vecmath.c
Basic vector and matrix functions.
Ernie Wright 17 Sep 00
====================================================================== */
#include <math.h>
float dot( float a[], float b[] )
{
return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ];
}
void cross( float a[], float b[], float c[] )
{
c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ];
c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ];
c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ];
}
void normalize( float v[] )
{
float r;
r = ( float ) sqrt( dot( v, v ));
if ( r > 0 ) {
v[ 0 ] /= r;
v[ 1 ] /= r;
v[ 2 ] /= r;
}
}

243
libs/picomodel/lwo/vmap.c Normal file
View File

@@ -0,0 +1,243 @@
/*
======================================================================
vmap.c
Vertex map functions for an LWO2 reader.
Ernie Wright 17 Sep 00
====================================================================== */
#include "../picointernal.h"
#include "lwo2.h"
/*
======================================================================
lwFreeVMap()
Free memory used by an lwVMap.
====================================================================== */
void lwFreeVMap( lwVMap *vmap )
{
if ( vmap ) {
if ( vmap->name ) _pico_free( vmap->name );
if ( vmap->vindex ) _pico_free( vmap->vindex );
if ( vmap->pindex ) _pico_free( vmap->pindex );
if ( vmap->val ) {
if ( vmap->val[ 0 ] ) _pico_free( vmap->val[ 0 ] );
_pico_free( vmap->val );
}
_pico_free( vmap );
}
}
/*
======================================================================
lwGetVMap()
Read an lwVMap from a VMAP or VMAD chunk in an LWO2.
====================================================================== */
lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset,
int perpoly )
{
unsigned char *buf, *bp;
lwVMap *vmap;
float *f;
int i, j, npts, rlen;
/* read the whole chunk */
set_flen( 0 );
buf = getbytes( fp, cksize );
if ( !buf ) return NULL;
vmap = _pico_calloc( 1, sizeof( lwVMap ));
if ( !vmap ) {
_pico_free( buf );
return NULL;
}
/* initialize the vmap */
vmap->perpoly = perpoly;
bp = buf;
set_flen( 0 );
vmap->type = sgetU4( &bp );
vmap->dim = sgetU2( &bp );
vmap->name = sgetS0( &bp );
rlen = get_flen();
/* count the vmap records */
npts = 0;
while ( bp < buf + cksize ) {
i = sgetVX( &bp );
if ( perpoly )
i = sgetVX( &bp );
bp += vmap->dim * sizeof( float );
++npts;
}
/* allocate the vmap */
vmap->nverts = npts;
vmap->vindex = _pico_calloc( npts, sizeof( int ));
if ( !vmap->vindex ) goto Fail;
if ( perpoly ) {
vmap->pindex = _pico_calloc( npts, sizeof( int ));
if ( !vmap->pindex ) goto Fail;
}
if ( vmap->dim > 0 ) {
vmap->val = _pico_calloc( npts, sizeof( float * ));
if ( !vmap->val ) goto Fail;
f = _pico_alloc( npts * vmap->dim * sizeof( float ));
if ( !f ) goto Fail;
for ( i = 0; i < npts; i++ )
vmap->val[ i ] = f + i * vmap->dim;
}
/* fill in the vmap values */
bp = buf + rlen;
for ( i = 0; i < npts; i++ ) {
vmap->vindex[ i ] = sgetVX( &bp );
if ( perpoly )
vmap->pindex[ i ] = sgetVX( &bp );
for ( j = 0; j < vmap->dim; j++ )
vmap->val[ i ][ j ] = sgetF4( &bp );
}
_pico_free( buf );
return vmap;
Fail:
if ( buf ) _pico_free( buf );
lwFreeVMap( vmap );
return NULL;
}
/*
======================================================================
lwGetPointVMaps()
Fill in the lwVMapPt structure for each point.
====================================================================== */
int lwGetPointVMaps( lwPointList *point, lwVMap *vmap )
{
lwVMap *vm;
int i, j, n;
/* count the number of vmap values for each point */
vm = vmap;
while ( vm ) {
if ( !vm->perpoly )
for ( i = 0; i < vm->nverts; i++ )
++point->pt[ vm->vindex[ i ]].nvmaps;
vm = vm->next;
}
/* allocate vmap references for each mapped point */
for ( i = 0; i < point->count; i++ ) {
if ( point->pt[ i ].nvmaps ) {
point->pt[ i ].vm = _pico_calloc( point->pt[ i ].nvmaps, sizeof( lwVMapPt ));
if ( !point->pt[ i ].vm ) return 0;
point->pt[ i ].nvmaps = 0;
}
}
/* fill in vmap references for each mapped point */
vm = vmap;
while ( vm ) {
if ( !vm->perpoly ) {
for ( i = 0; i < vm->nverts; i++ ) {
j = vm->vindex[ i ];
n = point->pt[ j ].nvmaps;
point->pt[ j ].vm[ n ].vmap = vm;
point->pt[ j ].vm[ n ].index = i;
++point->pt[ j ].nvmaps;
}
}
vm = vm->next;
}
return 1;
}
/*
======================================================================
lwGetPolyVMaps()
Fill in the lwVMapPt structure for each polygon vertex.
====================================================================== */
int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap )
{
lwVMap *vm;
lwPolVert *pv;
int i, j;
/* count the number of vmap values for each polygon vertex */
vm = vmap;
while ( vm ) {
if ( vm->perpoly ) {
for ( i = 0; i < vm->nverts; i++ ) {
for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
if ( vm->vindex[ i ] == pv->index ) {
++pv->nvmaps;
break;
}
}
}
}
vm = vm->next;
}
/* allocate vmap references for each mapped vertex */
for ( i = 0; i < polygon->count; i++ ) {
for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) {
pv = &polygon->pol[ i ].v[ j ];
if ( pv->nvmaps ) {
pv->vm = _pico_calloc( pv->nvmaps, sizeof( lwVMapPt ));
if ( !pv->vm ) return 0;
pv->nvmaps = 0;
}
}
}
/* fill in vmap references for each mapped point */
vm = vmap;
while ( vm ) {
if ( vm->perpoly ) {
for ( i = 0; i < vm->nverts; i++ ) {
for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) {
pv = &polygon->pol[ vm->pindex[ i ]].v[ j ];
if ( vm->vindex[ i ] == pv->index ) {
pv->vm[ pv->nvmaps ].vmap = vm;
pv->vm[ pv->nvmaps ].index = i;
++pv->nvmaps;
break;
}
}
}
}
vm = vm->next;
}
return 1;
}