]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_md3.c
Merge remote-tracking branch 'github/master'
[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         const md3_t *md3;
148
149
150         /* sanity check */
151         if ( (size_t) bufSize < ( sizeof( *md3 ) * 2 ) ) {
152                 return PICO_PMV_ERROR_SIZE;
153         }
154
155         /* set as md3 */
156         md3 = (const md3_t*) buffer;
157
158         /* check md3 magic */
159         if ( *( (const int*) md3->magic ) != *( (const int*) MD3_MAGIC ) ) {
160                 return PICO_PMV_ERROR_IDENT;
161         }
162
163         /* check md3 version */
164         if ( _pico_little_long( md3->version ) != MD3_VERSION ) {
165                 return PICO_PMV_ERROR_VERSION;
166         }
167
168         /* file seems to be a valid md3 */
169         return PICO_PMV_OK;
170 }
171
172
173
174 /*
175    _md3_load()
176    loads a quake3 arena md3 model file.
177  */
178
179 static picoModel_t *_md3_load( PM_PARAMS_LOAD ){
180         int i, j;
181         picoByte_t      *bb, *bb0;
182         md3_t           *md3;
183         md3Surface_t    *surface;
184         md3Shader_t     *shader;
185         md3TexCoord_t   *texCoord;
186         md3Frame_t      *frame;
187         md3Triangle_t   *triangle;
188         md3Vertex_t     *vertex;
189         double lat, lng;
190
191         picoModel_t     *picoModel;
192         picoSurface_t   *picoSurface;
193         picoShader_t    *picoShader;
194         picoVec3_t xyz, normal;
195         picoVec2_t st;
196         picoColor_t color;
197
198
199         /* -------------------------------------------------
200            md3 loading
201            ------------------------------------------------- */
202
203
204         /* set as md3 */
205         bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
206         memcpy( bb, buffer, bufSize );
207         md3 = (md3_t*) bb;
208
209         /* check ident and version */
210         if ( *( (int*) md3->magic ) != *( (int*) MD3_MAGIC ) || _pico_little_long( md3->version ) != MD3_VERSION ) {
211                 /* not an md3 file (todo: set error) */
212                 _pico_free( bb0 );
213                 return NULL;
214         }
215
216         /* swap md3; sea: swaps fixed */
217         md3->version = _pico_little_long( md3->version );
218         md3->numFrames = _pico_little_long( md3->numFrames );
219         md3->numTags = _pico_little_long( md3->numTags );
220         md3->numSurfaces = _pico_little_long( md3->numSurfaces );
221         md3->numSkins = _pico_little_long( md3->numSkins );
222         md3->ofsFrames = _pico_little_long( md3->ofsFrames );
223         md3->ofsTags = _pico_little_long( md3->ofsTags );
224         md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces );
225         md3->ofsEnd = _pico_little_long( md3->ofsEnd );
226
227         /* do frame check */
228         if ( md3->numFrames < 1 ) {
229                 _pico_printf( PICO_ERROR, "MD3 with 0 frames" );
230                 _pico_free( bb0 );
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                 _pico_free( bb0 );
237                 return NULL;
238         }
239
240         /* swap frames */
241         frame = (md3Frame_t*) ( bb + md3->ofsFrames );
242         for ( i = 0; i < md3->numFrames; i++, frame++ )
243         {
244                 frame->radius = _pico_little_float( frame->radius );
245                 for ( j = 0; j < 3; j++ )
246                 {
247                         frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
248                         frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
249                         frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
250                 }
251         }
252
253         /* swap surfaces */
254         surface = (md3Surface_t*) ( bb + md3->ofsSurfaces );
255         for ( i = 0; i < md3->numSurfaces; i++ )
256         {
257                 /* swap surface md3; sea: swaps fixed */
258                 surface->flags = _pico_little_long( surface->flags );
259                 surface->numFrames = _pico_little_long( surface->numFrames );
260                 surface->numShaders = _pico_little_long( surface->numShaders );
261                 surface->numTriangles = _pico_little_long( surface->numTriangles );
262                 surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
263                 surface->numVerts = _pico_little_long( surface->numVerts );
264                 surface->ofsShaders = _pico_little_long( surface->ofsShaders );
265                 surface->ofsSt = _pico_little_long( surface->ofsSt );
266                 surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );
267                 surface->ofsEnd = _pico_little_long( surface->ofsEnd );
268
269                 /* swap triangles */
270                 triangle = (md3Triangle_t*) ( (picoByte_t*) surface + surface->ofsTriangles );
271                 for ( j = 0; j < surface->numTriangles; j++, triangle++ )
272                 {
273                         /* sea: swaps fixed */
274                         triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
275                         triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
276                         triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
277                 }
278
279                 /* swap st coords */
280                 texCoord = (md3TexCoord_t*) ( (picoByte_t*) surface + surface->ofsSt );
281                 for ( j = 0; j < surface->numVerts; j++, texCoord++ )
282                 {
283                         texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
284                         texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
285                 }
286
287                 /* swap xyz/normals */
288                 vertex = (md3Vertex_t*) ( (picoByte_t*) surface + surface->ofsVertexes );
289                 for ( j = 0; j < ( surface->numVerts * surface->numFrames ); j++, vertex++ )
290                 {
291                         vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
292                         vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
293                         vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
294                         vertex->normal   = _pico_little_short( vertex->normal );
295                 }
296
297                 /* get next surface */
298                 surface = (md3Surface_t*) ( (picoByte_t*) surface + surface->ofsEnd );
299         }
300
301         /* -------------------------------------------------
302            pico model creation
303            ------------------------------------------------- */
304
305         /* create new pico model */
306         picoModel = PicoNewModel();
307         if ( picoModel == NULL ) {
308                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
309                 _pico_free( bb0 );
310                 return NULL;
311         }
312
313         /* do model setup */
314         PicoSetModelFrameNum( picoModel, frameNum );
315         PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */
316         PicoSetModelName( picoModel, fileName );
317         PicoSetModelFileName( picoModel, fileName );
318
319         /* md3 surfaces become picomodel surfaces */
320         surface = (md3Surface_t*) ( bb + md3->ofsSurfaces );
321
322         /* run through md3 surfaces */
323         for ( i = 0; i < md3->numSurfaces; i++ )
324         {
325                 /* allocate new pico surface */
326                 picoSurface = PicoNewSurface( picoModel );
327                 if ( picoSurface == NULL ) {
328                         _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
329                         PicoFreeModel( picoModel ); /* sea */
330                         _pico_free( bb0 );
331                         return NULL;
332                 }
333
334                 /* md3 model surfaces are all triangle meshes */
335                 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
336
337                 /* set surface name */
338                 PicoSetSurfaceName( picoSurface, surface->name );
339
340                 /* create new pico shader -sea */
341                 picoShader = PicoNewShader( picoModel );
342                 if ( picoShader == NULL ) {
343                         _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
344                         PicoFreeModel( picoModel );
345                         _pico_free( bb0 );
346                         return NULL;
347                 }
348
349                 /* detox and set shader name */
350                 shader = (md3Shader_t*) ( (picoByte_t*) surface + surface->ofsShaders );
351                 _pico_setfext( shader->name, "" );
352                 _pico_unixify( shader->name );
353                 PicoSetShaderName( picoShader, shader->name );
354
355                 /* associate current surface with newly created shader */
356                 PicoSetSurfaceShader( picoSurface, picoShader );
357
358                 /* copy indexes */
359                 triangle = (md3Triangle_t *) ( (picoByte_t*) surface + surface->ofsTriangles );
360
361                 for ( j = 0; j < surface->numTriangles; j++, triangle++ )
362                 {
363                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 0 ), (picoIndex_t) triangle->indexes[ 0 ] );
364                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 1 ), (picoIndex_t) triangle->indexes[ 1 ] );
365                         PicoSetSurfaceIndex( picoSurface, ( j * 3 + 2 ), (picoIndex_t) triangle->indexes[ 2 ] );
366                 }
367
368                 /* copy vertexes */
369                 texCoord = (md3TexCoord_t*) ( (picoByte_t *) surface + surface->ofsSt );
370                 vertex = (md3Vertex_t*) ( (picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );
371                 _pico_set_color( color, 255, 255, 255, 255 );
372
373                 for ( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )
374                 {
375                         /* set vertex origin */
376                         xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];
377                         xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];
378                         xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];
379                         PicoSetSurfaceXYZ( picoSurface, j, xyz );
380
381                         /* decode lat/lng normal to 3 float normal */
382                         lat = (float) ( ( vertex->normal >> 8 ) & 0xff );
383                         lng = (float) ( vertex->normal & 0xff );
384                         lat *= PICO_PI / 128;
385                         lng *= PICO_PI / 128;
386                         normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
387                         normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
388                         normal[ 2 ] = (picoVec_t) cos( lng );
389                         PicoSetSurfaceNormal( picoSurface, j, normal );
390
391                         /* set st coords */
392                         st[ 0 ] = texCoord->st[ 0 ];
393                         st[ 1 ] = texCoord->st[ 1 ];
394                         PicoSetSurfaceST( picoSurface, 0, j, st );
395
396                         /* set color */
397                         PicoSetSurfaceColor( picoSurface, 0, j, color );
398                 }
399
400                 /* get next surface */
401                 surface = (md3Surface_t*) ( (picoByte_t*) surface + surface->ofsEnd );
402         }
403
404         /* return the new pico model */
405         _pico_free( bb0 );
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 };