2016-09-14 18:01:13 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Copyright(C) 2005-2016 Christoph Oelckers
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
2013-06-23 07:49:34 +00:00
|
|
|
/*
|
|
|
|
** gl1_renderer.cpp
|
|
|
|
** Renderer interface
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2018-05-16 21:34:52 +00:00
|
|
|
#include "gl_load/gl_system.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "files.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "m_png.h"
|
|
|
|
#include "w_wad.h"
|
2016-07-26 19:27:02 +00:00
|
|
|
#include "doomstat.h"
|
2018-04-03 22:21:25 +00:00
|
|
|
#include "i_time.h"
|
|
|
|
#include "p_effect.h"
|
|
|
|
#include "d_player.h"
|
|
|
|
#include "a_dynlight.h"
|
2018-06-03 11:59:40 +00:00
|
|
|
#include "g_game.h"
|
2018-05-05 09:44:42 +00:00
|
|
|
#include "swrenderer/r_swscene.h"
|
2018-05-13 07:48:19 +00:00
|
|
|
#include "hwrenderer/utility/hw_clock.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2018-05-16 21:21:21 +00:00
|
|
|
#include "gl_load/gl_interface.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/system/gl_framebuffer.h"
|
2018-04-25 18:33:55 +00:00
|
|
|
#include "hwrenderer/utility/hw_cvars.h"
|
2016-08-17 21:18:47 +00:00
|
|
|
#include "gl/system/gl_debug.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/renderer/gl_renderer.h"
|
|
|
|
#include "gl/renderer/gl_renderstate.h"
|
2016-07-26 19:27:02 +00:00
|
|
|
#include "gl/renderer/gl_renderbuffers.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
#include "gl/data/gl_vertexbuffer.h"
|
|
|
|
#include "gl/scene/gl_drawinfo.h"
|
2018-08-19 22:23:03 +00:00
|
|
|
#include "hwrenderer/utility/hw_vrmodes.h"
|
2018-06-13 20:37:01 +00:00
|
|
|
#include "hwrenderer/postprocessing/hw_presentshader.h"
|
|
|
|
#include "hwrenderer/postprocessing/hw_present3dRowshader.h"
|
|
|
|
#include "hwrenderer/postprocessing/hw_shadowmapshader.h"
|
2018-04-02 10:28:20 +00:00
|
|
|
#include "gl/shaders/gl_postprocessshaderinstance.h"
|
2014-08-22 21:50:38 +00:00
|
|
|
#include "gl/textures/gl_samplers.h"
|
2014-08-01 18:59:39 +00:00
|
|
|
#include "gl/dynlights/gl_lightbuffer.h"
|
2018-08-11 16:25:15 +00:00
|
|
|
#include "gl/data/gl_viewpointbuffer.h"
|
2017-07-27 07:08:42 +00:00
|
|
|
#include "r_videoscale.h"
|
2013-06-23 07:49:34 +00:00
|
|
|
|
2016-07-26 19:27:02 +00:00
|
|
|
EXTERN_CVAR(Int, screenblocks)
|
2018-04-03 22:21:25 +00:00
|
|
|
EXTERN_CVAR(Bool, cl_capfps)
|
2016-07-26 19:27:02 +00:00
|
|
|
|
2018-04-03 22:21:25 +00:00
|
|
|
extern bool NoInterpolateView;
|
2016-08-12 05:28:29 +00:00
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Renderer interface
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Initialize
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2013-08-18 13:41:52 +00:00
|
|
|
FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
|
|
|
{
|
|
|
|
framebuffer = fb;
|
|
|
|
}
|
|
|
|
|
2016-08-08 12:24:48 +00:00
|
|
|
void FGLRenderer::Initialize(int width, int height)
|
2013-06-23 07:49:34 +00:00
|
|
|
{
|
2018-06-03 11:59:40 +00:00
|
|
|
mScreenBuffers = new FGLRenderBuffers();
|
|
|
|
mSaveBuffers = new FGLRenderBuffers();
|
|
|
|
mBuffers = mScreenBuffers;
|
2016-07-26 19:27:02 +00:00
|
|
|
mPresentShader = new FPresentShader();
|
2016-10-09 17:05:50 +00:00
|
|
|
mPresent3dCheckerShader = new FPresent3DCheckerShader();
|
|
|
|
mPresent3dColumnShader = new FPresent3DColumnShader();
|
2016-10-02 16:24:37 +00:00
|
|
|
mPresent3dRowShader = new FPresent3DRowShader();
|
2017-03-01 02:33:53 +00:00
|
|
|
mShadowMapShader = new FShadowMapShader();
|
2017-07-06 03:36:01 +00:00
|
|
|
mCustomPostProcessShaders = new FCustomPostProcessShaders();
|
2016-07-26 19:27:02 +00:00
|
|
|
|
2016-09-01 09:52:52 +00:00
|
|
|
// needed for the core profile, because someone decided it was a good idea to remove the default VAO.
|
2018-06-23 11:25:23 +00:00
|
|
|
glGenQueries(1, &PortalQueryObject);
|
|
|
|
|
2018-06-08 17:12:06 +00:00
|
|
|
glGenVertexArrays(1, &mVAOID);
|
|
|
|
glBindVertexArray(mVAOID);
|
|
|
|
FGLDebug::LabelObject(GL_VERTEX_ARRAY, mVAOID, "FGLRenderer.mVAOID");
|
2016-04-26 14:26:34 +00:00
|
|
|
|
2016-08-08 12:24:48 +00:00
|
|
|
mVBO = new FFlatVertexBuffer(width, height);
|
2014-06-13 23:24:28 +00:00
|
|
|
mSkyVBO = new FSkyVertexBuffer;
|
2018-06-08 17:12:06 +00:00
|
|
|
mLights = new FLightBuffer();
|
2018-08-11 16:25:15 +00:00
|
|
|
mViewpoints = new GLViewpointBuffer;
|
2014-05-20 22:36:04 +00:00
|
|
|
gl_RenderState.SetVertexBuffer(mVBO);
|
2013-06-23 07:49:34 +00:00
|
|
|
mFBID = 0;
|
2016-04-30 13:29:22 +00:00
|
|
|
mOldFBID = 0;
|
2016-04-26 14:26:34 +00:00
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
SetupLevel();
|
|
|
|
mShaderManager = new FShaderManager;
|
2014-08-22 21:50:38 +00:00
|
|
|
mSamplerManager = new FSamplerManager;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGLRenderer::~FGLRenderer()
|
|
|
|
{
|
2018-05-21 15:52:03 +00:00
|
|
|
FlushModels();
|
2017-03-12 15:56:00 +00:00
|
|
|
AActor::DeleteAllAttachedLights();
|
2013-06-23 07:49:34 +00:00
|
|
|
FMaterial::FlushAll();
|
2018-08-11 16:25:15 +00:00
|
|
|
if (mShaderManager != nullptr) delete mShaderManager;
|
|
|
|
if (mSamplerManager != nullptr) delete mSamplerManager;
|
|
|
|
if (mVBO != nullptr) delete mVBO;
|
|
|
|
if (mSkyVBO != nullptr) delete mSkyVBO;
|
|
|
|
if (mLights != nullptr) delete mLights;
|
|
|
|
if (mViewpoints != nullptr) delete mViewpoints;
|
2013-09-03 16:29:39 +00:00
|
|
|
if (mFBID != 0) glDeleteFramebuffers(1, &mFBID);
|
2016-04-26 14:26:34 +00:00
|
|
|
if (mVAOID != 0)
|
|
|
|
{
|
|
|
|
glBindVertexArray(0);
|
|
|
|
glDeleteVertexArrays(1, &mVAOID);
|
|
|
|
}
|
2018-06-23 11:25:23 +00:00
|
|
|
if (PortalQueryObject != 0) glDeleteQueries(1, &PortalQueryObject);
|
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
if (swdrawer) delete swdrawer;
|
2016-07-26 19:27:02 +00:00
|
|
|
if (mBuffers) delete mBuffers;
|
2018-09-02 18:05:36 +00:00
|
|
|
if (mSaveBuffers) delete mSaveBuffers;
|
2016-07-26 19:27:02 +00:00
|
|
|
if (mPresentShader) delete mPresentShader;
|
2016-10-09 17:05:50 +00:00
|
|
|
if (mPresent3dCheckerShader) delete mPresent3dCheckerShader;
|
|
|
|
if (mPresent3dColumnShader) delete mPresent3dColumnShader;
|
2016-10-02 16:24:37 +00:00
|
|
|
if (mPresent3dRowShader) delete mPresent3dRowShader;
|
2017-03-01 02:33:53 +00:00
|
|
|
if (mShadowMapShader) delete mShadowMapShader;
|
2017-07-06 03:36:01 +00:00
|
|
|
delete mCustomPostProcessShaders;
|
2016-07-26 19:27:02 +00:00
|
|
|
}
|
2016-04-26 14:26:34 +00:00
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2018-04-08 06:03:46 +00:00
|
|
|
void FGLRenderer::ResetSWScene()
|
|
|
|
{
|
|
|
|
// force recreation of the SW scene drawer to ensure it gets a new set of resources.
|
|
|
|
if (swdrawer != nullptr) delete swdrawer;
|
|
|
|
swdrawer = nullptr;
|
|
|
|
}
|
|
|
|
|
2013-06-23 07:49:34 +00:00
|
|
|
void FGLRenderer::SetupLevel()
|
|
|
|
{
|
|
|
|
mVBO->CreateVBO();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool FGLRenderer::StartOffscreen()
|
|
|
|
{
|
2016-08-17 21:18:47 +00:00
|
|
|
bool firstBind = (mFBID == 0);
|
|
|
|
if (mFBID == 0)
|
|
|
|
glGenFramebuffers(1, &mFBID);
|
2016-04-30 15:09:57 +00:00
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &mOldFBID);
|
2014-06-21 13:50:32 +00:00
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mFBID);
|
2016-08-17 21:18:47 +00:00
|
|
|
if (firstBind)
|
|
|
|
FGLDebug::LabelObject(GL_FRAMEBUFFER, mFBID, "OffscreenFB");
|
2014-06-21 13:50:32 +00:00
|
|
|
return true;
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void FGLRenderer::EndOffscreen()
|
|
|
|
{
|
2016-04-30 13:29:22 +00:00
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mOldFBID);
|
2013-06-23 07:49:34 +00:00
|
|
|
}
|
|
|
|
|
2018-04-03 22:21:25 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// renders the view
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2018-05-05 09:20:37 +00:00
|
|
|
sector_t *FGLRenderer::RenderView(player_t* player)
|
2018-04-03 22:21:25 +00:00
|
|
|
{
|
|
|
|
gl_RenderState.SetVertexBuffer(mVBO);
|
|
|
|
mVBO->Reset();
|
2018-05-05 09:20:37 +00:00
|
|
|
sector_t *retsec;
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-07 21:30:28 +00:00
|
|
|
if (!V_IsHardwareRenderer())
|
2018-04-05 21:08:09 +00:00
|
|
|
{
|
|
|
|
if (swdrawer == nullptr) swdrawer = new SWSceneDrawer;
|
2018-05-05 09:20:37 +00:00
|
|
|
retsec = swdrawer->RenderView(player);
|
2018-04-05 21:08:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
checkBenchActive();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
// reset statistics counters
|
|
|
|
ResetProfilingData();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
// Get this before everything else
|
|
|
|
if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.;
|
|
|
|
else r_viewpoint.TicFrac = I_GetTimeFrac();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
P_FindParticleSubsectors();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-06-08 17:12:06 +00:00
|
|
|
mLights->Clear();
|
2018-09-02 18:05:36 +00:00
|
|
|
mViewpoints->Clear();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
// NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below.
|
|
|
|
bool saved_niv = NoInterpolateView;
|
|
|
|
NoInterpolateView = false;
|
|
|
|
// prepare all camera textures that have been used in the last frame
|
|
|
|
FCanvasTextureInfo::UpdateAll();
|
|
|
|
NoInterpolateView = saved_niv;
|
2018-04-03 22:21:25 +00:00
|
|
|
|
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
// now render the main view
|
|
|
|
float fovratio;
|
|
|
|
float ratio = r_viewwindow.WidescreenRatio;
|
|
|
|
if (r_viewwindow.WidescreenRatio >= 1.3f)
|
|
|
|
{
|
|
|
|
fovratio = 1.333333f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fovratio = ratio;
|
|
|
|
}
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-04-05 21:08:09 +00:00
|
|
|
mShadowMap.Update();
|
2018-06-20 10:57:41 +00:00
|
|
|
retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
2018-04-05 21:08:09 +00:00
|
|
|
}
|
2018-04-03 22:21:25 +00:00
|
|
|
All.Unclock();
|
2018-05-05 09:20:37 +00:00
|
|
|
return retsec;
|
2018-04-03 22:21:25 +00:00
|
|
|
}
|
|
|
|
|
2018-07-14 11:05:49 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void FGLRenderer::BindToFrameBuffer(FMaterial *mat)
|
|
|
|
{
|
|
|
|
auto BaseLayer = static_cast<FHardwareTexture*>(mat->GetLayer(0));
|
|
|
|
|
|
|
|
if (BaseLayer == nullptr)
|
|
|
|
{
|
|
|
|
// must create the hardware texture first
|
|
|
|
BaseLayer->BindOrCreate(mat->sourcetex, 0, 0, 0, 0);
|
|
|
|
FHardwareTexture::Unbind(0);
|
|
|
|
gl_RenderState.ClearLastMaterial();
|
|
|
|
}
|
|
|
|
BaseLayer->BindToFrameBuffer(mat->GetWidth(), mat->GetHeight());
|
|
|
|
}
|
|
|
|
|
2018-04-03 22:21:25 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Camera texture rendering
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV)
|
|
|
|
{
|
|
|
|
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
|
|
|
|
|
|
|
|
int width = gltex->TextureWidth();
|
|
|
|
int height = gltex->TextureHeight();
|
|
|
|
|
2018-06-08 17:12:06 +00:00
|
|
|
StartOffscreen();
|
2018-07-14 11:18:34 +00:00
|
|
|
BindToFrameBuffer(gltex);
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-05-12 15:23:56 +00:00
|
|
|
IntRect bounds;
|
2018-04-03 22:21:25 +00:00
|
|
|
bounds.left = bounds.top = 0;
|
|
|
|
bounds.width = FHardwareTexture::GetTexDimension(gltex->GetWidth());
|
|
|
|
bounds.height = FHardwareTexture::GetTexDimension(gltex->GetHeight());
|
|
|
|
|
2018-06-19 21:16:22 +00:00
|
|
|
FRenderViewpoint texvp;
|
2018-06-20 10:57:41 +00:00
|
|
|
RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
|
2018-04-03 22:21:25 +00:00
|
|
|
|
2018-06-08 17:12:06 +00:00
|
|
|
EndOffscreen();
|
2018-04-03 22:21:25 +00:00
|
|
|
|
|
|
|
tex->SetUpdated();
|
|
|
|
}
|
|
|
|
|
2018-06-20 10:29:52 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Render the view to a savegame picture
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void FGLRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
|
2018-04-03 22:21:25 +00:00
|
|
|
{
|
2018-06-20 10:29:52 +00:00
|
|
|
IntRect bounds;
|
|
|
|
bounds.left = 0;
|
|
|
|
bounds.top = 0;
|
|
|
|
bounds.width = width;
|
|
|
|
bounds.height = height;
|
|
|
|
|
2018-06-20 20:18:31 +00:00
|
|
|
// if mVBO is persistently mapped we must be sure the GPU finished reading from it before we fill it with new data.
|
2018-06-20 10:29:52 +00:00
|
|
|
glFinish();
|
|
|
|
|
|
|
|
// Switch to render buffers dimensioned for the savepic
|
|
|
|
mBuffers = mSaveBuffers;
|
|
|
|
|
|
|
|
P_FindParticleSubsectors(); // make sure that all recently spawned particles have a valid subsector.
|
|
|
|
gl_RenderState.SetVertexBuffer(mVBO);
|
|
|
|
mVBO->Reset();
|
|
|
|
mLights->Clear();
|
2018-09-02 18:05:36 +00:00
|
|
|
mViewpoints->Clear();
|
|
|
|
|
2018-06-20 10:29:52 +00:00
|
|
|
// This shouldn't overwrite the global viewpoint even for a short time.
|
|
|
|
FRenderViewpoint savevp;
|
2018-06-20 10:57:41 +00:00
|
|
|
sector_t *viewsector = RenderViewpoint(savevp, players[consoleplayer].camera, &bounds, r_viewpoint.FieldOfView.Degrees, 1.6f, 1.6f, true, false);
|
2018-06-20 10:29:52 +00:00
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
gl_RenderState.SetSoftLightLevel(-1);
|
|
|
|
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();
|
|
|
|
|
|
|
|
uint8_t * scr = (uint8_t *)M_Malloc(width * height * 3);
|
|
|
|
glReadPixels(0,0,width, height,GL_RGB,GL_UNSIGNED_BYTE,scr);
|
|
|
|
M_CreatePNG (file, scr + ((height-1) * width * 3), NULL, SS_RGB, width, height, -width * 3, Gamma);
|
|
|
|
M_Free(scr);
|
|
|
|
|
|
|
|
// Switch back the screen render buffers
|
|
|
|
screen->SetViewportRects(nullptr);
|
|
|
|
mBuffers = mScreenBuffers;
|
2018-04-03 22:21:25 +00:00
|
|
|
}
|
|
|
|
|
2018-06-20 10:29:52 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2018-04-29 18:15:19 +00:00
|
|
|
void FGLRenderer::BeginFrame()
|
|
|
|
{
|
2018-06-30 13:24:13 +00:00
|
|
|
mScreenBuffers->Setup(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);
|
|
|
|
mSaveBuffers->Setup(SAVEPICWIDTH, SAVEPICHEIGHT, SAVEPICWIDTH, SAVEPICHEIGHT);
|
2018-04-29 18:15:19 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 19:38:00 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Vertex buffer for 2D drawer
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2018-03-29 09:58:28 +00:00
|
|
|
class F2DVertexBuffer : public FSimpleVertexBuffer
|
2018-03-28 19:38:00 +00:00
|
|
|
{
|
|
|
|
uint32_t ibo_id;
|
|
|
|
|
2018-03-29 09:58:28 +00:00
|
|
|
// Make sure we can build upon FSimpleVertexBuffer.
|
2018-04-08 08:18:20 +00:00
|
|
|
static_assert(offsetof(FSimpleVertex, x) == offsetof(F2DDrawer::TwoDVertex, x), "x not aligned");
|
|
|
|
static_assert(offsetof(FSimpleVertex, u) == offsetof(F2DDrawer::TwoDVertex, u), "u not aligned");
|
|
|
|
static_assert(offsetof(FSimpleVertex, color) == offsetof(F2DDrawer::TwoDVertex, color0), "color not aligned");
|
2018-03-29 09:58:28 +00:00
|
|
|
|
2018-03-28 19:38:00 +00:00
|
|
|
public:
|
|
|
|
|
|
|
|
F2DVertexBuffer()
|
|
|
|
{
|
|
|
|
glGenBuffers(1, &ibo_id);
|
|
|
|
}
|
|
|
|
~F2DVertexBuffer()
|
|
|
|
{
|
|
|
|
if (ibo_id != 0)
|
|
|
|
{
|
|
|
|
glDeleteBuffers(1, &ibo_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount)
|
|
|
|
{
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, vertcount * sizeof(vertices[0]), vertices, GL_STREAM_DRAW);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
|
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexcount * sizeof(indices[0]), indices, GL_STREAM_DRAW);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BindVBO() override
|
|
|
|
{
|
2018-03-29 09:58:28 +00:00
|
|
|
FSimpleVertexBuffer::BindVBO();
|
2018-03-28 21:42:06 +00:00
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id);
|
2018-03-28 19:38:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// Draws the 2D stuff. This is the version for OpenGL 3 and later.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2018-04-29 18:15:19 +00:00
|
|
|
CVAR(Bool, gl_aalines, false, CVAR_ARCHIVE)
|
2018-03-30 16:14:42 +00:00
|
|
|
|
2018-03-28 19:38:00 +00:00
|
|
|
void FGLRenderer::Draw2D(F2DDrawer *drawer)
|
|
|
|
{
|
2018-05-13 07:48:19 +00:00
|
|
|
twoD.Clock();
|
2018-06-30 13:41:12 +00:00
|
|
|
FGLDebug::PushGroup("Draw2D");
|
2018-08-19 22:23:03 +00:00
|
|
|
if (VRMode::GetVRMode(true)->mEyeCount == 1)
|
|
|
|
mBuffers->BindCurrentFB();
|
2018-05-12 15:23:56 +00:00
|
|
|
const auto &mScreenViewport = screen->mScreenViewport;
|
2018-04-29 18:15:19 +00:00
|
|
|
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
2018-08-11 16:25:15 +00:00
|
|
|
GLRenderer->mViewpoints->Set2D(screen->GetWidth(), screen->GetHeight());
|
2018-09-02 10:43:13 +00:00
|
|
|
|
2018-04-29 18:15:19 +00:00
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
// Korshun: ENABLE AUTOMAP ANTIALIASING!!!
|
|
|
|
if (gl_aalines)
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glDisable(GL_MULTISAMPLE);
|
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
glLineWidth(1.0);
|
|
|
|
}
|
2018-03-30 16:14:42 +00:00
|
|
|
|
|
|
|
|
2018-03-28 19:38:00 +00:00
|
|
|
auto &vertices = drawer->mVertices;
|
|
|
|
auto &indices = drawer->mIndices;
|
|
|
|
auto &commands = drawer->mData;
|
|
|
|
|
2018-05-13 07:48:19 +00:00
|
|
|
if (commands.Size() == 0)
|
|
|
|
{
|
|
|
|
twoD.Unclock();
|
|
|
|
return;
|
|
|
|
}
|
2018-03-28 19:38:00 +00:00
|
|
|
|
|
|
|
for (auto &v : vertices)
|
|
|
|
{
|
|
|
|
// Change from BGRA to RGBA
|
|
|
|
std::swap(v.color0.r, v.color0.b);
|
|
|
|
}
|
|
|
|
auto vb = new F2DVertexBuffer;
|
|
|
|
vb->UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size());
|
|
|
|
gl_RenderState.SetVertexBuffer(vb);
|
2018-04-29 18:15:19 +00:00
|
|
|
gl_RenderState.EnableFog(false);
|
2018-03-28 19:38:00 +00:00
|
|
|
|
|
|
|
for(auto &cmd : commands)
|
|
|
|
{
|
2018-03-30 16:14:42 +00:00
|
|
|
|
|
|
|
int gltrans = -1;
|
2018-10-21 12:18:08 +00:00
|
|
|
gl_RenderState.SetRenderStyle(cmd.mRenderStyle);
|
2018-04-30 19:28:06 +00:00
|
|
|
gl_RenderState.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed));
|
2018-06-16 11:47:24 +00:00
|
|
|
gl_RenderState.EnableFog(2); // Special 2D mode 'fog'.
|
2018-03-28 19:38:00 +00:00
|
|
|
|
|
|
|
// Rather than adding remapping code, let's enforce that the constants here are equal.
|
|
|
|
gl_RenderState.SetTextureMode(cmd.mDrawMode);
|
|
|
|
if (cmd.mFlags & F2DDrawer::DTF_Scissor)
|
|
|
|
{
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
// scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates
|
2018-03-29 09:58:28 +00:00
|
|
|
// Note that the origin here is the lower left corner!
|
2018-05-12 15:23:56 +00:00
|
|
|
auto sciX = screen->ScreenToWindowX(cmd.mScissor[0]);
|
|
|
|
auto sciY = screen->ScreenToWindowY(cmd.mScissor[3]);
|
|
|
|
auto sciW = screen->ScreenToWindowX(cmd.mScissor[2]) - sciX;
|
|
|
|
auto sciH = screen->ScreenToWindowY(cmd.mScissor[1]) - sciY;
|
2018-03-29 09:58:28 +00:00
|
|
|
glScissor(sciX, sciY, sciW, sciH);
|
2018-03-28 19:38:00 +00:00
|
|
|
}
|
|
|
|
else glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
2018-06-16 11:47:24 +00:00
|
|
|
if (cmd.mSpecialColormap[0].a != 0)
|
2018-03-28 19:38:00 +00:00
|
|
|
{
|
2018-06-16 11:47:24 +00:00
|
|
|
gl_RenderState.SetTextureMode(TM_FIXEDCOLORMAP);
|
|
|
|
gl_RenderState.SetObjectColor(cmd.mSpecialColormap[0]);
|
|
|
|
gl_RenderState.SetObjectColor2(cmd.mSpecialColormap[1]);
|
2018-03-28 19:38:00 +00:00
|
|
|
}
|
2018-06-16 11:47:24 +00:00
|
|
|
gl_RenderState.SetFog(cmd.mColor1, 0);
|
2018-03-28 21:42:06 +00:00
|
|
|
gl_RenderState.SetColor(1, 1, 1, 1, cmd.mDesaturate);
|
2018-03-28 19:38:00 +00:00
|
|
|
|
2018-10-20 16:37:12 +00:00
|
|
|
gl_RenderState.AlphaFunc(Alpha_GEqual, 0.f);
|
2018-03-28 19:38:00 +00:00
|
|
|
|
2018-03-30 16:14:42 +00:00
|
|
|
if (cmd.mTexture != nullptr)
|
2018-03-28 19:38:00 +00:00
|
|
|
{
|
2018-03-30 16:14:42 +00:00
|
|
|
auto mat = FMaterial::ValidateTexture(cmd.mTexture, false);
|
|
|
|
if (mat == nullptr) continue;
|
|
|
|
|
2018-03-31 22:59:49 +00:00
|
|
|
if (gltrans == -1 && cmd.mTranslation != nullptr) gltrans = cmd.mTranslation->GetUniqueIndex();
|
2018-10-20 19:36:50 +00:00
|
|
|
gl_RenderState.ApplyMaterial(mat, cmd.mFlags & F2DDrawer::DTF_Wrap ? CLAMP_NONE : CLAMP_XY_NOMIP, -gltrans, -1);
|
2018-03-30 16:14:42 +00:00
|
|
|
gl_RenderState.EnableTexture(true);
|
|
|
|
|
|
|
|
// Canvas textures are stored upside down
|
|
|
|
if (cmd.mTexture->bHasCanvas)
|
2018-03-28 19:38:00 +00:00
|
|
|
{
|
2018-03-30 16:14:42 +00:00
|
|
|
gl_RenderState.mTextureMatrix.loadIdentity();
|
|
|
|
gl_RenderState.mTextureMatrix.scale(1.f, -1.f, 1.f);
|
|
|
|
gl_RenderState.mTextureMatrix.translate(0.f, 1.f, 0.0f);
|
|
|
|
gl_RenderState.EnableTextureMatrix(true);
|
2018-03-28 19:38:00 +00:00
|
|
|
}
|
2018-08-28 13:11:35 +00:00
|
|
|
if (cmd.mFlags & F2DDrawer::DTF_Burn)
|
|
|
|
{
|
|
|
|
gl_RenderState.SetEffect(EFF_BURN);
|
|
|
|
}
|
2018-03-30 16:14:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gl_RenderState.EnableTexture(false);
|
|
|
|
}
|
|
|
|
gl_RenderState.Apply();
|
|
|
|
|
|
|
|
switch (cmd.mType)
|
|
|
|
{
|
|
|
|
case F2DDrawer::DrawTypeTriangles:
|
|
|
|
glDrawElements(GL_TRIANGLES, cmd.mIndexCount, GL_UNSIGNED_INT, (const void *)(cmd.mIndexIndex * sizeof(unsigned int)));
|
2018-03-28 19:38:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case F2DDrawer::DrawTypeLines:
|
|
|
|
glDrawArrays(GL_LINES, cmd.mVertIndex, cmd.mVertCount);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case F2DDrawer::DrawTypePoints:
|
|
|
|
glDrawArrays(GL_POINTS, cmd.mVertIndex, cmd.mVertCount);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2018-06-16 11:47:24 +00:00
|
|
|
gl_RenderState.SetObjectColor(0xffffffff);
|
|
|
|
gl_RenderState.SetObjectColor2(0);
|
2018-03-30 16:14:42 +00:00
|
|
|
gl_RenderState.EnableTextureMatrix(false);
|
2018-08-28 13:11:35 +00:00
|
|
|
gl_RenderState.SetEffect(EFF_NONE);
|
|
|
|
|
2018-03-28 19:38:00 +00:00
|
|
|
}
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
2018-03-29 09:58:28 +00:00
|
|
|
|
2018-10-21 12:26:14 +00:00
|
|
|
gl_RenderState.SetRenderStyle(STYLE_Translucent);
|
2018-06-20 20:18:31 +00:00
|
|
|
gl_RenderState.SetVertexBuffer(mVBO);
|
2018-03-28 21:42:06 +00:00
|
|
|
gl_RenderState.EnableTexture(true);
|
2018-04-30 19:28:06 +00:00
|
|
|
gl_RenderState.EnableBrightmap(true);
|
2018-10-21 06:14:48 +00:00
|
|
|
gl_RenderState.SetTextureMode(TM_NORMAL);
|
2018-06-16 11:47:24 +00:00
|
|
|
gl_RenderState.EnableFog(false);
|
2018-03-28 22:38:31 +00:00
|
|
|
gl_RenderState.ResetColor();
|
2018-03-29 09:58:28 +00:00
|
|
|
gl_RenderState.Apply();
|
2018-03-28 19:38:00 +00:00
|
|
|
delete vb;
|
2018-06-30 13:41:12 +00:00
|
|
|
FGLDebug::PopGroup();
|
2018-05-13 07:48:19 +00:00
|
|
|
twoD.Unclock();
|
2018-03-29 09:58:28 +00:00
|
|
|
}
|