worldspawn/libs/picomodel/vmap.c

266 lines
5.4 KiB
C

/*
======================================================================
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;
}