mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-24 05:11:42 +00:00
358 lines
8.9 KiB
C
358 lines
8.9 KiB
C
|
/* Texture Paint - a GIMP plugin
|
||
|
*
|
||
|
* Copyright (C) 1998 Uwe Maurer <uwe_maurer@t-online.de>
|
||
|
*
|
||
|
* Copyright (C) 1998 Lionel ULMER <bbrox@mygale.org>
|
||
|
*
|
||
|
* Based on code Copyright (C) 1997 Trey Harrison <trey@crack.com>
|
||
|
*
|
||
|
* 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 <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include <GL/gl.h>
|
||
|
#include <GL/glu.h>
|
||
|
#include <glib.h>
|
||
|
|
||
|
#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->x<xmin) xmin=p->x;
|
||
|
if (p->x>xmax) xmax=p->x;
|
||
|
if (p->y<ymin) ymin=p->y;
|
||
|
if (p->y>ymax) ymax=p->y;
|
||
|
if (p->z<zmin) zmin=p->z;
|
||
|
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;i<mdl->num_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);
|
||
|
}
|