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 ----------------------------------------------------------------------------- */
37 #include "picointernal.h"
38 #include "globaldefs.h"
40 /* disable warnings */
41 #if GDEF_COMPILER_MSVC
42 #pragma warning( disable:4100 ) /* unref param */
46 * - loader seems stable
48 * - fix uv coordinate problem
49 * - check for buffer overflows ('bufptr' accesses)
51 /* uncomment when debugging this module */
53 #define DEBUG_PM_MS3D_EX
56 static picoColor_t white = { 255,255,255,255 };
59 const int MS3D_MAX_VERTS = 8192;
60 const int MS3D_MAX_TRIS = 16384;
61 #define MS3D_MAX_GROUPS 128
62 const int MS3D_MAX_MATERIALS = 128;
63 const int MS3D_MAX_JOINTS = 128;
64 const int MS3D_MAX_KEYFRAMES = 216;
67 const int MS3D_SELECTED = 1;
68 const int MS3D_HIDDEN = 2;
69 const int MS3D_SELECTED2 = 4;
70 const int MS3D_DIRTY = 8;
72 /* this freaky loader needs byte alignment */
76 typedef struct SMsHeader
84 typedef struct SMsVertex
86 unsigned char flags; /* sel, sel2, or hidden */
88 char boneID; /* -1 means 'no bone' */
89 unsigned char refCount;
94 typedef struct SMsTriangle
96 unsigned short flags; /* sel, sel2, or hidden */
97 unsigned short vertexIndices[3];
98 float vertexNormals[3][3];
101 unsigned char smoothingGroup; /* 1 - 32 */
102 unsigned char groupIndex;
107 typedef struct SMsMaterial
114 float shininess; /* range 0..128 */
115 float transparency; /* range 0..1 */
117 char texture [128]; /* texture.bmp */
118 char alphamap[128]; /* alpha.bmp */
122 // ms3d group (static part)
123 // followed by a variable size block (see below)
124 typedef struct SMsGroup
126 unsigned char flags; // sel, hidden
128 unsigned short numTriangles;
130 unsigned short triangleIndices[ numTriangles ];
131 char materialIndex; // -1 means 'no material'
137 typedef struct SMsJoint
143 float translation[3];
144 unsigned short numRotationKeyframes;
145 unsigned short numTranslationKeyframes;
150 typedef struct SMsKeyframe
157 /* restore previous data alignment */
161 * validates a milkshape3d model file.
163 static int _ms3d_canload( PM_PARAMS_CANLOAD ){
164 const TMsHeader *hdr;
168 if ( (size_t) bufSize < sizeof( TMsHeader ) ) {
169 return PICO_PMV_ERROR_SIZE;
172 /* get ms3d header */
173 hdr = (const TMsHeader *)buffer;
175 /* check ms3d magic */
176 if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) {
177 return PICO_PMV_ERROR_IDENT;
180 /* check ms3d version */
181 if ( _pico_little_long( hdr->version ) < 3 ||
182 _pico_little_long( hdr->version ) > 4 ) {
183 _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
184 return PICO_PMV_ERROR_VERSION;
186 /* file seems to be a valid ms3d */
190 static unsigned char *GetWord( unsigned char *bufptr, int *out ){
191 if ( bufptr == NULL ) {
194 *out = _pico_little_short( *(unsigned short *)bufptr );
195 return( bufptr + 2 );
199 * loads a milkshape3d model file.
201 static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
203 unsigned char *bufptr, *bufptr0;
204 int shaderRefs[ MS3D_MAX_GROUPS ];
207 // unsigned char *ptrToGroups;
209 unsigned char *ptrToVerts;
211 unsigned char *ptrToTris;
214 /* create new pico model */
215 model = PicoNewModel();
216 if ( model == NULL ) {
221 PicoSetModelFrameNum( model, frameNum );
222 PicoSetModelName( model, fileName );
223 PicoSetModelFileName( model, fileName );
225 bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize );
226 memcpy( bufptr, buffer, bufSize );
228 bufptr += sizeof( TMsHeader );
230 /* get number of vertices */
231 bufptr = GetWord( bufptr,&numVerts );
236 printf( "NumVertices: %d\n",numVerts );
239 for ( i = 0; i < numVerts; i++ )
242 vertex = (TMsVertex *)bufptr;
243 bufptr += sizeof( TMsVertex );
245 vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
246 vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
247 vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
249 #ifdef DEBUG_PM_MS3D_EX_
250 printf( "Vertex: x: %f y: %f z: %f\n",
253 msvd[i]->vertex[2] );
256 /* get number of triangles */
257 bufptr = GetWord( bufptr,&numTris );
261 printf( "NumTriangles: %d\n",numTris );
264 for ( i = 0; i < numTris; i++ )
266 TMsTriangle *triangle;
267 triangle = (TMsTriangle *)bufptr;
268 bufptr += sizeof( TMsTriangle );
270 triangle->flags = _pico_little_short( triangle->flags );
272 /* run through all tri verts */
273 for ( k = 0; k < 3; k++ )
275 /* swap tex coords */
276 triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
277 triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
280 triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
281 triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
282 triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
283 triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
285 /* check for out of range indices */
286 if ( triangle->vertexIndices[ k ] >= numVerts ) {
287 _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
288 PicoFreeModel( model );
289 _pico_free( bufptr0 );
290 return NULL; /* yuck */
294 /* get number of groups */
295 bufptr = GetWord( bufptr,&numGroups );
297 // ptrToGroups = bufptr;
300 printf( "NumGroups: %d\n",numGroups );
302 /* run through all groups in model */
303 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
305 picoSurface_t *surface;
308 group = (TMsGroup *)bufptr;
309 bufptr += sizeof( TMsGroup );
311 /* we ignore hidden groups */
312 if ( group->flags & MS3D_HIDDEN ) {
313 bufptr += ( group->numTriangles * 2 ) + 1;
316 /* forced null term of group name */
317 group->name[ 31 ] = '\0';
319 /* create new pico surface */
320 surface = PicoNewSurface( model );
321 if ( surface == NULL ) {
322 PicoFreeModel( model );
323 _pico_free( bufptr0 );
326 /* do surface setup */
327 PicoSetSurfaceType( surface,PICO_TRIANGLES );
328 PicoSetSurfaceName( surface,group->name );
330 /* process triangle indices */
331 for ( k = 0; k < group->numTriangles; k++ )
333 TMsTriangle *triangle;
334 unsigned int triangleIndex;
336 /* get triangle index */
337 bufptr = GetWord( bufptr,(int *)&triangleIndex );
340 /* get ptr to triangle data */
341 triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );
343 /* run through triangle vertices */
344 for ( m = 0; m < 3; m++ )
347 unsigned int vertexIndex;
350 /* get ptr to vertex data */
351 vertexIndex = triangle->vertexIndices[ m ];
352 vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );
354 /* store vertex origin */
355 PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
357 /* store vertex color */
358 PicoSetSurfaceColor( surface,0,vertexIndex,white );
360 /* store vertex normal */
361 PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
363 /* store current face vertex index */
364 PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );
366 /* get texture vertex coord */
367 texCoord[ 0 ] = triangle->s[ m ];
368 texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
370 /* store texture vertex coord */
371 PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
375 shaderRefs[ i ] = *bufptr++;
378 printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
381 /* get number of materials */
382 bufptr = GetWord( bufptr,&numMaterials );
386 printf( "NumMaterials: %d\n",numMaterials );
388 /* run through all materials in model */
389 for ( i = 0; i < numMaterials; i++ )
391 picoShader_t *shader;
392 picoColor_t ambient,diffuse,specular;
393 TMsMaterial *material;
396 material = (TMsMaterial *)bufptr;
397 bufptr += sizeof( TMsMaterial );
399 /* null term strings */
400 material->name [ 31 ] = '\0';
401 material->texture [ 127 ] = '\0';
402 material->alphamap[ 127 ] = '\0';
405 _pico_strltrim( material->name );
406 _pico_strltrim( material->texture );
407 _pico_strltrim( material->alphamap );
410 _pico_strrtrim( material->name );
411 _pico_strrtrim( material->texture );
412 _pico_strrtrim( material->alphamap );
414 /* create new pico shader */
415 shader = PicoNewShader( model );
416 if ( shader == NULL ) {
417 PicoFreeModel( model );
418 _pico_free( bufptr0 );
421 /* scale shader colors */
422 for ( k = 0; k < 4; k++ )
424 ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
425 diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
426 specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
428 /* set shader colors */
429 PicoSetShaderAmbientColor( shader,ambient );
430 PicoSetShaderDiffuseColor( shader,diffuse );
431 PicoSetShaderSpecularColor( shader,specular );
433 /* set shader transparency */
434 PicoSetShaderTransparency( shader,material->transparency );
436 /* set shader shininess (0..127) */
437 PicoSetShaderShininess( shader,material->shininess );
439 /* set shader name */
440 PicoSetShaderName( shader,material->name );
442 /* set shader texture map name */
443 PicoSetShaderMapName( shader,material->texture );
446 printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
449 /* assign shaders to surfaces */
450 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
452 picoSurface_t *surface;
453 picoShader_t *shader;
456 if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
457 shaderRefs[ i ] < 0 ) {
462 surface = PicoGetModelSurface( model,i );
463 if ( surface == NULL ) {
468 shader = PicoGetModelShader( model,shaderRefs[ i ] );
469 if ( shader == NULL ) {
474 PicoSetSurfaceShader( surface,shader );
477 printf( "Mapped: %d ('%s') to %d (%s)\n",
478 shaderRefs[i],shader->name,i,surface->name );
481 /* return allocated pico model */
482 _pico_free( bufptr0 );
487 /* pico file format module definition */
488 const picoModule_t picoModuleMS3D =
490 "0.4-a", /* module version string */
491 "Milkshape 3D", /* module display name */
492 "seaw0lf", /* author's name */
493 "2002 seaw0lf", /* module copyright */
495 "ms3d",NULL,NULL,NULL /* default extensions to use */
497 _ms3d_canload, /* validation routine */
498 _ms3d_load, /* load routine */
499 NULL, /* save validation routine */
500 NULL /* save routine */