]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_md2.c
* picomodel: fix md2 loader
[xonotic/netradiant.git] / libs / picomodel / pm_md2.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    Nurail: Used pm_md3.c (Randy Reddig) as a template.
37  */
38
39 /* dependencies */
40 #include "picointernal.h"
41 #include "bytebool.h"
42
43 /* md2 model format */
44 const char *MD2_MAGIC             = "IDP2";
45 const int MD2_VERSION             = 8;
46
47 #define MD2_NUMVERTEXNORMALS 162
48
49 const int MD2_MAX_TRIANGLES       = 4096;
50 const int MD2_MAX_VERTS           = 2048;
51 const int MD2_MAX_FRAMES          = 512;
52 const int MD2_MAX_MD2SKINS        = 32;
53 const int MD2_MAX_SKINNAME        = 64;
54
55 typedef struct index_LUT_s
56 {
57         short Vert;
58         short ST;
59 } index_LUT_t;
60
61 typedef struct
62 {
63         short s;
64         short t;
65 } md2St_t;
66
67 typedef struct
68 {
69         short index_xyz[3];
70         short index_st[3];
71 } md2Triangle_t;
72
73 typedef struct
74 {
75         byte v[3];                          // scaled byte to fit in frame mins/maxs
76         byte lightnormalindex;
77 } md2XyzNormal_t;
78
79 typedef struct md2Frame_s
80 {
81         float scale[3];                     // multiply byte verts by this
82         float translate[3];                 // then add this
83         char name[16];                      // frame name from grabbing
84         md2XyzNormal_t verts[1];            // variable sized
85 }
86 md2Frame_t;
87
88
89 /* md2 model file md2 structure */
90 typedef struct md2_s
91 {
92         char magic[ 4 ];
93         int version;
94
95         int skinWidth;
96         int skinHeight;
97         int frameSize;
98
99         int numSkins;
100         int numXYZ;
101         int numST;
102         int numTris;
103         int numGLCmds;
104         int numFrames;
105
106         int ofsSkins;
107         int ofsST;
108         int ofsTris;
109         int ofsFrames;
110         int ofsGLCmds;
111         int ofsEnd;
112 }
113 md2_t;
114
115 float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =
116 {
117         { -0.525731f, 0.000000f, 0.850651f },
118         { -0.442863f, 0.238856f, 0.864188f },
119         { -0.295242f, 0.000000f, 0.955423f },
120         { -0.309017f, 0.500000f, 0.809017f },
121         { -0.162460f, 0.262866f, 0.951056f },
122         { 0.000000f, 0.000000f, 1.000000f },
123         { 0.000000f, 0.850651f, 0.525731f },
124         { -0.147621f, 0.716567f, 0.681718f },
125         { 0.147621f, 0.716567f, 0.681718f },
126         { 0.000000f, 0.525731f, 0.850651f },
127         { 0.309017f, 0.500000f, 0.809017f },
128         { 0.525731f, 0.000000f, 0.850651f },
129         { 0.295242f, 0.000000f, 0.955423f },
130         { 0.442863f, 0.238856f, 0.864188f },
131         { 0.162460f, 0.262866f, 0.951056f },
132         { -0.681718f, 0.147621f, 0.716567f },
133         { -0.809017f, 0.309017f, 0.500000f },
134         { -0.587785f, 0.425325f, 0.688191f },
135         { -0.850651f, 0.525731f, 0.000000f },
136         { -0.864188f, 0.442863f, 0.238856f },
137         { -0.716567f, 0.681718f, 0.147621f },
138         { -0.688191f, 0.587785f, 0.425325f },
139         { -0.500000f, 0.809017f, 0.309017f },
140         { -0.238856f, 0.864188f, 0.442863f },
141         { -0.425325f, 0.688191f, 0.587785f },
142         { -0.716567f, 0.681718f, -0.147621f },
143         { -0.500000f, 0.809017f, -0.309017f },
144         { -0.525731f, 0.850651f, 0.000000f },
145         { 0.000000f, 0.850651f, -0.525731f },
146         { -0.238856f, 0.864188f, -0.442863f },
147         { 0.000000f, 0.955423f, -0.295242f },
148         { -0.262866f, 0.951056f, -0.162460f },
149         { 0.000000f, 1.000000f, 0.000000f },
150         { 0.000000f, 0.955423f, 0.295242f },
151         { -0.262866f, 0.951056f, 0.162460f },
152         { 0.238856f, 0.864188f, 0.442863f },
153         { 0.262866f, 0.951056f, 0.162460f },
154         { 0.500000f, 0.809017f, 0.309017f },
155         { 0.238856f, 0.864188f, -0.442863f },
156         { 0.262866f, 0.951056f, -0.162460f },
157         { 0.500000f, 0.809017f, -0.309017f },
158         { 0.850651f, 0.525731f, 0.000000f },
159         { 0.716567f, 0.681718f, 0.147621f },
160         { 0.716567f, 0.681718f, -0.147621f },
161         { 0.525731f, 0.850651f, 0.000000f },
162         { 0.425325f, 0.688191f, 0.587785f },
163         { 0.864188f, 0.442863f, 0.238856f },
164         { 0.688191f, 0.587785f, 0.425325f },
165         { 0.809017f, 0.309017f, 0.500000f },
166         { 0.681718f, 0.147621f, 0.716567f },
167         { 0.587785f, 0.425325f, 0.688191f },
168         { 0.955423f, 0.295242f, 0.000000f },
169         { 1.000000f, 0.000000f, 0.000000f },
170         { 0.951056f, 0.162460f, 0.262866f },
171         { 0.850651f, -0.525731f, 0.000000f },
172         { 0.955423f, -0.295242f, 0.000000f },
173         { 0.864188f, -0.442863f, 0.238856f },
174         { 0.951056f, -0.162460f, 0.262866f },
175         { 0.809017f, -0.309017f, 0.500000f },
176         { 0.681718f, -0.147621f, 0.716567f },
177         { 0.850651f, 0.000000f, 0.525731f },
178         { 0.864188f, 0.442863f, -0.238856f },
179         { 0.809017f, 0.309017f, -0.500000f },
180         { 0.951056f, 0.162460f, -0.262866f },
181         { 0.525731f, 0.000000f, -0.850651f },
182         { 0.681718f, 0.147621f, -0.716567f },
183         { 0.681718f, -0.147621f, -0.716567f },
184         { 0.850651f, 0.000000f, -0.525731f },
185         { 0.809017f, -0.309017f, -0.500000f },
186         { 0.864188f, -0.442863f, -0.238856f },
187         { 0.951056f, -0.162460f, -0.262866f },
188         { 0.147621f, 0.716567f, -0.681718f },
189         { 0.309017f, 0.500000f, -0.809017f },
190         { 0.425325f, 0.688191f, -0.587785f },
191         { 0.442863f, 0.238856f, -0.864188f },
192         { 0.587785f, 0.425325f, -0.688191f },
193         { 0.688191f, 0.587785f, -0.425325f },
194         { -0.147621f, 0.716567f, -0.681718f },
195         { -0.309017f, 0.500000f, -0.809017f },
196         { 0.000000f, 0.525731f, -0.850651f },
197         { -0.525731f, 0.000000f, -0.850651f },
198         { -0.442863f, 0.238856f, -0.864188f },
199         { -0.295242f, 0.000000f, -0.955423f },
200         { -0.162460f, 0.262866f, -0.951056f },
201         { 0.000000f, 0.000000f, -1.000000f },
202         { 0.295242f, 0.000000f, -0.955423f },
203         { 0.162460f, 0.262866f, -0.951056f },
204         { -0.442863f, -0.238856f, -0.864188f },
205         { -0.309017f, -0.500000f, -0.809017f },
206         { -0.162460f, -0.262866f, -0.951056f },
207         { 0.000000f, -0.850651f, -0.525731f },
208         { -0.147621f, -0.716567f, -0.681718f },
209         { 0.147621f, -0.716567f, -0.681718f },
210         { 0.000000f, -0.525731f, -0.850651f },
211         { 0.309017f, -0.500000f, -0.809017f },
212         { 0.442863f, -0.238856f, -0.864188f },
213         { 0.162460f, -0.262866f, -0.951056f },
214         { 0.238856f, -0.864188f, -0.442863f },
215         { 0.500000f, -0.809017f, -0.309017f },
216         { 0.425325f, -0.688191f, -0.587785f },
217         { 0.716567f, -0.681718f, -0.147621f },
218         { 0.688191f, -0.587785f, -0.425325f },
219         { 0.587785f, -0.425325f, -0.688191f },
220         { 0.000000f, -0.955423f, -0.295242f },
221         { 0.000000f, -1.000000f, 0.000000f },
222         { 0.262866f, -0.951056f, -0.162460f },
223         { 0.000000f, -0.850651f, 0.525731f },
224         { 0.000000f, -0.955423f, 0.295242f },
225         { 0.238856f, -0.864188f, 0.442863f },
226         { 0.262866f, -0.951056f, 0.162460f },
227         { 0.500000f, -0.809017f, 0.309017f },
228         { 0.716567f, -0.681718f, 0.147621f },
229         { 0.525731f, -0.850651f, 0.000000f },
230         { -0.238856f, -0.864188f, -0.442863f },
231         { -0.500000f, -0.809017f, -0.309017f },
232         { -0.262866f, -0.951056f, -0.162460f },
233         { -0.850651f, -0.525731f, 0.000000f },
234         { -0.716567f, -0.681718f, -0.147621f },
235         { -0.716567f, -0.681718f, 0.147621f },
236         { -0.525731f, -0.850651f, 0.000000f },
237         { -0.500000f, -0.809017f, 0.309017f },
238         { -0.238856f, -0.864188f, 0.442863f },
239         { -0.262866f, -0.951056f, 0.162460f },
240         { -0.864188f, -0.442863f, 0.238856f },
241         { -0.809017f, -0.309017f, 0.500000f },
242         { -0.688191f, -0.587785f, 0.425325f },
243         { -0.681718f, -0.147621f, 0.716567f },
244         { -0.442863f, -0.238856f, 0.864188f },
245         { -0.587785f, -0.425325f, 0.688191f },
246         { -0.309017f, -0.500000f, 0.809017f },
247         { -0.147621f, -0.716567f, 0.681718f },
248         { -0.425325f, -0.688191f, 0.587785f },
249         { -0.162460f, -0.262866f, 0.951056f },
250         { 0.442863f, -0.238856f, 0.864188f },
251         { 0.162460f, -0.262866f, 0.951056f },
252         { 0.309017f, -0.500000f, 0.809017f },
253         { 0.147621f, -0.716567f, 0.681718f },
254         { 0.000000f, -0.525731f, 0.850651f },
255         { 0.425325f, -0.688191f, 0.587785f },
256         { 0.587785f, -0.425325f, 0.688191f },
257         { 0.688191f, -0.587785f, 0.425325f },
258         { -0.955423f, 0.295242f, 0.000000f },
259         { -0.951056f, 0.162460f, 0.262866f },
260         { -1.000000f, 0.000000f, 0.000000f },
261         { -0.850651f, 0.000000f, 0.525731f },
262         { -0.955423f, -0.295242f, 0.000000f },
263         { -0.951056f, -0.162460f, 0.262866f },
264         { -0.864188f, 0.442863f, -0.238856f },
265         { -0.951056f, 0.162460f, -0.262866f },
266         { -0.809017f, 0.309017f, -0.500000f },
267         { -0.864188f, -0.442863f, -0.238856f },
268         { -0.951056f, -0.162460f, -0.262866f },
269         { -0.809017f, -0.309017f, -0.500000f },
270         { -0.681718f, 0.147621f, -0.716567f },
271         { -0.681718f, -0.147621f, -0.716567f },
272         { -0.850651f, 0.000000f, -0.525731f },
273         { -0.688191f, 0.587785f, -0.425325f },
274         { -0.587785f, 0.425325f, -0.688191f },
275         { -0.425325f, 0.688191f, -0.587785f },
276         { -0.425325f, -0.688191f, -0.587785f },
277         { -0.587785f, -0.425325f, -0.688191f },
278         { -0.688191f, -0.587785f, -0.425325f },
279 };
280
281
282 // _md2_canload()
283
284 static int _md2_canload( PM_PARAMS_CANLOAD ){
285         const md2_t *md2;
286
287         /* sanity check */
288         if ( (size_t) bufSize < ( sizeof( *md2 ) * 2 ) ) {
289                 return PICO_PMV_ERROR_SIZE;
290         }
291
292         /* set as md2 */
293         md2 = (const md2_t*) buffer;
294
295         /* check md2 magic */
296         if ( *( (const int*) md2->magic ) != *( (const int*) MD2_MAGIC ) ) {
297                 return PICO_PMV_ERROR_IDENT;
298         }
299
300         /* check md2 version */
301         if ( _pico_little_long( md2->version ) != MD2_VERSION ) {
302                 return PICO_PMV_ERROR_VERSION;
303         }
304
305         /* file seems to be a valid md2 */
306         return PICO_PMV_OK;
307 }
308
309
310
311 // _md2_load() loads a quake2 md2 model file.
312
313
314 static picoModel_t *_md2_load( PM_PARAMS_LOAD ){
315         int i, j, k, dups;
316         index_LUT_t     *p_index_LUT;
317         md2Triangle_t   *p_md2Triangle;
318
319         char skinname[ MD2_MAX_SKINNAME + 1 ];
320         skinname[ MD2_MAX_SKINNAME] = '\0';
321         md2_t           *md2;
322         md2St_t         *texCoord;
323         md2Frame_t      *frame;
324         md2Triangle_t   *triangle;
325         md2XyzNormal_t  *vertex;
326
327         picoByte_t      *bb, *bb0;
328         picoModel_t     *picoModel;
329         picoSurface_t   *picoSurface;
330         picoShader_t    *picoShader;
331         picoVec3_t xyz, normal;
332         picoVec2_t st;
333
334
335         /* set as md2 */
336         bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
337         memcpy( bb, buffer, bufSize );
338         md2 = (md2_t*) bb;
339
340         /* check ident and version */
341         if ( *( (const int*) md2->magic ) != *( (const int*) MD2_MAGIC ) || _pico_little_long( md2->version ) != MD2_VERSION ) {
342                 /* not an md2 file (todo: set error) */
343                 _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );
344                 _pico_free( bb0 );
345                 return NULL;
346         }
347
348         // swap md2
349         md2->version = _pico_little_long( md2->version );
350
351         md2->skinWidth = _pico_little_long( md2->skinWidth );
352         md2->skinHeight = _pico_little_long( md2->skinHeight );
353         md2->frameSize = _pico_little_long( md2->frameSize );
354
355         md2->numSkins = _pico_little_long( md2->numSkins );
356         md2->numXYZ = _pico_little_long( md2->numXYZ );
357         md2->numST = _pico_little_long( md2->numST );
358         md2->numTris = _pico_little_long( md2->numTris );
359         md2->numGLCmds = _pico_little_long( md2->numGLCmds );
360         md2->numFrames = _pico_little_long( md2->numFrames );
361
362         md2->ofsSkins = _pico_little_long( md2->ofsSkins );
363         md2->ofsST = _pico_little_long( md2->ofsST );
364         md2->ofsTris = _pico_little_long( md2->ofsTris );
365         md2->ofsFrames = _pico_little_long( md2->ofsFrames );
366         md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );
367         md2->ofsEnd = _pico_little_long( md2->ofsEnd );
368
369         // do frame check
370         if ( md2->numFrames < 1 ) {
371                 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
372                 _pico_free( bb0 );
373                 return NULL;
374         }
375
376         if ( frameNum < 0 || frameNum >= md2->numFrames ) {
377                 _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
378                 _pico_free( bb0 );
379                 return NULL;
380         }
381
382         // Setup Frame
383         frame = (md2Frame_t *) ( bb + md2->ofsFrames + ( sizeof( md2Frame_t ) * frameNum ) );
384
385         // swap frame scale and translation
386         for ( i = 0; i < 3; i++ )
387         {
388                 frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
389                 frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
390         }
391
392         // swap triangles
393         triangle = (md2Triangle_t *) ( (picoByte_t *) ( bb + md2->ofsTris ) );
394         for ( i = 0; i < md2->numTris; i++, triangle++ )
395         {
396                 for ( j = 0; j < 3; j++ )
397                 {
398                         triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
399                         triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
400                 }
401         }
402
403         // swap st coords
404         texCoord = (md2St_t*) ( (picoByte_t *) ( bb + md2->ofsST ) );
405         for ( i = 0; i < md2->numST; i++, texCoord++ )
406         {
407                 texCoord->s = _pico_little_short( texCoord->s );
408                 texCoord->t = _pico_little_short( texCoord->t );
409         }
410
411         // set Skin Name
412         strncpy( skinname, (const char *) ( bb + md2->ofsSkins ), MD2_MAX_SKINNAME );
413
414         // Print out md2 values
415         _pico_printf( PICO_VERBOSE,"Skins: %d  Verts: %d  STs: %d  Triangles: %d  Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );
416
417         // detox Skin name
418         _pico_setfext( skinname, NULL );
419         _pico_unixify( skinname );
420
421         /* create new pico model */
422         picoModel = PicoNewModel();
423         if ( picoModel == NULL ) {
424                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
425                 _pico_free( bb0 );
426                 return NULL;
427         }
428
429         /* do model setup */
430         PicoSetModelFrameNum( picoModel, frameNum );
431         PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */
432         PicoSetModelName( picoModel, fileName );
433         PicoSetModelFileName( picoModel, fileName );
434
435         // allocate new pico surface
436         picoSurface = PicoNewSurface( picoModel );
437         if ( picoSurface == NULL ) {
438                 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
439                 PicoFreeModel( picoModel );
440                 _pico_free( bb0 );
441                 return NULL;
442         }
443
444
445         PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
446         PicoSetSurfaceName( picoSurface, frame->name );
447         picoShader = PicoNewShader( picoModel );
448         if ( picoShader == NULL ) {
449                 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
450                 PicoFreeModel( picoModel );
451                 _pico_free( bb0 );
452                 return NULL;
453         }
454
455         PicoSetShaderName( picoShader, skinname );
456
457         // associate current surface with newly created shader
458         PicoSetSurfaceShader( picoSurface, picoShader );
459
460         // Init LUT for Verts
461         p_index_LUT = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) * md2->numXYZ );
462         for ( i = 0; i < md2->numXYZ; i++ )
463         {
464                 p_index_LUT[i].Vert = -1;
465                 p_index_LUT[i].ST = -1;
466         }
467
468         index_LUT_t* p_index_LUT_dups = _pico_alloc( sizeof( index_LUT_t ) * md2->numTris * 3 ); //overallocating
469
470         // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
471         dups = 0;
472         for ( i = 0; i < md2->numTris; i++ )
473         {
474                 p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + ( sizeof( md2Triangle_t ) * i ) );
475                 for ( j = 0; j < 3; j++ )
476                 {
477                         const short iXYZ = p_md2Triangle->index_xyz[j];
478                         const short iST = p_md2Triangle->index_st[j];
479                         if ( p_index_LUT[iXYZ].ST == -1 ) { // No Main Entry
480                                 p_index_LUT[iXYZ].ST = iST;
481                                 p_index_LUT[iXYZ].Vert = iXYZ;
482                         }
483
484                         else if ( iST == p_index_LUT[iXYZ].ST && iXYZ == p_index_LUT[iXYZ].Vert ) { // Equal to Main Entry
485                                 continue;
486                         }
487
488                         else{
489                                 for( k = 0; k < dups; k++ ){ //search in dups
490                                         if( iST == p_index_LUT_dups[k].ST && iXYZ == p_index_LUT_dups[k].Vert ){
491                                                 p_md2Triangle->index_xyz[j] = k + md2->numXYZ; // Make change in Tri hunk
492                                                 p_md2Triangle->index_st[j] = k + md2->numXYZ; // Make change in Tri hunk
493                                                 break;
494                                         }
495                                 }
496
497                                 if( k == dups ){ //add new
498                                         p_index_LUT_dups[dups].ST = iST;
499                                         p_index_LUT_dups[dups].Vert = iXYZ;
500                                         p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
501                                         p_md2Triangle->index_st[j] = dups + md2->numXYZ; // Make change in Tri hunk
502                                         ++dups;
503                                 }
504                         }
505                 }
506         }
507
508         // Build Picomodel
509         triangle = (md2Triangle_t *) ( (picoByte_t *) ( bb + md2->ofsTris ) );
510         texCoord = (md2St_t*) ( (picoByte_t *) ( bb + md2->ofsST ) );
511         vertex = (md2XyzNormal_t*) ( (picoByte_t*) ( frame->verts ) );
512         for ( j = 0; j < md2->numTris; j++, triangle++ )
513         {
514                 PicoSetSurfaceIndex( picoSurface, j * 3, triangle->index_xyz[0] );
515                 PicoSetSurfaceIndex( picoSurface, j * 3 + 1, triangle->index_xyz[1] );
516                 PicoSetSurfaceIndex( picoSurface, j * 3 + 2, triangle->index_xyz[2] );
517         }
518
519         for ( i = 0; i < md2->numXYZ; i++, vertex++ )
520         {
521                 /* set vertex origin */
522                 xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];
523                 xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];
524                 xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];
525                 PicoSetSurfaceXYZ( picoSurface, i, xyz );
526
527                 /* set normal */
528                 normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];
529                 normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];
530                 normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];
531                 PicoSetSurfaceNormal( picoSurface, i, normal );
532
533                 /* set st coords */
534                 st[ 0 ] =  ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)md2->skinWidth ) );
535                 st[ 1 ] =  ( texCoord[p_index_LUT[i].ST].t / ( (float)md2->skinHeight ) );
536                 PicoSetSurfaceST( picoSurface, 0, i, st );
537
538                 /* set color */
539                 PicoSetSurfaceColor( picoSurface, 0, i, picoColor_white );
540         }
541
542         for ( i = 0; i < dups; i++ )
543         {
544                 const int surfN = i + md2->numXYZ;
545                 vertex = &frame->verts[p_index_LUT_dups[i].Vert];
546                 /* set vertex origin */
547                 xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];
548                 xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];
549                 xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];
550                 PicoSetSurfaceXYZ( picoSurface, surfN, xyz );
551
552                 /* set normal */
553                 normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];
554                 normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];
555                 normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];
556                 PicoSetSurfaceNormal( picoSurface, surfN, normal );
557
558                 j = p_index_LUT_dups[i].ST;
559                 /* set st coords */
560                 st[ 0 ] =  ( ( texCoord[j].s ) / ( (float)md2->skinWidth ) );
561                 st[ 1 ] =  ( texCoord[j].t / ( (float)md2->skinHeight ) );
562                 PicoSetSurfaceST( picoSurface, 0, surfN, st );
563
564                 /* set color */
565                 PicoSetSurfaceColor( picoSurface, 0, surfN, picoColor_white );
566         }
567
568         // Free malloc'ed LUTs
569         _pico_free( p_index_LUT );
570         _pico_free( p_index_LUT_dups );
571
572         /* return the new pico model */
573         _pico_free( bb0 );
574         return picoModel;
575
576 }
577
578
579
580 /* pico file format module definition */
581 const picoModule_t picoModuleMD2 =
582 {
583         "0.875",                        /* module version string */
584         "Quake 2 MD2",                  /* module display name */
585         "Nurail",                       /* author's name */
586         "2003 Nurail",                  /* module copyright */
587         {
588                 "md2", NULL, NULL, NULL     /* default extensions to use */
589         },
590         _md2_canload,                   /* validation routine */
591         _md2_load,                      /* load routine */
592         NULL,                           /* save validation routine */
593         NULL                            /* save routine */
594 };