1430 lines
37 KiB
C++
1430 lines
37 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.
|
|
*
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
* without written permission from Valve LLC.
|
|
*
|
|
****/
|
|
|
|
// Big thanks to Chicken Fortress developers
|
|
// for this code.
|
|
#include <assert.h>
|
|
#include "hud.h"
|
|
#include "cl_util.h"
|
|
#include "const.h"
|
|
#include "com_model.h"
|
|
#include "studio.h"
|
|
#include "entity_state.h"
|
|
#include "cl_entity.h"
|
|
#include "dlight.h"
|
|
#include "triangleapi.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <math.h>
|
|
|
|
#include "studio_util.h"
|
|
#include "r_studioint.h"
|
|
|
|
#include "StudioModelRenderer.h"
|
|
#include "GameStudioModelRenderer.h"
|
|
|
|
#include "event_api.h"
|
|
#include "pm_defs.h"
|
|
|
|
extern CGameStudioModelRenderer g_StudioRenderer;
|
|
extern engine_studio_api_t IEngineStudio;
|
|
typedef struct pmtrace_s pmtrace_t;
|
|
|
|
void CStudioModelRenderer::Init(void)
|
|
{
|
|
m_pCvarHiModels = IEngineStudio.GetCvar("cl_himodels");
|
|
m_pCvarDeveloper = IEngineStudio.GetCvar("developer");
|
|
m_pCvarDrawEntities = IEngineStudio.GetCvar("r_drawentities");
|
|
|
|
m_pChromeSprite = IEngineStudio.GetChromeSprite();
|
|
|
|
IEngineStudio.GetModelCounters(&m_pStudioModelCount, &m_pModelsDrawn);
|
|
|
|
m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform();
|
|
m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform();
|
|
m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform();
|
|
m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix();
|
|
}
|
|
|
|
CStudioModelRenderer::CStudioModelRenderer(void)
|
|
{
|
|
m_fDoInterp = 1;
|
|
m_fGaitEstimation = 1;
|
|
m_pCurrentEntity = NULL;
|
|
m_pCvarHiModels = NULL;
|
|
m_pCvarDeveloper = NULL;
|
|
m_pCvarDrawEntities = NULL;
|
|
m_pChromeSprite = NULL;
|
|
m_pStudioModelCount = NULL;
|
|
m_pModelsDrawn = NULL;
|
|
m_protationmatrix = NULL;
|
|
m_paliastransform = NULL;
|
|
m_pbonetransform = NULL;
|
|
m_plighttransform = NULL;
|
|
m_pStudioHeader = NULL;
|
|
m_pBodyPart = NULL;
|
|
m_pSubModel = NULL;
|
|
m_pPlayerInfo = NULL;
|
|
m_pRenderModel = NULL;
|
|
m_iShadowSprite = 0;
|
|
}
|
|
|
|
CStudioModelRenderer::~CStudioModelRenderer(void)
|
|
{
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioCalcBoneAdj(float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen)
|
|
{
|
|
int i, j;
|
|
float value;
|
|
mstudiobonecontroller_t *pbonecontroller;
|
|
|
|
pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex);
|
|
|
|
for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++)
|
|
{
|
|
i = pbonecontroller[j].index;
|
|
|
|
if (i <= 3)
|
|
{
|
|
if (pbonecontroller[j].type & STUDIO_RLOOP)
|
|
{
|
|
if (abs(pcontroller1[i] - pcontroller2[i]) > 128)
|
|
{
|
|
int a, b;
|
|
a = (pcontroller1[j] + 128) % 256;
|
|
b = (pcontroller2[j] + 128) % 256;
|
|
value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0 / 256.0) + pbonecontroller[j].start;
|
|
}
|
|
else
|
|
{
|
|
value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0 / 256.0) + pbonecontroller[j].start;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value = mouthopen / 64.0;
|
|
|
|
if (value > 1.0)
|
|
value = 1.0;
|
|
|
|
value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
|
|
}
|
|
|
|
switch (pbonecontroller[j].type & STUDIO_TYPES)
|
|
{
|
|
case STUDIO_XR:
|
|
case STUDIO_YR:
|
|
case STUDIO_ZR:
|
|
{
|
|
adj[j] = value * (M_PI / 180.0);
|
|
break;
|
|
}
|
|
case STUDIO_X:
|
|
case STUDIO_Y:
|
|
case STUDIO_Z:
|
|
{
|
|
adj[j] = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioCalcBoneQuaterion(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, 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];
|
|
}
|
|
else
|
|
{
|
|
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j + 3]);
|
|
k = frame;
|
|
|
|
if (panimvalue->num.total < panimvalue->num.valid)
|
|
k = 0;
|
|
|
|
while (panimvalue->num.total <= k)
|
|
{
|
|
k -= panimvalue->num.total;
|
|
panimvalue += panimvalue->num.valid + 1;
|
|
|
|
if (panimvalue->num.total < panimvalue->num.valid)
|
|
k = 0;
|
|
}
|
|
|
|
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] += adj[pbone->bonecontroller[j + 3]];
|
|
angle2[j] += 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 CStudioModelRenderer::StudioCalcBonePosition(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos)
|
|
{
|
|
int j, k;
|
|
mstudioanimvalue_t *panimvalue;
|
|
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
pos[j] = pbone->value[j];
|
|
|
|
if (panim->offset[j] != 0)
|
|
{
|
|
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
|
|
k = frame;
|
|
|
|
if (panimvalue->num.total < panimvalue->num.valid)
|
|
k = 0;
|
|
|
|
while (panimvalue->num.total <= k)
|
|
{
|
|
k -= panimvalue->num.total;
|
|
panimvalue += panimvalue->num.valid + 1;
|
|
|
|
if (panimvalue->num.total < panimvalue->num.valid)
|
|
k = 0;
|
|
}
|
|
|
|
if (panimvalue->num.valid > k)
|
|
{
|
|
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
|
|
{
|
|
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 && adj)
|
|
pos[j] += adj[pbone->bonecontroller[j]];
|
|
}
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioSlerpBones(vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], 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_pStudioHeader->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;
|
|
}
|
|
}
|
|
|
|
mstudioanim_t *CStudioModelRenderer::StudioGetAnim(model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc)
|
|
{
|
|
mstudioseqgroup_t *pseqgroup;
|
|
cache_user_t *paSequences;
|
|
|
|
pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;
|
|
|
|
if (pseqdesc->seqgroup == 0)
|
|
return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex);
|
|
|
|
paSequences = (cache_user_t *)m_pSubModel->submodels;
|
|
|
|
if (paSequences == NULL)
|
|
{
|
|
paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc(16, sizeof(cache_user_t));
|
|
m_pSubModel->submodels = (dmodel_t *)paSequences;
|
|
}
|
|
|
|
if (!IEngineStudio.Cache_Check((struct cache_user_s *)&(paSequences[pseqdesc->seqgroup])))
|
|
{
|
|
gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name);
|
|
IEngineStudio.LoadCacheFile(pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup]);
|
|
}
|
|
|
|
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioPlayerBlend(mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch)
|
|
{
|
|
*pBlend = (*pPitch * 3);
|
|
|
|
if (*pBlend < pseqdesc->blendstart[0])
|
|
{
|
|
*pPitch -= pseqdesc->blendstart[0] / 3.0;
|
|
*pBlend = 0;
|
|
}
|
|
else if (*pBlend > pseqdesc->blendend[0])
|
|
{
|
|
*pPitch -= pseqdesc->blendend[0] / 3.0;
|
|
*pBlend = 255;
|
|
}
|
|
else
|
|
{
|
|
if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1)
|
|
*pBlend = 127;
|
|
else
|
|
*pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]);
|
|
|
|
*pPitch = 0;
|
|
}
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioSetUpTransform(int trivial_accept)
|
|
{
|
|
int i;
|
|
vec3_t angles;
|
|
vec3_t modelpos;
|
|
|
|
VectorCopy(m_pCurrentEntity->origin, modelpos);
|
|
|
|
angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL];
|
|
angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH];
|
|
angles[YAW] = m_pCurrentEntity->curstate.angles[YAW];
|
|
|
|
if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP)
|
|
{
|
|
float f = 0;
|
|
float d;
|
|
|
|
if ((m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f) && (m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime))
|
|
f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime);
|
|
|
|
if (m_fDoInterp)
|
|
f = f - 1.0;
|
|
else
|
|
f = 0;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
float ang1, ang2;
|
|
|
|
ang1 = m_pCurrentEntity->angles[i];
|
|
ang2 = m_pCurrentEntity->latched.prevangles[i];
|
|
|
|
d = ang1 - ang2;
|
|
|
|
if (d > 180)
|
|
d -= 360;
|
|
else if (d < -180)
|
|
d += 360;
|
|
|
|
angles[i] += d * f;
|
|
}
|
|
}
|
|
else if (m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE)
|
|
{
|
|
VectorCopy(m_pCurrentEntity->angles, angles);
|
|
}
|
|
|
|
angles[PITCH] = -angles[PITCH];
|
|
AngleMatrix(angles, (*m_protationmatrix));
|
|
|
|
if (!IEngineStudio.IsHardware())
|
|
{
|
|
static float viewmatrix[3][4];
|
|
|
|
VectorCopy(m_vRight, viewmatrix[0]);
|
|
VectorCopy(m_vUp, viewmatrix[1]);
|
|
VectorInverse(viewmatrix[1]);
|
|
VectorCopy(m_vNormal, viewmatrix[2]);
|
|
|
|
(*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0];
|
|
(*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1];
|
|
(*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2];
|
|
|
|
ConcatTransforms(viewmatrix, (*m_protationmatrix), (*m_paliastransform));
|
|
|
|
if (trivial_accept)
|
|
{
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
(*m_paliastransform)[0][i] *= m_fSoftwareXScale * (1.0 / (ZISCALE * 0x10000));
|
|
(*m_paliastransform)[1][i] *= m_fSoftwareYScale * (1.0 / (ZISCALE * 0x10000));
|
|
(*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000);
|
|
}
|
|
}
|
|
}
|
|
|
|
(*m_protationmatrix)[0][3] = modelpos[0];
|
|
(*m_protationmatrix)[1][3] = modelpos[1];
|
|
(*m_protationmatrix)[2][3] = modelpos[2];
|
|
}
|
|
|
|
float CStudioModelRenderer::StudioEstimateInterpolant(void)
|
|
{
|
|
float dadt = 1.0;
|
|
|
|
if (m_fDoInterp && (m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01))
|
|
{
|
|
dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1;
|
|
|
|
if (dadt > 2.0)
|
|
dadt = 2.0;
|
|
}
|
|
|
|
return dadt;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioCalcRotations(float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f)
|
|
{
|
|
int i;
|
|
int frame;
|
|
mstudiobone_t *pbone;
|
|
|
|
float s;
|
|
float adj[MAXSTUDIOCONTROLLERS];
|
|
float dadt;
|
|
|
|
if (f > pseqdesc->numframes - 1)
|
|
f = 0;
|
|
else if (f < -0.01)
|
|
f = -0.01;
|
|
|
|
frame = (int)f;
|
|
dadt = StudioEstimateInterpolant();
|
|
s = (f - frame);
|
|
|
|
pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
|
|
|
|
StudioCalcBoneAdj(dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen);
|
|
|
|
for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++)
|
|
{
|
|
StudioCalcBoneQuaterion(frame, s, pbone, panim, adj, q[i]);
|
|
StudioCalcBonePosition(frame, s, pbone, panim, adj, 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;
|
|
|
|
s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate;
|
|
|
|
if (pseqdesc->motiontype & STUDIO_LX)
|
|
pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0];
|
|
|
|
if (pseqdesc->motiontype & STUDIO_LY)
|
|
pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1];
|
|
|
|
if (pseqdesc->motiontype & STUDIO_LZ)
|
|
pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2];
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioFxTransform(cl_entity_t *ent, float transform[3][4])
|
|
{
|
|
switch (ent->curstate.renderfx)
|
|
{
|
|
case kRenderFxDistort:
|
|
case kRenderFxHologram:
|
|
{
|
|
if (gEngfuncs.pfnRandomLong(0, 49) == 0)
|
|
{
|
|
int axis = gEngfuncs.pfnRandomLong(0, 1);
|
|
|
|
if (axis == 1)
|
|
axis = 2;
|
|
|
|
VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] );
|
|
}
|
|
else if (gEngfuncs.pfnRandomLong(0, 49) == 0)
|
|
{
|
|
float offset;
|
|
int axis = gEngfuncs.pfnRandomLong(0, 1);
|
|
|
|
if (axis == 1)
|
|
axis = 2;
|
|
|
|
offset = gEngfuncs.pfnRandomFloat(-10, 10);
|
|
transform[gEngfuncs.pfnRandomLong(0, 2)][3] += offset;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case kRenderFxExplode:
|
|
{
|
|
float scale;
|
|
|
|
scale = 1.0 + (m_clTime - ent->curstate.animtime) * 10.0;
|
|
|
|
if (scale > 2)
|
|
scale = 2;
|
|
|
|
transform[0][1] *= scale;
|
|
transform[1][1] *= scale;
|
|
transform[2][1] *= scale;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
float CStudioModelRenderer::StudioEstimateFrame(mstudioseqdesc_t *pseqdesc)
|
|
{
|
|
double dfdt, f;
|
|
|
|
if (m_fDoInterp)
|
|
{
|
|
if (m_clTime < m_pCurrentEntity->curstate.animtime)
|
|
dfdt = 0;
|
|
else
|
|
dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps;
|
|
}
|
|
else
|
|
dfdt = 0;
|
|
|
|
if (pseqdesc->numframes <= 1)
|
|
f = 0;
|
|
else
|
|
f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0;
|
|
|
|
f += dfdt;
|
|
|
|
if (pseqdesc->flags & STUDIO_LOOPING)
|
|
{
|
|
if (pseqdesc->numframes > 1)
|
|
f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1);
|
|
|
|
if (f < 0)
|
|
f += (pseqdesc->numframes - 1);
|
|
}
|
|
else
|
|
{
|
|
if (f >= pseqdesc->numframes - 1.001)
|
|
f = pseqdesc->numframes - 1.001;
|
|
|
|
if (f < 0.0)
|
|
f = 0.0;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioSetupBones(void)
|
|
{
|
|
int i;
|
|
double f;
|
|
|
|
mstudiobone_t *pbones;
|
|
mstudioseqdesc_t *pseqdesc;
|
|
mstudioanim_t *panim;
|
|
|
|
static float pos[MAXSTUDIOBONES][3];
|
|
static vec4_t q[MAXSTUDIOBONES];
|
|
float bonematrix[3][4];
|
|
|
|
static float pos2[MAXSTUDIOBONES][3];
|
|
static vec4_t q2[MAXSTUDIOBONES];
|
|
static float pos3[MAXSTUDIOBONES][3];
|
|
static vec4_t q3[MAXSTUDIOBONES];
|
|
static float pos4[MAXSTUDIOBONES][3];
|
|
static vec4_t q4[MAXSTUDIOBONES];
|
|
|
|
if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq)
|
|
m_pCurrentEntity->curstate.sequence = 0;
|
|
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;
|
|
|
|
f = StudioEstimateFrame(pseqdesc);
|
|
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
|
|
|
|
StudioCalcRotations(pos, q, pseqdesc, panim, f);
|
|
|
|
if (pseqdesc->numblends > 1)
|
|
{
|
|
float s;
|
|
float dadt;
|
|
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos2, q2, pseqdesc, panim, f);
|
|
|
|
dadt = StudioEstimateInterpolant();
|
|
s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0;
|
|
|
|
StudioSlerpBones(q, pos, q2, pos2, s);
|
|
|
|
if (pseqdesc->numblends == 4)
|
|
{
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos3, q3, pseqdesc, panim, f);
|
|
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos4, q4, pseqdesc, panim, f);
|
|
|
|
s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0;
|
|
StudioSlerpBones(q3, pos3, q4, pos4, s);
|
|
|
|
s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0;
|
|
StudioSlerpBones(q, pos, q3, pos3, s);
|
|
}
|
|
}
|
|
|
|
if (m_fDoInterp && m_pCurrentEntity->latched.sequencetime && (m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime) && (m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq))
|
|
{
|
|
static float pos1b[MAXSTUDIOBONES][3];
|
|
static vec4_t q1b[MAXSTUDIOBONES];
|
|
float s;
|
|
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence;
|
|
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
|
|
|
|
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
|
|
|
|
if (pseqdesc->numblends > 1)
|
|
{
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
|
|
|
|
s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0;
|
|
StudioSlerpBones(q1b, pos1b, q2, pos2, s);
|
|
|
|
if (pseqdesc->numblends == 4)
|
|
{
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
|
|
|
|
panim += m_pStudioHeader->numbones;
|
|
StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
|
|
|
|
s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0;
|
|
StudioSlerpBones(q3, pos3, q4, pos4, s);
|
|
|
|
s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0;
|
|
StudioSlerpBones(q1b, pos1b, q3, pos3, s);
|
|
}
|
|
}
|
|
|
|
s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2;
|
|
StudioSlerpBones(q, pos, q1b, pos1b, s);
|
|
}
|
|
else
|
|
{
|
|
m_pCurrentEntity->latched.prevframe = f;
|
|
}
|
|
|
|
pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
|
|
|
|
if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0)
|
|
{
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence;
|
|
|
|
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
|
|
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe);
|
|
|
|
for (i = 0; i < m_pStudioHeader->numbones; i++)
|
|
{
|
|
if (strcmp(pbones[i].name, "Bip01 Spine") == 0)
|
|
break;
|
|
|
|
memcpy(pos[i], pos2[i], sizeof( pos[i]));
|
|
memcpy(q[i], q2[i], sizeof( q[i]));
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < m_pStudioHeader->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)
|
|
{
|
|
if (IEngineStudio.IsHardware())
|
|
{
|
|
ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);
|
|
MatrixCopy((*m_pbonetransform)[i], (*m_plighttransform)[i]);
|
|
}
|
|
else
|
|
{
|
|
ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]);
|
|
ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
|
|
}
|
|
|
|
StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]);
|
|
}
|
|
else
|
|
{
|
|
ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
|
|
ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioSaveBones(void)
|
|
{
|
|
int i;
|
|
|
|
mstudiobone_t *pbones;
|
|
pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
|
|
|
|
m_nCachedBones = m_pStudioHeader->numbones;
|
|
|
|
for (i = 0; i < m_pStudioHeader->numbones; i++)
|
|
{
|
|
strncpy(m_nCachedBoneNames[i], pbones[i].name, 32);
|
|
MatrixCopy((*m_pbonetransform)[i], m_rgCachedBoneTransform[i]);
|
|
MatrixCopy((*m_plighttransform)[i], m_rgCachedLightTransform[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioMergeBones(model_t *m_pSubModel)
|
|
{
|
|
int i, j;
|
|
double f;
|
|
|
|
mstudiobone_t *pbones;
|
|
mstudioseqdesc_t *pseqdesc;
|
|
mstudioanim_t *panim;
|
|
|
|
static float pos[MAXSTUDIOBONES][3];
|
|
float bonematrix[3][4];
|
|
static vec4_t q[MAXSTUDIOBONES];
|
|
|
|
if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq)
|
|
m_pCurrentEntity->curstate.sequence = 0;
|
|
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;
|
|
|
|
f = StudioEstimateFrame(pseqdesc);
|
|
|
|
if (m_pCurrentEntity->latched.prevframe > f)
|
|
{
|
|
}
|
|
|
|
panim = StudioGetAnim(m_pSubModel, pseqdesc);
|
|
StudioCalcRotations(pos, q, pseqdesc, panim, f);
|
|
|
|
pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex);
|
|
|
|
for (i = 0; i < m_pStudioHeader->numbones; i++)
|
|
{
|
|
for (j = 0; j < m_nCachedBones; j++)
|
|
{
|
|
if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0)
|
|
{
|
|
MatrixCopy(m_rgCachedBoneTransform[j], (*m_pbonetransform)[i]);
|
|
MatrixCopy(m_rgCachedLightTransform[j], (*m_plighttransform)[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j >= m_nCachedBones)
|
|
{
|
|
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)
|
|
{
|
|
if (IEngineStudio.IsHardware())
|
|
{
|
|
ConcatTransforms((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]);
|
|
MatrixCopy((*m_pbonetransform)[i], (*m_plighttransform)[i]);
|
|
}
|
|
else
|
|
{
|
|
ConcatTransforms((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]);
|
|
ConcatTransforms((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]);
|
|
}
|
|
|
|
StudioFxTransform(m_pCurrentEntity, (*m_pbonetransform)[i]);
|
|
}
|
|
else
|
|
{
|
|
ConcatTransforms((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]);
|
|
ConcatTransforms((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int CStudioModelRenderer::StudioDrawModel(int flags)
|
|
{
|
|
m_pCurrentEntity = IEngineStudio.GetCurrentEntity();
|
|
|
|
IEngineStudio.GetTimes(&m_nFrameCount, &m_clTime, &m_clOldTime);
|
|
IEngineStudio.GetViewInfo(m_vRenderOrigin, m_vUp, m_vRight, m_vNormal);
|
|
IEngineStudio.GetAliasScale(&m_fSoftwareXScale, &m_fSoftwareYScale);
|
|
|
|
if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer)
|
|
{
|
|
entity_state_t deadplayer;
|
|
|
|
int result;
|
|
int save_interp;
|
|
|
|
if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients())
|
|
return 0;
|
|
|
|
deadplayer = *(IEngineStudio.GetPlayerState(m_pCurrentEntity->curstate.renderamt - 1));
|
|
|
|
deadplayer.number = m_pCurrentEntity->curstate.renderamt;
|
|
deadplayer.weaponmodel = 0;
|
|
deadplayer.gaitsequence = 0;
|
|
|
|
deadplayer.movetype = MOVETYPE_NONE;
|
|
VectorCopy(m_pCurrentEntity->curstate.angles, deadplayer.angles);
|
|
VectorCopy(m_pCurrentEntity->curstate.origin, deadplayer.origin);
|
|
|
|
save_interp = m_fDoInterp;
|
|
m_fDoInterp = 0;
|
|
|
|
result = StudioDrawPlayer(flags, &deadplayer);
|
|
|
|
m_fDoInterp = save_interp;
|
|
return result;
|
|
}
|
|
|
|
m_pRenderModel = m_pCurrentEntity->model;
|
|
m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(m_pRenderModel);
|
|
|
|
IEngineStudio.StudioSetHeader(m_pStudioHeader);
|
|
IEngineStudio.SetRenderModel(m_pRenderModel);
|
|
|
|
StudioSetUpTransform(0);
|
|
|
|
if(m_pCurrentEntity == gEngfuncs.GetViewModel() && (cl_righthand->value))
|
|
{
|
|
(*m_protationmatrix)[0][1] *= -1;
|
|
(*m_protationmatrix)[1][1] *= -1;
|
|
(*m_protationmatrix)[2][1] *= -1;
|
|
|
|
//IEngineStudio.StudioSetCullState(true);
|
|
}
|
|
|
|
if (flags & STUDIO_RENDER)
|
|
{
|
|
if (!IEngineStudio.StudioCheckBBox())
|
|
return 0;
|
|
|
|
(*m_pModelsDrawn)++;
|
|
(*m_pStudioModelCount)++;
|
|
|
|
if (m_pStudioHeader->numbodyparts == 0)
|
|
return 1;
|
|
}
|
|
|
|
if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW)
|
|
StudioMergeBones(m_pRenderModel);
|
|
else
|
|
StudioSetupBones();
|
|
|
|
StudioSaveBones();
|
|
|
|
if (flags & STUDIO_EVENTS)
|
|
{
|
|
StudioCalcAttachments();
|
|
IEngineStudio.StudioClientEvents();
|
|
|
|
if (m_pCurrentEntity->index > 0)
|
|
{
|
|
cl_entity_t *ent = gEngfuncs.GetEntityByIndex(m_pCurrentEntity->index);
|
|
memcpy(ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4);
|
|
}
|
|
}
|
|
|
|
if (flags & STUDIO_RENDER)
|
|
{
|
|
alight_t lighting;
|
|
vec3_t dir;
|
|
lighting.plightvec = dir;
|
|
|
|
IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting);
|
|
|
|
IEngineStudio.StudioEntityLight(&lighting);
|
|
IEngineStudio.StudioSetupLighting(&lighting);
|
|
|
|
m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF;
|
|
m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8;
|
|
|
|
IEngineStudio.StudioSetRemapColors(m_nTopColor, m_nBottomColor);
|
|
|
|
StudioRenderModel(dir);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioEstimateGait(entity_state_t *pplayer)
|
|
{
|
|
float dt;
|
|
vec3_t est_velocity;
|
|
|
|
dt = (m_clTime - m_clOldTime);
|
|
|
|
if (dt < 0)
|
|
dt = 0;
|
|
else if (dt > 1.0)
|
|
dt = 1;
|
|
|
|
if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount)
|
|
{
|
|
m_flGaitMovement = 0;
|
|
return;
|
|
}
|
|
|
|
if (m_fGaitEstimation)
|
|
{
|
|
VectorSubtract(m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity);
|
|
VectorCopy(m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin);
|
|
m_flGaitMovement = est_velocity.Length();
|
|
|
|
if (dt <= 0 || m_flGaitMovement / dt < 5)
|
|
{
|
|
m_flGaitMovement = 0;
|
|
est_velocity[0] = 0;
|
|
est_velocity[1] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VectorCopy(pplayer->velocity, est_velocity);
|
|
m_flGaitMovement = est_velocity.Length() * dt;
|
|
}
|
|
|
|
if (est_velocity[1] == 0 && est_velocity[0] == 0)
|
|
{
|
|
float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw;
|
|
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
|
|
|
|
if (flYawDiff > 180)
|
|
flYawDiff -= 360;
|
|
if (flYawDiff < -180)
|
|
flYawDiff += 360;
|
|
|
|
if (dt < 0.25)
|
|
flYawDiff *= dt * 4;
|
|
else
|
|
flYawDiff *= dt;
|
|
|
|
m_pPlayerInfo->gaityaw += flYawDiff;
|
|
m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360;
|
|
m_flGaitMovement = 0;
|
|
}
|
|
else
|
|
{
|
|
m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
|
|
|
|
if (m_pPlayerInfo->gaityaw > 180)
|
|
m_pPlayerInfo->gaityaw = 180;
|
|
|
|
if (m_pPlayerInfo->gaityaw < -180)
|
|
m_pPlayerInfo->gaityaw = -180;
|
|
}
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioProcessGait(entity_state_t *pplayer)
|
|
{
|
|
mstudioseqdesc_t *pseqdesc;
|
|
float dt;
|
|
int iBlend;
|
|
float flYaw;
|
|
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence;
|
|
|
|
StudioPlayerBlend(pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH]);
|
|
|
|
m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH];
|
|
m_pCurrentEntity->curstate.blending[0] = iBlend;
|
|
m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0];
|
|
m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0];
|
|
|
|
dt = (m_clTime - m_clOldTime);
|
|
|
|
if (dt < 0)
|
|
dt = 0;
|
|
else if (dt > 1.0)
|
|
dt = 1;
|
|
|
|
StudioEstimateGait(pplayer);
|
|
|
|
flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw;
|
|
flYaw = flYaw - (int)(flYaw / 360) * 360;
|
|
|
|
if (flYaw < -180)
|
|
flYaw = flYaw + 360;
|
|
|
|
if (flYaw > 180)
|
|
flYaw = flYaw - 360;
|
|
|
|
if (flYaw > 120)
|
|
{
|
|
m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180;
|
|
m_flGaitMovement = -m_flGaitMovement;
|
|
flYaw = flYaw - 180;
|
|
}
|
|
else if (flYaw < -120)
|
|
{
|
|
m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180;
|
|
m_flGaitMovement = -m_flGaitMovement;
|
|
flYaw = flYaw + 180;
|
|
}
|
|
|
|
m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
|
|
m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
|
|
m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
|
|
m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0);
|
|
m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
|
|
m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
|
|
m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
|
|
m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];
|
|
|
|
m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw;
|
|
|
|
if (m_pCurrentEntity->angles[YAW] < -0)
|
|
m_pCurrentEntity->angles[YAW] += 360;
|
|
|
|
m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW];
|
|
|
|
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence;
|
|
|
|
if (pseqdesc->linearmovement[0] > 0)
|
|
m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes;
|
|
else
|
|
m_pPlayerInfo->gaitframe += pseqdesc->fps * dt;
|
|
|
|
m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes;
|
|
|
|
if (m_pPlayerInfo->gaitframe < 0)
|
|
m_pPlayerInfo->gaitframe += pseqdesc->numframes;
|
|
}
|
|
|
|
int CStudioModelRenderer::StudioDrawPlayer(int flags, entity_state_t *pplayer)
|
|
{
|
|
m_pCurrentEntity = IEngineStudio.GetCurrentEntity();
|
|
|
|
IEngineStudio.GetTimes(&m_nFrameCount, &m_clTime, &m_clOldTime);
|
|
IEngineStudio.GetViewInfo(m_vRenderOrigin, m_vUp, m_vRight, m_vNormal);
|
|
IEngineStudio.GetAliasScale(&m_fSoftwareXScale, &m_fSoftwareYScale);
|
|
|
|
m_nPlayerIndex = pplayer->number - 1;
|
|
|
|
if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients())
|
|
return 0;
|
|
|
|
m_pRenderModel = IEngineStudio.SetupPlayerModel(m_nPlayerIndex);
|
|
|
|
if (m_pRenderModel == NULL)
|
|
return 0;
|
|
|
|
m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(m_pRenderModel);
|
|
|
|
IEngineStudio.StudioSetHeader(m_pStudioHeader);
|
|
IEngineStudio.SetRenderModel(m_pRenderModel);
|
|
|
|
if (pplayer->gaitsequence)
|
|
{
|
|
vec3_t orig_angles;
|
|
m_pPlayerInfo = IEngineStudio.PlayerInfo(m_nPlayerIndex);
|
|
|
|
VectorCopy(m_pCurrentEntity->angles, orig_angles);
|
|
|
|
StudioProcessGait(pplayer);
|
|
|
|
m_pPlayerInfo->gaitsequence = pplayer->gaitsequence;
|
|
m_pPlayerInfo = NULL;
|
|
|
|
StudioSetUpTransform(0);
|
|
VectorCopy(orig_angles, m_pCurrentEntity->angles);
|
|
}
|
|
else
|
|
{
|
|
m_pCurrentEntity->curstate.controller[0] = 127;
|
|
m_pCurrentEntity->curstate.controller[1] = 127;
|
|
m_pCurrentEntity->curstate.controller[2] = 127;
|
|
m_pCurrentEntity->curstate.controller[3] = 127;
|
|
m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0];
|
|
m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1];
|
|
m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2];
|
|
m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3];
|
|
|
|
m_pPlayerInfo = IEngineStudio.PlayerInfo(m_nPlayerIndex);
|
|
m_pPlayerInfo->gaitsequence = 0;
|
|
|
|
StudioSetUpTransform(0);
|
|
}
|
|
|
|
if (flags & STUDIO_RENDER)
|
|
{
|
|
if (!IEngineStudio.StudioCheckBBox())
|
|
return 0;
|
|
|
|
(*m_pModelsDrawn)++;
|
|
(*m_pStudioModelCount)++;
|
|
|
|
if (m_pStudioHeader->numbodyparts == 0)
|
|
return 1;
|
|
}
|
|
|
|
m_pPlayerInfo = IEngineStudio.PlayerInfo(m_nPlayerIndex);
|
|
|
|
StudioSetupBones();
|
|
StudioSaveBones();
|
|
|
|
m_pPlayerInfo->renderframe = m_nFrameCount;
|
|
m_pPlayerInfo = NULL;
|
|
|
|
if (flags & STUDIO_EVENTS)
|
|
{
|
|
StudioCalcAttachments();
|
|
IEngineStudio.StudioClientEvents();
|
|
|
|
if (m_pCurrentEntity->index > 0)
|
|
{
|
|
cl_entity_t *ent = gEngfuncs.GetEntityByIndex(m_pCurrentEntity->index);
|
|
memcpy(ent->attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * 4);
|
|
}
|
|
}
|
|
|
|
if (flags & STUDIO_RENDER)
|
|
{
|
|
if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model)
|
|
m_pCurrentEntity->curstate.body = 255;
|
|
|
|
if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1) && (m_pRenderModel == m_pCurrentEntity->model))
|
|
m_pCurrentEntity->curstate.body = 1;
|
|
|
|
alight_t lighting;
|
|
vec3_t dir;
|
|
lighting.plightvec = dir;
|
|
|
|
IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting);
|
|
IEngineStudio.StudioEntityLight(&lighting);
|
|
IEngineStudio.StudioSetupLighting(&lighting);
|
|
|
|
m_pPlayerInfo = IEngineStudio.PlayerInfo(m_nPlayerIndex);
|
|
|
|
m_nTopColor = m_pPlayerInfo->topcolor;
|
|
|
|
if (m_nTopColor < 0)
|
|
m_nTopColor = 0;
|
|
|
|
if (m_nTopColor > 360)
|
|
m_nTopColor = 360;
|
|
|
|
m_nBottomColor = m_pPlayerInfo->bottomcolor;
|
|
|
|
if (m_nBottomColor < 0)
|
|
m_nBottomColor = 0;
|
|
|
|
if (m_nBottomColor > 360)
|
|
m_nBottomColor = 360;
|
|
|
|
IEngineStudio.StudioSetRemapColors(m_nTopColor, m_nBottomColor);
|
|
|
|
StudioRenderModel(dir);
|
|
m_pPlayerInfo = NULL;
|
|
|
|
if (pplayer->weaponmodel)
|
|
{
|
|
cl_entity_t saveent = *m_pCurrentEntity;
|
|
model_t *pweaponmodel = IEngineStudio.GetModelByIndex(pplayer->weaponmodel);
|
|
|
|
m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata(pweaponmodel);
|
|
IEngineStudio.StudioSetHeader(m_pStudioHeader);
|
|
|
|
StudioMergeBones(pweaponmodel);
|
|
|
|
IEngineStudio.StudioSetupLighting(&lighting);
|
|
|
|
StudioRenderModel(dir);
|
|
|
|
StudioCalcAttachments();
|
|
|
|
*m_pCurrentEntity = saveent;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioCalcAttachments(void)
|
|
{
|
|
int i;
|
|
mstudioattachment_t *pattachment;
|
|
|
|
if (m_pStudioHeader->numattachments > 4)
|
|
gEngfuncs.Con_DPrintf("Too many attachments on %s\n", m_pCurrentEntity->model->name);
|
|
|
|
pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex);
|
|
|
|
for (i = 0; i < m_pStudioHeader->numattachments; i++)
|
|
VectorTransform(pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i]);
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioRenderModel(float *lightdir)
|
|
{
|
|
IEngineStudio.SetChromeOrigin();
|
|
|
|
int iSaveRenderMode = m_pCurrentEntity->curstate.rendermode;
|
|
int iSaveRenderFx = m_pCurrentEntity->curstate.renderfx;
|
|
int iSaveRenderAmt = m_pCurrentEntity->curstate.renderamt;
|
|
|
|
|
|
IEngineStudio.SetForceFaceFlags(0);
|
|
StudioRenderFinal();
|
|
|
|
if (iSaveRenderFx == kRenderFxGlowShell)
|
|
{
|
|
m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell;
|
|
|
|
gEngfuncs.pTriAPI->SpriteTexture(m_pChromeSprite, 0);
|
|
|
|
IEngineStudio.SetForceFaceFlags(STUDIO_NF_CHROME);
|
|
StudioRenderFinal();
|
|
}
|
|
|
|
|
|
m_pCurrentEntity->curstate.rendermode = iSaveRenderMode;
|
|
m_pCurrentEntity->curstate.renderfx = iSaveRenderFx;
|
|
m_pCurrentEntity->curstate.renderamt = iSaveRenderAmt;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioRenderFinal_Software(void)
|
|
{
|
|
int i;
|
|
|
|
IEngineStudio.SetupRenderer(0);
|
|
|
|
if (m_pCvarDrawEntities->value == 2)
|
|
{
|
|
IEngineStudio.StudioDrawBones();
|
|
}
|
|
else if (m_pCvarDrawEntities->value == 3)
|
|
{
|
|
IEngineStudio.StudioDrawHulls();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < m_pStudioHeader->numbodyparts; i++)
|
|
{
|
|
IEngineStudio.StudioSetupModel(i, (void **)&m_pBodyPart, (void **)&m_pSubModel);
|
|
IEngineStudio.StudioDrawPoints();
|
|
}
|
|
}
|
|
|
|
if (m_pCvarDrawEntities->value == 4)
|
|
{
|
|
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd);
|
|
IEngineStudio.StudioDrawHulls();
|
|
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
|
|
}
|
|
|
|
if (m_pCvarDrawEntities->value == 5)
|
|
IEngineStudio.StudioDrawAbsBBox();
|
|
|
|
IEngineStudio.RestoreRenderer();
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioRenderFinal_Hardware(void)
|
|
{
|
|
int i;
|
|
int rendermode;
|
|
|
|
rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode;
|
|
IEngineStudio.SetupRenderer(rendermode);
|
|
|
|
if (m_pCvarDrawEntities->value == 2)
|
|
{
|
|
IEngineStudio.StudioDrawBones();
|
|
}
|
|
else if (m_pCvarDrawEntities->value == 3)
|
|
{
|
|
IEngineStudio.StudioDrawHulls();
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < m_pStudioHeader->numbodyparts; i++)
|
|
{
|
|
IEngineStudio.StudioSetupModel(i, (void **)&m_pBodyPart, (void **)&m_pSubModel);
|
|
|
|
if (m_fDoInterp)
|
|
m_pCurrentEntity->trivial_accept = 0;
|
|
|
|
IEngineStudio.GL_SetRenderMode(rendermode);
|
|
IEngineStudio.StudioSetRenderamt(m_pCurrentEntity->curstate.renderamt);
|
|
IEngineStudio.StudioDrawPoints();
|
|
}
|
|
}
|
|
|
|
if (m_pCvarDrawEntities->value == 4)
|
|
{
|
|
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd);
|
|
IEngineStudio.StudioDrawHulls();
|
|
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);
|
|
}
|
|
|
|
IEngineStudio.RestoreRenderer();
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioRenderFinal(void)
|
|
{
|
|
if (IEngineStudio.IsHardware())
|
|
StudioRenderFinal_Hardware();
|
|
else
|
|
StudioRenderFinal_Software();
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioSetShadowSprite(int idx)
|
|
{
|
|
m_iShadowSprite = idx;
|
|
}
|
|
|
|
void CStudioModelRenderer::StudioDrawShadow( Vector origin, float scale )
|
|
{
|
|
Vector endPoint = origin;
|
|
Vector p1, p2, p3, p4;
|
|
pmtrace_t pmtrace;
|
|
|
|
endPoint.z -= 150.0f;
|
|
|
|
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
|
|
gEngfuncs.pEventAPI->EV_PushPMStates( );
|
|
gEngfuncs.pEventAPI->EV_SetSolidPlayers( -1 );
|
|
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
|
|
gEngfuncs.pEventAPI->EV_PlayerTrace( origin, endPoint, PM_STUDIO_IGNORE | PM_GLASS_IGNORE, -1, &pmtrace );
|
|
gEngfuncs.pEventAPI->EV_PopPMStates( );
|
|
|
|
// don't allow shadow if player in solid area
|
|
if( pmtrace.startsolid )
|
|
return;
|
|
|
|
// don't allow shadow if doesn't hit anything
|
|
if( pmtrace.fraction >= 1.0f )
|
|
return;
|
|
|
|
pmtrace.plane.normal = pmtrace.plane.normal.Normalize( );
|
|
|
|
// don't allow shadow on too lean planes
|
|
if( pmtrace.plane.normal.z <= 0.7 )
|
|
return;
|
|
|
|
pmtrace.plane.normal = pmtrace.plane.normal * scale * ( 1.0 - pmtrace.fraction );
|
|
|
|
|
|
// add 2.0f to Z, for avoid Z-fighting
|
|
p1.x = pmtrace.endpos.x - pmtrace.plane.normal.z;
|
|
p1.y = pmtrace.endpos.y + pmtrace.plane.normal.z;
|
|
p1.z = pmtrace.endpos.z + 2.0f + pmtrace.plane.normal.x - pmtrace.plane.normal.y;
|
|
|
|
p2.x = pmtrace.endpos.x + pmtrace.plane.normal.z;
|
|
p2.y = pmtrace.endpos.y + pmtrace.plane.normal.z;
|
|
p2.z = pmtrace.endpos.z + 2.0f - pmtrace.plane.normal.x - pmtrace.plane.normal.y;
|
|
|
|
p3.x = pmtrace.endpos.x + pmtrace.plane.normal.z;
|
|
p3.y = pmtrace.endpos.y - pmtrace.plane.normal.z;
|
|
p3.z = pmtrace.endpos.z + 2.0f - pmtrace.plane.normal.x + pmtrace.plane.normal.y;
|
|
|
|
p4.x = pmtrace.endpos.x - pmtrace.plane.normal.z;
|
|
p4.y = pmtrace.endpos.y - pmtrace.plane.normal.z;
|
|
p4.z = pmtrace.endpos.z + 2.0f + pmtrace.plane.normal.x + pmtrace.plane.normal.y;
|
|
|
|
IEngineStudio.StudioRenderShadow( m_iShadowSprite, p1, p2, p3, p4 );
|
|
}
|