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 ----------------------------------------------------------------------------- */
36 #include "picointernal.h"
38 /* disable warnings */
40 #pragma warning( disable:4100 ) /* unref param */
44 * - loader seems stable
46 * - fix uv coordinate problem
47 * - check for buffer overflows ('bufptr' accesses)
49 /* uncomment when debugging this module */
51 #define DEBUG_PM_MS3D_EX
54 static picoColor_t white = { 255,255,255,255 };
57 const int MS3D_MAX_VERTS = 8192;
58 const int MS3D_MAX_TRIS = 16384;
59 const int MS3D_MAX_GROUPS = 128;
60 const int MS3D_MAX_MATERIALS = 128;
61 const int MS3D_MAX_JOINTS = 128;
62 const int MS3D_MAX_KEYFRAMES = 216;
65 const int MS3D_SELECTED = 1;
66 const int MS3D_HIDDEN = 2;
67 const int MS3D_SELECTED2 = 4;
68 const int MS3D_DIRTY = 8;
70 /* this freaky loader needs byte alignment */
74 typedef struct SMsHeader
82 typedef struct SMsVertex
84 unsigned char flags; /* sel, sel2, or hidden */
86 char boneID; /* -1 means 'no bone' */
87 unsigned char refCount;
92 typedef struct SMsTriangle
94 unsigned short flags; /* sel, sel2, or hidden */
95 unsigned short vertexIndices[3];
96 float vertexNormals[3][3];
99 unsigned char smoothingGroup; /* 1 - 32 */
100 unsigned char groupIndex;
105 typedef struct SMsMaterial
112 float shininess; /* range 0..128 */
113 float transparency; /* range 0..1 */
115 char texture [128]; /* texture.bmp */
116 char alphamap[128]; /* alpha.bmp */
120 // ms3d group (static part)
121 // followed by a variable size block (see below)
122 typedef struct SMsGroup
124 unsigned char flags; // sel, hidden
126 unsigned short numTriangles;
128 unsigned short triangleIndices[ numTriangles ];
129 char materialIndex; // -1 means 'no material'
135 typedef struct SMsJoint
141 float translation[3];
142 unsigned short numRotationKeyframes;
143 unsigned short numTranslationKeyframes;
148 typedef struct SMsKeyframe
155 /* restore previous data alignment */
159 * validates a milkshape3d model file.
161 static int _ms3d_canload( PM_PARAMS_CANLOAD ){
162 const TMsHeader *hdr;
166 if ( (size_t) bufSize < sizeof( TMsHeader ) ) {
167 return PICO_PMV_ERROR_SIZE;
170 /* get ms3d header */
171 hdr = (const TMsHeader *)buffer;
173 /* check ms3d magic */
174 if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) {
175 return PICO_PMV_ERROR_IDENT;
178 /* check ms3d version */
179 if ( _pico_little_long( hdr->version ) < 3 ||
180 _pico_little_long( hdr->version ) > 4 ) {
181 _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
182 return PICO_PMV_ERROR_VERSION;
184 /* file seems to be a valid ms3d */
188 static unsigned char *GetWord( unsigned char *bufptr, int *out ){
189 if ( bufptr == NULL ) {
192 *out = _pico_little_short( *(unsigned short *)bufptr );
193 return( bufptr + 2 );
197 * loads a milkshape3d model file.
199 static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
201 unsigned char *bufptr, *bufptr0;
202 int shaderRefs[ MS3D_MAX_GROUPS ];
205 // unsigned char *ptrToGroups;
207 unsigned char *ptrToVerts;
209 unsigned char *ptrToTris;
212 /* create new pico model */
213 model = PicoNewModel();
214 if ( model == NULL ) {
219 PicoSetModelFrameNum( model, frameNum );
220 PicoSetModelName( model, fileName );
221 PicoSetModelFileName( model, fileName );
223 bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize );
224 memcpy( bufptr, buffer, bufSize );
226 bufptr += sizeof( TMsHeader );
228 /* get number of vertices */
229 bufptr = GetWord( bufptr,&numVerts );
233 printf( "NumVertices: %d\n",numVerts );
236 for ( i = 0; i < numVerts; i++ )
239 vertex = (TMsVertex *)bufptr;
240 bufptr += sizeof( TMsVertex );
242 vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
243 vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
244 vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
246 #ifdef DEBUG_PM_MS3D_EX_
247 printf( "Vertex: x: %f y: %f z: %f\n",
250 msvd[i]->vertex[2] );
253 /* get number of triangles */
254 bufptr = GetWord( bufptr,&numTris );
258 printf( "NumTriangles: %d\n",numTris );
261 for ( i = 0; i < numTris; i++ )
263 TMsTriangle *triangle;
264 triangle = (TMsTriangle *)bufptr;
265 bufptr += sizeof( TMsTriangle );
267 triangle->flags = _pico_little_short( triangle->flags );
269 /* run through all tri verts */
270 for ( k = 0; k < 3; k++ )
272 /* swap tex coords */
273 triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
274 triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
277 triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
278 triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
279 triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
280 triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
282 /* check for out of range indices */
283 if ( triangle->vertexIndices[ k ] >= numVerts ) {
284 _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
285 PicoFreeModel( model );
286 _pico_free( bufptr0 );
287 return NULL; /* yuck */
291 /* get number of groups */
292 bufptr = GetWord( bufptr,&numGroups );
293 // ptrToGroups = bufptr;
296 printf( "NumGroups: %d\n",numGroups );
298 /* run through all groups in model */
299 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
301 picoSurface_t *surface;
304 group = (TMsGroup *)bufptr;
305 bufptr += sizeof( TMsGroup );
307 /* we ignore hidden groups */
308 if ( group->flags & MS3D_HIDDEN ) {
309 bufptr += ( group->numTriangles * 2 ) + 1;
312 /* forced null term of group name */
313 group->name[ 31 ] = '\0';
315 /* create new pico surface */
316 surface = PicoNewSurface( model );
317 if ( surface == NULL ) {
318 PicoFreeModel( model );
319 _pico_free( bufptr0 );
322 /* do surface setup */
323 PicoSetSurfaceType( surface,PICO_TRIANGLES );
324 PicoSetSurfaceName( surface,group->name );
326 /* process triangle indices */
327 for ( k = 0; k < group->numTriangles; k++ )
329 TMsTriangle *triangle;
330 unsigned int triangleIndex;
332 /* get triangle index */
333 bufptr = GetWord( bufptr,(int *)&triangleIndex );
335 /* get ptr to triangle data */
336 triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );
338 /* run through triangle vertices */
339 for ( m = 0; m < 3; m++ )
342 unsigned int vertexIndex;
345 /* get ptr to vertex data */
346 vertexIndex = triangle->vertexIndices[ m ];
347 vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );
349 /* store vertex origin */
350 PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
352 /* store vertex color */
353 PicoSetSurfaceColor( surface,0,vertexIndex,white );
355 /* store vertex normal */
356 PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
358 /* store current face vertex index */
359 PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );
361 /* get texture vertex coord */
362 texCoord[ 0 ] = triangle->s[ m ];
363 texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
365 /* store texture vertex coord */
366 PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
370 shaderRefs[ i ] = *bufptr++;
373 printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
376 /* get number of materials */
377 bufptr = GetWord( bufptr,&numMaterials );
380 printf( "NumMaterials: %d\n",numMaterials );
382 /* run through all materials in model */
383 for ( i = 0; i < numMaterials; i++ )
385 picoShader_t *shader;
386 picoColor_t ambient,diffuse,specular;
387 TMsMaterial *material;
390 material = (TMsMaterial *)bufptr;
391 bufptr += sizeof( TMsMaterial );
393 /* null term strings */
394 material->name [ 31 ] = '\0';
395 material->texture [ 127 ] = '\0';
396 material->alphamap[ 127 ] = '\0';
399 _pico_strltrim( material->name );
400 _pico_strltrim( material->texture );
401 _pico_strltrim( material->alphamap );
404 _pico_strrtrim( material->name );
405 _pico_strrtrim( material->texture );
406 _pico_strrtrim( material->alphamap );
408 /* create new pico shader */
409 shader = PicoNewShader( model );
410 if ( shader == NULL ) {
411 PicoFreeModel( model );
412 _pico_free( bufptr0 );
415 /* scale shader colors */
416 for ( k = 0; k < 4; k++ )
418 ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
419 diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
420 specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
422 /* set shader colors */
423 PicoSetShaderAmbientColor( shader,ambient );
424 PicoSetShaderDiffuseColor( shader,diffuse );
425 PicoSetShaderSpecularColor( shader,specular );
427 /* set shader transparency */
428 PicoSetShaderTransparency( shader,material->transparency );
430 /* set shader shininess (0..127) */
431 PicoSetShaderShininess( shader,material->shininess );
433 /* set shader name */
434 PicoSetShaderName( shader,material->name );
436 /* set shader texture map name */
437 PicoSetShaderMapName( shader,material->texture );
440 printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
443 /* assign shaders to surfaces */
444 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
446 picoSurface_t *surface;
447 picoShader_t *shader;
450 if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
451 shaderRefs[ i ] < 0 ) {
456 surface = PicoGetModelSurface( model,i );
457 if ( surface == NULL ) {
462 shader = PicoGetModelShader( model,shaderRefs[ i ] );
463 if ( shader == NULL ) {
468 PicoSetSurfaceShader( surface,shader );
471 printf( "Mapped: %d ('%s') to %d (%s)\n",
472 shaderRefs[i],shader->name,i,surface->name );
475 /* return allocated pico model */
476 _pico_free( bufptr0 );
481 /* pico file format module definition */
482 const picoModule_t picoModuleMS3D =
484 "0.4-a", /* module version string */
485 "Milkshape 3D", /* module display name */
486 "seaw0lf", /* author's name */
487 "2002 seaw0lf", /* module copyright */
489 "ms3d",NULL,NULL,NULL /* default extensions to use */
491 _ms3d_canload, /* validation routine */
492 _ms3d_load, /* load routine */
493 NULL, /* save validation routine */
494 NULL /* save routine */