/* * * Copyright(c) 2005-2007 David HENRY * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files(the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * modified for fixed point and probably other stuff by smealum, 2012 * * updated for compatibility with modern libraries and modified for * dsgmLib integration, 2014 * * WARNING: All 3D functionality is still unpolished and experimental */ #include "DSGM.h" #define getInterpData(i,j,n) interpTable[(i)+(((j)+((n)<<2))<<8)] /* Table of precalculated normals */ u32 anorms_table[162] = #include "DSGM_anorms.h" ; vect3D anorms_table2[162] = #include "DSGM_anorms2.h" ; static void packFrameData(DSGM_Model *mdl, md2_frame_t *f) { int i; f->min=vect(f->verts[0].v[0],f->verts[0].v[1],f->verts[0].v[2]); f->max=vect(f->verts[0].v[0],f->verts[0].v[1],f->verts[0].v[2]); for(i = 0; i < mdl->header.num_vertices; i++) { md2_vertex_t *pvert = &f->verts[i]; f->packedv10[i] = NORMAL_PACK(pvert->v[0],pvert->v[1],pvert->v[2]); if(pvert->v[0]min.x) f->min.x=pvert->v[0]; else if(pvert->v[0]>f->max.x) f->max.x=pvert->v[0]; if(pvert->v[1]min.y) f->min.y=pvert->v[1]; else if(pvert->v[1]>f->max.y) f->max.y=pvert->v[1]; if(pvert->v[2]min.z) f->min.z=pvert->v[2]; else if(pvert->v[2]>f->max.z) f->max.z=pvert->v[2]; } f->min = vect(mulf32(f->min.x, f->scale.x) * 128 * 32, mulf32(f->min.y, f->scale.y) * 128 * 32, mulf32(f->min.z, f->scale.z) * 128 * 32); f->max = vect(mulf32(f->max.x, f->scale.x) * 128 * 32, mulf32(f->max.y, f->scale.y) * 128 * 32, mulf32(f->max.z, f->scale.z) * 128 * 32); //f->min = vect(f->min.x * f->scale.x, f->min.y * f->scale.y, f->min.z * f->scale.z); //f->max = vect(f->max.x * f->scale.x, f->max.y * f->scale.y, f->max.z * f->scale.z); f->min = addVect(f->min, f->translate); f->max = addVect(f->max, f->translate); } static void packTexcoordData(DSGM_Model *mdl) { int i; for(i = 0; i < mdl->header.num_st; i++) { mdl->packedTexcoords[i] = TEXTURE_PACK(inttot16(mdl->texcoords[i].s), inttot16(mdl->texcoords[i].t)); } } static void trimName(char* name) { int i = 0; while(name[i]) { if(name[i] >= '0' && name[i] <= '9') { name[i] = 0; return; } i++; } } static void getAnimations(DSGM_Model *mdl) { if(!mdl || !mdl->frames) return; int i; char *oldstr = NULL; int n = 0; for(i = 0;i < mdl->header.num_frames; i++) { md2_frame_t *pframe = &mdl->frames[i]; trimName(pframe->name); if(strcmp(pframe->name, oldstr)) n++; oldstr = pframe->name; } mdl->numAnim = n; mdl->animations = malloc(sizeof(md2Anim_struct)*mdl->numAnim); n = 0; mdl->animations[0].start = 0; oldstr=mdl->frames[0].name; for(i = 0; i < mdl->header.num_frames; i++) { md2_frame_t *pframe = &mdl->frames[i]; if(strcmp(pframe->name, oldstr)) { mdl->animations[n++].end = i - 1; mdl->animations[n].start = i; } oldstr = pframe->name; } mdl->animations[n].end = i - 1; for(i = 0; i < mdl->numAnim; i++) { int j; u16 n = mdl->animations[i].end-mdl->animations[i].start + 1; for(j = 0; j < n; j++) { mdl->frames[mdl->animations[i].start+j].next = mdl->animations[i].start+((j+1)%n); } } } int DSGM_LoadModel(const char *filename, DSGM_Model *mdl) { FILE *fp; int i; //mdl->texture = createTexture(texname, "textures"); fp = fopen(filename, "rb"); if(!fp) { DSGM_Debug("Error: couldn't open \"%s\"!\n", filename); return 0; } /* Read header */ fread(&mdl->header, 1, sizeof(md2_header_t), fp); if((mdl->header.ident != 844121161) ||(mdl->header.version != 8)) { /* Error! */ DSGM_Debug("Error: bad version or identifier\n"); fclose(fp); return 0; } /* Memory allocations */ mdl->skins = (md2_skin_t *)malloc(sizeof(md2_skin_t) * mdl->header.num_skins); mdl->texcoords = (md2_texCoord_t *)malloc(sizeof(md2_texCoord_t) * mdl->header.num_st); mdl->triangles = (md2_triangle_t *)malloc(sizeof(md2_triangle_t) * mdl->header.num_tris); mdl->frames = (md2_frame_t *)malloc(sizeof(md2_frame_t) * mdl->header.num_frames); /* Read model data */ fseek(fp, mdl->header.offset_skins, SEEK_SET); fread(mdl->skins, sizeof(md2_skin_t), mdl->header.num_skins, fp); fseek(fp, mdl->header.offset_st, SEEK_SET); fread(mdl->texcoords, sizeof(md2_texCoord_t), mdl->header.num_st, fp); mdl->packedTexcoords = malloc(sizeof(u32) * mdl->header.num_st); packTexcoordData(mdl); fseek(fp, mdl->header.offset_tris, SEEK_SET); fread(mdl->triangles, sizeof(md2_triangle_t), mdl->header.num_tris, fp); /* Read frames */ fseek(fp, mdl->header.offset_frames, SEEK_SET); for(i = 0; i < mdl->header.num_frames; i++) { /* Memory allocation for vertices of this frame */ mdl->frames[i].verts = (md2_vertex_t *)malloc(sizeof(md2_vertex_t) * mdl->header.num_vertices); mdl->frames[i].packedv10 = (u32 *)malloc(sizeof(u32) * mdl->header.num_vertices); mdl->frames[i].displayList[0] = NULL; mdl->frames[i].displayList[1] = NULL; mdl->frames[i].displayList[2] = NULL; mdl->frames[i].displayList[3] = NULL; // mdl->frames[i].faceNormals = (vect3D *)malloc(sizeof(vect3D) * mdl->header.num_tris); vec3_t scale, trans; fread(scale, sizeof(vec3_t), 1, fp); fread(trans, sizeof(vec3_t), 1, fp); mdl->frames[i].scale = vect(floattof32(scale[0]), floattof32(scale[1]), floattof32(scale[2])); mdl->frames[i].translate = vect(floattof32(trans[0]), floattof32(trans[1]), floattof32(trans[2])); fread(mdl->frames[i].name, sizeof(char), 16, fp); fread(mdl->frames[i].verts, sizeof(md2_vertex_t), mdl->header.num_vertices, fp); packFrameData(mdl, &mdl->frames[i]); } getAnimations(mdl); fclose(fp); return 1; } static void freeMd2FrameData(md2_frame_t *f, bool dl) { if(!f) return; if(f->verts) free(f->verts); if(f->packedv10) free(f->packedv10); f->verts = NULL; f->packedVerts = NULL; f->packedv10 = NULL; if(dl) { if(f->displayList[0]) free(f->displayList[0]); if(f->displayList[1]) free(f->displayList[1]); if(f->displayList[2]) free(f->displayList[2]); if(f->displayList[3]) free(f->displayList[3]); f->displayList[0] = NULL; f->displayList[1] = NULL; f->displayList[2] = NULL; f->displayList[3] = NULL; } } void DSGM_FreeModel(DSGM_Model *mdl) { int i; if(mdl->skins) { free(mdl->skins); mdl->skins = NULL; } if(mdl->texcoords) { free(mdl->texcoords); free(mdl->packedTexcoords); mdl->texcoords = NULL; mdl->packedTexcoords = NULL; } if(mdl->triangles) { free(mdl->triangles); mdl->triangles = NULL; } if(mdl->frames) { for(i = 0; i < mdl->header.num_frames; ++i) { freeMd2FrameData(&mdl->frames[i], true); } free(mdl->frames); mdl->frames = NULL; } if(mdl->animations) free(mdl->animations); mdl->animations=NULL; } /*static void generateFrameDisplayList(int n, const DSGM_Model *mdl, u8 normals) { int i, j; if(!mdl) return; if((n < 0) ||(n > mdl->header.num_frames - 1)) return; md2_frame_t *pframe = &mdl->frames[n]; u32 *ptr = glBeginListDL(); glBeginDL(GL_TRIANGLES); for(i = 0; i < mdl->header.num_tris; i++) { for(j = 0; j < 3; j++) { glTexCoordPACKED(mdl->packedTexcoords[mdl->triangles[i].st[j]]); if(normals)glNormalDL(anorms_table[pframe->verts[mdl->triangles[i].vertex[j]].normalIndex]); glVertexPackedDL(NORMAL_PACK(pframe->verts[mdl->triangles[i].vertex[j]].v[0]*2,pframe->verts[mdl->triangles[i].vertex[j]].v[1]*2,pframe->verts[mdl->triangles[i].vertex[j]].v[2]*2)); } } // glEndDL(); u32 size = glEndListDL(); pframe->displayList[0] = malloc((size + 1)*4); if(pframe->displayList) memcpy(pframe->displayList[0],ptr, (size + 1) * 4); }*/ /*static void generateFrameDisplayListInterp(int n, int n2, int m, const DSGM_Model *mdl, u8 normals) { int i, j; if(!mdl) return; if((n < 0) ||(n > mdl->header.num_frames - 1)) return; if((n2 < 0) ||(n2 > mdl->header.num_frames - 1)) return; if(!m || m>3) return; md2_frame_t *pframe = &mdl->frames[n]; md2_frame_t *pframe2 = &mdl->frames[n2]; u32 *ptr = glBeginListDL(); glBeginDL(GL_TRIANGLES); for(i = 0; i < mdl->header.num_tris; i++) { for(j = 0; j < 3; j++) { md2_vertex_t *pvert = &pframe->verts[mdl->triangles[i].vertex[j]]; md2_vertex_t *pvert2 = &pframe2->verts[mdl->triangles[i].vertex[j]]; glTexCoordPACKED(mdl->packedTexcoords[mdl->triangles[i].st[j]]); if(normals) glNormalDL(anorms_table[pframe->verts[mdl->triangles[i].vertex[j]].normalIndex]); vect3D v = vect((pvert->v[0]*2+((pvert2->v[0]-pvert->v[0])*m)/2),(pvert->v[1]*2+((pvert2->v[1]-pvert->v[1])*m)/2),(pvert->v[2]*2+((pvert2->v[2]-pvert->v[2])*m)/2)); glVertexPackedDL(NORMAL_PACK(v.x,v.y,v.z)); } } // glEndDL(); u32 size = glEndListDL(); pframe->displayList[m] = malloc((size + 1) * 4); if(pframe->displayList) memcpy(pframe->displayList[m], ptr, (size + 1) * 4); }*/ /*void generateModelDisplayLists(DSGM_Model *mdl, bool interp, u8 normals) { if(!mdl) return; int i; for(i = 0; i < mdl->header.num_frames; i++) { generateFrameDisplayList(i, mdl, normals); } if(interp) { for(i = 0; i < mdl->numAnim; i++) { int j; u16 n = mdl->animations[i].end-mdl->animations[i].start + 1; for(j = 0; j < n; j++) { generateFrameDisplayListInterp(mdl->animations[i].start + j, mdl->animations[i].start+((j+1)%n), 1, mdl, normals); generateFrameDisplayListInterp(mdl->animations[i].start + j, mdl->animations[i].start+((j+1)%n), 2, mdl, normals); generateFrameDisplayListInterp(mdl->animations[i].start + j, mdl->animations[i].start+((j+1)%n), 3, mdl, normals); } } } if(interp || mdl->header.num_frames == 1) { for(i = 0; i < mdl->header.num_frames; i++) { freeMd2FrameData(&mdl->frames[i], false); } } }*/ void DSGM_RenderModelFrame(int n, const DSGM_Model *mdl) { int i, j; n %= mdl->header.num_frames; if((n < 0) || (n > mdl->header.num_frames - 1)) return; md2_frame_t *pframe = &mdl->frames[n]; glPushMatrix(); //glRotateXi(-(1<<13)); // vect3D u=vect(inttof32(1),0,0); glTranslate3f32(pframe->translate.x, pframe->translate.y, pframe->translate.z); glScalef32((pframe->scale.x), (pframe->scale.y), (pframe->scale.z)); glScalef32(inttof32(64), inttof32(64), inttof32(64)); // necessary for v10 glBegin(GL_TRIANGLES); GFX_COLOR = RGB15(31, 31, 31); for(i = 0; i < mdl->header.num_tris; i++) { // if(fakeDotProduct(anorms_table2[pframe->verts[mdl->triangles[i].vertex[0]].normalIndex],u)>0) { for(j = 0; j < 3; j++) { GFX_TEX_COORD = mdl->packedTexcoords[mdl->triangles[i].st[j]]; GFX_NORMAL = anorms_table[pframe->verts[mdl->triangles[i].vertex[j]].normalIndex]; //v16 // vect3D v = pframe->packedVerts[mdl->triangles[i].vertex[j]]; // glVertex3v16(v.x,v.y,v.z); //v10 GFX_VERTEX10 = pframe->packedv10[mdl->triangles[i].vertex[j]]; } } } glEnd(); glPopMatrix(1); } void DSGM_RenderModelFrameInterp(int n, int n2, int m, bool t, const DSGM_Model *mdl) { int i, j; n %= mdl->header.num_frames; n2 %= mdl->header.num_frames; if((n < 0) || (n > mdl->header.num_frames - 1)) return; if((n2 < 0) || (n2 > mdl->header.num_frames - 1)) return; if(m < 0 || m > 3) return; if(n == n2) m = 0; md2_frame_t *pframe = &mdl->frames[n]; if(pframe->displayList[m]) n2 = pframe->next; md2_frame_t *pframe2 = &mdl->frames[n2]; glPushMatrix(); //glRotateXi(-(1<<13)); glTranslate3f32(pframe->translate.x+((pframe2->translate.x-pframe->translate.x)*m)/4,pframe->translate.y+((pframe2->translate.y-pframe->translate.y)*m)/4,pframe->translate.z+((pframe2->translate.z-pframe->translate.z)*m)/4); //TEMP?("fake" center) if(t) { md2_frame_t *frm = &mdl->frames[0]; glTranslate3f32(-(frm->min.x + frm->max.x) / 2, -(frm->min.y + frm->max.y) / 2, -(frm->min.z + frm->max.z) / 2); } glScalef32((pframe->scale.x+((pframe2->scale.x-pframe->scale.x)*m)/4),(pframe->scale.y+((pframe2->scale.y-pframe->scale.y)*m)/4),(pframe->scale.z+((pframe2->scale.z-pframe->scale.z)*m)/4)); glScalef32(inttof32(64), inttof32(64), inttof32(64)); // necessary for v10 glBegin(GL_TRIANGLES); GFX_COLOR = RGB15(31, 31, 31); if(pframe->displayList[m]) { glCallList(pframe->displayList[m]); } else { for(i = 0; i < mdl->header.num_tris; i++) { { for(j = 0; j < 3; ++j) { md2_vertex_t *pvert = &pframe->verts[mdl->triangles[i].vertex[j]]; md2_vertex_t *pvert2 = &pframe2->verts[mdl->triangles[i].vertex[j]]; GFX_TEX_COORD = mdl->packedTexcoords[mdl->triangles[i].st[j]]; GFX_NORMAL = anorms_table[pframe->verts[mdl->triangles[i].vertex[j]].normalIndex]; //vect3D v = vect((pvert->v[0]*2+((pvert2->v[0]-pvert->v[0])*m)/2),(pvert->v[1]*2+((pvert2->v[1]-pvert->v[1])*m)/2),(pvert->v[2]*2+((pvert2->v[2]-pvert->v[2])*m)/2)); vect3D v = vect((pvert->v[0]+((pvert2->v[0]-pvert->v[0])*m)/2),(pvert->v[1]+((pvert2->v[1]-pvert->v[1])*m)/2),(pvert->v[2]+((pvert2->v[2]-pvert->v[2])*m)/2)); if(t) GFX_VERTEX10 = NORMAL_PACK(v.x - 128, v.y - 128, v.z - 128); else GFX_VERTEX10 = NORMAL_PACK(v.x, v.y, v.z); } } } } glEnd(); glPopMatrix(1); } void DSGM_InitModelInstance(DSGM_ModelInstance *mi, DSGM_Model *mdl) { if(!mi || !mdl) return; mi->currentAnim = 0; mi->interpolate = false; mi->interpCounter = 0; mi->currentFrame = 0; mi->nextFrame = 0; mi->animationSpeed = 1; mi->palette = NULL; mi->model = mdl; } void DSGM_SetModelInstanceAnimation(DSGM_ModelInstance *mi, u16 newAnim, bool oneshot) { if(!mi || mi->currentAnim == newAnim || newAnim >= mi->model->numAnim) return; if(!oneshot && mi->oneshot) { mi->oldAnim = newAnim; return; } mi->oneshot = oneshot; mi->oldAnim = mi->currentAnim; mi->currentAnim = newAnim; mi->nextFrame = mi->model->animations[mi->currentAnim].start; } void DSGM_UpdateModelInstanceAnimation(DSGM_ModelInstance *mi) { if(!mi) return; if(!mi->oneshot) mi->oldAnim = mi->currentAnim; mi->interpCounter += mi->animationSpeed; if(mi->interpCounter >= 4) { mi->interpCounter = 0; mi->currentFrame = mi->nextFrame; if(mi->currentFrame >= mi->model->animations[mi->currentAnim].end) { if(mi->oneshot){u8 oa=mi->currentAnim;mi->currentAnim=mi->oldAnim;mi->oldAnim=oa;mi->oneshot=false;} mi->nextFrame = mi->model->animations[mi->currentAnim].start; } else mi->nextFrame++; } } inline void DSGM_RenderModelInstance(DSGM_ModelInstance *mi) { if(mi->interpolate) DSGM_RenderModelFrameInterp(mi->currentFrame, mi->nextFrame, mi->interpCounter, mi->fixTransformations, mi->model); else DSGM_RenderModelFrame(mi->currentFrame, mi->model); }