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