2019-10-17 07:42:11 +00:00
/*
* * glbackend . cpp
* *
* * OpenGL API abstraction
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2019 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2019-10-04 21:29:00 +00:00
# include <memory>
2020-05-30 22:01:00 +00:00
# include <assert.h>
2019-12-23 14:40:17 +00:00
# include "gl_load.h"
2019-10-06 17:32:35 +00:00
# include "glbackend.h"
2019-09-16 20:56:48 +00:00
# include "gl_samplers.h"
2019-10-05 10:28:08 +00:00
# include "gl_shader.h"
2019-10-17 18:29:58 +00:00
# include "textures.h"
# include "palette.h"
2020-04-11 21:54:33 +00:00
//#include "imgui.h"
2019-11-09 13:05:52 +00:00
# include "gamecontrol.h"
2020-04-11 21:54:33 +00:00
//#include "imgui_impl_sdl.h"
//#include "imgui_impl_opengl3.h"
2019-10-04 19:13:04 +00:00
# include "baselayer.h"
2019-12-23 18:37:40 +00:00
# include "gl_interface.h"
2019-12-28 21:36:47 +00:00
# include "v_2ddrawer.h"
# include "v_video.h"
2020-01-18 12:23:01 +00:00
# include "flatvertices.h"
2019-12-28 21:36:47 +00:00
# include "gl_renderer.h"
2020-04-26 21:17:54 +00:00
# include "build.h"
2020-05-30 22:01:00 +00:00
# include "v_draw.h"
# include "v_font.h"
2020-06-04 16:46:44 +00:00
# include "hw_viewpointuniforms.h"
2020-06-04 18:14:48 +00:00
# include "hw_viewpointbuffer.h"
# include "gl_renderstate.h"
2019-10-04 21:29:00 +00:00
2020-04-28 20:55:37 +00:00
F2DDrawer twodpsp ;
2020-06-04 16:46:44 +00:00
static int BufferLock = 0 ;
2020-04-28 20:55:37 +00:00
2019-12-31 21:53:03 +00:00
float shadediv [ MAXPALOOKUPS ] ;
2019-10-24 22:47:40 +00:00
2020-01-03 09:09:38 +00:00
static int blendstyles [ ] = { GL_ZERO , GL_ONE , GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA , GL_SRC_COLOR , GL_ONE_MINUS_SRC_COLOR , GL_DST_COLOR , GL_ONE_MINUS_DST_COLOR , GL_DST_ALPHA , GL_ONE_MINUS_DST_ALPHA } ;
static int renderops [ ] = { GL_FUNC_ADD , GL_FUNC_ADD , GL_FUNC_SUBTRACT , GL_FUNC_REVERSE_SUBTRACT } ;
2020-01-03 10:43:44 +00:00
int depthf [ ] = { GL_ALWAYS , GL_LESS , GL_EQUAL , GL_LEQUAL } ;
2020-01-03 09:09:38 +00:00
2020-01-19 22:27:59 +00:00
TArray < VSMatrix > matrixArray ;
2020-01-03 09:09:38 +00:00
2019-10-24 22:47:40 +00:00
FileReader GetResource ( const char * fn )
{
2020-04-11 21:54:33 +00:00
auto fr = fileSystem . OpenFileReader ( fn ) ;
2019-10-24 22:47:40 +00:00
if ( ! fr . isOpen ( ) )
2019-10-04 21:29:00 +00:00
{
2019-11-07 19:31:16 +00:00
I_Error ( " Fatal: '%s' not found " , fn ) ;
2019-10-04 21:29:00 +00:00
}
2019-10-24 22:47:40 +00:00
return fr ;
2019-10-04 21:29:00 +00:00
}
2019-09-23 21:33:59 +00:00
2019-09-16 17:35:04 +00:00
GLInstance GLInterface ;
2019-10-06 19:15:53 +00:00
GLInstance : : GLInstance ( )
: palmanager ( this )
{
2020-01-19 13:08:48 +00:00
VSMatrix mat ( 0 ) ;
matrixArray . Push ( mat ) ;
2019-10-06 19:15:53 +00:00
}
2020-04-11 21:54:33 +00:00
//void ImGui_Init_Backend();
//ImGuiContext* im_ctx;
2019-11-07 19:31:16 +00:00
TArray < uint8_t > ttf ;
void GLInstance : : Init ( int ydim )
2019-09-16 20:56:48 +00:00
{
2019-12-23 18:37:40 +00:00
//glinfo.bufferstorage = !!strstr(glinfo.extensions, "GL_ARB_buffer_storage");
2019-10-04 19:13:04 +00:00
glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & glinfo . maxanisotropy ) ;
2019-12-23 18:37:40 +00:00
2019-10-05 10:28:08 +00:00
new ( & renderState ) PolymostRenderState ; // reset to defaults.
2019-11-07 19:31:16 +00:00
LoadPolymostShader ( ) ;
2019-09-16 20:56:48 +00:00
}
2020-06-05 15:02:21 +00:00
auto i_data = R " (
2020-06-04 19:34:27 +00:00
# version 330
// This must match the HWViewpointUniforms struct
layout ( std140 ) uniform ViewpointUBO {
mat4 ProjectionMatrix ;
mat4 ViewMatrix ;
mat4 NormalViewMatrix ;
vec4 uCameraPos ;
vec4 uClipLine ;
float uGlobVis ; // uGlobVis = R_GetGlobVis(r_visibility) / 32.0
int uPalLightLevels ;
int uViewHeight ; // Software fuzz scaling
float uClipHeight ;
float uClipHeightDirection ;
int uShadowmapFilter ;
} ;
uniform mat4 ModelMatrix ;
uniform mat4 NormalModelMatrix ;
uniform mat4 TextureMatrix ;
uniform vec4 uDetailParms ;
2020-06-05 15:02:21 +00:00
uniform vec4 uTextureBlendColor ;
uniform vec4 uTextureModulateColor ;
uniform vec4 uTextureAddColor ;
uniform float uAlphaThreshold ;
2020-06-04 19:34:27 +00:00
) " ;
2020-06-04 18:14:48 +00:00
2019-10-05 10:28:08 +00:00
void GLInstance : : LoadPolymostShader ( )
{
2019-12-26 13:04:53 +00:00
auto fr1 = GetResource ( " engine/shaders/glsl/polymost.vp " ) ;
2019-10-05 11:38:02 +00:00
TArray < uint8_t > Vert = fr1 . Read ( ) ;
2019-12-26 13:04:53 +00:00
fr1 = GetResource ( " engine/shaders/glsl/polymost.fp " ) ;
2019-10-05 11:38:02 +00:00
TArray < uint8_t > Frag = fr1 . Read ( ) ;
2019-10-05 10:28:08 +00:00
// Zero-terminate both strings.
2019-10-05 11:38:02 +00:00
Vert . Push ( 0 ) ;
Frag . Push ( 0 ) ;
2020-06-04 18:14:48 +00:00
FStringf VertS ( " %s \n %s " , i_data , Vert . Data ( ) ) ;
FStringf FragS ( " %s \n %s " , i_data , Frag . Data ( ) ) ;
2019-10-05 10:28:08 +00:00
polymostShader = new PolymostShader ( ) ;
2020-06-04 18:14:48 +00:00
polymostShader - > Load ( " PolymostShader " , ( const char * ) VertS . GetChars ( ) , ( const char * ) FragS . GetChars ( ) ) ;
2019-10-05 10:28:08 +00:00
SetPolymostShader ( ) ;
}
2019-10-04 16:12:03 +00:00
void GLInstance : : InitGLState ( int fogmode , int multisample )
{
glShadeModel ( GL_SMOOTH ) ; // GL_FLAT
glEnable ( GL_TEXTURE_2D ) ;
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
glPixelStorei ( GL_UNPACK_ALIGNMENT , 1 ) ;
if ( multisample > 0 )
{
2019-12-23 14:40:17 +00:00
//glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
2019-10-04 16:12:03 +00:00
glEnable ( GL_MULTISAMPLE ) ;
}
glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & maxTextureSize ) ;
2019-12-28 21:36:47 +00:00
// This is a bad place to call this but without deconstructing the entire render loops in all front ends there is no way to have a well defined spot for this stuff.
// Before doing that the backend needs to work in some fashion, so we have to make sure everything is set up when the first render call is performed.
screen - > BeginFrame ( ) ;
2020-01-03 17:34:43 +00:00
bool useSSAO = ( gl_ssao ! = 0 ) ;
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( useSSAO ) ;
2020-01-18 12:23:01 +00:00
ClearBufferState ( ) ;
2019-12-28 21:36:47 +00:00
}
2019-09-16 20:56:48 +00:00
void GLInstance : : Deinit ( )
{
2019-12-23 19:03:03 +00:00
#if 0
2019-11-07 19:31:16 +00:00
if ( im_ctx )
{
ImGui_ImplOpenGL3_Shutdown ( ) ;
ImGui_ImplSDL2_Shutdown ( ) ;
ImGui : : DestroyContext ( im_ctx ) ;
}
2019-12-23 19:03:03 +00:00
# endif
2019-10-05 10:28:08 +00:00
if ( polymostShader ) delete polymostShader ;
polymostShader = nullptr ;
activeShader = nullptr ;
2020-05-24 22:31:05 +00:00
palmanager . DeleteAll ( ) ;
2019-10-06 22:07:45 +00:00
lastPalswapIndex = - 1 ;
2019-09-16 20:56:48 +00:00
}
2020-01-02 22:15:16 +00:00
2020-05-28 23:03:01 +00:00
OpenGLRenderer : : FHardwareTexture * GLInstance : : NewTexture ( int numchannels )
2020-01-02 22:15:16 +00:00
{
2020-05-28 23:03:01 +00:00
return new OpenGLRenderer : : FHardwareTexture ( numchannels ) ;
2020-01-02 22:15:16 +00:00
}
2020-01-05 08:38:44 +00:00
void GLInstance : : ResetFrame ( )
{
GLState s ;
lastState = s ; // Back to defaults.
lastState . Style . BlendOp = - 1 ; // invalidate. This forces a reset for the next operation
}
2020-01-18 21:41:08 +00:00
void GLInstance : : SetVertexBuffer ( IVertexBuffer * vb , int offset1 , int offset2 )
2020-01-18 12:23:01 +00:00
{
2020-01-18 21:41:08 +00:00
int o [ ] = { offset1 , offset2 } ;
static_cast < OpenGLRenderer : : GLVertexBuffer * > ( vb ) - > Bind ( o ) ;
}
2020-01-18 12:23:01 +00:00
2020-01-18 21:41:08 +00:00
void GLInstance : : SetIndexBuffer ( IIndexBuffer * vb )
{
if ( vb ) static_cast < OpenGLRenderer : : GLIndexBuffer * > ( vb ) - > Bind ( ) ;
else glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ) ;
2020-01-18 12:23:01 +00:00
}
2020-01-18 21:41:08 +00:00
void GLInstance : : ClearBufferState ( )
2019-09-16 17:35:04 +00:00
{
2020-01-18 21:41:08 +00:00
SetVertexBuffer ( screen - > mVertexData - > GetBufferObjects ( ) . first , 0 , 0 ) ;
SetIndexBuffer ( nullptr ) ;
2019-09-16 17:35:04 +00:00
}
2020-01-18 21:41:08 +00:00
2020-05-31 08:24:04 +00:00
static GLint primtypes [ ] = { GL_POINTS , GL_LINES , GL_TRIANGLES , GL_TRIANGLE_FAN , GL_TRIANGLE_STRIP } ;
2019-09-16 17:35:04 +00:00
2020-01-18 12:23:01 +00:00
2020-01-18 21:41:08 +00:00
void GLInstance : : Draw ( EDrawType type , size_t start , size_t count )
{
2020-06-04 16:46:44 +00:00
assert ( BufferLock > 0 ) ;
2020-04-11 22:21:35 +00:00
applyMapFog ( ) ;
2020-01-18 21:41:08 +00:00
renderState . vindex = start ;
renderState . vcount = count ;
renderState . primtype = type ;
rendercommands . Push ( renderState ) ;
2020-04-11 22:21:35 +00:00
clearMapFog ( ) ;
2020-01-18 21:41:08 +00:00
renderState . StateFlags & = ~ ( STF_CLEARCOLOR | STF_CLEARDEPTH | STF_VIEWPORTSET | STF_SCISSORSET ) ;
2020-01-18 12:23:01 +00:00
}
2020-01-18 21:41:08 +00:00
void GLInstance : : DrawElement ( EDrawType type , size_t start , size_t count , PolymostRenderState & renderState )
2019-09-16 17:35:04 +00:00
{
2019-10-10 19:24:09 +00:00
if ( activeShader = = polymostShader )
{
2020-01-03 10:43:44 +00:00
glVertexAttrib4fv ( 2 , renderState . Color ) ;
if ( renderState . Color [ 3 ] ! = 1.f ) renderState . Flags & = ~ RF_Brightmapping ; // The way the colormaps are set up means that brightmaps cannot be used on translucent content at all.
2020-01-02 22:15:16 +00:00
renderState . Apply ( polymostShader , lastState ) ;
2019-10-10 19:24:09 +00:00
}
2020-05-31 08:24:04 +00:00
if ( type ! = DT_Lines )
2019-11-05 22:35:38 +00:00
{
glDrawElements ( primtypes [ type ] , count , GL_UNSIGNED_INT , ( void * ) ( intptr_t ) ( start * sizeof ( uint32_t ) ) ) ;
2019-09-16 17:35:04 +00:00
}
2019-12-31 18:02:55 +00:00
else
{
glDrawArrays ( primtypes [ type ] , start , count ) ;
}
2020-01-18 21:41:08 +00:00
}
void GLInstance : : DoDraw ( )
{
for ( auto & rs : rendercommands )
2020-01-03 22:38:50 +00:00
{
2020-01-18 21:41:08 +00:00
glVertexAttrib4fv ( 2 , rs . Color ) ;
if ( rs . Color [ 3 ] ! = 1.f ) rs . Flags & = ~ RF_Brightmapping ; // The way the colormaps are set up means that brightmaps cannot be used on translucent content at all.
rs . Apply ( polymostShader , lastState ) ;
glDrawArrays ( primtypes [ rs . primtype ] , rs . vindex , rs . vcount ) ;
2020-01-03 22:38:50 +00:00
}
2020-01-18 21:41:08 +00:00
rendercommands . Clear ( ) ;
2020-01-19 13:08:48 +00:00
matrixArray . Resize ( 1 ) ;
2019-09-16 17:35:04 +00:00
}
2019-09-16 20:56:48 +00:00
2019-10-04 16:12:03 +00:00
2020-01-19 13:08:48 +00:00
int GLInstance : : SetMatrix ( int num , const VSMatrix * mat )
2019-10-04 16:12:03 +00:00
{
2020-01-19 13:08:48 +00:00
int r = renderState . matrixIndex [ num ] ;
2020-01-03 22:38:50 +00:00
renderState . matrixIndex [ num ] = matrixArray . Size ( ) ;
matrixArray . Push ( * mat ) ;
2020-01-19 13:08:48 +00:00
return r ;
2019-10-04 16:12:03 +00:00
}
2020-06-04 16:46:44 +00:00
void GLInstance : : SetIdentityMatrix ( int num )
{
renderState . matrixIndex [ num ] = 0 ;
}
2019-10-04 19:13:04 +00:00
void GLInstance : : ReadPixels ( int xdim , int ydim , uint8_t * buffer )
{
glReadPixels ( 0 , 0 , xdim , ydim , GL_RGB , GL_UNSIGNED_BYTE , buffer ) ;
2019-10-05 10:28:08 +00:00
}
void GLInstance : : SetPolymostShader ( )
{
if ( activeShader ! = polymostShader )
{
polymostShader - > Bind ( ) ;
activeShader = polymostShader ;
}
}
2019-10-06 19:15:53 +00:00
void GLInstance : : SetPalette ( int index )
{
palmanager . BindPalette ( index ) ;
}
2019-10-05 10:28:08 +00:00
2019-10-07 20:11:09 +00:00
void GLInstance : : SetPalswap ( int index )
{
2019-10-07 23:08:08 +00:00
palmanager . BindPalswap ( index ) ;
2020-06-04 18:14:48 +00:00
renderState . ShadeDiv = shadediv [ index ] = = 0 ? 1.f / ( numshades - 2 ) : shadediv [ index ] ;
2019-10-07 20:11:09 +00:00
}
2019-11-07 19:31:16 +00:00
void GLInstance : : DrawImGui ( ImDrawData * data )
{
2019-12-23 19:03:03 +00:00
#if 0
2019-11-07 19:31:16 +00:00
ImGui_ImplOpenGL3_RenderDrawData ( data ) ;
2019-12-23 19:03:03 +00:00
# endif
2019-11-07 19:31:16 +00:00
}
2020-01-04 22:58:26 +00:00
2020-05-30 19:45:17 +00:00
//===========================================================================
//
// Binds a texture to the renderer
//
//===========================================================================
void PolymostRenderState : : ApplyMaterial ( FMaterial * mat , int clampmode , int translation , int overrideshader )
{
auto tex = mat - > Source ( ) ;
//mEffectState = overrideshader >= 0 ? overrideshader : mat->GetShaderIndex();
//mShaderTimer = tex->GetShaderSpeed();
//SetSpecular(tex->GetGlossiness(), tex->GetSpecularLevel());
//if (tex->isHardwareCanvas()) static_cast<FCanvasTexture*>(tex->GetTexture())->NeedUpdate();
clampmode = tex - > GetClampMode ( clampmode ) ;
// avoid rebinding the same texture multiple times.
//if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return;
#if 0
lastMaterial = mat ;
lastClamp = clampmode ;
lastTranslation = translation ;
# endif
int scf = 0 ;
if ( Flags & RF_UsePalette )
{
scf | = CTF_Indexed ;
translation = - 1 ;
}
int usebright = false ;
int maxbound = 0 ;
int numLayers = mat - > NumLayers ( ) ;
MaterialLayerInfo * layer ;
auto base = static_cast < OpenGLRenderer : : FHardwareTexture * > ( mat - > GetLayer ( 0 , translation , & layer ) ) ;
scf | = layer - > scaleFlags ;
2020-05-31 10:23:35 +00:00
if ( base - > BindOrCreate ( layer - > layerTexture , 0 , layer - > clampflags = = - 1 ? clampmode : layer - > clampflags , translation , scf ) )
2020-05-30 19:45:17 +00:00
{
for ( int i = 1 ; i < numLayers ; i + + )
{
auto systex = static_cast < OpenGLRenderer : : FHardwareTexture * > ( mat - > GetLayer ( i , 0 , & layer ) ) ;
// fixme: Upscale flags must be disabled for certain layers.
2020-05-31 10:23:35 +00:00
systex - > BindOrCreate ( layer - > layerTexture , i , layer - > clampflags = = - 1 ? clampmode : layer - > clampflags , 0 , layer - > scaleFlags ) ;
2020-05-30 19:45:17 +00:00
maxbound = i ;
}
}
2020-05-31 10:23:35 +00:00
2020-05-30 19:45:17 +00:00
// The palette lookup must be done manually.
#if 0
// unbind everything from the last texture that's still active
for ( int i = maxbound + 1 ; i < = 16 /*maxBoundMaterial*/ ; i + + )
{
OpenGLRenderer : : FHardwareTexture : : Unbind ( i ) ;
//maxBoundMaterial = maxbound;
}
# endif
}
2020-01-03 09:09:38 +00:00
void PolymostRenderState : : Apply ( PolymostShader * shader , GLState & oldState )
2019-10-05 10:28:08 +00:00
{
2020-05-30 18:55:29 +00:00
if ( ! OpenGLRenderer : : GLRenderer ) return ;
auto sm = OpenGLRenderer : : GLRenderer - > mSamplerManager ;
2020-05-30 19:45:17 +00:00
2020-01-04 22:58:26 +00:00
bool reset = false ;
2020-05-30 19:45:17 +00:00
if ( mMaterial . mChanged )
2020-01-04 22:58:26 +00:00
{
2020-05-30 19:45:17 +00:00
mMaterial . mChanged = false ;
ApplyMaterial ( mMaterial . mMaterial , mMaterial . mClampMode , mMaterial . mTranslation , mMaterial . mOverrideShader ) ;
2020-06-04 19:34:27 +00:00
float buffer [ ] = { mMaterial . mMaterial - > GetDetailScale ( ) . X , mMaterial . mMaterial - > GetDetailScale ( ) . Y , 1.f , 0.f } ;
shader - > DetailParms . Set ( buffer ) ;
2020-01-04 22:58:26 +00:00
}
2020-05-30 19:45:17 +00:00
2020-05-30 18:55:29 +00:00
if ( PaletteTexture ! = nullptr )
{
PaletteTexture - > Bind ( 4 , false ) ;
sm - > Bind ( 4 , CLAMP_NOFILTER , - 1 ) ;
}
if ( LookupTexture ! = nullptr )
{
LookupTexture - > Bind ( 5 , false ) ;
sm - > Bind ( 5 , CLAMP_NOFILTER , - 1 ) ;
}
glActiveTexture ( GL_TEXTURE0 ) ;
2020-01-03 09:09:38 +00:00
if ( StateFlags ! = oldState . Flags )
2020-01-02 22:22:59 +00:00
{
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_DEPTHTEST )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_DEPTHTEST ) glEnable ( GL_DEPTH_TEST ) ;
else glDisable ( GL_DEPTH_TEST ) ;
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_BLEND )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_BLEND ) glEnable ( GL_BLEND ) ;
else glDisable ( GL_BLEND ) ;
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_MULTISAMPLE )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_MULTISAMPLE ) glEnable ( GL_MULTISAMPLE ) ;
else glDisable ( GL_MULTISAMPLE ) ;
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & ( STF_STENCILTEST | STF_STENCILWRITE ) )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_STENCILWRITE )
{
glEnable ( GL_STENCIL_TEST ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
glStencilOp ( GL_REPLACE , GL_REPLACE , GL_REPLACE ) ;
glStencilFunc ( GL_ALWAYS , 1 /*value*/ , 0xFF ) ;
}
else if ( StateFlags & STF_STENCILTEST )
{
glEnable ( GL_STENCIL_TEST ) ;
glStencilFunc ( GL_EQUAL , 1 /*value*/ , 0xFF ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_KEEP ) ;
}
else
{
glDisable ( GL_STENCIL_TEST ) ;
}
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & ( STF_CULLCW | STF_CULLCCW ) )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & ( STF_CULLCW | STF_CULLCCW ) )
{
glFrontFace ( StateFlags & STF_CULLCW ? GL_CW : GL_CCW ) ;
glEnable ( GL_CULL_FACE ) ;
glCullFace ( GL_BACK ) ; // Cull_Front is not being used.
}
else
{
glDisable ( GL_CULL_FACE ) ;
}
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_COLORMASK )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_COLORMASK ) glColorMask ( 1 , 1 , 1 , 1 ) ;
else glColorMask ( 0 , 0 , 0 , 0 ) ;
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_DEPTHMASK )
2020-01-02 22:22:59 +00:00
{
if ( StateFlags & STF_DEPTHMASK ) glDepthMask ( 1 ) ;
else glDepthMask ( 0 ) ;
}
2020-01-03 09:09:38 +00:00
if ( ( StateFlags ^ oldState . Flags ) & STF_WIREFRAME )
2020-01-02 22:22:59 +00:00
{
glPolygonMode ( GL_FRONT_AND_BACK , ( StateFlags & STF_WIREFRAME ) ? GL_LINE : GL_FILL ) ;
}
2020-01-02 22:56:35 +00:00
if ( StateFlags & ( STF_CLEARCOLOR | STF_CLEARDEPTH ) )
{
glClearColor ( ClearColor . r / 255.f , ClearColor . g / 255.f , ClearColor . b / 255.f , 1.f ) ;
int bit = 0 ;
if ( StateFlags & STF_CLEARCOLOR ) bit | = GL_COLOR_BUFFER_BIT ;
if ( StateFlags & STF_CLEARDEPTH ) bit | = GL_DEPTH_BUFFER_BIT ;
glClear ( bit ) ;
}
2020-01-03 09:48:01 +00:00
if ( StateFlags & STF_VIEWPORTSET )
{
glViewport ( vp_x , vp_y , vp_w , vp_h ) ;
}
if ( StateFlags & STF_SCISSORSET )
{
2020-01-05 09:21:34 +00:00
if ( sc_x > SHRT_MIN )
2020-01-03 09:48:01 +00:00
{
glScissor ( sc_x , sc_y , sc_w , sc_h ) ;
glEnable ( GL_SCISSOR_TEST ) ;
}
else
glDisable ( GL_SCISSOR_TEST ) ;
}
2020-02-06 17:43:27 +00:00
if ( mBias . mChanged )
{
if ( mBias . mFactor = = 0 & & mBias . mUnits = = 0 )
{
glDisable ( GL_POLYGON_OFFSET_FILL ) ;
}
else
{
glEnable ( GL_POLYGON_OFFSET_FILL ) ;
}
glPolygonOffset ( mBias . mFactor , mBias . mUnits ) ;
mBias . mChanged = false ;
}
2020-01-03 09:48:01 +00:00
StateFlags & = ~ ( STF_CLEARCOLOR | STF_CLEARDEPTH | STF_VIEWPORTSET | STF_SCISSORSET ) ;
2020-01-03 09:09:38 +00:00
oldState . Flags = StateFlags ;
}
if ( Style ! = oldState . Style )
{
glBlendFunc ( blendstyles [ Style . SrcAlpha ] , blendstyles [ Style . DestAlpha ] ) ;
if ( Style . BlendOp ! = oldState . Style . BlendOp ) glBlendEquation ( renderops [ Style . BlendOp ] ) ;
oldState . Style = Style ;
// Flags are not being checked yet, the current shader has no implementation for them.
2020-01-02 22:22:59 +00:00
}
2020-01-03 10:43:44 +00:00
if ( DepthFunc ! = oldState . DepthFunc )
{
glDepthFunc ( depthf [ DepthFunc ] ) ;
oldState . DepthFunc = DepthFunc ;
}
2019-11-10 18:42:26 +00:00
// Disable brightmaps if non-black fog is used.
if ( ! ( Flags & RF_FogDisabled ) & & ! FogColor . isBlack ( ) ) Flags & = ~ RF_Brightmapping ;
2019-10-19 20:46:37 +00:00
shader - > Flags . Set ( Flags ) ;
2019-10-05 10:28:08 +00:00
shader - > Shade . Set ( Shade ) ;
2019-10-19 23:14:48 +00:00
shader - > ShadeDiv . Set ( ShadeDiv ) ;
2019-10-05 10:28:08 +00:00
shader - > VisFactor . Set ( VisFactor ) ;
2019-10-19 20:46:37 +00:00
shader - > Flags . Set ( Flags ) ;
2019-10-05 10:28:08 +00:00
shader - > NPOTEmulationFactor . Set ( NPOTEmulationFactor ) ;
shader - > NPOTEmulationXOffset . Set ( NPOTEmulationXOffset ) ;
2019-11-10 09:01:31 +00:00
shader - > AlphaThreshold . Set ( AlphaTest ? AlphaThreshold : - 1.f ) ;
2019-10-05 10:28:08 +00:00
shader - > Brightness . Set ( Brightness ) ;
2019-10-06 10:42:35 +00:00
shader - > FogColor . Set ( FogColor ) ;
2020-06-05 15:02:21 +00:00
FVector4 addcol ( 0 , 0 , 0 , 0 ) ;
FVector4 modcol ( fullscreenTint . r / 255.f , fullscreenTint . g / 255.f , fullscreenTint . b / 255.f , 0 ) ;
FVector4 blendcol ( 0 , 0 , 0 , 0 ) ;
int flags = 0 ;
if ( fullscreenTint ! = 0xffffff ) flags | = 16 ;
if ( hictint_flags ! = - 1 )
{
flags | = 16 ;
if ( hictint_flags & TINTF_COLORIZE )
{
modcol . X * = hictint . r / 64.f ;
modcol . Y * = hictint . g / 64.f ;
modcol . Z * = hictint . b / 64.f ;
}
if ( hictint_flags & TINTF_GRAYSCALE )
modcol . W = 1.f ;
if ( hictint_flags & TINTF_INVERT )
flags | = 8 ;
if ( hictint_flags & TINTF_BLENDMASK )
flags | = ( ( hictint_flags & TINTF_BLENDMASK ) > > 6 ) + 1 ;
addcol . W = flags ;
}
shader - > muTextureAddColor . Set ( & addcol [ 0 ] ) ;
shader - > muTextureModulateColor . Set ( & modcol [ 0 ] ) ;
shader - > muTextureBlendColor . Set ( & blendcol [ 0 ] ) ;
2020-01-19 15:06:31 +00:00
if ( matrixIndex [ Matrix_Model ] ! = - 1 )
shader - > ModelMatrix . Set ( matrixArray [ matrixIndex [ Matrix_Model ] ] . get ( ) ) ;
2020-06-04 18:14:48 +00:00
2020-01-03 22:38:50 +00:00
memset ( matrixIndex , - 1 , sizeof ( matrixIndex ) ) ;
2019-10-05 10:28:08 +00:00
}
2020-04-26 21:17:54 +00:00
//===========================================================================
//
// Render the view to a savegame picture
//
//===========================================================================
void WriteSavePic ( FileWriter * file , int width , int height )
{
IntRect bounds ;
bounds . left = 0 ;
bounds . top = 0 ;
bounds . width = width ;
bounds . height = height ;
// we must be sure the GPU finished reading from the buffer before we fill it with new data.
glFinish ( ) ;
2020-05-31 08:53:11 +00:00
screen - > mVertexData - > Reset ( ) ;
2020-04-26 21:17:54 +00:00
// Switch to render buffers dimensioned for the savepic
OpenGLRenderer : : GLRenderer - > mBuffers = OpenGLRenderer : : GLRenderer - > mSaveBuffers ;
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( false ) ;
screen - > SetViewportRects ( & bounds ) ;
int oldx = xdim ;
int oldy = ydim ;
auto oldwindowxy1 = windowxy1 ;
auto oldwindowxy2 = windowxy2 ;
xdim = width ;
ydim = height ;
videoSetViewableArea ( 0 , 0 , width - 1 , height - 1 ) ;
renderSetAspect ( 65536 , 65536 ) ;
bool didit = gi - > GenerateSavePic ( ) ;
xdim = oldx ;
ydim = oldy ;
videoSetViewableArea ( oldwindowxy1 . x , oldwindowxy1 . y , oldwindowxy2 . x , oldwindowxy2 . y ) ;
// The 2D drawers can contain some garbage from the dirty render setup. Get rid of that first.
2020-05-30 22:01:00 +00:00
twod - > Clear ( ) ;
2020-04-26 21:17:54 +00:00
twodpsp . Clear ( ) ;
OpenGLRenderer : : GLRenderer - > CopyToBackbuffer ( & bounds , false ) ;
// strictly speaking not needed as the glReadPixels should block until the scene is rendered, but this is to safeguard against shitty drivers
glFinish ( ) ;
2020-05-31 08:53:11 +00:00
screen - > mVertexData - > Reset ( ) ;
2020-04-26 21:17:54 +00:00
if ( didit )
{
int numpixels = width * height ;
uint8_t * scr = ( uint8_t * ) Xmalloc ( numpixels * 3 ) ;
glReadPixels ( 0 , 0 , width , height , GL_RGB , GL_UNSIGNED_BYTE , scr ) ;
M_CreatePNG ( file , scr + ( ( height - 1 ) * width * 3 ) , nullptr , SS_RGB , width , height , - width * 3 , vid_gamma ) ;
M_FinishPNG ( file ) ;
Xfree ( scr ) ;
}
// Switch back the screen render buffers
screen - > SetViewportRects ( nullptr ) ;
OpenGLRenderer : : GLRenderer - > mBuffers = OpenGLRenderer : : GLRenderer - > mScreenBuffers ;
bool useSSAO = ( gl_ssao ! = 0 ) ;
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( useSSAO ) ;
}
2020-06-04 16:46:44 +00:00
static HWViewpointUniforms vp ;
void renderSetProjectionMatrix ( const float * p )
{
if ( p )
{
vp . mProjectionMatrix . loadMatrix ( p ) ;
GLInterface . mProjectionM5 = p [ 5 ] ;
}
else vp . mProjectionMatrix . loadIdentity ( ) ;
}
void renderSetViewMatrix ( const float * p )
{
if ( p ) vp . mViewMatrix . loadMatrix ( p ) ;
else vp . mViewMatrix . loadIdentity ( ) ;
}
2020-05-30 22:01:00 +00:00
2020-06-05 17:06:31 +00:00
void renderSetVisibility ( float vis )
{
vp . mGlobVis = vis ;
}
2020-05-30 22:01:00 +00:00
void renderBeginScene ( )
{
if ( videoGetRenderMode ( ) < REND_POLYMOST ) return ;
2020-06-04 16:46:44 +00:00
assert ( BufferLock = = 0 ) ;
2020-06-04 18:14:48 +00:00
vp . mPalLightLevels = numshades ;
screen - > mViewpoints - > SetViewpoint ( OpenGLRenderer : : gl_RenderState , & vp ) ;
2020-06-04 16:46:44 +00:00
2020-05-30 22:01:00 +00:00
if ( BufferLock + + = = 0 )
{
screen - > mVertexData - > Map ( ) ;
}
}
void renderFinishScene ( )
{
if ( videoGetRenderMode ( ) < REND_POLYMOST ) return ;
2020-06-04 16:46:44 +00:00
assert ( BufferLock = = 1 ) ;
2020-05-30 22:01:00 +00:00
if ( - - BufferLock = = 0 )
{
screen - > mVertexData - > Unmap ( ) ;
GLInterface . DoDraw ( ) ;
}
}
//==========================================================================
//
// DFrameBuffer :: DrawRateStuff
//
// Draws the fps counter, dot ticker, and palette debug.
//
//==========================================================================
CVAR ( Bool , vid_fps , false , 0 )
void DrawRateStuff ( )
{
// Draws frame time and cumulative fps
if ( vid_fps )
{
FString fpsbuff = gi - > statFPS ( ) ;
int textScale = active_con_scale ( twod ) ;
int rate_x = screen - > GetWidth ( ) / textScale - NewConsoleFont - > StringWidth ( & fpsbuff [ 0 ] ) ;
twod - > AddColorOnlyQuad ( rate_x * textScale , 0 , screen - > GetWidth ( ) , NewConsoleFont - > GetHeight ( ) * textScale , MAKEARGB ( 255 , 0 , 0 , 0 ) ) ;
DrawText ( twod , NewConsoleFont , CR_WHITE , rate_x , 0 , ( char * ) & fpsbuff [ 0 ] ,
DTA_VirtualWidth , screen - > GetWidth ( ) / textScale ,
DTA_VirtualHeight , screen - > GetHeight ( ) / textScale ,
DTA_KeepRatio , true , TAG_DONE ) ;
}
}
2020-04-28 20:55:37 +00:00
void videoShowFrame ( int32_t w )
{
static GLenum buffers [ ] = { GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2 } ;
if ( gl_ssao )
{
glDrawBuffers ( 1 , buffers ) ;
OpenGLRenderer : : GLRenderer - > AmbientOccludeScene ( GLInterface . GetProjectionM5 ( ) ) ;
glViewport ( screen - > mSceneViewport . left , screen - > mSceneViewport . top , screen - > mSceneViewport . width , screen - > mSceneViewport . height ) ;
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( true ) ;
glDrawBuffers ( 3 , buffers ) ;
// To do: the translucent part of the scene should be drawn here
glDrawBuffers ( 1 , buffers ) ;
}
OpenGLRenderer : : GLRenderer - > mBuffers - > BlitSceneToTexture ( ) ; // Copy the resulting scene to the current post process texture
screen - > PostProcessScene ( false , 0 , [ ] ( ) {
GLInterface . Draw2D ( & twodpsp ) ; // draws the weapon sprites
} ) ;
screen - > Update ( ) ;
// After finishing the frame, reset everything for the next frame. This needs to be done better.
screen - > BeginFrame ( ) ;
if ( gl_ssao )
{
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( true ) ;
glDrawBuffers ( 3 , buffers ) ;
}
else
{
OpenGLRenderer : : GLRenderer - > mBuffers - > BindSceneFB ( false ) ;
}
twodpsp . Clear ( ) ;
twod - > Clear ( ) ;
GLInterface . ResetFrame ( ) ;
}