From def3ad7533693978b9a546967219e0c900af94c4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 8 Aug 2016 12:13:09 +0200 Subject: [PATCH] - refactored all 2D drawing to use its own vertex buffer which does not need to be mapped permanently. --- src/CMakeLists.txt | 1 + src/gl/data/gl_vertexbuffer.cpp | 18 +- src/gl/data/gl_vertexbuffer.h | 23 +- src/gl/renderer/gl_2ddrawer.cpp | 488 +++++++++++++++++++++++++++++ src/gl/renderer/gl_2ddrawer.h | 73 +++++ src/gl/renderer/gl_postprocess.cpp | 2 + src/gl/renderer/gl_renderer.cpp | 371 +--------------------- src/gl/renderer/gl_renderer.h | 11 +- src/gl/system/gl_framebuffer.cpp | 29 +- src/gl/system/gl_wipe.cpp | 10 +- 10 files changed, 632 insertions(+), 394 deletions(-) create mode 100644 src/gl/renderer/gl_2ddrawer.cpp create mode 100644 src/gl/renderer/gl_2ddrawer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 170737fa54..e002fc66f9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1060,6 +1060,7 @@ set( FASTMATH_SOURCES gl/utility/gl_clock.cpp gl/utility/gl_cycler.cpp gl/utility/gl_geometric.cpp + gl/renderer/gl_2ddrawer.cpp gl/renderer/gl_renderer.cpp gl/renderer/gl_renderstate.cpp gl/renderer/gl_renderbuffers.cpp diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 2f38a720ee..1d69c25470 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -77,22 +77,26 @@ void FSimpleVertexBuffer::BindVBO() glBindBuffer(GL_ARRAY_BUFFER, vbo_id); if (gl.glslversion > 0) { - glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x); - glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u); - glDisableVertexAttribArray(VATTR_COLOR); + glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->x); + glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->u); + glVertexAttribPointer(VATTR_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(FSimpleVertex), &VSiO->color); + glEnableVertexAttribArray(VATTR_VERTEX); + glEnableVertexAttribArray(VATTR_TEXCOORD); + glEnableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); } else { - glVertexPointer(3, GL_FLOAT, sizeof(FFlatVertex), &VTO->x); - glTexCoordPointer(2, GL_FLOAT, sizeof(FFlatVertex), &VTO->u); + glVertexPointer(3, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->x); + glTexCoordPointer(2, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->u); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FSimpleVertex), &VSiO->color); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); } } -void FSimpleVertexBuffer::set(FFlatVertex *verts, int count) +void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count) { glBindBuffer(GL_ARRAY_BUFFER, vbo_id); gl_RenderState.SetVertexBuffer(this); diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 4d39a7f58f..ce598965f0 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -36,20 +36,37 @@ struct FFlatVertex u = uu; v = vv; } - void BindVBO(); +}; + +struct FSimpleVertex +{ + float x, z, y; // world position + float u, v; // texture coordinates + PalEntry color; + + void Set(float xx, float zz, float yy, float uu = 0, float vv = 0, PalEntry col = 0xffffffff) + { + x = xx; + z = zz; + y = yy; + u = uu; + v = vv; + color = col; + } }; #define VTO ((FFlatVertex*)NULL) +#define VSiO ((FSimpleVertex*)NULL) class FSimpleVertexBuffer : public FVertexBuffer { - TArray mBuffer; + TArray mBuffer; public: FSimpleVertexBuffer() { } void BindVBO(); - void set(FFlatVertex *verts, int count); + void set(FSimpleVertex *verts, int count); }; class FFlatVertexBuffer : public FVertexBuffer diff --git a/src/gl/renderer/gl_2ddrawer.cpp b/src/gl/renderer/gl_2ddrawer.cpp new file mode 100644 index 0000000000..75f76bbe69 --- /dev/null +++ b/src/gl/renderer/gl_2ddrawer.cpp @@ -0,0 +1,488 @@ +/* +** gl_2ddrawer.h +** Container class for drawing 2d graphics with a vertex buffer +** +**--------------------------------------------------------------------------- +** Copyright 2016 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. +** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be +** covered by the terms of the GNU Lesser General Public License as published +** by the Free Software Foundation; either version 2.1 of the License, or (at +** your option) any later version. +** 5. Full disclosure of the entire project's source code, except for third +** party libraries is mandatory. (NOTE: This clause is non-negotiable!) +** +** 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. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl/system/gl_system.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_2ddrawer.h" +#include "gl/textures/gl_material.h" +#include "gl/renderer/gl_renderstate.h" +#include "gl/renderer/gl_lightdata.h" +#include "gl/scene/gl_drawinfo.h" +#include "gl/textures/gl_translate.h" +#include "vectors.h" + +//========================================================================== +// +// +// +//========================================================================== + +int F2DDrawer::AddData(const F2DDrawer::DataGeneric *data) +{ + int addr = mData.Reserve(data->mLen); + memcpy(&mData[addr], data, data->mLen); + mLastLineCmd = -1; + return addr; +} + +//========================================================================== +// +// Draws a texture +// +//========================================================================== + +void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) +{ + double xscale = parms.destwidth / parms.texwidth; + double yscale = parms.destheight / parms.texheight; + double x = parms.x - parms.left * xscale; + double y = parms.y - parms.top * yscale; + double w = parms.destwidth; + double h = parms.destheight; + float u1, v1, u2, v2; + int light = 255; + + FMaterial * gltex = FMaterial::ValidateTexture(img, false); + if (gltex == nullptr) return; + + DataTexture dg; + + dg.mType = DrawTypeTexture; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mRenderStyle = parms.style; + dg.mMasked = !!parms.masked; + dg.mTexture = gltex; + + if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0) + { + // handle black overlays as reduced light. + light = 255 - APART(parms.colorOverlay); + parms.colorOverlay = 0; + } + dg.mVertIndex = (int)mVertices.Reserve(parms.colorOverlay == 0? 4 : 8); + dg.mColorOverlay = parms.colorOverlay; + dg.mTranslation = 0; + + if (!img->bHasCanvas) + { + if (!parms.alphaChannel) + { + if (parms.remap != NULL && !parms.remap->Inactive) + { + GLTranslationPalette * pal = static_cast(parms.remap->GetNative()); + if (pal) dg.mTranslation = -pal->GetIndex(); + } + } + dg.mAlphaTexture = !!(parms.style.Flags & STYLEF_RedIsAlpha); + u1 = gltex->GetUL(); + v1 = gltex->GetVT(); + u2 = gltex->GetUR(); + v2 = gltex->GetVB(); + + } + else + { + dg.mAlphaTexture = false; + u1 = 0.f; + v1 = 1.f; + u2 = 1.f; + v2 = 0.f; + } + + if (parms.flipX) + std::swap(u1, u2); + + + if (parms.windowleft > 0 || parms.windowright < parms.texwidth) + { + double wi = MIN(parms.windowright, parms.texwidth); + x += parms.windowleft * xscale; + w -= (parms.texwidth - wi + parms.windowleft) * xscale; + + u1 = float(u1 + parms.windowleft / parms.texwidth); + u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); + } + + PalEntry color; + if (parms.style.Flags & STYLEF_ColorIsFixed) + { + color = parms.fillcolor; + std::swap(color.r, color.b); + } + else + { + color = PalEntry(light, light, light); + } + color.a = (BYTE)(parms.Alpha * 255); + + // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates + int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; + btm = SCREENHEIGHT - btm; + + int space = (static_cast(screen)->GetTrueHeight() - screen->GetHeight()) / 2; + dg.mScissor[0] = parms.lclip; + dg.mScissor[1] = btm - parms.dclip + space; + dg.mScissor[2] = parms.rclip - parms.lclip; + dg.mScissor[3] = parms.dclip - parms.uclip; + + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x, y, 0, u1, v1, color); ptr++; + ptr->Set(x, y + h, 0, u1, v2, color); ptr++; + ptr->Set(x + w, y, 0, u2, v1, color); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++; + if (parms.colorOverlay != 0) + { + color = parms.colorOverlay; + std::swap(color.r, color.b); + ptr->Set(x, y, 0, u1, v1, color); ptr++; + ptr->Set(x, y + h, 0, u1, v2, color); ptr++; + ptr->Set(x + w, y, 0, u2, v1, color); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++; + } + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, FDynamicColormap *colormap, int lightlevel) +{ + FMaterial *gltexture = FMaterial::ValidateTexture(texture, false); + + if (gltexture == nullptr) + { + return; + } + DataSimplePoly poly; + + poly.mType = DrawTypePoly; + poly.mLen = (sizeof(poly) + 7) & ~7; + poly.mTexture = gltexture; + poly.mColormap = colormap; + poly.mLightLevel = lightlevel; + poly.mVertCount = npoints; + poly.mVertIndex = (int)mVertices.Reserve(npoints); + + bool dorotate = rotation != 0; + + float cosrot = cos(rotation.Radians()); + float sinrot = sin(rotation.Radians()); + + float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); + float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); + if (texture->bHasCanvas) + { + vscale = 0 - vscale; + } + float ox = float(originx); + float oy = float(originy); + + for (int i = 0; i < npoints; ++i) + { + float u = points[i].X - 0.5f - ox; + float v = points[i].Y - 0.5f - oy; + if (dorotate) + { + float t = u; + u = t * cosrot - v * sinrot; + v = v * cosrot + t * sinrot; + } + mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale); + } + AddData(&poly); +} + +//=========================================================================== +// +// +// +//=========================================================================== + +void F2DDrawer::AddDim(PalEntry color, float damount, int x1, int y1, int w, int h) +{ + color.a = uint8_t(damount * 255); + std::swap(color.r, color.b); + + DataGeneric dg; + + dg.mType = DrawTypeDim; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x1, y1, 0, 0, 0, color); ptr++; + ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++; + ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++; + AddData(&dg); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color) +{ + PalEntry p = palcolor == -1 || color != 0 ? (PalEntry)color : GPalette.BaseColors[palcolor]; + AddDim(p, 1.f, left, top, right - left, bottom - top); +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin) +{ + float fU1, fU2, fV1, fV2; + + FMaterial *gltexture = FMaterial::ValidateTexture(src, false); + + if (!gltexture) return; + + DataFlatFill dg; + + dg.mType = DrawTypeFlatFill; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + dg.mTexture = gltexture; + + // scaling is not used here. + if (!local_origin) + { + fU1 = float(left) / src->GetWidth(); + fV1 = float(top) / src->GetHeight(); + fU2 = float(right) / src->GetWidth(); + fV2 = float(bottom) / src->GetHeight(); + } + else + { + fU1 = 0; + fV1 = 0; + fU2 = float(right - left) / src->GetWidth(); + fV2 = float(bottom - top) / src->GetHeight(); + } + FSimpleVertex *ptr = &mVertices[dg.mVertIndex]; + ptr->Set(left, top, 0, fU1, fV1); ptr++; + ptr->Set(left, bottom, 0, fU1, fV2); ptr++; + ptr->Set(right, top, 0, fU2, fV1); ptr++; + ptr->Set(right, bottom, 0, fU2, fV2); ptr++; + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) +{ + PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; + p.a = 255; + std::swap(p.r, p.b); + + DataGeneric dg; + + dg.mType = DrawTypeLine; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 2; + dg.mVertIndex = (int)mVertices.Reserve(2); + mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); + mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p); + + // Test if we can batch multiple line commands + if (mLastLineCmd == -1) + { + mLastLineCmd = AddData(&dg); + } + else + { + DataGeneric *dg = (DataGeneric *)&mData[mLastLineCmd]; + dg->mVertCount += 2; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32 color) +{ + PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor]; + p.a = 255; + std::swap(p.r, p.b); + + DataGeneric dg; + + dg.mType = DrawTypePixel; + dg.mLen = (sizeof(dg) + 7) & ~7; + dg.mVertCount = 2; + dg.mVertIndex = (int)mVertices.Reserve(1); + mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p); + AddData(&dg); +} + + +//========================================================================== +// +// +// +//========================================================================== + +void F2DDrawer::Flush() +{ + if (mData.Size() == 0) return; + SBYTE savedlightmode = glset.lightmode; + // lightmode is only relevant for automap subsectors, + // but We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering. + if (glset.lightmode == 8) glset.lightmode = 0; + + set(&mVertices[0], mVertices.Size()); + for (unsigned i = 0; i < mData.Size();) + { + DataGeneric *dg = (DataGeneric *)&mData[i]; + switch (dg->mType) + { + default: + break; + + case DrawTypeTexture: + { + DataTexture *dt = static_cast(dg); + + gl_SetRenderStyle(dt->mRenderStyle, !dt->mMasked, false); + gl_RenderState.SetMaterial(dt->mTexture, CLAMP_XY_NOMIP, dt->mTranslation, -1, dt->mAlphaTexture); + if (dt->mTexture->tex->bHasCanvas) gl_RenderState.SetTextureMode(TM_OPAQUE); + + glEnable(GL_SCISSOR_TEST); + glScissor(dt->mScissor[0], dt->mScissor[1], dt->mScissor[2], dt->mScissor[3]); + + gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); + gl_RenderState.Apply(); + + glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex, 4); + + gl_RenderState.BlendEquation(GL_FUNC_ADD); + if (dt->mVertCount > 4) + { + gl_RenderState.SetTextureMode(TM_MASK); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex + 4, 4); + } + + glScissor(0, 0, screen->GetWidth(), screen->GetHeight()); + glDisable(GL_SCISSOR_TEST); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.SetTextureMode(TM_MODULATE); + break; + } + + case DrawTypePoly: + { + DataSimplePoly *dsp = static_cast(dg); + + FColormap cm; + cm = dsp->mColormap; + gl_SetColor(dsp->mLightLevel, 0, cm, 1.f); + gl_RenderState.SetMaterial(dsp->mTexture, CLAMP_NONE, 0, -1, false); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_FAN, dsp->mVertIndex, dsp->mVertCount); + break; + } + + case DrawTypeFlatFill: + { + DataFlatFill *dff = static_cast(dg); + gl_RenderState.SetMaterial(dff->mTexture, CLAMP_NONE, 0, -1, false); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_STRIP, dg->mVertIndex, dg->mVertCount); + break; + } + + case DrawTypeDim: + gl_RenderState.EnableTexture(false); + gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_RenderState.AlphaFunc(GL_GREATER, 0); + gl_RenderState.Apply(); + glDrawArrays(GL_TRIANGLE_FAN, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + case DrawTypeLine: + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + glDrawArrays(GL_LINES, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + case DrawTypePixel: + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + glDrawArrays(GL_POINTS, dg->mVertIndex, dg->mVertCount); + gl_RenderState.EnableTexture(true); + break; + + } + i += dg->mLen; + } + mVertices.Clear(); + mData.Clear(); + gl_RenderState.SetVertexBuffer(GLRenderer->mVBO); + glset.lightmode = savedlightmode; +} + + diff --git a/src/gl/renderer/gl_2ddrawer.h b/src/gl/renderer/gl_2ddrawer.h new file mode 100644 index 0000000000..32d2ad1f54 --- /dev/null +++ b/src/gl/renderer/gl_2ddrawer.h @@ -0,0 +1,73 @@ +#ifndef __2DDRAWER_H +#define __2DDRAWER_H + +#include "tarray.h" +#include "gl/data/gl_vertexbuffer.h" + +class F2DDrawer : public FSimpleVertexBuffer +{ + enum EDrawType + { + DrawTypeTexture, + DrawTypeDim, + DrawTypeFlatFill, + DrawTypePoly, + DrawTypeLine, + DrawTypePixel + }; + + struct DataGeneric + { + EDrawType mType; + uint32_t mLen; + int mVertIndex; + int mVertCount; + }; + + struct DataTexture : public DataGeneric + { + FMaterial *mTexture; + int mScissor[4]; + uint32_t mColorOverlay; + int mTranslation; + FRenderStyle mRenderStyle; + bool mMasked; + bool mAlphaTexture; + }; + + struct DataFlatFill : public DataGeneric + { + FMaterial *mTexture; + }; + + struct DataSimplePoly : public DataGeneric + { + FMaterial *mTexture; + int mLightLevel; + FDynamicColormap *mColormap; + }; + + TArray mVertices; + TArray mData; + int mLastLineCmd = -1; // consecutive lines can be batched into a single draw call so keep this info around. + + int AddData(const DataGeneric *data); + +public: + void AddTexture(FTexture *img, DrawParms &parms); + void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h); + void AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color); + void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin); + + void AddPoly(FTexture *texture, FVector2 *points, int npoints, + double originx, double originy, double scalex, double scaley, + DAngle rotation, FDynamicColormap *colormap, int lightlevel); + + void AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color); + void AddPixel(int x1, int y1, int palcolor, uint32 color); + + void Flush(); +}; + + +#endif diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index f249aa1cce..79bd31860f 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -71,6 +71,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/renderer/gl_2ddrawer.h" //========================================================================== // @@ -283,6 +284,7 @@ void FGLRenderer::LensDistortScene() void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma) { + m2DDrawer->Flush(); // draw all pending 2D stuff before copying the buffer if (FGLRenderBuffers::IsEnabled()) { FGLPostProcessState savedState; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 9105c08c7a..2716c6a2c4 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -58,6 +58,7 @@ #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" #include "gl/renderer/gl_renderbuffers.h" +#include "gl/renderer/gl_2ddrawer.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_drawinfo.h" @@ -106,6 +107,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mShaderManager = NULL; gllight = glpart2 = glpart = mirrortexture = NULL; mLights = NULL; + m2DDrawer = nullptr; } void gl_LoadModels(); @@ -120,6 +122,7 @@ void FGLRenderer::Initialize() mTonemapShader = new FTonemapShader(); mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); + m2DDrawer = new F2DDrawer; // Only needed for the core profile, because someone decided it was a good idea to remove the default VAO. if (gl.version >= 4.0) @@ -153,6 +156,7 @@ FGLRenderer::~FGLRenderer() gl_FlushModels(); gl_DeleteAllAttachedLights(); FMaterial::FlushAll(); + if (m2DDrawer != nullptr) delete m2DDrawer; if (mShaderManager != NULL) delete mShaderManager; if (mSamplerManager != NULL) delete mSamplerManager; if (mVBO != NULL) delete mVBO; @@ -378,366 +382,13 @@ void FGLRenderer::ClearBorders() int borderHeight = (trueHeight - height) / 2; glViewport(0, 0, width, trueHeight); - gl_RenderState.mProjectionMatrix.loadIdentity(); - gl_RenderState.mProjectionMatrix.ortho(0.0f, width * 1.0f, 0.0f, trueHeight, -1.0f, 1.0f); - gl_RenderState.SetColor(0.f ,0.f ,0.f ,1.f); - gl_RenderState.Set2DMode(true); - gl_RenderState.EnableTexture(false); - gl_RenderState.Apply(); - gl_RenderState.ApplyMatrices(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(0, borderHeight, 0, 0, 0); ptr++; - ptr->Set(0, 0, 0, 0, 0); ptr++; - ptr->Set(width, 0, 0, 0, 0); ptr++; - ptr->Set(width, borderHeight, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - ptr->Set(0, trueHeight, 0, 0, 0); ptr++; - ptr->Set(0, trueHeight - borderHeight, 0, 0, 0); ptr++; - ptr->Set(width, trueHeight - borderHeight, 0, 0, 0); ptr++; - ptr->Set(width, trueHeight, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - gl_RenderState.EnableTexture(true); - + glClearColor(0, 0, 0, 1); + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, width, borderHeight); + glClear(GL_COLOR_BUFFER_BIT); + glScissor(0, trueHeight-borderHeight, width, borderHeight); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); glViewport(0, (trueHeight - height) / 2, width, height); } -//========================================================================== -// -// Draws a texture -// -//========================================================================== - -void FGLRenderer::DrawTexture(FTexture *img, DrawParms &parms) -{ - double xscale = parms.destwidth / parms.texwidth; - double yscale = parms.destheight / parms.texheight; - double x = parms.x - parms.left * xscale; - double y = parms.y - parms.top * yscale; - double w = parms.destwidth; - double h = parms.destheight; - float u1, v1, u2, v2; - int light = 255; - - FMaterial * gltex = FMaterial::ValidateTexture(img, false); - - if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0) - { - // Right now there's only black. Should be implemented properly later - light = 255 - APART(parms.colorOverlay); - parms.colorOverlay = 0; - } - - gl_SetRenderStyle(parms.style, !parms.masked, false); - if (!img->bHasCanvas) - { - int translation = 0; - if (!parms.alphaChannel) - { - if (parms.remap != NULL && !parms.remap->Inactive) - { - GLTranslationPalette * pal = static_cast(parms.remap->GetNative()); - if (pal) translation = -pal->GetIndex(); - } - } - gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, translation, -1, !!(parms.style.Flags & STYLEF_RedIsAlpha)); - - u1 = gltex->GetUL(); - v1 = gltex->GetVT(); - u2 = gltex->GetUR(); - v2 = gltex->GetVB(); - - } - else - { - gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, 0, -1, false); - u1 = 0.f; - v1 = 1.f; - u2 = 1.f; - v2 = 0.f; - gl_RenderState.SetTextureMode(TM_OPAQUE); - } - - if (parms.flipX) - { - float temp = u1; - u1 = u2; - u2 = temp; - } - - - if (parms.windowleft > 0 || parms.windowright < parms.texwidth) - { - double wi = MIN(parms.windowright, parms.texwidth); - x += parms.windowleft * xscale; - w -= (parms.texwidth - wi + parms.windowleft) * xscale; - - u1 = float(u1 + parms.windowleft / parms.texwidth); - u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); - } - - PalEntry color; - if (parms.style.Flags & STYLEF_ColorIsFixed) - { - color = parms.fillcolor; - } - else - { - color = PalEntry(light, light, light); - } - color.a = (BYTE)(parms.Alpha * 255); - - // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates - int btm = (SCREENHEIGHT - screen->GetHeight()) / 2; - btm = SCREENHEIGHT - btm; - - glEnable(GL_SCISSOR_TEST); - int space = (static_cast(screen)->GetTrueHeight()-screen->GetHeight())/2; - glScissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip); - - gl_RenderState.SetColor(color); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x, y, 0, u1, v1); ptr++; - ptr->Set(x, y + h, 0, u1, v2); ptr++; - ptr->Set(x + w, y, 0, u2, v1); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - - if (parms.colorOverlay) - { - gl_RenderState.SetTextureMode(TM_MASK); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.BlendEquation(GL_FUNC_ADD); - gl_RenderState.SetColor(PalEntry(parms.colorOverlay)); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x, y, 0, u1, v1); ptr++; - ptr->Set(x, y + h, 0, u1, v2); ptr++; - ptr->Set(x + w, y, 0, u2, v1); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - } - - glScissor(0, 0, screen->GetWidth(), screen->GetHeight()); - glDisable(GL_SCISSOR_TEST); - gl_RenderState.SetTextureMode(TM_MODULATE); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.BlendEquation(GL_FUNC_ADD); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) -{ - PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor]; - gl_RenderState.EnableTexture(false); - gl_RenderState.SetColorAlpha(p, 1.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - ptr->Set(x2, y2, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_LINES); - - gl_RenderState.EnableTexture(true); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::DrawPixel(int x1, int y1, int palcolor, uint32 color) -{ - PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor]; - gl_RenderState.EnableTexture(false); - gl_RenderState.SetColorAlpha(p, 1.f); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_POINTS); - - gl_RenderState.EnableTexture(true); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void FGLRenderer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) -{ - gl_RenderState.EnableTexture(false); - gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl_RenderState.AlphaFunc(GL_GREATER,0); - gl_RenderState.SetColorAlpha(color, damount); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(x1, y1, 0, 0, 0); ptr++; - ptr->Set(x1, y1+h, 0, 0, 0); ptr++; - ptr->Set(x1+w, y1+h, 0, 0, 0); ptr++; - ptr->Set(x1+w, y1, 0, 0, 0); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); - - gl_RenderState.EnableTexture(true); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin) -{ - float fU1,fU2,fV1,fV2; - - FMaterial *gltexture=FMaterial::ValidateTexture(src, false); - - if (!gltexture) return; - - gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); - - // scaling is not used here. - if (!local_origin) - { - fU1 = float(left) / src->GetWidth(); - fV1 = float(top) / src->GetHeight(); - fU2 = float(right) / src->GetWidth(); - fV2 = float(bottom) / src->GetHeight(); - } - else - { - fU1 = 0; - fV1 = 0; - fU2 = float(right-left) / src->GetWidth(); - fV2 = float(bottom-top) / src->GetHeight(); - } - gl_RenderState.ResetColor(); - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - ptr->Set(left, top, 0, fU1, fV1); ptr++; - ptr->Set(left, bottom, 0, fU1, fV2); ptr++; - ptr->Set(right, top, 0, fU2, fV1); ptr++; - ptr->Set(right, bottom, 0, fU2, fV2); ptr++; - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); -} - -//========================================================================== -// -// -// -//========================================================================== -void FGLRenderer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) -{ - int rt; - int offY = 0; - PalEntry p = palcolor==-1 || color != 0? (PalEntry)color : GPalette.BaseColors[palcolor]; - int width = right-left; - int height= bottom-top; - - - rt = screen->GetHeight() - top; - - int space = (static_cast(screen)->GetTrueHeight()-screen->GetHeight())/2; // ugh... - rt += space; - /* - if (!m_windowed && (m_trueHeight != m_height)) - { - offY = (m_trueHeight - m_height) / 2; - rt += offY; - } - */ - - glEnable(GL_SCISSOR_TEST); - glScissor(left, rt - height, width, height); - - glClearColor(p.r/255.0f, p.g/255.0f, p.b/255.0f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.f, 0.f, 0.f, 0.f); - - glDisable(GL_SCISSOR_TEST); -} - -//========================================================================== -// -// D3DFB :: FillSimplePoly -// -// Here, "simple" means that a simple triangle fan can draw it. -// -//========================================================================== - -void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, - double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel) -{ - if (npoints < 3) - { // This is no polygon. - return; - } - - FMaterial *gltexture = FMaterial::ValidateTexture(texture, false); - - if (gltexture == NULL) - { - return; - } - - FColormap cm; - cm = colormap; - - // We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering. - SBYTE savedlightmode = glset.lightmode; - if (glset.lightmode == 8) glset.lightmode = 0; - - gl_SetColor(lightlevel, 0, cm, 1.f); - - glset.lightmode = savedlightmode; - - gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); - - int i; - bool dorotate = rotation != 0; - - float cosrot = cos(rotation.Radians()); - float sinrot = sin(rotation.Radians()); - - //float yoffs = GatheringWipeScreen ? 0 : LBOffset; - float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); - float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); - if (gltexture->tex->bHasCanvas) - { - vscale = 0 - vscale; - } - float ox = float(originx); - float oy = float(originy); - - gl_RenderState.Apply(); - - FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); - for (i = 0; i < npoints; ++i) - { - float u = points[i].X - 0.5f - ox; - float v = points[i].Y - 0.5f - oy; - if (dorotate) - { - float t = u; - u = t * cosrot - v * sinrot; - v = v * cosrot + t * sinrot; - } - ptr->Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale); - ptr++; - } - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); -} - diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 9caace177d..8a00e6ce48 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -25,6 +25,7 @@ class FBlurShader; class FTonemapShader; class FLensShader; class FPresentShader; +class F2DDrawer; inline float DEG2RAD(float deg) { @@ -107,6 +108,7 @@ public: FFlatVertexBuffer *mVBO; FSkyVertexBuffer *mSkyVBO; FLightBuffer *mLights; + F2DDrawer *m2DDrawer; GL_IRECT mScreenViewport; GL_IRECT mOutputViewportLB; @@ -142,12 +144,6 @@ public: void Begin2D(); void ClearBorders(); - void DrawTexture(FTexture *img, DrawParms &parms); - void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color); - void DrawPixel(int x1, int y1, int palcolor, uint32 color); - void Dim(PalEntry color, float damount, int x1, int y1, int w, int h); - void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin); - void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color); void ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector); void ProcessSprite(AActor *thing, sector_t *sector, bool thruportal); @@ -175,6 +171,9 @@ public: bool StartOffscreen(); void EndOffscreen(); + void StartSimplePolys(); + void FinishSimplePolys(); + void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel); diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 1b3a880b27..d5bb578e5c 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -64,6 +64,7 @@ #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" #include "gl/gl_functions.h" +#include "gl/renderer/gl_2ddrawer.h" IMPLEMENT_CLASS(OpenGLFrameBuffer) EXTERN_CVAR (Float, vid_brightness) @@ -386,7 +387,8 @@ bool OpenGLFrameBuffer::Begin2D(bool) void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) { - if (GLRenderer != NULL) GLRenderer->DrawTexture(img, parms); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddTexture(img, parms); } //========================================================================== @@ -396,8 +398,8 @@ void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) //========================================================================== void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->DrawLine(x1, y1, x2, y2, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddLine(x1, y1, x2, y2, palcolor, color); } //========================================================================== @@ -407,8 +409,8 @@ void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, u //========================================================================== void OpenGLFrameBuffer::DrawPixel(int x1, int y1, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->DrawPixel(x1, y1, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddPixel(x1, y1, palcolor, color); } //========================================================================== @@ -425,8 +427,8 @@ void OpenGLFrameBuffer::Dim(PalEntry) void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h) { - if (GLRenderer != NULL) - GLRenderer->Dim(color, damount, x1, y1, w, h); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddDim(color, damount, x1, y1, w, h); } //========================================================================== @@ -437,8 +439,8 @@ void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin) { - if (GLRenderer != NULL) - GLRenderer->FlatFill(left, top, right, bottom, src, local_origin); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddFlatFill(left, top, right, bottom, src, local_origin); } //========================================================================== @@ -448,8 +450,8 @@ void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTex //========================================================================== void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color) { - if (GLRenderer != NULL) - GLRenderer->Clear(left, top, right, bottom, palcolor, color); + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr) + GLRenderer->m2DDrawer->AddClear(left, top, right, bottom, palcolor, color); } //========================================================================== @@ -464,10 +466,9 @@ void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel) { - if (GLRenderer != NULL) + if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr && npoints >= 3) { - GLRenderer->FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, - rotation, colormap, lightlevel); + GLRenderer->m2DDrawer->AddPoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel); } } diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 2978dd55dc..bd03ca96e3 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -61,6 +61,7 @@ #include "gl/textures/gl_samplers.h" #include "gl/utility/gl_templates.h" #include "gl/data/gl_vertexbuffer.h" +#include "gl/renderer/gl_2ddrawer.h" #ifndef _WIN32 struct POINT { @@ -187,6 +188,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) void OpenGLFrameBuffer::WipeEndScreen() { + GLRenderer->m2DDrawer->Flush(); wipeendscreen = new FHardwareTexture(Width, Height, true); wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0); GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1); @@ -288,8 +290,8 @@ OpenGLFrameBuffer::Wiper::~Wiper() void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb) { - FFlatVertex make[4]; - FFlatVertex *ptr = make; + FSimpleVertex make[4]; + FSimpleVertex *ptr = make; float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); @@ -380,8 +382,8 @@ OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt() int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done) { - FFlatVertex *make = new FFlatVertex[321*4]; - FFlatVertex *ptr = make; + FSimpleVertex *make = new FSimpleVertex[321*4]; + FSimpleVertex *ptr = make; int dy; float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());