nuclide/src/client/view.qc

374 lines
9.9 KiB
Plaintext

/*
* Copyright (c) 2016-2022 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var bool autocvar_cg_viewmodelLag = 0;
void
View_Init(void)
{
for (int s = g_seats.length; s-- > numclientseats;) {
pSeat = &g_seats[s];
if(!pSeat->m_eViewModel) {
/* right side */
pSeat->m_eViewModel = spawn(NSRenderableEntity);
pSeat->m_eViewModel.classname = "vm";
pSeat->m_eViewModel.renderflags = RF_DEPTHHACK | RF_FIRSTPERSON;
pSeat->m_eViewModel.effects |= EF_NOSHADOW;
pSeat->m_eViewModel.alpha = 1.0f;
pSeat->m_eViewModel.drawmask = 0;
setsize(pSeat->m_eViewModel, [0,0,0], [0,0,0]);
/* left side */
pSeat->m_eViewModelL = spawn(NSRenderableEntity);
pSeat->m_eViewModelL.classname = "vm";
pSeat->m_eViewModelL.renderflags = RF_DEPTHHACK | RF_FIRSTPERSON;
pSeat->m_eViewModelL.effects |= EF_NOSHADOW;
pSeat->m_eViewModelL.alpha = 1.0f;
pSeat->m_eViewModelL.drawmask = 0;
setsize(pSeat->m_eViewModelL, [0,0,0], [0,0,0]);
}
}
}
void
View_SetMuzzleflash(int index)
{
NSRenderableEntity viewModel = (NSRenderableEntity)pSeat->m_eViewModelL;
viewModel.m_iMuzzleModel = (float)index;
viewModel = (NSRenderableEntity)pSeat->m_eViewModel;
viewModel.m_iMuzzleModel = (float)index;
}
void
View_AddEvent(void(void) pCallback, float flTime)
{
pSeat->m_pEventCall = pCallback;
pSeat->m_flEventTime = flTime;
pSeat->m_flEventFrame = pSeat->m_eViewModel.frame;
pSeat->m_flEventMdl = pSeat->m_eViewModel.modelindex;
NSClientPlayer pl = (NSClientPlayer)pSeat->m_ePlayer;
pSeat->m_iEventWeapon = pl.activeweapon;
}
void
View_ClearEvents(void)
{
pSeat->m_pEventCall = __NULL__;
pSeat->m_flEventTime = 0;
pSeat->m_flEventFrame = 0;
pSeat->m_flEventMdl = 0;
pSeat->m_iEventWeapon = 0;
pSeat->m_eViewModelL.frame1time = 0.0f;
pSeat->m_eViewModel.frame1time = 0.0f;
}
void
View_CalcViewport(int s, float fWinWidth, float fWinHeight)
{
switch (numclientseats) {
case 3:
if (!s) {
case 2:
g_viewSeats[s].SetViewSize([fWinWidth, fWinHeight * 0.5]);
g_viewSeats[s].SetViewPosition([0, (s & 1) * g_viewSeats[s].GetViewHeight()]);
break;
}
s++;
case 4:
g_viewSeats[s].SetViewSize([fWinWidth, fWinHeight] * 0.5);
g_viewSeats[s].SetViewPosition([(s&1) * g_viewSeats[s].GetViewWidth(), (s / 2i) * g_viewSeats[s].GetViewHeight()]);
break;
default:
g_viewSeats[s].SetViewSize([fWinWidth, fWinHeight]);
//g_viewSeats[s].SetViewPosition([0, 0]);
break;
}
video_res = g_viewSeats[s].m_vecSize;
video_mins = g_viewSeats[s].m_vecPosition;
g_hudmins = g_viewSeats[s].GetHUDCanvasPos();
g_hudres = g_viewSeats[s].GetHUDCanvasSize();
}
void
View_DrawViewmodel_Single(int weapon, float weapontime)
{
}
static void
View_HandleAnimEvent(float flTimeStamp, int iCode, string strData)
{
NSRenderableEntity viewModel = (NSRenderableEntity)self;
viewModel.HandleAnimEvent(flTimeStamp, iCode, strData);
}
void
View_ForceChange(player pl, int targetWeapon)
{
NSRenderableEntity m_eViewModel = (NSRenderableEntity)pSeat->m_eViewModel;
NSRenderableEntity m_eViewModelL = (NSRenderableEntity)pSeat->m_eViewModelL;
sendevent("PlayerSwitchWeapon", "i", targetWeapon);
View_ClearEvents();
View_DisableViewmodel();
View_SetMuzzleflash(0);
}
/*
====================
View_DrawViewModel
Really convoluted function that makes the gun,
muzzleflash, dynamic lights and so on appear
====================
*/
void
View_DrawViewModel(void)
{
vector currentAngle = g_view.GetCameraAngle();
NSRenderableEntity m_eViewModel = (NSRenderableEntity)pSeat->m_eViewModel;
NSRenderableEntity m_eViewModelL = (NSRenderableEntity)pSeat->m_eViewModelL;
NSClientPlayer pl = __NULL__;
NSClient cl = (NSClient)pSeat->m_ePlayer;
/* it's either us or us spectating */
if (Client_IsSpectator(cl)) {
NSClientSpectator spec = (NSClientSpectator)pSeat->m_ePlayer;
pl = (NSClientPlayer)findfloat(world, ::entnum, spec.spec_ent);
if (spec.spec_mode != SPECMODE_FIRSTPERSON)
return;
} else {
pl = (NSClientPlayer)pSeat->m_ePlayer;
}
if (!pl)
return;
if (pl.health <= 0) {
return;
}
if (pl.vehicle) {
NSVehicle veh = (NSVehicle)pl.vehicle;
if (veh.HideViewWeapon() == true)
return;
}
if (cvar("r_drawviewmodel") == 0 || autocvar_pm_thirdPerson == TRUE) {
return;
}
/* used to be View_UpdateWeapon */
/* only bother upon change */
if (pSeat->m_iLastWeapon != pl.activeweapon) {
pSeat->m_iOldWeapon = pSeat->m_iLastWeapon;
pSeat->m_iLastWeapon = pl.activeweapon;
if (pl.activeweapon) {
/* hack, we changed the wep, move this into Game_Input/PMove */
Weapons_Draw((player)pl);
} else {
pSeat->m_eViewModel.modelindex =
pSeat->m_eViewModelL.modelindex = 0;
}
NSRenderableEntity viewModel = (NSRenderableEntity)pSeat->m_eViewModelL;
viewModel._UpdateBoneCount();
viewModel = (NSRenderableEntity)pSeat->m_eViewModel;
viewModel._UpdateBoneCount();
View_EnableViewmodel();
View_ClearEvents();
}
float fBaseTime2 = m_eViewModel.frame1time;
float fBaseTime = m_eViewModel.frame1time;
m_eViewModelL.frame = m_eViewModel.frame = pl.weaponframe;
m_eViewModelL.frame1time =
m_eViewModelL.frame2time =
m_eViewModel.frame2time =
m_eViewModel.frame1time = pl.weapontime;
Event_Callback(m_eViewModel.frame1time, fBaseTime2);
entity oldSelf = self;
self = m_eViewModel;
processmodelevents(m_eViewModel.modelindex, m_eViewModel.frame, fBaseTime,
m_eViewModel.frame1time, View_HandleAnimEvent);
self = oldSelf;
makevectors(currentAngle);
if (autocvar_cg_viewmodelLag == 0)
m_eViewModel.angles = currentAngle;
else {
float limit;
float speed;
makevectors(pSeat->m_vecLag);
pSeat->m_vecLag = v_forward;
makevectors(view_angles);
if (autocvar_cg_viewmodelLag == 2) {
float pitchfix = fabs(view_angles[0] / 180);
limit = dotproduct(pSeat->m_vecLag, v_forward) * (1.0 - pitchfix);
speed = (1.0 - limit) * clframetime;
speed *= 90;
} else {
speed = clframetime * 20;
}
pSeat->m_vecLag[0] = Math_Lerp(pSeat->m_vecLag[0], v_forward[0], speed);
pSeat->m_vecLag[1] = Math_Lerp(pSeat->m_vecLag[1], v_forward[1], speed);
pSeat->m_vecLag[2] = Math_Lerp(pSeat->m_vecLag[2], v_forward[2], speed);
pSeat->m_vecLag = vectoangles(pSeat->m_vecLag);
m_eViewModel.angles = pSeat->m_vecLag;
}
/* apply to the left side */
m_eViewModelL.angles = m_eViewModel.angles;
m_eViewModelL.colormap = m_eViewModel.colormap = pSeat->m_ePlayer.colormap;
/* now apply the scale hack */
m_eViewModelL.scale = m_eViewModel.scale = autocvar_cg_viewmodelScale;
if (Client_IsSpectator(cl) || XR_Available(cl) == false) {
m_eViewModelL.origin = g_view.GetCameraOrigin();
m_eViewModel.origin = g_view.GetCameraOrigin();
if (Client_IsSpectator(cl)) {
m_eViewModel.angles = currentAngle;
m_eViewModelL.angles = currentAngle;
/* HACK: fool Viewmodel_CalcBob(); */
pSeat->m_vecPredictedVelocity = pl.velocity;
}
/* we only calculate bob on the right model, to avoid double speed bobbing */
Viewmodel_CalcBob();
makevectors(currentAngle);
Viewmodel_ApplyBob(m_eViewModel);
Viewmodel_ApplyBob(m_eViewModelL);
} else {
m_eViewModelL.origin = pl.m_xrInputLeft.GetOrigin();
m_eViewModel.origin = pl.m_xrInputRight.GetOrigin();
m_eViewModel.angles = pl.m_xrInputRight.GetAngles();
m_eViewModelL.angles = pl.m_xrInputLeft.GetAngles();
}
/* this is currently broken */
#if 0
// Left-handed weapons
if (autocvar_cg_viewmodelFlip) {
v_right *= -1;
m_eViewModel.renderflags |= RF_USEAXIS;
//m_eViewModel.forceshader = SHADER_CULLED;
} else {
if (m_eViewModel.forceshader) {
m_eViewModel.forceshader = 0;
m_eViewModel.renderflags &= ~RF_USEAXIS;
}
}
#endif
/* only draw the model when it's 'enabled'... */
if (m_eViewModel.alpha != 0.0f) {
setorigin(m_eViewModel, m_eViewModel.origin);
setorigin(m_eViewModelL, m_eViewModel.origin);
m_eViewModel.SetRenderMode(pl.GetRenderMode());
m_eViewModel.SetRenderFX(pl.GetRenderFX());
m_eViewModel.SetRenderColor(pl.GetRenderColor());
m_eViewModel.SetRenderAmt(pl.GetRenderAmt());
m_eViewModelL.SetRenderMode(pl.GetRenderMode());
m_eViewModelL.SetRenderFX(pl.GetRenderFX());
m_eViewModelL.SetRenderColor(pl.GetRenderColor());
m_eViewModelL.SetRenderAmt(pl.GetRenderAmt());
m_eViewModel.RenderFXPass();
m_eViewModelL.RenderFXPass();
m_eViewModelL.renderflags = RF_DEPTHHACK | RF_FIRSTPERSON;
m_eViewModel.renderflags = RF_DEPTHHACK | RF_FIRSTPERSON;
if (m_eViewModel.GetRenderMode() != RM_DONTRENDER)
addentity(m_eViewModel);
if (m_eViewModelL.GetRenderMode() != RM_DONTRENDER)
addentity(m_eViewModelL);
}
}
void
View_PreDraw(void)
{
ClientGame_PreDraw();
}
void
View_PostDraw(void)
{
ClientGame_PostDraw();
}
/*
====================
View_PlayAnimation
Resets the timeline and plays a new sequence
onto the view model
====================
*/
void
View_PlayAnimation(int iSequence)
{
pSeat->m_eViewModel.frame =
pSeat->m_eViewModelL.frame = (float)iSequence;
}
void
View_PlayAnimationLeft(int iSequence)
{
pSeat->m_eViewModelL.frame = (float)iSequence;
}
void
View_PlayAnimationRight(int iSequence)
{
pSeat->m_eViewModel.frame = (float)iSequence;
}
int
View_GetAnimation(void)
{
return pSeat->m_eViewModel.frame;
}
void
View_EnableViewmodel(void)
{
pSeat->m_eViewModel.alpha =
pSeat->m_eViewModelL.alpha = 1.0f;
}
void
View_DisableViewmodel(void)
{
pSeat->m_eViewModel.alpha =
pSeat->m_eViewModelL.alpha = 0.0f;
pSeat->m_eViewModel.frame1time =
pSeat->m_eViewModelL.frame1time = 0.0f;
}