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