mirror of
https://github.com/DrBeef/JKXR.git
synced 2024-11-23 20:43:09 +00:00
19ee9179e8
Added cvar g_saberAutoDeflect1stPerson so saber is only ever used to deflect lasers in first person Made selector always draw using HMD YAW so it remains in front when turning i.r.l Updated the hand model (@baggyg) Updated the crawler text with the patron credits Added @MuadDib's menu changes Aligned all weapons Scaled the saber hilt down a little bit Co-Authored-By: Grant Bagwell <general@grantbagwell.co.uk>
627 lines
13 KiB
C++
627 lines
13 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 1999 - 2005, Id Software, Inc.
|
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
|
Copyright (C) 2005 - 2015, ioquake3 contributors
|
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
|
|
|
This file is part of the OpenJK source code.
|
|
|
|
OpenJK is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License version 2 as
|
|
published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
===========================================================================
|
|
*/
|
|
|
|
// cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
|
|
|
|
#include "../server/exe_headers.h"
|
|
|
|
#include "client.h"
|
|
#include "client_ui.h"
|
|
#include <JKVR/VrCommon.h>
|
|
|
|
extern console_t con;
|
|
|
|
qboolean scr_initialized; // ready to draw
|
|
|
|
cvar_t *cl_timegraph;
|
|
cvar_t *cl_debuggraph;
|
|
cvar_t *cl_graphheight;
|
|
cvar_t *cl_graphscale;
|
|
cvar_t *cl_graphshift;
|
|
|
|
/*
|
|
================
|
|
SCR_DrawNamedPic
|
|
|
|
Coordinates are 640*480 virtual values
|
|
=================
|
|
*/
|
|
void SCR_DrawNamedPic( float x, float y, float width, float height, const char *picname ) {
|
|
qhandle_t hShader;
|
|
|
|
assert( width != 0 );
|
|
|
|
hShader = re.RegisterShader( picname );
|
|
re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
SCR_FillRect
|
|
|
|
Coordinates are 640*480 virtual values
|
|
=================
|
|
*/
|
|
void SCR_FillRect( float x, float y, float width, float height, const float *color ) {
|
|
re.SetColor( color );
|
|
|
|
re.DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cls.whiteShader );
|
|
|
|
re.SetColor( NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
SCR_DrawPic
|
|
|
|
Coordinates are 640*480 virtual values
|
|
A width of 0 will draw with the original image width
|
|
=================
|
|
*/
|
|
void SCR_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
|
|
re.DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
|
|
}
|
|
|
|
|
|
/*
|
|
** SCR_DrawBigChar
|
|
** big chars are drawn at 640*480 virtual screen size
|
|
*/
|
|
void SCR_DrawBigChar( int x, int y, int ch ) {
|
|
int row, col;
|
|
float frow, fcol;
|
|
float size;
|
|
float ax, ay, aw, ah;
|
|
|
|
ch &= 255;
|
|
|
|
if ( ch == ' ' ) {
|
|
return;
|
|
}
|
|
|
|
if ( y < -BIGCHAR_HEIGHT ) {
|
|
return;
|
|
}
|
|
|
|
ax = x;
|
|
ay = y;
|
|
aw = BIGCHAR_WIDTH;
|
|
ah = BIGCHAR_HEIGHT;
|
|
|
|
row = ch>>4;
|
|
col = ch&15;
|
|
|
|
frow = row*0.0625;
|
|
fcol = col*0.0625;
|
|
size = 0.0625;
|
|
/*
|
|
re.DrawStretchPic( ax, ay, aw, ah,
|
|
fcol, frow,
|
|
fcol + size, frow + size,
|
|
cls.charSetShader );
|
|
*/
|
|
float size2;
|
|
|
|
frow = row*0.0625;
|
|
fcol = col*0.0625;
|
|
size = 0.03125;
|
|
size2 = 0.0625;
|
|
|
|
re.DrawStretchPic( ax, ay, aw, ah,
|
|
fcol, frow,
|
|
fcol + size, frow + size2,
|
|
cls.charSetShader );
|
|
|
|
}
|
|
|
|
/*
|
|
** SCR_DrawSmallChar
|
|
** small chars are drawn at native screen resolution
|
|
*/
|
|
void SCR_DrawSmallChar( int x, int y, int ch ) {
|
|
int row, col;
|
|
float frow, fcol;
|
|
float size;
|
|
|
|
ch &= 255;
|
|
|
|
if ( ch == ' ' ) {
|
|
return;
|
|
}
|
|
|
|
if ( y < -SMALLCHAR_HEIGHT ) {
|
|
return;
|
|
}
|
|
|
|
row = ch>>4;
|
|
col = ch&15;
|
|
/*
|
|
frow = row*0.0625;
|
|
fcol = col*0.0625;
|
|
size = 0.0625;
|
|
|
|
re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
|
|
fcol, frow,
|
|
fcol + size, frow + size,
|
|
cls.charSetShader );
|
|
*/
|
|
|
|
float size2;
|
|
|
|
frow = row*0.0625;
|
|
fcol = col*0.0625;
|
|
size = 0.03125;
|
|
size2 = 0.0625;
|
|
|
|
re.DrawStretchPic( x * con.xadjust, y * con.yadjust,
|
|
SMALLCHAR_WIDTH * con.xadjust, SMALLCHAR_HEIGHT * con.yadjust,
|
|
fcol, frow,
|
|
fcol + size, frow + size2,
|
|
cls.charSetShader );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
==================
|
|
SCR_DrawBigString[Color]
|
|
|
|
Draws a multi-colored string with a drop shadow, optionally forcing
|
|
to a fixed color.
|
|
|
|
Coordinates are at 640 by 480 virtual resolution
|
|
==================
|
|
*/
|
|
void SCR_DrawBigStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor, qboolean noColorEscape ) {
|
|
vec4_t color;
|
|
const char *s;
|
|
int xx;
|
|
|
|
// draw the drop shadow
|
|
color[0] = color[1] = color[2] = 0;
|
|
color[3] = setColor[3];
|
|
re.SetColor( color );
|
|
s = string;
|
|
xx = x;
|
|
while ( *s ) {
|
|
if ( !noColorEscape && Q_IsColorString( s ) ) {
|
|
s += 2;
|
|
continue;
|
|
}
|
|
SCR_DrawBigChar( xx+2, y+2, *s );
|
|
xx += BIGCHAR_WIDTH;
|
|
s++;
|
|
}
|
|
|
|
|
|
// draw the colored text
|
|
s = string;
|
|
xx = x;
|
|
re.SetColor( setColor );
|
|
while ( *s ) {
|
|
if ( Q_IsColorString( s ) ) {
|
|
if ( !forceColor ) {
|
|
memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
|
|
color[3] = setColor[3];
|
|
re.SetColor( color );
|
|
}
|
|
if ( !noColorEscape ) {
|
|
s += 2;
|
|
continue;
|
|
}
|
|
}
|
|
SCR_DrawBigChar( xx, y, *s );
|
|
xx += BIGCHAR_WIDTH;
|
|
s++;
|
|
}
|
|
re.SetColor( NULL );
|
|
}
|
|
|
|
|
|
void SCR_DrawBigString( int x, int y, const char *s, float alpha, qboolean noColorEscape ) {
|
|
float color[4];
|
|
|
|
color[0] = color[1] = color[2] = 1.0;
|
|
color[3] = alpha;
|
|
SCR_DrawBigStringExt( x, y, s, color, qfalse, noColorEscape );
|
|
}
|
|
|
|
void SCR_DrawBigStringColor( int x, int y, const char *s, vec4_t color, qboolean noColorEscape ) {
|
|
SCR_DrawBigStringExt( x, y, s, color, qtrue, noColorEscape );
|
|
}
|
|
|
|
/*
|
|
==================
|
|
SCR_DrawSmallString[Color]
|
|
|
|
Draws a multi-colored string with a drop shadow, optionally forcing
|
|
to a fixed color.
|
|
==================
|
|
*/
|
|
void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, qboolean forceColor,
|
|
qboolean noColorEscape ) {
|
|
vec4_t color;
|
|
const char *s;
|
|
int xx;
|
|
|
|
// draw the colored text
|
|
s = string;
|
|
xx = x;
|
|
re.SetColor( setColor );
|
|
while ( *s ) {
|
|
if ( Q_IsColorString( s ) ) {
|
|
if ( !forceColor ) {
|
|
memcpy( color, g_color_table[ColorIndex(*(s+1))], sizeof( color ) );
|
|
color[3] = setColor[3];
|
|
re.SetColor( color );
|
|
}
|
|
if ( !noColorEscape ) {
|
|
s += 2;
|
|
continue;
|
|
}
|
|
}
|
|
SCR_DrawSmallChar( xx, y, *s );
|
|
xx += SMALLCHAR_WIDTH;
|
|
s++;
|
|
}
|
|
re.SetColor( NULL );
|
|
}
|
|
|
|
/*
|
|
** SCR_Strlen -- skips color escape codes
|
|
*/
|
|
static int SCR_Strlen( const char *str ) {
|
|
const char *s = str;
|
|
int count = 0;
|
|
|
|
while ( *s ) {
|
|
if ( Q_IsColorString( s ) ) {
|
|
s += 2;
|
|
} else {
|
|
count++;
|
|
s++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
** SCR_GetBigStringWidth
|
|
*/
|
|
int SCR_GetBigStringWidth( const char *str ) {
|
|
return SCR_Strlen( str ) * BIGCHAR_WIDTH;
|
|
}
|
|
|
|
//===============================================================================
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
DEBUG GRAPH
|
|
|
|
===============================================================================
|
|
*/
|
|
typedef struct
|
|
{
|
|
float value;
|
|
int color;
|
|
} graphsamp_t;
|
|
|
|
static int current;
|
|
static graphsamp_t values[1024];
|
|
|
|
/*
|
|
==============
|
|
SCR_DebugGraph
|
|
==============
|
|
*/
|
|
void SCR_DebugGraph (float value, int color)
|
|
{
|
|
values[current&1023].value = value;
|
|
values[current&1023].color = color;
|
|
current++;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
SCR_DrawDebugGraph
|
|
==============
|
|
*/
|
|
void SCR_DrawDebugGraph (void)
|
|
{
|
|
int a, x, y, w, i, h;
|
|
float v;
|
|
|
|
//
|
|
// draw the graph
|
|
//
|
|
w = cls.glconfig.vidWidth;
|
|
x = 0;
|
|
y = cls.glconfig.vidHeight;
|
|
re.SetColor( g_color_table[0] );
|
|
re.DrawStretchPic(x, y - cl_graphheight->integer,
|
|
w, cl_graphheight->integer, 0, 0, 0, 0, 0 );
|
|
re.SetColor( NULL );
|
|
|
|
for (a=0 ; a<w ; a++)
|
|
{
|
|
i = (current-1-a+1024) & 1023;
|
|
v = values[i].value;
|
|
v = v * cl_graphscale->integer + cl_graphshift->integer;
|
|
|
|
if (v < 0)
|
|
v += cl_graphheight->integer * (1+(int)(-v / cl_graphheight->integer));
|
|
h = (int)v % cl_graphheight->integer;
|
|
re.DrawStretchPic( x+w-1-a, y - h, 1, h, 0, 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
//=============================================================================
|
|
|
|
/*
|
|
==================
|
|
SCR_Init
|
|
==================
|
|
*/
|
|
void SCR_Init( void ) {
|
|
cl_timegraph = Cvar_Get ("timegraph", "0", CVAR_CHEAT);
|
|
cl_debuggraph = Cvar_Get ("debuggraph", "0", CVAR_CHEAT);
|
|
cl_graphheight = Cvar_Get ("graphheight", "32", CVAR_CHEAT);
|
|
cl_graphscale = Cvar_Get ("graphscale", "1", CVAR_CHEAT);
|
|
cl_graphshift = Cvar_Get ("graphshift", "0", CVAR_CHEAT);
|
|
|
|
scr_initialized = qtrue;
|
|
}
|
|
|
|
|
|
//=======================================================
|
|
|
|
void UI_SetActiveMenu( const char* menuname,const char *menuID );
|
|
void _UI_Refresh( int realtime );
|
|
void UI_DrawConnect( const char *servername, const char * updateInfoString );
|
|
void SCR_AddCreditTextCrawl( void );
|
|
|
|
/*
|
|
==================
|
|
SCR_DrawScreenField
|
|
|
|
This will be called twice if rendering in stereo mode
|
|
==================
|
|
*/
|
|
|
|
void SCR_DrawScreenField( stereoFrame_t stereoFrame ) {
|
|
|
|
re.BeginFrame( stereoFrame );
|
|
|
|
qboolean uiFullscreen = _UI_IsFullscreen();
|
|
static bool drawCreditsCrawl = true;
|
|
|
|
// if the menu is going to cover the entire screen, we
|
|
// don't need to render anything under it
|
|
if ( !uiFullscreen ) {
|
|
switch( cls.state ) {
|
|
default:
|
|
Com_Error( ERR_FATAL, "SCR_DrawScreenField: bad cls.state" );
|
|
break;
|
|
case CA_CINEMATIC:
|
|
SCR_DrawCinematic();
|
|
break;
|
|
case CA_DISCONNECTED:
|
|
// force menu up
|
|
UI_SetActiveMenu( "mainMenu", NULL );
|
|
break;
|
|
case CA_CONNECTING:
|
|
case CA_CHALLENGING:
|
|
case CA_CONNECTED:
|
|
// connecting clients will only show the connection dialog
|
|
UI_DrawConnect( clc.servername, cls.updateInfoString );
|
|
break;
|
|
case CA_LOADING:
|
|
case CA_PRIMED:
|
|
// draw the game information screen and loading progress
|
|
CL_CGameRendering( stereoFrame );
|
|
break;
|
|
case CA_ACTIVE:
|
|
drawCreditsCrawl = false;
|
|
if (CL_IsRunningInGameCinematic() || CL_InGameCinematicOnStandBy())
|
|
{
|
|
SCR_DrawCinematic();
|
|
}
|
|
else
|
|
{
|
|
CL_CGameRendering( stereoFrame );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
re.ProcessDissolve();
|
|
|
|
// draw downloading progress bar
|
|
|
|
// the menu draws next
|
|
_UI_Refresh( cls.realtime );
|
|
|
|
// console draws next
|
|
Con_DrawConsole ();
|
|
|
|
// debug graph can be drawn on top of anything
|
|
if ( cl_debuggraph->integer || cl_timegraph->integer ) {
|
|
SCR_DrawDebugGraph ();
|
|
}
|
|
|
|
if ( uiFullscreen && drawCreditsCrawl)
|
|
{
|
|
SCR_AddCreditTextCrawl();
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
SCR_UpdateScreen
|
|
|
|
This is called every frame, and can also be called explicitly to flush
|
|
text to the screen.
|
|
==================
|
|
*/
|
|
void SCR_UpdateScreen( void ) {
|
|
static int recursive;
|
|
|
|
if ( !scr_initialized ) {
|
|
return; // not initialized yet
|
|
}
|
|
|
|
// load the ref / ui / cgame if needed
|
|
CL_StartHunkUsers();
|
|
|
|
if ( ++recursive > 2 ) {
|
|
Com_Error( ERR_FATAL, "SCR_UpdateScreen: recursively called" );
|
|
}
|
|
recursive = qtrue;
|
|
|
|
// If there is no VM, there are also no rendering commands issued. Stop the renderer in
|
|
// that case.
|
|
if ( cls.uiStarted )
|
|
{
|
|
//Draw twice for Quest
|
|
SCR_DrawScreenField( STEREO_LEFT );
|
|
|
|
//This won't perform the submit eye buffers
|
|
{
|
|
if (com_speeds->integer) {
|
|
re.EndFrame(&time_frontend, &time_backend);
|
|
} else {
|
|
re.EndFrame(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
JKVR_finishEyeBuffer(0);
|
|
|
|
SCR_DrawScreenField( STEREO_RIGHT );
|
|
|
|
//This will perform the submit eye buffers
|
|
if ( com_speeds->integer ) {
|
|
re.EndFrame( &time_frontend, &time_backend );
|
|
} else {
|
|
re.EndFrame( NULL, NULL );
|
|
}
|
|
|
|
JKVR_finishEyeBuffer(1);
|
|
|
|
//And we're done
|
|
re.SubmitStereoFrame();
|
|
|
|
recursive = 0;
|
|
}
|
|
|
|
recursive = 0;
|
|
}
|
|
|
|
// this stuff is only used by the savegame (SG) code for screenshots...
|
|
//
|
|
|
|
|
|
static byte bScreenData[SG_SCR_WIDTH * SG_SCR_HEIGHT * 4];
|
|
static qboolean screenDataValid = qfalse;
|
|
void SCR_UnprecacheScreenshot()
|
|
{
|
|
screenDataValid = qfalse;
|
|
}
|
|
|
|
|
|
void SCR_PrecacheScreenshot()
|
|
{
|
|
// No screenshots unless connected to single player local server...
|
|
//
|
|
// char *psInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
|
|
// int iMaxClients = atoi(Info_ValueForKey( psInfo, "sv_maxclients" ));
|
|
|
|
// (no need to check single-player status in voyager, this code base is all singleplayer)
|
|
if ( cls.state != CA_ACTIVE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!Key_GetCatcher( ))
|
|
{
|
|
// in-game...
|
|
//
|
|
// SCR_UnprecacheScreenshot();
|
|
// pbScreenData = (byte *)Z_Malloc(SG_SCR_WIDTH * SG_SCR_HEIGHT * 4);
|
|
S_ClearSoundBuffer(); // clear DMA etc because the following glReadPixels() call can take ages
|
|
re.GetScreenShot( (byte *) &bScreenData, SG_SCR_WIDTH, SG_SCR_HEIGHT);
|
|
screenDataValid = qtrue;
|
|
}
|
|
|
|
}
|
|
|
|
byte *SCR_GetScreenshot(qboolean *qValid)
|
|
{
|
|
if (!screenDataValid) {
|
|
SCR_PrecacheScreenshot();
|
|
}
|
|
if (qValid) {
|
|
*qValid = screenDataValid;
|
|
}
|
|
return (byte *)&bScreenData;
|
|
}
|
|
|
|
// called from save-game code to set the lo-res loading screen to be the one from the save file...
|
|
//
|
|
void SCR_SetScreenshot(const byte *pbData, int w, int h)
|
|
{
|
|
if (w == SG_SCR_WIDTH && h == SG_SCR_HEIGHT)
|
|
{
|
|
screenDataValid = qtrue;
|
|
memcpy(&bScreenData, pbData, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
|
|
}
|
|
else
|
|
{
|
|
screenDataValid = qfalse;
|
|
memset(&bScreenData, 0, SG_SCR_WIDTH*SG_SCR_HEIGHT*4);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef JK2_MODE
|
|
// This is just a client-side wrapper for the function RE_TempRawImage_ReadFromFile() in the renderer code...
|
|
//
|
|
|
|
byte* SCR_TempRawImage_ReadFromFile(const char *psLocalFilename, int *piWidth, int *piHeight, byte *pbReSampleBuffer, qboolean qbVertFlip)
|
|
{
|
|
return re.TempRawImage_ReadFromFile(psLocalFilename, piWidth, piHeight, pbReSampleBuffer, qbVertFlip);
|
|
}
|
|
//
|
|
// ditto (sort of)...
|
|
//
|
|
void SCR_TempRawImage_CleanUp()
|
|
{
|
|
re.TempRawImage_CleanUp();
|
|
}
|
|
#endif
|
|
|
|
|