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 const int MS3D_MAX_VERTS = 8192;
56 const int MS3D_MAX_TRIS = 16384;
57 const int MS3D_MAX_GROUPS = 128;
58 const int MS3D_MAX_MATERIALS = 128;
59 const int MS3D_MAX_JOINTS = 128;
60 const int MS3D_MAX_KEYFRAMES = 216;
63 const int MS3D_SELECTED = 1;
64 const int MS3D_HIDDEN = 2;
65 const int MS3D_SELECTED2 = 4;
66 const int MS3D_DIRTY = 8;
68 /* this freaky loader needs byte alignment */
72 typedef struct SMsHeader
80 typedef struct SMsVertex
82 unsigned char flags; /* sel, sel2, or hidden */
84 char boneID; /* -1 means 'no bone' */
85 unsigned char refCount;
90 typedef struct SMsTriangle
92 unsigned short flags; /* sel, sel2, or hidden */
93 unsigned short vertexIndices[3];
94 float vertexNormals[3][3];
97 unsigned char smoothingGroup; /* 1 - 32 */
98 unsigned char groupIndex;
103 typedef struct SMsMaterial
110 float shininess; /* range 0..128 */
111 float transparency; /* range 0..1 */
113 char texture [128]; /* texture.bmp */
114 char alphamap[128]; /* alpha.bmp */
118 // ms3d group (static part)
119 // followed by a variable size block (see below)
120 typedef struct SMsGroup
122 unsigned char flags; // sel, hidden
124 unsigned short numTriangles;
126 unsigned short triangleIndices[ numTriangles ];
127 char materialIndex; // -1 means 'no material'
133 typedef struct SMsJoint
139 float translation[3];
140 unsigned short numRotationKeyframes;
141 unsigned short numTranslationKeyframes;
146 typedef struct SMsKeyframe
153 /* restore previous data alignment */
157 * validates a milkshape3d model file.
159 static int _ms3d_canload( PM_PARAMS_CANLOAD ){
160 const TMsHeader *hdr;
164 if ( (size_t) bufSize < sizeof( TMsHeader ) ) {
165 return PICO_PMV_ERROR_SIZE;
168 /* get ms3d header */
169 hdr = (const TMsHeader *)buffer;
171 /* check ms3d magic */
172 if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) {
173 return PICO_PMV_ERROR_IDENT;
176 /* check ms3d version */
177 if ( _pico_little_long( hdr->version ) < 3 ||
178 _pico_little_long( hdr->version ) > 4 ) {
179 _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
180 return PICO_PMV_ERROR_VERSION;
182 /* file seems to be a valid ms3d */
186 static unsigned char *GetWord( unsigned char *bufptr, int *out ){
187 if ( bufptr == NULL ) {
190 *out = _pico_little_short( *(unsigned short *)bufptr );
191 return( bufptr + 2 );
195 * loads a milkshape3d model file.
197 static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
199 unsigned char *bufptr, *bufptr0;
200 int shaderRefs[ MS3D_MAX_GROUPS ];
203 // unsigned char *ptrToGroups;
205 unsigned char *ptrToVerts;
207 unsigned char *ptrToTris;
210 /* create new pico model */
211 model = PicoNewModel();
212 if ( model == NULL ) {
217 PicoSetModelFrameNum( model, frameNum );
218 PicoSetModelName( model, fileName );
219 PicoSetModelFileName( model, fileName );
221 bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize );
222 memcpy( bufptr, buffer, bufSize );
224 bufptr += sizeof( TMsHeader );
226 /* get number of vertices */
227 bufptr = GetWord( bufptr,&numVerts );
231 printf( "NumVertices: %d\n",numVerts );
234 for ( i = 0; i < numVerts; i++ )
237 vertex = (TMsVertex *)bufptr;
238 bufptr += sizeof( TMsVertex );
240 vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
241 vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
242 vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
244 #ifdef DEBUG_PM_MS3D_EX_
245 printf( "Vertex: x: %f y: %f z: %f\n",
248 msvd[i]->vertex[2] );
251 /* get number of triangles */
252 bufptr = GetWord( bufptr,&numTris );
256 printf( "NumTriangles: %d\n",numTris );
259 for ( i = 0; i < numTris; i++ )
261 TMsTriangle *triangle;
262 triangle = (TMsTriangle *)bufptr;
263 bufptr += sizeof( TMsTriangle );
265 triangle->flags = _pico_little_short( triangle->flags );
267 /* run through all tri verts */
268 for ( k = 0; k < 3; k++ )
270 /* swap tex coords */
271 triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
272 triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
275 triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
276 triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
277 triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
278 triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
280 /* check for out of range indices */
281 if ( triangle->vertexIndices[ k ] >= numVerts ) {
282 _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
283 PicoFreeModel( model );
284 _pico_free( bufptr0 );
285 return NULL; /* yuck */
289 /* get number of groups */
290 bufptr = GetWord( bufptr,&numGroups );
291 // ptrToGroups = bufptr;
294 printf( "NumGroups: %d\n",numGroups );
296 /* run through all groups in model */
297 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
299 picoSurface_t *surface;
302 group = (TMsGroup *)bufptr;
303 bufptr += sizeof( TMsGroup );
305 /* we ignore hidden groups */
306 if ( group->flags & MS3D_HIDDEN ) {
307 bufptr += ( group->numTriangles * 2 ) + 1;
310 /* forced null term of group name */
311 group->name[ 31 ] = '\0';
313 /* create new pico surface */
314 surface = PicoNewSurface( model );
315 if ( surface == NULL ) {
316 PicoFreeModel( model );
317 _pico_free( bufptr0 );
320 /* do surface setup */
321 PicoSetSurfaceType( surface,PICO_TRIANGLES );
322 PicoSetSurfaceName( surface,group->name );
324 /* process triangle indices */
325 for ( k = 0; k < group->numTriangles; k++ )
327 TMsTriangle *triangle;
328 unsigned int triangleIndex;
330 /* get triangle index */
331 bufptr = GetWord( bufptr,(int *)&triangleIndex );
333 /* get ptr to triangle data */
334 triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );
336 /* run through triangle vertices */
337 for ( m = 0; m < 3; m++ )
340 unsigned int vertexIndex;
343 /* get ptr to vertex data */
344 vertexIndex = triangle->vertexIndices[ m ];
345 vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );
347 /* store vertex origin */
348 PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
350 /* store vertex color */
351 PicoSetSurfaceColor( surface, 0, vertexIndex, picoColor_white );
353 /* store vertex normal */
354 PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
356 /* store current face vertex index */
357 PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );
359 /* get texture vertex coord */
360 texCoord[ 0 ] = triangle->s[ m ];
361 texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
363 /* store texture vertex coord */
364 PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
368 shaderRefs[ i ] = *bufptr++;
371 printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
374 /* get number of materials */
375 bufptr = GetWord( bufptr,&numMaterials );
378 printf( "NumMaterials: %d\n",numMaterials );
380 /* run through all materials in model */
381 for ( i = 0; i < numMaterials; i++ )
383 picoShader_t *shader;
384 picoColor_t ambient,diffuse,specular;
385 TMsMaterial *material;
388 material = (TMsMaterial *)bufptr;
389 bufptr += sizeof( TMsMaterial );
391 /* null term strings */
392 material->name [ 31 ] = '\0';
393 material->texture [ 127 ] = '\0';
394 material->alphamap[ 127 ] = '\0';
397 _pico_strltrim( material->name );
398 _pico_strltrim( material->texture );
399 _pico_strltrim( material->alphamap );
402 _pico_strrtrim( material->name );
403 _pico_strrtrim( material->texture );
404 _pico_strrtrim( material->alphamap );
406 /* create new pico shader */
407 shader = PicoNewShader( model );
408 if ( shader == NULL ) {
409 PicoFreeModel( model );
410 _pico_free( bufptr0 );
413 /* scale shader colors */
414 for ( k = 0; k < 4; k++ )
416 ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
417 diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
418 specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
420 /* set shader colors */
421 PicoSetShaderAmbientColor( shader,ambient );
422 PicoSetShaderDiffuseColor( shader,diffuse );
423 PicoSetShaderSpecularColor( shader,specular );
425 /* set shader transparency */
426 PicoSetShaderTransparency( shader,material->transparency );
428 /* set shader shininess (0..127) */
429 PicoSetShaderShininess( shader,material->shininess );
431 /* set shader name */
432 PicoSetShaderName( shader,material->name );
434 /* set shader texture map name */
435 PicoSetShaderMapName( shader,material->texture );
438 printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
441 /* assign shaders to surfaces */
442 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
444 picoSurface_t *surface;
445 picoShader_t *shader;
448 if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
449 shaderRefs[ i ] < 0 ) {
454 surface = PicoGetModelSurface( model,i );
455 if ( surface == NULL ) {
460 shader = PicoGetModelShader( model,shaderRefs[ i ] );
461 if ( shader == NULL ) {
466 PicoSetSurfaceShader( surface,shader );
469 printf( "Mapped: %d ('%s') to %d (%s)\n",
470 shaderRefs[i],shader->name,i,surface->name );
473 /* return allocated pico model */
474 _pico_free( bufptr0 );
479 /* pico file format module definition */
480 const picoModule_t picoModuleMS3D =
482 "0.4-a", /* module version string */
483 "Milkshape 3D", /* module display name */
484 "seaw0lf", /* author's name */
485 "2002 seaw0lf", /* module copyright */
487 "ms3d",NULL,NULL,NULL /* default extensions to use */
489 _ms3d_canload, /* validation routine */
490 _ms3d_load, /* load routine */
491 NULL, /* save validation routine */
492 NULL /* save routine */