NSView: Take over some duties

This commit is contained in:
Marco Cawthorne 2022-07-28 15:53:27 -07:00
parent 9183958893
commit baab5c931c
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
11 changed files with 355 additions and 238 deletions

View File

@ -32,7 +32,7 @@ BUILD_IQMTOOL=1
BUILD_IMGTOOL=1
# Specify which engine revision to build, these are considered 'stable'; 0 = latest
BUILD_ENGINEREVISION=6283
BUILD_ENGINEREVISION=6301
# Whether or not to run 'git pull' or 'svn up' before building a component
BUILD_UPDATE=1

View File

@ -6,6 +6,14 @@
is done in the NSView.
*/
typedef enum
{
VIEWMODE_NORMAL, /* just a regular camera with no special logic */
VIEWMODE_FPS, /* uses view target position + view offset */
VIEWMODE_THIRDPERSON, /* third person view, fixed */
VIEWMODE_SPECTATING /* spectating, mixed viewmodes inside */
} viewmode_e;
class
NSView
{
@ -15,6 +23,7 @@ NSView
vector m_vecPosition;
vector m_vecSize;
float m_flFieldOfView;
viewmode_e m_viewmode;
/* the entity we're targetting */
NSEntity m_viewTarget;
@ -26,6 +35,13 @@ NSView
virtual void(void) SetupView;
virtual void(void) RenderView;
virtual void(viewmode_e) SetViewMode;
virtual viewmode_e(void) GetViewMode;
virtual void(void) UpdateView;
virtual void(void) Render2D;
virtual void(vector) SetViewPosition;
virtual void(vector) SetViewSize;
virtual void(NSEntity) SetViewTarget;
@ -35,6 +51,15 @@ NSView
virtual void(vector) SetCameraAngle;
virtual void(int) SetSeatID;
virtual void(float) SetAFOV;
virtual vector(void) GetHUDCanvasSize;
virtual vector(void) GetHUDCanvasPos;
virtual float(void) GetViewWidth;
virtual float(void) GetViewHeight;
virtual vector(void) GetCameraOrigin;
virtual vector(void) GetCameraAngle;
};
NSView g_viewSeats[4];

View File

@ -4,13 +4,13 @@ NSView::SetupView(void)
setproperty(VF_DRAWENGINESBAR, 0);
setproperty(VF_DRAWCROSSHAIR, 0);
setproperty(VF_DRAWWORLD, 1);
setproperty(VF_ACTIVESEAT, m_iSeat);
setproperty(VF_ACTIVESEAT, (float)m_iSeat);
setproperty(VF_MIN, m_vecPosition);
setproperty(VF_SIZE, m_vecSize);
setproperty(VF_AFOV, m_flFieldOfView);
/* this will hide said entity */
setproperty(VF_VIEWENTITY, num_for_edict(m_viewTarget));
setproperty(VF_VIEWENTITY, player_localentnum);
setproperty(VF_ORIGIN, origin);
//setproperty(VF_CL_VIEWANGLES, angles);
@ -53,6 +53,30 @@ NSView::SetCameraAngle(vector new_angle)
angles = new_angle;
}
vector
NSView::GetCameraOrigin(void)
{
return origin;
}
vector
NSView::GetCameraAngle(void)
{
return angles;
}
void
NSView::SetViewMode(viewmode_e new_mode)
{
m_viewmode = new_mode;
}
viewmode_e
NSView::GetViewMode(void)
{
return m_viewmode;
}
void
NSView::SetSeatID(int new_id)
{
@ -71,6 +95,188 @@ NSView::SetAFOV(float new_fov)
m_flFieldOfView = new_fov;
}
vector
NSView::GetHUDCanvasPos(void)
{
if (autocvar_cl_hudaspect <= 0) {
return m_vecPosition;
} else {
return [m_vecPosition[0] + ((m_vecSize[0] / 2) - ((m_vecSize[1] * autocvar_cl_hudaspect) / 2)), m_vecPosition[1]];
}
}
vector
NSView::GetHUDCanvasSize(void)
{
if (autocvar_cl_hudaspect <= 0) {
return m_vecSize;
} else {
return [m_vecSize[1] * autocvar_cl_hudaspect, m_vecSize[1]];
}
}
float
NSView::GetViewWidth(void)
{
return m_vecSize[0];
}
float
NSView::GetViewHeight(void)
{
return m_vecSize[1];
}
void View_PreDraw();
void View_PostDraw();
void View_DrawViewModel();
void Chat_Draw();
void Print_Draw();
void GameText_Draw();
void Voice_DrawHUD();
void Print_DrawCenterprint();
int VGUI_Draw();
void
NSView::Render2D(void)
{
Fade_Update(m_vecPosition[0], m_vecPosition[1], m_vecSize[0], m_vecSize[1]);
}
void
NSView::UpdateView(void)
{
player pl = (player)m_viewTarget;
NSClient cl = (NSClient)m_viewTarget;
NSClientSpectator spec = (NSClientSpectator)m_viewTarget;
entity c;
if (!cl)
return;
/* run preframe code on our viewtarge */
cl.PreFrame();
/* some mods use this */
View_PreDraw();
/* put entities into the scene (and call their predraws */
addentities(MASK_ENGINE);
/* after predraws we can act upon their new positions */
switch (GetViewMode()) {
case VIEWMODE_FPS:
cl.UpdateAliveCam();
if (Client_InIntermission()) {
cl.UpdateIntermissionCam();
}
pSeat->m_vecPredictedOrigin = cl.GetEyePos();
SetCameraOrigin(cl.GetEyePos());
SetCameraAngle(view_angles);
if (Client_IsDead(pl))
pl.UpdateDeathcam();
else
View_DrawViewModel();
break;
case VIEWMODE_THIRDPERSON:
break;
case VIEWMODE_SPECTATING:
spec = (NSClientSpectator)m_viewTarget;
switch (spec.spec_mode) {
case SPECMODE_THIRDPERSON:
makevectors(view_angles);
vector vecStart = spec.GetEyePos();
vecStart[2] += 16;
vecStart += (v_right * 4);
vector vecEnd = vecStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vecStart, vecEnd, FALSE, m_viewTarget);
SetCameraOrigin(trace_endpos + (v_forward * 5));
SetCameraAngle(view_angles);
break;
case SPECMODE_FIRSTPERSON:
c = findfloat(world, ::entnum, spec.spec_ent);
if (c.classname == "player") {
player bp = (player)c;
removeentity(c);
SetCameraOrigin(bp.GetEyePos());
SetCameraAngle(bp.v_angle);
}
break;
default:
SetCameraOrigin(cl.GetEyePos());
}
/* 0 means world */
if (spec.spec_ent) {
c = findfloat(world, ::entnum, spec.spec_ent);
/* we found them */
if (c && c != spec) {
player ps = (player)c;
if (ps.health <= 0)
pl.UpdateDeathcam();
else
View_DrawViewModel();
}
}
break;
default:
break;
}
if (pSeat->m_flCameraTime > time || pSeat->m_flCameraTime == -1) {
} else {
}
addentities(MASK_GLOWS);
//setproperty(VF_DRAWWORLD, 1);
SkyCamera_Setup(getproperty(VF_ORIGIN));
XR_UpdateView(m_viewTarget);
/* this is running whenever we're doing 'buildcubemaps' */
if (g_iCubeProcess == TRUE) {
//setproperty(VF_ORIGIN, g_vecCubePos);
//setproperty(VF_SIZE_X, g_dCubeSize);
//setproperty(VF_SIZE_Y, g_dCubeSize);
//setproperty(VF_AFOV, 90);
}
/* render the scene, then put monitor RenderTargets on top */
SetupView();
RenderView();
RenderTarget_Monitor_Update();
if (g_iCubeProcess == TRUE) {
cl.PostFrame();
return;
}
/* all 2D operations happen after this point */
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
NSEntity pf = (NSEntity) b;
pf.postdraw();
}
Render2D();
View_PostDraw();
/* move this into NSClient methods */
cl.PostFrame();
}
void
NSView::NSView(void)
{

View File

@ -21,6 +21,7 @@
#include "fade.h"
#include "cmd.h"
#include "util.h"
#include "NSView.h"
/* undocumented printcall types */
#define PRINT_LOW 0
@ -29,6 +30,11 @@
#define PRINT_CHAT 3
const float MASK_GLOWS = 16;
var bool g_focus;
bool Util_IsFocused(void);
var int g_numplayerslots;
int Util_GetMaxPlayers(void);
/* fonts */
font_s FONT_16;

View File

@ -29,6 +29,7 @@ CSQC_UpdateSeat(void)
int s = (float)getproperty(VF_ACTIVESEAT);
pSeat = &g_seats[s];
pSeatLocal = &g_seatslocal[s];
g_view = g_viewSeats[s];
}
/*
@ -43,8 +44,16 @@ CSQC_Init(float apilevel, string enginename, float engineversion)
{
print("--------- Initializing Client Game ----------\n");
for (int i = 0; i < 4; i++) {
g_viewSeats[i] = spawn(NSView);
//g_viewSeats[i].SetSeatID(i+1);
}
pSeat = &g_seats[0];
pSeatLocal = &g_seatslocal[0];
g_view = g_viewSeats[0];
g_numplayerslots = (int)serverkeyfloat("sv_playerslots");
Cmd_Init();
@ -141,6 +150,39 @@ CSQC_RenderScene(void)
renderscene(); /* render it twice, for the normal window */
}
void
CSQC_Update2D(float w, float h, bool focus)
{
NSClientPlayer cl = (NSClientPlayer)pSeat->m_ePlayer;
if (Util_GetMaxPlayers() > 1 && !VGUI_Active() && (Client_InIntermission() || (!cl.IsFakeSpectator() && cl.IsDead()))) {
Scores_Draw();
Chat_Draw();
Print_Draw();
} else if (Util_IsFocused() == true) {
GameText_Draw();
PointMessage_Draw();
if (Client_IsSpectator(cl) == false) {
HUD_Draw();
} else {
HUD_DrawSpectator();
}
Voice_DrawHUD();
Chat_Draw();
Print_Draw();
/* no prints overlapping scoreboards */
if (pSeat->m_iScoresVisible == TRUE) {
Scores_Draw();
} else {
VGUI_Draw();
Print_DrawCenterprint();
}
}
}
/*
=================
CSQC_UpdateView
@ -151,11 +193,10 @@ Run every single frame we're connected to a session.
void
CSQC_UpdateView(float w, float h, float focus)
{
player pl = __NULL__;
NSClient cl = __NULL__;
NSClientSpectator spec;
int s;
entity c;
g_focus = (bool)focus;
if (w == 0 || h == 0) {
return;
@ -178,264 +219,56 @@ CSQC_UpdateView(float w, float h, float focus)
VGUI_Reposition();
}
/* these have to be checked every frame */
Fog_Update();
Sky_Update(FALSE);
cvar_set("_background", serverkey("background"));
if (serverkeyfloat("background") == 1) {
/* ensure background maps do not get paused */
if (serverkeyfloat("background") == 1)
setpause(FALSE);
}
/* prepare rendering our views... */
clearscene();
setproperty(VF_DRAWENGINESBAR, 0);
setproperty(VF_DRAWCROSSHAIR, 0);
//just in case...
/* bounds sanity check */
if (numclientseats > g_seats.length) {
numclientseats = g_seats.length;
}
/* null our globals */
for (s = g_seats.length; s-- > numclientseats;) {
pSeat = &g_seats[s];
pSeatLocal = &g_seatslocal[s];
g_view = g_viewSeats[0];
pSeat->m_ePlayer = world;
}
/* now render each player seat */
for (s = numclientseats; s-- > 0;) {
pSeat = &g_seats[s];
pSeatLocal = &g_seatslocal[s];
g_view = g_viewSeats[s];
pSeat->m_ePlayer = findfloat(world, ::entnum, player_localentnum);
cl = (NSClient)pSeat->m_ePlayer;
/* set up our single/split viewport */
View_CalcViewport(s, w, h);
setproperty(VF_ACTIVESEAT, (float)s);
setproperty(VF_MIN, video_mins);
setproperty(VF_SIZE, video_res);
pSeat->m_ePlayer = self = findfloat(world, entnum, player_localentnum);
pl = (player)self;
cl = (NSClient)self;
/* our view target ourselves, if we're alive... */
g_view.SetViewTarget((NSEntity)pSeat->m_ePlayer);
/* player slot not present */
if (!self) {
continue;
}
if (Client_IsSpectator(cl))
g_view.SetViewMode(VIEWMODE_SPECTATING);
else
g_view.SetViewMode(VIEWMODE_FPS);
/* this needs to be moved into a NSClient method */
#if 1
cl.PreFrame();
g_view.UpdateView();
if (!Client_IsSpectator(pl)) {
pSeat->m_vecPredictedOrigin = pl.origin;
pSeat->m_vecPredictedVelocity = pl.velocity;
pSeat->m_flPredictedFlags = pl.flags;
/* Don't hide the player entity */
if (autocvar_cl_thirdperson == TRUE && pl.health) {
setproperty(VF_VIEWENTITY, (float)0);
} else {
setproperty(VF_VIEWENTITY, (float)player_localentnum);
}
float oldzoom = pl.viewzoom;
if (pl.viewzoom == 1.0f) {
pl.viewzoom = 1.0 - (0.5 * pSeat->m_flZoomTime);
/* +zoomin requested by Slacer */
if (pSeat->m_iZoomed) {
pSeat->m_flZoomTime += clframetime * 15;
} else {
pSeat->m_flZoomTime -= clframetime * 15;
}
pSeat->m_flZoomTime = bound(0, pSeat->m_flZoomTime, 1);
}
setproperty(VF_AFOV, cvar("fov") * pl.viewzoom);
if (autocvar_zoom_sensitivity && pl.viewzoom < 1.0f) {
setsensitivityscaler(pl.viewzoom * autocvar_zoom_sensitivity);
} else {
setsensitivityscaler(pl.viewzoom);
}
if (pl.viewzoom <= 0.0f) {
setsensitivityscaler(1.0f);
}
pl.viewzoom = oldzoom;
} else if (Client_IsSpectator(pl)) {
spec = (NSClientSpectator)self;
if (spec.spec_mode == SPECMODE_FIRSTPERSON || spec.spec_mode == SPECMODE_THIRDPERSON) {
NSClientPlayer spec_target;
c = findfloat(world, ::entnum, spec.spec_ent);
spec_target = (NSClientPlayer)c;
pSeat->m_vecPredictedOrigin = c.origin;
pSeat->m_vecPredictedVelocity = c.velocity;
pSeat->m_flPredictedFlags = c.flags;
if (spec.spec_mode == SPECMODE_FIRSTPERSON)
setproperty(VF_AFOV, cvar("fov") * spec_target.viewzoom);
else
setproperty(VF_AFOV, cvar("fov"));
} else {
pSeat->m_vecPredictedOrigin = spec.origin;
pSeat->m_vecPredictedVelocity = spec.velocity;
pSeat->m_flPredictedFlags = spec.flags;
}
}
View_PreDraw();
#endif
addentities(MASK_ENGINE);
/* ideally move this into a NSClientPlayer method */
#if 1
if (pSeat->m_flCameraTime > time || pSeat->m_flCameraTime == -1) {
view_angles = pSeat->m_vecCameraAngle;
setproperty(VF_ORIGIN, pSeat->m_vecCameraOrigin);
setproperty(VF_CL_VIEWANGLES, view_angles);
setproperty(VF_ANGLES, view_angles);
} else {
/* we're not spectating at all */
if (!Client_IsSpectator(pl)) {
cl.UpdateAliveCam();
} else if (Client_IsSpectator(pl)) {
spec = (NSClientSpectator)self;
switch (spec.spec_mode) {
case SPECMODE_THIRDPERSON:
makevectors(view_angles);
vector vecStart;
vecStart[0] = pSeat->m_vecPredictedOrigin[0];
vecStart[1] = pSeat->m_vecPredictedOrigin[1];
vecStart[2] = pSeat->m_vecPredictedOrigin[2] + 16;
vecStart += (v_right * 4);
vector vecEnd = vecStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vecStart, vecEnd, FALSE, self);
setproperty(VF_ORIGIN, trace_endpos + (v_forward * 5));
break;
case SPECMODE_FIRSTPERSON:
c = findfloat(world, ::entnum, spec.spec_ent);
if (c.classname == "player") {
player bp = (player)c;
removeentity(c);
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin + bp.view_ofs);
setproperty(VF_ANGLES, bp.v_angle);
setproperty(VF_CL_VIEWANGLES, bp.v_angle);
}
break;
default:
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin);
}
}
if (Client_InIntermission()) {
cl.UpdateIntermissionCam();
}
}
#endif
addentities(MASK_GLOWS);
setproperty(VF_DRAWWORLD, 1);
SkyCamera_Setup(getproperty(VF_ORIGIN));
XR_UpdateView(self);
/* draw the viewmodel in a second pass if desired */
if (autocvar_r_viewmodelpass && pl.health > 0) {
CSQC_RenderScene();
clearscene();
setproperty(VF_MIN, video_mins);
setproperty(VF_SIZE, video_res);
setproperty(VF_ANGLES, view_angles + pl.punchangle);
setproperty(VF_DRAWWORLD, 0);
setproperty(VF_AFOV, autocvar_r_viewmodelfov);
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin + pl.view_ofs);
View_DrawViewModel();
} else {
if (Client_IsSpectator(pl)) {
spec = (NSClientSpectator)self;
/* 0 means world */
if (spec.spec_ent) {
c = findfloat(world, ::entnum, spec.spec_ent);
/* we found them */
if (c && c != spec) {
player ps = (player)c;
if (ps.health <= 0)
pl.UpdateDeathcam();
else
View_DrawViewModel();
}
}
} else if (Client_IsDead(pl)) {
pl.UpdateDeathcam();
} else {
View_DrawViewModel();
}
}
/* this is running whenever we're doing 'buildcubemaps' */
if (g_iCubeProcess == TRUE) {
setproperty(VF_ORIGIN, g_vecCubePos);
setproperty(VF_SIZE_X, g_dCubeSize);
setproperty(VF_SIZE_Y, g_dCubeSize);
setproperty(VF_AFOV, 90);
}
/* render the scene, then put monitor RenderTargets on top */
CSQC_RenderScene();
RenderTarget_Monitor_Update();
if (g_iCubeProcess == TRUE) {
cl.PostFrame();
continue;
}
/* all 2D operations happen after this point */
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
NSEntity pf = (NSEntity) b;
pf.postdraw();
}
Fade_Update((int)video_mins[0],(int)video_mins[1], (int)w, (int)h);
View_PostDraw();
int players = (int)serverkeyfloat("sv_playerslots");
if (players > 1 && !VGUI_Active() && (Client_InIntermission() || (!cl.IsFakeSpectator() && cl.IsDead()))) {
Scores_Draw();
Chat_Draw();
Print_Draw();
} else if (focus == TRUE) {
GameText_Draw();
PointMessage_Draw();
if (Client_IsSpectator(cl) == false) {
HUD_Draw();
} else {
HUD_DrawSpectator();
}
Voice_DrawHUD();
Chat_Draw();
Print_Draw();
/* no prints overlapping scoreboards */
if (pSeat->m_iScoresVisible == TRUE) {
Scores_Draw();
} else {
VGUI_Draw();
Print_DrawCenterprint();
}
}
/* move this into NSClient methods */
#if 1
cl.PostFrame();
#endif
/* 2D calls happen here, after rendering is done */
CSQC_Update2D(w, h, focus);
}
/* this sucks and doesn't take seats into account */

View File

@ -1,5 +1,6 @@
#includelist
NSInteractiveSurface.qc
NSView.qc
fog.qc
font.qc
sky.qc

View File

@ -75,3 +75,15 @@ Util_GetKeyString(string strBind)
return strtoupper(strBindTx);
}
bool
Util_IsFocused(void)
{
return g_focus;
}
int
Util_GetMaxPlayers(void)
{
return g_numplayerslots;
}

View File

@ -74,6 +74,7 @@ View_AddEvent(void(void) pCallback, float flTime)
void
View_CalcViewport(int s, float fWinWidth, float fWinHeight)
{
#if 0
//FIXME: this is awkward. renderscene internally rounds to pixels.
//on the other hand, drawpic uses linear filtering and multisample and stuff.
//this means that there can be a pixel or so difference between scene and 2d.
@ -107,6 +108,31 @@ View_CalcViewport(int s, float fWinWidth, float fWinHeight)
g_hudres[0] = video_res[1] * autocvar_cl_hudaspect;
g_hudres[1] = video_res[1];
}
#else
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();
#endif
}
void
@ -136,13 +162,13 @@ View_DrawViewModel(void)
/* it's either us or us spectating */
if (Client_IsSpectator(cl)) {
NSClientSpectator spec = (NSClientSpectator)self;
NSClientSpectator spec = (NSClientSpectator)pSeat->m_ePlayer;
pl = (player)findfloat(world, ::entnum, spec.spec_ent);
if (spec.spec_mode != SPECMODE_FIRSTPERSON)
return;
} else {
pl = (player)self;
pl = (player)pSeat->m_ePlayer;
}
if (!pl)
@ -164,7 +190,6 @@ View_DrawViewModel(void)
}
View_UpdateWeapon(pl, m_eViewModel, m_eMuzzleflash);
float fBaseTime2 = m_eViewModel.frame1time;
float fBaseTime = m_eViewModel.frame1time;
m_eViewModelL.frame = m_eViewModel.frame = pl.weaponframe;

View File

@ -104,6 +104,9 @@ class NSSurfacePropEntity:NSRenderableEntity
nonvirtual void(void) SurfaceDataFinish;
nonvirtual void(void) PropDataFinish;
#endif
/* misc 'being' methods */
virtual vector(void) GetEyePos;
};
#ifdef CLIENT

View File

@ -14,6 +14,12 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
vector
NSSurfacePropEntity::GetEyePos(void)
{
return origin + view_ofs;
}
void
NSSurfacePropEntity::Spawned(void)
{

View File

@ -75,7 +75,7 @@ XR_UpdateView(entity ePlayer)
setviewprop(VF_ANGLES, pl.m_xrInputHead.GetAngles());
setviewprop(VF_ORIGIN, pl.m_xrInputHead.GetOrigin() + [0,0,autocvar_xr_viewheight]);
} else {
pl.m_xrSpace.SetOrigin(pSeat->m_vecPredictedOrigin + pSeat->m_ePlayer.view_ofs);
pl.m_xrSpace.SetOrigin(g_view.GetCameraOrigin());
pl.m_xrSpace.SetAngles(input_angles);
/*