fteqw/engine/gl/gl_screen.c

365 lines
8.2 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// screen.c -- master for refresh, status bar, console, chat, notify, etc
#include "quakedef.h"
extern qboolean gammaworks;
#ifdef GLQUAKE
#include "glquake.h"
#include "shader.h"
#include "gl_draw.h"
#include <time.h>
qboolean GLSCR_UpdateScreen (void);
extern qboolean scr_drawdialog;
extern cvar_t vid_triplebuffer;
extern cvar_t scr_fov;
extern qboolean scr_initialized;
extern float oldsbar;
extern qboolean scr_drawloading;
extern cvar_t vid_conautoscale;
extern qboolean scr_con_forcedraw;
extern qboolean depthcleared;
/*
==================
SCR_UpdateScreen
This is called every frame, and can also be called explicitly to flush
text to the screen.
WARNING: be very careful calling this from elsewhere, because the refresh
needs almost the entire 256k of stack space!
==================
*/
void SCR_DrawCursor(void);
qboolean GLSCR_UpdateScreen (void)
{
int uimenu;
qboolean nohud;
qboolean noworld;
extern cvar_t vid_srgb;
r_refdef.pxrect.maxheight = vid.pixelheight;
vid.numpages = 2 + vid_triplebuffer.value;
R2D_Font_Changed();
if (vid_srgb.modified)
{
vid_srgb.modified = false;
//vid_srgb can be changed between 0 and 1, but other values need texture reloads. do that without too much extra weirdness.
if ((vid.flags & VID_SRGB_CAPABLE) && gl_config.arb_framebuffer_srgb)
{ //srgb-capable
if (vid_srgb.ival > 1 && (vid.flags & VID_SRGBAWARE))
{ //full srgb wanted (and textures are loaded)
qglEnable(GL_FRAMEBUFFER_SRGB);
vid.flags |= VID_SRGB_FB_LINEAR;
}
else if (vid_srgb.ival==1 || (vid.flags & VID_SRGBAWARE))
{ //srgb wanted only for the framebuffer, for gamma tricks.
qglEnable(GL_FRAMEBUFFER_SRGB);
vid.flags |= VID_SRGB_FB_LINEAR;
}
else
{ //srgb not wanted...
qglDisable(GL_FRAMEBUFFER_SRGB);
vid.flags &= ~VID_SRGB_FB_LINEAR;
}
}
}
if (!scr_initialized || !con_initialized)
{
return false; // not initialized yet
}
if (scr_disabled_for_loading)
{
extern float scr_disabled_time;
if (Sys_DoubleTime() - scr_disabled_time > 60 || !Key_Dest_Has(~kdm_game))
{
//FIXME: instead of reenabling the screen, we should just draw the relevent things skipping only the game.
scr_disabled_for_loading = false;
}
else
{
// scr_drawloading = true;
SCR_DrawLoading (true);
SCR_SetUpToDrawConsole();
if (Key_Dest_Has(kdm_console))
SCR_DrawConsole(false);
// scr_drawloading = false;
if (R2D_Flush)
R2D_Flush();
VID_SwapBuffers();
return true;
}
}
Shader_DoReload();
qglDisable(GL_SCISSOR_TEST);
#ifdef VM_UI
uimenu = UI_MenuState();
#else
uimenu = 0;
#endif
#ifdef TEXTEDITOR
if (editormodal)
{
Editor_Draw();
V_UpdatePalette (false);
Media_RecordFrame();
R2D_BrightenScreen();
if (key_dest_mask & kdm_console)
Con_DrawConsole(vid.height/2, false);
else
Con_DrawConsole(0, false);
SCR_DrawCursor();
if (R2D_Flush)
R2D_Flush();
VID_SwapBuffers();
return true;
}
#endif
if (Media_ShowFilm())
{
M_Draw(0);
V_UpdatePalette (false);
R2D_BrightenScreen();
Media_RecordFrame();
if (R2D_Flush)
R2D_Flush();
GL_Set2D (false);
VID_SwapBuffers();
return true;
}
//
// do 3D refresh drawing, and then update the screen
//
SCR_SetUpToDrawConsole ();
noworld = false;
nohud = false;
if (r_clear.ival)
{
GL_ForceDepthWritable();
qglClearColor((r_clear.ival&1)?1:0, (r_clear.ival&2)?1:0, (r_clear.ival&4)?1:0, 1);
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
depthcleared = true;
}
#ifdef VM_CG
if (CG_Refresh())
nohud = true;
else
#endif
#ifdef CSQC_DAT
if (CSQC_DrawView())
nohud = true;
else
#endif
{
if (uimenu != 1)
{
if (r_worldentity.model && cls.state == ca_active)
V_RenderView ();
else
{
noworld = true;
}
}
}
GL_Set2D (false);
scr_con_forcedraw = false;
if (noworld)
{
extern char levelshotname[];
//draw the levelshot or the conback fullscreen
if (*levelshotname)
R2D_ScalePic(0, 0, vid.width, vid.height, R2D_SafeCachePic (levelshotname));
else if (scr_con_current != vid.height)
R2D_ConsoleBackground(0, vid.height, true);
else
scr_con_forcedraw = true;
nohud = true;
}
SCR_DrawTwoDimensional(uimenu, nohud);
V_UpdatePalette (false);
R2D_BrightenScreen();
Media_RecordFrame();
RSpeedShow();
if (R2D_Flush)
R2D_Flush();
{
RSpeedMark();
VID_SwapBuffers();
RSpeedEnd(RSPEED_PRESENT);
}
//gl 4.5 / GL_ARB_robustness / GL_KHR_robustness
if (qglGetGraphicsResetStatus)
{
GLenum err = qglGetGraphicsResetStatus();
switch(err)
{
case GL_NO_ERROR:
break;
case GL_GUILTY_CONTEXT_RESET: //we did it
case GL_INNOCENT_CONTEXT_RESET: //something else broke the hardware and broke our ram
case GL_UNKNOWN_CONTEXT_RESET: //whodunit
default:
Con_Printf("OpenGL reset detected\n");
Sys_Sleep(3.0);
Cmd_ExecuteString("vid_restart", RESTRICT_LOCAL);
break;
}
}
return true;
}
char *GLVID_GetRGBInfo(int *bytestride, int *truewidth, int *trueheight, enum uploadfmt *fmt)
{ //returns a BZ_Malloced array
extern qboolean gammaworks;
int i, c;
qbyte *ret;
extern qboolean r2d_canhwgamma;
*bytestride = 0;
*truewidth = vid.fbpwidth;
*trueheight = vid.fbpheight;
/*if (1)
{
float *p;
p = BZ_Malloc(vid.pixelwidth*vid.pixelheight*sizeof(float));
qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_DEPTH_COMPONENT, GL_FLOAT, p);
ret = BZ_Malloc(vid.pixelwidth*vid.pixelheight*3);
c = vid.pixelwidth*vid.pixelheight;
for (i = 1; i < c; i++)
{
ret[i*3+0]=p[i]*p[i]*p[i]*255;
ret[i*3+1]=p[i]*p[i]*p[i]*255;
ret[i*3+2]=p[i]*p[i]*p[i]*255;
}
BZ_Free(p);
}
else*/ if (gl_config.gles || (*truewidth&3))
{
qbyte *p;
//gles:
//Only two format/type parameter pairs are accepted.
//GL_RGBA/GL_UNSIGNED_BYTE is always accepted, and the other acceptable pair can be discovered by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
//thus its simpler to only use GL_RGBA/GL_UNSIGNED_BYTE
//desktopgl:
//total line byte length must be aligned to GL_PACK_ALIGNMENT. by reading rgba instead of rgb, we can ensure the line is a multiple of 4 bytes.
ret = BZ_Malloc((*truewidth)*(*trueheight)*4);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret);
*bytestride = *truewidth*-3;
*fmt = TF_RGB24;
c = (*truewidth)*(*trueheight);
p = ret;
for (i = 1; i < c; i++)
{
p[i*3+0]=p[i*4+0];
p[i*3+1]=p[i*4+1];
p[i*3+2]=p[i*4+2];
}
ret = BZ_Realloc(ret, (*truewidth)*(*trueheight)*3);
}
#if 1//def _DEBUG
else if (!gl_config.gles && sh_config.texfmt[PTI_BGRA8])
{
*fmt = TF_BGRA32;
ret = BZ_Malloc((*truewidth)*(*trueheight)*4);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, ret);
*bytestride = *truewidth*-4;
}
#endif
else
{
*fmt = TF_RGB24;
ret = BZ_Malloc((*truewidth)*(*trueheight)*3);
qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret);
*bytestride = *truewidth*-3;
}
if (gammaworks && r2d_canhwgamma)
{
if (*fmt == TF_BGRA32 || *fmt == TF_RGBA32)
{
c = (*truewidth)*(*trueheight)*4;
for (i=0 ; i<c ; i+=4)
{
extern qbyte gammatable[256];
ret[i+0] = gammatable[ret[i+0]];
ret[i+1] = gammatable[ret[i+1]];
ret[i+2] = gammatable[ret[i+2]];
}
}
else
{
c = (*truewidth)*(*trueheight)*3;
for (i=0 ; i<c ; i+=3)
{
extern qbyte gammatable[256];
ret[i+0] = gammatable[ret[i+0]];
ret[i+1] = gammatable[ret[i+1]];
ret[i+2] = gammatable[ret[i+2]];
}
}
}
return ret;
}
#endif