]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_md3.c
uncrustify! now the code is only ugly on the *inside*
[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         md3_t   *md3;
148
149
150         /* to keep the compiler happy */
151         *fileName = *fileName;
152
153         /* sanity check */
154         if ( bufSize < ( sizeof( *md3 ) * 2 ) ) {
155                 return PICO_PMV_ERROR_SIZE;
156         }
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
166         /* check md3 version */
167         if ( _pico_little_long( md3->version ) != MD3_VERSION ) {
168                 return PICO_PMV_ERROR_VERSION;
169         }
170
171         /* file seems to be a valid md3 */
172         return PICO_PMV_OK;
173 }
174
175
176
177 /*
178    _md3_load()
179    loads a quake3 arena md3 model file.
180  */
181
182 static picoModel_t *_md3_load( PM_PARAMS_LOAD ){
183         int i, j;
184         picoByte_t      *bb;
185         md3_t           *md3;
186         md3Surface_t    *surface;
187         md3Shader_t     *shader;
188         md3TexCoord_t   *texCoord;
189         md3Frame_t      *frame;
190         md3Triangle_t   *triangle;
191         md3Vertex_t     *vertex;
192         double lat, lng;
193
194         picoModel_t     *picoModel;
195         picoSurface_t   *picoSurface;
196         picoShader_t    *picoShader;
197         picoVec3_t xyz, normal;
198         picoVec2_t st;
199         picoColor_t color;
200
201
202         /* -------------------------------------------------
203            md3 loading
204            ------------------------------------------------- */
205
206
207         /* set as md3 */
208         bb = (picoByte_t*) buffer;
209         md3 = (md3_t*) buffer;
210
211         /* check ident and version */
212         if ( *( (int*) md3->magic ) != *( (int*) MD3_MAGIC ) || _pico_little_long( md3->version ) != MD3_VERSION ) {
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                 _pico_printf( PICO_ERROR, "MD3 with 0 frames" );
231                 return NULL;
232         }
233
234         if ( frameNum < 0 || frameNum >= md3->numFrames ) {
235                 _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" );
236                 return NULL;
237         }
238
239         /* swap frames */
240         frame = (md3Frame_t*) ( bb + md3->ofsFrames );
241         for ( i = 0; i < md3->numFrames; i++, frame++ )
242         {
243                 frame->radius = _pico_little_float( frame->radius );
244                 for ( j = 0; j < 3; j++ )
245                 {
246                         frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
247                         frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
248                         frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
249                 }
250         }
251
252         /* swap surfaces */
253         surface = (md3Surface_t*) ( bb + md3->ofsSurfaces );
254         for ( i = 0; i < md3->numSurfaces; i++ )
255         {
256                 /* swap surface md3; sea: swaps fixed */
257                 surface->flags = _pico_little_long( surface->flags );
258                 surface->numFrames = _pico_little_long( surface->numFrames );
259                 surface->numShaders = _pico_little_long( surface->numShaders );
260                 surface->numTriangles = _pico_little_long( surface->numTriangles );
261                 surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
262                 surface->numVerts = _pico_little_long( surface->numVerts );
263                 surface->ofsShaders = _pico_little_long( surface->ofsShaders );
264                 surface->ofsSt = _pico_little_long( surface->ofsSt );
265                 surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );
266                 surface->ofsEnd = _pico_little_long( surface->ofsEnd );
267
268                 /* swap triangles */
269                 triangle = (md3Triangle_t*) ( (picoByte_t*) surface + surface->ofsTriangles );
270                 for ( j = 0; j < surface->numTriangles; j++, triangle++ )
271                 {
272                         /* sea: swaps fixed */
273                         triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
274                         triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
275                         triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
276                 }
277
278                 /* swap st coords */
279                 texCoord = (md3TexCoord_t*) ( (picoByte_t*) surface + surface->ofsSt );
280                 for ( j = 0; j < surface->numVerts; j++, texCoord++ )
281                 {
282                         texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
283                         texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
284                 }
285
286                 /* swap xyz/normals */
287                 vertex = (md3Vertex_t*) ( (picoByte_t*) surface + surface->ofsVertexes );
288                 for ( j = 0; j < ( surface->numVerts * surface->numFrames ); j++, vertex++ )
289                 {
290                         vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
291                         vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
292                         vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
293                         vertex->normal   = _pico_little_short( vertex->normal );
294                 }
295
296                 /* get next surface */
297                 surface = (md3Surface_t*) ( (picoByte_t*) surface + surface->ofsEnd );
298         }
299
300         /* -------------------------------------------------
301            pico model creation
302            ------------------------------------------------- */
303
304         /* create new pico model */
305         picoModel = PicoNewModel();
306         if ( picoModel == NULL ) {
307                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
308                 return NULL;
309         }
310
311         /* do model setup */
312         PicoSetModelFrameNum( picoModel, frameNum );
313         PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */
314         PicoSetModelName( picoModel, fileName );
315         PicoSetModelFileName( picoModel, fileName );
316
317         /* md3 surfaces become picomodel surfaces */
318         surface = (md3Surface_t*) ( bb + md3->ofsSurfaces );
319
320         /* run through md3 surfaces */
321         for ( i = 0; i < md3->numSurfaces; i++ )
322         {
323                 /* allocate new pico surface */
324                 picoSurface = PicoNewSurface( picoModel );
325                 if ( picoSurface == NULL ) {
326                         _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
327                         PicoFreeModel( picoModel ); /* sea */
328                         return NULL;
329                 }
330
331                 /* md3 model surfaces are all triangle meshes */
332                 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
333
334                 /* set surface name */
335                 PicoSetSurfaceName( picoSurface, surface->name );
336
337                 /* create new pico shader -sea */
338                 picoShader = PicoNewShader( picoModel );
339                 if ( picoShader == NULL ) {
340                         _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
341                         PicoFreeModel( picoModel );
342                         return NULL;
343                 }
344
345                 /* detox and set shader name */
346                 shader = (md3Shader_t*) ( (picoByte_t*) surface + surface->ofsShaders );
347                 _pico_setfext( shader->name, "" );
348                 _pico_unixify( shader->name );
349                 PicoSetShaderName( picoShader, shader->name );
350
351                 /* associate current surface with newly created shader */
352                 PicoSetSurfaceShader( picoSurface, picoShader );
353
354                 /* copy indexes */
355                 triangle = (md3Triangle_t *) ( (picoByte_t*) surface + surface->ofsTriangles );
356
357                 for ( j = 0; j < surface->numTriangles; j++, triangle++ )
358                 {
359                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 0 ), (picoIndex_t) triangle->indexes[ 0 ] );
360                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 1 ), (picoIndex_t) triangle->indexes[ 1 ] );
361                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 2 ), (picoIndex_t) triangle->indexes[ 2 ] );
362                 }
363
364                 /* copy vertexes */
365                 texCoord = (md3TexCoord_t*) ( (picoByte_t *) surface + surface->ofsSt );
366                 vertex = (md3Vertex_t*) ( (picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );
367                 _pico_set_color( color, 255, 255, 255, 255 );
368
369                 for ( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )
370                 {
371                         /* set vertex origin */
372                         xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];
373                         xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];
374                         xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];
375                         PicoSetSurfaceXYZ( picoSurface, j, xyz );
376
377                         /* decode lat/lng normal to 3 float normal */
378                         lat = (float) ( ( vertex->normal >> 8 ) & 0xff );
379                         lng = (float) ( vertex->normal & 0xff );
380                         lat *= PICO_PI / 128;
381                         lng *= PICO_PI / 128;
382                         normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
383                         normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
384                         normal[ 2 ] = (picoVec_t) cos( lng );
385                         PicoSetSurfaceNormal( picoSurface, j, normal );
386
387                         /* set st coords */
388                         st[ 0 ] = texCoord->st[ 0 ];
389                         st[ 1 ] = texCoord->st[ 1 ];
390                         PicoSetSurfaceST( picoSurface, 0, j, st );
391
392                         /* set color */
393                         PicoSetSurfaceColor( picoSurface, 0, j, color );
394                 }
395
396                 /* get next surface */
397                 surface = (md3Surface_t*) ( (picoByte_t*) surface + surface->ofsEnd );
398         }
399
400         /* return the new pico model */
401         return picoModel;
402 }
403
404
405
406 /* pico file format module definition */
407 const picoModule_t picoModuleMD3 =
408 {
409         "1.3",                      /* module version string */
410         "Quake 3 Arena",            /* module display name */
411         "Randy Reddig",             /* author's name */
412         "2002 Randy Reddig",        /* module copyright */
413         {
414                 "md3", NULL, NULL, NULL /* default extensions to use */
415         },
416         _md3_canload,               /* validation routine */
417         _md3_load,                  /* load routine */
418         NULL,                       /* save validation routine */
419         NULL                        /* save routine */
420 };