jkxr/Projects/Android/jni/OpenJK/code/client/cl_scrn.cpp
Simon 19ee9179e8 Many improvements
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>
2022-10-13 23:19:44 +01:00

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