]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_md2.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / libs / picomodel / pm_md2.c
1 /* -----------------------------------------------------------------------------\r
2 \r
3 PicoModel Library \r
4 \r
5 Copyright (c) 2002, Randy Reddig & seaw0lf\r
6 All rights reserved.\r
7 \r
8 Redistribution and use in source and binary forms, with or without modification,\r
9 are permitted provided that the following conditions are met:\r
10 \r
11 Redistributions of source code must retain the above copyright notice, this list\r
12 of conditions and the following disclaimer.\r
13 \r
14 Redistributions in binary form must reproduce the above copyright notice, this\r
15 list of conditions and the following disclaimer in the documentation and/or\r
16 other materials provided with the distribution.\r
17 \r
18 Neither the names of the copyright holders nor the names of its contributors may\r
19 be used to endorse or promote products derived from this software without\r
20 specific prior written permission. \r
21 \r
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
32 \r
33 ----------------------------------------------------------------------------- */\r
34 \r
35 /*\r
36 Nurail: Used pm_md3.c (Randy Reddig) as a template.\r
37 */\r
38 \r
39 \r
40 /* marker */\r
41 #define PM_MD2_C\r
42 \r
43 /* dependencies */\r
44 #include "picointernal.h"\r
45 \r
46 \r
47 /* md2 model format */\r
48 #define MD2_MAGIC                               "IDP2"\r
49 #define MD2_VERSION                             8\r
50 \r
51 #define MD2_NUMVERTEXNORMALS    162\r
52 #define MD2_MAX_SKINNAME                64\r
53 #define MD2_MAX_TRIANGLES               4096\r
54 #define MD2_MAX_VERTS                   2048\r
55 #define MD2_MAX_FRAMES                  512\r
56 #define MD2_MAX_MD2SKINS                32\r
57 #define MD2_MAX_SKINNAME                64\r
58 \r
59 #ifndef byte\r
60         #define byte unsigned char\r
61 #endif\r
62 \r
63 typedef struct index_LUT_s\r
64 {\r
65         short   Vert;\r
66         short   ST;\r
67         struct  index_LUT_s     *next;\r
68 \r
69 } index_LUT_t;\r
70 \r
71 typedef struct index_DUP_LUT_s\r
72 {\r
73         short                   ST;\r
74         short                   OldVert;\r
75 \r
76 } index_DUP_LUT_t;\r
77 \r
78 typedef struct\r
79 {\r
80         short   s;\r
81         short   t;\r
82 } md2St_t;\r
83 \r
84 typedef struct\r
85 {\r
86         short   index_xyz[3];\r
87         short   index_st[3];\r
88 } md2Triangle_t;\r
89 \r
90 typedef struct\r
91 {\r
92         byte    v[3];                   // scaled byte to fit in frame mins/maxs\r
93         byte    lightnormalindex;\r
94 } md2XyzNormal_t;\r
95 \r
96 typedef struct md2Frame_s\r
97 {\r
98         float           scale[3];       // multiply byte verts by this\r
99         float           translate[3];   // then add this\r
100         char            name[16];       // frame name from grabbing\r
101         md2XyzNormal_t  verts[1];       // variable sized\r
102 }\r
103 md2Frame_t;\r
104 \r
105 \r
106 /* md2 model file md2 structure */\r
107 typedef struct md2_s\r
108 {\r
109         char    magic[ 4 ];\r
110         int     version;\r
111 \r
112         int     skinWidth;\r
113         int     skinHeight;\r
114         int     frameSize;\r
115 \r
116         int     numSkins;\r
117         int     numXYZ;\r
118         int     numST;\r
119         int     numTris;\r
120         int     numGLCmds;\r
121         int     numFrames;\r
122 \r
123         int     ofsSkins;\r
124         int     ofsST;\r
125         int     ofsTris;\r
126         int     ofsFrames;\r
127         int     ofsGLCmds;\r
128         int     ofsEnd;\r
129 }\r
130 md2_t;\r
131 \r
132 float   md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =\r
133 {\r
134         { -0.525731f, 0.000000f, 0.850651f },\r
135         { -0.442863f, 0.238856f, 0.864188f }, \r
136         { -0.295242f, 0.000000f, 0.955423f }, \r
137         { -0.309017f, 0.500000f, 0.809017f }, \r
138         { -0.162460f, 0.262866f, 0.951056f }, \r
139         { 0.000000f, 0.000000f, 1.000000f },\r
140         { 0.000000f, 0.850651f, 0.525731f },\r
141         { -0.147621f, 0.716567f, 0.681718f },\r
142         { 0.147621f, 0.716567f, 0.681718f }, \r
143         { 0.000000f, 0.525731f, 0.850651f }, \r
144         { 0.309017f, 0.500000f, 0.809017f }, \r
145         { 0.525731f, 0.000000f, 0.850651f }, \r
146         { 0.295242f, 0.000000f, 0.955423f }, \r
147         { 0.442863f, 0.238856f, 0.864188f }, \r
148         { 0.162460f, 0.262866f, 0.951056f }, \r
149         { -0.681718f, 0.147621f, 0.716567f }, \r
150         { -0.809017f, 0.309017f, 0.500000f }, \r
151         { -0.587785f, 0.425325f, 0.688191f }, \r
152         { -0.850651f, 0.525731f, 0.000000f }, \r
153         { -0.864188f, 0.442863f, 0.238856f }, \r
154         { -0.716567f, 0.681718f, 0.147621f }, \r
155         { -0.688191f, 0.587785f, 0.425325f }, \r
156         { -0.500000f, 0.809017f, 0.309017f }, \r
157         { -0.238856f, 0.864188f, 0.442863f }, \r
158         { -0.425325f, 0.688191f, 0.587785f }, \r
159         { -0.716567f, 0.681718f, -0.147621f }, \r
160         { -0.500000f, 0.809017f, -0.309017f }, \r
161         { -0.525731f, 0.850651f, 0.000000f }, \r
162         { 0.000000f, 0.850651f, -0.525731f }, \r
163         { -0.238856f, 0.864188f, -0.442863f }, \r
164         { 0.000000f, 0.955423f, -0.295242f }, \r
165         { -0.262866f, 0.951056f, -0.162460f }, \r
166         { 0.000000f, 1.000000f, 0.000000f }, \r
167         { 0.000000f, 0.955423f, 0.295242f }, \r
168         { -0.262866f, 0.951056f, 0.162460f }, \r
169         { 0.238856f, 0.864188f, 0.442863f }, \r
170         { 0.262866f, 0.951056f, 0.162460f }, \r
171         { 0.500000f, 0.809017f, 0.309017f }, \r
172         { 0.238856f, 0.864188f, -0.442863f }, \r
173         { 0.262866f, 0.951056f, -0.162460f }, \r
174         { 0.500000f, 0.809017f, -0.309017f }, \r
175         { 0.850651f, 0.525731f, 0.000000f }, \r
176         { 0.716567f, 0.681718f, 0.147621f }, \r
177         { 0.716567f, 0.681718f, -0.147621f }, \r
178         { 0.525731f, 0.850651f, 0.000000f }, \r
179         { 0.425325f, 0.688191f, 0.587785f }, \r
180         { 0.864188f, 0.442863f, 0.238856f }, \r
181         { 0.688191f, 0.587785f, 0.425325f }, \r
182         { 0.809017f, 0.309017f, 0.500000f }, \r
183         { 0.681718f, 0.147621f, 0.716567f }, \r
184         { 0.587785f, 0.425325f, 0.688191f }, \r
185         { 0.955423f, 0.295242f, 0.000000f }, \r
186         { 1.000000f, 0.000000f, 0.000000f }, \r
187         { 0.951056f, 0.162460f, 0.262866f }, \r
188         { 0.850651f, -0.525731f, 0.000000f }, \r
189         { 0.955423f, -0.295242f, 0.000000f }, \r
190         { 0.864188f, -0.442863f, 0.238856f }, \r
191         { 0.951056f, -0.162460f, 0.262866f }, \r
192         { 0.809017f, -0.309017f, 0.500000f }, \r
193         { 0.681718f, -0.147621f, 0.716567f }, \r
194         { 0.850651f, 0.000000f, 0.525731f }, \r
195         { 0.864188f, 0.442863f, -0.238856f }, \r
196         { 0.809017f, 0.309017f, -0.500000f }, \r
197         { 0.951056f, 0.162460f, -0.262866f }, \r
198         { 0.525731f, 0.000000f, -0.850651f }, \r
199         { 0.681718f, 0.147621f, -0.716567f }, \r
200         { 0.681718f, -0.147621f, -0.716567f }, \r
201         { 0.850651f, 0.000000f, -0.525731f }, \r
202         { 0.809017f, -0.309017f, -0.500000f }, \r
203         { 0.864188f, -0.442863f, -0.238856f }, \r
204         { 0.951056f, -0.162460f, -0.262866f }, \r
205         { 0.147621f, 0.716567f, -0.681718f }, \r
206         { 0.309017f, 0.500000f, -0.809017f }, \r
207         { 0.425325f, 0.688191f, -0.587785f }, \r
208         { 0.442863f, 0.238856f, -0.864188f }, \r
209         { 0.587785f, 0.425325f, -0.688191f }, \r
210         { 0.688191f, 0.587785f, -0.425325f }, \r
211         { -0.147621f, 0.716567f, -0.681718f }, \r
212         { -0.309017f, 0.500000f, -0.809017f }, \r
213         { 0.000000f, 0.525731f, -0.850651f }, \r
214         { -0.525731f, 0.000000f, -0.850651f }, \r
215         { -0.442863f, 0.238856f, -0.864188f }, \r
216         { -0.295242f, 0.000000f, -0.955423f }, \r
217         { -0.162460f, 0.262866f, -0.951056f }, \r
218         { 0.000000f, 0.000000f, -1.000000f }, \r
219         { 0.295242f, 0.000000f, -0.955423f }, \r
220         { 0.162460f, 0.262866f, -0.951056f }, \r
221         { -0.442863f, -0.238856f, -0.864188f }, \r
222         { -0.309017f, -0.500000f, -0.809017f }, \r
223         { -0.162460f, -0.262866f, -0.951056f }, \r
224         { 0.000000f, -0.850651f, -0.525731f }, \r
225         { -0.147621f, -0.716567f, -0.681718f }, \r
226         { 0.147621f, -0.716567f, -0.681718f }, \r
227         { 0.000000f, -0.525731f, -0.850651f }, \r
228         { 0.309017f, -0.500000f, -0.809017f }, \r
229         { 0.442863f, -0.238856f, -0.864188f }, \r
230         { 0.162460f, -0.262866f, -0.951056f }, \r
231         { 0.238856f, -0.864188f, -0.442863f }, \r
232         { 0.500000f, -0.809017f, -0.309017f }, \r
233         { 0.425325f, -0.688191f, -0.587785f }, \r
234         { 0.716567f, -0.681718f, -0.147621f }, \r
235         { 0.688191f, -0.587785f, -0.425325f }, \r
236         { 0.587785f, -0.425325f, -0.688191f }, \r
237         { 0.000000f, -0.955423f, -0.295242f }, \r
238         { 0.000000f, -1.000000f, 0.000000f }, \r
239         { 0.262866f, -0.951056f, -0.162460f }, \r
240         { 0.000000f, -0.850651f, 0.525731f }, \r
241         { 0.000000f, -0.955423f, 0.295242f }, \r
242         { 0.238856f, -0.864188f, 0.442863f }, \r
243         { 0.262866f, -0.951056f, 0.162460f }, \r
244         { 0.500000f, -0.809017f, 0.309017f }, \r
245         { 0.716567f, -0.681718f, 0.147621f }, \r
246         { 0.525731f, -0.850651f, 0.000000f }, \r
247         { -0.238856f, -0.864188f, -0.442863f }, \r
248         { -0.500000f, -0.809017f, -0.309017f }, \r
249         { -0.262866f, -0.951056f, -0.162460f }, \r
250         { -0.850651f, -0.525731f, 0.000000f }, \r
251         { -0.716567f, -0.681718f, -0.147621f }, \r
252         { -0.716567f, -0.681718f, 0.147621f }, \r
253         { -0.525731f, -0.850651f, 0.000000f }, \r
254         { -0.500000f, -0.809017f, 0.309017f }, \r
255         { -0.238856f, -0.864188f, 0.442863f }, \r
256         { -0.262866f, -0.951056f, 0.162460f }, \r
257         { -0.864188f, -0.442863f, 0.238856f }, \r
258         { -0.809017f, -0.309017f, 0.500000f }, \r
259         { -0.688191f, -0.587785f, 0.425325f }, \r
260         { -0.681718f, -0.147621f, 0.716567f }, \r
261         { -0.442863f, -0.238856f, 0.864188f }, \r
262         { -0.587785f, -0.425325f, 0.688191f }, \r
263         { -0.309017f, -0.500000f, 0.809017f }, \r
264         { -0.147621f, -0.716567f, 0.681718f }, \r
265         { -0.425325f, -0.688191f, 0.587785f }, \r
266         { -0.162460f, -0.262866f, 0.951056f }, \r
267         { 0.442863f, -0.238856f, 0.864188f }, \r
268         { 0.162460f, -0.262866f, 0.951056f }, \r
269         { 0.309017f, -0.500000f, 0.809017f }, \r
270         { 0.147621f, -0.716567f, 0.681718f }, \r
271         { 0.000000f, -0.525731f, 0.850651f }, \r
272         { 0.425325f, -0.688191f, 0.587785f }, \r
273         { 0.587785f, -0.425325f, 0.688191f }, \r
274         { 0.688191f, -0.587785f, 0.425325f }, \r
275         { -0.955423f, 0.295242f, 0.000000f }, \r
276         { -0.951056f, 0.162460f, 0.262866f }, \r
277         { -1.000000f, 0.000000f, 0.000000f }, \r
278         { -0.850651f, 0.000000f, 0.525731f }, \r
279         { -0.955423f, -0.295242f, 0.000000f }, \r
280         { -0.951056f, -0.162460f, 0.262866f }, \r
281         { -0.864188f, 0.442863f, -0.238856f }, \r
282         { -0.951056f, 0.162460f, -0.262866f }, \r
283         { -0.809017f, 0.309017f, -0.500000f }, \r
284         { -0.864188f, -0.442863f, -0.238856f },\r
285         { -0.951056f, -0.162460f, -0.262866f }, \r
286         { -0.809017f, -0.309017f, -0.500000f }, \r
287         { -0.681718f, 0.147621f, -0.716567f }, \r
288         { -0.681718f, -0.147621f, -0.716567f }, \r
289         { -0.850651f, 0.000000f, -0.525731f }, \r
290         { -0.688191f, 0.587785f, -0.425325f }, \r
291         { -0.587785f, 0.425325f, -0.688191f }, \r
292         { -0.425325f, 0.688191f, -0.587785f }, \r
293         { -0.425325f, -0.688191f, -0.587785f }, \r
294         { -0.587785f, -0.425325f, -0.688191f }, \r
295         { -0.688191f, -0.587785f, -0.425325f }, \r
296 };\r
297 \r
298 \r
299 // _md2_canload()\r
300 \r
301 static int _md2_canload( PM_PARAMS_CANLOAD )\r
302 {\r
303         md2_t   *md2;\r
304 \r
305         /* to keep the compiler happy */\r
306         *fileName = *fileName;\r
307 \r
308         /* sanity check */\r
309         if( bufSize < ( sizeof( *md2 ) * 2) )\r
310                 return PICO_PMV_ERROR_SIZE;\r
311         \r
312         /* set as md2 */\r
313         md2 = (md2_t*) buffer;\r
314         \r
315         /* check md2 magic */\r
316         if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) \r
317                 return PICO_PMV_ERROR_IDENT;\r
318         \r
319         /* check md2 version */\r
320         if( _pico_little_long( md2->version ) != MD2_VERSION )\r
321                 return PICO_PMV_ERROR_VERSION;\r
322 \r
323         /* file seems to be a valid md2 */\r
324         return PICO_PMV_OK;\r
325 }\r
326 \r
327 \r
328 \r
329 // _md2_load() loads a quake2 md2 model file.\r
330 \r
331 \r
332 static picoModel_t *_md2_load( PM_PARAMS_LOAD )\r
333 {\r
334         int                             i, j, dups, dup_index;\r
335         short                   tot_numVerts;\r
336         index_LUT_t             *p_index_LUT, *p_index_LUT2, *p_index_LUT3;\r
337         index_DUP_LUT_t *p_index_LUT_DUPS;\r
338         md2Triangle_t   *p_md2Triangle;\r
339 \r
340         char                    skinname[ MD2_MAX_SKINNAME ];\r
341         md2_t                   *md2;\r
342         md2St_t                 *texCoord;\r
343         md2Frame_t              *frame;\r
344         md2Triangle_t   *triangle;\r
345         md2XyzNormal_t  *vertex;\r
346 \r
347         picoByte_t      *bb;\r
348         picoModel_t             *picoModel;\r
349         picoSurface_t   *picoSurface;\r
350         picoShader_t    *picoShader;\r
351         picoVec3_t              xyz, normal;\r
352         picoVec2_t              st;\r
353         picoColor_t             color;\r
354         \r
355 \r
356         // md2 loading\r
357         _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );\r
358 \r
359         /* set as md2 */\r
360         bb = (picoByte_t*) buffer;\r
361         md2     = (md2_t*) buffer;\r
362 \r
363         /* check ident and version */\r
364         if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )\r
365         {\r
366                 /* not an md2 file (todo: set error) */\r
367                 _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );\r
368                 return NULL;\r
369         }\r
370         \r
371         // swap md2\r
372         md2->version = _pico_little_long( md2->version );\r
373 \r
374         md2->skinWidth = _pico_little_long( md2->skinWidth );\r
375         md2->skinHeight = _pico_little_long( md2->skinHeight );\r
376         md2->frameSize = _pico_little_long( md2->frameSize );\r
377 \r
378         md2->numSkins = _pico_little_long( md2->numSkins );\r
379         md2->numXYZ = _pico_little_long( md2->numXYZ );\r
380         md2->numST = _pico_little_long( md2->numST );\r
381         md2->numTris = _pico_little_long( md2->numTris );\r
382         md2->numGLCmds = _pico_little_long( md2->numGLCmds );\r
383         md2->numFrames = _pico_little_long( md2->numFrames );\r
384 \r
385         md2->ofsSkins = _pico_little_long( md2->ofsSkins );\r
386         md2->ofsST = _pico_little_long( md2->ofsST );\r
387         md2->ofsTris = _pico_little_long( md2->ofsTris );\r
388         md2->ofsFrames = _pico_little_long( md2->ofsFrames );\r
389         md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );\r
390         md2->ofsEnd = _pico_little_long( md2->ofsEnd );\r
391 \r
392         // do frame check\r
393         if( md2->numFrames < 1 )\r
394         {\r
395                 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );\r
396                 return NULL;\r
397         }\r
398         \r
399         if( frameNum < 0 || frameNum >= md2->numFrames )\r
400         {\r
401                 _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );\r
402                 return NULL;\r
403         }\r
404 \r
405         // Setup Frame\r
406         frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));\r
407 \r
408         // swap frame scale and translation\r
409         for( i = 0; i < 3; i++ )\r
410         {\r
411                 frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );\r
412                 frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );\r
413         }\r
414 \r
415         // swap triangles\r
416         triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );\r
417         for( i = 0; i < md2->numTris; i++, triangle++ )\r
418         {\r
419                 for( j = 0; j < 3; j++ )\r
420                 {\r
421                         triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );\r
422                         triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );\r
423                 }\r
424         }\r
425 \r
426         // swap st coords\r
427         texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );\r
428         for( i = 0; i < md2->numST; i++, texCoord++ )\r
429         {\r
430                 texCoord->s = _pico_little_short( texCoord->s );\r
431                 texCoord->t = _pico_little_short( texCoord->t );\r
432         }\r
433 \r
434         // set Skin Name\r
435         strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME );\r
436 \r
437         // Print out md2 values\r
438         _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 );\r
439 \r
440         // detox Skin name\r
441         _pico_setfext( skinname, "" );\r
442         _pico_unixify( skinname );\r
443 \r
444         /* create new pico model */\r
445         picoModel = PicoNewModel();\r
446         if( picoModel == NULL )\r
447         {\r
448                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );\r
449                 return NULL;\r
450         }\r
451 \r
452         /* do model setup */\r
453         PicoSetModelFrameNum( picoModel, frameNum );\r
454         PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */\r
455         PicoSetModelName( picoModel, fileName );\r
456         PicoSetModelFileName( picoModel, fileName );\r
457 \r
458         // allocate new pico surface\r
459         picoSurface = PicoNewSurface( picoModel );\r
460         if( picoSurface == NULL )\r
461         {\r
462                 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );\r
463                 PicoFreeModel( picoModel );\r
464                 return NULL;\r
465         }\r
466 \r
467 \r
468         PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );\r
469         PicoSetSurfaceName( picoSurface, frame->name );\r
470         picoShader = PicoNewShader( picoModel );\r
471         if( picoShader == NULL )\r
472         {\r
473                 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );\r
474                 PicoFreeModel( picoModel );\r
475                 return NULL;\r
476         }\r
477 \r
478         PicoSetShaderName( picoShader, skinname );\r
479 \r
480         // associate current surface with newly created shader\r
481         PicoSetSurfaceShader( picoSurface, picoShader );\r
482 \r
483         // Init LUT for Verts\r
484         p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);\r
485         for(i=0; i<md2->numXYZ; i++)\r
486         {\r
487                 p_index_LUT[i].Vert = -1;\r
488                 p_index_LUT[i].ST = -1;\r
489                 p_index_LUT[i].next = NULL;\r
490         }\r
491 \r
492         // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.\r
493         tot_numVerts = md2->numXYZ;\r
494         dups = 0;\r
495         for(i=0; i<md2->numTris; i++)\r
496         {\r
497                 p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i));\r
498                 for(j=0; j<3; j++)\r
499                 {\r
500                         if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry\r
501                                 p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];\r
502 \r
503                         else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry\r
504                                 continue;\r
505 \r
506                         else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) )  // Not equal to Main entry, and no LL entry\r
507                         {       // Add first entry of LL from Main\r
508                                 p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));\r
509                                 if (p_index_LUT2 == NULL)\r
510                                         _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
511                                 p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;\r
512                                 p_index_LUT2->Vert = dups;\r
513                                 p_index_LUT2->ST = p_md2Triangle->index_st[j];\r
514                                 p_index_LUT2->next = NULL;\r
515                                 p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk\r
516                                 dups++;\r
517                         }\r
518                         else // Try to find in LL from Main Entry\r
519                         {\r
520                                 p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next;\r
521                                 while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL\r
522                                 {\r
523                                         p_index_LUT3 = p_index_LUT2;\r
524                                         p_index_LUT2 = p_index_LUT2->next;\r
525                                 }\r
526                                 p_index_LUT2 = p_index_LUT3;\r
527 \r
528                                 if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it\r
529                                 {\r
530                                         p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk\r
531                                         continue;\r
532                                 }\r
533 \r
534                                 if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.\r
535                                 {\r
536                                         // Add the Entry\r
537                                         p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));\r
538                                         if (p_index_LUT3 == NULL)\r
539                                                 _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
540                                         p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;\r
541                                         p_index_LUT3->Vert = p_md2Triangle->index_xyz[j];\r
542                                         p_index_LUT3->ST = p_md2Triangle->index_st[j];\r
543                                         p_index_LUT3->next = NULL;\r
544                                         p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk\r
545                                         dups++;\r
546                                 }\r
547                         }\r
548                 }\r
549         }\r
550 \r
551         // malloc and build array for Dup STs\r
552         p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);\r
553         if (p_index_LUT_DUPS == NULL)\r
554                 _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
555 \r
556         dup_index = 0;\r
557         for(i=0; i<md2->numXYZ; i++)\r
558         {\r
559                 p_index_LUT2 = p_index_LUT[i].next;\r
560                 while (p_index_LUT2 != NULL)\r
561                 {\r
562                         p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;\r
563                         p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;\r
564                         dup_index++;\r
565                         p_index_LUT2 = p_index_LUT2->next;\r
566                 }\r
567         }\r
568 \r
569         // Build Picomodel\r
570         triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );\r
571         texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );\r
572         vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) );\r
573         for( j = 0; j < md2->numTris; j++, triangle++ )\r
574         {\r
575                 PicoSetSurfaceIndex( picoSurface, j*3   , triangle->index_xyz[0] );\r
576                 PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );\r
577                 PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );\r
578         }\r
579 \r
580         for(i=0; i< md2->numXYZ; i++, vertex++)\r
581         {\r
582                 /* set vertex origin */\r
583                 xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];\r
584                 xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];\r
585                 xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];\r
586                 PicoSetSurfaceXYZ( picoSurface, i , xyz );\r
587 \r
588                 /* set normal */\r
589                 normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];\r
590                 normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];\r
591                 normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];\r
592                 PicoSetSurfaceNormal( picoSurface, i , normal );\r
593 \r
594                 /* set st coords */\r
595                 st[ 0 ] =  ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth));\r
596                 st[ 1 ] =  (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight));\r
597                 PicoSetSurfaceST( picoSurface, 0, i , st );\r
598         }\r
599 \r
600         if (dups)\r
601         {\r
602                 for(i=0; i<dups; i++)\r
603                 {\r
604                         j = p_index_LUT_DUPS[i].OldVert;\r
605                         /* set vertex origin */\r
606                         xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0];\r
607                         xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1];\r
608                         xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2];\r
609                         PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz );\r
610 \r
611                         /* set normal */\r
612                         normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0];\r
613                         normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1];\r
614                         normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2];\r
615                         PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal );\r
616 \r
617                         /* set st coords */\r
618                         st[ 0 ] =  ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth));\r
619                         st[ 1 ] =  (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight));\r
620                         PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st );\r
621                 }\r
622         }\r
623 \r
624         /* set color */\r
625         PicoSetSurfaceColor( picoSurface, 0, 0, color );\r
626 \r
627         // Free up malloc'ed LL entries\r
628         for(i=0; i<md2->numXYZ; i++)\r
629         {\r
630                 if(p_index_LUT[i].next != NULL)\r
631                 {\r
632                         p_index_LUT2 = p_index_LUT[i].next;\r
633                         do {\r
634                                 p_index_LUT3 = p_index_LUT2->next;\r
635                                 _pico_free(p_index_LUT2);\r
636                                 p_index_LUT2 = p_index_LUT3;\r
637                                 dups--;\r
638                         } while (p_index_LUT2 != NULL);\r
639                 }\r
640         }\r
641 \r
642         if (dups)\r
643                 _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");\r
644 \r
645         // Free malloc'ed LUTs\r
646         _pico_free(p_index_LUT);\r
647         _pico_free(p_index_LUT_DUPS);\r
648 \r
649         /* return the new pico model */\r
650         return picoModel;\r
651 \r
652 }\r
653 \r
654 \r
655 \r
656 /* pico file format module definition */\r
657 const picoModule_t picoModuleMD2 =\r
658 {\r
659         "0.875",                                                /* module version string */\r
660         "Quake 2 MD2",                                  /* module display name */\r
661         "Nurail",                                               /* author's name */\r
662         "2003 Nurail",                                  /* module copyright */\r
663         {\r
664                 "md2", NULL, NULL, NULL         /* default extensions to use */\r
665         },\r
666         _md2_canload,                                   /* validation routine */\r
667         _md2_load,                                              /* load routine */\r
668          NULL,                                                  /* save validation routine */\r
669          NULL                                                   /* save routine */\r
670 };\r