mirror of
https://github.com/id-Software/GtkRadiant.git
synced 2026-03-20 00:49:29 +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;
|
||||
}
|
||||
1356
libs/picomodel/picointernal.c
Normal file
1356
libs/picomodel/picointernal.c
Normal file
File diff suppressed because it is too large
Load Diff
206
libs/picomodel/picointernal.h
Normal file
206
libs/picomodel/picointernal.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#ifndef PICOINTERNAL_H
|
||||
#define PICOINTERNAL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
/* dependencies */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "picomodel.h"
|
||||
|
||||
|
||||
/* os dependent replacements */
|
||||
#if WIN32 || _WIN32
|
||||
#define _pico_stricmp stricmp
|
||||
#define _pico_strnicmp strnicmp
|
||||
#else
|
||||
#define _pico_stricmp strcasecmp
|
||||
#define _pico_strnicmp strncasecmp
|
||||
#endif
|
||||
|
||||
|
||||
/* constants */
|
||||
#define PICO_PI 3.14159265358979323846
|
||||
|
||||
#define PICO_SEEK_SET 0
|
||||
#define PICO_SEEK_CUR 1
|
||||
#define PICO_SEEK_END 2
|
||||
|
||||
#define PICO_IOEOF 1
|
||||
#define PICO_IOERR 2
|
||||
|
||||
/* types */
|
||||
typedef struct picoParser_s
|
||||
{
|
||||
char *buffer;
|
||||
int bufSize;
|
||||
char *token;
|
||||
int tokenSize;
|
||||
int tokenMax;
|
||||
char *cursor;
|
||||
char *max;
|
||||
int curLine;
|
||||
}
|
||||
picoParser_t;
|
||||
|
||||
typedef struct picoMemStream_s
|
||||
{
|
||||
picoByte_t *buffer;
|
||||
int bufSize;
|
||||
picoByte_t *curPos;
|
||||
int flag;
|
||||
}
|
||||
picoMemStream_t;
|
||||
|
||||
|
||||
/* variables */
|
||||
extern const picoModule_t *picoModules[];
|
||||
|
||||
extern void *(*_pico_ptr_malloc)( size_t );
|
||||
extern void (*_pico_ptr_free)( void* );
|
||||
extern void (*_pico_ptr_load_file)( char*, unsigned char**, int* );
|
||||
extern void (*_pico_ptr_free_file)( void* );
|
||||
extern void (*_pico_ptr_print)( int, const char* );
|
||||
|
||||
|
||||
|
||||
/* prototypes */
|
||||
|
||||
/* memory */
|
||||
void *_pico_alloc( size_t size );
|
||||
void *_pico_calloc( size_t num, size_t size );
|
||||
void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize );
|
||||
char *_pico_clone_alloc( const char *str );
|
||||
void _pico_free( void *ptr );
|
||||
|
||||
/* files */
|
||||
void _pico_load_file( char *name, unsigned char **buffer, int *bufSize );
|
||||
void _pico_free_file( void *buffer );
|
||||
|
||||
/* strings */
|
||||
void _pico_first_token( char *str );
|
||||
char *_pico_strltrim( char *str );
|
||||
char *_pico_strrtrim( char *str );
|
||||
int _pico_strchcount( char *str, int ch );
|
||||
void _pico_printf( int level, const char *format, ... );
|
||||
char *_pico_stristr( char *str, const char *substr );
|
||||
void _pico_unixify( char *path );
|
||||
int _pico_nofname( const char *path, char *dest, int destSize );
|
||||
const char *_pico_nopath( const char *path );
|
||||
char *_pico_setfext( char *path, const char *ext );
|
||||
int _pico_getline( char *buf, int bufsize, char *dest, int destsize );
|
||||
char *_pico_strlwr( char *str );
|
||||
|
||||
/* vectors */
|
||||
void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs );
|
||||
void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs );
|
||||
void _pico_zero_vec( picoVec3_t vec );
|
||||
void _pico_zero_vec2( picoVec2_t vec );
|
||||
void _pico_zero_vec4( picoVec4_t vec );
|
||||
void _pico_set_vec( picoVec3_t v, float a, float b, float c );
|
||||
void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d );
|
||||
void _pico_set_color( picoColor_t c, int r, int g, int b, int a );
|
||||
void _pico_copy_color( picoColor_t src, picoColor_t dest );
|
||||
void _pico_copy_vec( picoVec3_t src, picoVec3_t dest );
|
||||
void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest );
|
||||
picoVec_t _pico_normalize_vec( picoVec3_t vec );
|
||||
void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest );
|
||||
void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest );
|
||||
picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b );
|
||||
void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest );
|
||||
picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c );
|
||||
void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest );
|
||||
void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest );
|
||||
|
||||
/* endian */
|
||||
int _pico_big_long( int src );
|
||||
short _pico_big_short( short src );
|
||||
float _pico_big_float( float src );
|
||||
|
||||
int _pico_little_long( int src );
|
||||
short _pico_little_short( short src );
|
||||
float _pico_little_float( float src );
|
||||
|
||||
/* pico ascii parser */
|
||||
picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize );
|
||||
void _pico_free_parser( picoParser_t *p );
|
||||
int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted );
|
||||
char *_pico_parse_first( picoParser_t *p );
|
||||
char *_pico_parse( picoParser_t *p, int allowLFs );
|
||||
void _pico_parse_skip_rest( picoParser_t *p );
|
||||
int _pico_parse_skip_braced( picoParser_t *p );
|
||||
int _pico_parse_check( picoParser_t *p, int allowLFs, char *str );
|
||||
int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str );
|
||||
int _pico_parse_int( picoParser_t *p, int *out );
|
||||
int _pico_parse_int_def( picoParser_t *p, int *out, int def );
|
||||
int _pico_parse_float( picoParser_t *p, float *out );
|
||||
int _pico_parse_float_def( picoParser_t *p, float *out, float def );
|
||||
int _pico_parse_vec( picoParser_t *p, picoVec3_t out);
|
||||
int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def);
|
||||
int _pico_parse_vec2( picoParser_t *p, picoVec2_t out );
|
||||
int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def );
|
||||
int _pico_parse_vec4( picoParser_t *p, picoVec4_t out);
|
||||
int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def);
|
||||
|
||||
/* pico memory stream */
|
||||
picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize );
|
||||
void _pico_free_memstream( picoMemStream_t *s );
|
||||
int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len );
|
||||
int _pico_memstream_getc( picoMemStream_t *s );
|
||||
int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin );
|
||||
long _pico_memstream_tell( picoMemStream_t *s );
|
||||
#define _pico_memstream_eof( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOEOF)
|
||||
#define _pico_memstream_error( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOERR)
|
||||
|
||||
/* end marker */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2289
libs/picomodel/picomodel.c
Normal file
2289
libs/picomodel/picomodel.c
Normal file
File diff suppressed because it is too large
Load Diff
206
libs/picomodel/picomodel.dsp
Normal file
206
libs/picomodel/picomodel.dsp
Normal file
@@ -0,0 +1,206 @@
|
||||
# Microsoft Developer Studio Project File - Name="picomodel" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=picomodel - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "picomodel.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "picomodel.mak" CFG="picomodel - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "picomodel - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "picomodel - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName "picomodel"
|
||||
# PROP Scc_LocalPath ".."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "picomodel - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
MTL=midl.exe
|
||||
F90=df.exe
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /Zi /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /FD /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x40c /d "NDEBUG"
|
||||
# ADD RSC /l 0x40c /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ELSEIF "$(CFG)" == "picomodel - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
MTL=midl.exe
|
||||
F90=df.exe
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x40c /d "_DEBUG"
|
||||
# ADD RSC /l 0x40c /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "picomodel - Win32 Release"
|
||||
# Name "picomodel - Win32 Debug"
|
||||
# Begin Group "src"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "lwo"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\clip.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\envelope.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\list.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\lwio.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\lwo2.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\lwob.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\pntspols.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\surface.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\vecmath.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\vmap.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\picointernal.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\picomodel.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\picomodules.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_3ds.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_ase.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_fm.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_lwo.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_md2.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_md3.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_mdc.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_ms3d.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_obj.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "include"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lwo\lwo2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\picointernal.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\picomodel.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pm_fm.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
206
libs/picomodel/picomodel.vcproj
Normal file
206
libs/picomodel/picomodel.vcproj
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="picomodel"
|
||||
ProjectGUID="{015EA9D3-85F2-4C4E-BFC3-430AC59093B9}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
StringPooling="TRUE"
|
||||
MinimalRebuild="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
BasicRuntimeChecks="0"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/picomodel.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
GlobalOptimizations="TRUE"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="TRUE"
|
||||
OptimizeForWindowsApplication="TRUE"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
StringPooling="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
RuntimeLibrary="2"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/picomodel.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\picointernal.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\picomodel.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\picomodules.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_3ds.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_ase.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_fm.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_lwo.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_md2.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_md3.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_mdc.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_ms3d.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_obj.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_terrain.c">
|
||||
</File>
|
||||
<Filter
|
||||
Name="lwo"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath=".\lwo\clip.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\envelope.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\list.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\lwio.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\lwo2.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\lwo2.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\lwob.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\pntspols.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\surface.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\vecmath.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\lwo\vmap.c">
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\picointernal.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\picomodel.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pm_fm.h">
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
94
libs/picomodel/picomodules.c
Normal file
94
libs/picomodel/picomodules.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PICOMODULES_C
|
||||
|
||||
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
|
||||
|
||||
/* external modules */
|
||||
extern const picoModule_t picoModuleMD3;
|
||||
extern const picoModule_t picoModule3DS;
|
||||
extern const picoModule_t picoModuleASE;
|
||||
extern const picoModule_t picoModuleOBJ;
|
||||
extern const picoModule_t picoModuleMS3D;
|
||||
extern const picoModule_t picoModuleMDC;
|
||||
extern const picoModule_t picoModuleMD2;
|
||||
extern const picoModule_t picoModuleFM;
|
||||
extern const picoModule_t picoModuleLWO;
|
||||
extern const picoModule_t picoModuleTerrain;
|
||||
|
||||
|
||||
|
||||
/* list of all supported file format modules */
|
||||
const picoModule_t *picoModules[] =
|
||||
{
|
||||
&picoModuleMD3, /* quake3 arena md3 */
|
||||
&picoModule3DS, /* autodesk 3ds */
|
||||
&picoModuleASE, /* autodesk ase */
|
||||
&picoModuleMS3D, /* milkshape3d */
|
||||
&picoModuleMDC, /* return to castle wolfenstein mdc */
|
||||
&picoModuleMD2, /* quake2 md2 */
|
||||
&picoModuleFM, /* heretic2 fm */
|
||||
&picoModuleLWO, /* lightwave object */
|
||||
&picoModuleTerrain, /* picoterrain object */
|
||||
&picoModuleOBJ, /* wavefront object */
|
||||
NULL /* arnold */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
PicoModuleList()
|
||||
returns a pointer to the module list and optionally stores
|
||||
the number of supported modules in 'numModules'. Note that
|
||||
this param can be NULL when the count is not needed.
|
||||
*/
|
||||
|
||||
const picoModule_t **PicoModuleList( int *numModules )
|
||||
{
|
||||
/* get module count */
|
||||
if( numModules != NULL )
|
||||
for( (*numModules) = 0; picoModules[ *numModules ] != NULL; (*numModules)++ );
|
||||
|
||||
/* return list of modules */
|
||||
return (const picoModule_t**) picoModules;
|
||||
}
|
||||
777
libs/picomodel/pm_3ds.c
Normal file
777
libs/picomodel/pm_3ds.c
Normal file
@@ -0,0 +1,777 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_3DS_C
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
/* ydnar */
|
||||
static picoColor_t white = { 255,255,255,255 };
|
||||
|
||||
/* remarks:
|
||||
* - 3ds file version is stored in pico special field 0 on load (ydnar: removed)
|
||||
* todo:
|
||||
* - sometimes there is one unnamed surface 0 having 0 verts as
|
||||
* well as 0 faces. this error occurs since pm 0.6 (ydnar?)
|
||||
*/
|
||||
/* uncomment when debugging this module */
|
||||
/* #define DEBUG_PM_3DS
|
||||
#define DEBUG_PM_3DS_EX */
|
||||
|
||||
/* structure holding persistent 3ds loader specific data used */
|
||||
/* to store formerly static vars to keep the module reentrant */
|
||||
/* safe. put everything that needs to be static in here. */
|
||||
typedef struct S3dsLoaderPers
|
||||
{
|
||||
picoModel_t *model; /* ptr to output model */
|
||||
picoSurface_t *surface; /* ptr to current surface */
|
||||
picoShader_t *shader; /* ptr to current shader */
|
||||
picoByte_t *bufptr; /* ptr to raw data */
|
||||
char *basename; /* ptr to model base name (eg. jeep) */
|
||||
int cofs;
|
||||
int maxofs;
|
||||
}
|
||||
T3dsLoaderPers;
|
||||
|
||||
/* 3ds chunk types that we use */
|
||||
enum {
|
||||
/* primary chunk */
|
||||
CHUNK_MAIN = 0x4D4D,
|
||||
|
||||
/* main chunks */
|
||||
CHUNK_VERSION = 0x0002,
|
||||
CHUNK_EDITOR_CONFIG = 0x3D3E,
|
||||
CHUNK_EDITOR_DATA = 0x3D3D,
|
||||
CHUNK_KEYFRAME_DATA = 0xB000,
|
||||
|
||||
/* editor data sub chunks */
|
||||
CHUNK_MATERIAL = 0xAFFF,
|
||||
CHUNK_OBJECT = 0x4000,
|
||||
|
||||
/* material sub chunks */
|
||||
CHUNK_MATNAME = 0xA000,
|
||||
CHUNK_MATDIFFUSE = 0xA020,
|
||||
CHUNK_MATMAP = 0xA200,
|
||||
CHUNK_MATMAPFILE = 0xA300,
|
||||
|
||||
/* lets us know we're reading a new object */
|
||||
CHUNK_OBJECT_MESH = 0x4100,
|
||||
|
||||
/* object mesh sub chunks */
|
||||
CHUNK_OBJECT_VERTICES = 0x4110,
|
||||
CHUNK_OBJECT_FACES = 0x4120,
|
||||
CHUNK_OBJECT_MATERIAL = 0x4130,
|
||||
CHUNK_OBJECT_UV = 0x4140,
|
||||
};
|
||||
#ifdef DEBUG_PM_3DS
|
||||
static struct
|
||||
{
|
||||
int id;
|
||||
char *name;
|
||||
}
|
||||
debugChunkNames[] =
|
||||
{
|
||||
{ CHUNK_MAIN , "CHUNK_MAIN" },
|
||||
{ CHUNK_VERSION , "CHUNK_VERSION" },
|
||||
{ CHUNK_EDITOR_CONFIG , "CHUNK_EDITOR_CONFIG" },
|
||||
{ CHUNK_EDITOR_DATA , "CHUNK_EDITOR_DATA" },
|
||||
{ CHUNK_KEYFRAME_DATA , "CHUNK_KEYFRAME_DATA" },
|
||||
{ CHUNK_MATERIAL , "CHUNK_MATERIAL" },
|
||||
{ CHUNK_OBJECT , "CHUNK_OBJECT" },
|
||||
{ CHUNK_MATNAME , "CHUNK_MATNAME" },
|
||||
{ CHUNK_MATDIFFUSE , "CHUNK_MATDIFFUSE" },
|
||||
{ CHUNK_MATMAP , "CHUNK_MATMAP" },
|
||||
{ CHUNK_MATMAPFILE , "CHUNK_MATMAPFILE" },
|
||||
{ CHUNK_OBJECT_MESH , "CHUNK_OBJECT_MESH" },
|
||||
{ CHUNK_OBJECT_VERTICES , "CHUNK_OBJECT_VERTICES" },
|
||||
{ CHUNK_OBJECT_FACES , "CHUNK_OBJECT_FACES" },
|
||||
{ CHUNK_OBJECT_MATERIAL , "CHUNK_OBJECT_MATERIAL" },
|
||||
{ CHUNK_OBJECT_UV , "CHUNK_OBJECT_UV" },
|
||||
{ 0 , NULL }
|
||||
};
|
||||
static char *DebugGetChunkName (int id)
|
||||
{
|
||||
int i,max; /* imax? ;) */
|
||||
max = sizeof(debugChunkNames) / sizeof(debugChunkNames[0]);
|
||||
|
||||
for (i=0; i<max; i++)
|
||||
{
|
||||
if (debugChunkNames[i].id == id)
|
||||
{
|
||||
/* gaynux update -sea */
|
||||
return _pico_strlwr( debugChunkNames[i].name );
|
||||
}
|
||||
}
|
||||
return "chunk_unknown";
|
||||
}
|
||||
#endif /*DEBUG_PM_3DS*/
|
||||
|
||||
/* this funky loader needs byte alignment */
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct S3dsIndices
|
||||
{
|
||||
unsigned short a,b,c;
|
||||
unsigned short visible;
|
||||
}
|
||||
T3dsIndices;
|
||||
|
||||
typedef struct S3dsChunk
|
||||
{
|
||||
unsigned short id;
|
||||
unsigned int len;
|
||||
}
|
||||
T3dsChunk;
|
||||
|
||||
/* restore previous data alignment */
|
||||
#pragma pack(pop)
|
||||
|
||||
/* _3ds_canload:
|
||||
* validates an autodesk 3ds model file.
|
||||
*/
|
||||
static int _3ds_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
T3dsChunk *chunk;
|
||||
|
||||
/* to keep the compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* sanity check */
|
||||
if (bufSize < sizeof(T3dsChunk))
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* get pointer to 3ds header chunk */
|
||||
chunk = (T3dsChunk *)buffer;
|
||||
|
||||
/* check data length */
|
||||
if (bufSize < _pico_little_long(chunk->len))
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* check 3ds magic */
|
||||
if (_pico_little_short(chunk->id) != CHUNK_MAIN)
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* file seems to be a valid 3ds */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
static T3dsChunk *GetChunk (T3dsLoaderPers *pers)
|
||||
{
|
||||
T3dsChunk *chunk;
|
||||
|
||||
/* sanity check */
|
||||
if (pers->cofs > pers->maxofs) return 0;
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
/* printf("GetChunk: pers->cofs %x\n",pers->cofs); */
|
||||
#endif
|
||||
/* fill in pointer to chunk */
|
||||
chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ];
|
||||
if (!chunk) return NULL;
|
||||
|
||||
chunk->id = _pico_little_short(chunk->id );
|
||||
chunk->len = _pico_little_long (chunk->len);
|
||||
|
||||
/* advance in buffer */
|
||||
pers->cofs += sizeof(T3dsChunk);
|
||||
|
||||
/* this means yay */
|
||||
return chunk;
|
||||
}
|
||||
|
||||
static int GetASCIIZ (T3dsLoaderPers *pers, char *dest, int max)
|
||||
{
|
||||
int pos = 0;
|
||||
int ch;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ch = pers->bufptr[ pers->cofs++ ];
|
||||
if (ch == '\0') break;
|
||||
if (pers->cofs >= pers->maxofs)
|
||||
{
|
||||
dest[ pos ] = '\0';
|
||||
return 0;
|
||||
}
|
||||
dest[ pos++ ] = ch;
|
||||
if (pos >= max) break;
|
||||
}
|
||||
dest[ pos ] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
static picoByte_t GetByte (T3dsLoaderPers *pers)
|
||||
{
|
||||
picoByte_t *value;
|
||||
|
||||
/* sanity check */
|
||||
if (pers->cofs > pers->maxofs) return 0;
|
||||
|
||||
/* get and return value */
|
||||
value = (picoByte_t *)(pers->bufptr + pers->cofs);
|
||||
pers->cofs += 1;
|
||||
return *value;
|
||||
}
|
||||
|
||||
static int GetWord (T3dsLoaderPers *pers)
|
||||
{
|
||||
unsigned short *value;
|
||||
|
||||
/* sanity check */
|
||||
if (pers->cofs > pers->maxofs) return 0;
|
||||
|
||||
/* get and return value */
|
||||
value = (unsigned short *)(pers->bufptr + pers->cofs);
|
||||
pers->cofs += 2;
|
||||
return _pico_little_short(*value);
|
||||
}
|
||||
|
||||
static float GetFloat (T3dsLoaderPers *pers)
|
||||
{
|
||||
float *value;
|
||||
|
||||
/* sanity check */
|
||||
if (pers->cofs > pers->maxofs) return 0;
|
||||
|
||||
/* get and return value */
|
||||
value = (float *)(pers->bufptr + pers->cofs);
|
||||
pers->cofs += 4;
|
||||
return _pico_little_float(*value);
|
||||
}
|
||||
|
||||
static int GetMeshVertices (T3dsLoaderPers *pers)
|
||||
{
|
||||
int numVerts;
|
||||
int i;
|
||||
|
||||
/* get number of verts for this surface */
|
||||
numVerts = GetWord(pers);
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("GetMeshVertices: numverts %d\n",numVerts);
|
||||
#endif
|
||||
/* read in vertices for current surface */
|
||||
for (i=0; i<numVerts; i++)
|
||||
{
|
||||
picoVec3_t v;
|
||||
v[0] = GetFloat( pers );
|
||||
v[1] = GetFloat( pers ); /* ydnar: unflipped */
|
||||
v[2] = GetFloat( pers ); /* ydnar: unflipped and negated */
|
||||
|
||||
/* add current vertex */
|
||||
PicoSetSurfaceXYZ( pers->surface,i,v );
|
||||
PicoSetSurfaceColor( pers->surface,0,i,white ); /* ydnar */
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]);
|
||||
#endif
|
||||
}
|
||||
/* success (no errors occured) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetMeshFaces (T3dsLoaderPers *pers)
|
||||
{
|
||||
int numFaces;
|
||||
int i;
|
||||
|
||||
/* get number of faces for this surface */
|
||||
numFaces = GetWord(pers);
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("GetMeshFaces: numfaces %d\n",numFaces);
|
||||
#endif
|
||||
/* read in vertex indices for current surface */
|
||||
for (i=0; i<numFaces; i++)
|
||||
{
|
||||
/* remember, we only need 3 of 4 values read in for each */
|
||||
/* face. the 4th value is a vis flag for 3dsmax which is */
|
||||
/* being ignored by us here */
|
||||
T3dsIndices face;
|
||||
face.a = GetWord(pers);
|
||||
face.c = GetWord(pers); /* ydnar: flipped order */
|
||||
face.b = GetWord(pers); /* ydnar: flipped order */
|
||||
face.visible = GetWord(pers);
|
||||
|
||||
/* copy indexes */
|
||||
PicoSetSurfaceIndex( pers->surface, (i * 3 + 0), (picoIndex_t)face.a );
|
||||
PicoSetSurfaceIndex( pers->surface, (i * 3 + 1), (picoIndex_t)face.b );
|
||||
PicoSetSurfaceIndex( pers->surface, (i * 3 + 2), (picoIndex_t)face.c );
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("Face: a: %d b: %d c: %d (%d)\n",face.a,face.b,face.c,face.visible);
|
||||
#endif
|
||||
}
|
||||
/* success (no errors occured) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetMeshTexCoords (T3dsLoaderPers *pers)
|
||||
{
|
||||
int numTexCoords;
|
||||
int i;
|
||||
|
||||
/* get number of uv coords for this surface */
|
||||
numTexCoords = GetWord(pers);
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("GetMeshTexCoords: numcoords %d\n",numTexCoords);
|
||||
#endif
|
||||
/* read in uv coords for current surface */
|
||||
for (i=0; i<numTexCoords; i++)
|
||||
{
|
||||
picoVec2_t uv;
|
||||
uv[0] = GetFloat( pers );
|
||||
uv[1] = -GetFloat( pers ); /* ydnar: we use origin at bottom */
|
||||
|
||||
/* to make sure we don't mess up memory */
|
||||
if (pers->surface == NULL)
|
||||
continue;
|
||||
|
||||
/* add current uv */
|
||||
PicoSetSurfaceST( pers->surface,0,i,uv );
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("u: %f v: %f\n",uv[0],uv[1]);
|
||||
#endif
|
||||
}
|
||||
/* success (no errors occured) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetMeshShader (T3dsLoaderPers *pers)
|
||||
{
|
||||
char shaderName[255] = { 0 };
|
||||
picoShader_t *shader;
|
||||
int numSharedVerts;
|
||||
int setShaderName = 0;
|
||||
int i;
|
||||
|
||||
/* the shader is either the color or the texture map of the */
|
||||
/* object. it can also hold other information like the brightness, */
|
||||
/* shine, etc. stuff we don't really care about. we just want the */
|
||||
/* color, or the texture map file name really */
|
||||
|
||||
/* get in the shader name */
|
||||
if (!GetASCIIZ(pers,shaderName,sizeof(shaderName)))
|
||||
return 0;
|
||||
|
||||
/* ydnar: trim to first whitespace */
|
||||
_pico_first_token( shaderName );
|
||||
|
||||
/* now that we have the shader name we need to go through all of */
|
||||
/* the shaders and check the name against each shader. when we */
|
||||
/* find a shader in our shader list that matches this name we */
|
||||
/* just read in, then we assign the shader's id of the object to */
|
||||
/* that shader */
|
||||
|
||||
/* get shader id for shader name */
|
||||
shader = PicoFindShader( pers->model, shaderName, 1 );
|
||||
|
||||
/* we've found a matching shader */
|
||||
if ((shader != NULL) && pers->surface)
|
||||
{
|
||||
char mapName[1024+1];
|
||||
char *mapNamePtr;
|
||||
memset( mapName,0,sizeof(mapName) );
|
||||
|
||||
/* get ptr to shader's map name */
|
||||
mapNamePtr = PicoGetShaderMapName( shader );
|
||||
|
||||
/* we have a valid map name ptr */
|
||||
if (mapNamePtr != NULL)
|
||||
{
|
||||
char temp[128];
|
||||
const char *name;
|
||||
|
||||
/* copy map name to local buffer */
|
||||
strcpy( mapName,mapNamePtr );
|
||||
|
||||
/* extract file name */
|
||||
name = _pico_nopath( mapName );
|
||||
strncpy( temp, name, sizeof(temp) );
|
||||
|
||||
/* remove file extension */
|
||||
/* name = _pico_setfext( name,"" ); */
|
||||
|
||||
/* assign default name if no name available */
|
||||
if (strlen(temp) < 1)
|
||||
strcpy(temp,pers->basename);
|
||||
|
||||
/* build shader name */
|
||||
_pico_strlwr( temp ); /* gaynux update -sea */
|
||||
sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp );
|
||||
|
||||
/* set shader name */
|
||||
/* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */
|
||||
|
||||
/* set surface's shader index */
|
||||
PicoSetSurfaceShader( pers->surface, shader );
|
||||
|
||||
setShaderName = 1;
|
||||
}
|
||||
}
|
||||
/* we didn't set a shader name; throw out warning */
|
||||
if (!setShaderName)
|
||||
{
|
||||
_pico_printf( PICO_WARNING,"3DS mesh is missing shader name");
|
||||
}
|
||||
/* we don't process the list of shared vertices here; there is a */
|
||||
/* short int that gives the number of faces of the mesh concerned */
|
||||
/* by this shader, then there is the list itself of these faces. */
|
||||
/* 0000 means the first face of the (4120) face list */
|
||||
|
||||
/* get number of shared verts */
|
||||
numSharedVerts = GetWord(pers);
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts);
|
||||
#endif
|
||||
/* skip list of shared verts */
|
||||
for (i=0; i<numSharedVerts; i++)
|
||||
{
|
||||
GetWord(pers);
|
||||
}
|
||||
/* success (no errors occured) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetDiffuseColor (T3dsLoaderPers *pers)
|
||||
{
|
||||
/* todo: support all 3ds specific color formats; */
|
||||
/* that means: rgb,tru,trug,rgbg */
|
||||
|
||||
/* get rgb color (range 0..255; 3 bytes) */
|
||||
picoColor_t color;
|
||||
|
||||
color[0] = GetByte(pers);
|
||||
color[1] = GetByte(pers);
|
||||
color[2] = GetByte(pers);
|
||||
color[3] = 255;
|
||||
|
||||
/* store this as the current shader's diffuse color */
|
||||
if( pers->shader )
|
||||
{
|
||||
PicoSetShaderDiffuseColor( pers->shader,color );
|
||||
}
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("GetDiffuseColor: %d %d %d\n",color[0],color[1],color[2]);
|
||||
#endif
|
||||
/* success (no errors occured) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs)
|
||||
{
|
||||
T3dsChunk *chunk;
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("DoNextEditorDataChunk: endofs %d\n",endofs);
|
||||
#endif
|
||||
while (pers->cofs < endofs)
|
||||
{
|
||||
long nextofs = pers->cofs;
|
||||
if ((chunk = GetChunk(pers)) == NULL) return 0;
|
||||
if (!chunk->len) return 0;
|
||||
nextofs += chunk->len;
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs);
|
||||
#endif
|
||||
/*** meshes ***/
|
||||
if (chunk->id == CHUNK_OBJECT)
|
||||
{
|
||||
picoSurface_t *surface;
|
||||
char surfaceName[ 0xff ] = { 0 };
|
||||
|
||||
/* read in surface name */
|
||||
if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) )
|
||||
return 0; /* this is bad */
|
||||
|
||||
//PicoGetSurfaceName
|
||||
/* ignore NULL name surfaces */
|
||||
// if( surfaceName
|
||||
|
||||
/* allocate a pico surface */
|
||||
surface = PicoNewSurface( pers->model );
|
||||
if( surface == NULL )
|
||||
{
|
||||
pers->surface = NULL;
|
||||
return 0; /* this is bad too */
|
||||
}
|
||||
/* assign ptr to current surface */
|
||||
pers->surface = surface;
|
||||
|
||||
/* 3ds models surfaces are all triangle meshes */
|
||||
PicoSetSurfaceType( pers->surface,PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( pers->surface,surfaceName );
|
||||
|
||||
/* continue mess with object's sub chunks */
|
||||
DoNextEditorDataChunk(pers,nextofs);
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_OBJECT_MESH)
|
||||
{
|
||||
/* continue mess with mesh's sub chunks */
|
||||
if (!DoNextEditorDataChunk(pers,nextofs)) return 0;
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_OBJECT_VERTICES)
|
||||
{
|
||||
if (!GetMeshVertices(pers)) return 0;
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_OBJECT_FACES)
|
||||
{
|
||||
if (!GetMeshFaces(pers)) return 0;
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_OBJECT_UV)
|
||||
{
|
||||
if (!GetMeshTexCoords(pers)) return 0;
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_OBJECT_MATERIAL)
|
||||
{
|
||||
if (!GetMeshShader(pers)) return 0;
|
||||
continue;
|
||||
}
|
||||
/*** materials ***/
|
||||
if (chunk->id == CHUNK_MATERIAL)
|
||||
{
|
||||
/* new shader specific things should be */
|
||||
/* initialized right here */
|
||||
picoShader_t *shader;
|
||||
|
||||
/* allocate a pico shader */
|
||||
shader = PicoNewShader( pers->model ); /* ydnar */
|
||||
if( shader == NULL )
|
||||
{
|
||||
pers->shader = NULL;
|
||||
return 0; /* this is bad too */
|
||||
}
|
||||
|
||||
/* assign ptr to current shader */
|
||||
pers->shader = shader;
|
||||
|
||||
/* continue and process the material's sub chunks */
|
||||
DoNextEditorDataChunk(pers,nextofs);
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_MATNAME)
|
||||
{
|
||||
/* new material's names should be stored here. note that */
|
||||
/* GetMeshMaterial returns the name of the material that */
|
||||
/* is used by the mesh. new material names are set HERE. */
|
||||
/* but for now we skip the new material's name ... */
|
||||
if (pers->shader)
|
||||
{
|
||||
char *name = (char*) (pers->bufptr + pers->cofs);
|
||||
char *cleanedName = _pico_clone_alloc( name );
|
||||
_pico_first_token( cleanedName );
|
||||
PicoSetShaderName( pers->shader, cleanedName );
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf( "NewShader: '%s'\n", cleanedName );
|
||||
#endif
|
||||
_pico_free( cleanedName );
|
||||
}
|
||||
}
|
||||
if (chunk->id == CHUNK_MATDIFFUSE)
|
||||
{
|
||||
/* todo: color for last inserted new material should be */
|
||||
/* stored somewhere by GetDiffuseColor */
|
||||
if (!GetDiffuseColor(pers)) return 0;
|
||||
|
||||
/* rest of chunk is skipped here */
|
||||
}
|
||||
if (chunk->id == CHUNK_MATMAP)
|
||||
{
|
||||
/* continue and process the material map sub chunks */
|
||||
DoNextEditorDataChunk(pers,nextofs);
|
||||
continue;
|
||||
}
|
||||
if (chunk->id == CHUNK_MATMAPFILE)
|
||||
{
|
||||
/* map file name for last inserted new material should */
|
||||
/* be stored here. but for now we skip this too ... */
|
||||
if( pers->shader )
|
||||
{
|
||||
char *name = (char *)(pers->bufptr + pers->cofs);
|
||||
PicoSetShaderMapName( pers->shader,name );
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("NewShaderMapfile: '%s'\n",name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*** keyframes ***/
|
||||
if (chunk->id == CHUNK_KEYFRAME_DATA)
|
||||
{
|
||||
/* well umm, this is a bit too much since we don't really */
|
||||
/* need model animation sequences right now. we skip this */
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("KeyframeData: len %d\n",chunk->len);
|
||||
#endif
|
||||
}
|
||||
/* skip unknown chunk */
|
||||
pers->cofs = nextofs;
|
||||
if (pers->cofs >= pers->maxofs) break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int DoNextChunk (T3dsLoaderPers *pers, int endofs)
|
||||
{
|
||||
T3dsChunk *chunk;
|
||||
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("DoNextChunk: endofs %d\n",endofs);
|
||||
#endif
|
||||
while (pers->cofs < endofs)
|
||||
{
|
||||
long nextofs = pers->cofs;
|
||||
if ((chunk = GetChunk(pers)) == NULL) return 0;
|
||||
if (!chunk->len) return 0;
|
||||
nextofs += chunk->len;
|
||||
|
||||
#ifdef DEBUG_PM_3DS_EX
|
||||
printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs);
|
||||
#endif
|
||||
/*** version ***/
|
||||
if (chunk->id == CHUNK_VERSION)
|
||||
{
|
||||
/* at this point i get the 3ds file version. since there */
|
||||
/* might be new additions to the 3ds file format in 4.0 */
|
||||
/* it might be a good idea to store the version somewhere */
|
||||
/* for later handling or message displaying */
|
||||
|
||||
/* get the version */
|
||||
int version;
|
||||
version = GetWord(pers);
|
||||
GetWord(pers);
|
||||
#ifdef DEBUG_PM_3DS
|
||||
printf("FileVersion: %d\n",version);
|
||||
#endif
|
||||
|
||||
/* throw out a warning for version 4 models */
|
||||
if (version == 4)
|
||||
{
|
||||
_pico_printf( PICO_WARNING,
|
||||
"3DS version is 4. Model might load incorrectly.");
|
||||
}
|
||||
/* store the 3ds file version in pico special field 0 */
|
||||
/* PicoSetSurfaceSpecial(pers->surface,0,version); */ /* ydnar: this was causing a crash accessing uninitialized surface */
|
||||
|
||||
/* rest of chunk is skipped here */
|
||||
}
|
||||
/*** editor data ***/
|
||||
if (chunk->id == CHUNK_EDITOR_DATA)
|
||||
{
|
||||
if (!DoNextEditorDataChunk(pers,nextofs)) return 0;
|
||||
continue;
|
||||
}
|
||||
/* skip unknown chunk */
|
||||
pers->cofs = nextofs;
|
||||
if (pers->cofs >= pers->maxofs) break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* _3ds_load:
|
||||
* loads an autodesk 3ds model file.
|
||||
*/
|
||||
static picoModel_t *_3ds_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
T3dsLoaderPers pers;
|
||||
picoModel_t *model;
|
||||
char basename[128];
|
||||
|
||||
/* create a new pico model */
|
||||
model = PicoNewModel();
|
||||
if (model == NULL)
|
||||
{
|
||||
/* user must have some serious ram problems ;) */
|
||||
return NULL;
|
||||
}
|
||||
/* get model's base name (eg. jeep from c:\models\jeep.3ds) */
|
||||
memset( basename,0,sizeof(basename) );
|
||||
strncpy( basename,_pico_nopath(fileName),sizeof(basename) );
|
||||
_pico_setfext( basename,"" );
|
||||
|
||||
/* initialize persistant vars (formerly static) */
|
||||
pers.model = model;
|
||||
pers.bufptr = (picoByte_t *)buffer;
|
||||
pers.basename = (char *)basename;
|
||||
pers.maxofs = bufSize;
|
||||
pers.cofs = 0L;
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( model,frameNum );
|
||||
PicoSetModelName( model,fileName );
|
||||
PicoSetModelFileName( model,fileName );
|
||||
|
||||
/* skip first chunk in file (magic) */
|
||||
GetChunk(&pers);
|
||||
|
||||
/* process chunks */
|
||||
if (!DoNextChunk(&pers,pers.maxofs))
|
||||
{
|
||||
/* well, bleh i guess */
|
||||
PicoFreeModel(model);
|
||||
return NULL;
|
||||
}
|
||||
/* return allocated pico model */
|
||||
return model;
|
||||
}
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModule3DS =
|
||||
{
|
||||
"0.86-b", /* module version string */
|
||||
"Autodesk 3Dstudio", /* module display name */
|
||||
"seaw0lf", /* author's name */
|
||||
"2002 seaw0lf", /* module copyright */
|
||||
{
|
||||
"3ds",NULL,NULL,NULL /* default extensions to use */
|
||||
},
|
||||
_3ds_canload, /* validation routine */
|
||||
_3ds_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
1211
libs/picomodel/pm_ase.c
Normal file
1211
libs/picomodel/pm_ase.c
Normal file
File diff suppressed because it is too large
Load Diff
667
libs/picomodel/pm_fm.c
Normal file
667
libs/picomodel/pm_fm.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Nurail: Used pm_md3.c (Randy Reddig) as a template.
|
||||
*/
|
||||
|
||||
/* marker */
|
||||
#define PM_FM_C
|
||||
|
||||
/* dependencies */
|
||||
#include "pm_fm.h"
|
||||
|
||||
//#define FM_VERBOSE_DBG 0
|
||||
#undef FM_VERBOSE_DBG
|
||||
#undef FM_DBG
|
||||
|
||||
typedef struct index_LUT_s
|
||||
{
|
||||
short Vert;
|
||||
short ST;
|
||||
struct index_LUT_s *next;
|
||||
|
||||
} index_LUT_t;
|
||||
|
||||
typedef struct index_DUP_LUT_s
|
||||
{
|
||||
short ST;
|
||||
short OldVert;
|
||||
|
||||
} index_DUP_LUT_t;
|
||||
|
||||
|
||||
// _fm_canload()
|
||||
static int _fm_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
fm_t fm;
|
||||
unsigned char *bb;
|
||||
int fm_file_pos;
|
||||
|
||||
bb = (unsigned char *) buffer;
|
||||
|
||||
// Header
|
||||
fm.fm_header_hdr = (fm_chunk_header_t *) bb;
|
||||
fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
|
||||
#endif
|
||||
if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
// check fm
|
||||
if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
|
||||
// Skin
|
||||
fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );
|
||||
#endif
|
||||
if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
// check fm
|
||||
if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
|
||||
// st
|
||||
fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
|
||||
#endif
|
||||
if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
// check fm
|
||||
if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
|
||||
// tri
|
||||
fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
|
||||
#endif
|
||||
if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
// check fm
|
||||
if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
|
||||
// frame
|
||||
fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
|
||||
#endif
|
||||
if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
// check fm
|
||||
if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
|
||||
{
|
||||
#ifdef FM_DBG
|
||||
_pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
|
||||
#endif
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
|
||||
// file seems to be a valid fm
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// _fm_load() loads a Heretic 2 model file.
|
||||
static picoModel_t *_fm_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
int i, j, dups, dup_index;
|
||||
int fm_file_pos;
|
||||
short tot_numVerts;
|
||||
index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
|
||||
index_DUP_LUT_t *p_index_LUT_DUPS;
|
||||
|
||||
fm_vert_normal_t *vert;
|
||||
|
||||
char skinname[FM_SKINPATHSIZE];
|
||||
fm_t fm;
|
||||
fm_header_t *fm_head;
|
||||
fm_st_t *texCoord;
|
||||
fm_xyz_st_t *tri_verts;
|
||||
fm_xyz_st_t *triangle;
|
||||
fm_frame_t *frame;
|
||||
|
||||
picoByte_t *bb;
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
|
||||
bb = (picoByte_t*) buffer;
|
||||
|
||||
// Header Header
|
||||
fm.fm_header_hdr = (fm_chunk_header_t *) bb;
|
||||
fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
|
||||
if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Skin Header
|
||||
fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
|
||||
if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ST Header
|
||||
fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
|
||||
if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Tris Header
|
||||
fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
|
||||
if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Frame Header
|
||||
fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Header
|
||||
fm_file_pos = sizeof(fm_chunk_header_t);
|
||||
fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += fm.fm_header_hdr->size;
|
||||
|
||||
// Skin
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += fm.fm_skin_hdr->size;
|
||||
|
||||
// ST
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += fm.fm_st_hdr->size;
|
||||
|
||||
// Tri
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);
|
||||
fm_file_pos += fm.fm_tri_hdr->size;
|
||||
|
||||
// Frame
|
||||
fm_file_pos += sizeof(fm_chunk_header_t);
|
||||
frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);
|
||||
|
||||
// do frame check
|
||||
if( fm_head->numFrames < 1 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( frameNum < 0 || frameNum >= fm_head->numFrames )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// swap fm
|
||||
fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
|
||||
fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
|
||||
fm_head->frameSize = _pico_little_long( fm_head->frameSize );
|
||||
|
||||
fm_head->numSkins = _pico_little_long( fm_head->numSkins );
|
||||
fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
|
||||
fm_head->numST = _pico_little_long( fm_head->numST );
|
||||
fm_head->numTris = _pico_little_long( fm_head->numTris );
|
||||
fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
|
||||
fm_head->numFrames = _pico_little_long( fm_head->numFrames );
|
||||
|
||||
// swap frame scale and translation
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
|
||||
frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
|
||||
}
|
||||
|
||||
// swap triangles
|
||||
triangle = tri_verts;
|
||||
for( i = 0; i < fm_head->numTris; i++, triangle++ )
|
||||
{
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
|
||||
triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
|
||||
}
|
||||
}
|
||||
|
||||
// swap st coords
|
||||
for( i = 0; i < fm_head->numST; i++ )
|
||||
{
|
||||
texCoord->s = _pico_little_short( texCoord[i].s );
|
||||
texCoord->t = _pico_little_short( texCoord[i].t );
|
||||
}
|
||||
// set Skin Name
|
||||
strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE );
|
||||
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
// Print out md2 values
|
||||
_pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname );
|
||||
#endif
|
||||
|
||||
// detox Skin name
|
||||
_pico_setfext( skinname, "" );
|
||||
_pico_unixify( skinname );
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if( picoModel == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
// allocate new pico surface
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if( picoSurface == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
PicoSetSurfaceName( picoSurface, frame->header.name );
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if( picoShader == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PicoSetShaderName( picoShader, skinname );
|
||||
|
||||
// associate current surface with newly created shader
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
// Init LUT for Verts
|
||||
p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ);
|
||||
for(i=0; i<fm_head->numXYZ; i++)
|
||||
{
|
||||
p_index_LUT[i].Vert = -1;
|
||||
p_index_LUT[i].ST = -1;
|
||||
p_index_LUT[i].next = NULL;
|
||||
}
|
||||
|
||||
// Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
|
||||
tot_numVerts = fm_head->numXYZ;
|
||||
dups = 0;
|
||||
triangle = tri_verts;
|
||||
|
||||
for(i=0; i<fm_head->numTris; i++)
|
||||
{
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry
|
||||
p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
|
||||
|
||||
else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
|
||||
{
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry
|
||||
{ // Add first entry of LL from Main
|
||||
p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
|
||||
if (p_index_LUT2 == NULL)
|
||||
_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
|
||||
p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
|
||||
p_index_LUT2->Vert = dups;
|
||||
p_index_LUT2->ST = triangle->index_st[j];
|
||||
p_index_LUT2->next = NULL;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);
|
||||
#endif
|
||||
triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
|
||||
dups++;
|
||||
}
|
||||
else // Try to find in LL from Main Entry
|
||||
{
|
||||
p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
|
||||
while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
|
||||
{
|
||||
p_index_LUT3 = p_index_LUT2;
|
||||
p_index_LUT2 = p_index_LUT2->next;
|
||||
}
|
||||
p_index_LUT2 = p_index_LUT3;
|
||||
|
||||
if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
|
||||
{
|
||||
triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL.
|
||||
{
|
||||
// Add the Entry
|
||||
p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
|
||||
if (p_index_LUT3 == NULL)
|
||||
_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
|
||||
p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
|
||||
p_index_LUT3->Vert = dups;
|
||||
p_index_LUT3->ST = triangle->index_st[j];
|
||||
p_index_LUT3->next = NULL;
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]);
|
||||
#endif
|
||||
triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
|
||||
dups++;
|
||||
}
|
||||
}
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
|
||||
#endif
|
||||
}
|
||||
triangle++;
|
||||
}
|
||||
|
||||
// malloc and build array for Dup STs
|
||||
p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
|
||||
if (p_index_LUT_DUPS == NULL)
|
||||
_pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
|
||||
|
||||
dup_index = 0;
|
||||
for(i=0; i<fm_head->numXYZ; i++)
|
||||
{
|
||||
p_index_LUT2 = p_index_LUT[i].next;
|
||||
while (p_index_LUT2 != NULL)
|
||||
{
|
||||
p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
|
||||
p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
|
||||
dup_index++;
|
||||
p_index_LUT2 = p_index_LUT2->next;
|
||||
}
|
||||
}
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, " Dups = %d\n", dups);
|
||||
_pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);
|
||||
#endif
|
||||
for(i=0; i<fm_head->numXYZ; i++)
|
||||
{
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
|
||||
#endif
|
||||
if (p_index_LUT[i].next != NULL)
|
||||
{
|
||||
|
||||
p_index_LUT2 = p_index_LUT[i].next;
|
||||
do {
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
|
||||
#endif
|
||||
p_index_LUT2 = p_index_LUT2->next;
|
||||
} while ( p_index_LUT2 != NULL);
|
||||
|
||||
}
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
_pico_printf( PICO_NORMAL, "\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef FM_VERBOSE_DBG
|
||||
for(i=0; i<dup_index; i++)
|
||||
_pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST);
|
||||
|
||||
triangle = tri_verts;
|
||||
for(i=0; i<fm_head->numTris; i++)
|
||||
{
|
||||
for(j=0; j<3; j++)
|
||||
_pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
|
||||
_pico_printf( PICO_NORMAL, "\n");
|
||||
triangle++;
|
||||
}
|
||||
#endif
|
||||
// Build Picomodel
|
||||
triangle = tri_verts;
|
||||
for( j = 0; j < fm_head->numTris; j++, triangle++ )
|
||||
{
|
||||
PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] );
|
||||
PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
|
||||
PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
|
||||
}
|
||||
|
||||
vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
|
||||
for(i=0; i< fm_head->numXYZ; i++, vert++)
|
||||
{
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
|
||||
xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
|
||||
xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
|
||||
PicoSetSurfaceXYZ( picoSurface, i , xyz );
|
||||
|
||||
/* set normal */
|
||||
normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
|
||||
normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
|
||||
normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
|
||||
PicoSetSurfaceNormal( picoSurface, i , normal );
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));
|
||||
st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight));
|
||||
PicoSetSurfaceST( picoSurface, 0, i , st );
|
||||
}
|
||||
|
||||
if (dups)
|
||||
{
|
||||
for(i=0; i<dups; i++)
|
||||
{
|
||||
j = p_index_LUT_DUPS[i].OldVert;
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
|
||||
xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
|
||||
xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
|
||||
PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );
|
||||
|
||||
/* set normal */
|
||||
normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
|
||||
normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
|
||||
normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
|
||||
PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));
|
||||
st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));
|
||||
PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st );
|
||||
}
|
||||
}
|
||||
|
||||
/* set color */
|
||||
PicoSetSurfaceColor( picoSurface, 0, 0, color );
|
||||
|
||||
// Free up malloc'ed LL entries
|
||||
for(i=0; i<fm_head->numXYZ; i++)
|
||||
{
|
||||
if(p_index_LUT[i].next != NULL)
|
||||
{
|
||||
p_index_LUT2 = p_index_LUT[i].next;
|
||||
do {
|
||||
p_index_LUT3 = p_index_LUT2->next;
|
||||
_pico_free(p_index_LUT2);
|
||||
p_index_LUT2 = p_index_LUT3;
|
||||
dups--;
|
||||
} while (p_index_LUT2 != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (dups)
|
||||
_pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
|
||||
|
||||
// Free malloc'ed LUTs
|
||||
_pico_free(p_index_LUT);
|
||||
_pico_free(p_index_LUT_DUPS);
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleFM =
|
||||
{
|
||||
"0.85", /* module version string */
|
||||
"Heretic 2 FM", /* module display name */
|
||||
"Nurail", /* author's name */
|
||||
"2003 Nurail", /* module copyright */
|
||||
{
|
||||
"fm", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_fm_canload, /* validation routine */
|
||||
_fm_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
367
libs/picomodel/pm_fm.h
Normal file
367
libs/picomodel/pm_fm.h
Normal file
@@ -0,0 +1,367 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
// This header file is based from the following:
|
||||
|
||||
/*
|
||||
FlexModel.H - Header file for FlexModel file structure
|
||||
|
||||
By Chris Burke
|
||||
serotonin@earthlink.net
|
||||
*/
|
||||
|
||||
#ifndef __PM_FM_H__
|
||||
#define __PM_FM_H__
|
||||
|
||||
#include "picointernal.h"
|
||||
|
||||
|
||||
//
|
||||
// Absolute limits (from QData / QMView source)
|
||||
//
|
||||
#define MAX_FM_TRIANGLES 2048
|
||||
#define MAX_FM_VERTS 2048
|
||||
#define MAX_FM_FRAMES 2048
|
||||
#define MAX_FM_SKINS 64
|
||||
#define MAX_FM_SKINNAME 64
|
||||
#define MAX_FM_MESH_NODES 16
|
||||
|
||||
#define DTRIVERTX_V0 0
|
||||
#define DTRIVERTX_V1 1
|
||||
#define DTRIVERTX_V2 2
|
||||
#define DTRIVERTX_LNI 3
|
||||
#define DTRIVERTX_SIZE 4
|
||||
|
||||
#define SKINPAGE_WIDTH 640
|
||||
#define SKINPAGE_HEIGHT 480
|
||||
|
||||
#define ENCODED_WIDTH_X 92
|
||||
#define ENCODED_WIDTH_Y 475
|
||||
#define ENCODED_HEIGHT_X 128
|
||||
#define ENCODED_HEIGHT_Y 475
|
||||
|
||||
#define SCALE_ADJUST_FACTOR 0.96
|
||||
|
||||
#define INFO_HEIGHT 5
|
||||
#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT)
|
||||
|
||||
#ifndef byte
|
||||
#define byte unsigned char
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Generic header on every chunk
|
||||
//
|
||||
#define FM_MAXCHUNKIDENT 32L
|
||||
typedef struct
|
||||
{
|
||||
char ident[FM_MAXCHUNKIDENT];
|
||||
unsigned int version;
|
||||
unsigned int size;
|
||||
} fm_chunk_header_t;
|
||||
|
||||
//
|
||||
// The format of the "header" chunk
|
||||
//
|
||||
#define FM_HEADERCHUNKNAME "header"
|
||||
#define FM_HEADERCHUNKVER 2
|
||||
#define FM_HEADERCHUNKSIZE 40
|
||||
typedef struct
|
||||
{
|
||||
int skinWidth; // in pixels
|
||||
int skinHeight; // in pixels
|
||||
int frameSize; // size of each frame (in bytes)
|
||||
int numSkins; // number of skins
|
||||
int numXYZ; // number of unique vertices in 3D space
|
||||
int numST; // number of unique vertices in texture space
|
||||
int numTris; // number of unique triangles
|
||||
int numGLCmds; // # 32-bit elements in strip/fan command list
|
||||
int numFrames; // number of animation frames
|
||||
int numMeshNodes; // number of mesh nodes
|
||||
} fm_header_t;
|
||||
|
||||
//
|
||||
// The format of an entry in the "skin" chunk.
|
||||
// The number of entries is given in the fmheader chunk
|
||||
//
|
||||
#define FM_SKINCHUNKNAME "skin"
|
||||
#define FM_SKINCHUNKVER 1
|
||||
#define FM_MAXPATHLENGTH 64L
|
||||
#define FM_SKINPATHSIZE (FM_MAXPATHLENGTH)
|
||||
typedef struct
|
||||
{
|
||||
char path[FM_SKINPATHSIZE]; // path, relative to 'base'
|
||||
} fm_skinpath_t;
|
||||
|
||||
//
|
||||
// The format of the "st coord" chunk. This is a list
|
||||
// of unique skin texture (u, v) coordinates to be mapped
|
||||
// to verteces of the model
|
||||
//
|
||||
#define FM_STCOORDCHUNKNAME "st coord"
|
||||
#define FM_STCOORDCHUNKVER 1
|
||||
#define FM_STCOORDUVSIZE (2L + 2L)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short s;
|
||||
short t;
|
||||
} fm_st_t;
|
||||
|
||||
//
|
||||
// The format of the "tris" chunk. This is a list of vertex indeces
|
||||
// in 3D space, and the corresponding vertex indeces in texture space.
|
||||
//
|
||||
#define FM_TRISCHUNKNAME "tris"
|
||||
#define FM_TRISCHUNKVER 1
|
||||
#define FM_TRISINFOSIZE (2L*3 + 2L*3)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3];
|
||||
short index_st[3];
|
||||
} fm_xyz_st_t;
|
||||
|
||||
|
||||
//
|
||||
// The format of the "frames" chunk. This is a list of animation
|
||||
// frames, each specifying the coordinates and "light normal" index
|
||||
// of every vertex of the model in 3D space.
|
||||
//
|
||||
#define FM_FRAMESCHUNKNAME "frames"
|
||||
#define FM_FRAMESCHUNKVER 1
|
||||
|
||||
#define FM_NUMVERTEXNORMALS 162
|
||||
|
||||
// Frame info
|
||||
typedef struct
|
||||
{
|
||||
byte v[3]; // scaled by header info
|
||||
byte lightnormalindex; // index in canned table of closest vertex normal
|
||||
} fm_vert_normal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float scale[3]; // multiply byte verts by this
|
||||
float translate[3]; // then add this
|
||||
char name[16]; // frame name
|
||||
} fm_framehdr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fm_framehdr_t header; // One header per frame
|
||||
fm_vert_normal_t verts[1]; // variable number of these
|
||||
} fm_frame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fm_chunk_header_t *fm_header_hdr;
|
||||
fm_header_t *fm_header;
|
||||
fm_chunk_header_t *fm_skin_hdr;
|
||||
fm_skinpath_t *fm_skin;
|
||||
fm_chunk_header_t *fm_st_hdr;
|
||||
fm_st_t *fm_st;
|
||||
fm_chunk_header_t *fm_tri_hdr;
|
||||
fm_xyz_st_t *fm_tri;
|
||||
fm_chunk_header_t *fm_frame_hdr;
|
||||
fm_frame_t *fm_frame;
|
||||
} fm_t;
|
||||
|
||||
float fm_normals[FM_NUMVERTEXNORMALS][3] = {
|
||||
{-0.525731f, 0.000000f, 0.850651f},
|
||||
{-0.442863f, 0.238856f, 0.864188f},
|
||||
{-0.295242f, 0.000000f, 0.955423f},
|
||||
{-0.309017f, 0.500000f, 0.809017f},
|
||||
{-0.162460f, 0.262866f, 0.951056f},
|
||||
{0.000000f, 0.000000f, 1.000000f},
|
||||
{0.000000f, 0.850651f, 0.525731f},
|
||||
{-0.147621f, 0.716567f, 0.681718f},
|
||||
{0.147621f, 0.716567f, 0.681718f},
|
||||
{0.000000f, 0.525731f, 0.850651f},
|
||||
{0.309017f, 0.500000f, 0.809017f},
|
||||
{0.525731f, 0.000000f, 0.850651f},
|
||||
{0.295242f, 0.000000f, 0.955423f},
|
||||
{0.442863f, 0.238856f, 0.864188f},
|
||||
{0.162460f, 0.262866f, 0.951056f},
|
||||
{-0.681718f, 0.147621f, 0.716567f},
|
||||
{-0.809017f, 0.309017f, 0.500000f},
|
||||
{-0.587785f, 0.425325f, 0.688191f},
|
||||
{-0.850651f, 0.525731f, 0.000000f},
|
||||
{-0.864188f, 0.442863f, 0.238856f},
|
||||
{-0.716567f, 0.681718f, 0.147621f},
|
||||
{-0.688191f, 0.587785f, 0.425325f},
|
||||
{-0.500000f, 0.809017f, 0.309017f},
|
||||
{-0.238856f, 0.864188f, 0.442863f},
|
||||
{-0.425325f, 0.688191f, 0.587785f},
|
||||
{-0.716567f, 0.681718f, -0.147621f},
|
||||
{-0.500000f, 0.809017f, -0.309017f},
|
||||
{-0.525731f, 0.850651f, 0.000000f},
|
||||
{0.000000f, 0.850651f, -0.525731f},
|
||||
{-0.238856f, 0.864188f, -0.442863f},
|
||||
{0.000000f, 0.955423f, -0.295242f},
|
||||
{-0.262866f, 0.951056f, -0.162460f},
|
||||
{0.000000f, 1.000000f, 0.000000f},
|
||||
{0.000000f, 0.955423f, 0.295242f},
|
||||
{-0.262866f, 0.951056f, 0.162460f},
|
||||
{0.238856f, 0.864188f, 0.442863f},
|
||||
{0.262866f, 0.951056f, 0.162460f},
|
||||
{0.500000f, 0.809017f, 0.309017f},
|
||||
{0.238856f, 0.864188f, -0.442863f},
|
||||
{0.262866f, 0.951056f, -0.162460f},
|
||||
{0.500000f, 0.809017f, -0.309017f},
|
||||
{0.850651f, 0.525731f, 0.000000f},
|
||||
{0.716567f, 0.681718f, 0.147621f},
|
||||
{0.716567f, 0.681718f, -0.147621f},
|
||||
{0.525731f, 0.850651f, 0.000000f},
|
||||
{0.425325f, 0.688191f, 0.587785f},
|
||||
{0.864188f, 0.442863f, 0.238856f},
|
||||
{0.688191f, 0.587785f, 0.425325f},
|
||||
{0.809017f, 0.309017f, 0.500000f},
|
||||
{0.681718f, 0.147621f, 0.716567f},
|
||||
{0.587785f, 0.425325f, 0.688191f},
|
||||
{0.955423f, 0.295242f, 0.000000f},
|
||||
{1.000000f, 0.000000f, 0.000000f},
|
||||
{0.951056f, 0.162460f, 0.262866f},
|
||||
{0.850651f, -0.525731f, 0.000000f},
|
||||
{0.955423f, -0.295242f, 0.000000f},
|
||||
{0.864188f, -0.442863f, 0.238856f},
|
||||
{0.951056f, -0.162460f, 0.262866f},
|
||||
{0.809017f, -0.309017f, 0.500000f},
|
||||
{0.681718f, -0.147621f, 0.716567f},
|
||||
{0.850651f, 0.000000f, 0.525731f},
|
||||
{0.864188f, 0.442863f, -0.238856f},
|
||||
{0.809017f, 0.309017f, -0.500000f},
|
||||
{0.951056f, 0.162460f, -0.262866f},
|
||||
{0.525731f, 0.000000f, -0.850651f},
|
||||
{0.681718f, 0.147621f, -0.716567f},
|
||||
{0.681718f, -0.147621f, -0.716567f},
|
||||
{0.850651f, 0.000000f, -0.525731f},
|
||||
{0.809017f, -0.309017f, -0.500000f},
|
||||
{0.864188f, -0.442863f, -0.238856f},
|
||||
{0.951056f, -0.162460f, -0.262866f},
|
||||
{0.147621f, 0.716567f, -0.681718f},
|
||||
{0.309017f, 0.500000f, -0.809017f},
|
||||
{0.425325f, 0.688191f, -0.587785f},
|
||||
{0.442863f, 0.238856f, -0.864188f},
|
||||
{0.587785f, 0.425325f, -0.688191f},
|
||||
{0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.147621f, 0.716567f, -0.681718f},
|
||||
{-0.309017f, 0.500000f, -0.809017f},
|
||||
{0.000000f, 0.525731f, -0.850651f},
|
||||
{-0.525731f, 0.000000f, -0.850651f},
|
||||
{-0.442863f, 0.238856f, -0.864188f},
|
||||
{-0.295242f, 0.000000f, -0.955423f},
|
||||
{-0.162460f, 0.262866f, -0.951056f},
|
||||
{0.000000f, 0.000000f, -1.000000f},
|
||||
{0.295242f, 0.000000f, -0.955423f},
|
||||
{0.162460f, 0.262866f, -0.951056f},
|
||||
{-0.442863f, -0.238856f, -0.864188f},
|
||||
{-0.309017f, -0.500000f, -0.809017f},
|
||||
{-0.162460f, -0.262866f, -0.951056f},
|
||||
{0.000000f, -0.850651f, -0.525731f},
|
||||
{-0.147621f, -0.716567f, -0.681718f},
|
||||
{0.147621f, -0.716567f, -0.681718f},
|
||||
{0.000000f, -0.525731f, -0.850651f},
|
||||
{0.309017f, -0.500000f, -0.809017f},
|
||||
{0.442863f, -0.238856f, -0.864188f},
|
||||
{0.162460f, -0.262866f, -0.951056f},
|
||||
{0.238856f, -0.864188f, -0.442863f},
|
||||
{0.500000f, -0.809017f, -0.309017f},
|
||||
{0.425325f, -0.688191f, -0.587785f},
|
||||
{0.716567f, -0.681718f, -0.147621f},
|
||||
{0.688191f, -0.587785f, -0.425325f},
|
||||
{0.587785f, -0.425325f, -0.688191f},
|
||||
{0.000000f, -0.955423f, -0.295242f},
|
||||
{0.000000f, -1.000000f, 0.000000f},
|
||||
{0.262866f, -0.951056f, -0.162460f},
|
||||
{0.000000f, -0.850651f, 0.525731f},
|
||||
{0.000000f, -0.955423f, 0.295242f},
|
||||
{0.238856f, -0.864188f, 0.442863f},
|
||||
{0.262866f, -0.951056f, 0.162460f},
|
||||
{0.500000f, -0.809017f, 0.309017f},
|
||||
{0.716567f, -0.681718f, 0.147621f},
|
||||
{0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.238856f, -0.864188f, -0.442863f},
|
||||
{-0.500000f, -0.809017f, -0.309017f},
|
||||
{-0.262866f, -0.951056f, -0.162460f},
|
||||
{-0.850651f, -0.525731f, 0.000000f},
|
||||
{-0.716567f, -0.681718f, -0.147621f},
|
||||
{-0.716567f, -0.681718f, 0.147621f},
|
||||
{-0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.500000f, -0.809017f, 0.309017f},
|
||||
{-0.238856f, -0.864188f, 0.442863f},
|
||||
{-0.262866f, -0.951056f, 0.162460f},
|
||||
{-0.864188f, -0.442863f, 0.238856f},
|
||||
{-0.809017f, -0.309017f, 0.500000f},
|
||||
{-0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.681718f, -0.147621f, 0.716567f},
|
||||
{-0.442863f, -0.238856f, 0.864188f},
|
||||
{-0.587785f, -0.425325f, 0.688191f},
|
||||
{-0.309017f, -0.500000f, 0.809017f},
|
||||
{-0.147621f, -0.716567f, 0.681718f},
|
||||
{-0.425325f, -0.688191f, 0.587785f},
|
||||
{-0.162460f, -0.262866f, 0.951056f},
|
||||
{0.442863f, -0.238856f, 0.864188f},
|
||||
{0.162460f, -0.262866f, 0.951056f},
|
||||
{0.309017f, -0.500000f, 0.809017f},
|
||||
{0.147621f, -0.716567f, 0.681718f},
|
||||
{0.000000f, -0.525731f, 0.850651f},
|
||||
{0.425325f, -0.688191f, 0.587785f},
|
||||
{0.587785f, -0.425325f, 0.688191f},
|
||||
{0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.955423f, 0.295242f, 0.000000f},
|
||||
{-0.951056f, 0.162460f, 0.262866f},
|
||||
{-1.000000f, 0.000000f, 0.000000f},
|
||||
{-0.850651f, 0.000000f, 0.525731f},
|
||||
{-0.955423f, -0.295242f, 0.000000f},
|
||||
{-0.951056f, -0.162460f, 0.262866f},
|
||||
{-0.864188f, 0.442863f, -0.238856f},
|
||||
{-0.951056f, 0.162460f, -0.262866f},
|
||||
{-0.809017f, 0.309017f, -0.500000f},
|
||||
{-0.864188f, -0.442863f, -0.238856f},
|
||||
{-0.951056f, -0.162460f, -0.262866f},
|
||||
{-0.809017f, -0.309017f, -0.500000f},
|
||||
{-0.681718f, 0.147621f, -0.716567f},
|
||||
{-0.681718f, -0.147621f, -0.716567f},
|
||||
{-0.850651f, 0.000000f, -0.525731f},
|
||||
{-0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.587785f, 0.425325f, -0.688191f},
|
||||
{-0.425325f, 0.688191f, -0.587785f},
|
||||
{-0.425325f, -0.688191f, -0.587785f},
|
||||
{-0.587785f, -0.425325f, -0.688191f},
|
||||
{-0.688191f, -0.587785f, -0.425325f},
|
||||
};
|
||||
|
||||
#endif
|
||||
445
libs/picomodel/pm_lwo.c
Normal file
445
libs/picomodel/pm_lwo.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/* marker */
|
||||
#define PM_LWO_C
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
#include "lwo/lwo2.h"
|
||||
|
||||
/* uncomment when debugging this module */
|
||||
/*#define DEBUG_PM_LWO*/
|
||||
|
||||
#ifdef DEBUG_PM_LWO
|
||||
#include "time.h"
|
||||
#endif
|
||||
|
||||
/* helper functions */
|
||||
static const char *lwo_lwIDToStr( unsigned int lwID )
|
||||
{
|
||||
static char lwIDStr[5];
|
||||
|
||||
if (!lwID)
|
||||
{
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
lwIDStr[ 0 ] = (char)((lwID) >> 24);
|
||||
lwIDStr[ 1 ] = (char)((lwID) >> 16);
|
||||
lwIDStr[ 2 ] = (char)((lwID) >> 8);
|
||||
lwIDStr[ 3 ] = (char)((lwID));
|
||||
lwIDStr[ 4 ] = '\0';
|
||||
|
||||
return lwIDStr;
|
||||
}
|
||||
|
||||
/*
|
||||
_lwo_canload()
|
||||
validates a LightWave Object model file. btw, i use the
|
||||
preceding underscore cause it's a static func referenced
|
||||
by one structure only.
|
||||
*/
|
||||
static int _lwo_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
picoMemStream_t *s;
|
||||
unsigned int failID = 0;
|
||||
int failpos = -1;
|
||||
int ret;
|
||||
|
||||
/* create a new pico memorystream */
|
||||
s = _pico_new_memstream( (picoByte_t *)buffer, bufSize );
|
||||
if (s == NULL)
|
||||
{
|
||||
return PICO_PMV_ERROR_MEMORY;
|
||||
}
|
||||
|
||||
ret = lwValidateObject( fileName, s, &failID, &failpos );
|
||||
|
||||
_pico_free_memstream( s );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
_lwo_load()
|
||||
loads a LightWave Object model file.
|
||||
*/
|
||||
static picoModel_t *_lwo_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
picoMemStream_t *s;
|
||||
unsigned int failID = 0;
|
||||
int failpos = -1;
|
||||
lwObject *obj;
|
||||
lwSurface *surface;
|
||||
lwLayer *layer;
|
||||
lwPoint *pt;
|
||||
lwPolygon *pol;
|
||||
lwPolVert *v;
|
||||
lwVMapPt *vm;
|
||||
char name[ 256 ];
|
||||
int i, j, k, numverts;
|
||||
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
int defaultSTAxis[ 2 ];
|
||||
picoVec2_t defaultXYZtoSTScale;
|
||||
|
||||
picoVertexCombinationHash_t **hashTable;
|
||||
picoVertexCombinationHash_t *vertexCombinationHash;
|
||||
|
||||
#ifdef DEBUG_PM_LWO
|
||||
clock_t load_start, load_finish, convert_start, convert_finish;
|
||||
double load_elapsed, convert_elapsed;
|
||||
|
||||
load_start = clock();
|
||||
#endif
|
||||
|
||||
/* do frame check */
|
||||
if( frameNum < 0 || frameNum >= 1 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create a new pico memorystream */
|
||||
s = _pico_new_memstream( (picoByte_t *)buffer, bufSize );
|
||||
if (s == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = lwGetObject( fileName, s, &failID, &failpos );
|
||||
|
||||
_pico_free_memstream( s );
|
||||
|
||||
if( !obj ) {
|
||||
_pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PM_LWO
|
||||
convert_start = load_finish = clock();
|
||||
load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC;
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------
|
||||
pico model creation
|
||||
------------------------------------------------- */
|
||||
|
||||
/* create a new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if (picoModel == NULL)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, 1 );
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
/* create all polygons from layer[ 0 ] that belong to this surface */
|
||||
layer = &obj->layer[0];
|
||||
|
||||
/* warn the user that other layers are discarded */
|
||||
if (obj->nlayers > 1)
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers );
|
||||
}
|
||||
|
||||
/* initialize dummy normal */
|
||||
normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f;
|
||||
|
||||
/* setup default st map */
|
||||
st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */
|
||||
defaultSTAxis[ 0 ] = 0;
|
||||
defaultSTAxis[ 1 ] = 1;
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
float min = layer->bbox[ i ];
|
||||
float max = layer->bbox[ i + 3 ];
|
||||
float size = max - min;
|
||||
|
||||
if (size > st[ 0 ])
|
||||
{
|
||||
defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ];
|
||||
defaultSTAxis[ 0 ] = i;
|
||||
|
||||
st[ 1 ] = st[ 0 ];
|
||||
st[ 0 ] = size;
|
||||
}
|
||||
else if (size > st[ 1 ])
|
||||
{
|
||||
defaultSTAxis[ 1 ] = i;
|
||||
st[ 1 ] = size;
|
||||
}
|
||||
}
|
||||
defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ];
|
||||
defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ];
|
||||
|
||||
/* LWO surfaces become pico surfaces */
|
||||
surface = obj->surf;
|
||||
while (surface)
|
||||
{
|
||||
/* allocate new pico surface */
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if (picoSurface == NULL)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel );
|
||||
lwFreeObject( obj );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* LWO model surfaces are all triangle meshes */
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( picoSurface, surface->name );
|
||||
|
||||
/* create new pico shader */
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if (picoShader == NULL)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
lwFreeObject( obj );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detox and set shader name */
|
||||
strncpy( name, surface->name, sizeof(name) );
|
||||
_pico_first_token( name );
|
||||
_pico_setfext( name, "" );
|
||||
_pico_unixify( name );
|
||||
PicoSetShaderName( picoShader, name );
|
||||
|
||||
/* associate current surface with newly created shader */
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
/* copy indices and vertex data */
|
||||
numverts = 0;
|
||||
|
||||
hashTable = PicoNewVertexCombinationHashTable();
|
||||
|
||||
if (hashTable == NULL)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate hash table" );
|
||||
PicoFreeModel( picoModel );
|
||||
lwFreeObject( obj );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ )
|
||||
{
|
||||
/* does this polygon belong to this surface? */
|
||||
if (pol->surf != surface)
|
||||
continue;
|
||||
|
||||
/* we only support polygons of the FACE type */
|
||||
if (pol->type != ID_FACE)
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */
|
||||
if (pol->nverts != 3)
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts );
|
||||
continue;
|
||||
}
|
||||
|
||||
for( j = 0, v = pol->v; j < 3; j++, v++ )
|
||||
{
|
||||
pt = &layer->point.pt[ v->index ];
|
||||
|
||||
/* setup data */
|
||||
xyz[ 0 ] = pt->pos[ 0 ];
|
||||
xyz[ 1 ] = pt->pos[ 2 ];
|
||||
xyz[ 2 ] = pt->pos[ 1 ];
|
||||
|
||||
/* doom3 lwo data doesn't seem to have smoothing-angle information */
|
||||
#if 0
|
||||
if(surface->smooth <= 0)
|
||||
{
|
||||
/* use face normals */
|
||||
normal[ 0 ] = v->norm[ 0 ];
|
||||
normal[ 1 ] = v->norm[ 2 ];
|
||||
normal[ 2 ] = v->norm[ 1 ];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* smooth normals later */
|
||||
normal[ 0 ] = 0;
|
||||
normal[ 1 ] = 0;
|
||||
normal[ 2 ] = 0;
|
||||
}
|
||||
|
||||
st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ];
|
||||
st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ];
|
||||
|
||||
color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 3 ] = 0xFF;
|
||||
|
||||
/* set from points */
|
||||
for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ )
|
||||
{
|
||||
if (vm->vmap->type == LWID_('T','X','U','V'))
|
||||
{
|
||||
/* set st coords */
|
||||
st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ];
|
||||
st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ];
|
||||
}
|
||||
else if (vm->vmap->type == LWID_('R','G','B','A'))
|
||||
{
|
||||
/* set rgba */
|
||||
color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* override with polygon data */
|
||||
for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ )
|
||||
{
|
||||
if (vm->vmap->type == LWID_('T','X','U','V'))
|
||||
{
|
||||
/* set st coords */
|
||||
st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ];
|
||||
st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ];
|
||||
}
|
||||
else if (vm->vmap->type == LWID_('R','G','B','A'))
|
||||
{
|
||||
/* set rgba */
|
||||
color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
|
||||
color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* find vertex in this surface and if we can't find it there create it */
|
||||
vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color );
|
||||
|
||||
if (vertexCombinationHash)
|
||||
{
|
||||
/* found an existing one */
|
||||
PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* it is a new one */
|
||||
vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts );
|
||||
|
||||
if (vertexCombinationHash == NULL)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" );
|
||||
PicoFreeVertexCombinationHashTable( hashTable );
|
||||
PicoFreeModel( picoModel );
|
||||
lwFreeObject( obj );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add the vertex to this surface */
|
||||
PicoSetSurfaceXYZ( picoSurface, numverts, xyz );
|
||||
|
||||
/* set dummy normal */
|
||||
PicoSetSurfaceNormal( picoSurface, numverts, normal );
|
||||
|
||||
/* set color */
|
||||
PicoSetSurfaceColor( picoSurface, 0, numverts, color );
|
||||
|
||||
/* set st coords */
|
||||
PicoSetSurfaceST( picoSurface, 0, numverts, st );
|
||||
|
||||
/* set index */
|
||||
PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts );
|
||||
|
||||
numverts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free the hashtable */
|
||||
PicoFreeVertexCombinationHashTable( hashTable );
|
||||
|
||||
/* get next surface */
|
||||
surface = surface->next;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PM_LWO
|
||||
load_start = convert_finish = clock();
|
||||
#endif
|
||||
|
||||
lwFreeObject( obj );
|
||||
|
||||
#ifdef DEBUG_PM_LWO
|
||||
load_finish = clock();
|
||||
load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC;
|
||||
convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC;
|
||||
_pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed );
|
||||
#endif
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
}
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleLWO =
|
||||
{
|
||||
"1.0", /* module version string */
|
||||
"LightWave Object", /* module display name */
|
||||
"Arnout van Meer", /* author's name */
|
||||
"2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */
|
||||
{
|
||||
"lwo", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_lwo_canload, /* validation routine */
|
||||
_lwo_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
667
libs/picomodel/pm_md2.c
Normal file
667
libs/picomodel/pm_md2.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
Nurail: Used pm_md3.c (Randy Reddig) as a template.
|
||||
*/
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_MD2_C
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
|
||||
/* md2 model format */
|
||||
#define MD2_MAGIC "IDP2"
|
||||
#define MD2_VERSION 8
|
||||
|
||||
#define MD2_NUMVERTEXNORMALS 162
|
||||
#define MD2_MAX_SKINNAME 64
|
||||
#define MD2_MAX_TRIANGLES 4096
|
||||
#define MD2_MAX_VERTS 2048
|
||||
#define MD2_MAX_FRAMES 512
|
||||
#define MD2_MAX_MD2SKINS 32
|
||||
#define MD2_MAX_SKINNAME 64
|
||||
|
||||
#ifndef byte
|
||||
#define byte unsigned char
|
||||
#endif
|
||||
|
||||
typedef struct index_LUT_s
|
||||
{
|
||||
short Vert;
|
||||
short ST;
|
||||
struct index_LUT_s *next;
|
||||
|
||||
} index_LUT_t;
|
||||
|
||||
typedef struct index_DUP_LUT_s
|
||||
{
|
||||
short ST;
|
||||
short OldVert;
|
||||
|
||||
} index_DUP_LUT_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short s;
|
||||
short t;
|
||||
} md2St_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3];
|
||||
short index_st[3];
|
||||
} md2Triangle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte v[3]; // scaled byte to fit in frame mins/maxs
|
||||
byte lightnormalindex;
|
||||
} md2XyzNormal_t;
|
||||
|
||||
typedef struct md2Frame_s
|
||||
{
|
||||
float scale[3]; // multiply byte verts by this
|
||||
float translate[3]; // then add this
|
||||
char name[16]; // frame name from grabbing
|
||||
md2XyzNormal_t verts[1]; // variable sized
|
||||
}
|
||||
md2Frame_t;
|
||||
|
||||
|
||||
/* md2 model file md2 structure */
|
||||
typedef struct md2_s
|
||||
{
|
||||
char magic[ 4 ];
|
||||
int version;
|
||||
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
|
||||
int numSkins;
|
||||
int numXYZ;
|
||||
int numST;
|
||||
int numTris;
|
||||
int numGLCmds;
|
||||
int numFrames;
|
||||
|
||||
int ofsSkins;
|
||||
int ofsST;
|
||||
int ofsTris;
|
||||
int ofsFrames;
|
||||
int ofsGLCmds;
|
||||
int ofsEnd;
|
||||
}
|
||||
md2_t;
|
||||
|
||||
float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =
|
||||
{
|
||||
{ -0.525731f, 0.000000f, 0.850651f },
|
||||
{ -0.442863f, 0.238856f, 0.864188f },
|
||||
{ -0.295242f, 0.000000f, 0.955423f },
|
||||
{ -0.309017f, 0.500000f, 0.809017f },
|
||||
{ -0.162460f, 0.262866f, 0.951056f },
|
||||
{ 0.000000f, 0.000000f, 1.000000f },
|
||||
{ 0.000000f, 0.850651f, 0.525731f },
|
||||
{ -0.147621f, 0.716567f, 0.681718f },
|
||||
{ 0.147621f, 0.716567f, 0.681718f },
|
||||
{ 0.000000f, 0.525731f, 0.850651f },
|
||||
{ 0.309017f, 0.500000f, 0.809017f },
|
||||
{ 0.525731f, 0.000000f, 0.850651f },
|
||||
{ 0.295242f, 0.000000f, 0.955423f },
|
||||
{ 0.442863f, 0.238856f, 0.864188f },
|
||||
{ 0.162460f, 0.262866f, 0.951056f },
|
||||
{ -0.681718f, 0.147621f, 0.716567f },
|
||||
{ -0.809017f, 0.309017f, 0.500000f },
|
||||
{ -0.587785f, 0.425325f, 0.688191f },
|
||||
{ -0.850651f, 0.525731f, 0.000000f },
|
||||
{ -0.864188f, 0.442863f, 0.238856f },
|
||||
{ -0.716567f, 0.681718f, 0.147621f },
|
||||
{ -0.688191f, 0.587785f, 0.425325f },
|
||||
{ -0.500000f, 0.809017f, 0.309017f },
|
||||
{ -0.238856f, 0.864188f, 0.442863f },
|
||||
{ -0.425325f, 0.688191f, 0.587785f },
|
||||
{ -0.716567f, 0.681718f, -0.147621f },
|
||||
{ -0.500000f, 0.809017f, -0.309017f },
|
||||
{ -0.525731f, 0.850651f, 0.000000f },
|
||||
{ 0.000000f, 0.850651f, -0.525731f },
|
||||
{ -0.238856f, 0.864188f, -0.442863f },
|
||||
{ 0.000000f, 0.955423f, -0.295242f },
|
||||
{ -0.262866f, 0.951056f, -0.162460f },
|
||||
{ 0.000000f, 1.000000f, 0.000000f },
|
||||
{ 0.000000f, 0.955423f, 0.295242f },
|
||||
{ -0.262866f, 0.951056f, 0.162460f },
|
||||
{ 0.238856f, 0.864188f, 0.442863f },
|
||||
{ 0.262866f, 0.951056f, 0.162460f },
|
||||
{ 0.500000f, 0.809017f, 0.309017f },
|
||||
{ 0.238856f, 0.864188f, -0.442863f },
|
||||
{ 0.262866f, 0.951056f, -0.162460f },
|
||||
{ 0.500000f, 0.809017f, -0.309017f },
|
||||
{ 0.850651f, 0.525731f, 0.000000f },
|
||||
{ 0.716567f, 0.681718f, 0.147621f },
|
||||
{ 0.716567f, 0.681718f, -0.147621f },
|
||||
{ 0.525731f, 0.850651f, 0.000000f },
|
||||
{ 0.425325f, 0.688191f, 0.587785f },
|
||||
{ 0.864188f, 0.442863f, 0.238856f },
|
||||
{ 0.688191f, 0.587785f, 0.425325f },
|
||||
{ 0.809017f, 0.309017f, 0.500000f },
|
||||
{ 0.681718f, 0.147621f, 0.716567f },
|
||||
{ 0.587785f, 0.425325f, 0.688191f },
|
||||
{ 0.955423f, 0.295242f, 0.000000f },
|
||||
{ 1.000000f, 0.000000f, 0.000000f },
|
||||
{ 0.951056f, 0.162460f, 0.262866f },
|
||||
{ 0.850651f, -0.525731f, 0.000000f },
|
||||
{ 0.955423f, -0.295242f, 0.000000f },
|
||||
{ 0.864188f, -0.442863f, 0.238856f },
|
||||
{ 0.951056f, -0.162460f, 0.262866f },
|
||||
{ 0.809017f, -0.309017f, 0.500000f },
|
||||
{ 0.681718f, -0.147621f, 0.716567f },
|
||||
{ 0.850651f, 0.000000f, 0.525731f },
|
||||
{ 0.864188f, 0.442863f, -0.238856f },
|
||||
{ 0.809017f, 0.309017f, -0.500000f },
|
||||
{ 0.951056f, 0.162460f, -0.262866f },
|
||||
{ 0.525731f, 0.000000f, -0.850651f },
|
||||
{ 0.681718f, 0.147621f, -0.716567f },
|
||||
{ 0.681718f, -0.147621f, -0.716567f },
|
||||
{ 0.850651f, 0.000000f, -0.525731f },
|
||||
{ 0.809017f, -0.309017f, -0.500000f },
|
||||
{ 0.864188f, -0.442863f, -0.238856f },
|
||||
{ 0.951056f, -0.162460f, -0.262866f },
|
||||
{ 0.147621f, 0.716567f, -0.681718f },
|
||||
{ 0.309017f, 0.500000f, -0.809017f },
|
||||
{ 0.425325f, 0.688191f, -0.587785f },
|
||||
{ 0.442863f, 0.238856f, -0.864188f },
|
||||
{ 0.587785f, 0.425325f, -0.688191f },
|
||||
{ 0.688191f, 0.587785f, -0.425325f },
|
||||
{ -0.147621f, 0.716567f, -0.681718f },
|
||||
{ -0.309017f, 0.500000f, -0.809017f },
|
||||
{ 0.000000f, 0.525731f, -0.850651f },
|
||||
{ -0.525731f, 0.000000f, -0.850651f },
|
||||
{ -0.442863f, 0.238856f, -0.864188f },
|
||||
{ -0.295242f, 0.000000f, -0.955423f },
|
||||
{ -0.162460f, 0.262866f, -0.951056f },
|
||||
{ 0.000000f, 0.000000f, -1.000000f },
|
||||
{ 0.295242f, 0.000000f, -0.955423f },
|
||||
{ 0.162460f, 0.262866f, -0.951056f },
|
||||
{ -0.442863f, -0.238856f, -0.864188f },
|
||||
{ -0.309017f, -0.500000f, -0.809017f },
|
||||
{ -0.162460f, -0.262866f, -0.951056f },
|
||||
{ 0.000000f, -0.850651f, -0.525731f },
|
||||
{ -0.147621f, -0.716567f, -0.681718f },
|
||||
{ 0.147621f, -0.716567f, -0.681718f },
|
||||
{ 0.000000f, -0.525731f, -0.850651f },
|
||||
{ 0.309017f, -0.500000f, -0.809017f },
|
||||
{ 0.442863f, -0.238856f, -0.864188f },
|
||||
{ 0.162460f, -0.262866f, -0.951056f },
|
||||
{ 0.238856f, -0.864188f, -0.442863f },
|
||||
{ 0.500000f, -0.809017f, -0.309017f },
|
||||
{ 0.425325f, -0.688191f, -0.587785f },
|
||||
{ 0.716567f, -0.681718f, -0.147621f },
|
||||
{ 0.688191f, -0.587785f, -0.425325f },
|
||||
{ 0.587785f, -0.425325f, -0.688191f },
|
||||
{ 0.000000f, -0.955423f, -0.295242f },
|
||||
{ 0.000000f, -1.000000f, 0.000000f },
|
||||
{ 0.262866f, -0.951056f, -0.162460f },
|
||||
{ 0.000000f, -0.850651f, 0.525731f },
|
||||
{ 0.000000f, -0.955423f, 0.295242f },
|
||||
{ 0.238856f, -0.864188f, 0.442863f },
|
||||
{ 0.262866f, -0.951056f, 0.162460f },
|
||||
{ 0.500000f, -0.809017f, 0.309017f },
|
||||
{ 0.716567f, -0.681718f, 0.147621f },
|
||||
{ 0.525731f, -0.850651f, 0.000000f },
|
||||
{ -0.238856f, -0.864188f, -0.442863f },
|
||||
{ -0.500000f, -0.809017f, -0.309017f },
|
||||
{ -0.262866f, -0.951056f, -0.162460f },
|
||||
{ -0.850651f, -0.525731f, 0.000000f },
|
||||
{ -0.716567f, -0.681718f, -0.147621f },
|
||||
{ -0.716567f, -0.681718f, 0.147621f },
|
||||
{ -0.525731f, -0.850651f, 0.000000f },
|
||||
{ -0.500000f, -0.809017f, 0.309017f },
|
||||
{ -0.238856f, -0.864188f, 0.442863f },
|
||||
{ -0.262866f, -0.951056f, 0.162460f },
|
||||
{ -0.864188f, -0.442863f, 0.238856f },
|
||||
{ -0.809017f, -0.309017f, 0.500000f },
|
||||
{ -0.688191f, -0.587785f, 0.425325f },
|
||||
{ -0.681718f, -0.147621f, 0.716567f },
|
||||
{ -0.442863f, -0.238856f, 0.864188f },
|
||||
{ -0.587785f, -0.425325f, 0.688191f },
|
||||
{ -0.309017f, -0.500000f, 0.809017f },
|
||||
{ -0.147621f, -0.716567f, 0.681718f },
|
||||
{ -0.425325f, -0.688191f, 0.587785f },
|
||||
{ -0.162460f, -0.262866f, 0.951056f },
|
||||
{ 0.442863f, -0.238856f, 0.864188f },
|
||||
{ 0.162460f, -0.262866f, 0.951056f },
|
||||
{ 0.309017f, -0.500000f, 0.809017f },
|
||||
{ 0.147621f, -0.716567f, 0.681718f },
|
||||
{ 0.000000f, -0.525731f, 0.850651f },
|
||||
{ 0.425325f, -0.688191f, 0.587785f },
|
||||
{ 0.587785f, -0.425325f, 0.688191f },
|
||||
{ 0.688191f, -0.587785f, 0.425325f },
|
||||
{ -0.955423f, 0.295242f, 0.000000f },
|
||||
{ -0.951056f, 0.162460f, 0.262866f },
|
||||
{ -1.000000f, 0.000000f, 0.000000f },
|
||||
{ -0.850651f, 0.000000f, 0.525731f },
|
||||
{ -0.955423f, -0.295242f, 0.000000f },
|
||||
{ -0.951056f, -0.162460f, 0.262866f },
|
||||
{ -0.864188f, 0.442863f, -0.238856f },
|
||||
{ -0.951056f, 0.162460f, -0.262866f },
|
||||
{ -0.809017f, 0.309017f, -0.500000f },
|
||||
{ -0.864188f, -0.442863f, -0.238856f },
|
||||
{ -0.951056f, -0.162460f, -0.262866f },
|
||||
{ -0.809017f, -0.309017f, -0.500000f },
|
||||
{ -0.681718f, 0.147621f, -0.716567f },
|
||||
{ -0.681718f, -0.147621f, -0.716567f },
|
||||
{ -0.850651f, 0.000000f, -0.525731f },
|
||||
{ -0.688191f, 0.587785f, -0.425325f },
|
||||
{ -0.587785f, 0.425325f, -0.688191f },
|
||||
{ -0.425325f, 0.688191f, -0.587785f },
|
||||
{ -0.425325f, -0.688191f, -0.587785f },
|
||||
{ -0.587785f, -0.425325f, -0.688191f },
|
||||
{ -0.688191f, -0.587785f, -0.425325f },
|
||||
};
|
||||
|
||||
|
||||
// _md2_canload()
|
||||
|
||||
static int _md2_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
md2_t *md2;
|
||||
|
||||
/* to keep the compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* sanity check */
|
||||
if( bufSize < ( sizeof( *md2 ) * 2) )
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* set as md2 */
|
||||
md2 = (md2_t*) buffer;
|
||||
|
||||
/* check md2 magic */
|
||||
if( *((int*) md2->magic) != *((int*) MD2_MAGIC) )
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* check md2 version */
|
||||
if( _pico_little_long( md2->version ) != MD2_VERSION )
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
|
||||
/* file seems to be a valid md2 */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// _md2_load() loads a quake2 md2 model file.
|
||||
|
||||
|
||||
static picoModel_t *_md2_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
int i, j, dups, dup_index;
|
||||
short tot_numVerts;
|
||||
index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
|
||||
index_DUP_LUT_t *p_index_LUT_DUPS;
|
||||
md2Triangle_t *p_md2Triangle;
|
||||
|
||||
char skinname[ MD2_MAX_SKINNAME ];
|
||||
md2_t *md2;
|
||||
md2St_t *texCoord;
|
||||
md2Frame_t *frame;
|
||||
md2Triangle_t *triangle;
|
||||
md2XyzNormal_t *vertex;
|
||||
|
||||
picoByte_t *bb;
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
|
||||
/* set as md2 */
|
||||
bb = (picoByte_t*) buffer;
|
||||
md2 = (md2_t*) buffer;
|
||||
|
||||
/* check ident and version */
|
||||
if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )
|
||||
{
|
||||
/* not an md2 file (todo: set error) */
|
||||
_pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// swap md2
|
||||
md2->version = _pico_little_long( md2->version );
|
||||
|
||||
md2->skinWidth = _pico_little_long( md2->skinWidth );
|
||||
md2->skinHeight = _pico_little_long( md2->skinHeight );
|
||||
md2->frameSize = _pico_little_long( md2->frameSize );
|
||||
|
||||
md2->numSkins = _pico_little_long( md2->numSkins );
|
||||
md2->numXYZ = _pico_little_long( md2->numXYZ );
|
||||
md2->numST = _pico_little_long( md2->numST );
|
||||
md2->numTris = _pico_little_long( md2->numTris );
|
||||
md2->numGLCmds = _pico_little_long( md2->numGLCmds );
|
||||
md2->numFrames = _pico_little_long( md2->numFrames );
|
||||
|
||||
md2->ofsSkins = _pico_little_long( md2->ofsSkins );
|
||||
md2->ofsST = _pico_little_long( md2->ofsST );
|
||||
md2->ofsTris = _pico_little_long( md2->ofsTris );
|
||||
md2->ofsFrames = _pico_little_long( md2->ofsFrames );
|
||||
md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );
|
||||
md2->ofsEnd = _pico_little_long( md2->ofsEnd );
|
||||
|
||||
// do frame check
|
||||
if( md2->numFrames < 1 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( frameNum < 0 || frameNum >= md2->numFrames )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup Frame
|
||||
frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));
|
||||
|
||||
// swap frame scale and translation
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
|
||||
frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
|
||||
}
|
||||
|
||||
// swap triangles
|
||||
triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
|
||||
for( i = 0; i < md2->numTris; i++, triangle++ )
|
||||
{
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
|
||||
triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
|
||||
}
|
||||
}
|
||||
|
||||
// swap st coords
|
||||
texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
|
||||
for( i = 0; i < md2->numST; i++, texCoord++ )
|
||||
{
|
||||
texCoord->s = _pico_little_short( texCoord->s );
|
||||
texCoord->t = _pico_little_short( texCoord->t );
|
||||
}
|
||||
|
||||
// set Skin Name
|
||||
strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME );
|
||||
|
||||
// Print out md2 values
|
||||
_pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );
|
||||
|
||||
// detox Skin name
|
||||
_pico_setfext( skinname, "" );
|
||||
_pico_unixify( skinname );
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if( picoModel == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
// allocate new pico surface
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if( picoSurface == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
PicoSetSurfaceName( picoSurface, frame->name );
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if( picoShader == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PicoSetShaderName( picoShader, skinname );
|
||||
|
||||
// associate current surface with newly created shader
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
// Init LUT for Verts
|
||||
p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);
|
||||
for(i=0; i<md2->numXYZ; i++)
|
||||
{
|
||||
p_index_LUT[i].Vert = -1;
|
||||
p_index_LUT[i].ST = -1;
|
||||
p_index_LUT[i].next = NULL;
|
||||
}
|
||||
|
||||
// Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
|
||||
tot_numVerts = md2->numXYZ;
|
||||
dups = 0;
|
||||
for(i=0; i<md2->numTris; i++)
|
||||
{
|
||||
p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i));
|
||||
for(j=0; j<3; j++)
|
||||
{
|
||||
if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry
|
||||
p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];
|
||||
|
||||
else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry
|
||||
continue;
|
||||
|
||||
else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry
|
||||
{ // Add first entry of LL from Main
|
||||
p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
|
||||
if (p_index_LUT2 == NULL)
|
||||
_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
|
||||
p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
|
||||
p_index_LUT2->Vert = dups;
|
||||
p_index_LUT2->ST = p_md2Triangle->index_st[j];
|
||||
p_index_LUT2->next = NULL;
|
||||
p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
|
||||
dups++;
|
||||
}
|
||||
else // Try to find in LL from Main Entry
|
||||
{
|
||||
p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next;
|
||||
while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
|
||||
{
|
||||
p_index_LUT3 = p_index_LUT2;
|
||||
p_index_LUT2 = p_index_LUT2->next;
|
||||
}
|
||||
p_index_LUT2 = p_index_LUT3;
|
||||
|
||||
if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it
|
||||
{
|
||||
p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL.
|
||||
{
|
||||
// Add the Entry
|
||||
p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
|
||||
if (p_index_LUT3 == NULL)
|
||||
_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
|
||||
p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
|
||||
p_index_LUT3->Vert = p_md2Triangle->index_xyz[j];
|
||||
p_index_LUT3->ST = p_md2Triangle->index_st[j];
|
||||
p_index_LUT3->next = NULL;
|
||||
p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
|
||||
dups++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// malloc and build array for Dup STs
|
||||
p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
|
||||
if (p_index_LUT_DUPS == NULL)
|
||||
_pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
|
||||
|
||||
dup_index = 0;
|
||||
for(i=0; i<md2->numXYZ; i++)
|
||||
{
|
||||
p_index_LUT2 = p_index_LUT[i].next;
|
||||
while (p_index_LUT2 != NULL)
|
||||
{
|
||||
p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
|
||||
p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
|
||||
dup_index++;
|
||||
p_index_LUT2 = p_index_LUT2->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Build Picomodel
|
||||
triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
|
||||
texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
|
||||
vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) );
|
||||
for( j = 0; j < md2->numTris; j++, triangle++ )
|
||||
{
|
||||
PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] );
|
||||
PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
|
||||
PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
|
||||
}
|
||||
|
||||
for(i=0; i< md2->numXYZ; i++, vertex++)
|
||||
{
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];
|
||||
xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];
|
||||
xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];
|
||||
PicoSetSurfaceXYZ( picoSurface, i , xyz );
|
||||
|
||||
/* set normal */
|
||||
normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];
|
||||
normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];
|
||||
normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];
|
||||
PicoSetSurfaceNormal( picoSurface, i , normal );
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth));
|
||||
st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight));
|
||||
PicoSetSurfaceST( picoSurface, 0, i , st );
|
||||
}
|
||||
|
||||
if (dups)
|
||||
{
|
||||
for(i=0; i<dups; i++)
|
||||
{
|
||||
j = p_index_LUT_DUPS[i].OldVert;
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0];
|
||||
xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1];
|
||||
xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2];
|
||||
PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz );
|
||||
|
||||
/* set normal */
|
||||
normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0];
|
||||
normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1];
|
||||
normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2];
|
||||
PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal );
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth));
|
||||
st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight));
|
||||
PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st );
|
||||
}
|
||||
}
|
||||
|
||||
/* set color */
|
||||
PicoSetSurfaceColor( picoSurface, 0, 0, color );
|
||||
|
||||
// Free up malloc'ed LL entries
|
||||
for(i=0; i<md2->numXYZ; i++)
|
||||
{
|
||||
if(p_index_LUT[i].next != NULL)
|
||||
{
|
||||
p_index_LUT2 = p_index_LUT[i].next;
|
||||
do {
|
||||
p_index_LUT3 = p_index_LUT2->next;
|
||||
_pico_free(p_index_LUT2);
|
||||
p_index_LUT2 = p_index_LUT3;
|
||||
dups--;
|
||||
} while (p_index_LUT2 != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (dups)
|
||||
_pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
|
||||
|
||||
// Free malloc'ed LUTs
|
||||
_pico_free(p_index_LUT);
|
||||
_pico_free(p_index_LUT_DUPS);
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleMD2 =
|
||||
{
|
||||
"0.875", /* module version string */
|
||||
"Quake 2 MD2", /* module display name */
|
||||
"Nurail", /* author's name */
|
||||
"2003 Nurail", /* module copyright */
|
||||
{
|
||||
"md2", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_md2_canload, /* validation routine */
|
||||
_md2_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
425
libs/picomodel/pm_md3.c
Normal file
425
libs/picomodel/pm_md3.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_MD3_C
|
||||
|
||||
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
|
||||
|
||||
/* md3 model format */
|
||||
#define MD3_MAGIC "IDP3"
|
||||
#define MD3_VERSION 15
|
||||
|
||||
/* md3 vertex scale */
|
||||
#define MD3_SCALE (1.0f / 64.0f)
|
||||
|
||||
/* md3 model frame information */
|
||||
typedef struct md3Frame_s
|
||||
{
|
||||
float bounds[ 2 ][ 3 ];
|
||||
float localOrigin[ 3 ];
|
||||
float radius;
|
||||
char creator[ 16 ];
|
||||
}
|
||||
md3Frame_t;
|
||||
|
||||
/* md3 model tag information */
|
||||
typedef struct md3Tag_s
|
||||
{
|
||||
char name[ 64 ];
|
||||
float origin[ 3 ];
|
||||
float axis[ 3 ][ 3 ];
|
||||
}
|
||||
md3Tag_t;
|
||||
|
||||
/* md3 surface md3 (one object mesh) */
|
||||
typedef struct md3Surface_s
|
||||
{
|
||||
char magic[ 4 ];
|
||||
char name[ 64 ]; /* polyset name */
|
||||
int flags;
|
||||
int numFrames; /* all model surfaces should have the same */
|
||||
int numShaders; /* all model surfaces should have the same */
|
||||
int numVerts;
|
||||
int numTriangles;
|
||||
int ofsTriangles;
|
||||
int ofsShaders; /* offset from start of md3Surface_t */
|
||||
int ofsSt; /* texture coords are common for all frames */
|
||||
int ofsVertexes; /* numVerts * numFrames */
|
||||
int ofsEnd; /* next surface follows */
|
||||
}
|
||||
md3Surface_t;
|
||||
|
||||
typedef struct md3Shader_s
|
||||
{
|
||||
char name[ 64 ];
|
||||
int shaderIndex; /* for ingame use */
|
||||
}
|
||||
md3Shader_t;
|
||||
|
||||
typedef struct md3Triangle_s
|
||||
{
|
||||
int indexes[ 3 ];
|
||||
}
|
||||
md3Triangle_t;
|
||||
|
||||
typedef struct md3TexCoord_s
|
||||
{
|
||||
float st[ 2 ];
|
||||
}
|
||||
md3TexCoord_t;
|
||||
|
||||
typedef struct md3Vertex_s
|
||||
{
|
||||
short xyz[ 3 ];
|
||||
short normal;
|
||||
}
|
||||
md3Vertex_t;
|
||||
|
||||
|
||||
/* md3 model file md3 structure */
|
||||
typedef struct md3_s
|
||||
{
|
||||
char magic[ 4 ]; /* MD3_MAGIC */
|
||||
int version;
|
||||
char name[ 64 ]; /* model name */
|
||||
int flags;
|
||||
int numFrames;
|
||||
int numTags;
|
||||
int numSurfaces;
|
||||
int numSkins; /* number of skins for the mesh */
|
||||
int ofsFrames; /* offset for first frame */
|
||||
int ofsTags; /* numFrames * numTags */
|
||||
int ofsSurfaces; /* first surface, others follow */
|
||||
int ofsEnd; /* end of file */
|
||||
}
|
||||
md3_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_md3_canload()
|
||||
validates a quake3 arena md3 model file. btw, i use the
|
||||
preceding underscore cause it's a static func referenced
|
||||
by one structure only.
|
||||
*/
|
||||
|
||||
static int _md3_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
md3_t *md3;
|
||||
|
||||
|
||||
/* to keep the compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* sanity check */
|
||||
if( bufSize < ( sizeof( *md3 ) * 2) )
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* set as md3 */
|
||||
md3 = (md3_t*) buffer;
|
||||
|
||||
/* check md3 magic */
|
||||
if( *((int*) md3->magic) != *((int*) MD3_MAGIC) )
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* check md3 version */
|
||||
if( _pico_little_long( md3->version ) != MD3_VERSION )
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
|
||||
/* file seems to be a valid md3 */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_md3_load()
|
||||
loads a quake3 arena md3 model file.
|
||||
*/
|
||||
|
||||
static picoModel_t *_md3_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
int i, j;
|
||||
picoByte_t *bb;
|
||||
md3_t *md3;
|
||||
md3Surface_t *surface;
|
||||
md3Shader_t *shader;
|
||||
md3TexCoord_t *texCoord;
|
||||
md3Frame_t *frame;
|
||||
md3Triangle_t *triangle;
|
||||
md3Vertex_t *vertex;
|
||||
double lat, lng;
|
||||
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
|
||||
/* -------------------------------------------------
|
||||
md3 loading
|
||||
------------------------------------------------- */
|
||||
|
||||
|
||||
/* set as md3 */
|
||||
bb = (picoByte_t*) buffer;
|
||||
md3 = (md3_t*) buffer;
|
||||
|
||||
/* check ident and version */
|
||||
if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION )
|
||||
{
|
||||
/* not an md3 file (todo: set error) */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* swap md3; sea: swaps fixed */
|
||||
md3->version = _pico_little_long( md3->version );
|
||||
md3->numFrames = _pico_little_long( md3->numFrames );
|
||||
md3->numTags = _pico_little_long( md3->numTags );
|
||||
md3->numSurfaces = _pico_little_long( md3->numSurfaces );
|
||||
md3->numSkins = _pico_little_long( md3->numSkins );
|
||||
md3->ofsFrames = _pico_little_long( md3->ofsFrames );
|
||||
md3->ofsTags = _pico_little_long( md3->ofsTags );
|
||||
md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces );
|
||||
md3->ofsEnd = _pico_little_long( md3->ofsEnd );
|
||||
|
||||
/* do frame check */
|
||||
if( md3->numFrames < 1 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "MD3 with 0 frames" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( frameNum < 0 || frameNum >= md3->numFrames )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* swap frames */
|
||||
frame = (md3Frame_t*) (bb + md3->ofsFrames );
|
||||
for( i = 0; i < md3->numFrames; i++, frame++ )
|
||||
{
|
||||
frame->radius = _pico_little_float( frame->radius );
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
|
||||
frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
|
||||
frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* swap surfaces */
|
||||
surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
|
||||
for( i = 0; i < md3->numSurfaces; i++ )
|
||||
{
|
||||
/* swap surface md3; sea: swaps fixed */
|
||||
surface->flags = _pico_little_long( surface->flags );
|
||||
surface->numFrames = _pico_little_long( surface->numFrames );
|
||||
surface->numShaders = _pico_little_long( surface->numShaders );
|
||||
surface->numTriangles = _pico_little_long( surface->numTriangles );
|
||||
surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
|
||||
surface->numVerts = _pico_little_long( surface->numVerts );
|
||||
surface->ofsShaders = _pico_little_long( surface->ofsShaders );
|
||||
surface->ofsSt = _pico_little_long( surface->ofsSt );
|
||||
surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );
|
||||
surface->ofsEnd = _pico_little_long( surface->ofsEnd );
|
||||
|
||||
/* swap triangles */
|
||||
triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles);
|
||||
for( j = 0; j < surface->numTriangles; j++, triangle++ )
|
||||
{
|
||||
/* sea: swaps fixed */
|
||||
triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
|
||||
triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
|
||||
triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
|
||||
}
|
||||
|
||||
/* swap st coords */
|
||||
texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt);
|
||||
for( j = 0; j < surface->numVerts; j++, texCoord++ )
|
||||
{
|
||||
texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
|
||||
texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
|
||||
}
|
||||
|
||||
/* swap xyz/normals */
|
||||
vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes);
|
||||
for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++)
|
||||
{
|
||||
vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
|
||||
vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
|
||||
vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
|
||||
vertex->normal = _pico_little_short( vertex->normal );
|
||||
}
|
||||
|
||||
/* get next surface */
|
||||
surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------
|
||||
pico model creation
|
||||
------------------------------------------------- */
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if( picoModel == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
/* md3 surfaces become picomodel surfaces */
|
||||
surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
|
||||
|
||||
/* run through md3 surfaces */
|
||||
for( i = 0; i < md3->numSurfaces; i++ )
|
||||
{
|
||||
/* allocate new pico surface */
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if( picoSurface == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel ); /* sea */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* md3 model surfaces are all triangle meshes */
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( picoSurface, surface->name );
|
||||
|
||||
/* create new pico shader -sea */
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if( picoShader == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detox and set shader name */
|
||||
shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders);
|
||||
_pico_setfext( shader->name, "" );
|
||||
_pico_unixify( shader->name );
|
||||
PicoSetShaderName( picoShader, shader->name );
|
||||
|
||||
/* associate current surface with newly created shader */
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
/* copy indexes */
|
||||
triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles);
|
||||
|
||||
for( j = 0; j < surface->numTriangles; j++, triangle++ )
|
||||
{
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] );
|
||||
}
|
||||
|
||||
/* copy vertexes */
|
||||
texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt);
|
||||
vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );
|
||||
_pico_set_color( color, 255, 255, 255, 255 );
|
||||
|
||||
for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )
|
||||
{
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];
|
||||
xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];
|
||||
xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];
|
||||
PicoSetSurfaceXYZ( picoSurface, j, xyz );
|
||||
|
||||
/* decode lat/lng normal to 3 float normal */
|
||||
lat = (float) ((vertex->normal >> 8) & 0xff);
|
||||
lng = (float) (vertex->normal & 0xff);
|
||||
lat *= PICO_PI / 128;
|
||||
lng *= PICO_PI / 128;
|
||||
normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
|
||||
normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
|
||||
normal[ 2 ] = (picoVec_t) cos( lng );
|
||||
PicoSetSurfaceNormal( picoSurface, j, normal );
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = texCoord->st[ 0 ];
|
||||
st[ 1 ] = texCoord->st[ 1 ];
|
||||
PicoSetSurfaceST( picoSurface, 0, j, st );
|
||||
|
||||
/* set color */
|
||||
PicoSetSurfaceColor( picoSurface, 0, j, color );
|
||||
}
|
||||
|
||||
/* get next surface */
|
||||
surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
|
||||
}
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleMD3 =
|
||||
{
|
||||
"1.3", /* module version string */
|
||||
"Quake 3 Arena", /* module display name */
|
||||
"Randy Reddig", /* author's name */
|
||||
"2002 Randy Reddig", /* module copyright */
|
||||
{
|
||||
"md3", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_md3_canload, /* validation routine */
|
||||
_md3_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
750
libs/picomodel/pm_mdc.c
Normal file
750
libs/picomodel/pm_mdc.c
Normal file
@@ -0,0 +1,750 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_MDC_C
|
||||
|
||||
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
/* mdc model format */
|
||||
#define MDC_MAGIC "IDPC"
|
||||
#define MDC_VERSION 2
|
||||
|
||||
/* mdc vertex scale */
|
||||
#define MDC_SCALE (1.0f / 64.0f)
|
||||
#define MDC_MAX_OFS 127.0f
|
||||
#define MDC_DIST_SCALE 0.05f
|
||||
|
||||
/* mdc decoding normal table */
|
||||
double mdcNormals[ 256 ][ 3 ] =
|
||||
{
|
||||
{ 1.000000, 0.000000, 0.000000 },
|
||||
{ 0.980785, 0.195090, 0.000000 },
|
||||
{ 0.923880, 0.382683, 0.000000 },
|
||||
{ 0.831470, 0.555570, 0.000000 },
|
||||
{ 0.707107, 0.707107, 0.000000 },
|
||||
{ 0.555570, 0.831470, 0.000000 },
|
||||
{ 0.382683, 0.923880, 0.000000 },
|
||||
{ 0.195090, 0.980785, 0.000000 },
|
||||
{ -0.000000, 1.000000, 0.000000 },
|
||||
{ -0.195090, 0.980785, 0.000000 },
|
||||
{ -0.382683, 0.923880, 0.000000 },
|
||||
{ -0.555570, 0.831470, 0.000000 },
|
||||
{ -0.707107, 0.707107, 0.000000 },
|
||||
{ -0.831470, 0.555570, 0.000000 },
|
||||
{ -0.923880, 0.382683, 0.000000 },
|
||||
{ -0.980785, 0.195090, 0.000000 },
|
||||
{ -1.000000, -0.000000, 0.000000 },
|
||||
{ -0.980785, -0.195090, 0.000000 },
|
||||
{ -0.923880, -0.382683, 0.000000 },
|
||||
{ -0.831470, -0.555570, 0.000000 },
|
||||
{ -0.707107, -0.707107, 0.000000 },
|
||||
{ -0.555570, -0.831469, 0.000000 },
|
||||
{ -0.382684, -0.923880, 0.000000 },
|
||||
{ -0.195090, -0.980785, 0.000000 },
|
||||
{ 0.000000, -1.000000, 0.000000 },
|
||||
{ 0.195090, -0.980785, 0.000000 },
|
||||
{ 0.382684, -0.923879, 0.000000 },
|
||||
{ 0.555570, -0.831470, 0.000000 },
|
||||
{ 0.707107, -0.707107, 0.000000 },
|
||||
{ 0.831470, -0.555570, 0.000000 },
|
||||
{ 0.923880, -0.382683, 0.000000 },
|
||||
{ 0.980785, -0.195090, 0.000000 },
|
||||
{ 0.980785, 0.000000, -0.195090 },
|
||||
{ 0.956195, 0.218245, -0.195090 },
|
||||
{ 0.883657, 0.425547, -0.195090 },
|
||||
{ 0.766809, 0.611510, -0.195090 },
|
||||
{ 0.611510, 0.766809, -0.195090 },
|
||||
{ 0.425547, 0.883657, -0.195090 },
|
||||
{ 0.218245, 0.956195, -0.195090 },
|
||||
{ -0.000000, 0.980785, -0.195090 },
|
||||
{ -0.218245, 0.956195, -0.195090 },
|
||||
{ -0.425547, 0.883657, -0.195090 },
|
||||
{ -0.611510, 0.766809, -0.195090 },
|
||||
{ -0.766809, 0.611510, -0.195090 },
|
||||
{ -0.883657, 0.425547, -0.195090 },
|
||||
{ -0.956195, 0.218245, -0.195090 },
|
||||
{ -0.980785, -0.000000, -0.195090 },
|
||||
{ -0.956195, -0.218245, -0.195090 },
|
||||
{ -0.883657, -0.425547, -0.195090 },
|
||||
{ -0.766809, -0.611510, -0.195090 },
|
||||
{ -0.611510, -0.766809, -0.195090 },
|
||||
{ -0.425547, -0.883657, -0.195090 },
|
||||
{ -0.218245, -0.956195, -0.195090 },
|
||||
{ 0.000000, -0.980785, -0.195090 },
|
||||
{ 0.218245, -0.956195, -0.195090 },
|
||||
{ 0.425547, -0.883657, -0.195090 },
|
||||
{ 0.611510, -0.766809, -0.195090 },
|
||||
{ 0.766809, -0.611510, -0.195090 },
|
||||
{ 0.883657, -0.425547, -0.195090 },
|
||||
{ 0.956195, -0.218245, -0.195090 },
|
||||
{ 0.923880, 0.000000, -0.382683 },
|
||||
{ 0.892399, 0.239118, -0.382683 },
|
||||
{ 0.800103, 0.461940, -0.382683 },
|
||||
{ 0.653281, 0.653281, -0.382683 },
|
||||
{ 0.461940, 0.800103, -0.382683 },
|
||||
{ 0.239118, 0.892399, -0.382683 },
|
||||
{ -0.000000, 0.923880, -0.382683 },
|
||||
{ -0.239118, 0.892399, -0.382683 },
|
||||
{ -0.461940, 0.800103, -0.382683 },
|
||||
{ -0.653281, 0.653281, -0.382683 },
|
||||
{ -0.800103, 0.461940, -0.382683 },
|
||||
{ -0.892399, 0.239118, -0.382683 },
|
||||
{ -0.923880, -0.000000, -0.382683 },
|
||||
{ -0.892399, -0.239118, -0.382683 },
|
||||
{ -0.800103, -0.461940, -0.382683 },
|
||||
{ -0.653282, -0.653281, -0.382683 },
|
||||
{ -0.461940, -0.800103, -0.382683 },
|
||||
{ -0.239118, -0.892399, -0.382683 },
|
||||
{ 0.000000, -0.923880, -0.382683 },
|
||||
{ 0.239118, -0.892399, -0.382683 },
|
||||
{ 0.461940, -0.800103, -0.382683 },
|
||||
{ 0.653281, -0.653282, -0.382683 },
|
||||
{ 0.800103, -0.461940, -0.382683 },
|
||||
{ 0.892399, -0.239117, -0.382683 },
|
||||
{ 0.831470, 0.000000, -0.555570 },
|
||||
{ 0.790775, 0.256938, -0.555570 },
|
||||
{ 0.672673, 0.488726, -0.555570 },
|
||||
{ 0.488726, 0.672673, -0.555570 },
|
||||
{ 0.256938, 0.790775, -0.555570 },
|
||||
{ -0.000000, 0.831470, -0.555570 },
|
||||
{ -0.256938, 0.790775, -0.555570 },
|
||||
{ -0.488726, 0.672673, -0.555570 },
|
||||
{ -0.672673, 0.488726, -0.555570 },
|
||||
{ -0.790775, 0.256938, -0.555570 },
|
||||
{ -0.831470, -0.000000, -0.555570 },
|
||||
{ -0.790775, -0.256938, -0.555570 },
|
||||
{ -0.672673, -0.488726, -0.555570 },
|
||||
{ -0.488725, -0.672673, -0.555570 },
|
||||
{ -0.256938, -0.790775, -0.555570 },
|
||||
{ 0.000000, -0.831470, -0.555570 },
|
||||
{ 0.256938, -0.790775, -0.555570 },
|
||||
{ 0.488725, -0.672673, -0.555570 },
|
||||
{ 0.672673, -0.488726, -0.555570 },
|
||||
{ 0.790775, -0.256938, -0.555570 },
|
||||
{ 0.707107, 0.000000, -0.707107 },
|
||||
{ 0.653281, 0.270598, -0.707107 },
|
||||
{ 0.500000, 0.500000, -0.707107 },
|
||||
{ 0.270598, 0.653281, -0.707107 },
|
||||
{ -0.000000, 0.707107, -0.707107 },
|
||||
{ -0.270598, 0.653282, -0.707107 },
|
||||
{ -0.500000, 0.500000, -0.707107 },
|
||||
{ -0.653281, 0.270598, -0.707107 },
|
||||
{ -0.707107, -0.000000, -0.707107 },
|
||||
{ -0.653281, -0.270598, -0.707107 },
|
||||
{ -0.500000, -0.500000, -0.707107 },
|
||||
{ -0.270598, -0.653281, -0.707107 },
|
||||
{ 0.000000, -0.707107, -0.707107 },
|
||||
{ 0.270598, -0.653281, -0.707107 },
|
||||
{ 0.500000, -0.500000, -0.707107 },
|
||||
{ 0.653282, -0.270598, -0.707107 },
|
||||
{ 0.555570, 0.000000, -0.831470 },
|
||||
{ 0.481138, 0.277785, -0.831470 },
|
||||
{ 0.277785, 0.481138, -0.831470 },
|
||||
{ -0.000000, 0.555570, -0.831470 },
|
||||
{ -0.277785, 0.481138, -0.831470 },
|
||||
{ -0.481138, 0.277785, -0.831470 },
|
||||
{ -0.555570, -0.000000, -0.831470 },
|
||||
{ -0.481138, -0.277785, -0.831470 },
|
||||
{ -0.277785, -0.481138, -0.831470 },
|
||||
{ 0.000000, -0.555570, -0.831470 },
|
||||
{ 0.277785, -0.481138, -0.831470 },
|
||||
{ 0.481138, -0.277785, -0.831470 },
|
||||
{ 0.382683, 0.000000, -0.923880 },
|
||||
{ 0.270598, 0.270598, -0.923880 },
|
||||
{ -0.000000, 0.382683, -0.923880 },
|
||||
{ -0.270598, 0.270598, -0.923880 },
|
||||
{ -0.382683, -0.000000, -0.923880 },
|
||||
{ -0.270598, -0.270598, -0.923880 },
|
||||
{ 0.000000, -0.382683, -0.923880 },
|
||||
{ 0.270598, -0.270598, -0.923880 },
|
||||
{ 0.195090, 0.000000, -0.980785 },
|
||||
{ -0.000000, 0.195090, -0.980785 },
|
||||
{ -0.195090, -0.000000, -0.980785 },
|
||||
{ 0.000000, -0.195090, -0.980785 },
|
||||
{ 0.980785, 0.000000, 0.195090 },
|
||||
{ 0.956195, 0.218245, 0.195090 },
|
||||
{ 0.883657, 0.425547, 0.195090 },
|
||||
{ 0.766809, 0.611510, 0.195090 },
|
||||
{ 0.611510, 0.766809, 0.195090 },
|
||||
{ 0.425547, 0.883657, 0.195090 },
|
||||
{ 0.218245, 0.956195, 0.195090 },
|
||||
{ -0.000000, 0.980785, 0.195090 },
|
||||
{ -0.218245, 0.956195, 0.195090 },
|
||||
{ -0.425547, 0.883657, 0.195090 },
|
||||
{ -0.611510, 0.766809, 0.195090 },
|
||||
{ -0.766809, 0.611510, 0.195090 },
|
||||
{ -0.883657, 0.425547, 0.195090 },
|
||||
{ -0.956195, 0.218245, 0.195090 },
|
||||
{ -0.980785, -0.000000, 0.195090 },
|
||||
{ -0.956195, -0.218245, 0.195090 },
|
||||
{ -0.883657, -0.425547, 0.195090 },
|
||||
{ -0.766809, -0.611510, 0.195090 },
|
||||
{ -0.611510, -0.766809, 0.195090 },
|
||||
{ -0.425547, -0.883657, 0.195090 },
|
||||
{ -0.218245, -0.956195, 0.195090 },
|
||||
{ 0.000000, -0.980785, 0.195090 },
|
||||
{ 0.218245, -0.956195, 0.195090 },
|
||||
{ 0.425547, -0.883657, 0.195090 },
|
||||
{ 0.611510, -0.766809, 0.195090 },
|
||||
{ 0.766809, -0.611510, 0.195090 },
|
||||
{ 0.883657, -0.425547, 0.195090 },
|
||||
{ 0.956195, -0.218245, 0.195090 },
|
||||
{ 0.923880, 0.000000, 0.382683 },
|
||||
{ 0.892399, 0.239118, 0.382683 },
|
||||
{ 0.800103, 0.461940, 0.382683 },
|
||||
{ 0.653281, 0.653281, 0.382683 },
|
||||
{ 0.461940, 0.800103, 0.382683 },
|
||||
{ 0.239118, 0.892399, 0.382683 },
|
||||
{ -0.000000, 0.923880, 0.382683 },
|
||||
{ -0.239118, 0.892399, 0.382683 },
|
||||
{ -0.461940, 0.800103, 0.382683 },
|
||||
{ -0.653281, 0.653281, 0.382683 },
|
||||
{ -0.800103, 0.461940, 0.382683 },
|
||||
{ -0.892399, 0.239118, 0.382683 },
|
||||
{ -0.923880, -0.000000, 0.382683 },
|
||||
{ -0.892399, -0.239118, 0.382683 },
|
||||
{ -0.800103, -0.461940, 0.382683 },
|
||||
{ -0.653282, -0.653281, 0.382683 },
|
||||
{ -0.461940, -0.800103, 0.382683 },
|
||||
{ -0.239118, -0.892399, 0.382683 },
|
||||
{ 0.000000, -0.923880, 0.382683 },
|
||||
{ 0.239118, -0.892399, 0.382683 },
|
||||
{ 0.461940, -0.800103, 0.382683 },
|
||||
{ 0.653281, -0.653282, 0.382683 },
|
||||
{ 0.800103, -0.461940, 0.382683 },
|
||||
{ 0.892399, -0.239117, 0.382683 },
|
||||
{ 0.831470, 0.000000, 0.555570 },
|
||||
{ 0.790775, 0.256938, 0.555570 },
|
||||
{ 0.672673, 0.488726, 0.555570 },
|
||||
{ 0.488726, 0.672673, 0.555570 },
|
||||
{ 0.256938, 0.790775, 0.555570 },
|
||||
{ -0.000000, 0.831470, 0.555570 },
|
||||
{ -0.256938, 0.790775, 0.555570 },
|
||||
{ -0.488726, 0.672673, 0.555570 },
|
||||
{ -0.672673, 0.488726, 0.555570 },
|
||||
{ -0.790775, 0.256938, 0.555570 },
|
||||
{ -0.831470, -0.000000, 0.555570 },
|
||||
{ -0.790775, -0.256938, 0.555570 },
|
||||
{ -0.672673, -0.488726, 0.555570 },
|
||||
{ -0.488725, -0.672673, 0.555570 },
|
||||
{ -0.256938, -0.790775, 0.555570 },
|
||||
{ 0.000000, -0.831470, 0.555570 },
|
||||
{ 0.256938, -0.790775, 0.555570 },
|
||||
{ 0.488725, -0.672673, 0.555570 },
|
||||
{ 0.672673, -0.488726, 0.555570 },
|
||||
{ 0.790775, -0.256938, 0.555570 },
|
||||
{ 0.707107, 0.000000, 0.707107 },
|
||||
{ 0.653281, 0.270598, 0.707107 },
|
||||
{ 0.500000, 0.500000, 0.707107 },
|
||||
{ 0.270598, 0.653281, 0.707107 },
|
||||
{ -0.000000, 0.707107, 0.707107 },
|
||||
{ -0.270598, 0.653282, 0.707107 },
|
||||
{ -0.500000, 0.500000, 0.707107 },
|
||||
{ -0.653281, 0.270598, 0.707107 },
|
||||
{ -0.707107, -0.000000, 0.707107 },
|
||||
{ -0.653281, -0.270598, 0.707107 },
|
||||
{ -0.500000, -0.500000, 0.707107 },
|
||||
{ -0.270598, -0.653281, 0.707107 },
|
||||
{ 0.000000, -0.707107, 0.707107 },
|
||||
{ 0.270598, -0.653281, 0.707107 },
|
||||
{ 0.500000, -0.500000, 0.707107 },
|
||||
{ 0.653282, -0.270598, 0.707107 },
|
||||
{ 0.555570, 0.000000, 0.831470 },
|
||||
{ 0.481138, 0.277785, 0.831470 },
|
||||
{ 0.277785, 0.481138, 0.831470 },
|
||||
{ -0.000000, 0.555570, 0.831470 },
|
||||
{ -0.277785, 0.481138, 0.831470 },
|
||||
{ -0.481138, 0.277785, 0.831470 },
|
||||
{ -0.555570, -0.000000, 0.831470 },
|
||||
{ -0.481138, -0.277785, 0.831470 },
|
||||
{ -0.277785, -0.481138, 0.831470 },
|
||||
{ 0.000000, -0.555570, 0.831470 },
|
||||
{ 0.277785, -0.481138, 0.831470 },
|
||||
{ 0.481138, -0.277785, 0.831470 },
|
||||
{ 0.382683, 0.000000, 0.923880 },
|
||||
{ 0.270598, 0.270598, 0.923880 },
|
||||
{ -0.000000, 0.382683, 0.923880 },
|
||||
{ -0.270598, 0.270598, 0.923880 },
|
||||
{ -0.382683, -0.000000, 0.923880 },
|
||||
{ -0.270598, -0.270598, 0.923880 },
|
||||
{ 0.000000, -0.382683, 0.923880 },
|
||||
{ 0.270598, -0.270598, 0.923880 },
|
||||
{ 0.195090, 0.000000, 0.980785 },
|
||||
{ -0.000000, 0.195090, 0.980785 },
|
||||
{ -0.195090, -0.000000, 0.980785 },
|
||||
{ 0.000000, -0.195090, 0.980785 }
|
||||
};
|
||||
|
||||
/* mdc model frame information */
|
||||
typedef struct mdcFrame_s
|
||||
{
|
||||
float bounds[ 2 ][ 3 ];
|
||||
float localOrigin[ 3 ];
|
||||
float radius;
|
||||
char creator[ 16 ];
|
||||
}
|
||||
mdcFrame_t;
|
||||
|
||||
/* mdc model tag information */
|
||||
typedef struct mdcTag_s
|
||||
{
|
||||
short xyz[3];
|
||||
short angles[3];
|
||||
}
|
||||
mdcTag_t;
|
||||
|
||||
/* mdc surface mdc (one object mesh) */
|
||||
typedef struct mdcSurface_s
|
||||
{
|
||||
char magic[ 4 ];
|
||||
char name[ 64 ]; /* polyset name */
|
||||
int flags;
|
||||
int numCompFrames; /* all surfaces in a model should have the same */
|
||||
int numBaseFrames; /* ditto */
|
||||
int numShaders; /* all model surfaces should have the same */
|
||||
int numVerts;
|
||||
int numTriangles;
|
||||
int ofsTriangles;
|
||||
int ofsShaders; /* offset from start of mdcSurface_t */
|
||||
int ofsSt; /* texture coords are common for all frames */
|
||||
int ofsXyzNormals; /* numVerts * numBaseFrames */
|
||||
int ofsXyzCompressed; /* numVerts * numCompFrames */
|
||||
|
||||
int ofsFrameBaseFrames; /* numFrames */
|
||||
int ofsFrameCompFrames; /* numFrames */
|
||||
int ofsEnd; /* next surface follows */
|
||||
}
|
||||
mdcSurface_t;
|
||||
|
||||
typedef struct mdcShader_s
|
||||
{
|
||||
char name[ 64 ];
|
||||
int shaderIndex; /* for ingame use */
|
||||
}
|
||||
mdcShader_t;
|
||||
|
||||
typedef struct mdcTriangle_s
|
||||
{
|
||||
int indexes[ 3 ];
|
||||
}
|
||||
mdcTriangle_t;
|
||||
|
||||
typedef struct mdcTexCoord_s
|
||||
{
|
||||
float st[ 2 ];
|
||||
}
|
||||
mdcTexCoord_t;
|
||||
|
||||
typedef struct mdcVertex_s
|
||||
{
|
||||
short xyz[ 3 ];
|
||||
short normal;
|
||||
}
|
||||
mdcVertex_t;
|
||||
|
||||
typedef struct mdcXyzCompressed_s
|
||||
{
|
||||
unsigned int ofsVec; /* offset direction from the last base frame */
|
||||
}
|
||||
mdcXyzCompressed_t;
|
||||
|
||||
|
||||
/* mdc model file mdc structure */
|
||||
typedef struct mdc_s
|
||||
{
|
||||
char magic[ 4 ]; /* MDC_MAGIC */
|
||||
int version;
|
||||
char name[ 64 ]; /* model name */
|
||||
int flags;
|
||||
int numFrames;
|
||||
int numTags;
|
||||
int numSurfaces;
|
||||
int numSkins; /* number of skins for the mesh */
|
||||
int ofsFrames; /* offset for first frame */
|
||||
int ofsTagNames; /* numTags */
|
||||
int ofsTags; /* numFrames * numTags */
|
||||
int ofsSurfaces; /* first surface, others follow */
|
||||
int ofsEnd; /* end of file */
|
||||
}
|
||||
mdc_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_mdc_canload()
|
||||
validates a Return to Castle Wolfenstein model file. btw, i use the
|
||||
preceding underscore cause it's a static func referenced
|
||||
by one structure only.
|
||||
*/
|
||||
|
||||
static int _mdc_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
mdc_t *mdc;
|
||||
|
||||
|
||||
/* to keep the compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* sanity check */
|
||||
if( bufSize < ( sizeof( *mdc ) * 2) )
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* set as mdc */
|
||||
mdc = (mdc_t*) buffer;
|
||||
|
||||
/* check mdc magic */
|
||||
if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) )
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* check mdc version */
|
||||
if( _pico_little_long( mdc->version ) != MDC_VERSION )
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
|
||||
/* file seems to be a valid mdc */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_mdc_load()
|
||||
loads a Return to Castle Wolfenstein mdc model file.
|
||||
*/
|
||||
|
||||
static picoModel_t *_mdc_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
int i, j;
|
||||
picoByte_t *bb;
|
||||
mdc_t *mdc;
|
||||
mdcSurface_t *surface;
|
||||
mdcShader_t *shader;
|
||||
mdcTexCoord_t *texCoord;
|
||||
mdcFrame_t *frame;
|
||||
mdcTriangle_t *triangle;
|
||||
mdcVertex_t *vertex;
|
||||
mdcXyzCompressed_t *vertexComp;
|
||||
short *mdcShort, *mdcCompVert;
|
||||
double lat, lng;
|
||||
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
|
||||
/* -------------------------------------------------
|
||||
mdc loading
|
||||
------------------------------------------------- */
|
||||
|
||||
|
||||
/* set as mdc */
|
||||
bb = (picoByte_t*) buffer;
|
||||
mdc = (mdc_t*) buffer;
|
||||
|
||||
/* check ident and version */
|
||||
if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) || _pico_little_long( mdc->version ) != MDC_VERSION )
|
||||
{
|
||||
/* not an mdc file (todo: set error) */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* swap mdc */
|
||||
mdc->version = _pico_little_long( mdc->version );
|
||||
mdc->numFrames = _pico_little_long( mdc->numFrames );
|
||||
mdc->numTags = _pico_little_long( mdc->numTags );
|
||||
mdc->numSurfaces = _pico_little_long( mdc->numSurfaces );
|
||||
mdc->numSkins = _pico_little_long( mdc->numSkins );
|
||||
mdc->ofsFrames = _pico_little_long( mdc->ofsFrames );
|
||||
mdc->ofsTags = _pico_little_long( mdc->ofsTags );
|
||||
mdc->ofsTagNames = _pico_little_long( mdc->ofsTagNames );
|
||||
mdc->ofsSurfaces = _pico_little_long( mdc->ofsSurfaces );
|
||||
mdc->ofsEnd = _pico_little_long( mdc->ofsEnd );
|
||||
|
||||
/* do frame check */
|
||||
if( mdc->numFrames < 1 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "MDC with 0 frames" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( frameNum < 0 || frameNum >= mdc->numFrames )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid or out-of-range MDC frame specified" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* swap frames */
|
||||
frame = (mdcFrame_t*) (bb + mdc->ofsFrames );
|
||||
for( i = 0; i < mdc->numFrames; i++, frame++ )
|
||||
{
|
||||
frame->radius = _pico_little_float( frame->radius );
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
|
||||
frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
|
||||
frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
|
||||
}
|
||||
}
|
||||
|
||||
/* swap surfaces */
|
||||
surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces);
|
||||
for( i = 0; i < mdc->numSurfaces; i++ )
|
||||
{
|
||||
/* swap surface mdc */
|
||||
surface->flags = _pico_little_long( surface->flags );
|
||||
surface->numBaseFrames = _pico_little_long( surface->numBaseFrames );
|
||||
surface->numCompFrames = _pico_little_long( surface->numCompFrames );
|
||||
surface->numShaders = _pico_little_long( surface->numShaders );
|
||||
surface->numTriangles = _pico_little_long( surface->numTriangles );
|
||||
surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
|
||||
surface->numVerts = _pico_little_long( surface->numVerts );
|
||||
surface->ofsShaders = _pico_little_long( surface->ofsShaders );
|
||||
surface->ofsSt = _pico_little_long( surface->ofsSt );
|
||||
surface->ofsXyzNormals = _pico_little_long( surface->ofsXyzNormals );
|
||||
surface->ofsXyzCompressed = _pico_little_long( surface->ofsXyzCompressed );
|
||||
surface->ofsFrameBaseFrames = _pico_little_long( surface->ofsFrameBaseFrames );
|
||||
surface->ofsFrameCompFrames = _pico_little_long( surface->ofsFrameCompFrames );
|
||||
surface->ofsEnd = _pico_little_long( surface->ofsEnd );
|
||||
|
||||
/* swap triangles */
|
||||
triangle = (mdcTriangle_t*) ((picoByte_t*) surface + surface->ofsTriangles);
|
||||
for( j = 0; j < surface->numTriangles; j++, triangle++ )
|
||||
{
|
||||
/* sea: swaps fixed */
|
||||
triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
|
||||
triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
|
||||
triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
|
||||
}
|
||||
|
||||
/* swap st coords */
|
||||
texCoord = (mdcTexCoord_t*) ((picoByte_t*) surface + surface->ofsSt);
|
||||
for( j = 0; j < surface->numVerts; j++, texCoord++ )
|
||||
{
|
||||
texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
|
||||
texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
|
||||
}
|
||||
|
||||
/* swap xyz/normals */
|
||||
vertex = (mdcVertex_t*) ((picoByte_t*) surface + surface->ofsXyzNormals);
|
||||
for( j = 0; j < (surface->numVerts * surface->numBaseFrames); j++, vertex++)
|
||||
{
|
||||
vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
|
||||
vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
|
||||
vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
|
||||
vertex->normal = _pico_little_short( vertex->normal );
|
||||
}
|
||||
|
||||
/* swap xyz/compressed */
|
||||
vertexComp = (mdcXyzCompressed_t*) ((picoByte_t*) surface + surface->ofsXyzCompressed);
|
||||
for( j = 0; j < (surface->numVerts * surface->numCompFrames); j++, vertexComp++)
|
||||
{
|
||||
vertexComp->ofsVec = _pico_little_long( vertexComp->ofsVec );
|
||||
}
|
||||
|
||||
/* swap base frames */
|
||||
mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameBaseFrames);
|
||||
for( j = 0; j < mdc->numFrames; j++, mdcShort++)
|
||||
{
|
||||
*mdcShort = _pico_little_short( *mdcShort );
|
||||
}
|
||||
|
||||
/* swap compressed frames */
|
||||
mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameCompFrames);
|
||||
for( j = 0; j < mdc->numFrames; j++, mdcShort++)
|
||||
{
|
||||
*mdcShort = _pico_little_short( *mdcShort );
|
||||
}
|
||||
|
||||
/* get next surface */
|
||||
surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------
|
||||
pico model creation
|
||||
------------------------------------------------- */
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if( picoModel == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, mdc->numFrames ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
/* mdc surfaces become picomodel surfaces */
|
||||
surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces);
|
||||
|
||||
/* run through mdc surfaces */
|
||||
for( i = 0; i < mdc->numSurfaces; i++ )
|
||||
{
|
||||
/* allocate new pico surface */
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if( picoSurface == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel ); /* sea */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* mdc model surfaces are all triangle meshes */
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( picoSurface, surface->name );
|
||||
|
||||
/* create new pico shader -sea */
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if( picoShader == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detox and set shader name */
|
||||
shader = (mdcShader_t*) ((picoByte_t*) surface + surface->ofsShaders);
|
||||
_pico_setfext( shader->name, "" );
|
||||
_pico_unixify( shader->name );
|
||||
PicoSetShaderName( picoShader, shader->name );
|
||||
|
||||
/* associate current surface with newly created shader */
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
/* copy indexes */
|
||||
triangle = (mdcTriangle_t *) ((picoByte_t*) surface + surface->ofsTriangles);
|
||||
|
||||
for( j = 0; j < surface->numTriangles; j++, triangle++ )
|
||||
{
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] );
|
||||
}
|
||||
|
||||
/* copy vertexes */
|
||||
texCoord = (mdcTexCoord_t*) ((picoByte_t *) surface + surface->ofsSt);
|
||||
mdcShort = (short *) ((picoByte_t *) surface + surface->ofsXyzNormals) + ((int)*((short *) ((picoByte_t *) surface + surface->ofsFrameBaseFrames) + frameNum) * surface->numVerts * 4);
|
||||
if( surface->numCompFrames > 0 )
|
||||
{
|
||||
mdcCompVert = (short *) ((picoByte_t *) surface + surface->ofsFrameCompFrames) + frameNum;
|
||||
if( *mdcCompVert >= 0 )
|
||||
vertexComp = (mdcXyzCompressed_t *) ((picoByte_t *) surface + surface->ofsXyzCompressed) + (*mdcCompVert * surface->numVerts);
|
||||
}
|
||||
_pico_set_color( color, 255, 255, 255, 255 );
|
||||
|
||||
for( j = 0; j < surface->numVerts; j++, texCoord++, mdcShort+=4 )
|
||||
{
|
||||
/* set vertex origin */
|
||||
xyz[ 0 ] = MDC_SCALE * mdcShort[ 0 ];
|
||||
xyz[ 1 ] = MDC_SCALE * mdcShort[ 1 ];
|
||||
xyz[ 2 ] = MDC_SCALE * mdcShort[ 2 ];
|
||||
|
||||
/* add compressed ofsVec */
|
||||
if( surface->numCompFrames > 0 && *mdcCompVert >= 0 )
|
||||
{
|
||||
xyz[ 0 ] += ((float) ((vertexComp->ofsVec) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE;
|
||||
xyz[ 1 ] += ((float) ((vertexComp->ofsVec >> 8) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE;
|
||||
xyz[ 2 ] += ((float) ((vertexComp->ofsVec >> 16) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE;
|
||||
PicoSetSurfaceXYZ( picoSurface, j, xyz );
|
||||
|
||||
normal[ 0 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 0 ];
|
||||
normal[ 1 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 1 ];
|
||||
normal[ 2 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 2 ];
|
||||
PicoSetSurfaceNormal( picoSurface, j, normal );
|
||||
|
||||
vertexComp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
PicoSetSurfaceXYZ( picoSurface, j, xyz );
|
||||
|
||||
/* decode lat/lng normal to 3 float normal */
|
||||
lat = (float) ((*(mdcShort + 3) >> 8) & 0xff);
|
||||
lng = (float) (*(mdcShort + 3) & 0xff);
|
||||
lat *= PICO_PI / 128;
|
||||
lng *= PICO_PI / 128;
|
||||
normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
|
||||
normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
|
||||
normal[ 2 ] = (picoVec_t) cos( lng );
|
||||
PicoSetSurfaceNormal( picoSurface, j, normal );
|
||||
}
|
||||
|
||||
/* set st coords */
|
||||
st[ 0 ] = texCoord->st[ 0 ];
|
||||
st[ 1 ] = texCoord->st[ 1 ];
|
||||
PicoSetSurfaceST( picoSurface, 0, j, st );
|
||||
|
||||
/* set color */
|
||||
PicoSetSurfaceColor( picoSurface, 0, j, color );
|
||||
}
|
||||
|
||||
/* get next surface */
|
||||
surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd);
|
||||
}
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleMDC =
|
||||
{
|
||||
"1.3", /* module version string */
|
||||
"RtCW MDC", /* module display name */
|
||||
"Arnout van Meer", /* author's name */
|
||||
"2002 Arnout van Meer", /* module copyright */
|
||||
{
|
||||
"mdc", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_mdc_canload, /* validation routine */
|
||||
_mdc_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
494
libs/picomodel/pm_ms3d.c
Normal file
494
libs/picomodel/pm_ms3d.c
Normal file
@@ -0,0 +1,494 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_MS3D_C
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
/* disable warnings */
|
||||
#ifdef WIN32
|
||||
#pragma warning( disable:4100 ) /* unref param */
|
||||
#endif
|
||||
|
||||
/* remarks:
|
||||
* - loader seems stable
|
||||
* todo:
|
||||
* - fix uv coordinate problem
|
||||
* - check for buffer overflows ('bufptr' accesses)
|
||||
*/
|
||||
/* uncomment when debugging this module */
|
||||
#define DEBUG_PM_MS3D
|
||||
#define DEBUG_PM_MS3D_EX
|
||||
|
||||
/* plain white */
|
||||
static picoColor_t white = { 255,255,255,255 };
|
||||
|
||||
/* ms3d limits */
|
||||
#define MS3D_MAX_VERTS 8192
|
||||
#define MS3D_MAX_TRIS 16384
|
||||
#define MS3D_MAX_GROUPS 128
|
||||
#define MS3D_MAX_MATERIALS 128
|
||||
#define MS3D_MAX_JOINTS 128
|
||||
#define MS3D_MAX_KEYFRAMES 216
|
||||
|
||||
/* ms3d flags */
|
||||
#define MS3D_SELECTED 1
|
||||
#define MS3D_HIDDEN 2
|
||||
#define MS3D_SELECTED2 4
|
||||
#define MS3D_DIRTY 8
|
||||
|
||||
/* this freaky loader needs byte alignment */
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* ms3d header */
|
||||
typedef struct SMsHeader
|
||||
{
|
||||
char magic[10];
|
||||
int version;
|
||||
}
|
||||
TMsHeader;
|
||||
|
||||
/* ms3d vertex */
|
||||
typedef struct SMsVertex
|
||||
{
|
||||
unsigned char flags; /* sel, sel2, or hidden */
|
||||
float xyz[3];
|
||||
char boneID; /* -1 means 'no bone' */
|
||||
unsigned char refCount;
|
||||
}
|
||||
TMsVertex;
|
||||
|
||||
/* ms3d triangle */
|
||||
typedef struct SMsTriangle
|
||||
{
|
||||
unsigned short flags; /* sel, sel2, or hidden */
|
||||
unsigned short vertexIndices[3];
|
||||
float vertexNormals[3][3];
|
||||
float s[3];
|
||||
float t[3];
|
||||
unsigned char smoothingGroup; /* 1 - 32 */
|
||||
unsigned char groupIndex;
|
||||
}
|
||||
TMsTriangle;
|
||||
|
||||
/* ms3d material */
|
||||
typedef struct SMsMaterial
|
||||
{
|
||||
char name[32];
|
||||
float ambient[4];
|
||||
float diffuse[4];
|
||||
float specular[4];
|
||||
float emissive[4];
|
||||
float shininess; /* range 0..128 */
|
||||
float transparency; /* range 0..1 */
|
||||
unsigned char mode;
|
||||
char texture [128]; /* texture.bmp */
|
||||
char alphamap[128]; /* alpha.bmp */
|
||||
}
|
||||
TMsMaterial;
|
||||
|
||||
// ms3d group (static part)
|
||||
// followed by a variable size block (see below)
|
||||
typedef struct SMsGroup
|
||||
{
|
||||
unsigned char flags; // sel, hidden
|
||||
char name[32];
|
||||
unsigned short numTriangles;
|
||||
/*
|
||||
unsigned short triangleIndices[ numTriangles ];
|
||||
char materialIndex; // -1 means 'no material'
|
||||
*/
|
||||
}
|
||||
TMsGroup;
|
||||
|
||||
// ms3d joint
|
||||
typedef struct SMsJoint
|
||||
{
|
||||
unsigned char flags;
|
||||
char name[32];
|
||||
char parentName[32];
|
||||
float rotation[3];
|
||||
float translation[3];
|
||||
unsigned short numRotationKeyframes;
|
||||
unsigned short numTranslationKeyframes;
|
||||
}
|
||||
TMsJoint;
|
||||
|
||||
// ms3d keyframe
|
||||
typedef struct SMsKeyframe
|
||||
{
|
||||
float time;
|
||||
float parameter[3];
|
||||
}
|
||||
TMsKeyframe;
|
||||
|
||||
/* restore previous data alignment */
|
||||
#pragma pack(pop)
|
||||
|
||||
/* _ms3d_canload:
|
||||
* validates a milkshape3d model file.
|
||||
*/
|
||||
static int _ms3d_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
TMsHeader *hdr;
|
||||
|
||||
|
||||
/* to keep the compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* sanity check */
|
||||
if (bufSize < sizeof(TMsHeader))
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* get ms3d header */
|
||||
hdr = (TMsHeader *)buffer;
|
||||
|
||||
/* check ms3d magic */
|
||||
if (strncmp(hdr->magic,"MS3D000000",10) != 0)
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* check ms3d version */
|
||||
if (_pico_little_long(hdr->version) < 3 ||
|
||||
_pico_little_long(hdr->version) > 4)
|
||||
{
|
||||
_pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
}
|
||||
/* file seems to be a valid ms3d */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
static unsigned char *GetWord( unsigned char *bufptr, int *out )
|
||||
{
|
||||
if (bufptr == NULL) return NULL;
|
||||
*out = _pico_little_short( *(unsigned short *)bufptr );
|
||||
return( bufptr + 2 );
|
||||
}
|
||||
|
||||
/* _ms3d_load:
|
||||
* loads a milkshape3d model file.
|
||||
*/
|
||||
static picoModel_t *_ms3d_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
picoModel_t *model;
|
||||
unsigned char *bufptr;
|
||||
int shaderRefs[ MS3D_MAX_GROUPS ];
|
||||
int numGroups;
|
||||
int numMaterials;
|
||||
// unsigned char *ptrToGroups;
|
||||
int numVerts;
|
||||
unsigned char *ptrToVerts;
|
||||
int numTris;
|
||||
unsigned char *ptrToTris;
|
||||
int i,k,m;
|
||||
|
||||
/* create new pico model */
|
||||
model = PicoNewModel();
|
||||
if (model == NULL) return NULL;
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( model, frameNum );
|
||||
PicoSetModelName( model, fileName );
|
||||
PicoSetModelFileName( model, fileName );
|
||||
|
||||
/* skip header */
|
||||
bufptr = (unsigned char *)buffer + sizeof(TMsHeader);
|
||||
|
||||
/* get number of vertices */
|
||||
bufptr = GetWord( bufptr,&numVerts );
|
||||
ptrToVerts = bufptr;
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("NumVertices: %d\n",numVerts);
|
||||
#endif
|
||||
/* swap verts */
|
||||
for (i=0; i<numVerts; i++)
|
||||
{
|
||||
TMsVertex *vertex;
|
||||
vertex = (TMsVertex *)bufptr;
|
||||
bufptr += sizeof( TMsVertex );
|
||||
|
||||
vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
|
||||
vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
|
||||
vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
|
||||
|
||||
#ifdef DEBUG_PM_MS3D_EX_
|
||||
printf("Vertex: x: %f y: %f z: %f\n",
|
||||
msvd[i]->vertex[0],
|
||||
msvd[i]->vertex[1],
|
||||
msvd[i]->vertex[2]);
|
||||
#endif
|
||||
}
|
||||
/* get number of triangles */
|
||||
bufptr = GetWord( bufptr,&numTris );
|
||||
ptrToTris = bufptr;
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("NumTriangles: %d\n",numTris);
|
||||
#endif
|
||||
/* swap tris */
|
||||
for (i=0; i<numTris; i++)
|
||||
{
|
||||
TMsTriangle *triangle;
|
||||
triangle = (TMsTriangle *)bufptr;
|
||||
bufptr += sizeof( TMsTriangle );
|
||||
|
||||
triangle->flags = _pico_little_short( triangle->flags );
|
||||
|
||||
/* run through all tri verts */
|
||||
for (k=0; k<3; k++)
|
||||
{
|
||||
/* swap tex coords */
|
||||
triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
|
||||
triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
|
||||
|
||||
/* swap fields */
|
||||
triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
|
||||
triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
|
||||
triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
|
||||
triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
|
||||
|
||||
/* check for out of range indices */
|
||||
if (triangle->vertexIndices[ k ] >= numVerts)
|
||||
{
|
||||
_pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1);
|
||||
PicoFreeModel( model );
|
||||
return NULL; /* yuck */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* get number of groups */
|
||||
bufptr = GetWord( bufptr,&numGroups );
|
||||
// ptrToGroups = bufptr;
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("NumGroups: %d\n",numGroups);
|
||||
#endif
|
||||
/* run through all groups in model */
|
||||
for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++)
|
||||
{
|
||||
picoSurface_t *surface;
|
||||
TMsGroup *group;
|
||||
|
||||
group = (TMsGroup *)bufptr;
|
||||
bufptr += sizeof( TMsGroup );
|
||||
|
||||
/* we ignore hidden groups */
|
||||
if (group->flags & MS3D_HIDDEN)
|
||||
{
|
||||
bufptr += (group->numTriangles * 2) + 1;
|
||||
continue;
|
||||
}
|
||||
/* forced null term of group name */
|
||||
group->name[ 31 ] = '\0';
|
||||
|
||||
/* create new pico surface */
|
||||
surface = PicoNewSurface( model );
|
||||
if (surface == NULL)
|
||||
{
|
||||
PicoFreeModel( model );
|
||||
return NULL;
|
||||
}
|
||||
/* do surface setup */
|
||||
PicoSetSurfaceType( surface,PICO_TRIANGLES );
|
||||
PicoSetSurfaceName( surface,group->name );
|
||||
|
||||
/* process triangle indices */
|
||||
for (k=0; k<group->numTriangles; k++)
|
||||
{
|
||||
TMsTriangle *triangle;
|
||||
unsigned int triangleIndex;
|
||||
|
||||
/* get triangle index */
|
||||
bufptr = GetWord( bufptr,(int *)&triangleIndex );
|
||||
|
||||
/* get ptr to triangle data */
|
||||
triangle = (TMsTriangle *)(ptrToTris + (sizeof(TMsTriangle) * triangleIndex));
|
||||
|
||||
/* run through triangle vertices */
|
||||
for (m=0; m<3; m++)
|
||||
{
|
||||
TMsVertex *vertex;
|
||||
unsigned int vertexIndex;
|
||||
picoVec2_t texCoord;
|
||||
|
||||
/* get ptr to vertex data */
|
||||
vertexIndex = triangle->vertexIndices[ m ];
|
||||
vertex = (TMsVertex *)(ptrToVerts + (sizeof(TMsVertex) * vertexIndex));
|
||||
|
||||
/* store vertex origin */
|
||||
PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
|
||||
|
||||
/* store vertex color */
|
||||
PicoSetSurfaceColor( surface,0,vertexIndex,white );
|
||||
|
||||
/* store vertex normal */
|
||||
PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
|
||||
|
||||
/* store current face vertex index */
|
||||
PicoSetSurfaceIndex( surface,(k * 3 + (2 - m)),(picoIndex_t)vertexIndex );
|
||||
|
||||
/* get texture vertex coord */
|
||||
texCoord[ 0 ] = triangle->s[ m ];
|
||||
texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
|
||||
|
||||
/* store texture vertex coord */
|
||||
PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
|
||||
}
|
||||
}
|
||||
/* store material */
|
||||
shaderRefs[ i ] = *bufptr++;
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles);
|
||||
#endif
|
||||
}
|
||||
/* get number of materials */
|
||||
bufptr = GetWord( bufptr,&numMaterials );
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("NumMaterials: %d\n",numMaterials);
|
||||
#endif
|
||||
/* run through all materials in model */
|
||||
for (i=0; i<numMaterials; i++)
|
||||
{
|
||||
picoShader_t *shader;
|
||||
picoColor_t ambient,diffuse,specular;
|
||||
TMsMaterial *material;
|
||||
int k;
|
||||
|
||||
material = (TMsMaterial *)bufptr;
|
||||
bufptr += sizeof( TMsMaterial );
|
||||
|
||||
/* null term strings */
|
||||
material->name [ 31 ] = '\0';
|
||||
material->texture [ 127 ] = '\0';
|
||||
material->alphamap[ 127 ] = '\0';
|
||||
|
||||
/* ltrim strings */
|
||||
_pico_strltrim( material->name );
|
||||
_pico_strltrim( material->texture );
|
||||
_pico_strltrim( material->alphamap );
|
||||
|
||||
/* rtrim strings */
|
||||
_pico_strrtrim( material->name );
|
||||
_pico_strrtrim( material->texture );
|
||||
_pico_strrtrim( material->alphamap );
|
||||
|
||||
/* create new pico shader */
|
||||
shader = PicoNewShader( model );
|
||||
if (shader == NULL)
|
||||
{
|
||||
PicoFreeModel( model );
|
||||
return NULL;
|
||||
}
|
||||
/* scale shader colors */
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
ambient [ k ] = (picoByte_t) (material->ambient[ k ] * 255);
|
||||
diffuse [ k ] = (picoByte_t) (material->diffuse[ k ] * 255);
|
||||
specular[ k ] = (picoByte_t) (material->specular[ k ] * 255);
|
||||
}
|
||||
/* set shader colors */
|
||||
PicoSetShaderAmbientColor( shader,ambient );
|
||||
PicoSetShaderDiffuseColor( shader,diffuse );
|
||||
PicoSetShaderSpecularColor( shader,specular );
|
||||
|
||||
/* set shader transparency */
|
||||
PicoSetShaderTransparency( shader,material->transparency );
|
||||
|
||||
/* set shader shininess (0..127) */
|
||||
PicoSetShaderShininess( shader,material->shininess );
|
||||
|
||||
/* set shader name */
|
||||
PicoSetShaderName( shader,material->name );
|
||||
|
||||
/* set shader texture map name */
|
||||
PicoSetShaderMapName( shader,material->texture );
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap);
|
||||
#endif
|
||||
}
|
||||
/* assign shaders to surfaces */
|
||||
for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++)
|
||||
{
|
||||
picoSurface_t *surface;
|
||||
picoShader_t *shader;
|
||||
|
||||
/* sanity check */
|
||||
if (shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
|
||||
shaderRefs[ i ] < 0)
|
||||
continue;
|
||||
|
||||
/* get surface */
|
||||
surface = PicoGetModelSurface( model,i );
|
||||
if (surface == NULL) continue;
|
||||
|
||||
/* get shader */
|
||||
shader = PicoGetModelShader( model,shaderRefs[ i ] );
|
||||
if (shader == NULL) continue;
|
||||
|
||||
/* assign shader */
|
||||
PicoSetSurfaceShader( surface,shader );
|
||||
|
||||
#ifdef DEBUG_PM_MS3D
|
||||
printf("Mapped: %d ('%s') to %d (%s)\n",
|
||||
shaderRefs[i],shader->name,i,surface->name);
|
||||
#endif
|
||||
}
|
||||
/* return allocated pico model */
|
||||
return model;
|
||||
// return NULL;
|
||||
}
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleMS3D =
|
||||
{
|
||||
"0.4-a", /* module version string */
|
||||
"Milkshape 3D", /* module display name */
|
||||
"seaw0lf", /* author's name */
|
||||
"2002 seaw0lf", /* module copyright */
|
||||
{
|
||||
"ms3d",NULL,NULL,NULL /* default extensions to use */
|
||||
},
|
||||
_ms3d_canload, /* validation routine */
|
||||
_ms3d_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
858
libs/picomodel/pm_obj.c
Normal file
858
libs/picomodel/pm_obj.c
Normal file
@@ -0,0 +1,858 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2002, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_OBJ_C
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
/* disable warnings */
|
||||
#ifdef WIN32
|
||||
#pragma warning( disable:4100 ) /* unref param */
|
||||
#endif
|
||||
|
||||
/* todo:
|
||||
* - '_obj_load' code crashes in a weird way after
|
||||
* '_obj_mtl_load' for a few .mtl files
|
||||
* - process 'mtllib' rather than using <model>.mtl
|
||||
* - handle 'usemtl' statements
|
||||
*/
|
||||
/* uncomment when debugging this module */
|
||||
/* #define DEBUG_PM_OBJ */
|
||||
/* #define DEBUG_PM_OBJ_EX */
|
||||
|
||||
/* this holds temporary vertex data read by parser */
|
||||
typedef struct SObjVertexData
|
||||
{
|
||||
picoVec3_t v; /* geometric vertices */
|
||||
picoVec2_t vt; /* texture vertices */
|
||||
picoVec3_t vn; /* vertex normals (optional) */
|
||||
}
|
||||
TObjVertexData;
|
||||
|
||||
/* _obj_canload:
|
||||
* validates a wavefront obj model file.
|
||||
*/
|
||||
static int _obj_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
picoParser_t *p;
|
||||
|
||||
/* check data length */
|
||||
if (bufSize < 30)
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
/* first check file extension. we have to do this for objs */
|
||||
/* cause there is no good way to identify the contents */
|
||||
if (_pico_stristr(fileName,".obj") != NULL ||
|
||||
_pico_stristr(fileName,".wf" ) != NULL)
|
||||
{
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
/* if the extension check failed we parse through the first */
|
||||
/* few lines in file and look for common keywords often */
|
||||
/* appearing at the beginning of wavefront objects */
|
||||
|
||||
/* alllocate a new pico parser */
|
||||
p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
|
||||
if (p == NULL)
|
||||
return PICO_PMV_ERROR_MEMORY;
|
||||
|
||||
/* parse obj head line by line for type check */
|
||||
while( 1 )
|
||||
{
|
||||
/* get first token on line */
|
||||
if (_pico_parse_first( p ) == NULL)
|
||||
break;
|
||||
|
||||
/* we only parse the first few lines, say 80 */
|
||||
if (p->curLine > 80)
|
||||
break;
|
||||
|
||||
/* skip empty lines */
|
||||
if (p->token == NULL || !strlen( p->token ))
|
||||
continue;
|
||||
|
||||
/* material library keywords are teh good */
|
||||
if (!_pico_stricmp(p->token,"usemtl") ||
|
||||
!_pico_stricmp(p->token,"mtllib") ||
|
||||
!_pico_stricmp(p->token,"g") ||
|
||||
!_pico_stricmp(p->token,"v")) /* v,g bit fishy, but uh... */
|
||||
{
|
||||
/* free the pico parser thing */
|
||||
_pico_free_parser( p );
|
||||
|
||||
/* seems to be a valid wavefront obj */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
/* skip rest of line */
|
||||
_pico_parse_skip_rest( p );
|
||||
}
|
||||
/* free the pico parser thing */
|
||||
_pico_free_parser( p );
|
||||
|
||||
/* doesn't really look like an obj to us */
|
||||
return PICO_PMV_ERROR;
|
||||
}
|
||||
|
||||
/* SizeObjVertexData:
|
||||
* This pretty piece of 'alloc ahead' code dynamically
|
||||
* allocates - and reallocates as soon as required -
|
||||
* my vertex data array in even steps.
|
||||
*/
|
||||
#define SIZE_OBJ_STEP 4096
|
||||
|
||||
static TObjVertexData *SizeObjVertexData(
|
||||
TObjVertexData *vertexData, int reqEntries,
|
||||
int *entries, int *allocated)
|
||||
{
|
||||
int newAllocated;
|
||||
|
||||
/* sanity checks */
|
||||
if (reqEntries < 1)
|
||||
return NULL;
|
||||
if (entries == NULL || allocated == NULL)
|
||||
return NULL; /* must have */
|
||||
|
||||
/* no need to grow yet */
|
||||
if (vertexData && (reqEntries < *allocated))
|
||||
{
|
||||
*entries = reqEntries;
|
||||
return vertexData;
|
||||
}
|
||||
/* given vertex data ptr not allocated yet */
|
||||
if (vertexData == NULL)
|
||||
{
|
||||
/* how many entries to allocate */
|
||||
newAllocated = (reqEntries > SIZE_OBJ_STEP) ?
|
||||
reqEntries : SIZE_OBJ_STEP;
|
||||
|
||||
/* throw out an extended debug message */
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("SizeObjVertexData: allocate (%d entries)\n",
|
||||
newAllocated);
|
||||
#endif
|
||||
/* first time allocation */
|
||||
vertexData = (TObjVertexData *)
|
||||
_pico_alloc( sizeof(TObjVertexData) * newAllocated );
|
||||
|
||||
/* allocation failed */
|
||||
if (vertexData == NULL)
|
||||
return NULL;
|
||||
|
||||
/* allocation succeeded */
|
||||
*allocated = newAllocated;
|
||||
*entries = reqEntries;
|
||||
return vertexData;
|
||||
}
|
||||
/* given vertex data ptr needs to be resized */
|
||||
if (reqEntries == *allocated)
|
||||
{
|
||||
newAllocated = (*allocated + SIZE_OBJ_STEP);
|
||||
|
||||
/* throw out an extended debug message */
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("SizeObjVertexData: reallocate (%d entries)\n",
|
||||
newAllocated);
|
||||
#endif
|
||||
/* try to reallocate */
|
||||
vertexData = (TObjVertexData *)
|
||||
_pico_realloc( (void *)&vertexData,
|
||||
sizeof(TObjVertexData) * (*allocated),
|
||||
sizeof(TObjVertexData) * (newAllocated));
|
||||
|
||||
/* reallocation failed */
|
||||
if (vertexData == NULL)
|
||||
return NULL;
|
||||
|
||||
/* reallocation succeeded */
|
||||
*allocated = newAllocated;
|
||||
*entries = reqEntries;
|
||||
return vertexData;
|
||||
}
|
||||
/* we're b0rked when we reach this */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void FreeObjVertexData( TObjVertexData *vertexData )
|
||||
{
|
||||
if (vertexData != NULL)
|
||||
{
|
||||
free( (TObjVertexData *)vertexData );
|
||||
}
|
||||
}
|
||||
|
||||
static int _obj_mtl_load( picoModel_t *model )
|
||||
{
|
||||
picoShader_t *curShader = NULL;
|
||||
picoParser_t *p;
|
||||
picoByte_t *mtlBuffer;
|
||||
int mtlBufSize;
|
||||
char *fileName;
|
||||
|
||||
/* sanity checks */
|
||||
if( model == NULL || model->fileName == NULL )
|
||||
return 0;
|
||||
|
||||
/* skip if we have a zero length model file name */
|
||||
if (!strlen( model->fileName ))
|
||||
return 0;
|
||||
|
||||
/* helper */
|
||||
#define _obj_mtl_error_return \
|
||||
{ \
|
||||
_pico_free_parser( p ); \
|
||||
_pico_free_file( mtlBuffer ); \
|
||||
_pico_free( fileName ); \
|
||||
return 0; \
|
||||
}
|
||||
/* alloc copy of model file name */
|
||||
fileName = _pico_clone_alloc( model->fileName );
|
||||
if (fileName == NULL)
|
||||
return 0;
|
||||
|
||||
/* change extension of model file to .mtl */
|
||||
_pico_setfext( fileName, "mtl" );
|
||||
|
||||
/* load .mtl file contents */
|
||||
_pico_load_file( fileName,&mtlBuffer,&mtlBufSize );
|
||||
|
||||
/* check result */
|
||||
if (mtlBufSize == 0) return 1; /* file is empty: no error */
|
||||
if (mtlBufSize < 0) return 0; /* load failed: error */
|
||||
|
||||
/* create a new pico parser */
|
||||
p = _pico_new_parser( mtlBuffer, mtlBufSize );
|
||||
if (p == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* doo teh .mtl parse */
|
||||
while( 1 )
|
||||
{
|
||||
/* get next token in material file */
|
||||
if (_pico_parse( p,1 ) == NULL)
|
||||
break;
|
||||
#if 0
|
||||
|
||||
/* skip empty lines */
|
||||
if (p->token == NULL || !strlen( p->token ))
|
||||
continue;
|
||||
|
||||
/* skip comment lines */
|
||||
if (p->token[0] == '#')
|
||||
{
|
||||
_pico_parse_skip_rest( p );
|
||||
continue;
|
||||
}
|
||||
/* new material */
|
||||
if (!_pico_stricmp(p->token,"newmtl"))
|
||||
{
|
||||
picoShader_t *shader;
|
||||
char *name;
|
||||
|
||||
/* get material name */
|
||||
name = _pico_parse( p,0 );
|
||||
|
||||
/* validate material name */
|
||||
if (name == NULL || !strlen(name))
|
||||
{
|
||||
_pico_printf( PICO_ERROR,"Missing material name in MTL, line %d.",p->curLine);
|
||||
_obj_mtl_error_return;
|
||||
}
|
||||
/* create a new pico shader */
|
||||
shader = PicoNewShader( model );
|
||||
if (shader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* set shader name */
|
||||
PicoSetShaderName( shader,name );
|
||||
|
||||
/* assign pointer to current shader */
|
||||
curShader = shader;
|
||||
}
|
||||
/* diffuse map name */
|
||||
else if (!_pico_stricmp(p->token,"map_kd"))
|
||||
{
|
||||
char *mapName;
|
||||
|
||||
/* pointer to current shader must be valid */
|
||||
if (curShader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* get material's diffuse map name */
|
||||
mapName = _pico_parse( p,0 );
|
||||
|
||||
/* validate map name */
|
||||
if (mapName == NULL || !strlen(mapName))
|
||||
{
|
||||
_pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
|
||||
_obj_mtl_error_return;
|
||||
}
|
||||
/* set shader map name */
|
||||
PicoSetShaderMapName( shader,mapName );
|
||||
}
|
||||
/* dissolve factor (pseudo transparency 0..1) */
|
||||
/* where 0 means 100% transparent and 1 means opaque */
|
||||
else if (!_pico_stricmp(p->token,"d"))
|
||||
{
|
||||
picoByte_t *diffuse;
|
||||
float value;
|
||||
|
||||
|
||||
/* get dissolve factor */
|
||||
if (!_pico_parse_float( p,&value ))
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* set shader transparency */
|
||||
PicoSetShaderTransparency( curShader,value );
|
||||
|
||||
/* get shader's diffuse color */
|
||||
diffuse = PicoGetShaderDiffuseColor( curShader );
|
||||
|
||||
/* set diffuse alpha to transparency */
|
||||
diffuse[ 3 ] = (picoByte_t)( value * 255.0 );
|
||||
|
||||
/* set shader's new diffuse color */
|
||||
PicoSetShaderDiffuseColor( curShader,diffuse );
|
||||
}
|
||||
/* shininess (phong specular component) */
|
||||
else if (!_pico_stricmp(p->token,"ns"))
|
||||
{
|
||||
/* remark:
|
||||
* - well, this is some major obj spec fuckup once again. some
|
||||
* apps store this in 0..1 range, others use 0..100 range,
|
||||
* even others use 0..2048 range, and again others use the
|
||||
* range 0..128, some even use 0..1000, 0..200, 400..700,
|
||||
* honestly, what's up with the 3d app coders? happens when
|
||||
* you smoke too much weed i guess. -sea
|
||||
*/
|
||||
float value;
|
||||
|
||||
/* pointer to current shader must be valid */
|
||||
if (curShader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* get totally screwed up shininess (a random value in fact ;) */
|
||||
if (!_pico_parse_float( p,&value ))
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* okay, there is no way to set this correctly, so we simply */
|
||||
/* try to guess a few ranges (most common ones i have seen) */
|
||||
|
||||
/* assume 0..2048 range */
|
||||
if (value > 1000)
|
||||
value = 128.0 * (value / 2048.0);
|
||||
/* assume 0..1000 range */
|
||||
else if (value > 200)
|
||||
value = 128.0 * (value / 1000.0);
|
||||
/* assume 0..200 range */
|
||||
else if (value > 100)
|
||||
value = 128.0 * (value / 200.0);
|
||||
/* assume 0..100 range */
|
||||
else if (value > 1)
|
||||
value = 128.0 * (value / 100.0);
|
||||
/* assume 0..1 range */
|
||||
else {
|
||||
value *= 128.0;
|
||||
}
|
||||
/* negative shininess is bad (yes, i have seen it...) */
|
||||
if (value < 0.0) value = 0.0;
|
||||
|
||||
/* set the pico shininess value in range 0..127 */
|
||||
/* geez, .obj is such a mess... */
|
||||
PicoSetShaderShininess( curShader,value );
|
||||
}
|
||||
/* kol0r ambient (wut teh fuk does "ka" stand for?) */
|
||||
else if (!_pico_stricmp(p->token,"ka"))
|
||||
{
|
||||
picoColor_t color;
|
||||
picoVec3_t v;
|
||||
|
||||
/* pointer to current shader must be valid */
|
||||
if (curShader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* get color vector */
|
||||
if (!_pico_parse_vec( p,v ))
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* scale to byte range */
|
||||
color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
|
||||
color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
|
||||
color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
|
||||
color[ 3 ] = (picoByte_t)( 255 );
|
||||
|
||||
/* set ambient color */
|
||||
PicoSetShaderAmbientColor( curShader,color );
|
||||
}
|
||||
/* kol0r diffuse */
|
||||
else if (!_pico_stricmp(p->token,"kd"))
|
||||
{
|
||||
picoColor_t color;
|
||||
picoVec3_t v;
|
||||
|
||||
/* pointer to current shader must be valid */
|
||||
if (curShader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* get color vector */
|
||||
if (!_pico_parse_vec( p,v ))
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* scale to byte range */
|
||||
color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
|
||||
color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
|
||||
color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
|
||||
color[ 3 ] = (picoByte_t)( 255 );
|
||||
|
||||
/* set diffuse color */
|
||||
PicoSetShaderDiffuseColor( curShader,color );
|
||||
}
|
||||
/* kol0r specular */
|
||||
else if (!_pico_stricmp(p->token,"ks"))
|
||||
{
|
||||
picoColor_t color;
|
||||
picoVec3_t v;
|
||||
|
||||
/* pointer to current shader must be valid */
|
||||
if (curShader == NULL)
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* get color vector */
|
||||
if (!_pico_parse_vec( p,v ))
|
||||
_obj_mtl_error_return;
|
||||
|
||||
/* scale to byte range */
|
||||
color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
|
||||
color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
|
||||
color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
|
||||
color[ 3 ] = (picoByte_t)( 255 );
|
||||
|
||||
/* set specular color */
|
||||
PicoSetShaderSpecularColor( curShader,color );
|
||||
}
|
||||
#endif
|
||||
/* skip rest of line */
|
||||
_pico_parse_skip_rest( p );
|
||||
}
|
||||
|
||||
/* free parser, file buffer, and file name */
|
||||
_pico_free_parser( p );
|
||||
_pico_free_file( mtlBuffer );
|
||||
_pico_free( fileName );
|
||||
|
||||
/* return with success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* _obj_load:
|
||||
* loads a wavefront obj model file.
|
||||
*/
|
||||
static picoModel_t *_obj_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
TObjVertexData *vertexData = NULL;
|
||||
picoModel_t *model;
|
||||
picoSurface_t *curSurface = NULL;
|
||||
picoParser_t *p;
|
||||
int allocated;
|
||||
int entries;
|
||||
int numVerts = 0;
|
||||
int numNormals = 0;
|
||||
int numUVs = 0;
|
||||
int curVertex = 0;
|
||||
int curFace = 0;
|
||||
|
||||
/* helper */
|
||||
#define _obj_error_return(m) \
|
||||
{ \
|
||||
_pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \
|
||||
_pico_free_parser( p ); \
|
||||
FreeObjVertexData( vertexData ); \
|
||||
PicoFreeModel( model ); \
|
||||
return NULL; \
|
||||
}
|
||||
/* alllocate a new pico parser */
|
||||
p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
|
||||
if (p == NULL) return NULL;
|
||||
|
||||
/* create a new pico model */
|
||||
model = PicoNewModel();
|
||||
if (model == NULL)
|
||||
{
|
||||
_pico_free_parser( p );
|
||||
return NULL;
|
||||
}
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( model,frameNum );
|
||||
PicoSetModelName( model,fileName );
|
||||
PicoSetModelFileName( model,fileName );
|
||||
|
||||
/* try loading the materials; we don't handle the result */
|
||||
#if 0
|
||||
_obj_mtl_load( model );
|
||||
#endif
|
||||
|
||||
/* parse obj line by line */
|
||||
while( 1 )
|
||||
{
|
||||
/* get first token on line */
|
||||
if (_pico_parse_first( p ) == NULL)
|
||||
break;
|
||||
|
||||
/* skip empty lines */
|
||||
if (p->token == NULL || !strlen( p->token ))
|
||||
continue;
|
||||
|
||||
/* skip comment lines */
|
||||
if (p->token[0] == '#')
|
||||
{
|
||||
_pico_parse_skip_rest( p );
|
||||
continue;
|
||||
}
|
||||
/* vertex */
|
||||
if (!_pico_stricmp(p->token,"v"))
|
||||
{
|
||||
TObjVertexData *data;
|
||||
picoVec3_t v;
|
||||
|
||||
vertexData = SizeObjVertexData( vertexData,numVerts+1,&entries,&allocated );
|
||||
if (vertexData == NULL)
|
||||
_obj_error_return("Realloc of vertex data failed (1)");
|
||||
|
||||
data = &vertexData[ numVerts++ ];
|
||||
|
||||
/* get and copy vertex */
|
||||
if (!_pico_parse_vec( p,v ))
|
||||
_obj_error_return("Vertex parse error");
|
||||
|
||||
_pico_copy_vec( v,data->v );
|
||||
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]);
|
||||
#endif
|
||||
}
|
||||
/* uv coord */
|
||||
else if (!_pico_stricmp(p->token,"vt"))
|
||||
{
|
||||
TObjVertexData *data;
|
||||
picoVec2_t coord;
|
||||
|
||||
vertexData = SizeObjVertexData( vertexData,numUVs+1,&entries,&allocated );
|
||||
if (vertexData == NULL)
|
||||
_obj_error_return("Realloc of vertex data failed (2)");
|
||||
|
||||
data = &vertexData[ numUVs++ ];
|
||||
|
||||
/* get and copy tex coord */
|
||||
if (!_pico_parse_vec2( p,coord ))
|
||||
_obj_error_return("UV coord parse error");
|
||||
|
||||
_pico_copy_vec2( coord,data->vt );
|
||||
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]);
|
||||
#endif
|
||||
}
|
||||
/* vertex normal */
|
||||
else if (!_pico_stricmp(p->token,"vn"))
|
||||
{
|
||||
TObjVertexData *data;
|
||||
picoVec3_t n;
|
||||
|
||||
vertexData = SizeObjVertexData( vertexData,numNormals+1,&entries,&allocated );
|
||||
if (vertexData == NULL)
|
||||
_obj_error_return("Realloc of vertex data failed (3)");
|
||||
|
||||
data = &vertexData[ numNormals++ ];
|
||||
|
||||
/* get and copy vertex normal */
|
||||
if (!_pico_parse_vec( p,n ))
|
||||
_obj_error_return("Vertex normal parse error");
|
||||
|
||||
_pico_copy_vec( n,data->vn );
|
||||
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]);
|
||||
#endif
|
||||
}
|
||||
/* new group (for us this means a new surface) */
|
||||
else if (!_pico_stricmp(p->token,"g"))
|
||||
{
|
||||
picoSurface_t *newSurface;
|
||||
char *groupName;
|
||||
|
||||
/* get first group name (ignore 2nd,3rd,etc.) */
|
||||
groupName = _pico_parse( p,0 );
|
||||
if (groupName == NULL || !strlen(groupName))
|
||||
{
|
||||
/* some obj exporters feel like they don't need to */
|
||||
/* supply a group name. so we gotta handle it here */
|
||||
#if 1
|
||||
strcpy( p->token,"default" );
|
||||
groupName = p->token;
|
||||
#else
|
||||
_obj_error_return("Invalid or missing group name");
|
||||
#endif
|
||||
}
|
||||
/* allocate a pico surface */
|
||||
newSurface = PicoNewSurface( model );
|
||||
if (newSurface == NULL)
|
||||
_obj_error_return("Error allocating surface");
|
||||
|
||||
/* reset face index for surface */
|
||||
curFace = 0;
|
||||
|
||||
/* set ptr to current surface */
|
||||
curSurface = newSurface;
|
||||
|
||||
/* we use triangle meshes */
|
||||
PicoSetSurfaceType( newSurface,PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( newSurface,groupName );
|
||||
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("Group: '%s'\n",groupName);
|
||||
#endif
|
||||
}
|
||||
/* face (oh jesus, hopefully this will do the job right ;) */
|
||||
else if (!_pico_stricmp(p->token,"f"))
|
||||
{
|
||||
/* okay, this is a mess. some 3d apps seem to try being unique, */
|
||||
/* hello cinema4d & 3d exploration, feel good today?, and save */
|
||||
/* this crap in tons of different formats. gah, those screwed */
|
||||
/* coders. tho the wavefront obj standard defines exactly two */
|
||||
/* ways of storing face information. so, i really won't support */
|
||||
/* such stupid extravaganza here! */
|
||||
|
||||
picoVec3_t verts [ 4 ];
|
||||
picoVec3_t normals[ 4 ];
|
||||
picoVec2_t coords [ 4 ];
|
||||
|
||||
int iv [ 4 ], has_v;
|
||||
int ivt[ 4 ], has_vt = 0;
|
||||
int ivn[ 4 ], has_vn = 0;
|
||||
int have_quad = 0;
|
||||
int slashcount;
|
||||
int doubleslash;
|
||||
int i;
|
||||
|
||||
/* group defs *must* come before faces */
|
||||
if (curSurface == NULL)
|
||||
_obj_error_return("No group defined for faces");
|
||||
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("Face: ");
|
||||
#endif
|
||||
/* read vertex/uv/normal indices for the first three face */
|
||||
/* vertices (cause we only support triangles) into 'i*[]' */
|
||||
/* store the actual vertex/uv/normal data in three arrays */
|
||||
/* called 'verts','coords' and 'normals'. */
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
char *str;
|
||||
|
||||
/* get next vertex index string (different */
|
||||
/* formats are handled below) */
|
||||
str = _pico_parse( p,0 );
|
||||
if (str == NULL)
|
||||
{
|
||||
/* just break for quads */
|
||||
if (i == 3) break;
|
||||
|
||||
/* error otherwise */
|
||||
_obj_error_return("Face parse error");
|
||||
}
|
||||
/* if this is the fourth index string we're */
|
||||
/* parsing we assume that we have a quad */
|
||||
if (i == 3)
|
||||
have_quad = 1;
|
||||
|
||||
/* get slash count once */
|
||||
if (i == 0)
|
||||
{
|
||||
slashcount = _pico_strchcount( str,'/' );
|
||||
doubleslash = strstr(str,"//") != NULL;
|
||||
}
|
||||
/* handle format 'v//vn' */
|
||||
if (doubleslash && (slashcount == 2))
|
||||
{
|
||||
has_v = has_vn = 1;
|
||||
sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] );
|
||||
}
|
||||
/* handle format 'v/vt/vn' */
|
||||
else if (!doubleslash && (slashcount == 2))
|
||||
{
|
||||
has_v = has_vt = has_vn = 1;
|
||||
sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] );
|
||||
}
|
||||
/* handle format 'v/vt' (non-standard fuckage) */
|
||||
else if (!doubleslash && (slashcount == 1))
|
||||
{
|
||||
has_v = has_vt = 1;
|
||||
sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] );
|
||||
}
|
||||
/* else assume face format 'v' */
|
||||
/* (must have been invented by some bored granny) */
|
||||
else {
|
||||
/* get single vertex index */
|
||||
has_v = 1;
|
||||
iv[ i ] = atoi( str );
|
||||
|
||||
/* either invalid face format or out of range */
|
||||
if (iv[ i ] == 0)
|
||||
_obj_error_return("Invalid face format");
|
||||
}
|
||||
/* fix useless back references */
|
||||
/* todo: check if this works as it is supposed to */
|
||||
|
||||
/* assign new indices */
|
||||
if (iv [ i ] < 0) iv [ i ] = (numVerts - iv [ i ]);
|
||||
if (ivt[ i ] < 0) ivt[ i ] = (numUVs - ivt[ i ]);
|
||||
if (ivn[ i ] < 0) ivn[ i ] = (numNormals - ivn[ i ]);
|
||||
|
||||
/* validate indices */
|
||||
/* - commented out. index range checks will trigger
|
||||
if (iv [ i ] < 1) iv [ i ] = 1;
|
||||
if (ivt[ i ] < 1) ivt[ i ] = 1;
|
||||
if (ivn[ i ] < 1) ivn[ i ] = 1;
|
||||
*/
|
||||
/* set vertex origin */
|
||||
if (has_v)
|
||||
{
|
||||
/* check vertex index range */
|
||||
if (iv[ i ] < 1 || iv[ i ] > numVerts)
|
||||
_obj_error_return("Vertex index out of range");
|
||||
|
||||
/* get vertex data */
|
||||
verts[ i ][ 0 ] = vertexData[ iv[ i ] - 1 ].v[ 0 ];
|
||||
verts[ i ][ 1 ] = vertexData[ iv[ i ] - 1 ].v[ 1 ];
|
||||
verts[ i ][ 2 ] = vertexData[ iv[ i ] - 1 ].v[ 2 ];
|
||||
}
|
||||
/* set vertex normal */
|
||||
if (has_vn)
|
||||
{
|
||||
/* check normal index range */
|
||||
if (ivn[ i ] < 1 || ivn[ i ] > numNormals)
|
||||
_obj_error_return("Normal index out of range");
|
||||
|
||||
/* get normal data */
|
||||
normals[ i ][ 0 ] = vertexData[ ivn[ i ] - 1 ].vn[ 0 ];
|
||||
normals[ i ][ 1 ] = vertexData[ ivn[ i ] - 1 ].vn[ 1 ];
|
||||
normals[ i ][ 2 ] = vertexData[ ivn[ i ] - 1 ].vn[ 2 ];
|
||||
}
|
||||
/* set texture coordinate */
|
||||
if (has_vt)
|
||||
{
|
||||
/* check uv index range */
|
||||
if (ivt[ i ] < 1 || ivt[ i ] > numUVs)
|
||||
_obj_error_return("UV coord index out of range");
|
||||
|
||||
/* get uv coord data */
|
||||
coords[ i ][ 0 ] = vertexData[ ivt[ i ] - 1 ].vt[ 0 ];
|
||||
coords[ i ][ 1 ] = vertexData[ ivt[ i ] - 1 ].vt[ 1 ];
|
||||
coords[ i ][ 1 ] = -coords[ i ][ 1 ];
|
||||
}
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("(%4d",iv[ i ]);
|
||||
if (has_vt) printf(" %4d",ivt[ i ]);
|
||||
if (has_vn) printf(" %4d",ivn[ i ]);
|
||||
printf(") ");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_PM_OBJ_EX
|
||||
printf("\n");
|
||||
#endif
|
||||
/* now that we have extracted all the indices and have */
|
||||
/* read the actual data we need to assign all the crap */
|
||||
/* to our current pico surface */
|
||||
if (has_v)
|
||||
{
|
||||
int max = 3;
|
||||
if (have_quad) max = 4;
|
||||
|
||||
/* assign all surface information */
|
||||
for (i=0; i<max; i++)
|
||||
{
|
||||
/*if( has_v )*/ PicoSetSurfaceXYZ ( curSurface, (curVertex + i), verts [ i ] );
|
||||
/*if( has_vt )*/ PicoSetSurfaceST ( curSurface,0,(curVertex + i), coords [ i ] );
|
||||
/*if( has_vn )*/ PicoSetSurfaceNormal( curSurface, (curVertex + i), normals[ i ] );
|
||||
}
|
||||
/* add our triangle (A B C) */
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 1 ) );
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 2 ) );
|
||||
curFace++;
|
||||
|
||||
/* if we don't have a simple triangle, but a quad... */
|
||||
if (have_quad)
|
||||
{
|
||||
/* we have to add another triangle (2nd half of quad which is A C D) */
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 2 ) );
|
||||
PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 3 ) );
|
||||
curFace++;
|
||||
}
|
||||
/* increase vertex count */
|
||||
curVertex += max;
|
||||
}
|
||||
}
|
||||
/* skip unparsed rest of line and continue */
|
||||
_pico_parse_skip_rest( p );
|
||||
}
|
||||
/* free memory used by temporary vertexdata */
|
||||
FreeObjVertexData( vertexData );
|
||||
|
||||
/* return allocated pico model */
|
||||
return model;
|
||||
// return NULL;
|
||||
}
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleOBJ =
|
||||
{
|
||||
"0.6-b", /* module version string */
|
||||
"Wavefront ASCII", /* module display name */
|
||||
"seaw0lf", /* author's name */
|
||||
"2002 seaw0lf", /* module copyright */
|
||||
{
|
||||
"obj",NULL,NULL,NULL /* default extensions to use */
|
||||
},
|
||||
_obj_canload, /* validation routine */
|
||||
_obj_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
610
libs/picomodel/pm_terrain.c
Normal file
610
libs/picomodel/pm_terrain.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
||||
PicoModel Library
|
||||
|
||||
Copyright (c) 2003, Randy Reddig & seaw0lf
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* marker */
|
||||
#define PM_TERRAIN_C
|
||||
|
||||
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
|
||||
|
||||
|
||||
typedef struct tga_s
|
||||
{
|
||||
unsigned char id_length, colormap_type, image_type;
|
||||
unsigned short colormap_index, colormap_length;
|
||||
unsigned char colormap_size;
|
||||
unsigned short x_origin, y_origin, width, height;
|
||||
unsigned char pixel_size, attributes;
|
||||
}
|
||||
tga_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_terrain_load_tga_buffer()
|
||||
loads a tga image into a newly allocated image buffer
|
||||
fixme: replace/clean this function
|
||||
*/
|
||||
|
||||
void _terrain_load_tga_buffer( unsigned char *buffer, unsigned char **pic, int *width, int *height )
|
||||
{
|
||||
int row, column;
|
||||
int columns, rows, numPixels;
|
||||
unsigned char *pixbuf;
|
||||
unsigned char *buf_p;
|
||||
tga_t targa_header;
|
||||
unsigned char *targa_rgba;
|
||||
|
||||
|
||||
*pic = NULL;
|
||||
|
||||
if( buffer == NULL )
|
||||
return;
|
||||
|
||||
buf_p = buffer;
|
||||
|
||||
targa_header.id_length = *buf_p++;
|
||||
targa_header.colormap_type = *buf_p++;
|
||||
targa_header.image_type = *buf_p++;
|
||||
|
||||
targa_header.colormap_index = _pico_little_short ( *(short*)buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.colormap_length = _pico_little_short ( *(short*) buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.colormap_size = *buf_p++;
|
||||
targa_header.x_origin = _pico_little_short ( *(short*) buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.y_origin = _pico_little_short ( *(short*) buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.width = _pico_little_short ( *(short*) buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.height = _pico_little_short ( *(short*) buf_p );
|
||||
buf_p += 2;
|
||||
targa_header.pixel_size = *buf_p++;
|
||||
targa_header.attributes = *buf_p++;
|
||||
|
||||
if( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
|
||||
pic = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if( targa_header.colormap_type != 0 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Indexed color TGA images not supported\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 && targa_header.image_type != 3 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Only 32 or 24 bit TGA images supported (not indexed color)\n");
|
||||
pic = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
columns = targa_header.width;
|
||||
rows = targa_header.height;
|
||||
numPixels = columns * rows;
|
||||
|
||||
if (width)
|
||||
*width = columns;
|
||||
if (height)
|
||||
*height = rows;
|
||||
|
||||
targa_rgba = _pico_alloc( numPixels * 4 );
|
||||
*pic = targa_rgba;
|
||||
|
||||
if (targa_header.id_length != 0)
|
||||
buf_p += targa_header.id_length; // skip TARGA image comment
|
||||
|
||||
if ( targa_header.image_type==2 || targa_header.image_type == 3 )
|
||||
{
|
||||
// Uncompressed RGB or gray scale image
|
||||
for(row=rows-1; row>=0; row--)
|
||||
{
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; column++)
|
||||
{
|
||||
unsigned char red,green,blue,alphabyte;
|
||||
switch (targa_header.pixel_size)
|
||||
{
|
||||
|
||||
case 8:
|
||||
blue = *buf_p++;
|
||||
green = blue;
|
||||
red = blue;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* rle encoded pixels */
|
||||
else if( targa_header.image_type == 10 )
|
||||
{
|
||||
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
|
||||
|
||||
red = 0;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
alphabyte = 0xff;
|
||||
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; ) {
|
||||
packetHeader= *buf_p++;
|
||||
packetSize = 1 + (packetHeader & 0x7f);
|
||||
if (packetHeader & 0x80) { // run-length packet
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
break;
|
||||
default:
|
||||
//Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
|
||||
break;
|
||||
}
|
||||
|
||||
for(j=0;j<packetSize;j++) {
|
||||
*pixbuf++=red;
|
||||
*pixbuf++=green;
|
||||
*pixbuf++=blue;
|
||||
*pixbuf++=alphabyte;
|
||||
column++;
|
||||
if (column==columns) { // run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // non run-length packet
|
||||
for(j=0;j<packetSize;j++) {
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
break;
|
||||
default:
|
||||
//Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name );
|
||||
break;
|
||||
}
|
||||
column++;
|
||||
if (column==columns) { // pixel packet run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakOut:;
|
||||
}
|
||||
}
|
||||
|
||||
/* fix vertically flipped image */
|
||||
if( (targa_header.attributes & (1<<5)) )
|
||||
{
|
||||
int flip;
|
||||
for (row = 0; row < .5f * rows; row++)
|
||||
{
|
||||
for (column = 0; column < columns; column++)
|
||||
{
|
||||
flip = *( (int*)targa_rgba + row * columns + column);
|
||||
*( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
|
||||
*( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_terrain_canload()
|
||||
validates a picoterrain file
|
||||
*/
|
||||
|
||||
static int _terrain_canload( PM_PARAMS_CANLOAD )
|
||||
{
|
||||
picoParser_t *p;
|
||||
|
||||
|
||||
/* keep the friggin compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* create pico parser */
|
||||
p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
|
||||
if( p == NULL )
|
||||
return PICO_PMV_ERROR_MEMORY;
|
||||
|
||||
/* get first token */
|
||||
if( _pico_parse_first( p ) == NULL)
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
|
||||
/* check first token */
|
||||
if( _pico_stricmp( p->token, "picoterrain" ) )
|
||||
{
|
||||
_pico_free_parser( p );
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
}
|
||||
|
||||
/* free the pico parser object */
|
||||
_pico_free_parser( p );
|
||||
|
||||
/* file seems to be a valid picoterrain file */
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
_terrain_load()
|
||||
loads a picoterrain file
|
||||
*/
|
||||
|
||||
static picoModel_t *_terrain_load( PM_PARAMS_LOAD )
|
||||
{
|
||||
int i, j, v, pw[ 5 ], r;
|
||||
picoParser_t *p;
|
||||
|
||||
char *shader, *heightmapFile, *colormapFile;
|
||||
picoVec3_t scale, origin;
|
||||
|
||||
unsigned char *imageBuffer;
|
||||
int imageBufSize, w, h, cw, ch;
|
||||
unsigned char *heightmap, *colormap, *heightPixel, *colorPixel;
|
||||
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
|
||||
/* keep the friggin compiler happy */
|
||||
*fileName = *fileName;
|
||||
|
||||
/* create pico parser */
|
||||
p = _pico_new_parser( (picoByte_t*) buffer, bufSize );
|
||||
if( p == NULL )
|
||||
return NULL;
|
||||
|
||||
/* get first token */
|
||||
if( _pico_parse_first( p ) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check first token */
|
||||
if( _pico_stricmp( p->token, "picoterrain" ) )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Invalid PicoTerrain model" );
|
||||
_pico_free_parser( p );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* setup */
|
||||
shader = heightmapFile = colormapFile = NULL;
|
||||
_pico_set_vec( scale, 512, 512, 32 );
|
||||
|
||||
/* parse ase model file */
|
||||
while( 1 )
|
||||
{
|
||||
/* get first token on line */
|
||||
if( !_pico_parse_first( p ) )
|
||||
break;
|
||||
|
||||
/* skip empty lines */
|
||||
if( !p->token || !p->token[ 0 ] )
|
||||
continue;
|
||||
|
||||
/* shader */
|
||||
if( !_pico_stricmp( p->token, "shader" ) )
|
||||
{
|
||||
if( _pico_parse( p, 0 ) && p->token[ 0 ] )
|
||||
{
|
||||
if( shader != NULL )
|
||||
_pico_free( shader );
|
||||
shader = _pico_clone_alloc( p->token );
|
||||
}
|
||||
}
|
||||
|
||||
/* heightmap */
|
||||
else if( !_pico_stricmp( p->token, "heightmap" ) )
|
||||
{
|
||||
if( _pico_parse( p, 0 ) && p->token[ 0 ] )
|
||||
{
|
||||
if( heightmapFile != NULL )
|
||||
_pico_free( heightmapFile );
|
||||
heightmapFile = _pico_clone_alloc( p->token );
|
||||
}
|
||||
}
|
||||
|
||||
/* colormap */
|
||||
else if( !_pico_stricmp( p->token, "colormap" ) )
|
||||
{
|
||||
if( _pico_parse( p, 0 ) && p->token[ 0 ] )
|
||||
{
|
||||
if( colormapFile != NULL )
|
||||
_pico_free( colormapFile );
|
||||
colormapFile = _pico_clone_alloc( p->token );
|
||||
}
|
||||
}
|
||||
|
||||
/* scale */
|
||||
else if( !_pico_stricmp( p->token, "scale" ) )
|
||||
{
|
||||
_pico_parse_vec( p, scale );
|
||||
}
|
||||
|
||||
/* skip unparsed rest of line and continue */
|
||||
_pico_parse_skip_rest( p );
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/* load heightmap */
|
||||
heightmap = imageBuffer = NULL;
|
||||
_pico_load_file( heightmapFile, &imageBuffer, &imageBufSize );
|
||||
_terrain_load_tga_buffer( imageBuffer, &heightmap, &w, &h );
|
||||
_pico_free( heightmapFile );
|
||||
_pico_free_file( imageBuffer );
|
||||
|
||||
if( heightmap == NULL || w < 2 || h < 2 )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "PicoTerrain model with invalid heightmap" );
|
||||
if( shader != NULL )
|
||||
_pico_free( shader );
|
||||
if( colormapFile != NULL )
|
||||
_pico_free( colormapFile );
|
||||
_pico_free_parser( p );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set origin (bottom lowest corner of terrain mesh) */
|
||||
_pico_set_vec( origin, (w / -2) * scale[ 0 ], (h / -2) * scale[ 1 ], -128 * scale[ 2 ] );
|
||||
|
||||
/* load colormap */
|
||||
colormap = imageBuffer = NULL;
|
||||
_pico_load_file( colormapFile, &imageBuffer, &imageBufSize );
|
||||
_terrain_load_tga_buffer( imageBuffer, &colormap, &cw, &ch );
|
||||
_pico_free( colormapFile );
|
||||
_pico_free_file( imageBuffer );
|
||||
|
||||
if( cw != w || ch != h )
|
||||
{
|
||||
_pico_printf( PICO_WARNING, "PicoTerrain colormap/heightmap size mismatch" );
|
||||
_pico_free( colormap );
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if( picoModel == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, 1 ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
/* allocate new pico surface */
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if( picoSurface == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel ); /* sea */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* terrain surfaces are triangle meshes */
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
|
||||
/* set surface name */
|
||||
PicoSetSurfaceName( picoSurface, "picoterrain" );
|
||||
|
||||
/* create new pico shader */
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if( picoShader == NULL )
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
_pico_free( shader );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* detox and set shader name */
|
||||
_pico_setfext( shader, "" );
|
||||
_pico_unixify( shader );
|
||||
PicoSetShaderName( picoShader, shader );
|
||||
_pico_free( shader );
|
||||
|
||||
/* associate current surface with newly created shader */
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
/* make bogus normal */
|
||||
_pico_set_vec( normal, 0.0f, 0.0f, 0.0f );
|
||||
|
||||
/* create mesh */
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
/* get pointers */
|
||||
v = i + (j * w);
|
||||
heightPixel = heightmap + v * 4;
|
||||
colorPixel = colormap
|
||||
? colormap + v * 4
|
||||
: NULL;
|
||||
|
||||
/* set xyz */
|
||||
_pico_set_vec( xyz, origin[ 0 ] + scale[ 0 ] * i,
|
||||
origin[ 1 ] + scale[ 1 ] * j,
|
||||
origin[ 2 ] + scale[ 2 ] * heightPixel[ 0 ] );
|
||||
PicoSetSurfaceXYZ( picoSurface, v, xyz );
|
||||
|
||||
/* set normal */
|
||||
PicoSetSurfaceNormal( picoSurface, v, normal );
|
||||
|
||||
/* set st */
|
||||
st[ 0 ] = (float) i;
|
||||
st[ 1 ] = (float) j;
|
||||
PicoSetSurfaceST( picoSurface, 0, v, st );
|
||||
|
||||
/* set color */
|
||||
if( colorPixel != NULL )
|
||||
_pico_set_color( color, colorPixel[ 0 ], colorPixel[ 1 ], colorPixel[ 2 ], colorPixel[ 3 ] );
|
||||
else
|
||||
_pico_set_color( color, 255, 255, 255, 255 );
|
||||
PicoSetSurfaceColor( picoSurface, 0, v, color );
|
||||
|
||||
/* set triangles (zero alpha in heightmap suppresses this quad) */
|
||||
if( i < (w - 1) && j < (h - 1) && heightPixel[ 3 ] >= 128 )
|
||||
{
|
||||
/* set indexes */
|
||||
pw[ 0 ] = i + (j * w);
|
||||
pw[ 1 ] = i + ((j + 1) * w);
|
||||
pw[ 2 ] = i + 1 + ((j + 1) * w);
|
||||
pw[ 3 ] = i + 1 + (j * w);
|
||||
pw[ 4 ] = i + (j * w); /* same as pw[ 0 ] */
|
||||
|
||||
/* set radix */
|
||||
r = (i + j) & 1;
|
||||
|
||||
/* make first triangle */
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 0), (picoIndex_t) pw[ r + 0 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 1), (picoIndex_t) pw[ r + 1 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 2), (picoIndex_t) pw[ r + 2 ] );
|
||||
|
||||
/* make second triangle */
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 3), (picoIndex_t) pw[ r + 0 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 4), (picoIndex_t) pw[ r + 2 ] );
|
||||
PicoSetSurfaceIndex( picoSurface, (v * 6 + 5), (picoIndex_t) pw[ r + 3 ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free stuff */
|
||||
_pico_free_parser( p );
|
||||
_pico_free( heightmap );
|
||||
_pico_free( colormap );
|
||||
|
||||
/* return the new pico model */
|
||||
return picoModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleTerrain =
|
||||
{
|
||||
"1.3", /* module version string */
|
||||
"PicoTerrain", /* module display name */
|
||||
"Randy Reddig", /* author's name */
|
||||
"2003 Randy Reddig", /* module copyright */
|
||||
{
|
||||
"picoterrain", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_terrain_canload, /* validation routine */
|
||||
_terrain_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
||||
Reference in New Issue
Block a user