2019-09-07 12:37:39 +00:00
# include <cmath>
2018-10-04 08:29:23 +00:00
# include "gl4.h"
# include "rend/gles/glcache.h"
# include "rend/rend.h"
/*
Drawing and related state management
Takes vertex , textures and renders to the currently set up target
*/
static gl4PipelineShader * CurrentShader ;
extern u32 gcflip ;
static GLuint geom_fbo ;
GLuint stencilTexId ;
GLuint opaqueTexId ;
GLuint depthTexId ;
static GLuint texSamplers [ 2 ] ;
static GLuint depth_fbo ;
GLuint depthSaveTexId ;
2019-09-11 19:10:02 +00:00
static gl4PipelineShader * gl4GetProgram ( u32 cp_AlphaTest , s32 pp_ClipTestMode ,
2018-10-05 13:07:30 +00:00
u32 pp_Texture , u32 pp_UseAlpha , u32 pp_IgnoreTexA , u32 pp_ShadInstr , u32 pp_Offset ,
u32 pp_FogCtrl , bool pp_TwoVolumes , u32 pp_DepthFunc , bool pp_Gouraud , bool pp_BumpMap , bool fog_clamping , int pass )
{
2019-04-09 13:18:48 +00:00
if ( settings . rend . Rotate90 ! = gl4 . rotate90 )
{
gl4_delete_shaders ( ) ;
gl4 . rotate90 = settings . rend . Rotate90 ;
}
2018-10-05 13:07:30 +00:00
u32 rv = 0 ;
2019-09-11 19:10:02 +00:00
rv | = ( pp_ClipTestMode + 1 ) ;
2018-10-05 13:07:30 +00:00
rv < < = 1 ; rv | = cp_AlphaTest ;
rv < < = 1 ; rv | = pp_Texture ;
rv < < = 1 ; rv | = pp_UseAlpha ;
rv < < = 1 ; rv | = pp_IgnoreTexA ;
rv < < = 2 ; rv | = pp_ShadInstr ;
rv < < = 1 ; rv | = pp_Offset ;
rv < < = 2 ; rv | = pp_FogCtrl ;
rv < < = 1 ; rv | = ( int ) pp_TwoVolumes ;
rv < < = 3 ; rv | = pp_DepthFunc ;
rv < < = 1 ; rv | = ( int ) pp_Gouraud ;
rv < < = 1 ; rv | = pp_BumpMap ;
rv < < = 1 ; rv | = fog_clamping ;
rv < < = 2 ; rv | = pass ;
2019-04-04 20:26:21 +00:00
gl4PipelineShader * shader = & gl4 . shaders [ rv ] ;
if ( shader - > program = = 0 )
{
shader - > cp_AlphaTest = cp_AlphaTest ;
shader - > pp_ClipTestMode = pp_ClipTestMode ;
shader - > pp_Texture = pp_Texture ;
shader - > pp_UseAlpha = pp_UseAlpha ;
shader - > pp_IgnoreTexA = pp_IgnoreTexA ;
shader - > pp_ShadInstr = pp_ShadInstr ;
shader - > pp_Offset = pp_Offset ;
shader - > pp_FogCtrl = pp_FogCtrl ;
shader - > pp_TwoVolumes = pp_TwoVolumes ;
shader - > pp_DepthFunc = pp_DepthFunc ;
shader - > pp_Gouraud = pp_Gouraud ;
shader - > pp_BumpMap = pp_BumpMap ;
shader - > fog_clamping = fog_clamping ;
shader - > pass = pass ;
2019-04-09 13:18:48 +00:00
gl4CompilePipelineShader ( shader , settings . rend . Rotate90 ) ;
2018-10-04 13:55:41 +00:00
}
2019-04-04 20:26:21 +00:00
return shader ;
2018-10-04 13:55:41 +00:00
}
2018-10-04 08:29:23 +00:00
static void SetTextureRepeatMode ( int index , GLuint dir , u32 clamp , u32 mirror )
{
if ( clamp )
glSamplerParameteri ( texSamplers [ index ] , dir , GL_CLAMP_TO_EDGE ) ;
else
glSamplerParameteri ( texSamplers [ index ] , dir , mirror ? GL_MIRRORED_REPEAT : GL_REPEAT ) ;
}
template < u32 Type , bool SortingEnabled >
2019-07-10 20:23:26 +00:00
static void SetGPState ( const PolyParam * gp , int pass )
2018-10-04 08:29:23 +00:00
{
if ( gp - > pcw . Texture & & gp - > tsp . FilterMode > 1 )
{
gl4ShaderUniforms . trilinear_alpha = 0.25 * ( gp - > tsp . MipMapD & 0x3 ) ;
if ( gp - > tsp . FilterMode = = 2 )
// Trilinear pass A
gl4ShaderUniforms . trilinear_alpha = 1.0 - gl4ShaderUniforms . trilinear_alpha ;
}
else
gl4ShaderUniforms . trilinear_alpha = 1.0 ;
2018-10-04 10:32:26 +00:00
s32 clipping = SetTileClip ( gp - > tileclip , - 1 ) ;
2018-10-04 08:29:23 +00:00
if ( pass = = 0 )
{
2019-04-04 20:26:21 +00:00
CurrentShader = gl4GetProgram ( Type = = ListType_Punch_Through ? 1 : 0 ,
2018-10-04 13:55:41 +00:00
clipping ,
2018-10-04 08:29:23 +00:00
Type = = ListType_Punch_Through ? gp - > pcw . Texture : 0 ,
1 ,
gp - > tsp . IgnoreTexA ,
0 ,
0 ,
2 ,
false , // TODO Can PT have two different textures for area 0 and 1 ??
0 ,
false ,
false ,
false ,
pass ) ;
}
else
{
// Two volumes mode only supported for OP and PT
bool two_volumes_mode = ( gp - > tsp1 . full ! = - 1 ) & & Type ! = ListType_Translucent ;
bool color_clamp = gp - > tsp . ColorClamp & & ( pvrrc . fog_clamp_min ! = 0 | | pvrrc . fog_clamp_max ! = 0xffffffff ) ;
2019-04-04 17:26:15 +00:00
int fog_ctrl = settings . rend . Fog ? gp - > tsp . FogCtrl : 2 ;
2018-10-04 08:29:23 +00:00
int depth_func = 0 ;
if ( Type = = ListType_Translucent )
{
if ( SortingEnabled )
depth_func = 6 ; // GEQUAL
else
depth_func = gp - > isp . DepthMode ;
}
2019-04-04 20:26:21 +00:00
CurrentShader = gl4GetProgram ( Type = = ListType_Punch_Through ? 1 : 0 ,
2018-10-04 13:55:41 +00:00
clipping ,
gp - > pcw . Texture ,
gp - > tsp . UseAlpha ,
gp - > tsp . IgnoreTexA ,
gp - > tsp . ShadInstr ,
gp - > pcw . Offset ,
2019-04-04 17:26:15 +00:00
fog_ctrl ,
2018-10-04 13:55:41 +00:00
two_volumes_mode ,
depth_func ,
gp - > pcw . Gouraud ,
gp - > tcw . PixelFmt = = PixelBumpMap ,
color_clamp ,
pass ) ;
2018-10-04 08:29:23 +00:00
}
glcache . UseProgram ( CurrentShader - > program ) ;
gl4ShaderUniforms . tsp0 = gp - > tsp ;
gl4ShaderUniforms . tsp1 = gp - > tsp1 ;
gl4ShaderUniforms . tcw0 = gp - > tcw ;
gl4ShaderUniforms . tcw1 = gp - > tcw1 ;
if ( Type = = ListType_Opaque | | Type = = ListType_Punch_Through ) // TODO Can PT have a >0 and <1 alpha?
{
gl4ShaderUniforms . tsp0 . SrcInstr = 1 ;
gl4ShaderUniforms . tsp0 . DstInstr = 0 ;
gl4ShaderUniforms . tsp1 . SrcInstr = 1 ;
gl4ShaderUniforms . tsp1 . DstInstr = 0 ;
}
gl4ShaderUniforms . Set ( CurrentShader ) ;
2018-10-04 10:32:26 +00:00
SetTileClip ( gp - > tileclip , CurrentShader - > pp_ClipTest ) ;
2018-10-04 08:29:23 +00:00
//This bit control which pixels are affected
//by modvols
const u32 stencil = ( gp - > pcw . Shadow ! = 0 ) ? 0x80 : 0x0 ;
glcache . StencilFunc ( GL_ALWAYS , stencil , stencil ) ;
if ( CurrentShader - > pp_Texture )
{
for ( int i = 0 ; i < 2 ; i + + )
{
glActiveTexture ( GL_TEXTURE0 + i ) ;
GLuint texid = i = = 0 ? gp - > texid : gp - > texid1 ;
glBindTexture ( GL_TEXTURE_2D , texid = = - 1 ? 0 : texid ) ;
if ( texid ! = - 1 )
{
TSP tsp = i = = 0 ? gp - > tsp : gp - > tsp1 ;
TCW tcw = i = = 0 ? gp - > tcw : gp - > tcw1 ;
glBindSampler ( i , texSamplers [ i ] ) ;
SetTextureRepeatMode ( i , GL_TEXTURE_WRAP_S , tsp . ClampU , tsp . FlipU ) ;
SetTextureRepeatMode ( i , GL_TEXTURE_WRAP_T , tsp . ClampV , tsp . FlipV ) ;
//set texture filter mode
if ( tsp . FilterMode = = 0 )
{
//disable filtering, mipmaps
glSamplerParameteri ( texSamplers [ i ] , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glSamplerParameteri ( texSamplers [ i ] , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
}
else
{
//bilinear filtering
//PowerVR supports also trilinear via two passes, but we ignore that for now
glSamplerParameteri ( texSamplers [ i ] , GL_TEXTURE_MIN_FILTER , ( tcw . MipMapped & & settings . rend . UseMipmaps ) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR ) ;
glSamplerParameteri ( texSamplers [ i ] , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
}
}
}
glActiveTexture ( GL_TEXTURE0 ) ;
}
//set cull mode !
//cflip is required when exploding triangles for triangle sorting
//gcflip is global clip flip, needed for when rendering to texture due to mirrored Y direction
2019-07-09 13:25:15 +00:00
SetCull ( gp - > isp . CullMode ^ gcflip ) ;
2018-10-04 08:29:23 +00:00
//set Z mode, only if required
2019-07-10 20:23:26 +00:00
if ( Type = = ListType_Punch_Through | | ( pass = = 0 & & SortingEnabled ) )
2018-10-04 08:29:23 +00:00
{
2019-09-17 11:35:23 +00:00
glcache . DepthFunc ( GL_GEQUAL ) ;
2018-10-04 08:29:23 +00:00
}
2019-07-10 20:23:26 +00:00
else if ( Type = = ListType_Opaque | | ( pass = = 0 & & ! SortingEnabled ) )
2018-10-04 08:29:23 +00:00
{
glcache . DepthFunc ( Zfunction [ gp - > isp . DepthMode ] ) ;
}
// Depth buffer is updated in pass 0 (and also in pass 1 for OP PT)
if ( pass < 2 )
2019-07-07 20:13:43 +00:00
{
2019-07-09 13:25:15 +00:00
// Z Write Disable seems to be ignored for punch-through polys
// Fixes Worms World Party, Bust-a-Move 4 and Re-Volt
2019-07-07 20:13:43 +00:00
if ( Type = = ListType_Punch_Through )
glcache . DepthMask ( GL_TRUE ) ;
else
glcache . DepthMask ( ! gp - > isp . ZWriteDis ) ;
}
2018-10-04 08:29:23 +00:00
else
glcache . DepthMask ( GL_FALSE ) ;
}
2019-07-09 13:25:15 +00:00
template < u32 Type , bool SortingEnabled , bool OnlyAlwaysDepth >
2018-10-04 08:29:23 +00:00
static void DrawList ( const List < PolyParam > & gply , int first , int count , int pass )
{
PolyParam * params = & gply . head ( ) [ first ] ;
if ( count = = 0 )
return ;
//we want at least 1 PParam
while ( count - - > 0 )
{
if ( params - > count > 2 ) //this actually happens for some games. No idea why ..
{
if ( pass ! = 0 )
{
// No need to draw this one
if ( Type = = ListType_Translucent & & params - > tsp . SrcInstr = = 0 & & params - > tsp . DstInstr = = 1 )
{
params + + ;
continue ;
}
}
2019-07-09 13:25:15 +00:00
if ( OnlyAlwaysDepth & & ( params - > isp . DepthMode ! = 7 | | params - > isp . ZWriteDis ) )
2019-07-08 14:30:07 +00:00
{
params + + ;
continue ;
}
2018-10-04 08:29:23 +00:00
gl4ShaderUniforms . poly_number = params - gply . head ( ) ;
SetGPState < Type , SortingEnabled > ( params , pass ) ;
2018-12-13 09:57:51 +00:00
glDrawElements ( GL_TRIANGLE_STRIP , params - > count , GL_UNSIGNED_INT , ( GLvoid * ) ( sizeof ( u32 ) * params - > first ) ) ; glCheck ( ) ;
2018-10-04 08:29:23 +00:00
}
params + + ;
}
}
2019-02-20 18:22:24 +00:00
void gl4SetupMainVBO ( )
2018-10-04 08:29:23 +00:00
{
2019-02-20 18:22:24 +00:00
glBindVertexArray ( gl4 . vbo . main_vao ) ;
2018-10-04 08:29:23 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , gl4 . vbo . geometry ) ; glCheck ( ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , gl4 . vbo . idxs ) ; glCheck ( ) ;
//setup vertex buffers attrib pointers
glEnableVertexAttribArray ( VERTEX_POS_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_POS_ARRAY , 3 , GL_FLOAT , GL_FALSE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , x ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_COL_BASE_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_COL_BASE_ARRAY , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , col ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_COL_OFFS_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_COL_OFFS_ARRAY , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , spc ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_UV_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_UV_ARRAY , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , u ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_COL_BASE1_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_COL_BASE1_ARRAY , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , col1 ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_COL_OFFS1_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_COL_OFFS1_ARRAY , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , spc1 ) ) ; glCheck ( ) ;
glEnableVertexAttribArray ( VERTEX_UV1_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_UV1_ARRAY , 2 , GL_FLOAT , GL_FALSE , sizeof ( Vertex ) , ( void * ) offsetof ( Vertex , u1 ) ) ; glCheck ( ) ;
}
void gl4SetupModvolVBO ( )
{
2019-02-20 18:22:24 +00:00
glBindVertexArray ( gl4 . vbo . modvol_vao ) ;
2018-10-04 08:29:23 +00:00
glBindBuffer ( GL_ARRAY_BUFFER , gl4 . vbo . modvols ) ; glCheck ( ) ;
//setup vertex buffers attrib pointers
glEnableVertexAttribArray ( VERTEX_POS_ARRAY ) ; glCheck ( ) ;
glVertexAttribPointer ( VERTEX_POS_ARRAY , 3 , GL_FLOAT , GL_FALSE , sizeof ( float ) * 3 , ( void * ) 0 ) ; glCheck ( ) ;
}
static void DrawModVols ( int first , int count )
{
if ( count = = 0 | | pvrrc . modtrig . used ( ) = = 0 )
return ;
2019-02-20 18:22:24 +00:00
glBindVertexArray ( gl4 . vbo . modvol_vao ) ;
2018-10-04 08:29:23 +00:00
glcache . UseProgram ( gl4 . modvol_shader . program ) ;
2019-09-17 11:35:23 +00:00
glcache . Enable ( GL_DEPTH_TEST ) ;
2018-10-04 08:29:23 +00:00
glcache . DepthMask ( GL_FALSE ) ;
2019-09-17 11:35:23 +00:00
glcache . DepthFunc ( GL_GREATER ) ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
ModifierVolumeParam * params = & pvrrc . global_param_mvo . head ( ) [ first ] ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
int mod_base = - 1 ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
for ( u32 cmv = 0 ; cmv < count ; cmv + + )
{
ModifierVolumeParam & param = params [ cmv ] ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
if ( param . count = = 0 )
continue ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
u32 mv_mode = param . isp . DepthMode ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
if ( mod_base = = - 1 )
mod_base = param . first ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
if ( ! param . isp . VolumeLast & & mv_mode > 0 )
SetMVS_Mode ( Or , param . isp ) ; // OR'ing (open volume or quad)
else
SetMVS_Mode ( Xor , param . isp ) ; // XOR'ing (closed volume)
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
glDrawArrays ( GL_TRIANGLES , param . first * 3 , param . count * 3 ) ;
2018-10-04 08:29:23 +00:00
2019-09-17 11:35:23 +00:00
if ( mv_mode = = 1 | | mv_mode = = 2 )
{
// Sum the area
SetMVS_Mode ( mv_mode = = 1 ? Inclusion : Exclusion , param . isp ) ;
glDrawArrays ( GL_TRIANGLES , mod_base * 3 , ( param . first + param . count - mod_base ) * 3 ) ;
mod_base = - 1 ;
2018-10-04 08:29:23 +00:00
}
}
//restore states
2019-02-20 18:22:24 +00:00
glBindVertexArray ( gl4 . vbo . main_vao ) ;
2018-10-04 08:29:23 +00:00
glcache . Enable ( GL_DEPTH_TEST ) ;
glcache . DepthMask ( GL_TRUE ) ;
}
2019-06-30 09:40:42 +00:00
void renderABuffer ( bool sortFragments ) ;
2018-10-04 08:29:23 +00:00
void DrawTranslucentModVols ( int first , int count ) ;
void checkOverflowAndReset ( ) ;
2019-02-19 10:36:59 +00:00
static GLuint CreateColorFBOTexture ( int width , int height )
2018-10-04 08:29:23 +00:00
{
GLuint texId = glcache . GenTexture ( ) ;
2018-10-04 13:55:41 +00:00
glBindTexture ( GL_TEXTURE_2D , texId ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2019-02-19 10:36:59 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
2018-10-04 08:29:23 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texId , 0 ) ;
glCheck ( ) ;
return texId ;
}
2019-06-27 20:41:16 +00:00
void gl4CreateTextures ( int width , int height )
2018-10-04 08:29:23 +00:00
{
2019-06-27 20:41:16 +00:00
if ( geom_fbo = = 0 )
{
glGenFramebuffers ( 1 , & geom_fbo ) ;
}
glBindFramebuffer ( GL_FRAMEBUFFER , geom_fbo ) ;
2018-10-04 08:29:23 +00:00
stencilTexId = glcache . GenTexture ( ) ;
2018-10-04 13:55:41 +00:00
glBindTexture ( GL_TEXTURE_2D , stencilTexId ) ; glCheck ( ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_DEPTH_STENCIL_TEXTURE_MODE , GL_STENCIL_INDEX ) ; // OpenGL >= 4.3
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2018-10-04 08:29:23 +00:00
// Using glTexStorage2D instead of glTexImage2D to satisfy requirement GL_TEXTURE_IMMUTABLE_FORMAT=true, needed for glTextureView below
2019-02-19 10:36:59 +00:00
glTexStorage2D ( GL_TEXTURE_2D , 1 , GL_DEPTH32F_STENCIL8 , width , height ) ;
2018-10-04 08:29:23 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_STENCIL_ATTACHMENT , GL_TEXTURE_2D , stencilTexId , 0 ) ; glCheck ( ) ;
glCheck ( ) ;
2019-02-19 10:36:59 +00:00
opaqueTexId = CreateColorFBOTexture ( width , height ) ;
2018-10-04 08:29:23 +00:00
depthTexId = glcache . GenTexture ( ) ;
glTextureView ( depthTexId , GL_TEXTURE_2D , stencilTexId , GL_DEPTH32F_STENCIL8 , 0 , 1 , 0 , 1 ) ;
glCheck ( ) ;
2018-10-04 13:55:41 +00:00
glBindTexture ( GL_TEXTURE_2D , depthTexId ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_DEPTH_STENCIL_TEXTURE_MODE , GL_DEPTH_COMPONENT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2018-10-04 08:29:23 +00:00
glCheck ( ) ;
2019-06-27 20:41:16 +00:00
GLuint uStatus = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
verify ( uStatus = = GL_FRAMEBUFFER_COMPLETE ) ;
2018-10-04 08:29:23 +00:00
}
2019-06-27 20:41:16 +00:00
void gl4DrawStrips ( GLuint output_fbo , int width , int height )
2018-10-04 08:29:23 +00:00
{
checkOverflowAndReset ( ) ;
2019-06-27 20:41:16 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , geom_fbo ) ;
2018-10-04 08:29:23 +00:00
if ( texSamplers [ 0 ] = = 0 )
glGenSamplers ( 2 , texSamplers ) ;
glcache . DepthMask ( GL_TRUE ) ;
2019-09-17 11:35:23 +00:00
glClearDepthf ( 0.0 ) ;
2018-10-04 08:29:23 +00:00
glStencilMask ( 0xFF ) ;
2018-10-05 13:07:30 +00:00
glClear ( GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ; glCheck ( ) ;
2018-10-04 08:29:23 +00:00
//Draw the strips !
//We use sampler 0
glActiveTexture ( GL_TEXTURE0 ) ;
glcache . Disable ( GL_BLEND ) ;
glProvokingVertex ( GL_LAST_VERTEX_CONVENTION ) ;
2019-09-07 12:37:39 +00:00
RenderPass previous_pass = { } ;
2018-10-04 08:29:23 +00:00
int render_pass_count = pvrrc . render_passes . used ( ) ;
for ( int render_pass = 0 ; render_pass < render_pass_count ; render_pass + + )
{
const RenderPass & current_pass = pvrrc . render_passes . head ( ) [ render_pass ] ;
// Check if we can skip this pass, in part or completely, in case nothing is drawn (Cosmic Smash)
bool skip_op_pt = true ;
bool skip_tr = true ;
for ( int j = previous_pass . op_count ; skip_op_pt & & j < current_pass . op_count ; j + + )
{
if ( pvrrc . global_param_op . head ( ) [ j ] . count > 2 )
skip_op_pt = false ;
}
for ( int j = previous_pass . pt_count ; skip_op_pt & & j < current_pass . pt_count ; j + + )
{
if ( pvrrc . global_param_pt . head ( ) [ j ] . count > 2 )
skip_op_pt = false ;
}
for ( int j = previous_pass . tr_count ; skip_tr & & j < current_pass . tr_count ; j + + )
{
if ( pvrrc . global_param_tr . head ( ) [ j ] . count > 2 )
skip_tr = false ;
}
if ( skip_op_pt & & skip_tr )
{
previous_pass = current_pass ;
continue ;
}
2019-09-11 13:09:23 +00:00
DEBUG_LOG ( RENDERER , " Render pass %d OP %d PT %d TR %d " , render_pass + 1 ,
current_pass . op_count - previous_pass . op_count ,
current_pass . pt_count - previous_pass . pt_count ,
current_pass . tr_count - previous_pass . tr_count ) ;
2019-02-20 18:22:24 +00:00
glBindVertexArray ( gl4 . vbo . main_vao ) ;
2018-10-04 08:29:23 +00:00
if ( ! skip_op_pt )
{
//
// PASS 1: Geometry pass to update depth and stencil
//
if ( render_pass > 0 )
{
// Make a copy of the depth buffer that will be reused in pass 2
if ( depth_fbo = = 0 )
glGenFramebuffers ( 1 , & depth_fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , depth_fbo ) ;
if ( depthSaveTexId = = 0 )
{
depthSaveTexId = glcache . GenTexture ( ) ;
2018-10-04 13:55:41 +00:00
glBindTexture ( GL_TEXTURE_2D , depthSaveTexId ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_DEPTH_STENCIL_TEXTURE_MODE , GL_DEPTH_COMPONENT ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2019-06-28 15:37:06 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_DEPTH32F_STENCIL8 , max_image_width , max_image_height , 0 , GL_DEPTH_STENCIL , GL_FLOAT_32_UNSIGNED_INT_24_8_REV , NULL ) ; glCheck ( ) ;
2018-10-04 08:29:23 +00:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_STENCIL_ATTACHMENT , GL_TEXTURE_2D , depthSaveTexId , 0 ) ; glCheck ( ) ;
}
GLuint uStatus = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ;
verify ( uStatus = = GL_FRAMEBUFFER_COMPLETE ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , geom_fbo ) ;
2019-06-27 20:41:16 +00:00
glBlitFramebuffer ( 0 , 0 , width , height , 0 , 0 , width , height , GL_DEPTH_BUFFER_BIT , GL_NEAREST ) ;
2018-10-04 08:29:23 +00:00
glCheck ( ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , geom_fbo ) ;
}
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
glcache . Enable ( GL_DEPTH_TEST ) ;
glcache . DepthMask ( GL_TRUE ) ;
glcache . Enable ( GL_STENCIL_TEST ) ;
glcache . StencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
2019-07-09 13:25:15 +00:00
DrawList < ListType_Opaque , false , false > ( pvrrc . global_param_op , previous_pass . op_count , current_pass . op_count - previous_pass . op_count , 0 ) ;
DrawList < ListType_Punch_Through , false , false > ( pvrrc . global_param_pt , previous_pass . pt_count , current_pass . pt_count - previous_pass . pt_count , 0 ) ;
2018-10-04 08:29:23 +00:00
// Modifier volumes
if ( settings . rend . ModifierVolumes )
DrawModVols ( previous_pass . mvo_count , current_pass . mvo_count - previous_pass . mvo_count ) ;
//
// PASS 2: Render OP and PT to fbo
//
if ( render_pass = = 0 )
{
glcache . DepthMask ( GL_TRUE ) ;
2019-09-17 11:35:23 +00:00
glClearDepthf ( 0.0 ) ;
2018-10-04 08:29:23 +00:00
glClear ( GL_DEPTH_BUFFER_BIT ) ;
}
else
{
// Restore the depth buffer from the last render pass
// FIXME This is pretty slow apparently (CS)
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , geom_fbo ) ;
glBindFramebuffer ( GL_READ_FRAMEBUFFER , depth_fbo ) ;
2019-06-27 20:41:16 +00:00
glBlitFramebuffer ( 0 , 0 , width , height , 0 , 0 , width , height , GL_DEPTH_BUFFER_BIT , GL_NEAREST ) ;
2018-10-04 08:29:23 +00:00
glCheck ( ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , geom_fbo ) ;
}
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glcache . Disable ( GL_STENCIL_TEST ) ;
// Bind stencil buffer for the fragment shader (shadowing)
glActiveTexture ( GL_TEXTURE3 ) ;
glBindTexture ( GL_TEXTURE_2D , stencilTexId ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glCheck ( ) ;
//Opaque
2019-07-09 13:25:15 +00:00
DrawList < ListType_Opaque , false , false > ( pvrrc . global_param_op , previous_pass . op_count , current_pass . op_count - previous_pass . op_count , 1 ) ;
2018-10-04 08:29:23 +00:00
//Alpha tested
2019-07-09 13:25:15 +00:00
DrawList < ListType_Punch_Through , false , false > ( pvrrc . global_param_pt , previous_pass . pt_count , current_pass . pt_count - previous_pass . pt_count , 1 ) ;
2018-10-04 08:29:23 +00:00
// Unbind stencil
glActiveTexture ( GL_TEXTURE3 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
}
if ( ! skip_tr )
{
2019-07-08 14:30:07 +00:00
if ( ! current_pass . autosort )
{
// This pass is for HeadHunter but possibly others as well.
// The map/radar HUD is drawn is a second pass without autosort.
// The first poly drawn uses Always depth func to punch a hole in the depth buffer
// and the subsequent polys draw on top of it with Greater depth func.
// That doesn't work with this renderer because the depth test for transparent polys
// only use the opaque/pt depth, so the first poly is correctly drawn but subsequent polys are discarded.
// To work around this problem, we do a depth only pass with the transparent polys
// that use the Always depth func.
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
glcache . Enable ( GL_DEPTH_TEST ) ;
glcache . DepthMask ( GL_TRUE ) ;
2019-07-09 13:25:15 +00:00
DrawList < ListType_Translucent , false , true > ( pvrrc . global_param_tr , previous_pass . tr_count , current_pass . tr_count - previous_pass . tr_count , 0 ) ;
2019-07-08 14:30:07 +00:00
}
2018-10-04 08:29:23 +00:00
//
// PASS 3: Render TR to a-buffers
//
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
glcache . Disable ( GL_DEPTH_TEST ) ;
2019-09-15 16:30:44 +00:00
// Although the depth test is disabled and thus writes to the depth buffer are also disabled,
// AMD cards have serious issues when the depth/stencil texture is still bound to the framebuffer
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_STENCIL_ATTACHMENT , GL_TEXTURE_2D , 0 , 0 ) ;
2018-10-04 08:29:23 +00:00
glActiveTexture ( GL_TEXTURE2 ) ;
glBindTexture ( GL_TEXTURE_2D , depthTexId ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
//Alpha blended
if ( current_pass . autosort )
2019-07-09 13:25:15 +00:00
DrawList < ListType_Translucent , true , false > ( pvrrc . global_param_tr , previous_pass . tr_count , current_pass . tr_count - previous_pass . tr_count , 3 ) ; // 3 because pass 2 is no more
2018-10-04 08:29:23 +00:00
else
2019-07-09 13:25:15 +00:00
DrawList < ListType_Translucent , false , false > ( pvrrc . global_param_tr , previous_pass . tr_count , current_pass . tr_count - previous_pass . tr_count , 3 ) ; // 3 because pass 2 is no more
2018-10-04 08:29:23 +00:00
glCheck ( ) ;
// Translucent modifier volumes
if ( settings . rend . ModifierVolumes )
DrawTranslucentModVols ( previous_pass . mvo_tr_count , current_pass . mvo_tr_count - previous_pass . mvo_tr_count ) ;
2019-09-15 16:30:44 +00:00
// Rebind the depth/stencil texture to the framebuffer
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_DEPTH_STENCIL_ATTACHMENT , GL_TEXTURE_2D , stencilTexId , 0 ) ;
2018-10-04 08:29:23 +00:00
if ( render_pass < render_pass_count - 1 )
{
//
// PASS 3b: Geometry pass with TR to update the depth for the next TA render pass
//
// Unbind depth texture
glActiveTexture ( GL_TEXTURE2 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glcache . Enable ( GL_DEPTH_TEST ) ;
if ( current_pass . autosort )
2019-07-09 13:25:15 +00:00
DrawList < ListType_Translucent , true , false > ( pvrrc . global_param_tr , previous_pass . tr_count , current_pass . tr_count - previous_pass . tr_count , 0 ) ;
2018-10-04 08:29:23 +00:00
else
2019-07-09 13:25:15 +00:00
DrawList < ListType_Translucent , false , false > ( pvrrc . global_param_tr , previous_pass . tr_count , current_pass . tr_count - previous_pass . tr_count , 0 ) ;
2018-10-04 08:29:23 +00:00
//
// PASS 3c: Render a-buffer to temporary texture
//
2019-06-28 15:37:06 +00:00
GLuint texId = CreateColorFBOTexture ( max_image_width , max_image_height ) ;
2018-10-04 08:29:23 +00:00
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindSampler ( 0 , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , opaqueTexId ) ;
2019-06-30 09:40:42 +00:00
renderABuffer ( current_pass . autosort ) ;
2018-10-04 08:29:23 +00:00
glcache . DeleteTextures ( 1 , & opaqueTexId ) ;
opaqueTexId = texId ;
glCheck ( ) ;
}
}
if ( ! skip_op_pt & & render_pass < render_pass_count - 1 )
{
// Clear the stencil from this pass
glStencilMask ( 0xFF ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
}
previous_pass = current_pass ;
}
//
// PASS 4: Render a-buffers to screen
//
glBindFramebuffer ( GL_FRAMEBUFFER , output_fbo ) ; glCheck ( ) ;
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindSampler ( 0 , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , opaqueTexId ) ;
2019-06-30 09:40:42 +00:00
renderABuffer ( previous_pass . autosort ) ;
2018-10-04 08:29:23 +00:00
}
2019-06-27 20:41:16 +00:00
static void gl4_draw_quad_texture ( GLuint texture , float w , float h )
2018-10-04 08:29:23 +00:00
{
glcache . Disable ( GL_SCISSOR_TEST ) ;
glcache . Disable ( GL_DEPTH_TEST ) ;
glcache . Disable ( GL_STENCIL_TEST ) ;
glcache . Disable ( GL_CULL_FACE ) ;
glcache . Disable ( GL_BLEND ) ;
2019-09-11 19:10:02 +00:00
gl4ShaderUniforms . trilinear_alpha = 1.0 ;
2018-10-04 08:29:23 +00:00
2019-04-04 20:26:21 +00:00
CurrentShader = gl4GetProgram ( 0 ,
2018-10-04 13:55:41 +00:00
0 ,
2018-10-04 08:29:23 +00:00
1 ,
0 ,
1 ,
0 ,
0 ,
2 ,
false ,
0 ,
false ,
false ,
false ,
1 ) ;
2018-10-04 13:55:41 +00:00
glcache . UseProgram ( CurrentShader - > program ) ;
gl4ShaderUniforms . Set ( CurrentShader ) ;
2018-10-04 08:29:23 +00:00
glActiveTexture ( GL_TEXTURE0 ) ;
2019-02-19 10:36:59 +00:00
glBindTexture ( GL_TEXTURE_2D , texture ) ;
2018-10-04 08:29:23 +00:00
2019-06-30 09:40:42 +00:00
struct Vertex vertices [ ] = {
{ 0 , 0 + h , 1 , { 255 , 255 , 255 , 255 } , { 0 , 0 , 0 , 0 } , 0 , 1 } ,
{ 0 , 0 , 1 , { 255 , 255 , 255 , 255 } , { 0 , 0 , 0 , 0 } , 0 , 0 } ,
{ 0 + w , 0 + h , 1 , { 255 , 255 , 255 , 255 } , { 0 , 0 , 0 , 0 } , 1 , 1 } ,
{ 0 + w , 0 , 1 , { 255 , 255 , 255 , 255 } , { 0 , 0 , 0 , 0 } , 1 , 0 } ,
} ;
GLushort indices [ ] = { 0 , 1 , 2 , 1 , 3 } ;
2019-09-11 19:10:02 +00:00
glBindVertexArray ( gl4 . vbo . main_vao ) ;
glBindBuffer ( GL_ARRAY_BUFFER , gl4 . vbo . geometry ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , gl4 . vbo . idxs ) ;
2019-06-30 09:40:42 +00:00
glBufferData ( GL_ARRAY_BUFFER , sizeof ( vertices ) , vertices , GL_STREAM_DRAW ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , sizeof ( indices ) , indices , GL_STREAM_DRAW ) ;
glDrawElements ( GL_TRIANGLE_STRIP , 5 , GL_UNSIGNED_SHORT , ( void * ) 0 ) ;
2019-09-11 19:10:02 +00:00
glCheck ( ) ;
2019-02-19 10:36:59 +00:00
}
2018-10-04 08:29:23 +00:00
2019-02-19 10:36:59 +00:00
void gl4DrawFramebuffer ( float w , float h )
{
2019-06-27 20:41:16 +00:00
gl4_draw_quad_texture ( fbTextureId , w , h ) ;
2018-10-04 08:29:23 +00:00
glcache . DeleteTextures ( 1 , & fbTextureId ) ;
fbTextureId = 0 ;
2019-02-19 10:36:59 +00:00
}
bool gl4_render_output_framebuffer ( )
{
glViewport ( 0 , 0 , screen_width , screen_height ) ;
2019-04-07 22:21:06 +00:00
glcache . Disable ( GL_SCISSOR_TEST ) ;
if ( gl . ofbo . fbo = = 0 )
2019-02-19 10:36:59 +00:00
return false ;
2019-04-07 22:21:06 +00:00
glBindFramebuffer ( GL_READ_FRAMEBUFFER , gl . ofbo . fbo ) ;
glBindFramebuffer ( GL_DRAW_FRAMEBUFFER , 0 ) ;
glBlitFramebuffer ( 0 , 0 , gl . ofbo . width , gl . ofbo . height ,
0 , 0 , screen_width , screen_height ,
GL_COLOR_BUFFER_BIT , GL_LINEAR ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2019-02-19 10:36:59 +00:00
return true ;
2018-10-04 08:29:23 +00:00
}