cs16-client-legacy/cl_dll/studio/GameStudioModelRenderer.cpp

1092 lines
28 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 "pm_defs.h"
#define ANIM_WALK_SEQUENCE 3
#define ANIM_JUMP_SEQUENCE 6
#define ANIM_SWIM_1 8
#define ANIM_SWIM_2 9
#define ANIM_FIRST_DEATH_SEQUENCE 101
#define ANIM_LAST_DEATH_SEQUENCE 159
#define ANIM_FIRST_EMOTION_SEQUENCE 198
#define ANIM_LAST_EMOTION_SEQUENCE 207
CGameStudioModelRenderer g_StudioRenderer;
int g_rseq;
int g_gaitseq;
vec3_t g_clorg;
vec3_t g_clang;
void CounterStrike_GetSequence(int *seq, int *gaitseq)
{
*seq = g_rseq;
*gaitseq = g_gaitseq;
}
void CounterStrike_GetOrientation(float *o, float *a)
{
VectorCopy(g_clorg, o);
VectorCopy(g_clang, a);
}
float g_flStartScaleTime;
int iPrevRenderState;
int iRenderStateChanged;
engine_studio_api_t IEngineStudio;
static client_anim_state_t g_state;
static client_anim_state_t g_clientstate;
CGameStudioModelRenderer::CGameStudioModelRenderer(void)
{
m_bLocal = false;
}
mstudioanim_t *CGameStudioModelRenderer::LookupAnimation(mstudioseqdesc_t *pseqdesc, int index)
{
mstudioanim_t *panim = NULL;
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
if (index < 0)
return panim;
if (index > (pseqdesc->numblends - 1))
return panim;
panim += index * m_pStudioHeader->numbones;
return panim;
}
void CGameStudioModelRenderer::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->player)
{
CStudioModelRenderer::StudioSetupBones();
return;
}
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;
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
f = StudioEstimateFrame(pseqdesc);
if (m_pPlayerInfo->gaitsequence == ANIM_WALK_SEQUENCE)
{
if (m_pCurrentEntity->curstate.blending[0] <= 26)
{
m_pCurrentEntity->curstate.blending[0] = 0;
m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0];
}
else
{
m_pCurrentEntity->curstate.blending[0] -= 26;
m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0];
}
}
if (pseqdesc->numblends == 9)
{
float s = m_pCurrentEntity->curstate.blending[0];
float t = m_pCurrentEntity->curstate.blending[1];
if (s <= 127.0)
{
s = (s * 2.0);
if (t <= 127.0)
{
t = (t * 2.0);
StudioCalcRotations(pos, q, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 1);
StudioCalcRotations(pos2, q2, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 3);
StudioCalcRotations(pos3, q3, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos4, q4, pseqdesc, panim, f);
}
else
{
t = 2.0 * (t - 127.0);
panim = LookupAnimation(pseqdesc, 3);
StudioCalcRotations(pos, q, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos2, q2, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 6);
StudioCalcRotations(pos3, q3, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 7);
StudioCalcRotations(pos4, q4, pseqdesc, panim, f);
}
}
else
{
s = 2.0 * (s - 127.0);
if (t <= 127.0)
{
t = (t * 2.0);
panim = LookupAnimation(pseqdesc, 1);
StudioCalcRotations(pos, q, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 2);
StudioCalcRotations(pos2, q2, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos3, q3, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 5);
StudioCalcRotations(pos4, q4, pseqdesc, panim, f);
}
else
{
t = 2.0 * (t - 127.0);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos, q, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 5);
StudioCalcRotations(pos2, q2, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 7);
StudioCalcRotations(pos3, q3, pseqdesc, panim, f);
panim = LookupAnimation(pseqdesc, 8);
StudioCalcRotations(pos4, q4, pseqdesc, panim, f);
}
}
s /= 255.0;
t /= 255.0;
StudioSlerpBones(q, pos, q2, pos2, s);
StudioSlerpBones(q3, pos3, q4, pos4, s);
StudioSlerpBones(q, pos, q3, pos3, t);
}
else
{
StudioCalcRotations(pos, q, pseqdesc, panim, f);
}
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 = m_pCurrentEntity->latched.prevseqblending[0];
float t = m_pCurrentEntity->latched.prevseqblending[1];
pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence;
panim = StudioGetAnim(m_pRenderModel, pseqdesc);
if (pseqdesc->numblends == 9)
{
if (s <= 127.0)
{
s = (s * 2.0);
if (t <= 127.0)
{
t = (t * 2.0);
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 1);
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 3);
StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
}
else
{
t = 2.0 * (t - 127.0);
panim = LookupAnimation(pseqdesc, 3);
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 6);
StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 7);
StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
}
}
else
{
s = 2.0 * (s - 127.0);
if (t <= 127.0)
{
t = (t * 2.0);
panim = LookupAnimation(pseqdesc, 1);
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 2);
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 5);
StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
}
else
{
t = 2.0 * (t - 127.0);
panim = LookupAnimation(pseqdesc, 4);
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 5);
StudioCalcRotations(pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 7);
StudioCalcRotations(pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
panim = LookupAnimation(pseqdesc, 8);
StudioCalcRotations(pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
}
}
s /= 255.0;
t /= 255.0;
StudioSlerpBones(q1b, pos1b, q2, pos2, s);
StudioSlerpBones(q3, pos3, q4, pos4, s);
StudioSlerpBones(q1b, pos1b, q3, pos3, t);
}
else
{
StudioCalcRotations(pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe);
}
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_pCurrentEntity->curstate.sequence < ANIM_FIRST_DEATH_SEQUENCE || m_pCurrentEntity->curstate.sequence > ANIM_LAST_DEATH_SEQUENCE) && (m_pCurrentEntity->curstate.sequence < ANIM_FIRST_EMOTION_SEQUENCE || m_pCurrentEntity->curstate.sequence > ANIM_LAST_EMOTION_SEQUENCE) && m_pCurrentEntity->curstate.sequence != ANIM_SWIM_1 && m_pCurrentEntity->curstate.sequence != ANIM_SWIM_2)
{
int copy = 1;
if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq)
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"))
copy = 0;
else if (!strcmp(pbones[pbones[i].parent].name, "Bip01 Pelvis"))
copy = 1;
if (copy)
{
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 CGameStudioModelRenderer::StudioEstimateGait(entity_state_t *pplayer)
{
float dt;
vec3_t est_velocity;
dt = (m_clTime - m_clOldTime);
dt = max(0.0, dt);
dt = min(1.0, dt);
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 CGameStudioModelRenderer::StudioPlayerBlend(mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch)
{
float range = 45.0;
*pBlend = (*pPitch * 3);
if (*pBlend <= -range)
*pBlend = 255;
else if (*pBlend >= range)
*pBlend = 0;
else
*pBlend = 255 * (range - *pBlend) / (2 * range);
*pPitch = 0;
}
void CGameStudioModelRenderer::CalculatePitchBlend(entity_state_t *pplayer)
{
mstudioseqdesc_t *pseqdesc;
int iBlend;
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[1] = iBlend;
m_pCurrentEntity->latched.prevblending[1] = m_pCurrentEntity->curstate.blending[1];
m_pCurrentEntity->latched.prevseqblending[1] = m_pCurrentEntity->curstate.blending[1];
}
void CGameStudioModelRenderer::CalculateYawBlend(entity_state_t *pplayer)
{
float dt;
float flYaw;
dt = (m_clTime - m_clOldTime);
dt = max(0.0, dt);
dt = min(1.0, dt);
StudioEstimateGait(pplayer);
flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw;
flYaw = fmod(flYaw, 360.0f);
if (flYaw < -180)
flYaw = flYaw + 360;
else if (flYaw > 180)
flYaw = flYaw - 360;
float maxyaw = 120.0;
if (flYaw > maxyaw)
{
m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180;
m_flGaitMovement = -m_flGaitMovement;
flYaw = flYaw - 180;
}
else if (flYaw < -maxyaw)
{
m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180;
m_flGaitMovement = -m_flGaitMovement;
flYaw = flYaw + 180;
}
float blend_yaw = (flYaw / 90.0) * 128.0 + 127.0;
blend_yaw = min(255.0, blend_yaw);
blend_yaw = max(0.0, blend_yaw);
blend_yaw = 255.0 - blend_yaw;
m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw);
m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0];
m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0];
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];
}
void CGameStudioModelRenderer::StudioProcessGait(entity_state_t *pplayer)
{
mstudioseqdesc_t *pseqdesc;
float dt;
CalculateYawBlend(pplayer);
CalculatePitchBlend(pplayer);
dt = (m_clTime - m_clOldTime);
dt = max(0.0, dt);
dt = min(1.0, dt);
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_pCurrentEntity->curstate.framerate;
m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes;
if (m_pPlayerInfo->gaitframe < 0)
m_pPlayerInfo->gaitframe += pseqdesc->numframes;
}
void CGameStudioModelRenderer::SavePlayerState(entity_state_t *pplayer)
{
client_anim_state_t *st;
cl_entity_t *ent = IEngineStudio.GetCurrentEntity();
if (!ent)
return;
st = &g_state;
VectorCopy(ent->curstate.angles, st->angles);
VectorCopy(ent->curstate.origin, st->origin);
VectorCopy(ent->angles, st->realangles);
st->sequence = ent->curstate.sequence;
st->gaitsequence = pplayer->gaitsequence;
st->animtime = ent->curstate.animtime;
st->frame = ent->curstate.frame;
st->framerate = ent->curstate.framerate;
memcpy(st->blending, ent->curstate.blending, 2);
memcpy(st->controller, ent->curstate.controller, 4);
st->lv = ent->latched;
}
void GetSequenceInfo(void *pmodel, client_anim_state_t *pev, float *pflFrameRate, float *pflGroundSpeed)
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (!pstudiohdr)
return;
mstudioseqdesc_t *pseqdesc;
if (pev->sequence >= pstudiohdr->numseq)
{
*pflFrameRate = 0.0;
*pflGroundSpeed = 0.0;
return;
}
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
if (pseqdesc->numframes > 1)
{
*pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1);
*pflGroundSpeed = sqrt(pseqdesc->linearmovement[0] * pseqdesc->linearmovement[0] + pseqdesc->linearmovement[1] * pseqdesc->linearmovement[1] + pseqdesc->linearmovement[2] * pseqdesc->linearmovement[2]);
*pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1);
}
else
{
*pflFrameRate = 256.0;
*pflGroundSpeed = 0.0;
}
}
int GetSequenceFlags(void *pmodel, client_anim_state_t *pev)
{
studiohdr_t *pstudiohdr;
pstudiohdr = (studiohdr_t *)pmodel;
if (!pstudiohdr || pev->sequence >= pstudiohdr->numseq)
return 0;
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence;
return pseqdesc->flags;
}
float StudioFrameAdvance(client_anim_state_t *st, float framerate, float flInterval)
{
if (flInterval == 0.0)
{
flInterval = (gEngfuncs.GetClientTime() - st->animtime);
if (flInterval <= 0.001)
{
st->animtime = gEngfuncs.GetClientTime();
return 0.0;
}
}
if (!st->animtime)
flInterval = 0.0;
st->frame += flInterval * framerate * st->framerate;
st->animtime = gEngfuncs.GetClientTime();
if (st->frame < 0.0 || st->frame >= 256.0)
{
if (st->m_fSequenceLoops)
st->frame -= (int)(st->frame / 256.0) * 256.0;
else
st->frame = (st->frame < 0.0) ? 0 : 255;
st->m_fSequenceFinished = TRUE;
}
return flInterval;
}
void CGameStudioModelRenderer::SetupClientAnimation(entity_state_t *pplayer)
{
static double oldtime;
double curtime, dt;
client_anim_state_t *st;
float fr, gs;
cl_entity_t *ent = IEngineStudio.GetCurrentEntity();
if (!ent)
return;
curtime = gEngfuncs.GetClientTime();
dt = curtime - oldtime;
dt = min(1.0, max(0.0, dt));
oldtime = curtime;
st = &g_clientstate;
st->framerate = 1.0;
int oldseq = st->sequence;
CounterStrike_GetSequence(&st->sequence, &st->gaitsequence);
CounterStrike_GetOrientation((float *)&st->origin, (float *)&st->angles);
VectorCopy(st->angles, st->realangles);
if (st->sequence != oldseq)
{
st->frame = 0.0;
st->lv.prevsequence = oldseq;
st->lv.sequencetime = st->animtime;
memcpy(st->lv.prevseqblending, st->blending, 2);
memcpy(st->lv.prevcontroller, st->controller, 4);
}
void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata(ent->model);
GetSequenceInfo(pmodel, st, &fr, &gs);
st->m_fSequenceLoops = ((GetSequenceFlags(pmodel, st) & STUDIO_LOOPING) != 0);
StudioFrameAdvance(st, fr, dt);
VectorCopy(st->realangles, ent->angles);
VectorCopy(st->angles, ent->curstate.angles);
VectorCopy(st->origin, ent->curstate.origin);
ent->curstate.sequence = st->sequence;
pplayer->gaitsequence = st->gaitsequence;
ent->curstate.animtime = st->animtime;
ent->curstate.frame = st->frame;
ent->curstate.framerate = st->framerate;
memcpy(ent->curstate.blending, st->blending, 2);
memcpy(ent->curstate.controller, st->controller, 4);
ent->latched = st->lv;
}
void CGameStudioModelRenderer::RestorePlayerState(entity_state_t *pplayer)
{
client_anim_state_t *st;
cl_entity_t *ent = IEngineStudio.GetCurrentEntity();
if (!ent)
return;
st = &g_clientstate;
VectorCopy(ent->curstate.angles, st->angles);
VectorCopy(ent->curstate.origin, st->origin);
VectorCopy(ent->angles, st->realangles);
st->sequence = ent->curstate.sequence;
st->gaitsequence = pplayer->gaitsequence;
st->animtime = ent->curstate.animtime;
st->frame = ent->curstate.frame;
st->framerate = ent->curstate.framerate;
memcpy(st->blending, ent->curstate.blending, 2);
memcpy(st->controller, ent->curstate.controller, 4);
st->lv = ent->latched;
st = &g_state;
VectorCopy(st->angles, ent->curstate.angles);
VectorCopy(st->origin, ent->curstate.origin);
VectorCopy(st->realangles, ent->angles);
ent->curstate.sequence = st->sequence;
pplayer->gaitsequence = st->gaitsequence;
ent->curstate.animtime = st->animtime;
ent->curstate.frame = st->frame;
ent->curstate.framerate = st->framerate;
memcpy(ent->curstate.blending, st->blending, 2);
memcpy(ent->curstate.controller, st->controller, 4);
ent->latched = st->lv;
}
int CGameStudioModelRenderer::StudioDrawPlayer(int flags, entity_state_t *pplayer)
{
int iret = 0;
bool isLocalPlayer = false;
if (m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer())
isLocalPlayer = true;
if (isLocalPlayer)
{
SavePlayerState(pplayer);
SetupClientAnimation(pplayer);
}
iret = _StudioDrawPlayer(flags, pplayer);
if (isLocalPlayer)
RestorePlayerState(pplayer);
if( gHUD.cl_shadows->value != 0.0f )
{
Vector chestpos;
for( int i = 0; i < m_nCachedBones; i++ )
{
if( !stricmp(m_nCachedBoneNames[i], "Bip01 Spine3") )
{
chestpos.x = m_rgCachedBoneTransform[i][0][3];
chestpos.y = m_rgCachedBoneTransform[i][1][3];
chestpos.z = m_rgCachedBoneTransform[i][2][3];
StudioDrawShadow(chestpos, 20.0f);
break;
}
}
}
return iret;
}
bool WeaponHasAttachments(entity_state_t *pplayer)
{
studiohdr_t *modelheader = NULL;
model_t *pweaponmodel;
if (!pplayer)
return false;
pweaponmodel = IEngineStudio.GetModelByIndex(pplayer->weaponmodel);
modelheader = (studiohdr_t *)IEngineStudio.Mod_Extradata(pweaponmodel);
return (modelheader->numattachments != 0);
}
int CGameStudioModelRenderer::_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 (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq)
m_pCurrentEntity->curstate.sequence = 0;
if (pplayer->sequence >= m_pStudioHeader->numseq)
pplayer->sequence = 0;
if (m_pCurrentEntity->curstate.gaitsequence >= m_pStudioHeader->numseq)
m_pCurrentEntity->curstate.gaitsequence = 0;
if (pplayer->gaitsequence >= m_pStudioHeader->numseq)
pplayer->gaitsequence = 0;
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);
CalculatePitchBlend(pplayer);
CalculateYawBlend(pplayer);
m_pPlayerInfo->gaitsequence = 0;
StudioSetUpTransform(0);
}
if (flags & STUDIO_RENDER)
{
(*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 && (!(flags & STUDIO_RENDER) || !pplayer->weaponmodel || !WeaponHasAttachments(pplayer)))
{
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_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)
{
studiohdr_t *saveheader = m_pStudioHeader;
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();
if (m_pCurrentEntity->index > 0)
memcpy(saveent.attachment, m_pCurrentEntity->attachment, sizeof(vec3_t) * m_pStudioHeader->numattachments);
*m_pCurrentEntity = saveent;
m_pStudioHeader = saveheader;
IEngineStudio.StudioSetHeader(m_pStudioHeader);
if (flags & STUDIO_EVENTS)
IEngineStudio.StudioClientEvents();
}
}
return 1;
}
void CGameStudioModelRenderer::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:
{
if (iRenderStateChanged)
{
g_flStartScaleTime = m_clTime;
iRenderStateChanged = FALSE;
}
float flTimeDelta = m_clTime - g_flStartScaleTime;
if (flTimeDelta > 0)
{
float flScale = 0.001;
if (flTimeDelta <= 2.0)
flScale = 1.0 - (flTimeDelta / 2.0);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
transform[i][j] *= flScale;
}
}
break;
}
}
}
void R_StudioInit(void)
{
g_StudioRenderer.Init();
}
int R_StudioDrawPlayer(int flags, entity_state_t *pplayer)
{
return g_StudioRenderer.StudioDrawPlayer(flags, pplayer);
}
int R_StudioDrawModel(int flags)
{
return g_StudioRenderer.StudioDrawModel(flags);
}
// The simple drawing interface we'll pass back to the engine
r_studio_interface_t studio =
{
STUDIO_INTERFACE_VERSION,
R_StudioDrawModel,
R_StudioDrawPlayer,
};
#ifdef _WIN32
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT
#endif
/*
====================
HUD_GetStudioModelInterface
Export this function for the engine to use the studio renderer class to render objects.
====================
*/
extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio )
{
if ( version != STUDIO_INTERFACE_VERSION )
return 0;
// Point the engine to our callbacks
*ppinterface = &studio;
// Copy in engine helper functions
memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) );
// Initialize local variables, etc.
R_StudioInit();
// Success
return 1;
}