2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2019-11-11 19:07:33 +00:00
Copyright ( C ) 2013 - 2019 Robert Beckebans
2017-09-10 11:43:28 +00:00
Copyright ( C ) 2016 - 2017 Dustin Land
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
2017-09-03 08:22:36 +00:00
# include "../RenderCommon.h"
2017-09-03 21:17:44 +00:00
# include "../RenderBackend.h"
2012-11-26 18:58:24 +00:00
# include "../../framework/Common_local.h"
idCVar r_drawFlickerBox ( " r_drawFlickerBox " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " visual test for dropping frames " ) ;
idCVar stereoRender_warp ( " stereoRender_warp " , " 0 " , CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL , " use the optical warping renderprog instead of stereoDeGhost " ) ;
idCVar stereoRender_warpStrength ( " stereoRender_warpStrength " , " 1.45 " , CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT , " amount of pre-distortion " ) ;
idCVar stereoRender_warpCenterX ( " stereoRender_warpCenterX " , " 0.5 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " center for left eye, right eye will be 1.0 - this " ) ;
idCVar stereoRender_warpCenterY ( " stereoRender_warpCenterY " , " 0.5 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " center for both eyes " ) ;
idCVar stereoRender_warpParmZ ( " stereoRender_warpParmZ " , " 0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " development parm " ) ;
idCVar stereoRender_warpParmW ( " stereoRender_warpParmW " , " 0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " development parm " ) ;
idCVar stereoRender_warpTargetFraction ( " stereoRender_warpTargetFraction " , " 1.0 " , CVAR_RENDERER | CVAR_FLOAT | CVAR_ARCHIVE , " fraction of half-width the through-lens view covers " ) ;
2012-11-28 15:47:07 +00:00
idCVar r_showSwapBuffers ( " r_showSwapBuffers " , " 0 " , CVAR_BOOL , " Show timings from GL_BlockingSwapBuffers " ) ;
idCVar r_syncEveryFrame ( " r_syncEveryFrame " , " 1 " , CVAR_BOOL , " Don't let the GPU buffer execution past swapbuffers " ) ;
2012-11-26 18:58:24 +00:00
static int swapIndex ; // 0 or 1 into renderSync
static GLsync renderSync [ 2 ] ;
void GLimp_SwapBuffers ( ) ;
2012-11-28 15:47:07 +00:00
void RB_SetMVP ( const idRenderMatrix & mvp ) ;
2012-11-26 18:58:24 +00:00
2017-09-10 11:32:44 +00:00
glContext_t glcontext ;
2017-09-03 21:17:44 +00:00
2017-09-10 11:32:44 +00:00
/*
= = = = = = = = = = = = = = = = = =
GL_CheckErrors
= = = = = = = = = = = = = = = = = =
*/
// RB: added filename, line parms
bool GL_CheckErrors_ ( const char * filename , int line )
{
int err ;
char s [ 64 ] ;
int i ;
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
if ( r_ignoreGLErrors . GetBool ( ) )
{
return false ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
// check for up to 10 errors pending
bool error = false ;
for ( i = 0 ; i < 10 ; i + + )
{
err = glGetError ( ) ;
if ( err = = GL_NO_ERROR )
{
break ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
error = true ;
switch ( err )
{
case GL_INVALID_ENUM :
strcpy ( s , " GL_INVALID_ENUM " ) ;
break ;
case GL_INVALID_VALUE :
strcpy ( s , " GL_INVALID_VALUE " ) ;
break ;
case GL_INVALID_OPERATION :
strcpy ( s , " GL_INVALID_OPERATION " ) ;
break ;
# if !defined(USE_GLES2) && !defined(USE_GLES3)
case GL_STACK_OVERFLOW :
strcpy ( s , " GL_STACK_OVERFLOW " ) ;
break ;
case GL_STACK_UNDERFLOW :
strcpy ( s , " GL_STACK_UNDERFLOW " ) ;
break ;
# endif
case GL_OUT_OF_MEMORY :
strcpy ( s , " GL_OUT_OF_MEMORY " ) ;
break ;
default :
idStr : : snPrintf ( s , sizeof ( s ) , " %i " , err ) ;
break ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
common - > Printf ( " caught OpenGL error: %s in file %s line %i \n " , s , filename , line ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
return error ;
}
2018-10-03 20:05:30 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
DebugCallback
For ARB_debug_output
= = = = = = = = = = = = = = = = = = = = = = = =
*/
// RB: added const to userParam
static void CALLBACK DebugCallback ( unsigned int source , unsigned int type ,
unsigned int id , unsigned int severity , int length , const char * message , const void * userParam )
{
// it probably isn't safe to do an idLib::Printf at this point
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// RB: printf should be thread safe on Linux
# if defined(_WIN32)
OutputDebugString ( message ) ;
OutputDebugString ( " \n " ) ;
# else
printf ( " %s \n " , message ) ;
# endif
// RB end
}
/*
= = = = = = = = = = = = = = = = = =
R_CheckPortableExtensions
= = = = = = = = = = = = = = = = = =
*/
// RB: replaced QGL with GLEW
static void R_CheckPortableExtensions ( )
{
glConfig . glVersion = atof ( glConfig . version_string ) ;
const char * badVideoCard = idLocalization : : GetString ( " #str_06780 " ) ;
if ( glConfig . glVersion < 2.0f )
{
idLib : : FatalError ( " %s " , badVideoCard ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
if ( idStr : : Icmpn ( glConfig . renderer_string , " ATI " , 4 ) = = 0 | | idStr : : Icmpn ( glConfig . renderer_string , " AMD " , 4 ) = = 0 )
{
glConfig . vendor = VENDOR_AMD ;
}
else if ( idStr : : Icmpn ( glConfig . renderer_string , " NVIDIA " , 6 ) = = 0 )
{
glConfig . vendor = VENDOR_NVIDIA ;
}
else if ( idStr : : Icmpn ( glConfig . renderer_string , " Intel " , 5 ) = = 0 )
{
glConfig . vendor = VENDOR_INTEL ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// RB: Mesa support
if ( idStr : : Icmpn ( glConfig . renderer_string , " Mesa " , 4 ) = = 0 | | idStr : : Icmpn ( glConfig . renderer_string , " X.org " , 5 ) = = 0 | | idStr : : Icmpn ( glConfig . renderer_string , " Gallium " , 7 ) = = 0 | |
strcmp ( glConfig . vendor_string , " X.Org " ) = = 0 | |
idStr : : Icmpn ( glConfig . renderer_string , " llvmpipe " , 8 ) = = 0 )
{
if ( glConfig . driverType = = GLDRV_OPENGL32_CORE_PROFILE )
{
glConfig . driverType = GLDRV_OPENGL_MESA_CORE_PROFILE ;
}
else
{
glConfig . driverType = GLDRV_OPENGL_MESA ;
}
}
// RB end
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_multitexture
if ( glConfig . driverType ! = GLDRV_OPENGL3X )
{
glConfig . multitextureAvailable = true ;
}
else
{
glConfig . multitextureAvailable = GLEW_ARB_multitexture ! = 0 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_EXT_direct_state_access
glConfig . directStateAccess = GLEW_EXT_direct_state_access ! = 0 ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_texture_compression + GL_S3_s3tc
// DRI drivers may have GL_ARB_texture_compression but no GL_EXT_texture_compression_s3tc
if ( glConfig . driverType = = GLDRV_OPENGL_MESA_CORE_PROFILE )
{
glConfig . textureCompressionAvailable = true ;
}
else
{
glConfig . textureCompressionAvailable = GLEW_ARB_texture_compression ! = 0 & & GLEW_EXT_texture_compression_s3tc ! = 0 ;
}
// GL_EXT_texture_filter_anisotropic
glConfig . anisotropicFilterAvailable = GLEW_EXT_texture_filter_anisotropic ! = 0 ;
if ( glConfig . anisotropicFilterAvailable )
{
glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & glConfig . maxTextureAnisotropy ) ;
common - > Printf ( " maxTextureAnisotropy: %f \n " , glConfig . maxTextureAnisotropy ) ;
}
else
{
glConfig . maxTextureAnisotropy = 1 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_EXT_texture_lod_bias
// The actual extension is broken as specificed, storing the state in the texture unit instead
// of the texture object. The behavior in GL 1.4 is the behavior we use.
glConfig . textureLODBiasAvailable = ( glConfig . glVersion > = 1.4 | | GLEW_EXT_texture_lod_bias ! = 0 ) ;
if ( glConfig . textureLODBiasAvailable )
{
common - > Printf ( " ...using %s \n " , " GL_EXT_texture_lod_bias " ) ;
}
else
{
common - > Printf ( " X..%s not found \n " , " GL_EXT_texture_lod_bias " ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_seamless_cube_map
glConfig . seamlessCubeMapAvailable = GLEW_ARB_seamless_cube_map ! = 0 ;
r_useSeamlessCubeMap . SetModified ( ) ; // the CheckCvars() next frame will enable / disable it
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_framebuffer_sRGB
glConfig . sRGBFramebufferAvailable = GLEW_ARB_framebuffer_sRGB ! = 0 ;
r_useSRGB . SetModified ( ) ; // the CheckCvars() next frame will enable / disable it
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_vertex_buffer_object
if ( glConfig . driverType = = GLDRV_OPENGL_MESA_CORE_PROFILE )
{
glConfig . vertexBufferObjectAvailable = true ;
}
else
{
glConfig . vertexBufferObjectAvailable = GLEW_ARB_vertex_buffer_object ! = 0 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_map_buffer_range, map a section of a buffer object's data store
//if( glConfig.driverType == GLDRV_OPENGL_MESA_CORE_PROFILE )
//{
// glConfig.mapBufferRangeAvailable = true;
//}
//else
{
glConfig . mapBufferRangeAvailable = GLEW_ARB_map_buffer_range ! = 0 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_vertex_array_object
//if( glConfig.driverType == GLDRV_OPENGL_MESA_CORE_PROFILE )
//{
// glConfig.vertexArrayObjectAvailable = true;
//}
//else
{
glConfig . vertexArrayObjectAvailable = GLEW_ARB_vertex_array_object ! = 0 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_draw_elements_base_vertex
glConfig . drawElementsBaseVertexAvailable = GLEW_ARB_draw_elements_base_vertex ! = 0 ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_vertex_program / GL_ARB_fragment_program
glConfig . fragmentProgramAvailable = GLEW_ARB_fragment_program ! = 0 ;
//if( glConfig.fragmentProgramAvailable )
{
glGetIntegerv ( GL_MAX_TEXTURE_COORDS , ( GLint * ) & glConfig . maxTextureCoords ) ;
glGetIntegerv ( GL_MAX_TEXTURE_IMAGE_UNITS , ( GLint * ) & glConfig . maxTextureImageUnits ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GLSL, core in OpenGL > 2.0
glConfig . glslAvailable = ( glConfig . glVersion > = 2.0f ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_uniform_buffer_object
glConfig . uniformBufferAvailable = GLEW_ARB_uniform_buffer_object ! = 0 ;
if ( glConfig . uniformBufferAvailable )
{
glGetIntegerv ( GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT , ( GLint * ) & glConfig . uniformBufferOffsetAlignment ) ;
if ( glConfig . uniformBufferOffsetAlignment < 256 )
{
glConfig . uniformBufferOffsetAlignment = 256 ;
}
}
// RB: make GPU skinning optional for weak OpenGL drivers
glConfig . gpuSkinningAvailable = glConfig . uniformBufferAvailable & & ( glConfig . driverType = = GLDRV_OPENGL3X | | glConfig . driverType = = GLDRV_OPENGL32_CORE_PROFILE | | glConfig . driverType = = GLDRV_OPENGL32_COMPATIBILITY_PROFILE ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// ATI_separate_stencil / OpenGL 2.0 separate stencil
glConfig . twoSidedStencilAvailable = ( glConfig . glVersion > = 2.0f ) | | GLEW_ATI_separate_stencil ! = 0 ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_EXT_depth_bounds_test
glConfig . depthBoundsTestAvailable = GLEW_EXT_depth_bounds_test ! = 0 ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_sync
glConfig . syncAvailable = GLEW_ARB_sync & &
// as of 5/24/2012 (driver version 15.26.12.64.2761) sync objects
// do not appear to work for the Intel HD 4000 graphics
( glConfig . vendor ! = VENDOR_INTEL | | r_skipIntelWorkarounds . GetBool ( ) ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_occlusion_query
glConfig . occlusionQueryAvailable = GLEW_ARB_occlusion_query ! = 0 ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_timer_query
glConfig . timerQueryAvailable = ( GLEW_ARB_timer_query ! = 0 | | GLEW_EXT_timer_query ! = 0 ) & & ( glConfig . vendor ! = VENDOR_INTEL | | r_skipIntelWorkarounds . GetBool ( ) ) & & glConfig . driverType ! = GLDRV_OPENGL_MESA ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GREMEDY_string_marker
glConfig . gremedyStringMarkerAvailable = GLEW_GREMEDY_string_marker ! = 0 ;
if ( glConfig . gremedyStringMarkerAvailable )
{
common - > Printf ( " ...using %s \n " , " GL_GREMEDY_string_marker " ) ;
}
else
{
common - > Printf ( " X..%s not found \n " , " GL_GREMEDY_string_marker " ) ;
}
2019-11-11 19:27:44 +00:00
2020-05-03 11:39:38 +00:00
// KHR_debug
glConfig . khronosDebugAvailable = GLEW_KHR_debug ! = 0 ;
if ( glConfig . khronosDebugAvailable )
{
common - > Printf ( " ...using %s \n " , " GLEW_KHR_debug " ) ;
}
else
{
common - > Printf ( " X..%s not found \n " , " GLEW_KHR_debug " ) ;
}
2018-10-03 20:05:30 +00:00
// GL_ARB_framebuffer_object
glConfig . framebufferObjectAvailable = GLEW_ARB_framebuffer_object ! = 0 ;
if ( glConfig . framebufferObjectAvailable )
{
glGetIntegerv ( GL_MAX_RENDERBUFFER_SIZE , & glConfig . maxRenderbufferSize ) ;
glGetIntegerv ( GL_MAX_COLOR_ATTACHMENTS , & glConfig . maxColorAttachments ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
common - > Printf ( " ...using %s \n " , " GL_ARB_framebuffer_object " ) ;
}
else
{
common - > Printf ( " X..%s not found \n " , " GL_ARB_framebuffer_object " ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_EXT_framebuffer_blit
glConfig . framebufferBlitAvailable = GLEW_EXT_framebuffer_blit ! = 0 ;
if ( glConfig . framebufferBlitAvailable )
{
common - > Printf ( " ...using %s \n " , " GL_EXT_framebuffer_blit " ) ;
}
else
{
common - > Printf ( " X..%s not found \n " , " GL_EXT_framebuffer_blit " ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_debug_output
glConfig . debugOutputAvailable = GLEW_ARB_debug_output ! = 0 ;
if ( glConfig . debugOutputAvailable )
{
if ( r_debugContext . GetInteger ( ) > = 1 )
{
glDebugMessageCallbackARB ( ( GLDEBUGPROCARB ) DebugCallback , NULL ) ;
}
if ( r_debugContext . GetInteger ( ) > = 2 )
{
// force everything to happen in the main thread instead of in a separate driver thread
glEnable ( GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB ) ;
}
if ( r_debugContext . GetInteger ( ) > = 3 )
{
// enable all the low priority messages
glDebugMessageControlARB ( GL_DONT_CARE ,
GL_DONT_CARE ,
GL_DEBUG_SEVERITY_LOW_ARB ,
0 , NULL , true ) ;
}
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// GL_ARB_multitexture
if ( ! glConfig . multitextureAvailable )
{
idLib : : Error ( " GL_ARB_multitexture not available " ) ;
}
// GL_ARB_texture_compression + GL_EXT_texture_compression_s3tc
if ( ! glConfig . textureCompressionAvailable )
{
idLib : : Error ( " GL_ARB_texture_compression or GL_EXT_texture_compression_s3tc not available " ) ;
}
// GL_ARB_vertex_buffer_object
if ( ! glConfig . vertexBufferObjectAvailable )
{
idLib : : Error ( " GL_ARB_vertex_buffer_object not available " ) ;
}
// GL_ARB_map_buffer_range
if ( ! glConfig . mapBufferRangeAvailable )
{
idLib : : Error ( " GL_ARB_map_buffer_range not available " ) ;
}
// GL_ARB_vertex_array_object
if ( ! glConfig . vertexArrayObjectAvailable )
{
idLib : : Error ( " GL_ARB_vertex_array_object not available " ) ;
}
// GL_ARB_draw_elements_base_vertex
if ( ! glConfig . drawElementsBaseVertexAvailable )
{
idLib : : Error ( " GL_ARB_draw_elements_base_vertex not available " ) ;
}
// GL_ARB_vertex_program / GL_ARB_fragment_program
//if( !glConfig.fragmentProgramAvailable )
//{
// idLib::Warning( "GL_ARB_fragment_program not available" );
//}
// GLSL
if ( ! glConfig . glslAvailable )
{
idLib : : Error ( " GLSL not available " ) ;
}
// GL_ARB_uniform_buffer_object
if ( ! glConfig . uniformBufferAvailable )
{
idLib : : Error ( " GL_ARB_uniform_buffer_object not available " ) ;
}
// GL_EXT_stencil_two_side
if ( ! glConfig . twoSidedStencilAvailable )
{
idLib : : Error ( " GL_ATI_separate_stencil not available " ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// generate one global Vertex Array Object (VAO)
glGenVertexArrays ( 1 , & glConfig . global_vao ) ;
glBindVertexArray ( glConfig . global_vao ) ;
}
2017-09-10 11:32:44 +00:00
// RB end
2017-09-03 21:17:44 +00:00
2018-10-03 20:05:30 +00:00
idStr extensions_string ;
/*
= = = = = = = = = = = = = = = = = =
R_InitOpenGL
This function is responsible for initializing a valid OpenGL subsystem
for rendering . This is done by calling the system specific GLimp_Init ,
which gives us a working OGL subsystem , then setting all necessary openGL
state , including images , vertex programs , and display lists .
Changes to the vertex cache size or smp state require a vid_restart .
If R_IsInitialized ( ) is false , no rendering can take place , but
all renderSystem functions will still operate properly , notably the material
and model information functions .
= = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : Init ( )
{
common - > Printf ( " ----- R_InitOpenGL ----- \n " ) ;
2019-11-11 19:27:44 +00:00
2018-10-05 19:43:55 +00:00
if ( tr . IsInitialized ( ) )
2018-10-03 20:05:30 +00:00
{
common - > FatalError ( " R_InitOpenGL called while active " ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// DG: make sure SDL has setup video so getting supported modes in R_SetNewMode() works
GLimp_PreInit ( ) ;
// DG end
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
R_SetNewMode ( true ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// input and sound systems need to be tied to the new window
Sys_InitInput ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// get our config strings
glConfig . vendor_string = ( const char * ) glGetString ( GL_VENDOR ) ;
glConfig . renderer_string = ( const char * ) glGetString ( GL_RENDERER ) ;
glConfig . version_string = ( const char * ) glGetString ( GL_VERSION ) ;
glConfig . shading_language_string = ( const char * ) glGetString ( GL_SHADING_LANGUAGE_VERSION ) ;
glConfig . extensions_string = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
if ( glConfig . extensions_string = = NULL )
{
// As of OpenGL 3.2, glGetStringi is required to obtain the available extensions
//glGetStringi = ( PFNGLGETSTRINGIPROC )GLimp_ExtensionPointer( "glGetStringi" );
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// Build the extensions string
GLint numExtensions ;
glGetIntegerv ( GL_NUM_EXTENSIONS , & numExtensions ) ;
extensions_string . Clear ( ) ;
for ( int i = 0 ; i < numExtensions ; i + + )
{
extensions_string . Append ( ( const char * ) glGetStringi ( GL_EXTENSIONS , i ) ) ;
// the now deprecated glGetString method usaed to create a single string with each extension separated by a space
if ( i < numExtensions - 1 )
{
extensions_string . Append ( ' ' ) ;
}
}
glConfig . extensions_string = extensions_string . c_str ( ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
float glVersion = atof ( glConfig . version_string ) ;
float glslVersion = atof ( glConfig . shading_language_string ) ;
idLib : : Printf ( " OpenGL Version : %3.1f \n " , glVersion ) ;
idLib : : Printf ( " OpenGL Vendor : %s \n " , glConfig . vendor_string ) ;
idLib : : Printf ( " OpenGL Renderer : %s \n " , glConfig . renderer_string ) ;
idLib : : Printf ( " OpenGL GLSL : %3.1f \n " , glslVersion ) ;
idLib : : Printf ( " OpenGL Extensions: %s \n " , glConfig . extensions_string ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// OpenGL driver constants
GLint temp ;
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & temp ) ;
glConfig . maxTextureSize = temp ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// stubbed or broken drivers may have reported 0...
if ( glConfig . maxTextureSize < = 0 )
{
glConfig . maxTextureSize = 256 ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// recheck all the extensions (FIXME: this might be dangerous)
R_CheckPortableExtensions ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
renderProgManager . Init ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-05 19:43:55 +00:00
tr . SetInitialized ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// allocate the vertex array range or vertex objects
vertexCache . Init ( glConfig . uniformBufferOffsetAlignment ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// allocate the frame data, which may be more if smp is enabled
R_InitFrameData ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
// Reset our gamma
R_SetColorMappings ( ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
// RB: prepare ImGui system
ImGui_Init ( ) ;
2018-10-03 20:05:30 +00:00
}
void idRenderBackend : : Shutdown ( )
{
2019-10-28 19:06:10 +00:00
ImGui_Shutdown ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 20:05:30 +00:00
GLimp_Shutdown ( ) ;
}
2017-09-03 21:17:44 +00:00
/*
= = = = = = = = = = = = =
idRenderBackend : : DrawElementsWithCounters
= = = = = = = = = = = = =
*/
void idRenderBackend : : DrawElementsWithCounters ( const drawSurf_t * surf )
{
// get vertex buffer
const vertCacheHandle_t vbHandle = surf - > ambientCache ;
idVertexBuffer * vertexBuffer ;
if ( vertexCache . CacheIsStatic ( vbHandle ) )
{
vertexBuffer = & vertexCache . staticData . vertexBuffer ;
}
else
{
const uint64 frameNum = ( int ) ( vbHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
idLib : : Warning ( " RB_DrawElementsWithCounters, vertexBuffer == NULL " ) ;
return ;
}
vertexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . vertexBuffer ;
}
const int vertOffset = ( int ) ( vbHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// get index buffer
const vertCacheHandle_t ibHandle = surf - > indexCache ;
idIndexBuffer * indexBuffer ;
if ( vertexCache . CacheIsStatic ( ibHandle ) )
{
indexBuffer = & vertexCache . staticData . indexBuffer ;
}
else
{
const uint64 frameNum = ( int ) ( ibHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
idLib : : Warning ( " RB_DrawElementsWithCounters, indexBuffer == NULL " ) ;
return ;
}
indexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . indexBuffer ;
}
// RB: 64 bit fixes, changed int to GLintptr
const GLintptr indexOffset = ( GLintptr ) ( ibHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
// RB end
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
RENDERLOG_PRINTF ( " Binding Buffers: %p:%i %p:%i \n " , vertexBuffer , vertOffset , indexBuffer , indexOffset ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( surf - > jointCache )
{
// DG: this happens all the time in the erebus1 map with blendlight.vfp,
// so don't call assert (through verify) here until it's fixed (if fixable)
// else the game crashes on linux when using debug builds
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// FIXME: fix this properly if possible?
// RB: yes but it would require an additional blend light skinned shader
//if( !verify( renderProgManager.ShaderUsesJoints() ) )
if ( ! renderProgManager . ShaderUsesJoints ( ) )
// DG end
{
return ;
}
}
else
{
if ( ! verify ( ! renderProgManager . ShaderUsesJoints ( ) | | renderProgManager . ShaderHasOptionalSkinning ( ) ) )
{
return ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( surf - > jointCache )
{
2018-10-02 15:50:51 +00:00
idUniformBuffer jointBuffer ;
2017-09-03 21:17:44 +00:00
if ( ! vertexCache . GetJointBuffer ( surf - > jointCache , & jointBuffer ) )
{
idLib : : Warning ( " RB_DrawElementsWithCounters, jointBuffer == NULL " ) ;
return ;
}
assert ( ( jointBuffer . GetOffset ( ) & ( glConfig . uniformBufferOffsetAlignment - 1 ) ) = = 0 ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptr
2018-10-02 15:50:51 +00:00
const GLintptr ubo = jointBuffer . GetAPIObject ( ) ;
2017-09-03 21:17:44 +00:00
// RB end
2019-11-11 19:27:44 +00:00
2018-10-02 15:50:51 +00:00
glBindBufferRange ( GL_UNIFORM_BUFFER , 0 , ubo , jointBuffer . GetOffset ( ) , jointBuffer . GetSize ( ) ) ;
2017-09-03 21:17:44 +00:00
}
2019-11-11 19:27:44 +00:00
2018-10-13 12:42:30 +00:00
renderProgManager . CommitUniforms ( glStateBits ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptr
if ( currentIndexBuffer ! = ( GLintptr ) indexBuffer - > GetAPIObject ( ) | | ! r_useStateCaching . GetBool ( ) )
{
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , ( GLintptr ) indexBuffer - > GetAPIObject ( ) ) ;
currentIndexBuffer = ( GLintptr ) indexBuffer - > GetAPIObject ( ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( ( vertexLayout ! = LAYOUT_DRAW_VERT ) | | ( currentVertexBuffer ! = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
{
glBindBuffer ( GL_ARRAY_BUFFER , ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) ;
2017-09-09 12:57:48 +00:00
currentVertexBuffer = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_VERTEX ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_NORMAL ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR2 ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_ST ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_TANGENT ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glVertexAttribPointer ( PC_ATTRIB_INDEX_VERTEX , 3 , GL_FLOAT , GL_FALSE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_XYZ_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_NORMAL , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_NORMAL_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_COLOR2_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_ST , 2 , GL_HALF_FLOAT , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_ST_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_TANGENT , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idDrawVert ) , ( void * ) ( DRAWVERT_TANGENT_OFFSET ) ) ;
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
vertexLayout = LAYOUT_DRAW_VERT ;
2017-09-03 21:17:44 +00:00
}
// RB end
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glDrawElementsBaseVertex ( GL_TRIANGLES ,
r_singleTriangle . GetBool ( ) ? 3 : surf - > numIndexes ,
GL_INDEX_TYPE ,
( triIndex_t * ) indexOffset ,
vertOffset / sizeof ( idDrawVert ) ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// RB: added stats
2017-09-09 12:57:48 +00:00
pc . c_drawElements + + ;
pc . c_drawIndexes + = surf - > numIndexes ;
2017-09-03 21:17:44 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
GL COMMANDS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_StartFrame
= = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_StartFrame ( )
{
2018-10-06 15:21:49 +00:00
// If we have a stereo pixel format, this will draw to both
// the back left and back right buffers, which will have a
// performance penalty.
glDrawBuffer ( GL_BACK ) ;
2017-09-03 21:17:44 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_EndFrame
= = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_EndFrame ( )
{
// Fix for the steam overlay not showing up while in game without Shell/Debug/Console/Menu also rendering
glColorMask ( 1 , 1 , 1 , 1 ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glFlush ( ) ;
}
2019-11-11 19:07:33 +00:00
/*
= = = = = = = = = = = = =
GL_BlockingSwapBuffers
We want to exit this with the GPU idle , right at vsync
= = = = = = = = = = = = =
*/
void idRenderBackend : : GL_BlockingSwapBuffers ( )
{
RENDERLOG_PRINTF ( " ***************** GL_BlockingSwapBuffers ***************** \n \n \n " ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const int beforeFinish = Sys_Milliseconds ( ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
if ( ! glConfig . syncAvailable )
{
glFinish ( ) ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const int beforeSwap = Sys_Milliseconds ( ) ;
if ( r_showSwapBuffers . GetBool ( ) & & beforeSwap - beforeFinish > 1 )
{
common - > Printf ( " %i msec to glFinish \n " , beforeSwap - beforeFinish ) ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
GLimp_SwapBuffers ( ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const int beforeFence = Sys_Milliseconds ( ) ;
if ( r_showSwapBuffers . GetBool ( ) & & beforeFence - beforeSwap > 1 )
{
common - > Printf ( " %i msec to swapBuffers \n " , beforeFence - beforeSwap ) ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
if ( glConfig . syncAvailable )
{
swapIndex ^ = 1 ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
if ( glIsSync ( renderSync [ swapIndex ] ) )
{
glDeleteSync ( renderSync [ swapIndex ] ) ;
}
// draw something tiny to ensure the sync is after the swap
const int start = Sys_Milliseconds ( ) ;
glScissor ( 0 , 0 , 1 , 1 ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
renderSync [ swapIndex ] = glFenceSync ( GL_SYNC_GPU_COMMANDS_COMPLETE , 0 ) ;
const int end = Sys_Milliseconds ( ) ;
if ( r_showSwapBuffers . GetBool ( ) & & end - start > 1 )
{
common - > Printf ( " %i msec to start fence \n " , end - start ) ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
GLsync syncToWaitOn ;
if ( r_syncEveryFrame . GetBool ( ) )
{
syncToWaitOn = renderSync [ swapIndex ] ;
}
else
{
syncToWaitOn = renderSync [ ! swapIndex ] ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
if ( glIsSync ( syncToWaitOn ) )
{
for ( GLenum r = GL_TIMEOUT_EXPIRED ; r = = GL_TIMEOUT_EXPIRED ; )
{
r = glClientWaitSync ( syncToWaitOn , GL_SYNC_FLUSH_COMMANDS_BIT , 1000 * 1000 ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const int afterFence = Sys_Milliseconds ( ) ;
if ( r_showSwapBuffers . GetBool ( ) & & afterFence - beforeFence > 1 )
{
common - > Printf ( " %i msec to wait on fence \n " , afterFence - beforeFence ) ;
}
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const int64 exitBlockTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
static int64 prevBlockTime ;
if ( r_showSwapBuffers . GetBool ( ) & & prevBlockTime )
{
const int delta = ( int ) ( exitBlockTime - prevBlockTime ) ;
common - > Printf ( " blockToBlock: %i \n " , delta ) ;
}
prevBlockTime = exitBlockTime ;
}
2017-09-03 21:17:44 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
GL_SetDefaultState
This should initialize all GL state that any part of the entire program
may touch , including the editor .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_SetDefaultState ( )
{
RENDERLOG_PRINTF ( " --- GL_SetDefaultState --- \n " ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glClearDepth ( 1.0f ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// make sure our GL state vector is set correctly
memset ( & glcontext . tmu , 0 , sizeof ( glcontext . tmu ) ) ;
currenttmu = 0 ;
currentVertexBuffer = 0 ;
currentIndexBuffer = 0 ;
currentFramebuffer = 0 ;
vertexLayout = LAYOUT_UNKNOWN ;
polyOfsScale = 0.0f ;
polyOfsBias = 0.0f ;
glStateBits = 0 ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
hdrAverageLuminance = 0 ;
hdrMaxLuminance = 0 ;
hdrTime = 0 ;
hdrKey = 0 ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
GL_State ( 0 , true ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// RB begin
Framebuffer : : Unbind ( ) ;
// RB end
2019-11-11 19:27:44 +00:00
2018-11-01 15:30:05 +00:00
#if 0
2017-09-03 21:17:44 +00:00
// These are changed by GL_Cull
glCullFace ( GL_FRONT_AND_BACK ) ;
glEnable ( GL_CULL_FACE ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// These are changed by GL_State
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glBlendFunc ( GL_ONE , GL_ZERO ) ;
glDepthMask ( GL_TRUE ) ;
glDepthFunc ( GL_LESS ) ;
glDisable ( GL_STENCIL_TEST ) ;
glDisable ( GL_POLYGON_OFFSET_FILL ) ;
glDisable ( GL_POLYGON_OFFSET_LINE ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
2018-11-01 15:30:05 +00:00
# endif
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// These should never be changed
// DG: deprecated in opengl 3.2 and not needed because we don't do fixed function pipeline
// glShadeModel( GL_SMOOTH );
// DG end
glEnable ( GL_DEPTH_TEST ) ;
glEnable ( GL_BLEND ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glDrawBuffer ( GL_BACK ) ;
glReadBuffer ( GL_BACK ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( r_useScissor . GetBool ( ) )
{
glScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// RB: don't keep renderprogs that were enabled during level load
renderProgManager . Unbind ( ) ;
// RB end
}
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_State
This routine is responsible for setting the most commonly changed state
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_State ( uint64 stateBits , bool forceGlState )
{
uint64 diff = stateBits ^ glStateBits ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( ! r_useStateCaching . GetBool ( ) | | forceGlState )
{
// make sure everything is set all the time, so we
// can see if our delta checking is screwing up
diff = 0xFFFFFFFFFFFFFFFF ;
}
else if ( diff = = 0 )
{
return ;
}
2019-11-11 19:27:44 +00:00
2018-11-01 15:30:05 +00:00
//
// culling
//
if ( diff & ( GLS_CULL_BITS ) ) //| GLS_MIRROR_VIEW ) )
{
switch ( stateBits & GLS_CULL_BITS )
{
case GLS_CULL_TWOSIDED :
glDisable ( GL_CULL_FACE ) ;
break ;
2019-11-11 19:27:44 +00:00
2018-11-01 15:30:05 +00:00
case GLS_CULL_BACKSIDED :
glEnable ( GL_CULL_FACE ) ;
if ( viewDef ! = NULL & & viewDef - > isMirror )
{
stateBits | = GLS_MIRROR_VIEW ;
glCullFace ( GL_FRONT ) ;
}
else
{
glCullFace ( GL_BACK ) ;
}
break ;
2019-11-11 19:27:44 +00:00
2018-11-01 15:30:05 +00:00
case GLS_CULL_FRONTSIDED :
default :
glEnable ( GL_CULL_FACE ) ;
if ( viewDef ! = NULL & & viewDef - > isMirror )
{
stateBits | = GLS_MIRROR_VIEW ;
glCullFace ( GL_BACK ) ;
}
else
{
glCullFace ( GL_FRONT ) ;
}
break ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// check depthFunc bits
//
if ( diff & GLS_DEPTHFUNC_BITS )
{
switch ( stateBits & GLS_DEPTHFUNC_BITS )
{
case GLS_DEPTHFUNC_EQUAL :
glDepthFunc ( GL_EQUAL ) ;
break ;
case GLS_DEPTHFUNC_ALWAYS :
glDepthFunc ( GL_ALWAYS ) ;
break ;
case GLS_DEPTHFUNC_LESS :
glDepthFunc ( GL_LEQUAL ) ;
break ;
case GLS_DEPTHFUNC_GREATER :
glDepthFunc ( GL_GEQUAL ) ;
break ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// check blend bits
//
if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
{
GLenum srcFactor = GL_ONE ;
GLenum dstFactor = GL_ZERO ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
switch ( stateBits & GLS_SRCBLEND_BITS )
{
case GLS_SRCBLEND_ZERO :
srcFactor = GL_ZERO ;
break ;
case GLS_SRCBLEND_ONE :
srcFactor = GL_ONE ;
break ;
case GLS_SRCBLEND_DST_COLOR :
srcFactor = GL_DST_COLOR ;
break ;
case GLS_SRCBLEND_ONE_MINUS_DST_COLOR :
srcFactor = GL_ONE_MINUS_DST_COLOR ;
break ;
case GLS_SRCBLEND_SRC_ALPHA :
srcFactor = GL_SRC_ALPHA ;
break ;
case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA :
srcFactor = GL_ONE_MINUS_SRC_ALPHA ;
break ;
case GLS_SRCBLEND_DST_ALPHA :
srcFactor = GL_DST_ALPHA ;
break ;
case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA :
srcFactor = GL_ONE_MINUS_DST_ALPHA ;
break ;
default :
assert ( ! " GL_State: invalid src blend state bits \n " ) ;
break ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
switch ( stateBits & GLS_DSTBLEND_BITS )
{
case GLS_DSTBLEND_ZERO :
dstFactor = GL_ZERO ;
break ;
case GLS_DSTBLEND_ONE :
dstFactor = GL_ONE ;
break ;
case GLS_DSTBLEND_SRC_COLOR :
dstFactor = GL_SRC_COLOR ;
break ;
case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR :
dstFactor = GL_ONE_MINUS_SRC_COLOR ;
break ;
case GLS_DSTBLEND_SRC_ALPHA :
dstFactor = GL_SRC_ALPHA ;
break ;
case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA :
dstFactor = GL_ONE_MINUS_SRC_ALPHA ;
break ;
case GLS_DSTBLEND_DST_ALPHA :
dstFactor = GL_DST_ALPHA ;
break ;
case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA :
dstFactor = GL_ONE_MINUS_DST_ALPHA ;
break ;
default :
assert ( ! " GL_State: invalid dst blend state bits \n " ) ;
break ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
// Only actually update GL's blend func if blending is enabled.
if ( srcFactor = = GL_ONE & & dstFactor = = GL_ZERO )
{
glDisable ( GL_BLEND ) ;
}
else
{
glEnable ( GL_BLEND ) ;
glBlendFunc ( srcFactor , dstFactor ) ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// check depthmask
//
if ( diff & GLS_DEPTHMASK )
{
if ( stateBits & GLS_DEPTHMASK )
{
glDepthMask ( GL_FALSE ) ;
}
else
{
glDepthMask ( GL_TRUE ) ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// check colormask
//
if ( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) )
{
GLboolean r = ( stateBits & GLS_REDMASK ) ? GL_FALSE : GL_TRUE ;
GLboolean g = ( stateBits & GLS_GREENMASK ) ? GL_FALSE : GL_TRUE ;
GLboolean b = ( stateBits & GLS_BLUEMASK ) ? GL_FALSE : GL_TRUE ;
GLboolean a = ( stateBits & GLS_ALPHAMASK ) ? GL_FALSE : GL_TRUE ;
glColorMask ( r , g , b , a ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// fill/line mode
//
if ( diff & GLS_POLYMODE_LINE )
{
if ( stateBits & GLS_POLYMODE_LINE )
{
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
}
else
{
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// polygon offset
//
if ( diff & GLS_POLYGON_OFFSET )
{
if ( stateBits & GLS_POLYGON_OFFSET )
{
glPolygonOffset ( polyOfsScale , polyOfsBias ) ;
glEnable ( GL_POLYGON_OFFSET_FILL ) ;
glEnable ( GL_POLYGON_OFFSET_LINE ) ;
}
else
{
glDisable ( GL_POLYGON_OFFSET_FILL ) ;
glDisable ( GL_POLYGON_OFFSET_LINE ) ;
}
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
//
// stencil
//
if ( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) )
{
if ( ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) ! = 0 )
{
glEnable ( GL_STENCIL_TEST ) ;
}
else
{
glDisable ( GL_STENCIL_TEST ) ;
}
}
if ( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) )
{
GLuint ref = GLuint ( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) > > GLS_STENCIL_FUNC_REF_SHIFT ) ;
GLuint mask = GLuint ( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) > > GLS_STENCIL_FUNC_MASK_SHIFT ) ;
GLenum func = 0 ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
switch ( stateBits & GLS_STENCIL_FUNC_BITS )
{
case GLS_STENCIL_FUNC_NEVER :
func = GL_NEVER ;
break ;
case GLS_STENCIL_FUNC_LESS :
func = GL_LESS ;
break ;
case GLS_STENCIL_FUNC_EQUAL :
func = GL_EQUAL ;
break ;
case GLS_STENCIL_FUNC_LEQUAL :
func = GL_LEQUAL ;
break ;
case GLS_STENCIL_FUNC_GREATER :
func = GL_GREATER ;
break ;
case GLS_STENCIL_FUNC_NOTEQUAL :
func = GL_NOTEQUAL ;
break ;
case GLS_STENCIL_FUNC_GEQUAL :
func = GL_GEQUAL ;
break ;
case GLS_STENCIL_FUNC_ALWAYS :
func = GL_ALWAYS ;
break ;
}
glStencilFunc ( func , ref , mask ) ;
}
if ( diff & ( GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS ) )
{
GLenum sFail = 0 ;
GLenum zFail = 0 ;
GLenum pass = 0 ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
switch ( stateBits & GLS_STENCIL_OP_FAIL_BITS )
{
case GLS_STENCIL_OP_FAIL_KEEP :
sFail = GL_KEEP ;
break ;
case GLS_STENCIL_OP_FAIL_ZERO :
sFail = GL_ZERO ;
break ;
case GLS_STENCIL_OP_FAIL_REPLACE :
sFail = GL_REPLACE ;
break ;
case GLS_STENCIL_OP_FAIL_INCR :
sFail = GL_INCR ;
break ;
case GLS_STENCIL_OP_FAIL_DECR :
sFail = GL_DECR ;
break ;
case GLS_STENCIL_OP_FAIL_INVERT :
sFail = GL_INVERT ;
break ;
case GLS_STENCIL_OP_FAIL_INCR_WRAP :
sFail = GL_INCR_WRAP ;
break ;
case GLS_STENCIL_OP_FAIL_DECR_WRAP :
sFail = GL_DECR_WRAP ;
break ;
}
switch ( stateBits & GLS_STENCIL_OP_ZFAIL_BITS )
{
case GLS_STENCIL_OP_ZFAIL_KEEP :
zFail = GL_KEEP ;
break ;
case GLS_STENCIL_OP_ZFAIL_ZERO :
zFail = GL_ZERO ;
break ;
case GLS_STENCIL_OP_ZFAIL_REPLACE :
zFail = GL_REPLACE ;
break ;
case GLS_STENCIL_OP_ZFAIL_INCR :
zFail = GL_INCR ;
break ;
case GLS_STENCIL_OP_ZFAIL_DECR :
zFail = GL_DECR ;
break ;
case GLS_STENCIL_OP_ZFAIL_INVERT :
zFail = GL_INVERT ;
break ;
case GLS_STENCIL_OP_ZFAIL_INCR_WRAP :
zFail = GL_INCR_WRAP ;
break ;
case GLS_STENCIL_OP_ZFAIL_DECR_WRAP :
zFail = GL_DECR_WRAP ;
break ;
}
switch ( stateBits & GLS_STENCIL_OP_PASS_BITS )
{
case GLS_STENCIL_OP_PASS_KEEP :
pass = GL_KEEP ;
break ;
case GLS_STENCIL_OP_PASS_ZERO :
pass = GL_ZERO ;
break ;
case GLS_STENCIL_OP_PASS_REPLACE :
pass = GL_REPLACE ;
break ;
case GLS_STENCIL_OP_PASS_INCR :
pass = GL_INCR ;
break ;
case GLS_STENCIL_OP_PASS_DECR :
pass = GL_DECR ;
break ;
case GLS_STENCIL_OP_PASS_INVERT :
pass = GL_INVERT ;
break ;
case GLS_STENCIL_OP_PASS_INCR_WRAP :
pass = GL_INCR_WRAP ;
break ;
case GLS_STENCIL_OP_PASS_DECR_WRAP :
pass = GL_DECR_WRAP ;
break ;
}
glStencilOp ( sFail , zFail , pass ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
glStateBits = stateBits ;
}
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : SelectTexture
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_SelectTexture ( int unit )
{
if ( currenttmu = = unit )
{
return ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
if ( unit < 0 | | unit > = glConfig . maxTextureImageUnits )
{
common - > Warning ( " GL_SelectTexture: unit = %i " , unit ) ;
return ;
}
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
RENDERLOG_PRINTF ( " GL_SelectTexture( %i ); \n " , unit ) ;
2019-11-11 19:27:44 +00:00
2017-09-03 21:17:44 +00:00
currenttmu = unit ;
}
2017-09-09 12:57:48 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_Scissor
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_Scissor ( int x /* left*/ , int y /* bottom */ , int w , int h )
{
glScissor ( x , y , w , h ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_Viewport
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_Viewport ( int x /* left */ , int y /* bottom */ , int w , int h )
{
glViewport ( x , y , w , h ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_PolygonOffset
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_PolygonOffset ( float scale , float bias )
{
polyOfsScale = scale ;
polyOfsBias = bias ;
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
if ( glStateBits & GLS_POLYGON_OFFSET )
{
glPolygonOffset ( scale , bias ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_DepthBoundsTest
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_DepthBoundsTest ( const float zmin , const float zmax )
{
if ( ! glConfig . depthBoundsTestAvailable | | zmin > zmax )
{
return ;
}
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
if ( zmin = = 0.0f & & zmax = = 0.0f )
{
glDisable ( GL_DEPTH_BOUNDS_TEST_EXT ) ;
}
else
{
glEnable ( GL_DEPTH_BOUNDS_TEST_EXT ) ;
glDepthBoundsEXT ( zmin , zmax ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_Color
= = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_Color ( float r , float g , float b , float a )
{
float parm [ 4 ] ;
parm [ 0 ] = idMath : : ClampFloat ( 0.0f , 1.0f , r ) ;
parm [ 1 ] = idMath : : ClampFloat ( 0.0f , 1.0f , g ) ;
parm [ 2 ] = idMath : : ClampFloat ( 0.0f , 1.0f , b ) ;
parm [ 3 ] = idMath : : ClampFloat ( 0.0f , 1.0f , a ) ;
renderProgManager . SetRenderParm ( RENDERPARM_COLOR , parm ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_Clear
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void idRenderBackend : : GL_Clear ( bool color , bool depth , bool stencil , byte stencilValue , float r , float g , float b , float a , bool clearHDR )
{
int clearFlags = 0 ;
if ( color )
{
glClearColor ( r , g , b , a ) ;
clearFlags | = GL_COLOR_BUFFER_BIT ;
}
if ( depth )
{
clearFlags | = GL_DEPTH_BUFFER_BIT ;
}
if ( stencil )
{
glClearStencil ( stencilValue ) ;
clearFlags | = GL_STENCIL_BUFFER_BIT ;
}
glClear ( clearFlags ) ;
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
// RB begin
if ( r_useHDR . GetBool ( ) & & clearHDR & & globalFramebuffers . hdrFBO ! = NULL )
{
bool isDefaultFramebufferActive = Framebuffer : : IsDefaultFramebufferActive ( ) ;
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
globalFramebuffers . hdrFBO - > Bind ( ) ;
glClear ( clearFlags ) ;
2019-11-11 19:27:44 +00:00
2017-09-09 12:57:48 +00:00
if ( isDefaultFramebufferActive )
{
Framebuffer : : Unbind ( ) ;
}
}
// RB end
}
/*
= = = = = = = = = = = = = = = = =
idRenderBackend : : GL_GetCurrentState
= = = = = = = = = = = = = = = = =
*/
uint64 idRenderBackend : : GL_GetCurrentState ( ) const
{
2018-10-13 12:42:30 +00:00
return glStateBits ;
2017-09-09 12:57:48 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idRenderBackend : : GL_GetCurrentStateMinusStencil
= = = = = = = = = = = = = = = = = = = = = = = =
*/
uint64 idRenderBackend : : GL_GetCurrentStateMinusStencil ( ) const
{
return GL_GetCurrentState ( ) & ~ ( GLS_STENCIL_OP_BITS | GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) ;
}
2017-09-10 11:32:44 +00:00
/*
= = = = = = = = = = = = =
idRenderBackend : : CheckCVars
See if some cvars that we watch have changed
= = = = = = = = = = = = =
*/
void idRenderBackend : : CheckCVars ( )
{
// gamma stuff
if ( r_gamma . IsModified ( ) | | r_brightness . IsModified ( ) )
{
r_gamma . ClearModified ( ) ;
r_brightness . ClearModified ( ) ;
R_SetColorMappings ( ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
// filtering
if ( r_maxAnisotropicFiltering . IsModified ( ) | | r_useTrilinearFiltering . IsModified ( ) | | r_lodBias . IsModified ( ) )
{
idLib : : Printf ( " Updating texture filter parameters. \n " ) ;
r_maxAnisotropicFiltering . ClearModified ( ) ;
r_useTrilinearFiltering . ClearModified ( ) ;
r_lodBias . ClearModified ( ) ;
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
for ( int i = 0 ; i < globalImages - > images . Num ( ) ; i + + )
{
if ( globalImages - > images [ i ] )
{
globalImages - > images [ i ] - > Bind ( ) ;
globalImages - > images [ i ] - > SetTexParameters ( ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
if ( r_useSeamlessCubeMap . IsModified ( ) )
{
r_useSeamlessCubeMap . ClearModified ( ) ;
if ( glConfig . seamlessCubeMapAvailable )
{
if ( r_useSeamlessCubeMap . GetBool ( ) )
{
glEnable ( GL_TEXTURE_CUBE_MAP_SEAMLESS ) ;
}
else
{
glDisable ( GL_TEXTURE_CUBE_MAP_SEAMLESS ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
if ( r_useSRGB . IsModified ( ) )
{
r_useSRGB . ClearModified ( ) ;
if ( glConfig . sRGBFramebufferAvailable )
{
if ( r_useSRGB . GetBool ( ) & & r_useSRGB . GetInteger ( ) ! = 3 )
{
glEnable ( GL_FRAMEBUFFER_SRGB ) ;
}
else
{
glDisable ( GL_FRAMEBUFFER_SRGB ) ;
}
}
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
if ( r_antiAliasing . IsModified ( ) )
{
switch ( r_antiAliasing . GetInteger ( ) )
{
case ANTI_ALIASING_MSAA_2X :
case ANTI_ALIASING_MSAA_4X :
case ANTI_ALIASING_MSAA_8X :
if ( r_antiAliasing . GetInteger ( ) > 0 )
{
glEnable ( GL_MULTISAMPLE ) ;
}
break ;
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
default :
glDisable ( GL_MULTISAMPLE ) ;
break ;
}
}
2019-11-11 19:27:44 +00:00
2020-04-26 08:41:09 +00:00
if ( r_usePBR . IsModified ( ) | |
2020-04-26 08:38:28 +00:00
r_useHDR . IsModified ( ) | |
r_useHalfLambertLighting . IsModified ( ) | |
r_pbrDebug . IsModified ( ) )
2017-09-10 11:32:44 +00:00
{
2019-11-22 17:25:33 +00:00
bool needShaderReload = false ;
2020-04-26 08:41:09 +00:00
if ( r_usePBR . GetBool ( ) & & r_useHalfLambertLighting . GetBool ( ) )
2019-11-22 17:25:33 +00:00
{
r_useHalfLambertLighting . SetBool ( false ) ;
needShaderReload = true ;
}
needShaderReload | = r_useHDR . IsModified ( ) ;
2020-04-26 08:38:28 +00:00
needShaderReload | = r_pbrDebug . IsModified ( ) ;
2019-11-22 17:25:33 +00:00
2020-04-26 08:41:09 +00:00
r_usePBR . ClearModified ( ) ;
2017-09-10 11:32:44 +00:00
r_useHDR . ClearModified ( ) ;
r_useHalfLambertLighting . ClearModified ( ) ;
2020-04-26 08:38:28 +00:00
r_pbrDebug . ClearModified ( ) ;
2019-11-22 17:25:33 +00:00
2017-09-10 11:32:44 +00:00
renderProgManager . KillAllShaders ( ) ;
renderProgManager . LoadAllShaders ( ) ;
}
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
// RB: turn off shadow mapping for OpenGL drivers that are too slow
switch ( glConfig . driverType )
{
case GLDRV_OPENGL_ES2 :
case GLDRV_OPENGL_ES3 :
//case GLDRV_OPENGL_MESA:
r_useShadowMapping . SetInteger ( 0 ) ;
break ;
2019-11-11 19:27:44 +00:00
2017-09-10 11:32:44 +00:00
default :
break ;
}
// RB end
}
2019-11-11 19:07:33 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
RENDER BACK END THREAD FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = =
idRenderBackend : : DrawFlickerBox
= = = = = = = = = = = = =
*/
void idRenderBackend : : DrawFlickerBox ( )
{
if ( ! r_drawFlickerBox . GetBool ( ) )
{
return ;
}
if ( tr . frameCount & 1 )
{
glClearColor ( 1 , 0 , 0 , 1 ) ;
}
else
{
glClearColor ( 0 , 1 , 0 , 1 ) ;
}
glScissor ( 0 , 0 , 256 , 256 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
/*
= = = = = = = = = = = = =
idRenderBackend : : SetBuffer
= = = = = = = = = = = = =
*/
void idRenderBackend : : SetBuffer ( const void * data )
{
// see which draw buffer we want to render the frame to
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
const setBufferCommand_t * cmd = ( const setBufferCommand_t * ) data ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
RENDERLOG_PRINTF ( " ---------- RB_SetBuffer ---------- to buffer # %d \n " , cmd - > buffer ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
GL_Scissor ( 0 , 0 , tr . GetWidth ( ) , tr . GetHeight ( ) ) ;
2019-11-11 19:27:44 +00:00
2019-11-11 19:07:33 +00:00
// clear screen for debugging
// automatically enable this with several other debug tools
// that might leave unrendered portions of the screen
if ( r_clear . GetFloat ( ) | | idStr : : Length ( r_clear . GetString ( ) ) ! = 1 | | r_singleArea . GetBool ( ) | | r_showOverDraw . GetBool ( ) )
{
float c [ 3 ] ;
if ( sscanf ( r_clear . GetString ( ) , " %f %f %f " , & c [ 0 ] , & c [ 1 ] , & c [ 2 ] ) = = 3 )
{
GL_Clear ( true , false , false , 0 , c [ 0 ] , c [ 1 ] , c [ 2 ] , 1.0f , true ) ;
}
else if ( r_clear . GetInteger ( ) = = 2 )
{
GL_Clear ( true , false , false , 0 , 0.0f , 0.0f , 0.0f , 1.0f , true ) ;
}
else if ( r_showOverDraw . GetBool ( ) )
{
GL_Clear ( true , false , false , 0 , 1.0f , 1.0f , 1.0f , 1.0f , true ) ;
}
else
{
GL_Clear ( true , false , false , 0 , 0.4f , 0.0f , 0.25f , 1.0f , true ) ;
}
}
}
2018-10-03 19:14:28 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
STENCIL SHADOW RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
2019-11-11 19:07:33 +00:00
= = = = = = = = = = = = = = = = = = = = =
2018-10-03 19:14:28 +00:00
idRenderBackend : : DrawStencilShadowPass
2019-11-11 19:07:33 +00:00
= = = = = = = = = = = = = = = = = = = = =
2018-10-03 19:14:28 +00:00
*/
2019-11-22 17:25:33 +00:00
extern idCVar r_useStencilShadowPreload ;
2018-10-03 19:14:28 +00:00
void idRenderBackend : : DrawStencilShadowPass ( const drawSurf_t * drawSurf , const bool renderZPass )
{
2019-11-08 17:12:37 +00:00
if ( renderZPass )
{
// Z-pass
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_KEEP , GL_DECR ) ;
}
else if ( r_useStencilShadowPreload . GetBool ( ) )
{
// preload + Z-pass
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_DECR , GL_DECR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_INCR , GL_INCR ) ;
}
else
{
2019-11-19 20:02:47 +00:00
// Z-fail (Carmack's Reverse)
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_DECR , GL_KEEP ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_INCR , GL_KEEP ) ;
2019-11-08 17:12:37 +00:00
}
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
// get vertex buffer
const vertCacheHandle_t vbHandle = drawSurf - > shadowCache ;
idVertexBuffer * vertexBuffer ;
if ( vertexCache . CacheIsStatic ( vbHandle ) )
{
vertexBuffer = & vertexCache . staticData . vertexBuffer ;
}
else
{
const uint64 frameNum = ( int ) ( vbHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
idLib : : Warning ( " DrawStencilShadowPass, vertexBuffer == NULL " ) ;
return ;
}
2019-11-11 19:07:33 +00:00
vertexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . vertexBuffer ;
2018-10-03 19:14:28 +00:00
}
const int vertOffset = ( int ) ( vbHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
// get index buffer
const vertCacheHandle_t ibHandle = drawSurf - > indexCache ;
idIndexBuffer * indexBuffer ;
if ( vertexCache . CacheIsStatic ( ibHandle ) )
{
indexBuffer = & vertexCache . staticData . indexBuffer ;
}
else
{
const uint64 frameNum = ( int ) ( ibHandle > > VERTCACHE_FRAME_SHIFT ) & VERTCACHE_FRAME_MASK ;
if ( frameNum ! = ( ( vertexCache . currentFrame - 1 ) & VERTCACHE_FRAME_MASK ) )
{
idLib : : Warning ( " DrawStencilShadowPass, indexBuffer == NULL " ) ;
return ;
}
2019-11-11 19:07:33 +00:00
indexBuffer = & vertexCache . frameData [ vertexCache . drawListNum ] . indexBuffer ;
2018-10-03 19:14:28 +00:00
}
const uint64 indexOffset = ( int ) ( ibHandle > > VERTCACHE_OFFSET_SHIFT ) & VERTCACHE_OFFSET_MASK ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
RENDERLOG_PRINTF ( " Binding Buffers: %p %p \n " , vertexBuffer , indexBuffer ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
// RB: 64 bit fixes, changed GLuint to GLintptr
if ( currentIndexBuffer ! = ( GLintptr ) indexBuffer - > GetAPIObject ( ) | | ! r_useStateCaching . GetBool ( ) )
{
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , ( GLintptr ) indexBuffer - > GetAPIObject ( ) ) ;
currentIndexBuffer = ( GLintptr ) indexBuffer - > GetAPIObject ( ) ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
if ( drawSurf - > jointCache )
{
assert ( renderProgManager . ShaderUsesJoints ( ) ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
idUniformBuffer jointBuffer ;
if ( ! vertexCache . GetJointBuffer ( drawSurf - > jointCache , & jointBuffer ) )
{
idLib : : Warning ( " DrawStencilShadowPass, jointBuffer == NULL " ) ;
return ;
}
assert ( ( jointBuffer . GetOffset ( ) & ( glConfig . uniformBufferOffsetAlignment - 1 ) ) = = 0 ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
const GLintptr ubo = jointBuffer . GetAPIObject ( ) ;
glBindBufferRange ( GL_UNIFORM_BUFFER , 0 , ubo , jointBuffer . GetOffset ( ) , jointBuffer . GetSize ( ) ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
if ( ( vertexLayout ! = LAYOUT_DRAW_SHADOW_VERT_SKINNED ) | | ( currentVertexBuffer ! = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
{
glBindBuffer ( GL_ARRAY_BUFFER , ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) ;
currentVertexBuffer = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_VERTEX ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_NORMAL ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR ) ;
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR2 ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_ST ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_TANGENT ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
# if defined(USE_GLES2) || defined(USE_GLES3)
glVertexAttribPointer ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVertSkinned ) , ( void * ) ( vertOffset + SHADOWVERTSKINNED_XYZW_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( vertOffset + SHADOWVERTSKINNED_COLOR_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( vertOffset + SHADOWVERTSKINNED_COLOR2_OFFSET ) ) ;
# else
glVertexAttribPointer ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_XYZW_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR_OFFSET ) ) ;
glVertexAttribPointer ( PC_ATTRIB_INDEX_COLOR2 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( idShadowVertSkinned ) , ( void * ) ( SHADOWVERTSKINNED_COLOR2_OFFSET ) ) ;
# endif
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
vertexLayout = LAYOUT_DRAW_SHADOW_VERT_SKINNED ;
}
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
}
else
{
if ( ( vertexLayout ! = LAYOUT_DRAW_SHADOW_VERT ) | | ( currentVertexBuffer ! = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) | | ! r_useStateCaching . GetBool ( ) )
{
glBindBuffer ( GL_ARRAY_BUFFER , ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ) ;
currentVertexBuffer = ( GLintptr ) vertexBuffer - > GetAPIObject ( ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
glEnableVertexAttribArray ( PC_ATTRIB_INDEX_VERTEX ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_NORMAL ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR2 ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_ST ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_TANGENT ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
# if defined(USE_GLES2) || defined(USE_GLES3)
glVertexAttribPointer ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVert ) , ( void * ) ( vertOffset + SHADOWVERT_XYZW_OFFSET ) ) ;
# else
glVertexAttribPointer ( PC_ATTRIB_INDEX_VERTEX , 4 , GL_FLOAT , GL_FALSE , sizeof ( idShadowVert ) , ( void * ) ( SHADOWVERT_XYZW_OFFSET ) ) ;
# endif
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
vertexLayout = LAYOUT_DRAW_SHADOW_VERT ;
}
}
// RB end
2019-11-11 19:27:44 +00:00
2018-10-13 12:42:30 +00:00
renderProgManager . CommitUniforms ( glStateBits ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
if ( drawSurf - > jointCache )
{
# if defined(USE_GLES3) //defined(USE_GLES2)
glDrawElements ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset ) ;
# else
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVertSkinned ) ) ;
# endif
}
else
{
# if defined(USE_GLES3)
glDrawElements ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset ) ;
# else
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVert ) ) ;
# endif
}
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
// RB: added stats
pc . c_shadowElements + + ;
pc . c_shadowIndexes + = drawSurf - > numIndexes ;
// RB end
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
if ( ! renderZPass & & r_useStencilShadowPreload . GetBool ( ) )
{
// render again with Z-pass
glStencilOpSeparate ( GL_FRONT , GL_KEEP , GL_KEEP , GL_INCR ) ;
glStencilOpSeparate ( GL_BACK , GL_KEEP , GL_KEEP , GL_DECR ) ;
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
if ( drawSurf - > jointCache )
{
# if defined(USE_GLES3)
glDrawElements ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset ) ;
# else
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVertSkinned ) ) ;
# endif
}
else
{
# if defined(USE_GLES3)
glDrawElements ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset ) ;
# else
glDrawElementsBaseVertex ( GL_TRIANGLES , r_singleTriangle . GetBool ( ) ? 3 : drawSurf - > numIndexes , GL_INDEX_TYPE , ( triIndex_t * ) indexOffset , vertOffset / sizeof ( idShadowVert ) ) ;
# endif
}
2019-11-11 19:27:44 +00:00
2018-10-03 19:14:28 +00:00
// RB: added stats
pc . c_shadowElements + + ;
pc . c_shadowIndexes + = drawSurf - > numIndexes ;
// RB end
}
}
2019-10-28 19:06:10 +00:00
2017-09-03 21:17:44 +00:00
/*
= = = = = = = = = = = = =
idRenderBackend : : idRenderBackend
= = = = = = = = = = = = =
*/
idRenderBackend : : idRenderBackend ( )
{
2018-10-03 20:05:30 +00:00
memset ( glcontext . tmu , 0 , sizeof ( glcontext . tmu ) ) ;
memset ( glcontext . stencilOperations , 0 , sizeof ( glcontext . stencilOperations ) ) ;
2017-09-03 21:17:44 +00:00
}
/*
= = = = = = = = = = = = =
idRenderBackend : : ~ idRenderBackend
= = = = = = = = = = = = =
*/
idRenderBackend : : ~ idRenderBackend ( )
{
}
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
R_MakeStereoRenderImage
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
static void R_MakeStereoRenderImage ( idImage * image )
{
2012-11-26 18:58:24 +00:00
idImageOpts opts ;
opts . width = renderSystem - > GetWidth ( ) ;
opts . height = renderSystem - > GetHeight ( ) ;
opts . numLevels = 1 ;
opts . format = FMT_RGBA8 ;
image - > AllocImage ( opts , TF_LINEAR , TR_CLAMP ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
2017-09-03 21:17:44 +00:00
idRenderBackend : : StereoRenderExecuteBackEndCommands
2012-11-26 18:58:24 +00:00
Renders the draw list twice , with slight modifications for left eye / right eye
= = = = = = = = = = = = = = = = = = = =
*/
2017-09-03 21:17:44 +00:00
void idRenderBackend : : StereoRenderExecuteBackEndCommands ( const emptyCommand_t * const allCmds )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
uint64 backEndStartTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// If we are in a monoscopic context, this draws to the only buffer, and is
// the same as GL_BACK. In a quad-buffer stereo context, this is necessary
// to prevent GL from forcing the rendering to go to both BACK_LEFT and
// BACK_RIGHT at a performance penalty.
// To allow stereo deghost processing, the views have to be copied to separate
// textures anyway, so there isn't any benefit to rendering to BACK_RIGHT for
// that eye.
2012-12-17 16:30:59 +00:00
glDrawBuffer ( GL_BACK_LEFT ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// create the stereoRenderImage if we haven't already
2012-11-28 15:47:07 +00:00
static idImage * stereoRenderImages [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + )
{
if ( stereoRenderImages [ i ] = = NULL )
{
stereoRenderImages [ i ] = globalImages - > ImageFromFunction ( va ( " _stereoRender%i " , i ) , R_MakeStereoRenderImage ) ;
2012-11-26 18:58:24 +00:00
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// resize the stereo render image if the main window has changed size
2012-11-28 15:47:07 +00:00
if ( stereoRenderImages [ i ] - > GetUploadWidth ( ) ! = renderSystem - > GetWidth ( ) | |
stereoRenderImages [ i ] - > GetUploadHeight ( ) ! = renderSystem - > GetHeight ( ) )
{
2012-11-26 18:58:24 +00:00
stereoRenderImages [ i ] - > Resize ( renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// In stereoRender mode, the front end has generated two RC_DRAW_VIEW commands
// with slightly different origins for each eye.
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// TODO: only do the copy after the final view has been rendered, not mirror subviews?
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Render the 3D draw views from the screen origin so all the screen relative
// texture mapping works properly, then copy the portion we are going to use
// off to a texture.
bool foundEye [ 2 ] = { false , false } ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
for ( int stereoEye = 1 ; stereoEye > = - 1 ; stereoEye - = 2 )
{
2012-11-26 18:58:24 +00:00
// set up the target texture we will draw to
const int targetEye = ( stereoEye = = 1 ) ? 1 : 0 ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Set the back end into a known default state to fix any stale render state issues
GL_SetDefaultState ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . Unbind ( ) ;
renderProgManager . ZeroUniforms ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
for ( const emptyCommand_t * cmds = allCmds ; cmds ! = NULL ; cmds = ( const emptyCommand_t * ) cmds - > next )
{
switch ( cmds - > commandId )
{
case RC_NOP :
break ;
case RC_DRAW_VIEW_GUI :
case RC_DRAW_VIEW_3D :
2012-11-26 18:58:24 +00:00
{
2012-11-28 15:47:07 +00:00
const drawSurfsCommand_t * const dsc = ( const drawSurfsCommand_t * ) cmds ;
const viewDef_t & eyeViewDef = * dsc - > viewDef ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( eyeViewDef . renderView . viewEyeBuffer & & eyeViewDef . renderView . viewEyeBuffer ! = stereoEye )
{
2012-11-26 18:58:24 +00:00
// this is the render view for the other eye
continue ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
foundEye [ targetEye ] = true ;
2017-09-09 12:57:48 +00:00
DrawView ( dsc , stereoEye ) ;
2012-11-28 15:47:07 +00:00
if ( cmds - > commandId = = RC_DRAW_VIEW_GUI )
{
2012-11-26 18:58:24 +00:00
}
}
break ;
2012-11-28 15:47:07 +00:00
case RC_SET_BUFFER :
2017-09-03 21:17:44 +00:00
SetBuffer ( cmds ) ;
2012-11-28 15:47:07 +00:00
break ;
case RC_COPY_RENDER :
2017-09-10 11:32:44 +00:00
CopyRender ( cmds ) ;
2012-11-28 15:47:07 +00:00
break ;
case RC_POST_PROCESS :
2012-11-26 18:58:24 +00:00
{
2012-11-28 15:47:07 +00:00
postProcessCommand_t * cmd = ( postProcessCommand_t * ) cmds ;
if ( cmd - > viewDef - > renderView . viewEyeBuffer ! = stereoEye )
{
2012-11-26 18:58:24 +00:00
break ;
}
2017-09-10 11:32:44 +00:00
PostProcess ( cmds ) ;
2012-11-26 18:58:24 +00:00
}
break ;
2012-11-28 15:47:07 +00:00
default :
common - > Error ( " RB_ExecuteBackEndCommands: bad commandId " ) ;
break ;
2012-11-26 18:58:24 +00:00
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// copy to the target
stereoRenderImages [ targetEye ] - > CopyFramebuffer ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// perform the final compositing / warping / deghosting to the actual framebuffer(s)
assert ( foundEye [ 0 ] & & foundEye [ 1 ] ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
GL_SetDefaultState ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
RB_SetMVP ( renderMatrix_identity ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// If we are in quad-buffer pixel format but testing another 3D mode,
// make sure we draw to both eyes. This is likely to be sub-optimal
// performance on most cards and drivers, but it is better than getting
// a confusing, half-ghosted view.
2012-11-28 15:47:07 +00:00
if ( renderSystem - > GetStereo3DMode ( ) ! = STEREO3D_QUAD_BUFFER )
{
2012-11-26 18:58:24 +00:00
glDrawBuffer ( GL_BACK ) ;
}
2019-11-11 19:27:44 +00:00
2018-11-01 15:30:05 +00:00
GL_State ( GLS_DEPTHFUNC_ALWAYS | GLS_CULL_TWOSIDED ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// We just want to do a quad pass - so make sure we disable any texgen and
2012-11-28 15:47:07 +00:00
// set the texture matrix to the identity so we don't get anomalies from
2012-11-26 18:58:24 +00:00
// any stale uniform data being present from a previous draw call
const float texS [ 4 ] = { 1.0f , 0.0f , 0.0f , 0.0f } ;
const float texT [ 4 ] = { 0.0f , 1.0f , 0.0f , 0.0f } ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXTUREMATRIX_S , texS ) ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXTUREMATRIX_T , texT ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// disable any texgen
const float texGenEnabled [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
renderProgManager . SetRenderParm ( RENDERPARM_TEXGEN_0_ENABLED , texGenEnabled ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
renderProgManager . BindShader_Texture ( ) ;
GL_Color ( 1 , 1 , 1 , 1 ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
switch ( renderSystem - > GetStereo3DMode ( ) )
{
case STEREO3D_QUAD_BUFFER :
glDrawBuffer ( GL_BACK_RIGHT ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
glDrawBuffer ( GL_BACK_LEFT ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2017-09-09 12:57:48 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2012-11-28 15:47:07 +00:00
break ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
case STEREO3D_HDMI_720 :
// HDMI 720P 3D
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , 1280 , 720 ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 750 , 1280 , 720 ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
// force the HDMI 720P 3D guard band to a constant color
glScissor ( 0 , 720 , 1280 , 30 ) ;
2012-11-26 18:58:24 +00:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
2012-11-28 15:47:07 +00:00
break ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
default :
case STEREO3D_SIDE_BY_SIDE :
if ( stereoRender_warp . GetBool ( ) )
{
// this is the Rift warp
// renderSystem->GetWidth() / GetHeight() have returned equal values (640 for initial Rift)
// and we are going to warp them onto a symetric square region of each half of the screen
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
renderProgManager . BindShader_StereoWarp ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
// clear the entire screen to black
// we could be smart and only clear the areas we aren't going to draw on, but
// clears are fast...
glScissor ( 0 , 0 , glConfig . nativeScreenWidth , glConfig . nativeScreenHeight ) ;
glClearColor ( 0 , 0 , 0 , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
// the size of the box that will get the warped pixels
// With the 7" displays, this will be less than half the screen width
const int pixelDimensions = ( glConfig . nativeScreenWidth > > 1 ) * stereoRender_warpTargetFraction . GetFloat ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
// Always scissor to the half-screen boundary, but the viewports
// might cross that boundary if the lenses can be adjusted closer
// together.
glViewport ( ( glConfig . nativeScreenWidth > > 1 ) - pixelDimensions ,
( glConfig . nativeScreenHeight > > 1 ) - ( pixelDimensions > > 1 ) ,
pixelDimensions , pixelDimensions ) ;
glScissor ( 0 , 0 , glConfig . nativeScreenWidth > > 1 , glConfig . nativeScreenHeight ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
idVec4 color ( stereoRender_warpCenterX . GetFloat ( ) , stereoRender_warpCenterY . GetFloat ( ) , stereoRender_warpParmZ . GetFloat ( ) , stereoRender_warpParmW . GetFloat ( ) ) ;
// don't use GL_Color(), because we don't want to clamp
renderProgManager . SetRenderParm ( RENDERPARM_COLOR , color . ToFloatPtr ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
idVec4 color2 ( stereoRender_warpCenterX . GetFloat ( ) , stereoRender_warpCenterY . GetFloat ( ) , stereoRender_warpParmZ . GetFloat ( ) , stereoRender_warpParmW . GetFloat ( ) ) ;
// don't use GL_Color(), because we don't want to clamp
renderProgManager . SetRenderParm ( RENDERPARM_COLOR , color2 . ToFloatPtr ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
glViewport ( ( glConfig . nativeScreenWidth > > 1 ) ,
( glConfig . nativeScreenHeight > > 1 ) - ( pixelDimensions > > 1 ) ,
pixelDimensions , pixelDimensions ) ;
glScissor ( glConfig . nativeScreenWidth > > 1 , 0 , glConfig . nativeScreenWidth > > 1 , glConfig . nativeScreenHeight ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2012-11-28 15:47:07 +00:00
break ;
}
2019-11-11 19:27:44 +00:00
2015-01-18 11:13:24 +00:00
// a non-warped side-by-side-uncompressed (dual input cable) is rendered
// just like STEREO3D_SIDE_BY_SIDE_COMPRESSED, so fall through.
2012-11-28 15:47:07 +00:00
case STEREO3D_SIDE_BY_SIDE_COMPRESSED :
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( renderSystem - > GetWidth ( ) , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2012-11-26 18:58:24 +00:00
break ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
case STEREO3D_TOP_AND_BOTTOM_COMPRESSED :
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
GL_ViewportAndScissor ( 0 , renderSystem - > GetHeight ( ) , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) ) ;
2017-09-03 21:17:44 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2012-11-28 15:47:07 +00:00
break ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
case STEREO3D_INTERLACED :
// every other scanline
GL_SelectTexture ( 0 ) ;
stereoRenderImages [ 0 ] - > Bind ( ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
stereoRenderImages [ 1 ] - > Bind ( ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_ViewportAndScissor ( 0 , 0 , renderSystem - > GetWidth ( ) , renderSystem - > GetHeight ( ) * 2 ) ;
renderProgManager . BindShader_StereoInterlace ( ) ;
2017-09-09 12:57:48 +00:00
DrawElementsWithCounters ( & unitSquareSurface ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 0 ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
GL_SelectTexture ( 1 ) ;
2012-12-17 16:30:59 +00:00
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
break ;
2012-11-26 18:58:24 +00:00
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// debug tool
2017-09-03 21:17:44 +00:00
DrawFlickerBox ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// make sure the drawing is actually started
2012-12-17 16:30:59 +00:00
glFlush ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// we may choose to sync to the swapbuffers before the next frame
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// stop rendering on this thread
uint64 backEndFinishTime = Sys_Microseconds ( ) ;
2017-09-03 21:17:44 +00:00
pc . totalMicroSec = backEndFinishTime - backEndStartTime ;
2012-11-26 18:58:24 +00:00
}
2019-10-28 19:06:10 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
IMGUI RENDERING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "../../libs/imgui/imgui.h"
int g_ShaderHandle = 0 , g_VertHandle = 0 , g_FragHandle = 0 ;
int g_AttribLocationTex = 0 , g_AttribLocationProjMtx = 0 ;
int g_AttribLocationPosition = 0 , g_AttribLocationUV = 0 , g_AttribLocationColor = 0 ;
unsigned int g_VboHandle = 0 , g_VaoHandle = 0 , g_ElementsHandle = 0 ;
void idRenderBackend : : ImGui_Init ( )
{
# if 1
const GLchar * vertex_shader =
" #version 330 \n "
" uniform mat4 ProjMtx; \n "
" in vec2 Position; \n "
" in vec2 UV; \n "
" in vec4 Color; \n "
" out vec2 Frag_UV; \n "
" out vec4 Frag_Color; \n "
" void main() \n "
" { \n "
" Frag_UV = UV; \n "
" Frag_Color = Color; \n "
" gl_Position = ProjMtx * vec4(Position.xy,0,1); \n "
" } \n " ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
const GLchar * fragment_shader =
" #version 330 \n "
" uniform sampler2D Texture; \n "
" in vec2 Frag_UV; \n "
" in vec4 Frag_Color; \n "
" out vec4 Out_Color; \n "
" void main() \n "
" { \n "
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st); \n "
" } \n " ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
g_ShaderHandle = glCreateProgram ( ) ;
g_VertHandle = glCreateShader ( GL_VERTEX_SHADER ) ;
g_FragHandle = glCreateShader ( GL_FRAGMENT_SHADER ) ;
glShaderSource ( g_VertHandle , 1 , & vertex_shader , 0 ) ;
glShaderSource ( g_FragHandle , 1 , & fragment_shader , 0 ) ;
glCompileShader ( g_VertHandle ) ;
glCompileShader ( g_FragHandle ) ;
glAttachShader ( g_ShaderHandle , g_VertHandle ) ;
glAttachShader ( g_ShaderHandle , g_FragHandle ) ;
glLinkProgram ( g_ShaderHandle ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
g_AttribLocationTex = glGetUniformLocation ( g_ShaderHandle , " Texture " ) ;
g_AttribLocationProjMtx = glGetUniformLocation ( g_ShaderHandle , " ProjMtx " ) ;
g_AttribLocationPosition = glGetAttribLocation ( g_ShaderHandle , " Position " ) ;
g_AttribLocationUV = glGetAttribLocation ( g_ShaderHandle , " UV " ) ;
g_AttribLocationColor = glGetAttribLocation ( g_ShaderHandle , " Color " ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glGenBuffers ( 1 , & g_VboHandle ) ;
glGenBuffers ( 1 , & g_ElementsHandle ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glGenVertexArrays ( 1 , & g_VaoHandle ) ;
glBindVertexArray ( g_VaoHandle ) ;
glBindBuffer ( GL_ARRAY_BUFFER , g_VboHandle ) ;
glEnableVertexAttribArray ( g_AttribLocationPosition ) ;
glEnableVertexAttribArray ( g_AttribLocationUV ) ;
glEnableVertexAttribArray ( g_AttribLocationColor ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
# define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
glVertexAttribPointer ( g_AttribLocationPosition , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , pos ) ) ;
glVertexAttribPointer ( g_AttribLocationUV , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , uv ) ) ;
glVertexAttribPointer ( g_AttribLocationColor , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , col ) ) ;
# undef OFFSETOF
glBindVertexArray ( 0 ) ;
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
# endif
}
void idRenderBackend : : ImGui_Shutdown ( )
{
2019-11-11 19:27:44 +00:00
if ( g_VaoHandle )
{
glDeleteVertexArrays ( 1 , & g_VaoHandle ) ;
}
if ( g_VboHandle )
{
glDeleteBuffers ( 1 , & g_VboHandle ) ;
}
if ( g_ElementsHandle )
{
glDeleteBuffers ( 1 , & g_ElementsHandle ) ;
}
2019-10-28 19:06:10 +00:00
g_VaoHandle = g_VboHandle = g_ElementsHandle = 0 ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glDetachShader ( g_ShaderHandle , g_VertHandle ) ;
glDeleteShader ( g_VertHandle ) ;
g_VertHandle = 0 ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glDetachShader ( g_ShaderHandle , g_FragHandle ) ;
glDeleteShader ( g_FragHandle ) ;
g_FragHandle = 0 ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glDeleteProgram ( g_ShaderHandle ) ;
g_ShaderHandle = 0 ;
2019-11-11 19:27:44 +00:00
2019-10-28 22:45:13 +00:00
//ImGui::GetIO().Fonts->TexID = 0;
2019-10-28 19:06:10 +00:00
}
2012-11-26 18:58:24 +00:00
2019-10-28 19:06:10 +00:00
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
// If text or lines are blurry when integrating ImGui in your engine:
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
void idRenderBackend : : ImGui_RenderDrawLists ( ImDrawData * draw_data )
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
GLint last_program , last_texture , polygon_mode [ 2 ] ;
glGetIntegerv ( GL_CURRENT_PROGRAM , & last_program ) ;
glGetIntegerv ( GL_TEXTURE_BINDING_2D , & last_texture ) ;
glGetIntegerv ( GL_POLYGON_MODE , polygon_mode ) ;
glEnable ( GL_BLEND ) ;
glBlendEquation ( GL_FUNC_ADD ) ;
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_DEPTH_TEST ) ;
glEnable ( GL_SCISSOR_TEST ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
// Setup orthographic projection matrix
const float width = ImGui : : GetIO ( ) . DisplaySize . x ;
const float height = ImGui : : GetIO ( ) . DisplaySize . y ;
const float ortho_projection [ 4 ] [ 4 ] =
{
{ 2.0f / width , 0.0f , 0.0f , 0.0f } ,
{ 0.0f , 2.0f / - height , 0.0f , 0.0f } ,
{ 0.0f , 0.0f , - 1.0f , 0.0f } ,
{ - 1.0f , 1.0f , 0.0f , 1.0f } ,
} ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glUseProgram ( g_ShaderHandle ) ;
glUniform1i ( g_AttribLocationTex , 0 ) ;
glUniformMatrix4fv ( g_AttribLocationProjMtx , 1 , GL_FALSE , & ortho_projection [ 0 ] [ 0 ] ) ;
glBindVertexArray ( g_VaoHandle ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
#if 0
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_VERTEX ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_NORMAL ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_COLOR2 ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_ST ) ;
glDisableVertexAttribArray ( PC_ATTRIB_INDEX_TANGENT ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
//glVertexAttribPointer( PC_ATTRIB_INDEX_VERTEX, 4, GL_FLOAT, GL_FALSE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_XYZW_OFFSET ) );
//glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR_OFFSET ) );
//glVertexAttribPointer( PC_ATTRIB_INDEX_COLOR2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( idShadowVertSkinned ), ( void* )( SHADOWVERTSKINNED_COLOR2_OFFSET ) );
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glEnableVertexAttribArray ( g_AttribLocationPosition ) ;
glEnableVertexAttribArray ( g_AttribLocationUV ) ;
glEnableVertexAttribArray ( g_AttribLocationColor ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
# define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
glVertexAttribPointer ( g_AttribLocationPosition , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , pos ) ) ;
glVertexAttribPointer ( g_AttribLocationUV , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , uv ) ) ;
glVertexAttribPointer ( g_AttribLocationColor , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( ImDrawVert ) , ( GLvoid * ) OFFSETOF ( ImDrawVert , col ) ) ;
# undef OFFSETOF
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
# endif
tr . backend . vertexLayout = LAYOUT_DRAW_IMGUI_VERT ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
for ( int n = 0 ; n < draw_data - > CmdListsCount ; n + + )
{
const ImDrawList * cmd_list = draw_data - > CmdLists [ n ] ;
const ImDrawIdx * idx_buffer_offset = 0 ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , g_VboHandle ) ;
glBufferData ( GL_ARRAY_BUFFER , ( GLsizeiptr ) cmd_list - > VtxBuffer . size ( ) * sizeof ( ImDrawVert ) , ( GLvoid * ) & cmd_list - > VtxBuffer . front ( ) , GL_STREAM_DRAW ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , g_ElementsHandle ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , ( GLsizeiptr ) cmd_list - > IdxBuffer . size ( ) * sizeof ( ImDrawIdx ) , ( GLvoid * ) & cmd_list - > IdxBuffer . front ( ) , GL_STREAM_DRAW ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
for ( const ImDrawCmd * pcmd = cmd_list - > CmdBuffer . begin ( ) ; pcmd ! = cmd_list - > CmdBuffer . end ( ) ; pcmd + + )
{
if ( pcmd - > UserCallback )
{
pcmd - > UserCallback ( cmd_list , pcmd ) ;
}
else
{
glBindTexture ( GL_TEXTURE_2D , ( GLuint ) ( intptr_t ) pcmd - > TextureId ) ;
glScissor ( ( int ) pcmd - > ClipRect . x , ( int ) ( height - pcmd - > ClipRect . w ) , ( int ) ( pcmd - > ClipRect . z - pcmd - > ClipRect . x ) , ( int ) ( pcmd - > ClipRect . w - pcmd - > ClipRect . y ) ) ;
glDrawElements ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , GL_UNSIGNED_SHORT , idx_buffer_offset ) ;
}
idx_buffer_offset + = pcmd - > ElemCount ;
}
}
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
// Restore modified state
//glPolygonMode( polygon_mode[0], polygon_mode[1] );
glBindVertexArray ( glConfig . global_vao ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , 0 ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
glUseProgram ( last_program ) ;
glDisable ( GL_SCISSOR_TEST ) ;
glBindTexture ( GL_TEXTURE_2D , last_texture ) ;
2019-11-11 19:27:44 +00:00
2019-10-28 19:06:10 +00:00
renderProgManager . Unbind ( ) ;
}