/* Texture Paint - a GIMP plugin * * Copyright (C) 1998 Uwe Maurer * * Copyright (C) 1998 Lionel ULMER * * Based on code Copyright (C) 1997 Trey Harrison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include "model.h" #include "texturepaint.h" void FreeModel(Model *mdl); typedef struct { float x, y, z; } Vec3; /* MD2 (Quake II) Model */ typedef struct { gint32 ident; gint32 version; gint32 skinwidth; gint32 skinheight; gint32 framesize; /* byte size of each frame*/ gint32 num_skins; gint32 num_xyz; gint32 num_st; /* greater than num_xyz for seams*/ gint32 num_tris; gint32 num_glcmds; /* dwords in strip/fan command list*/ gint32 num_frames; gint32 ofs_skins; /* each skin is a MAX_SKINNAME string */ gint32 ofs_st; /* byte offset from start for stverts */ gint32 ofs_tris; /* offset for dtriangles */ gint32 ofs_frames; /* offset for first frame */ gint32 ofs_glcmds; gint32 ofs_end; /* end of file */ } Model2Header; typedef struct { guchar x; guchar y; /* X,Y,Z coordinate, packed on 0-255 */ guchar z; guchar lightnormalindex; /* index of the vertex normal */ } Trivertex; typedef struct { Vec3 scale; /* multiply byte verts by this */ Vec3 origin; /* then add this */ char name[16]; /* frame name from grabbing */ Trivertex verts[1]; /* variable sized */ } FrameInfo; typedef struct { gint16 v[3]; gint16 st[3]; } d_triangle_t; typedef struct { gint16 s,t; } d_stvert_t; void DrawModel(Model *mdl, int frame, int nextframe, float ratio) { int nb_vert; long *command; Frame *frame1, *frame2; /* Keeps the frame value valid */ frame = frame % mdl->numframes; nextframe = nextframe % mdl->numframes; /* Gets the frames information */ frame1 = mdl->frames + frame; frame2 = mdl->frames + nextframe; /* Do the gl commands */ command = mdl->glcmds; nb_vert = 0; while (*command != 0) { int num_verts, i; /* Determine the command to draw the triangles */ if (*command > 0) { /* Triangle strip */ num_verts = *command; glBegin(GL_TRIANGLE_STRIP); } else { /* Triangle fan */ num_verts = -(*command); glBegin(GL_TRIANGLE_FAN); } command++; for (i = 0; i < num_verts; i++) { Vec3 p; /* Interpolated point */ int vert_index; /* Grab the vertex index */ vert_index = *command; command++; /* Interpolate */ p.x = frame1->vert_table[vert_index].x + (frame2->vert_table[vert_index].x - frame1->vert_table[vert_index].x) * ratio; p.y = frame1->vert_table[vert_index].y + (frame2->vert_table[vert_index].y - frame1->vert_table[vert_index].y) * ratio; p.z = frame1->vert_table[vert_index].z + (frame2->vert_table[vert_index].z - frame1->vert_table[vert_index].z) * ratio; glTexCoord2f(mdl->texinfo[nb_vert].s, mdl->texinfo[nb_vert].t); glVertex3f(p.x, p.y, p.z); nb_vert++; } glEnd(); } } Model *Model2Load(char *name,FILE *f) { int frame; Model2Header mdl_header; Model *mdl; FrameInfo *frames; long *glcmds; long *command, *cmd_copy; TexInfo *texinfo; int i,k; int num_vertices; long offset; d_triangle_t *d_tri; d_stvert_t *d_stvert; gfloat x,y,z; gfloat xmin,xmax; gfloat ymin,ymax; gfloat zmin,zmax,scale; /* Failsafe... */ if (f == NULL) return NULL; /* In case of a PAK loading */ offset = ftell(f); /* Read the header*/ fread(&mdl_header, sizeof(Model2Header), 1, f); /* Check if this is really a .MD2 file :-) */ if (strncmp((char *) &(mdl_header.ident), "IDP2", 4)) return NULL; /* Create the model */ mdl = (Model *) malloc(sizeof(Model)); memset(mdl, 0, sizeof(Model)); /* We do not need all the info from the header, just some of it*/ mdl->numframes = mdl_header.num_frames; mdl->draw=DrawModel; mdl->destroy=FreeModel; /* Reads the GL commands */ fseek(f, offset + mdl_header.ofs_glcmds, SEEK_SET); glcmds = (long *) malloc(mdl_header.num_glcmds * sizeof(long)); fread(glcmds, mdl_header.num_glcmds * sizeof(long), 1, f); /* We keep only the commands and the index in the glcommands. We 'pre-parse' the texture coordinates */ /* Do not ask me how I found this formula :-)) */ num_vertices = ((mdl_header.num_tris + 2 * mdl_header.num_glcmds - 2) / 7); mdl->texinfo = (TexInfo *) malloc(sizeof(TexInfo) * num_vertices); mdl->glcmds = (long *) malloc(sizeof(long) * (mdl_header.num_glcmds - 2 * num_vertices)); /* Reads the frames */ fseek(f, offset + mdl_header.ofs_frames, SEEK_SET); frames = (FrameInfo *) malloc(mdl_header.framesize * mdl->numframes); fread(frames, mdl_header.framesize * mdl->numframes, 1, f); /* Converts the FrameInfos to Frames */ mdl->frames = (Frame *) malloc(sizeof(Frame) * mdl->numframes); xmax=-G_MAXFLOAT; ymax=-G_MAXFLOAT; zmax=-G_MAXFLOAT; xmin=+G_MAXFLOAT; ymin=+G_MAXFLOAT; zmin=+G_MAXFLOAT; for (frame = 0; frame < mdl->numframes; frame++) { FrameInfo *frameinfo; /* Gets the frames information */ frameinfo = (FrameInfo *) ((char *) frames + mdl_header.framesize * frame); strcpy(mdl->frames[frame].name, frameinfo->name); mdl->frames[frame].vert_table = (Vertex *) malloc(sizeof(Vertex) * mdl_header.num_xyz); /* Loads the vertices */ for (i = 0; i < mdl_header.num_xyz; i++) { Vertex *p = (mdl->frames[frame].vert_table) + i; p->x = (float) frameinfo->verts[i].x * frameinfo->scale.x + frameinfo->origin.x; p->y = (float)frameinfo->verts[i].y * frameinfo->scale.y + frameinfo->origin.y; p->z = (float)frameinfo->verts[i].z * frameinfo->scale.z + frameinfo->origin.z; if (p->xx; if (p->x>xmax) xmax=p->x; if (p->yy; if (p->y>ymax) ymax=p->y; if (p->zz; if (p->z>zmax) zmax=p->z; } } x=(xmax-xmin)/2; y=(ymax-ymin)/2; z=(zmax-zmin)/2; scale=x; if (y>scale) scale=y; if (z>scale) scale=z; if (scale) scale=1/scale; else scale=1; x=(xmax+xmin)/2; y=(ymax+ymin)/2; z=(zmax+zmin)/2; for (frame = 0; frame < mdl->numframes; frame++) { for (i = 0; i < mdl_header.num_xyz; i++) { Vertex *p = (mdl->frames[frame].vert_table) + i; p->x=(p->x-x)*scale; p->y=(p->y-y)*scale; p->z=(p->z-z)*scale; } } /* Now transform the GL commands */ command = glcmds; cmd_copy = mdl->glcmds; texinfo = mdl->texinfo; while (*command != 0) { int nb_verts, i; /* Determine the command to draw the triangles */ if (*command > 0) /* Triangle strip */ nb_verts = *command; else /* Triangle fan */ nb_verts = -(*command); *(cmd_copy++) = *(command++); for (i = 0; i < nb_verts; i++) { float s, t; /* Gets the texture information */ s = *((float *) command); command++; t = *((float *) command); command++; texinfo->s = s; texinfo->t = t; texinfo++; /* We keep the vertex index */ *(cmd_copy++) = *(command++); } } /* Do not forget to copy the zero :-) */ *(cmd_copy++) = *(command++); mdl->num_tris=mdl_header.num_tris; mdl->tri = malloc(mdl->num_tris*sizeof(*mdl->tri)); fseek(f, offset + mdl_header.ofs_tris, SEEK_SET); d_tri = malloc(mdl->num_tris*sizeof(*d_tri)); fread(d_tri,mdl->num_tris*sizeof(*d_tri) , 1, f); fseek(f, offset + mdl_header.ofs_st, SEEK_SET); d_stvert = malloc(mdl_header.num_st*sizeof(*d_stvert)); fread(d_stvert,mdl_header.num_st*sizeof(*d_stvert) , 1, f); for (i=0;inum_tris;i++) { for (k=0;k<3;k++) { mdl->tri[i].v[k]=d_tri[i].v[k]; mdl->tri[i].tex[k][0]=(float)d_stvert[d_tri[i].st[k]].s /mdl_header.skinwidth; mdl->tri[i].tex[k][1]=(float)d_stvert[d_tri[i].st[k]].t /mdl_header.skinheight; } } g_free(d_tri); g_free(d_stvert); /* Clean memory */ free(frames); free(glcmds); return mdl; } /* Frees the memory used by a model */ void FreeModel(Model *mdl) { int frame; for (frame = 0; frame < mdl->numframes; frame++) free(mdl->frames[frame].vert_table); free(mdl->frames); free(mdl->glcmds); free(mdl->texinfo); free(mdl); }