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 ----------------------------------------------------------------------------- */
41 #include "picointernal.h"
43 /* disable warnings */
45 #pragma warning( disable:4100 ) /* unref param */
49 * - loader seems stable
51 * - fix uv coordinate problem
52 * - check for buffer overflows ('bufptr' accesses)
54 /* uncomment when debugging this module */
56 #define DEBUG_PM_MS3D_EX
59 static picoColor_t white = { 255,255,255,255 };
62 #define MS3D_MAX_VERTS 8192
63 #define MS3D_MAX_TRIS 16384
64 #define MS3D_MAX_GROUPS 128
65 #define MS3D_MAX_MATERIALS 128
66 #define MS3D_MAX_JOINTS 128
67 #define MS3D_MAX_KEYFRAMES 216
70 #define MS3D_SELECTED 1
72 #define MS3D_SELECTED2 4
75 /* this freaky loader needs byte alignment */
79 typedef struct SMsHeader
87 typedef struct SMsVertex
89 unsigned char flags; /* sel, sel2, or hidden */
91 char boneID; /* -1 means 'no bone' */
92 unsigned char refCount;
97 typedef struct SMsTriangle
99 unsigned short flags; /* sel, sel2, or hidden */
100 unsigned short vertexIndices[3];
101 float vertexNormals[3][3];
104 unsigned char smoothingGroup; /* 1 - 32 */
105 unsigned char groupIndex;
110 typedef struct SMsMaterial
117 float shininess; /* range 0..128 */
118 float transparency; /* range 0..1 */
120 char texture [128]; /* texture.bmp */
121 char alphamap[128]; /* alpha.bmp */
125 // ms3d group (static part)
126 // followed by a variable size block (see below)
127 typedef struct SMsGroup
129 unsigned char flags; // sel, hidden
131 unsigned short numTriangles;
133 unsigned short triangleIndices[ numTriangles ];
134 char materialIndex; // -1 means 'no material'
140 typedef struct SMsJoint
146 float translation[3];
147 unsigned short numRotationKeyframes;
148 unsigned short numTranslationKeyframes;
153 typedef struct SMsKeyframe
160 /* restore previous data alignment */
164 * validates a milkshape3d model file.
166 static int _ms3d_canload( PM_PARAMS_CANLOAD ){
170 /* to keep the compiler happy */
171 *fileName = *fileName;
174 if ( bufSize < sizeof( TMsHeader ) ) {
175 return PICO_PMV_ERROR_SIZE;
178 /* get ms3d header */
179 hdr = (TMsHeader *)buffer;
181 /* check ms3d magic */
182 if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) {
183 return PICO_PMV_ERROR_IDENT;
186 /* check ms3d version */
187 if ( _pico_little_long( hdr->version ) < 3 ||
188 _pico_little_long( hdr->version ) > 4 ) {
189 _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );
190 return PICO_PMV_ERROR_VERSION;
192 /* file seems to be a valid ms3d */
196 static unsigned char *GetWord( unsigned char *bufptr, int *out ){
197 if ( bufptr == NULL ) {
200 *out = _pico_little_short( *(unsigned short *)bufptr );
201 return( bufptr + 2 );
205 * loads a milkshape3d model file.
207 static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){
209 unsigned char *bufptr;
210 int shaderRefs[ MS3D_MAX_GROUPS ];
213 // unsigned char *ptrToGroups;
215 unsigned char *ptrToVerts;
217 unsigned char *ptrToTris;
220 /* create new pico model */
221 model = PicoNewModel();
222 if ( model == NULL ) {
227 PicoSetModelFrameNum( model, frameNum );
228 PicoSetModelName( model, fileName );
229 PicoSetModelFileName( model, fileName );
232 bufptr = (unsigned char *)buffer + sizeof( TMsHeader );
234 /* get number of vertices */
235 bufptr = GetWord( bufptr,&numVerts );
239 printf( "NumVertices: %d\n",numVerts );
242 for ( i = 0; i < numVerts; i++ )
245 vertex = (TMsVertex *)bufptr;
246 bufptr += sizeof( TMsVertex );
248 vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );
249 vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );
250 vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );
252 #ifdef DEBUG_PM_MS3D_EX_
253 printf( "Vertex: x: %f y: %f z: %f\n",
256 msvd[i]->vertex[2] );
259 /* get number of triangles */
260 bufptr = GetWord( bufptr,&numTris );
264 printf( "NumTriangles: %d\n",numTris );
267 for ( i = 0; i < numTris; i++ )
269 TMsTriangle *triangle;
270 triangle = (TMsTriangle *)bufptr;
271 bufptr += sizeof( TMsTriangle );
273 triangle->flags = _pico_little_short( triangle->flags );
275 /* run through all tri verts */
276 for ( k = 0; k < 3; k++ )
278 /* swap tex coords */
279 triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );
280 triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );
283 triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] );
284 triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );
285 triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );
286 triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );
288 /* check for out of range indices */
289 if ( triangle->vertexIndices[ k ] >= numVerts ) {
290 _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 );
291 PicoFreeModel( model );
292 return NULL; /* yuck */
296 /* get number of groups */
297 bufptr = GetWord( bufptr,&numGroups );
298 // ptrToGroups = bufptr;
301 printf( "NumGroups: %d\n",numGroups );
303 /* run through all groups in model */
304 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
306 picoSurface_t *surface;
309 group = (TMsGroup *)bufptr;
310 bufptr += sizeof( TMsGroup );
312 /* we ignore hidden groups */
313 if ( group->flags & MS3D_HIDDEN ) {
314 bufptr += ( group->numTriangles * 2 ) + 1;
317 /* forced null term of group name */
318 group->name[ 31 ] = '\0';
320 /* create new pico surface */
321 surface = PicoNewSurface( model );
322 if ( surface == NULL ) {
323 PicoFreeModel( model );
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 );
339 /* get ptr to triangle data */
340 triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) );
342 /* run through triangle vertices */
343 for ( m = 0; m < 3; m++ )
346 unsigned int vertexIndex;
349 /* get ptr to vertex data */
350 vertexIndex = triangle->vertexIndices[ m ];
351 vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) );
353 /* store vertex origin */
354 PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
356 /* store vertex color */
357 PicoSetSurfaceColor( surface,0,vertexIndex,white );
359 /* store vertex normal */
360 PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
362 /* store current face vertex index */
363 PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex );
365 /* get texture vertex coord */
366 texCoord[ 0 ] = triangle->s[ m ];
367 texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */
369 /* store texture vertex coord */
370 PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
374 shaderRefs[ i ] = *bufptr++;
377 printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles );
380 /* get number of materials */
381 bufptr = GetWord( bufptr,&numMaterials );
384 printf( "NumMaterials: %d\n",numMaterials );
386 /* run through all materials in model */
387 for ( i = 0; i < numMaterials; i++ )
389 picoShader_t *shader;
390 picoColor_t ambient,diffuse,specular;
391 TMsMaterial *material;
394 material = (TMsMaterial *)bufptr;
395 bufptr += sizeof( TMsMaterial );
397 /* null term strings */
398 material->name [ 31 ] = '\0';
399 material->texture [ 127 ] = '\0';
400 material->alphamap[ 127 ] = '\0';
403 _pico_strltrim( material->name );
404 _pico_strltrim( material->texture );
405 _pico_strltrim( material->alphamap );
408 _pico_strrtrim( material->name );
409 _pico_strrtrim( material->texture );
410 _pico_strrtrim( material->alphamap );
412 /* create new pico shader */
413 shader = PicoNewShader( model );
414 if ( shader == NULL ) {
415 PicoFreeModel( model );
418 /* scale shader colors */
419 for ( k = 0; k < 4; k++ )
421 ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 );
422 diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 );
423 specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 );
425 /* set shader colors */
426 PicoSetShaderAmbientColor( shader,ambient );
427 PicoSetShaderDiffuseColor( shader,diffuse );
428 PicoSetShaderSpecularColor( shader,specular );
430 /* set shader transparency */
431 PicoSetShaderTransparency( shader,material->transparency );
433 /* set shader shininess (0..127) */
434 PicoSetShaderShininess( shader,material->shininess );
436 /* set shader name */
437 PicoSetShaderName( shader,material->name );
439 /* set shader texture map name */
440 PicoSetShaderMapName( shader,material->texture );
443 printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap );
446 /* assign shaders to surfaces */
447 for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ )
449 picoSurface_t *surface;
450 picoShader_t *shader;
453 if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
454 shaderRefs[ i ] < 0 ) {
459 surface = PicoGetModelSurface( model,i );
460 if ( surface == NULL ) {
465 shader = PicoGetModelShader( model,shaderRefs[ i ] );
466 if ( shader == NULL ) {
471 PicoSetSurfaceShader( surface,shader );
474 printf( "Mapped: %d ('%s') to %d (%s)\n",
475 shaderRefs[i],shader->name,i,surface->name );
478 /* return allocated pico model */
483 /* pico file format module definition */
484 const picoModule_t picoModuleMS3D =
486 "0.4-a", /* module version string */
487 "Milkshape 3D", /* module display name */
488 "seaw0lf", /* author's name */
489 "2002 seaw0lf", /* module copyright */
491 "ms3d",NULL,NULL,NULL /* default extensions to use */
493 _ms3d_canload, /* validation routine */
494 _ms3d_load, /* load routine */
495 NULL, /* save validation routine */
496 NULL /* save routine */