871 lines
17 KiB
C
871 lines
17 KiB
C
/*
|
|
======================================================================
|
|
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"
|
|
#include "globaldefs.h"
|
|
|
|
/* disable warnings */
|
|
#if GDEF_COMPILER_MSVC
|
|
#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)" ) ) != NULL ) {
|
|
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 = NULL;
|
|
lwPlugin *shdr = NULL;
|
|
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:
|
|
if( tex == NULL ) {
|
|
goto Fail;
|
|
}
|
|
|
|
flags = getU2( fp );
|
|
|
|
i = -1;
|
|
|
|
//only one of the three axis bits should be set
|
|
if ( flags & 1 ) {
|
|
i = 0;
|
|
}
|
|
if ( flags & 2 ) {
|
|
i = 1;
|
|
}
|
|
if ( flags & 4 ) {
|
|
i = 2;
|
|
}
|
|
if ( i < 0 ) {
|
|
goto Fail;
|
|
}
|
|
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:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
for ( i = 0; i < 3; i++ )
|
|
tex->tmap.size.val[ i ] = getF4( fp );
|
|
break;
|
|
|
|
case ID_TCTR:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
for ( i = 0; i < 3; i++ )
|
|
tex->tmap.center.val[ i ] = getF4( fp );
|
|
break;
|
|
|
|
case ID_TFAL:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
for ( i = 0; i < 3; i++ )
|
|
tex->tmap.falloff.val[ i ] = getF4( fp );
|
|
break;
|
|
|
|
case ID_TVEL:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
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 ) {
|
|
goto Fail;
|
|
}
|
|
if ( tex->type == ID_PROC ) {
|
|
for ( i = 0; i < 3; i++ )
|
|
tex->param.proc.value[ i ] = getU1( fp ) / 255.0f;
|
|
}
|
|
break;
|
|
|
|
case ID_TVAL:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f;
|
|
break;
|
|
|
|
case ID_TAMP:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
if ( tex->type == ID_IMAP ) {
|
|
tex->param.imap.amplitude.val = getF4( fp );
|
|
}
|
|
break;
|
|
|
|
case ID_TIMG:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
s = getS0( fp );
|
|
tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips );
|
|
break;
|
|
|
|
case ID_TAAS:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
tex->param.imap.aa_strength = getF4( fp );
|
|
tex->param.imap.aas_flags = 1;
|
|
break;
|
|
|
|
case ID_TREF:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
tex->tmap.ref_object = getbytes( fp, sz );
|
|
break;
|
|
|
|
case ID_TOPC:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
tex->opacity.val = getF4( fp );
|
|
break;
|
|
|
|
case ID_TFP0:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
if ( tex->type == ID_IMAP ) {
|
|
tex->param.imap.wrapw.val = getF4( fp );
|
|
}
|
|
break;
|
|
|
|
case ID_TFP1:
|
|
if ( !tex ) {
|
|
goto Fail;
|
|
}
|
|
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:
|
|
if ( !shdr ) {
|
|
goto Fail;
|
|
}
|
|
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 * ) (size_t) 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( const 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 <= (unsigned int) ( _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( const char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ){
|
|
unsigned int id, 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;
|
|
}
|