1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
14 Redistributions in binary form must reproduce the above copyright notice, this
15 list of conditions and the following disclaimer in the documentation and/or
16 other materials provided with the distribution.
18 Neither the names of the copyright holders nor the names of its contributors may
19 be used to endorse or promote products derived from this software without
20 specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ----------------------------------------------------------------------------- */
39 #include "picointernal.h"
42 /* uncomment when debugging this module */
43 /*#define DEBUG_PM_LWO*/
49 /* helper functions */
50 static const char *lwo_lwIDToStr( unsigned int lwID )
52 static char lwIDStr[5];
59 lwIDStr[ 0 ] = (char)((lwID) >> 24);
60 lwIDStr[ 1 ] = (char)((lwID) >> 16);
61 lwIDStr[ 2 ] = (char)((lwID) >> 8);
62 lwIDStr[ 3 ] = (char)((lwID));
70 validates a LightWave Object model file. btw, i use the
71 preceding underscore cause it's a static func referenced
72 by one structure only.
74 static int _lwo_canload( PM_PARAMS_CANLOAD )
77 unsigned int failID = 0;
81 /* create a new pico memorystream */
82 s = _pico_new_memstream( (picoByte_t *)buffer, bufSize );
85 return PICO_PMV_ERROR_MEMORY;
88 ret = lwValidateObject( fileName, s, &failID, &failpos );
90 _pico_free_memstream( s );
97 loads a LightWave Object model file.
99 static picoModel_t *_lwo_load( PM_PARAMS_LOAD )
102 unsigned int failID = 0;
112 int i, j, k, numverts;
114 picoModel_t *picoModel;
115 picoSurface_t *picoSurface;
116 picoShader_t *picoShader;
117 picoVec3_t xyz, normal;
121 int defaultSTAxis[ 2 ];
122 picoVec2_t defaultXYZtoSTScale;
124 picoVertexCombinationHash_t **hashTable;
125 picoVertexCombinationHash_t *vertexCombinationHash;
128 clock_t load_start, load_finish, convert_start, convert_finish;
129 double load_elapsed, convert_elapsed;
131 load_start = clock();
135 if( frameNum < 0 || frameNum >= 1 )
137 _pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" );
141 /* create a new pico memorystream */
142 s = _pico_new_memstream( (picoByte_t *)buffer, bufSize );
148 obj = lwGetObject( fileName, s, &failID, &failpos );
150 _pico_free_memstream( s );
153 _pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos );
158 convert_start = load_finish = clock();
159 load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC;
162 /* -------------------------------------------------
164 ------------------------------------------------- */
166 /* create a new pico model */
167 picoModel = PicoNewModel();
168 if (picoModel == NULL)
170 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
175 PicoSetModelFrameNum( picoModel, frameNum );
176 PicoSetModelNumFrames( picoModel, 1 );
177 PicoSetModelName( picoModel, fileName );
178 PicoSetModelFileName( picoModel, fileName );
180 /* create all polygons from layer[ 0 ] that belong to this surface */
181 layer = &obj->layer[0];
183 /* warn the user that other layers are discarded */
184 if (obj->nlayers > 1)
186 _pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers );
189 /* initialize dummy normal */
190 normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f;
192 /* setup default st map */
193 st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */
194 defaultSTAxis[ 0 ] = 0;
195 defaultSTAxis[ 1 ] = 1;
196 for( i = 0; i < 3; i++ )
198 float min = layer->bbox[ i ];
199 float max = layer->bbox[ i + 3 ];
200 float size = max - min;
204 defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ];
205 defaultSTAxis[ 0 ] = i;
210 else if (size > st[ 1 ])
212 defaultSTAxis[ 1 ] = i;
216 defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ];
217 defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ];
219 /* LWO surfaces become pico surfaces */
223 /* allocate new pico surface */
224 picoSurface = PicoNewSurface( picoModel );
225 if (picoSurface == NULL)
227 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
228 PicoFreeModel( picoModel );
233 /* LWO model surfaces are all triangle meshes */
234 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
236 /* set surface name */
237 PicoSetSurfaceName( picoSurface, surface->name );
239 /* create new pico shader */
240 picoShader = PicoNewShader( picoModel );
241 if (picoShader == NULL)
243 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
244 PicoFreeModel( picoModel );
249 /* detox and set shader name */
250 strncpy( name, surface->name, sizeof(name) );
251 _pico_setfext( name, "" );
252 _pico_unixify( name );
253 PicoSetShaderName( picoShader, name );
255 /* associate current surface with newly created shader */
256 PicoSetSurfaceShader( picoSurface, picoShader );
258 /* copy indices and vertex data */
261 hashTable = PicoNewVertexCombinationHashTable();
263 if (hashTable == NULL)
265 _pico_printf( PICO_ERROR, "Unable to allocate hash table" );
266 PicoFreeModel( picoModel );
271 for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ )
273 /* does this polygon belong to this surface? */
274 if (pol->surf != surface)
277 /* we only support polygons of the FACE type */
278 if (pol->type != ID_FACE)
280 _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) );
284 /* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */
285 if (pol->nverts != 3)
287 _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts );
291 for( j = 0, v = pol->v; j < 3; j++, v++ )
293 pt = &layer->point.pt[ v->index ];
296 xyz[ 0 ] = pt->pos[ 0 ];
297 xyz[ 1 ] = pt->pos[ 2 ];
298 xyz[ 2 ] = pt->pos[ 1 ];
300 normal[ 0 ] = v->norm[ 0 ];
301 normal[ 1 ] = v->norm[ 2 ];
302 normal[ 2 ] = v->norm[ 1 ];
304 st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ];
305 st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ];
307 color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
308 color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
309 color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
312 /* set from points */
313 for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ )
315 if (vm->vmap->type == LWID_('T','X','U','V'))
318 st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ];
319 st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ];
321 else if (vm->vmap->type == LWID_('R','G','B','A'))
324 color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
325 color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
326 color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
327 color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF);
331 /* override with polygon data */
332 for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ )
334 if (vm->vmap->type == LWID_('T','X','U','V'))
337 st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ];
338 st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ];
340 else if (vm->vmap->type == LWID_('R','G','B','A'))
343 color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF);
344 color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF);
345 color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF);
346 color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF);
350 /* find vertex in this surface and if we can't find it there create it */
351 vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color );
353 if (vertexCombinationHash)
355 /* found an existing one */
356 PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index );
360 /* it is a new one */
361 vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts );
363 if (vertexCombinationHash == NULL)
365 _pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" );
366 PicoFreeVertexCombinationHashTable( hashTable );
367 PicoFreeModel( picoModel );
372 /* add the vertex to this surface */
373 PicoSetSurfaceXYZ( picoSurface, numverts, xyz );
375 /* set dummy normal */
376 PicoSetSurfaceNormal( picoSurface, numverts, normal );
379 PicoSetSurfaceColor( picoSurface, 0, numverts, color );
382 PicoSetSurfaceST( picoSurface, 0, numverts, st );
385 PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts );
392 /* free the hashtable */
393 PicoFreeVertexCombinationHashTable( hashTable );
395 /* get next surface */
396 surface = surface->next;
400 load_start = convert_finish = clock();
406 load_finish = clock();
407 load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC;
408 convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC;
409 _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed );
412 /* return the new pico model */
416 /* pico file format module definition */
417 const picoModule_t picoModuleLWO =
419 "1.0", /* module version string */
420 "LightWave Object", /* module display name */
421 "Arnout van Meer", /* author's name */
422 "2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */
424 "lwo", NULL, NULL, NULL /* default extensions to use */
426 _lwo_canload, /* validation routine */
427 _lwo_load, /* load routine */
428 NULL, /* save validation routine */
429 NULL /* save routine */