ew-engine/mq engine src/gl_md2.c
2006-10-08 00:00:00 +00:00

438 lines
No EOL
13 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
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.
*/
//
// all MD2 code goes into this file
//
#include "quakedef.h"
char loadname[32]; // for hunk tags
// precalculated dot products for quantized angles
float r_avertexnormal_dots_md2[16][256] =
#include "anorm_dots.h"
;
float *shadedots_md2 = r_avertexnormal_dots_md2[0];
float *shadedots2_md2 = r_avertexnormal_dots_md2[0];
extern float lightlerpoffset;
extern vec3_t lightcolor;
extern vec3_t lightspot;
int md2bboxmins[3], md2bboxmaxs[3];
/*
=================
Mod_LoadQ2AliasModel
=================
*/
void Mod_LoadQ2AliasModel (model_t *mod, void *buffer)
{
int i, j, version, numframes, size, *pinglcmd, *poutglcmd, start, end, total;
md2_t *pinmodel, *pheader;
md2triangle_t *pintriangles, *pouttriangles;
md2frame_t *pinframe, *poutframe;
char *pinskins;
vec3_t temp;
start = Hunk_LowMark ();
pinmodel = (md2_t *)buffer;
version = LittleLong (pinmodel->version);
if (version != MD2ALIAS_VERSION)
Sys_Error ("%s has wrong version number (%i should be %i)",
mod->name, version, MD2ALIAS_VERSION);
mod->type = mod_alias;
mod->aliastype = ALIASTYPE_MD2;
size = LittleLong(pinmodel->ofs_end) + sizeof(md2_t);
if (size <= 0 || size >= MD2MAX_SIZE)
Sys_Error ("%s is not a valid model", mod->name);
pheader = Hunk_AllocName (size, loadname);
mod->flags = 0; // there are no MD2 flags
// endian-adjust and copy the data, starting with the alias model header
for (i = 0;i < 17;i++)
((int*)pheader)[i] = LittleLong(((int *)pinmodel)[i]);
mod->numframes = numframes = pheader->num_frames;
mod->synctype = ST_RAND;
if (pheader->ofs_skins <= 0 || pheader->ofs_skins >= pheader->ofs_end)
Sys_Error ("%s is not a valid model", mod->name);
if (pheader->ofs_st <= 0 || pheader->ofs_st >= pheader->ofs_end)
Sys_Error ("%s is not a valid model", mod->name);
if (pheader->ofs_tris <= 0 || pheader->ofs_tris >= pheader->ofs_end)
Sys_Error ("%s is not a valid model", mod->name);
if (pheader->ofs_frames <= 0 || pheader->ofs_frames >= pheader->ofs_end)
Sys_Error ("%s is not a valid model", mod->name);
if (pheader->ofs_glcmds <= 0 || pheader->ofs_glcmds >= pheader->ofs_end)
Sys_Error ("%s is not a valid model", mod->name);
if (pheader->num_tris < 1 || pheader->num_tris > MD2MAX_TRIANGLES)
Sys_Error ("%s has invalid number of triangles: %i", mod->name, pheader->num_tris);
if (pheader->num_xyz < 1 || pheader->num_xyz > MD2MAX_VERTS)
Sys_Error ("%s has invalid number of vertices: %i", mod->name, pheader->num_xyz);
if (pheader->num_frames < 1 || pheader->num_frames > MD2MAX_FRAMES)
Sys_Error ("%s has invalid number of frames: %i", mod->name, pheader->num_frames);
if (pheader->num_skins < 0 || pheader->num_skins > MD2MAX_SKINS)
Sys_Error ("%s has invalid number of skins: %i", mod->name, pheader->num_skins);
for (i = 0;i < 7;i++)
((int*)&pheader->ofs_skins)[i] += sizeof(pheader);
// load the skins
if (pheader->num_skins)
{
pinskins = (void*)((int) pinmodel + LittleLong(pinmodel->ofs_skins));
for (i = 0;i < pheader->num_skins;i++)
{
pheader->gl_texturenum[i] = loadtextureimage (pinskins, true, true);
pinskins += MD2MAX_SKINNAME;
}
}
// load triangles
pintriangles = (void*)((int) pinmodel + LittleLong(pinmodel->ofs_tris));
pouttriangles = (void*)((int) pheader + pheader->ofs_tris);
// swap the triangle list
for (i=0 ; i < pheader->num_tris ; i++)
{
for (j=0 ; j<3 ; j++)
{
pouttriangles->index_xyz[j] = LittleShort (pintriangles->index_xyz[j]);
pouttriangles->index_st[j] = LittleShort (pintriangles->index_st[j]);
if (pouttriangles->index_xyz[j] >= pheader->num_xyz)
Sys_Error ("%s has invalid vertex indices", mod->name);
if (pouttriangles->index_st[j] >= pheader->num_st)
Sys_Error ("%s has invalid vertex indices", mod->name);
}
pintriangles++;
pouttriangles++;
}
//
// load the frames
//
pinframe = (void*) ((int) pinmodel + LittleLong(pinmodel->ofs_frames));
poutframe = (void*) ((int) pheader + pheader->ofs_frames);
for (i=0 ; i < numframes ; i++)
{
for (j = 0;j < 3;j++)
{
poutframe->scale[j] = LittleFloat(pinframe->scale[j]);
poutframe->translate[j] = LittleFloat(pinframe->translate[j]);
}
strcpy (poutframe->name, pinframe->name);
for (j = 0;j < pheader->num_xyz;j++)
{
VectorCopy (pinframe->verts[j].v, poutframe->verts[j].v);
poutframe->verts[j].lightnormalindex = pinframe->verts[j].lightnormalindex;
temp[0] = poutframe->verts[j].v[0] * poutframe->scale[0] + poutframe->translate[0];
temp[1] = poutframe->verts[j].v[1] * poutframe->scale[1] + poutframe->translate[1];
temp[2] = poutframe->verts[j].v[2] * poutframe->scale[2] + poutframe->translate[2];
// update bounding box
if (temp[0] < md2bboxmins[0]) md2bboxmins[0] = temp[0];
if (temp[1] < md2bboxmins[1]) md2bboxmins[1] = temp[1];
if (temp[2] < md2bboxmins[2]) md2bboxmins[2] = temp[2];
if (temp[0] > md2bboxmaxs[0]) md2bboxmaxs[0] = temp[0];
if (temp[1] > md2bboxmaxs[1]) md2bboxmaxs[1] = temp[1];
if (temp[2] > md2bboxmaxs[2]) md2bboxmaxs[2] = temp[2];
}
pinframe = (void*) &pinframe->verts[j].v[0];
poutframe = (void*) &poutframe->verts[j].v[0];
}
VectorCopy (md2bboxmaxs, mod->maxs);
VectorCopy (md2bboxmins, mod->mins);
// load the draw list
pinglcmd = (void*) ((int) pinmodel + LittleLong(pinmodel->ofs_glcmds));
poutglcmd = (void*) ((int) pheader + pheader->ofs_glcmds);
for (i = 0;i < pheader->num_glcmds;i++)
*poutglcmd++ = LittleLong(*pinglcmd++);
// move the complete, relocatable alias model to the cache
end = Hunk_LowMark ();
total = end - start;
Cache_Alloc (&mod->cache, total, loadname);
if (!mod->cache.data)
return;
memcpy (mod->cache.data, pheader, total);
Hunk_FreeToLowMark (start);
}
/*
=============
GL_DrawQ2AliasFrame
=============
*/
void GL_DrawQ2AliasFrame (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp)
{
float ilerp;
float l;
int *order, count;
md2trivertx_t *verts1, *verts2;
vec3_t scale1, translate1, scale2, translate2;
md2frame_t *frame1, *frame2;
ilerp = 1.0 - lerp;
frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose));
frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose));
VectorCopy(frame1->scale, scale1);
VectorCopy(frame1->translate, translate1);
VectorCopy(frame2->scale, scale2);
VectorCopy(frame2->translate, translate2);
verts1 = &frame1->verts[0];
verts2 = &frame2->verts[0];
order = (int *)((int)pheader + pheader->ofs_glcmds);
while (1)
{
// get the vertex count and primitive type
count = *order++;
if (!count)
break; // done
if (count < 0)
{
count = -count;
glBegin (GL_TRIANGLE_FAN);
}
else
glBegin (GL_TRIANGLE_STRIP);
do
{
if (!e->model->fullbright)
{
float d1, d2, l1, l2, diff;
d1 = shadedots_md2[verts2->lightnormalindex] - shadedots_md2[verts1->lightnormalindex];
d2 = shadedots2_md2[verts2->lightnormalindex] - shadedots2_md2[verts1->lightnormalindex];
l1 = shadedots_md2[verts1->lightnormalindex] + (lerp * d1);
l2 = shadedots2_md2[verts1->lightnormalindex] + (lerp * d2);
if (l1 != l2)
{
if (l1 > l2) {
diff = l1 - l2;
diff *= lightlerpoffset;
l = l1 - diff;
} else {
diff = l2 - l1;
diff *= lightlerpoffset;
l = l1 + diff;
}
}
else
{
l = l1;
}
glColor4f (l * lightcolor[0], l * lightcolor[1], l * lightcolor[2], e->alpha);
}
else {
glColor4f (1, 1, 1, e->alpha);
}
glTexCoord2f(((float *)order)[0], ((float *)order)[1]);
glVertex3f((verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp,
(verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp,
(verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp);
order+=3;
} while (--count);
glEnd ();
}
glColor4f (1,1,1,1);
}
/*
=============
GL_DrawQ2AliasShadow
=============
*/
void GL_DrawQ2AliasShadow (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp)
{
float ilerp, height, lheight;
int *order, count;
md2trivertx_t *verts1, *verts2;
vec3_t scale1, translate1, scale2, translate2, point;
md2frame_t *frame1, *frame2;
// Tomaz - New Shadow Begin
trace_t downtrace;
vec3_t downmove;
float s1,c1;
// Tomaz - New Shadow End
lheight = e->origin[2] - lightspot[2];
height = 0;
ilerp = 1.0 - lerp;
// Tomaz - New Shadow Begin
VectorCopy (e->origin, downmove);
downmove[2] = downmove[2] - 4096;
memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace);
s1 = sin( e->angles[1]/180*M_PI);
c1 = cos( e->angles[1]/180*M_PI);
// Tomaz - New Shadow End
frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose));
frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose));
VectorCopy(frame1->scale, scale1);
VectorCopy(frame1->translate, translate1);
VectorCopy(frame2->scale, scale2);
VectorCopy(frame2->translate, translate2);
verts1 = &frame1->verts[0];
verts2 = &frame2->verts[0];
order = (int *)((int) pheader + pheader->ofs_glcmds);
height = -lheight + 1.0;
while (1)
{
// get the vertex count and primitive type
count = *order++;
if (!count)
break; // done
if (count < 0)
{
count = -count;
glBegin (GL_TRIANGLE_FAN);
}
else
glBegin (GL_TRIANGLE_STRIP);
do
{
point[0] = (verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp;
point[1] = (verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp;
point[2] = (verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp;
// Tomaz - New shadow Begin
point[2] = - (e->origin[2] - downtrace.endpos[2]) ;
point[2] += ((point[1] * (s1 * downtrace.plane.normal[0])) -
(point[0] * (c1 * downtrace.plane.normal[0])) -
(point[0] * (s1 * downtrace.plane.normal[1])) -
(point[1] * (c1 * downtrace.plane.normal[1]))) +
((1.0 - downtrace.plane.normal[2])*20) + 0.2 ;
glVertex3fv (point);
// Tomaz - New shadow Begin
order+=3;
} while (--count);
glEnd ();
}
}
/*
=================
R_SetupQ2AliasFrame
=================
*/
void R_SetupQ2AliasFrame (int frame, md2_t *pheader, entity_t *e)
{
float lerp;
if ((frame >= pheader->num_frames) || (frame < 0))
{
Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame);
frame = 0;
}
if (e->draw_lastmodel == e->model)
{
if (frame != e->draw_pose)
{
e->draw_lastpose = e->draw_pose;
e->draw_pose = frame;
e->draw_lerpstart = cl.time;
lerp = 0;
}
else
lerp = (cl.time - e->draw_lerpstart) * 10.0;
}
else // uninitialized
{
e->draw_lastmodel = e->model;
e->draw_lastpose = e->draw_pose = frame;
e->draw_lerpstart = cl.time;
lerp = 0;
}
if (lerp > 1) lerp = 1;
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
GL_DrawQ2AliasFrame (e, pheader, e->draw_lastpose, frame, lerp);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (r_shadows.value)
{
if (!e->model->noshadow)
{
trace_t downtrace;
vec3_t downmove;
glPushMatrix ();
VectorCopy (e->origin, downmove);
downmove[2] = downmove[2] - 4096;
memset (&downtrace, 0, sizeof(downtrace));
SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, e->origin, downmove, &downtrace);
glDisable (GL_TEXTURE_2D);
glDepthMask(false); // disable zbuffer updates
glColor4f (0,0,0,(e->alpha - ((e->origin[2] + e->model->mins[2]-downtrace.endpos[2])/60)));
GL_DrawQ2AliasShadow (e, pheader, e->draw_lastpose, frame, lerp);
glDepthMask(true); // enable zbuffer updates
glEnable (GL_TEXTURE_2D);
glColor4f (1,1,1,1);
glPopMatrix ();
}
}
}