quakeforge/tools/texpaint/model1.c

303 lines
5.9 KiB
C

/* Texture Paint - a GIMP plugin
*
* Copyright (C) 1998 Uwe Maurer <uwe_maurer@t-online.de>
*
* 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 "texturepaint.h"
#include "model.h"
#include "q1pal.h"
#define MDL_VERSION 6
/*
MDL (Quake I) Model
*/
typedef struct
{
gint32 ident;
gint32 version;
vec3_t scale;
vec3_t origin;
gfloat radius;
vec3_t offsets;
gint32 num_skins;
gint32 skin_width;
gint32 skin_height;
gint32 num_verts;
gint32 num_tris;
gint32 num_frames;
gint32 sync_type;
gint32 flags;
gfloat size;
} Model1Header;
typedef struct
{
gint32 onseam;
gint32 s;
gint32 t;
} stvert_t;
typedef struct
{
gint32 facesfront;
gint32 v[3];
} mdl_triangle_t;
typedef struct
{
unsigned char p[3];
unsigned char normal;
} vertex_t;
typedef struct
{
vertex_t min,max;
char name[16];
} frame_t;
static void destroy(Model *mdl)
{
g_free(mdl->tri);
g_free(mdl->vertex);
g_free(mdl->frames);
g_free(mdl);
}
static void draw(Model *mdl,int frame,int nextframe,float interp)
{
int i,j,v;
vec3_t *vertex;
gfloat x,y,z;
frame= (frame % mdl->numframes)*mdl->num_verts;
nextframe= (nextframe % mdl->numframes)*mdl->num_verts;
vertex=mdl->vertex;
glBegin(GL_TRIANGLES);
for (i=0;i<mdl->num_tris;i++)
{
for (j=0;j<3;j++)
{
v=mdl->tri[i].v[j];
x= vertex[frame+v].x +
(vertex[nextframe+v].x-vertex[frame+v].x)*interp;
y= vertex[frame+v].y +
(vertex[nextframe+v].y-vertex[frame+v].y)*interp;
z= vertex[frame+v].z +
(vertex[nextframe+v].z-vertex[frame+v].z)*interp;
glTexCoord2fv(mdl->tri[i].tex[j]);
glVertex3f(x,y,z);
}
}
glEnd();
}
Model *Model1Load(char *name,FILE *fp)
{
Model1Header header;
Model *mdl;
int i,k,f;
gint32 dummy;
guchar *texture;
gint size;
gint32 image_id,layer_id;
GimpPixelRgn rgn;
GimpDrawable *drawable;
gint w,h;
stvert_t *stvert;
mdl_triangle_t *triangle;
vertex_t *vertex;
frame_t frame;
gfloat x,y,z;
gint v;
gfloat xmin,xmax,ymax,ymin,zmax,zmin,scale;
char filename[300];
fread(&header,sizeof(header),1,fp);
if (strncmp((char *)&header.ident,"IDPO",4)!=0) return NULL;
if (header.version!=MDL_VERSION) return NULL;
mdl=g_malloc(sizeof(*mdl));
memset(mdl,0,sizeof(*mdl));
mdl->num_tris=header.num_tris;
mdl->num_verts=header.num_verts;
w=header.skin_width;
h=header.skin_height;
size=w*h;
texture=g_malloc(size);
image_id=-1;
for (i=0;i<header.num_skins;i++)
{
fread(&dummy,sizeof(dummy),1,fp);
fread(texture,size,1,fp);
image_id=gimp_image_new(w,h,GIMP_INDEXED);
if (i==0)
{
strcpy(filename,name);
}
else
{
sprintf(filename,"%s%i",name,i);
}
gimp_image_set_filename(image_id,filename);
layer_id=gimp_layer_new(image_id,"skin",w,h,GIMP_INDEXED_IMAGE,100,GIMP_NORMAL_MODE);
gimp_image_add_layer(image_id,layer_id,1);
gimp_image_set_cmap(image_id,q1pal,256);
drawable=gimp_drawable_get(layer_id);
gimp_pixel_rgn_init(&rgn,drawable,0,0,w,h,TRUE,FALSE);
gimp_pixel_rgn_set_rect(&rgn,texture,0,0,w,h);
gimp_drawable_detach(drawable);
gimp_display_new(image_id);
gimp_image_clean_all(image_id);
}
gimp_displays_flush();
g_free(texture);
update_images_menu(image_id);
size=header.num_verts*sizeof(stvert_t);
stvert=g_malloc(size);
fread(stvert,size,1,fp);
size=header.num_tris*sizeof(mdl_triangle_t);
triangle=g_malloc(size);
fread(triangle,size,1,fp);
mdl->tri=g_malloc(header.num_tris*sizeof(triangle_t));
mdl->vertex=g_malloc(header.num_frames*header.num_verts*sizeof(mdl->vertex[0]));
size=header.num_verts*sizeof(vertex_t);
vertex=g_malloc(size);
mdl->frames=g_malloc(header.num_frames*sizeof(mdl->frames[0]));
mdl->numframes=header.num_frames;
xmax=-G_MAXFLOAT;
ymax=-G_MAXFLOAT;
zmax=-G_MAXFLOAT;
xmin=+G_MAXFLOAT;
ymin=+G_MAXFLOAT;
zmin=+G_MAXFLOAT;
for (f=k=0;f<header.num_frames;f++)
{
fread(&dummy,sizeof(dummy),1,fp);
fread(&frame,sizeof(frame),1,fp);
strncpy(mdl->frames[f].name,frame.name,16);
fread(vertex,size,1,fp);
for (i=0;i<header.num_verts;i++,k++)
{
x=(gfloat)vertex[i].p[0] * header.scale.x
+ header.origin.x;
y=(gfloat)vertex[i].p[1] * header.scale.y
+ header.origin.y;
z=(gfloat)vertex[i].p[2] * header.scale.z
+ header.origin.z;
mdl->vertex[k].x=x;
mdl->vertex[k].y=y;
mdl->vertex[k].z=z;
if (x>xmax) xmax=x;
if (x<xmin) xmin=x;
if (y>ymax) ymax=y;
if (y<ymin) ymin=y;
if (z>zmax) zmax=z;
if (z<zmin) zmin=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 (i=0;i<header.num_verts*header.num_frames;i++)
{
mdl->vertex[i].x=(mdl->vertex[i].x-x)*scale;
mdl->vertex[i].y=(mdl->vertex[i].y-y)*scale;
mdl->vertex[i].z=(mdl->vertex[i].z-z)*scale;
}
for (i=0;i<header.num_tris;i++)
{
for (k=0;k<3;k++)
{
v=triangle[i].v[k];
x=(gfloat)stvert[v].s/header.skin_width;
y=(gfloat)stvert[v].t/header.skin_height;
if (!triangle[i].facesfront && stvert[v].onseam)
{
x+=0.5;
}
mdl->tri[i].v[k]=v;
mdl->tri[i].tex[k][0]=x;
mdl->tri[i].tex[k][1]=y;
}
}
g_free(vertex);
g_free(stvert);
g_free(triangle);
mdl->destroy=destroy;
mdl->draw=draw;
return mdl;
}