1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
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.
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.
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.
33 ----------------------------------------------------------------------------- */
36 Nurail: Used pm_md3.c (Randy Reddig) as a template.
40 #include "picointernal.h"
43 /* md2 model format */
44 const char *MD2_MAGIC = "IDP2";
45 const int MD2_VERSION = 8;
47 #define MD2_NUMVERTEXNORMALS 162
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;
55 typedef struct index_LUT_s
75 byte v[3]; // scaled byte to fit in frame mins/maxs
76 byte lightnormalindex;
79 typedef struct md2Frame_s
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
89 /* md2 model file md2 structure */
115 float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =
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 },
284 static int _md2_canload( PM_PARAMS_CANLOAD ){
288 if ( (size_t) bufSize < ( sizeof( *md2 ) * 2 ) ) {
289 return PICO_PMV_ERROR_SIZE;
293 md2 = (const md2_t*) buffer;
295 /* check md2 magic */
296 if ( *( (const int*) md2->magic ) != *( (const int*) MD2_MAGIC ) ) {
297 return PICO_PMV_ERROR_IDENT;
300 /* check md2 version */
301 if ( _pico_little_long( md2->version ) != MD2_VERSION ) {
302 return PICO_PMV_ERROR_VERSION;
305 /* file seems to be a valid md2 */
311 // _md2_load() loads a quake2 md2 model file.
314 static picoModel_t *_md2_load( PM_PARAMS_LOAD ){
316 index_LUT_t *p_index_LUT;
317 md2Triangle_t *p_md2Triangle;
319 char skinname[ MD2_MAX_SKINNAME + 1 ];
320 skinname[ MD2_MAX_SKINNAME] = '\0';
324 md2Triangle_t *triangle;
325 md2XyzNormal_t *vertex;
327 picoByte_t *bb, *bb0;
328 picoModel_t *picoModel;
329 picoSurface_t *picoSurface;
330 picoShader_t *picoShader;
331 picoVec3_t xyz, normal;
336 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
337 memcpy( bb, buffer, bufSize );
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 );
349 md2->version = _pico_little_long( md2->version );
351 md2->skinWidth = _pico_little_long( md2->skinWidth );
352 md2->skinHeight = _pico_little_long( md2->skinHeight );
353 md2->frameSize = _pico_little_long( md2->frameSize );
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 );
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 );
370 if ( md2->numFrames < 1 ) {
371 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
376 if ( frameNum < 0 || frameNum >= md2->numFrames ) {
377 _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
383 frame = (md2Frame_t *) ( bb + md2->ofsFrames + ( sizeof( md2Frame_t ) * frameNum ) );
385 // swap frame scale and translation
386 for ( i = 0; i < 3; i++ )
388 frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
389 frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
393 triangle = (md2Triangle_t *) ( (picoByte_t *) ( bb + md2->ofsTris ) );
394 for ( i = 0; i < md2->numTris; i++, triangle++ )
396 for ( j = 0; j < 3; j++ )
398 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
399 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
404 texCoord = (md2St_t*) ( (picoByte_t *) ( bb + md2->ofsST ) );
405 for ( i = 0; i < md2->numST; i++, texCoord++ )
407 texCoord->s = _pico_little_short( texCoord->s );
408 texCoord->t = _pico_little_short( texCoord->t );
412 strncpy( skinname, (const char *) ( bb + md2->ofsSkins ), MD2_MAX_SKINNAME );
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 );
418 _pico_setfext( skinname, NULL );
419 _pico_unixify( skinname );
421 /* create new pico model */
422 picoModel = PicoNewModel();
423 if ( picoModel == NULL ) {
424 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
430 PicoSetModelFrameNum( picoModel, frameNum );
431 PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */
432 PicoSetModelName( picoModel, fileName );
433 PicoSetModelFileName( picoModel, fileName );
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 );
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 );
455 PicoSetShaderName( picoShader, skinname );
457 // associate current surface with newly created shader
458 PicoSetSurfaceShader( picoSurface, picoShader );
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++ )
464 p_index_LUT[i].Vert = -1;
465 p_index_LUT[i].ST = -1;
468 index_LUT_t* p_index_LUT_dups = _pico_alloc( sizeof( index_LUT_t ) * md2->numTris * 3 ); //overallocating
470 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
472 for ( i = 0; i < md2->numTris; i++ )
474 p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + ( sizeof( md2Triangle_t ) * i ) );
475 for ( j = 0; j < 3; j++ )
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;
484 else if ( iST == p_index_LUT[iXYZ].ST && iXYZ == p_index_LUT[iXYZ].Vert ) { // Equal to Main Entry
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
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
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++ )
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] );
519 for ( i = 0; i < md2->numXYZ; i++, vertex++ )
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 );
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 );
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 );
539 PicoSetSurfaceColor( picoSurface, 0, i, picoColor_white );
542 for ( i = 0; i < dups; i++ )
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 );
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 );
558 j = p_index_LUT_dups[i].ST;
560 st[ 0 ] = ( ( texCoord[j].s ) / ( (float)md2->skinWidth ) );
561 st[ 1 ] = ( texCoord[j].t / ( (float)md2->skinHeight ) );
562 PicoSetSurfaceST( picoSurface, 0, surfN, st );
565 PicoSetSurfaceColor( picoSurface, 0, surfN, picoColor_white );
568 // Free malloc'ed LUTs
569 _pico_free( p_index_LUT );
570 _pico_free( p_index_LUT_dups );
572 /* return the new pico model */
580 /* pico file format module definition */
581 const picoModule_t picoModuleMD2 =
583 "0.875", /* module version string */
584 "Quake 2 MD2", /* module display name */
585 "Nurail", /* author's name */
586 "2003 Nurail", /* module copyright */
588 "md2", NULL, NULL, NULL /* default extensions to use */
590 _md2_canload, /* validation routine */
591 _md2_load, /* load routine */
592 NULL, /* save validation routine */
593 NULL /* save routine */