The GtkRadiant sources as originally released under the GPL license.

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

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

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

View File

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

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

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

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

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

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

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

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

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

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

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

View File

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

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

File diff suppressed because it is too large Load Diff

View File

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

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

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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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>

View 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
View 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

File diff suppressed because it is too large Load Diff

667
libs/picomodel/pm_fm.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 */
};