00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #define PM_MD2_C
00041
00042
00043 #include "picointernal.h"
00044 #include "../../../shared/byte.h"
00045
00046
00047 #define MD2_MAGIC "IDP2"
00048 #define MD2_VERSION 8
00049
00050 #define MD2_NUMVERTEXNORMALS 162
00051 #define MD2_MAX_SKINNAME 64
00052 #define MD2_MAX_TRIANGLES 4096
00053 #define MD2_MAX_VERTS 2048
00054 #define MD2_MAX_FRAMES 512
00055 #define MD2_MAX_MD2SKINS 32
00056 #define MD2_MAX_SKINNAME 64
00057
00058 #ifndef byte
00059 #define byte unsigned char
00060 #endif
00061
00062 typedef struct
00063 {
00064 short s;
00065 short t;
00066 } md2St_t;
00067
00068 typedef struct
00069 {
00070 short index_xyz[3];
00071 short index_st[3];
00072 } md2Triangle_t;
00073
00074 typedef struct
00075 {
00076 byte v[3];
00077 byte lightnormalindex;
00078 } md2XyzNormal_t;
00079
00080 typedef struct md2Frame_s
00081 {
00082 float scale[3];
00083 float translate[3];
00084 char name[16];
00085 md2XyzNormal_t verts[1];
00086 } md2Frame_t;
00087
00088
00089 typedef struct md2_s
00090 {
00091 char magic[4];
00092 int version;
00093
00094 int skinWidth;
00095 int skinHeight;
00096 int frameSize;
00097
00098 int numSkins;
00099 int numXYZ;
00100 int numST;
00101 int numTris;
00102 int numGLCmds;
00103 int numFrames;
00104
00105 int ofsSkins;
00106 int ofsST;
00107 int ofsTris;
00108 int ofsFrames;
00109 int ofsGLCmds;
00110 int ofsEnd;
00111 } md2_t;
00112
00113 static const float md2_normals[MD2_NUMVERTEXNORMALS][3] = { { -0.525731f, 0.000000f, 0.850651f }, { -0.442863f,
00114 0.238856f, 0.864188f }, { -0.295242f, 0.000000f, 0.955423f }, { -0.309017f, 0.500000f, 0.809017f }, {
00115 -0.162460f, 0.262866f, 0.951056f }, { 0.000000f, 0.000000f, 1.000000f }, { 0.000000f, 0.850651f, 0.525731f }, {
00116 -0.147621f, 0.716567f, 0.681718f }, { 0.147621f, 0.716567f, 0.681718f }, { 0.000000f, 0.525731f, 0.850651f }, {
00117 0.309017f, 0.500000f, 0.809017f }, { 0.525731f, 0.000000f, 0.850651f }, { 0.295242f, 0.000000f, 0.955423f }, {
00118 0.442863f, 0.238856f, 0.864188f }, { 0.162460f, 0.262866f, 0.951056f }, { -0.681718f, 0.147621f, 0.716567f }, {
00119 -0.809017f, 0.309017f, 0.500000f }, { -0.587785f, 0.425325f, 0.688191f }, { -0.850651f, 0.525731f, 0.000000f },
00120 { -0.864188f, 0.442863f, 0.238856f }, { -0.716567f, 0.681718f, 0.147621f },
00121 { -0.688191f, 0.587785f, 0.425325f }, { -0.500000f, 0.809017f, 0.309017f },
00122 { -0.238856f, 0.864188f, 0.442863f }, { -0.425325f, 0.688191f, 0.587785f },
00123 { -0.716567f, 0.681718f, -0.147621f }, { -0.500000f, 0.809017f, -0.309017f }, { -0.525731f, 0.850651f,
00124 0.000000f }, { 0.000000f, 0.850651f, -0.525731f }, { -0.238856f, 0.864188f, -0.442863f }, { 0.000000f,
00125 0.955423f, -0.295242f }, { -0.262866f, 0.951056f, -0.162460f }, { 0.000000f, 1.000000f, 0.000000f }, {
00126 0.000000f, 0.955423f, 0.295242f }, { -0.262866f, 0.951056f, 0.162460f }, { 0.238856f, 0.864188f,
00127 0.442863f }, { 0.262866f, 0.951056f, 0.162460f }, { 0.500000f, 0.809017f, 0.309017f }, { 0.238856f,
00128 0.864188f, -0.442863f }, { 0.262866f, 0.951056f, -0.162460f }, { 0.500000f, 0.809017f, -0.309017f }, {
00129 0.850651f, 0.525731f, 0.000000f }, { 0.716567f, 0.681718f, 0.147621f }, { 0.716567f, 0.681718f,
00130 -0.147621f }, { 0.525731f, 0.850651f, 0.000000f }, { 0.425325f, 0.688191f, 0.587785f }, { 0.864188f,
00131 0.442863f, 0.238856f }, { 0.688191f, 0.587785f, 0.425325f }, { 0.809017f, 0.309017f, 0.500000f }, {
00132 0.681718f, 0.147621f, 0.716567f }, { 0.587785f, 0.425325f, 0.688191f }, { 0.955423f, 0.295242f,
00133 0.000000f }, { 1.000000f, 0.000000f, 0.000000f }, { 0.951056f, 0.162460f, 0.262866f }, { 0.850651f,
00134 -0.525731f, 0.000000f }, { 0.955423f, -0.295242f, 0.000000f }, { 0.864188f, -0.442863f, 0.238856f }, {
00135 0.951056f, -0.162460f, 0.262866f }, { 0.809017f, -0.309017f, 0.500000f }, { 0.681718f, -0.147621f,
00136 0.716567f }, { 0.850651f, 0.000000f, 0.525731f }, { 0.864188f, 0.442863f, -0.238856f }, { 0.809017f,
00137 0.309017f, -0.500000f }, { 0.951056f, 0.162460f, -0.262866f }, { 0.525731f, 0.000000f, -0.850651f }, {
00138 0.681718f, 0.147621f, -0.716567f }, { 0.681718f, -0.147621f, -0.716567f }, { 0.850651f, 0.000000f,
00139 -0.525731f }, { 0.809017f, -0.309017f, -0.500000f }, { 0.864188f, -0.442863f, -0.238856f }, {
00140 0.951056f, -0.162460f, -0.262866f }, { 0.147621f, 0.716567f, -0.681718f }, { 0.309017f, 0.500000f,
00141 -0.809017f }, { 0.425325f, 0.688191f, -0.587785f }, { 0.442863f, 0.238856f, -0.864188f }, { 0.587785f,
00142 0.425325f, -0.688191f }, { 0.688191f, 0.587785f, -0.425325f }, { -0.147621f, 0.716567f, -0.681718f }, {
00143 -0.309017f, 0.500000f, -0.809017f }, { 0.000000f, 0.525731f, -0.850651f }, { -0.525731f, 0.000000f,
00144 -0.850651f }, { -0.442863f, 0.238856f, -0.864188f }, { -0.295242f, 0.000000f, -0.955423f }, {
00145 -0.162460f, 0.262866f, -0.951056f }, { 0.000000f, 0.000000f, -1.000000f }, { 0.295242f, 0.000000f,
00146 -0.955423f }, { 0.162460f, 0.262866f, -0.951056f }, { -0.442863f, -0.238856f, -0.864188f }, {
00147 -0.309017f, -0.500000f, -0.809017f }, { -0.162460f, -0.262866f, -0.951056f }, { 0.000000f, -0.850651f,
00148 -0.525731f }, { -0.147621f, -0.716567f, -0.681718f }, { 0.147621f, -0.716567f, -0.681718f }, {
00149 0.000000f, -0.525731f, -0.850651f }, { 0.309017f, -0.500000f, -0.809017f }, { 0.442863f, -0.238856f,
00150 -0.864188f }, { 0.162460f, -0.262866f, -0.951056f }, { 0.238856f, -0.864188f, -0.442863f }, {
00151 0.500000f, -0.809017f, -0.309017f }, { 0.425325f, -0.688191f, -0.587785f }, { 0.716567f, -0.681718f,
00152 -0.147621f }, { 0.688191f, -0.587785f, -0.425325f }, { 0.587785f, -0.425325f, -0.688191f }, {
00153 0.000000f, -0.955423f, -0.295242f }, { 0.000000f, -1.000000f, 0.000000f }, { 0.262866f, -0.951056f,
00154 -0.162460f }, { 0.000000f, -0.850651f, 0.525731f }, { 0.000000f, -0.955423f, 0.295242f }, { 0.238856f,
00155 -0.864188f, 0.442863f }, { 0.262866f, -0.951056f, 0.162460f }, { 0.500000f, -0.809017f, 0.309017f }, {
00156 0.716567f, -0.681718f, 0.147621f }, { 0.525731f, -0.850651f, 0.000000f }, { -0.238856f, -0.864188f,
00157 -0.442863f }, { -0.500000f, -0.809017f, -0.309017f }, { -0.262866f, -0.951056f, -0.162460f }, {
00158 -0.850651f, -0.525731f, 0.000000f }, { -0.716567f, -0.681718f, -0.147621f }, { -0.716567f, -0.681718f,
00159 0.147621f }, { -0.525731f, -0.850651f, 0.000000f }, { -0.500000f, -0.809017f, 0.309017f }, {
00160 -0.238856f, -0.864188f, 0.442863f }, { -0.262866f, -0.951056f, 0.162460f }, { -0.864188f, -0.442863f,
00161 0.238856f }, { -0.809017f, -0.309017f, 0.500000f }, { -0.688191f, -0.587785f, 0.425325f }, {
00162 -0.681718f, -0.147621f, 0.716567f }, { -0.442863f, -0.238856f, 0.864188f }, { -0.587785f, -0.425325f,
00163 0.688191f }, { -0.309017f, -0.500000f, 0.809017f }, { -0.147621f, -0.716567f, 0.681718f }, {
00164 -0.425325f, -0.688191f, 0.587785f }, { -0.162460f, -0.262866f, 0.951056f }, { 0.442863f, -0.238856f,
00165 0.864188f }, { 0.162460f, -0.262866f, 0.951056f }, { 0.309017f, -0.500000f, 0.809017f }, { 0.147621f,
00166 -0.716567f, 0.681718f }, { 0.000000f, -0.525731f, 0.850651f }, { 0.425325f, -0.688191f, 0.587785f }, {
00167 0.587785f, -0.425325f, 0.688191f }, { 0.688191f, -0.587785f, 0.425325f }, { -0.955423f, 0.295242f,
00168 0.000000f }, { -0.951056f, 0.162460f, 0.262866f }, { -1.000000f, 0.000000f, 0.000000f }, { -0.850651f,
00169 0.000000f, 0.525731f }, { -0.955423f, -0.295242f, 0.000000f }, { -0.951056f, -0.162460f, 0.262866f }, {
00170 -0.864188f, 0.442863f, -0.238856f }, { -0.951056f, 0.162460f, -0.262866f }, { -0.809017f, 0.309017f,
00171 -0.500000f }, { -0.864188f, -0.442863f, -0.238856f }, { -0.951056f, -0.162460f, -0.262866f }, {
00172 -0.809017f, -0.309017f, -0.500000f }, { -0.681718f, 0.147621f, -0.716567f }, { -0.681718f, -0.147621f,
00173 -0.716567f }, { -0.850651f, 0.000000f, -0.525731f }, { -0.688191f, 0.587785f, -0.425325f }, {
00174 -0.587785f, 0.425325f, -0.688191f }, { -0.425325f, 0.688191f, -0.587785f }, { -0.425325f, -0.688191f,
00175 -0.587785f }, { -0.587785f, -0.425325f, -0.688191f }, { -0.688191f, -0.587785f, -0.425325f }, };
00176
00180 static int _md2_canload (PM_PARAMS_CANLOAD)
00181 {
00182 md2_t *md2;
00183
00184
00185 if (bufSize < (sizeof(*md2) * 2))
00186 return PICO_PMV_ERROR_SIZE;
00187
00188
00189 md2 = (md2_t*) buffer;
00190
00191
00192 if (*((int*) md2->magic) != *((int*) MD2_MAGIC))
00193 return PICO_PMV_ERROR_IDENT;
00194
00195
00196 if (_pico_little_long(md2->version) != MD2_VERSION)
00197 return PICO_PMV_ERROR_VERSION;
00198
00199
00200 return PICO_PMV_OK;
00201 }
00202
00206 static picoModel_t *_md2_load (PM_PARAMS_LOAD)
00207 {
00208 int i, j;
00209
00210 char skinname[MD2_MAX_SKINNAME];
00211 md2_t *md2;
00212 md2St_t *texCoord;
00213 md2Frame_t *frame;
00214 md2Triangle_t *triangle;
00215 md2XyzNormal_t *vertex;
00216
00217 picoByte_t *bb;
00218 picoModel_t *picoModel;
00219 picoSurface_t *picoSurface;
00220 picoShader_t *picoShader;
00221 picoColor_t color;
00222
00223 int numIndexes, numVerts;
00224 double isw, ish;
00225 int tempIndex[MD2_MAX_TRIANGLES * 3];
00226 int tempSTIndex[MD2_MAX_TRIANGLES * 3];
00227 int indRemap[MD2_MAX_TRIANGLES * 3];
00228 int *outIndex;
00229
00230
00231 bb = (picoByte_t*) buffer;
00232 md2 = (md2_t*) buffer;
00233
00234
00235 if (*((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long(md2->version) != MD2_VERSION) {
00236
00237 _pico_printf(PICO_ERROR, "%s is not an MD2 File!", fileName);
00238 return NULL;
00239 }
00240
00241
00242 md2->version = _pico_little_long(md2->version);
00243
00244 md2->skinWidth = _pico_little_long(md2->skinWidth);
00245 md2->skinHeight = _pico_little_long(md2->skinHeight);
00246 md2->frameSize = _pico_little_long(md2->frameSize);
00247
00248 md2->numSkins = _pico_little_long(md2->numSkins);
00249 md2->numXYZ = _pico_little_long(md2->numXYZ);
00250 md2->numST = _pico_little_long(md2->numST);
00251 md2->numTris = _pico_little_long(md2->numTris);
00252 md2->numGLCmds = _pico_little_long(md2->numGLCmds);
00253 md2->numFrames = _pico_little_long(md2->numFrames);
00254
00255 md2->ofsSkins = _pico_little_long(md2->ofsSkins);
00256 md2->ofsST = _pico_little_long(md2->ofsST);
00257 md2->ofsTris = _pico_little_long(md2->ofsTris);
00258 md2->ofsFrames = _pico_little_long(md2->ofsFrames);
00259 md2->ofsGLCmds = _pico_little_long(md2->ofsGLCmds);
00260 md2->ofsEnd = _pico_little_long(md2->ofsEnd);
00261
00262
00263 if (md2->numFrames < 1) {
00264 _pico_printf(PICO_ERROR, "%s has 0 frames!", fileName);
00265 return NULL;
00266 }
00267
00268 if (frameNum < 0 || frameNum >= md2->numFrames) {
00269 _pico_printf(PICO_ERROR, "Invalid or out-of-range MD2 frame specified");
00270 return NULL;
00271 }
00272
00273
00274 frame = (md2Frame_t *) (bb + md2->ofsFrames);
00275
00276
00277 for (i = 0; i < 3; i++) {
00278 frame->scale[i] = _pico_little_float(frame->scale[i]);
00279 frame->translate[i] = _pico_little_float(frame->translate[i]);
00280 }
00281
00282
00283 triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris));
00284 for (i = 0; i < md2->numTris; i++, triangle++) {
00285 for (j = 0; j < 3; j++) {
00286 triangle->index_xyz[j] = _pico_little_short(triangle->index_xyz[j]);
00287 triangle->index_st[j] = _pico_little_short(triangle->index_st[j]);
00288 }
00289 }
00290
00291
00292 texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST));
00293 for (i = 0; i < md2->numST; i++, texCoord++) {
00294 texCoord->s = _pico_little_short(texCoord->s);
00295 texCoord->t = _pico_little_short(texCoord->t);
00296 }
00297
00298
00299 _pico_printf(PICO_VERBOSE, "Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\n\n",
00300 md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames);
00301
00302
00303 picoModel = PicoNewModel();
00304 if (picoModel == NULL) {
00305 _pico_printf(PICO_ERROR, "Unable to allocate a new model");
00306 return NULL;
00307 }
00308
00309
00310 PicoSetModelFrameNum(picoModel, frameNum);
00311 PicoSetModelNumFrames(picoModel, md2->numFrames);
00312 PicoSetModelName(picoModel, fileName);
00313 PicoSetModelFileName(picoModel, fileName);
00314
00315 for (i = 0; i < md2->numSkins; i++) {
00316 char *offsetSkin = (char*) (bb + md2->ofsSkins) + i * MD2_MAX_SKINNAME;
00317
00318 strncpy(skinname, offsetSkin, MD2_MAX_SKINNAME);
00319
00320
00321 if (skinname[0] == '.') {
00322 char path[MD2_MAX_SKINNAME];
00323 char skinnameRelative[MD2_MAX_SKINNAME];
00324 strncpy(path, fileName, MD2_MAX_SKINNAME);
00325 strncpy(skinnameRelative, skinname, MD2_MAX_SKINNAME);
00326 _pico_unixify(path);
00327 for (j = MD2_MAX_SKINNAME; j--;) {
00328 if (path[j] == '/')
00329 break;
00330 path[j] = '\0';
00331 }
00332 snprintf(skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1]);
00333 }
00334 _pico_setfext(skinname, "");
00335
00336 picoShader = PicoNewShader(picoModel);
00337 if (picoShader == NULL) {
00338 _pico_printf(PICO_ERROR, "Unable to allocate a new model shader");
00339 PicoFreeModel(picoModel);
00340 return NULL;
00341 }
00342
00343 PicoSetShaderName(picoShader, skinname);
00344 }
00345
00346
00347 picoSurface = PicoNewSurface(picoModel);
00348 if (picoSurface == NULL) {
00349 _pico_printf(PICO_ERROR, "Unable to allocate a new model surface");
00350 PicoFreeModel(picoModel);
00351 return NULL;
00352 }
00353
00354 PicoSetSurfaceType(picoSurface, PICO_TRIANGLES);
00355 PicoSetSurfaceName(picoSurface, frame->name);
00356
00357
00358 PicoSetSurfaceShader(picoSurface, PicoGetModelShader(picoModel, 0));
00359
00360
00361 _pico_set_color(color, 255, 255, 255, 255);
00362
00363 isw = 1.0 / (double)md2->skinWidth;
00364 ish = 1.0 / (double)md2->skinHeight;
00365
00366
00367 triangle = (md2Triangle_t *) ((picoByte_t *) bb + md2->ofsTris);
00368 texCoord = (md2St_t *) ((picoByte_t *) bb + md2->ofsST);
00369
00370 for (i = 0; i < md2->numTris; i++) {
00371 for (j = 0; j < 3; j++) {
00372 tempIndex[i * 3 + j] = triangle[i].index_xyz[j];
00373 tempSTIndex[i * 3 + j] = triangle[i].index_st[j];
00374 }
00375 }
00376
00377
00378 numIndexes = md2->numTris * 3;
00379 numVerts = 0;
00380 outIndex = (int *) _pico_alloc(sizeof(int) * numIndexes);
00381
00382 for (i = 0; i < numIndexes; i++)
00383 indRemap[i] = -1;
00384
00385 for (i = 0; i < numIndexes; i++) {
00386 if (indRemap[i] != -1)
00387 continue;
00388
00389
00390 for (j = i + 1; j < numIndexes; j++) {
00391 if (tempIndex[j] != tempIndex[i])
00392 continue;
00393 if (texCoord[tempSTIndex[j]].s != texCoord[tempSTIndex[i]].s
00394 || texCoord[tempSTIndex[j]].t != texCoord[tempSTIndex[i]].t)
00395 continue;
00396
00397 indRemap[j] = i;
00398 outIndex[j] = numVerts;
00399 }
00400
00401
00402 indRemap[i] = i;
00403 outIndex[i] = numVerts++;
00404 }
00405
00406 for (i = 0; i < numIndexes; i++) {
00407 if (indRemap[i] == i)
00408 continue;
00409
00410 outIndex[i] = outIndex[indRemap[i]];
00411 }
00412
00413 vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts));
00414 for (j = 0; j < numIndexes; j++) {
00415 const int index = outIndex[j];
00416 picoVec3_t xyz, normal;
00417 picoVec2_t st;
00418
00419 st[0] = (float)(((double)texCoord[tempSTIndex[indRemap[j]]].s) + 0.5) * isw;
00420 st[1] = (float)(((double)texCoord[tempSTIndex[indRemap[j]]].t) + 0.5) * isw;
00421
00422 xyz[0] = (int16_t)frame->verts[tempIndex[indRemap[j]]].v[0] * frame->scale[0] + frame->translate[0];
00423 xyz[1] = (int16_t)frame->verts[tempIndex[indRemap[j]]].v[1] * frame->scale[1] + frame->translate[1];
00424 xyz[2] = (int16_t)frame->verts[tempIndex[indRemap[j]]].v[2] * frame->scale[2] + frame->translate[2];
00425
00426
00427 normal[0] = md2_normals[frame->verts[tempIndex[indRemap[j]]].lightnormalindex][0];
00428 normal[1] = md2_normals[frame->verts[tempIndex[indRemap[j]]].lightnormalindex][1];
00429 normal[2] = md2_normals[frame->verts[tempIndex[indRemap[j]]].lightnormalindex][2];
00430
00431 PicoSetSurfaceIndex(picoSurface, j, index);
00432 PicoSetSurfaceXYZ(picoSurface, index, xyz);
00433 PicoSetSurfaceNormal(picoSurface, index, normal);
00434 PicoSetSurfaceST(picoSurface, 0, index, st);
00435
00436 PicoSetSurfaceColor(picoSurface, 0, index, color);
00437 }
00438
00439
00440 _pico_free(outIndex);
00441
00442
00443 return picoModel;
00444 }
00445
00446
00447 const picoModule_t picoModuleMD2 = { "0.875",
00448 "Quake 2 MD2",
00449 "Nurail",
00450 "2003 Nurail",
00451 { "md2", NULL, NULL, NULL
00452 }, _md2_canload,
00453 _md2_load,
00454 NULL,
00455 NULL
00456 };