]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_md3.c
ok
[xonotic/netradiant.git] / libs / picomodel / pm_md3.c
1 /* -----------------------------------------------------------------------------
2
3 PicoModel Library 
4
5 Copyright (c) 2002, Randy Reddig & seaw0lf
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
13
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.
17
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. 
21
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.
32
33 ----------------------------------------------------------------------------- */
34
35
36
37 /* marker */
38 #define PM_MD3_C
39
40
41
42 /* dependencies */
43 #include "picointernal.h"
44
45
46
47 /* md3 model format */
48 #define MD3_MAGIC                       "IDP3"
49 #define MD3_VERSION                     15
50
51 /* md3 vertex scale */
52 #define MD3_SCALE                 (1.0f / 64.0f)
53
54 /* md3 model frame information */
55 typedef struct md3Frame_s
56 {
57         float           bounds[ 2 ][ 3 ];
58         float           localOrigin[ 3 ];
59         float           radius;
60         char            creator[ 16 ];
61 }
62 md3Frame_t;
63
64 /* md3 model tag information */
65 typedef struct md3Tag_s
66 {
67         char            name[ 64 ];
68         float           origin[ 3 ];
69         float           axis[ 3 ][ 3 ];
70 }
71 md3Tag_t;
72
73 /* md3 surface md3 (one object mesh) */
74 typedef struct md3Surface_s
75 {
76         char            magic[ 4 ];
77         char            name[ 64 ];             /* polyset name */
78         int                     flags;
79         int                     numFrames;              /* all model surfaces should have the same */
80         int                     numShaders;             /* all model surfaces should have the same */
81         int                     numVerts;
82         int                     numTriangles;
83         int                     ofsTriangles;
84         int                     ofsShaders;             /* offset from start of md3Surface_t */
85         int                     ofsSt;                  /* texture coords are common for all frames */
86         int                     ofsVertexes;    /* numVerts * numFrames */
87         int                     ofsEnd;                 /* next surface follows */
88 }
89 md3Surface_t;
90
91 typedef struct md3Shader_s
92 {
93         char            name[ 64 ];
94         int                     shaderIndex;    /* for ingame use */
95 }
96 md3Shader_t;
97
98 typedef struct md3Triangle_s
99 {
100         int                     indexes[ 3 ];
101 }
102 md3Triangle_t;
103
104 typedef struct md3TexCoord_s
105 {
106         float           st[ 2 ];
107 }
108 md3TexCoord_t;
109
110 typedef struct md3Vertex_s
111 {
112         short           xyz[ 3 ];
113         short           normal;
114 }
115 md3Vertex_t;
116
117
118 /* md3 model file md3 structure */
119 typedef struct md3_s
120 {
121         char            magic[ 4 ];             /* MD3_MAGIC */
122         int                     version;
123         char            name[ 64 ];             /* model name */
124         int                     flags;
125         int                     numFrames;
126         int                     numTags;
127         int                     numSurfaces;
128         int                     numSkins;               /* number of skins for the mesh */
129         int                     ofsFrames;              /* offset for first frame */
130         int                     ofsTags;                /* numFrames * numTags */
131         int                     ofsSurfaces;    /* first surface, others follow */
132         int                     ofsEnd;                 /* end of file */
133 }
134 md3_t;
135
136
137
138
139 /*
140 _md3_canload()
141 validates a quake3 arena md3 model file. btw, i use the
142 preceding underscore cause it's a static func referenced
143 by one structure only.
144 */
145
146 static int _md3_canload( PM_PARAMS_CANLOAD )
147 {
148         md3_t   *md3;
149         
150
151         /* to keep the compiler happy */
152         *fileName = *fileName;
153         
154         /* sanity check */
155         if( bufSize < ( sizeof( *md3 ) * 2) )
156                 return PICO_PMV_ERROR_SIZE;
157         
158         /* set as md3 */
159         md3     = (md3_t*) buffer;
160         
161         /* check md3 magic */
162         if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) 
163                 return PICO_PMV_ERROR_IDENT;
164         
165         /* check md3 version */
166         if( _pico_little_long( md3->version ) != MD3_VERSION )
167                 return PICO_PMV_ERROR_VERSION;
168         
169         /* file seems to be a valid md3 */
170         return PICO_PMV_OK;
171 }
172
173
174
175 /*
176 _md3_load()
177 loads a quake3 arena md3 model file.
178 */
179
180 static picoModel_t *_md3_load( PM_PARAMS_LOAD )
181 {
182         int                             i, j;
183         picoByte_t              *bb;
184         md3_t                   *md3;
185         md3Surface_t    *surface;
186         md3Shader_t             *shader;
187         md3TexCoord_t   *texCoord;
188         md3Frame_t              *frame;
189         md3Triangle_t   *triangle;
190         md3Vertex_t             *vertex;
191         double                  lat, lng;
192         
193         picoModel_t             *picoModel;
194         picoSurface_t   *picoSurface;
195         picoShader_t    *picoShader;
196         picoVec3_t              xyz, normal;
197         picoVec2_t              st;
198         picoColor_t             color;
199         
200         
201         /* -------------------------------------------------
202         md3 loading
203         ------------------------------------------------- */
204
205
206         /* set as md3 */
207         bb = (picoByte_t*) buffer;
208         md3     = (md3_t*) buffer;
209         
210         /* check ident and version */
211         if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION )
212         {
213                 /* not an md3 file (todo: set error) */
214                 return NULL;
215         }
216         
217         /* swap md3; sea: swaps fixed */
218         md3->version = _pico_little_long( md3->version );
219         md3->numFrames = _pico_little_long( md3->numFrames );
220         md3->numTags = _pico_little_long( md3->numTags );
221         md3->numSurfaces = _pico_little_long( md3->numSurfaces );
222         md3->numSkins = _pico_little_long( md3->numSkins );
223         md3->ofsFrames = _pico_little_long( md3->ofsFrames );
224         md3->ofsTags = _pico_little_long( md3->ofsTags );
225         md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces );
226         md3->ofsEnd = _pico_little_long( md3->ofsEnd );
227         
228         /* do frame check */
229         if( md3->numFrames < 1 )
230         {
231                 _pico_printf( PICO_ERROR, "MD3 with 0 frames" );
232                 return NULL;
233         }
234         
235         if( frameNum < 0 || frameNum >= md3->numFrames )
236         {
237                 _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" );
238                 return NULL;
239         }
240         
241         /* swap frames */
242         frame = (md3Frame_t*) (bb + md3->ofsFrames );
243         for( i = 0; i < md3->numFrames; i++, frame++ )
244         {
245                 frame->radius = _pico_little_float( frame->radius );
246                 for( j = 0; j < 3; j++ )
247                 {
248                         frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
249                         frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
250                         frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
251                 }
252         }
253         
254         /* swap surfaces */
255         surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
256         for( i = 0; i < md3->numSurfaces; i++ )
257         {
258                 /* swap surface md3; sea: swaps fixed */
259                 surface->flags = _pico_little_long( surface->flags );
260                 surface->numFrames = _pico_little_long( surface->numFrames );
261                 surface->numShaders = _pico_little_long( surface->numShaders );
262                 surface->numTriangles = _pico_little_long( surface->numTriangles );
263                 surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
264                 surface->numVerts = _pico_little_long( surface->numVerts );
265                 surface->ofsShaders = _pico_little_long( surface->ofsShaders );
266                 surface->ofsSt = _pico_little_long( surface->ofsSt );
267                 surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );
268                 surface->ofsEnd = _pico_little_long( surface->ofsEnd );
269                 
270                 /* swap triangles */
271                 triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles);
272                 for( j = 0; j < surface->numTriangles; j++, triangle++ )
273                 {
274                         /* sea: swaps fixed */
275                         triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
276                         triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
277                         triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
278                 }
279                 
280                 /* swap st coords */
281                 texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt);
282                 for( j = 0; j < surface->numVerts; j++, texCoord++ )
283                 {
284                         texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
285                         texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
286                 }
287                 
288                 /* swap xyz/normals */
289                 vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes);
290                 for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++)
291                 {
292                         vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
293                         vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
294                         vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
295                         vertex->normal   = _pico_little_short( vertex->normal );
296                 }
297                 
298                 /* get next surface */
299                 surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
300         }
301         
302         /* -------------------------------------------------
303         pico model creation
304         ------------------------------------------------- */
305         
306         /* create new pico model */
307         picoModel = PicoNewModel();
308         if( picoModel == NULL )
309         {
310                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
311                 return NULL;
312         }
313         
314         /* do model setup */
315         PicoSetModelFrameNum( picoModel, frameNum );
316         PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */
317         PicoSetModelName( picoModel, fileName );
318         PicoSetModelFileName( picoModel, fileName );
319         
320         /* md3 surfaces become picomodel surfaces */
321         surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
322         
323         /* run through md3 surfaces */
324         for( i = 0; i < md3->numSurfaces; i++ )
325         {
326                 /* allocate new pico surface */
327                 picoSurface = PicoNewSurface( picoModel );
328                 if( picoSurface == NULL )
329                 {
330                         _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
331                         PicoFreeModel( picoModel ); /* sea */
332                         return NULL;
333                 }
334                 
335                 /* md3 model surfaces are all triangle meshes */
336                 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
337                 
338                 /* set surface name */
339                 PicoSetSurfaceName( picoSurface, surface->name );
340                 
341                 /* create new pico shader -sea */
342                 picoShader = PicoNewShader( picoModel );
343                 if( picoShader == NULL )
344                 {
345                         _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
346                         PicoFreeModel( picoModel );
347                         return NULL;
348                 }
349                 
350                 /* detox and set shader name */
351                 shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders);
352                 _pico_setfext( shader->name, "" );
353                 _pico_unixify( shader->name );
354                 PicoSetShaderName( picoShader, shader->name );
355                 
356                 /* associate current surface with newly created shader */
357                 PicoSetSurfaceShader( picoSurface, picoShader );
358                 
359                 /* copy indexes */
360                 triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles);
361                 
362                 for( j = 0; j < surface->numTriangles; j++, triangle++ )
363                 {
364                         PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] );
365                         PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] );
366                         PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] );
367                 }
368                 
369                 /* copy vertexes */
370                 texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt);
371                 vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );
372                 _pico_set_color( color, 255, 255, 255, 255 );
373                 
374                 for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )
375                 {
376                         /* set vertex origin */
377                         xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];
378                         xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];
379                         xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];
380                         PicoSetSurfaceXYZ( picoSurface, j, xyz );
381                         
382                         /* decode lat/lng normal to 3 float normal */
383                         lat = (float) ((vertex->normal >> 8) & 0xff);
384                         lng = (float) (vertex->normal & 0xff);
385                         lat *= PICO_PI / 128;
386                         lng *= PICO_PI / 128;
387                         normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
388                         normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
389                         normal[ 2 ] = (picoVec_t) cos( lng );
390                         PicoSetSurfaceNormal( picoSurface, j, normal );
391                         
392                         /* set st coords */
393                         st[ 0 ] = texCoord->st[ 0 ];
394                         st[ 1 ] = texCoord->st[ 1 ];
395                         PicoSetSurfaceST( picoSurface, 0, j, st );
396
397                         /* set color */
398                         PicoSetSurfaceColor( picoSurface, 0, j, color );
399                 }
400                 
401                 /* get next surface */
402                 surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
403         }
404         
405         /* return the new pico model */
406         return picoModel;
407 }
408
409
410
411 /* pico file format module definition */
412 const picoModule_t picoModuleMD3 =
413 {
414         "1.3",                                          /* module version string */
415         "Quake 3 Arena",                        /* module display name */
416         "Randy Reddig",                         /* author's name */
417         "2002 Randy Reddig",            /* module copyright */
418         {
419                 "md3", NULL, NULL, NULL /* default extensions to use */
420         },
421         _md3_canload,                           /* validation routine */
422         _md3_load,                                      /* load routine */
423          NULL,                                          /* save validation routine */
424          NULL                                           /* save routine */
425 };