mirror of
https://github.com/id-Software/GtkRadiant.git
synced 2026-03-20 17:09:39 +01:00
The GtkRadiant sources as originally released under the GPL license.
This commit is contained in:
278
libs/picomodel/lwo/clip.c
Normal file
278
libs/picomodel/lwo/clip.c
Normal 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;
|
||||
}
|
||||
600
libs/picomodel/lwo/envelope.c
Normal file
600
libs/picomodel/lwo/envelope.c
Normal 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
101
libs/picomodel/lwo/list.c
Normal 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
442
libs/picomodel/lwo/lwio.c
Normal 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
308
libs/picomodel/lwo/lwo2.c
Normal 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
651
libs/picomodel/lwo/lwo2.h
Normal 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
723
libs/picomodel/lwo/lwob.c
Normal 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;
|
||||
}
|
||||
537
libs/picomodel/lwo/pntspols.c
Normal file
537
libs/picomodel/lwo/pntspols.c
Normal 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
1005
libs/picomodel/lwo/surface.c
Normal file
File diff suppressed because it is too large
Load Diff
37
libs/picomodel/lwo/vecmath.c
Normal file
37
libs/picomodel/lwo/vecmath.c
Normal 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
243
libs/picomodel/lwo/vmap.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user