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"
37 #include "globaldefs.h"
39 /* disable warnings */
40 #if GDEF_COMPILER_MSVC
41 #pragma warning( disable:4100 ) /* unref param */
45 * - loader seems stable
47 * - fix uv coordinate problem
48 * - check for buffer overflows ('bufptr' accesses)
50 /* uncomment when debugging this module */
52 #define DEBUG_PM_MS3D_EX
55 static picoColor_t white = { 255,255,255,255 };
58 const int MS3D_MAX_VERTS = 8192;
59 const int MS3D_MAX_TRIS = 16384;
60 const int MS3D_MAX_GROUPS = 128;
61 const int MS3D_MAX_MATERIALS = 128;
62 const int MS3D_MAX_JOINTS = 128;
63 const int MS3D_MAX_KEYFRAMES = 216;
66 const int MS3D_SELECTED = 1;
67 const int MS3D_HIDDEN = 2;
68 const int MS3D_SELECTED2 = 4;
69 const int MS3D_DIRTY = 8;
71 /* this freaky loader needs byte alignment */
75 typedef struct SMsHeader
83 typedef struct SMsVertex
85 unsigned char flags; /* sel, sel2, or hidden */
87 char boneID; /* -1 means 'no bone' */
88 unsigned char refCount;
93 typedef struct SMsTriangle
95 unsigned short flags; /* sel, sel2, or hidden */
96 unsigned short vertexIndices[3];
97 float vertexNormals[3][3];
100 unsigned char smoothingGroup; /* 1 - 32 */
101 unsigned char groupIndex;
106 typedef struct SMsMaterial
113 float shininess; /* range 0..128 */
114 float transparency; /* range 0..1 */
116 char texture [128]; /* texture.bmp */
117 char alphamap[128]; /* alpha.bmp */
121 // ms3d group (static part)
122 // followed by a variable size block (see below)
123 typedef struct SMsGroup
125 unsigned char flags; // sel, hidden
127 unsigned short numTriangles;
129 unsigned short triangleIndices[ numTriangles ];
130 char materialIndex; // -1 means 'no material'
136 typedef struct SMsJoint
142 float translation[3];
143 unsigned short numRotationKeyframes;
144 unsigned short numTranslationKeyframes;
149 typedef struct SMsKeyframe
156 /* restore previous data alignment */
160 * validates a milkshape3d model file.
162 static int _ms3d_canload( PM_PARAMS_CANLOAD ){
163 const TMsHeader *hdr;
167 if ( (size_t) bufSize < sizeof( TMsHeader ) ) {
168 return PICO_PMV_ERROR_SIZE;
171 /* get ms3d header */
172 hdr = (const TMsHeader *)buffer;
174 /* check ms3d magic */
175 if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) {
176 return PICO_PMV_ERROR_IDENT;
179 /* check ms3d version */
180 if ( _pico_little_long( hdr->version ) < 3 ||
181 _pico_little_long( hdr->version ) > 4 ) {
182 _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
183 return PICO_PMV_ERROR_VERSION;
185 /* file seems to be a valid ms3d */
189 static unsigned char *GetWord( unsigned char *bufptr, int *out ){
190 if ( bufptr == NULL ) {
193 *out = _pico_little_short( *(unsigned short *)bufptr );
194 return( bufptr + 2 );
198 * loads a milkshape3d model file.
200 static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
202 unsigned char *bufptr, *bufptr0;
203 int shaderRefs[ MS3D_MAX_GROUPS ];
206 // unsigned char *ptrToGroups;
208 unsigned char *ptrToVerts;
210 unsigned char *ptrToTris;
213 /* create new pico model */
214 model = PicoNewModel();
215 if ( model == NULL ) {
220 PicoSetModelFrameNum( model, frameNum );
221 PicoSetModelName( model, fileName );
222 PicoSetModelFileName( model, fileName );
224 bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize );
225 memcpy( bufptr, buffer, bufSize );
227 bufptr += sizeof( TMsHeader );
229 /* get number of vertices */
230 bufptr = GetWord( bufptr,&numVerts );
234 printf( "NumVertices: %d\n",numVerts );
237 for ( i = 0; i < numVerts; i++ )
240 vertex = (TMsVertex *)bufptr;
241 bufptr += sizeof( TMsVertex );
243 vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
244 vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
245 vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
247 #ifdef DEBUG_PM_MS3D_EX_
248 printf( "Vertex: x: %f y: %f z: %f\n",
251 msvd[i]->vertex[2] );
254 /* get number of triangles */
255 bufptr = GetWord( bufptr,&numTris );
259 printf( "NumTriangles: %d\n",numTris );
262 for ( i = 0; i < numTris; i++ )
264 TMsTriangle *triangle;
265 triangle = (TMsTriangle *)bufptr;
266 bufptr += sizeof( TMsTriangle );
268 triangle->flags = _pico_little_short( triangle->flags );
270 /* run through all tri verts */
271 for ( k = 0; k < 3; k++ )
273 /* swap tex coords */
274 triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
275 triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
278 triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
279 triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
280 triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
281 triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
283 /* check for out of range indices */
284 if ( triangle->vertexIndices[ k ] >= numVerts ) {
285 _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
286 PicoFreeModel( model );
287 _pico_free( bufptr0 );
288 return NULL; /* yuck */
292 /* get number of groups */
293 bufptr = GetWord( bufptr,&numGroups );
294 // ptrToGroups = bufptr;
297 printf( "NumGroups: %d\n",numGroups );
299 /* run through all groups in model */
300 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
302 picoSurface_t *surface;
305 group = (TMsGroup *)bufptr;
306 bufptr += sizeof( TMsGroup );
308 /* we ignore hidden groups */
309 if ( group->flags & MS3D_HIDDEN ) {
310 bufptr += ( group->numTriangles * 2 ) + 1;
313 /* forced null term of group name */
314 group->name[ 31 ] = '\0';
316 /* create new pico surface */
317 surface = PicoNewSurface( model );
318 if ( surface == NULL ) {
319 PicoFreeModel( model );
320 _pico_free( bufptr0 );
323 /* do surface setup */
324 PicoSetSurfaceType( surface,PICO_TRIANGLES );
325 PicoSetSurfaceName( surface,group->name );
327 /* process triangle indices */
328 for ( k = 0; k < group->numTriangles; k++ )
330 TMsTriangle *triangle;
331 unsigned int triangleIndex;
333 /* get triangle index */
334 bufptr = GetWord( bufptr,(int *)&triangleIndex );
336 /* get ptr to triangle data */
337 triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );
339 /* run through triangle vertices */
340 for ( m = 0; m < 3; m++ )
343 unsigned int vertexIndex;
346 /* get ptr to vertex data */
347 vertexIndex = triangle->vertexIndices[ m ];
348 vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );
350 /* store vertex origin */
351 PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
353 /* store vertex color */
354 PicoSetSurfaceColor( surface,0,vertexIndex,white );
356 /* store vertex normal */
357 PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
359 /* store current face vertex index */
360 PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );
362 /* get texture vertex coord */
363 texCoord[ 0 ] = triangle->s[ m ];
364 texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
366 /* store texture vertex coord */
367 PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
371 shaderRefs[ i ] = *bufptr++;
374 printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
377 /* get number of materials */
378 bufptr = GetWord( bufptr,&numMaterials );
381 printf( "NumMaterials: %d\n",numMaterials );
383 /* run through all materials in model */
384 for ( i = 0; i < numMaterials; i++ )
386 picoShader_t *shader;
387 picoColor_t ambient,diffuse,specular;
388 TMsMaterial *material;
391 material = (TMsMaterial *)bufptr;
392 bufptr += sizeof( TMsMaterial );
394 /* null term strings */
395 material->name [ 31 ] = '\0';
396 material->texture [ 127 ] = '\0';
397 material->alphamap[ 127 ] = '\0';
400 _pico_strltrim( material->name );
401 _pico_strltrim( material->texture );
402 _pico_strltrim( material->alphamap );
405 _pico_strrtrim( material->name );
406 _pico_strrtrim( material->texture );
407 _pico_strrtrim( material->alphamap );
409 /* create new pico shader */
410 shader = PicoNewShader( model );
411 if ( shader == NULL ) {
412 PicoFreeModel( model );
413 _pico_free( bufptr0 );
416 /* scale shader colors */
417 for ( k = 0; k < 4; k++ )
419 ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
420 diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
421 specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
423 /* set shader colors */
424 PicoSetShaderAmbientColor( shader,ambient );
425 PicoSetShaderDiffuseColor( shader,diffuse );
426 PicoSetShaderSpecularColor( shader,specular );
428 /* set shader transparency */
429 PicoSetShaderTransparency( shader,material->transparency );
431 /* set shader shininess (0..127) */
432 PicoSetShaderShininess( shader,material->shininess );
434 /* set shader name */
435 PicoSetShaderName( shader,material->name );
437 /* set shader texture map name */
438 PicoSetShaderMapName( shader,material->texture );
441 printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
444 /* assign shaders to surfaces */
445 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
447 picoSurface_t *surface;
448 picoShader_t *shader;
451 if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
452 shaderRefs[ i ] < 0 ) {
457 surface = PicoGetModelSurface( model,i );
458 if ( surface == NULL ) {
463 shader = PicoGetModelShader( model,shaderRefs[ i ] );
464 if ( shader == NULL ) {
469 PicoSetSurfaceShader( surface,shader );
472 printf( "Mapped: %d ('%s') to %d (%s)\n",
473 shaderRefs[i],shader->name,i,surface->name );
476 /* return allocated pico model */
477 _pico_free( bufptr0 );
482 /* pico file format module definition */
483 const picoModule_t picoModuleMS3D =
485 "0.4-a", /* module version string */
486 "Milkshape 3D", /* module display name */
487 "seaw0lf", /* author's name */
488 "2002 seaw0lf", /* module copyright */
490 "ms3d",NULL,NULL,NULL /* default extensions to use */
492 _ms3d_canload, /* validation routine */
493 _ms3d_load, /* load routine */
494 NULL, /* save validation routine */
495 NULL /* save routine */