dsgmLib/source/DSGM_MD2.c

480 lines
15 KiB
C

/*
*
* 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]<f->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]<f->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]<f->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);
}