739 lines
17 KiB
C++
739 lines
17 KiB
C++
/***
|
|
*
|
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
|
*
|
|
* This product contains software technology licensed from Id
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
****/
|
|
// studio_render.cpp: routines for drawing Half-Life 3DStudio models
|
|
// updates:
|
|
// 1-4-99 fixed AdvanceFrame wraping bug
|
|
|
|
#include <windows.h>
|
|
|
|
#include <gl\gl.h>
|
|
#include <gl\glu.h>
|
|
|
|
#pragma warning(disable : 4244) // double to float
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "mathlib.h"
|
|
#undef DotProduct
|
|
#include "../../dlls/vector.h"
|
|
#include "../../public/steam/steamtypes.h" // defines int32, required by studio.h
|
|
#include "..\..\engine\studio.h"
|
|
#include "mdlviewer.h"
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
vec3_t g_xformverts[MAXSTUDIOVERTS]; // transformed vertices
|
|
vec3_t g_lightvalues[MAXSTUDIOVERTS]; // light surface normals
|
|
vec3_t* g_pxformverts;
|
|
vec3_t* g_pvlightvalues;
|
|
|
|
vec3_t g_lightvec; // light vector in model reference frame
|
|
vec3_t g_blightvec[MAXSTUDIOBONES]; // light vectors in bone reference frames
|
|
int g_ambientlight; // ambient world light
|
|
float g_shadelight; // direct world light
|
|
vec3_t g_lightcolor;
|
|
|
|
int g_smodels_total; // cookie
|
|
|
|
float g_bonetransform[MAXSTUDIOBONES][3][4]; // bone transformation matrix
|
|
|
|
int g_chrome[MAXSTUDIOVERTS][2]; // texture coords for surface normals
|
|
int g_chromeage[MAXSTUDIOBONES]; // last time chrome vectors were updated
|
|
vec3_t g_chromeup[MAXSTUDIOBONES]; // chrome vector "up" in bone reference frames
|
|
vec3_t g_chromeright[MAXSTUDIOBONES]; // chrome vector "right" in bone reference frames
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void StudioModel::CalcBoneAdj()
|
|
{
|
|
int i, j;
|
|
float value;
|
|
mstudiobonecontroller_t* pbonecontroller;
|
|
|
|
pbonecontroller = (mstudiobonecontroller_t*)((byte*)m_pstudiohdr + m_pstudiohdr->bonecontrollerindex);
|
|
|
|
for (j = 0; j < m_pstudiohdr->numbonecontrollers; j++)
|
|
{
|
|
i = pbonecontroller[j].index;
|
|
if (i <= 3)
|
|
{
|
|
// check for 360% wrapping
|
|
if (pbonecontroller[j].type & STUDIO_RLOOP)
|
|
{
|
|
value = m_controller[i] * (360.0 / 256.0) + pbonecontroller[j].start;
|
|
}
|
|
else
|
|
{
|
|
value = m_controller[i] / 255.0;
|
|
if (value < 0)
|
|
value = 0;
|
|
if (value > 1.0)
|
|
value = 1.0;
|
|
value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
|
|
}
|
|
// Con_DPrintf( "%d %d %f : %f\n", m_controller[j], m_prevcontroller[j], value, dadt );
|
|
}
|
|
else
|
|
{
|
|
value = m_mouth / 64.0;
|
|
if (value > 1.0)
|
|
value = 1.0;
|
|
value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
|
|
// Con_DPrintf("%d %f\n", mouthopen, value );
|
|
}
|
|
switch (pbonecontroller[j].type & STUDIO_TYPES)
|
|
{
|
|
case STUDIO_XR:
|
|
case STUDIO_YR:
|
|
case STUDIO_ZR:
|
|
m_adj[j] = value * (Q_PI / 180.0);
|
|
break;
|
|
case STUDIO_X:
|
|
case STUDIO_Y:
|
|
case STUDIO_Z:
|
|
m_adj[j] = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void StudioModel::CalcBoneQuaternion(int frame, float s, mstudiobone_t* pbone, mstudioanim_t* panim, float* q)
|
|
{
|
|
int j, k;
|
|
vec4_t q1, q2;
|
|
vec3_t angle1, angle2;
|
|
mstudioanimvalue_t* panimvalue;
|
|
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
if (panim->offset[j + 3] == 0)
|
|
{
|
|
angle2[j] = angle1[j] = pbone->value[j + 3]; // default;
|
|
}
|
|
else
|
|
{
|
|
panimvalue = (mstudioanimvalue_t*)((byte*)panim + panim->offset[j + 3]);
|
|
k = frame;
|
|
while (panimvalue->num.total <= k)
|
|
{
|
|
k -= panimvalue->num.total;
|
|
panimvalue += panimvalue->num.valid + 1;
|
|
}
|
|
// Bah, missing blend!
|
|
if (panimvalue->num.valid > k)
|
|
{
|
|
angle1[j] = panimvalue[k + 1].value;
|
|
|
|
if (panimvalue->num.valid > k + 1)
|
|
{
|
|
angle2[j] = panimvalue[k + 2].value;
|
|
}
|
|
else
|
|
{
|
|
if (panimvalue->num.total > k + 1)
|
|
angle2[j] = angle1[j];
|
|
else
|
|
angle2[j] = panimvalue[panimvalue->num.valid + 2].value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
angle1[j] = panimvalue[panimvalue->num.valid].value;
|
|
if (panimvalue->num.total > k + 1)
|
|
{
|
|
angle2[j] = angle1[j];
|
|
}
|
|
else
|
|
{
|
|
angle2[j] = panimvalue[panimvalue->num.valid + 2].value;
|
|
}
|
|
}
|
|
angle1[j] = pbone->value[j + 3] + angle1[j] * pbone->scale[j + 3];
|
|
angle2[j] = pbone->value[j + 3] + angle2[j] * pbone->scale[j + 3];
|
|
}
|
|
|
|
if (pbone->bonecontroller[j + 3] != -1)
|
|
{
|
|
angle1[j] += m_adj[pbone->bonecontroller[j + 3]];
|
|
angle2[j] += m_adj[pbone->bonecontroller[j + 3]];
|
|
}
|
|
}
|
|
|
|
if (!VectorCompare(angle1, angle2))
|
|
{
|
|
AngleQuaternion(angle1, q1);
|
|
AngleQuaternion(angle2, q2);
|
|
QuaternionSlerp(q1, q2, s, q);
|
|
}
|
|
else
|
|
{
|
|
AngleQuaternion(angle1, q);
|
|
}
|
|
}
|
|
|
|
|
|
void StudioModel::CalcBonePosition(int frame, float s, mstudiobone_t* pbone, mstudioanim_t* panim, float* pos)
|
|
{
|
|
int j, k;
|
|
mstudioanimvalue_t* panimvalue;
|
|
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
pos[j] = pbone->value[j]; // default;
|
|
if (panim->offset[j] != 0)
|
|
{
|
|
panimvalue = (mstudioanimvalue_t*)((byte*)panim + panim->offset[j]);
|
|
|
|
k = frame;
|
|
// find span of values that includes the frame we want
|
|
while (panimvalue->num.total <= k)
|
|
{
|
|
k -= panimvalue->num.total;
|
|
panimvalue += panimvalue->num.valid + 1;
|
|
}
|
|
// if we're inside the span
|
|
if (panimvalue->num.valid > k)
|
|
{
|
|
// and there's more data in the span
|
|
if (panimvalue->num.valid > k + 1)
|
|
{
|
|
pos[j] += (panimvalue[k + 1].value * (1.0 - s) + s * panimvalue[k + 2].value) * pbone->scale[j];
|
|
}
|
|
else
|
|
{
|
|
pos[j] += panimvalue[k + 1].value * pbone->scale[j];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// are we at the end of the repeating values section and there's another section with data?
|
|
if (panimvalue->num.total <= k + 1)
|
|
{
|
|
pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j];
|
|
}
|
|
else
|
|
{
|
|
pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j];
|
|
}
|
|
}
|
|
}
|
|
if (pbone->bonecontroller[j] != -1)
|
|
{
|
|
pos[j] += m_adj[pbone->bonecontroller[j]];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void StudioModel::CalcRotations(vec3_t* pos, vec4_t* q, mstudioseqdesc_t* pseqdesc, mstudioanim_t* panim, float f)
|
|
{
|
|
int i;
|
|
int frame;
|
|
mstudiobone_t* pbone;
|
|
float s;
|
|
|
|
frame = (int)f;
|
|
s = (f - frame);
|
|
|
|
// add in programatic controllers
|
|
CalcBoneAdj();
|
|
|
|
pbone = (mstudiobone_t*)((byte*)m_pstudiohdr + m_pstudiohdr->boneindex);
|
|
for (i = 0; i < m_pstudiohdr->numbones; i++, pbone++, panim++)
|
|
{
|
|
CalcBoneQuaternion(frame, s, pbone, panim, q[i]);
|
|
CalcBonePosition(frame, s, pbone, panim, pos[i]);
|
|
}
|
|
|
|
if (pseqdesc->motiontype & STUDIO_X)
|
|
pos[pseqdesc->motionbone][0] = 0.0;
|
|
if (pseqdesc->motiontype & STUDIO_Y)
|
|
pos[pseqdesc->motionbone][1] = 0.0;
|
|
if (pseqdesc->motiontype & STUDIO_Z)
|
|
pos[pseqdesc->motionbone][2] = 0.0;
|
|
}
|
|
|
|
|
|
mstudioanim_t* StudioModel::GetAnim(mstudioseqdesc_t* pseqdesc)
|
|
{
|
|
mstudioseqgroup_t* pseqgroup;
|
|
pseqgroup = (mstudioseqgroup_t*)((byte*)m_pstudiohdr + m_pstudiohdr->seqgroupindex) + pseqdesc->seqgroup;
|
|
|
|
if (pseqdesc->seqgroup == 0)
|
|
{
|
|
return (mstudioanim_t*)((byte*)m_pstudiohdr + pseqgroup->unused2 /* was pseqgroup->data, will be almost always be 0 */ + pseqdesc->animindex);
|
|
}
|
|
|
|
return (mstudioanim_t*)((byte*)m_panimhdr[pseqdesc->seqgroup] + pseqdesc->animindex);
|
|
}
|
|
|
|
|
|
void StudioModel::SlerpBones(vec4_t q1[], vec3_t pos1[], vec4_t q2[], vec3_t pos2[], float s)
|
|
{
|
|
int i;
|
|
vec4_t q3;
|
|
float s1;
|
|
|
|
if (s < 0)
|
|
s = 0;
|
|
else if (s > 1.0)
|
|
s = 1.0;
|
|
|
|
s1 = 1.0 - s;
|
|
|
|
for (i = 0; i < m_pstudiohdr->numbones; i++)
|
|
{
|
|
QuaternionSlerp(q1[i], q2[i], s, q3);
|
|
q1[i][0] = q3[0];
|
|
q1[i][1] = q3[1];
|
|
q1[i][2] = q3[2];
|
|
q1[i][3] = q3[3];
|
|
pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;
|
|
pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;
|
|
pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;
|
|
}
|
|
}
|
|
|
|
|
|
void StudioModel::AdvanceFrame(float dt)
|
|
{
|
|
mstudioseqdesc_t* pseqdesc;
|
|
pseqdesc = (mstudioseqdesc_t*)((byte*)m_pstudiohdr + m_pstudiohdr->seqindex) + m_sequence;
|
|
|
|
if (dt > 0.1)
|
|
dt = (float)0.1;
|
|
m_frame += dt * pseqdesc->fps;
|
|
|
|
if (pseqdesc->numframes <= 1)
|
|
{
|
|
m_frame = 0;
|
|
}
|
|
else
|
|
{
|
|
// wrap
|
|
m_frame -= (int)(m_frame / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1);
|
|
}
|
|
}
|
|
|
|
|
|
void StudioModel::SetUpBones(void)
|
|
{
|
|
int i;
|
|
|
|
mstudiobone_t* pbones;
|
|
mstudioseqdesc_t* pseqdesc;
|
|
mstudioanim_t* panim;
|
|
|
|
static vec3_t pos[MAXSTUDIOBONES];
|
|
float bonematrix[3][4];
|
|
static vec4_t q[MAXSTUDIOBONES];
|
|
|
|
static vec3_t pos2[MAXSTUDIOBONES];
|
|
static vec4_t q2[MAXSTUDIOBONES];
|
|
static vec3_t pos3[MAXSTUDIOBONES];
|
|
static vec4_t q3[MAXSTUDIOBONES];
|
|
static vec3_t pos4[MAXSTUDIOBONES];
|
|
static vec4_t q4[MAXSTUDIOBONES];
|
|
|
|
|
|
if (m_sequence >= m_pstudiohdr->numseq)
|
|
{
|
|
m_sequence = 0;
|
|
}
|
|
|
|
pseqdesc = (mstudioseqdesc_t*)((byte*)m_pstudiohdr + m_pstudiohdr->seqindex) + m_sequence;
|
|
|
|
panim = GetAnim(pseqdesc);
|
|
CalcRotations(pos, q, pseqdesc, panim, m_frame);
|
|
|
|
if (pseqdesc->numblends > 1)
|
|
{
|
|
float s;
|
|
|
|
panim += m_pstudiohdr->numbones;
|
|
CalcRotations(pos2, q2, pseqdesc, panim, m_frame);
|
|
s = m_blending[0] / 255.0;
|
|
|
|
SlerpBones(q, pos, q2, pos2, s);
|
|
|
|
if (pseqdesc->numblends == 4)
|
|
{
|
|
panim += m_pstudiohdr->numbones;
|
|
CalcRotations(pos3, q3, pseqdesc, panim, m_frame);
|
|
|
|
panim += m_pstudiohdr->numbones;
|
|
CalcRotations(pos4, q4, pseqdesc, panim, m_frame);
|
|
|
|
s = m_blending[0] / 255.0;
|
|
SlerpBones(q3, pos3, q4, pos4, s);
|
|
|
|
s = m_blending[1] / 255.0;
|
|
SlerpBones(q, pos, q3, pos3, s);
|
|
}
|
|
}
|
|
|
|
pbones = (mstudiobone_t*)((byte*)m_pstudiohdr + m_pstudiohdr->boneindex);
|
|
|
|
for (i = 0; i < m_pstudiohdr->numbones; i++)
|
|
{
|
|
QuaternionMatrix(q[i], bonematrix);
|
|
|
|
bonematrix[0][3] = pos[i][0];
|
|
bonematrix[1][3] = pos[i][1];
|
|
bonematrix[2][3] = pos[i][2];
|
|
|
|
if (pbones[i].parent == -1)
|
|
{
|
|
memcpy(g_bonetransform[i], bonematrix, sizeof(float) * 12);
|
|
}
|
|
else
|
|
{
|
|
R_ConcatTransforms(g_bonetransform[pbones[i].parent], bonematrix, g_bonetransform[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
================
|
|
StudioModel::TransformFinalVert
|
|
================
|
|
*/
|
|
void StudioModel::Lighting(float* lv, int bone, int flags, vec3_t normal)
|
|
{
|
|
float illum;
|
|
float lightcos;
|
|
|
|
illum = g_ambientlight;
|
|
|
|
if (flags & STUDIO_NF_FLATSHADE)
|
|
{
|
|
illum += g_shadelight * 0.8;
|
|
}
|
|
else
|
|
{
|
|
float r;
|
|
lightcos = DotProduct(normal, g_blightvec[bone]); // -1 colinear, 1 opposite
|
|
|
|
if (lightcos > 1.0)
|
|
lightcos = 1;
|
|
|
|
illum += g_shadelight;
|
|
|
|
r = g_lambert;
|
|
if (r <= 1.0)
|
|
r = 1.0;
|
|
|
|
lightcos = (lightcos + (r - 1.0)) / r; // do modified hemispherical lighting
|
|
if (lightcos > 0.0)
|
|
{
|
|
illum -= g_shadelight * lightcos;
|
|
}
|
|
if (illum <= 0)
|
|
illum = 0;
|
|
}
|
|
|
|
if (illum > 255)
|
|
illum = 255;
|
|
*lv = illum / 255.0; // Light from 0 to 1.0
|
|
}
|
|
|
|
|
|
void StudioModel::Chrome(int* pchrome, int bone, vec3_t normal)
|
|
{
|
|
float n;
|
|
|
|
if (g_chromeage[bone] != g_smodels_total)
|
|
{
|
|
// calculate vectors from the viewer to the bone. This roughly adjusts for position
|
|
vec3_t chromeupvec; // g_chrome t vector in world reference frame
|
|
vec3_t chromerightvec; // g_chrome s vector in world reference frame
|
|
vec3_t tmp; // vector pointing at bone in world reference frame
|
|
VectorScale(m_origin, -1, tmp);
|
|
tmp[0] += g_bonetransform[bone][0][3];
|
|
tmp[1] += g_bonetransform[bone][1][3];
|
|
tmp[2] += g_bonetransform[bone][2][3];
|
|
VectorNormalize(tmp);
|
|
CrossProduct(tmp, g_vright, chromeupvec);
|
|
VectorNormalize(chromeupvec);
|
|
CrossProduct(tmp, chromeupvec, chromerightvec);
|
|
VectorNormalize(chromerightvec);
|
|
|
|
VectorIRotate(chromeupvec, g_bonetransform[bone], g_chromeup[bone]);
|
|
VectorIRotate(chromerightvec, g_bonetransform[bone], g_chromeright[bone]);
|
|
|
|
g_chromeage[bone] = g_smodels_total;
|
|
}
|
|
|
|
// calc s coord
|
|
n = DotProduct(normal, g_chromeright[bone]);
|
|
pchrome[0] = (n + 1.0) * 32; // FIX: make this a float
|
|
|
|
// calc t coord
|
|
n = DotProduct(normal, g_chromeup[bone]);
|
|
pchrome[1] = (n + 1.0) * 32; // FIX: make this a float
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
StudioModel::SetupLighting
|
|
set some global variables based on entity position
|
|
inputs:
|
|
outputs:
|
|
g_ambientlight
|
|
g_shadelight
|
|
================
|
|
*/
|
|
void StudioModel::SetupLighting()
|
|
{
|
|
int i;
|
|
g_ambientlight = 32;
|
|
g_shadelight = 192;
|
|
|
|
g_lightvec[0] = 0;
|
|
g_lightvec[1] = 0;
|
|
g_lightvec[2] = -1.0;
|
|
|
|
g_lightcolor[0] = 1.0;
|
|
g_lightcolor[1] = 1.0;
|
|
g_lightcolor[2] = 1.0;
|
|
|
|
// TODO: only do it for bones that actually have textures
|
|
for (i = 0; i < m_pstudiohdr->numbones; i++)
|
|
{
|
|
VectorIRotate(g_lightvec, g_bonetransform[i], g_blightvec[i]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
StudioModel::SetupModel
|
|
based on the body part, figure out which mesh it should be using.
|
|
inputs:
|
|
currententity
|
|
outputs:
|
|
pstudiomesh
|
|
pmdl
|
|
=================
|
|
*/
|
|
|
|
void StudioModel::SetupModel(int bodypart)
|
|
{
|
|
int index;
|
|
|
|
if (bodypart > m_pstudiohdr->numbodyparts)
|
|
{
|
|
// Con_DPrintf ("StudioModel::SetupModel: no such bodypart %d\n", bodypart);
|
|
bodypart = 0;
|
|
}
|
|
|
|
mstudiobodyparts_t* pbodypart = (mstudiobodyparts_t*)((byte*)m_pstudiohdr + m_pstudiohdr->bodypartindex) + bodypart;
|
|
|
|
index = m_bodynum / pbodypart->base;
|
|
index = index % pbodypart->nummodels;
|
|
|
|
m_pmodel = (mstudiomodel_t*)((byte*)m_pstudiohdr + pbodypart->modelindex) + index;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
StudioModel::DrawModel
|
|
inputs:
|
|
currententity
|
|
r_entorigin
|
|
================
|
|
*/
|
|
void StudioModel::DrawModel()
|
|
{
|
|
int i;
|
|
|
|
g_smodels_total++; // render data cache cookie
|
|
|
|
g_pxformverts = &g_xformverts[0];
|
|
g_pvlightvalues = &g_lightvalues[0];
|
|
|
|
if (m_pstudiohdr->numbodyparts == 0)
|
|
return;
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(m_origin[0], m_origin[1], m_origin[2]);
|
|
|
|
glRotatef(m_angles[1], 0, 0, 1);
|
|
glRotatef(m_angles[0], 0, 1, 0);
|
|
glRotatef(m_angles[2], 1, 0, 0);
|
|
|
|
// glShadeModel (GL_SMOOTH);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
// glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
|
|
SetUpBones();
|
|
|
|
SetupLighting();
|
|
|
|
for (i = 0; i < m_pstudiohdr->numbodyparts; i++)
|
|
{
|
|
SetupModel(i);
|
|
DrawPoints();
|
|
}
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
// glShadeModel (GL_FLAT);
|
|
|
|
// glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
/*
|
|
================
|
|
|
|
================
|
|
*/
|
|
void StudioModel::DrawPoints()
|
|
{
|
|
int i, j;
|
|
mstudiomesh_t* pmesh;
|
|
byte* pvertbone;
|
|
byte* pnormbone;
|
|
vec3_t* pstudioverts;
|
|
vec3_t* pstudionorms;
|
|
mstudiotexture_t* ptexture;
|
|
float* av;
|
|
float* lv;
|
|
float lv_tmp;
|
|
short* pskinref;
|
|
|
|
pvertbone = ((byte*)m_pstudiohdr + m_pmodel->vertinfoindex);
|
|
pnormbone = ((byte*)m_pstudiohdr + m_pmodel->norminfoindex);
|
|
ptexture = (mstudiotexture_t*)((byte*)m_ptexturehdr + m_ptexturehdr->textureindex);
|
|
|
|
pmesh = (mstudiomesh_t*)((byte*)m_pstudiohdr + m_pmodel->meshindex);
|
|
|
|
pstudioverts = (vec3_t*)((byte*)m_pstudiohdr + m_pmodel->vertindex);
|
|
pstudionorms = (vec3_t*)((byte*)m_pstudiohdr + m_pmodel->normindex);
|
|
|
|
pskinref = (short*)((byte*)m_ptexturehdr + m_ptexturehdr->skinindex);
|
|
if (m_skinnum != 0 && m_skinnum < m_ptexturehdr->numskinfamilies)
|
|
pskinref += (m_skinnum * m_ptexturehdr->numskinref);
|
|
|
|
for (i = 0; i < m_pmodel->numverts; i++)
|
|
{
|
|
VectorTransform(pstudioverts[i], g_bonetransform[pvertbone[i]], g_pxformverts[i]);
|
|
}
|
|
|
|
//
|
|
// clip and draw all triangles
|
|
//
|
|
|
|
lv = (float*)g_pvlightvalues;
|
|
for (j = 0; j < m_pmodel->nummesh; j++)
|
|
{
|
|
int flags;
|
|
flags = ptexture[pskinref[pmesh[j].skinref]].flags;
|
|
for (i = 0; i < pmesh[j].numnorms; i++, lv += 3, pstudionorms++, pnormbone++)
|
|
{
|
|
Lighting(&lv_tmp, *pnormbone, flags, (float*)pstudionorms);
|
|
|
|
// FIX: move this check out of the inner loop
|
|
if (flags & STUDIO_NF_CHROME)
|
|
Chrome(g_chrome[(float(*)[3])lv - g_pvlightvalues], *pnormbone, (float*)pstudionorms);
|
|
|
|
lv[0] = lv_tmp * g_lightcolor[0];
|
|
lv[1] = lv_tmp * g_lightcolor[1];
|
|
lv[2] = lv_tmp * g_lightcolor[2];
|
|
}
|
|
}
|
|
|
|
glCullFace(GL_FRONT);
|
|
|
|
for (j = 0; j < m_pmodel->nummesh; j++)
|
|
{
|
|
float s, t;
|
|
short* ptricmds;
|
|
|
|
pmesh = (mstudiomesh_t*)((byte*)m_pstudiohdr + m_pmodel->meshindex) + j;
|
|
ptricmds = (short*)((byte*)m_pstudiohdr + pmesh->triindex);
|
|
|
|
s = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].width;
|
|
t = 1.0 / (float)ptexture[pskinref[pmesh->skinref]].height;
|
|
|
|
glBindTexture(GL_TEXTURE_2D, ptexture[pskinref[pmesh->skinref]].index);
|
|
|
|
if (ptexture[pskinref[pmesh->skinref]].flags & STUDIO_NF_CHROME)
|
|
{
|
|
while ((i = *(ptricmds++)) != 0)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
i = -i;
|
|
}
|
|
else
|
|
{
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
}
|
|
|
|
|
|
for (; i > 0; i--, ptricmds += 4)
|
|
{
|
|
// FIX: put these in as integer coords, not floats
|
|
glTexCoord2f(g_chrome[ptricmds[1]][0] * s, g_chrome[ptricmds[1]][1] * t);
|
|
|
|
lv = g_pvlightvalues[ptricmds[1]];
|
|
glColor4f(lv[0], lv[1], lv[2], 1.0);
|
|
|
|
av = g_pxformverts[ptricmds[0]];
|
|
glVertex3f(av[0], av[1], av[2]);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((i = *(ptricmds++)) != 0)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
i = -i;
|
|
}
|
|
else
|
|
{
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
}
|
|
|
|
|
|
for (; i > 0; i--, ptricmds += 4)
|
|
{
|
|
// FIX: put these in as integer coords, not floats
|
|
glTexCoord2f(ptricmds[2] * s, ptricmds[3] * t);
|
|
|
|
lv = g_pvlightvalues[ptricmds[1]];
|
|
glColor4f(lv[0], lv[1], lv[2], 1.0);
|
|
|
|
av = g_pxformverts[ptricmds[0]];
|
|
glVertex3f(av[0], av[1], av[2]);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
}
|
|
}
|