438 lines
No EOL
13 KiB
C
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 ();
|
|
}
|
|
}
|
|
} |