diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 3c5555eff..d1089bebe 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -713,6 +713,8 @@ set (PCH_SOURCES glbackend/glbackend.cpp glbackend/gl_palmanager.cpp glbackend/gl_texture.cpp + glbackend/gl_buffers.cpp + glbackend/hw_draw2d.cpp mact/src/animlib.cpp mact/src/control.cpp diff --git a/source/common/2d/renderstyle.h b/source/common/2d/renderstyle.h index ac4419ee1..12ac15191 100644 --- a/source/common/2d/renderstyle.h +++ b/source/common/2d/renderstyle.h @@ -108,6 +108,8 @@ enum ERenderAlpha STYLEALPHA_InvSrcCol, // Blend factor is 1.0 - color (HWR only) STYLEALPHA_DstCol, // Blend factor is dest. color (HWR only) STYLEALPHA_InvDstCol, // Blend factor is 1.0 - dest. color (HWR only) + STYLEALPHA_Dst, // Blend factor is dest. alpha + STYLEALPHA_InvDst, // Blend factor is 1.0 - dest. alpha STYLEALPHA_MAX }; diff --git a/source/common/2d/v_2ddrawer.cpp b/source/common/2d/v_2ddrawer.cpp index ccbc752ed..bdc0da2f5 100644 --- a/source/common/2d/v_2ddrawer.cpp +++ b/source/common/2d/v_2ddrawer.cpp @@ -247,7 +247,7 @@ void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) dg.mVertCount = 4; dg.mTexture = img; - dg.mTranslation = 0; + dg.mRemapIndex = parms.remap; SetStyle(img, parms, vertexcolor, dg); u1 = parms.srcx; diff --git a/source/common/2d/v_2ddrawer.h b/source/common/2d/v_2ddrawer.h index e658dcdc0..8e2d52e6e 100644 --- a/source/common/2d/v_2ddrawer.h +++ b/source/common/2d/v_2ddrawer.h @@ -67,7 +67,7 @@ public: int mIndexCount; FTexture *mTexture; - FRemapTable *mTranslation; + int mRemapIndex; PalEntry mSpecialColormap[2]; int mScissor[4]; int mDesaturate; @@ -86,7 +86,7 @@ public: { return mTexture == other.mTexture && mType == other.mType && - mTranslation == other.mTranslation && + mRemapIndex == other.mRemapIndex && mSpecialColormap[0].d == other.mSpecialColormap[0].d && mSpecialColormap[1].d == other.mSpecialColormap[1].d && !memcmp(mScissor, other.mScissor, sizeof(mScissor)) && diff --git a/source/common/2d/v_draw.cpp b/source/common/2d/v_draw.cpp index e2057f91e..0b44e95d8 100644 --- a/source/common/2d/v_draw.cpp +++ b/source/common/2d/v_draw.cpp @@ -265,7 +265,7 @@ bool ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t tag, Va_Li parms->burn = false; parms->monospace = EMonospacing::Off; parms->spacing = 0; - parms->remap = 0; + parms->remap = -1; // Parse the tag list for attributes. (For floating point attributes, // consider that the C ABI dictates that all floats be promoted to diff --git a/source/common/2d/v_drawtext.cpp b/source/common/2d/v_drawtext.cpp index 9e379ca68..59b2cf753 100644 --- a/source/common/2d/v_drawtext.cpp +++ b/source/common/2d/v_drawtext.cpp @@ -126,7 +126,7 @@ void DrawTextCommon(F2DDrawer* drawer, FFont *font, int normalcolor, double x, d double cx; double cy; int boldcolor; - FRemapTable *range; + int range; int kerning; FTexture *pic; diff --git a/source/common/fonts/font.cpp b/source/common/fonts/font.cpp index bc913a83d..bb1653544 100644 --- a/source/common/fonts/font.cpp +++ b/source/common/fonts/font.cpp @@ -52,6 +52,7 @@ #include "myiswalpha.h" #include "fontchars.h" #include "imagehelpers.h" +#include "glbackend/glbackend.h" #include "fontinternals.h" @@ -219,7 +220,7 @@ void FFont::SetDefaultTranslation(uint32_t *othercolors) SimpleTranslation(mycolors, mytranslation, myreverse, myluminosity); SimpleTranslation(othercolors, othertranslation, otherreverse, otherluminosity); - FRemapTable remap(ActiveColors); + FRemapTable remap; remap.Palette[0] = 0; for (unsigned l = 1; l < myluminosity.Size(); l++) @@ -247,7 +248,7 @@ void FFont::SetDefaultTranslation(uint32_t *othercolors) } } } - Ranges[CR_UNTRANSLATED] = remap; + Ranges[CR_UNTRANSLATED] = GLInterface.GetPaletteIndex(remap.Palette); forceremap = true; } @@ -355,7 +356,7 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity int i, j; const TranslationParm *parmstart = (const TranslationParm *)ranges; - FRemapTable remap(total_colors); + FRemapTable remap; // Create different translations for different color ranges Ranges.Clear(); @@ -380,15 +381,14 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity } else { - remap = Ranges[0]; } - Ranges.Push(remap); + Ranges.Push(GLInterface.GetPaletteIndex(remap.Palette)); continue; } assert(parmstart->RangeStart >= 0); - remap.Palette[255] = 0; + remap.Palette[0] = 0; for (j = 0; j < ActiveColors; j++) { @@ -414,7 +414,8 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity b = clamp(b, 0, 255); remap.Palette[j] = PalEntry(255,r,g,b); } - Ranges.Push(remap); + + Ranges.Push(GLInterface.GetPaletteIndex(remap.Palette)); // Advance to the next color range. while (parmstart[1].RangeStart > parmstart[0].RangeEnd) @@ -431,7 +432,7 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity // //========================================================================== -FRemapTable *FFont::GetColorTranslation (EColorRange range, PalEntry *color) const +int FFont::GetColorTranslation (EColorRange range, PalEntry *color) const { if (noTranslate) { @@ -444,11 +445,11 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range, PalEntry *color) con if (color != nullptr) *color = retcolor; } if (ActiveColors == 0) - return nullptr; + return -1; else if (range >= NumTextColors) range = CR_UNTRANSLATED; //if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr; - return &Ranges[range]; + return Ranges[range]; } //========================================================================== diff --git a/source/common/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp index 74ac0d433..82bac7354 100644 --- a/source/common/fonts/hexfont.cpp +++ b/source/common/fonts/hexfont.cpp @@ -376,8 +376,8 @@ public: SimpleTranslation(colors, othertranslation, otherreverse, otherluminosity); - FRemapTable remap(ActiveColors); - remap.Palette[255] = 0; + FRemapTable remap; + remap.Palette[0] = 0; for (unsigned l = 1; l < 18; l++) { diff --git a/source/common/fonts/v_font.h b/source/common/fonts/v_font.h index 055c61c2d..8c805d57f 100644 --- a/source/common/fonts/v_font.h +++ b/source/common/fonts/v_font.h @@ -99,7 +99,7 @@ public: virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; virtual int GetCharWidth (int code) const; - FRemapTable *GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; + int GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; int GetSpaceWidth () const { return SpaceWidth; } int GetHeight () const { return FontHeight; } int GetDefaultKerning () const { return GlobalKerning; } @@ -164,7 +164,7 @@ protected: }; TArray<CharData> Chars; int ActiveColors; - TArray<FRemapTable> Ranges; + TArray<int> Ranges; uint8_t PatchRemap[256]; FName FontName = NAME_None; @@ -192,17 +192,7 @@ char* CleanseString(char* str); struct FRemapTable { - FRemapTable(int count = 256) {} - ~FRemapTable() { delete Palette; } - - PalEntry *Palette = nullptr; // The ideal palette this maps to - int PalIndex; - int NumEntries; // # of elements in this table (usually 256) - bool Inactive; // This table is inactive and should be treated as if it was passed as NULL - -private: - void Free(); - void Alloc(int count); + PalEntry Palette[256] = { }; // The ideal palette this maps to }; diff --git a/source/glad/include/glad/glad.h b/source/glad/include/glad/glad.h index 03272f78f..8f4cd9f9a 100644 --- a/source/glad/include/glad/glad.h +++ b/source/glad/include/glad/glad.h @@ -1,3 +1,4 @@ +#pragma once /* OpenGL loader generated by glad 0.1.33 on Mon Sep 16 17:51:07 2019. diff --git a/source/glbackend/buffers.h b/source/glbackend/buffers.h new file mode 100644 index 000000000..51110c72c --- /dev/null +++ b/source/glbackend/buffers.h @@ -0,0 +1,83 @@ +#pragma once + +#include <stddef.h> +#include <assert.h> + +class FRenderState; + +// The low level code needs to know which attributes exist. +// OpenGL needs to change the state of all of them per buffer binding. +// VAOs are mostly useless for this because they lump buffer and binding state together which the model code does not want. +enum +{ + VATTR_VERTEX, + VATTR_TEXCOORD, + VATTR_COLOR, + VATTR_VERTEX2, + VATTR_NORMAL, + VATTR_NORMAL2, + + VATTR_MAX +}; + +enum EVertexAttributeFormat +{ + VFmt_Float4, + VFmt_Float3, + VFmt_Float2, + VFmt_Float, + VFmt_Byte4, + VFmt_Packed_A2R10G10B10, +}; + +struct FVertexBufferAttribute +{ + int binding; + int location; + int format; + int offset; +}; + +class IBuffer +{ +protected: + size_t buffersize = 0; + void *map = nullptr; +public: + IBuffer() = default; + IBuffer(const IBuffer &) = delete; + IBuffer &operator=(const IBuffer &) = delete; + virtual ~IBuffer() = default; + + virtual void SetData(size_t size, const void *data, bool staticdata = true) = 0; + virtual void SetSubData(size_t offset, size_t size, const void *data) = 0; + virtual void *Lock(unsigned int size) = 0; + virtual void Unlock() = 0; + virtual void Resize(size_t newsize) = 0; + virtual void Map() {} // Only needed by old OpenGL but this needs to be in the interface. + virtual void Unmap() {} + void *Memory() { assert(map); return map; } + size_t Size() { return buffersize; } +}; + +class IVertexBuffer : virtual public IBuffer +{ +public: + virtual void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) = 0; +}; + +// This merely exists to have a dedicated type for index buffers to inherit from. +class IIndexBuffer : virtual public IBuffer +{ + // Element size is fixed to 4, thanks to OpenGL requiring this info to be coded into the glDrawElements call. + // This mostly prohibits a more flexible buffer setup but GZDoom doesn't use any other format anyway. + // Ob Vulkam, element size is a buffer property and of no concern to the drawing functions (as it should be.) +}; + +class IDataBuffer : virtual public IBuffer +{ + // Can be either uniform or shader storage buffer, depending on its needs. +public: + virtual void BindRange(FRenderState *state, size_t start, size_t length) = 0; + +}; diff --git a/source/glbackend/gl_buffers.cpp b/source/glbackend/gl_buffers.cpp new file mode 100644 index 000000000..d33678451 --- /dev/null +++ b/source/glbackend/gl_buffers.cpp @@ -0,0 +1,218 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 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/ +// +//-------------------------------------------------------------------------- +// +/* +** Low level vertex buffer class +** +**/ + +#include <algorithm> +#include "glad/glad.h" +#include "glbackend.h" +#include "gl_buffers.h" + +namespace OpenGLRenderer +{ + +//========================================================================== +// +// basic buffer implementation +// +//========================================================================== + +GLBuffer::GLBuffer(int usetype) + : mUseType(usetype) +{ + glGenBuffers(1, &mBufferId); +} + +GLBuffer::~GLBuffer() +{ + if (mBufferId != 0) + { + glBindBuffer(mUseType, mBufferId); + glUnmapBuffer(mUseType); + glBindBuffer(mUseType, 0); + glDeleteBuffers(1, &mBufferId); + } +} + +void GLBuffer::Bind() +{ + glBindBuffer(mUseType, mBufferId); +} + + +void GLBuffer::SetData(size_t size, const void *data, bool staticdata) +{ + Bind(); + if (data != nullptr) + { + glBufferData(mUseType, size, data, staticdata? GL_STATIC_DRAW : GL_STREAM_DRAW); + } + else + { + mPersistent = /*screen->BuffersArePersistent() &&*/ !staticdata; + if (mPersistent) + { + glBufferStorage(mUseType, size, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + map = glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } + else + { + glBufferData(mUseType, size, nullptr, staticdata ? GL_STATIC_DRAW : GL_STREAM_DRAW); + map = nullptr; + } + if (!staticdata) nomap = false; + } + buffersize = size; +} + +void GLBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + Bind(); + glBufferSubData(mUseType, offset, size, data); +} + +void GLBuffer::Map() +{ + assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too. + if (!mPersistent && !nomap) + { + Bind(); + map = glMapBufferRange(mUseType, 0, buffersize, GL_MAP_WRITE_BIT|GL_MAP_UNSYNCHRONIZED_BIT); + } +} + +void GLBuffer::Unmap() +{ + assert(nomap == false); + if (!mPersistent && map != nullptr) + { + Bind(); + glUnmapBuffer(mUseType); + map = nullptr; + } +} + +void *GLBuffer::Lock(unsigned int size) +{ + // This initializes this buffer as a static object with no data. + SetData(size, nullptr, true); + return glMapBufferRange(mUseType, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT); +} + +void GLBuffer::Unlock() +{ + Bind(); + glUnmapBuffer(mUseType); +} + +void GLBuffer::Resize(size_t newsize) +{ + assert(!nomap); // only mappable buffers can be resized. + if (newsize > buffersize && !nomap) + { + // reallocate the buffer with twice the size + unsigned int oldbuffer = mBufferId; + + // first unmap the old buffer + Bind(); + glUnmapBuffer(mUseType); + + glGenBuffers(1, &mBufferId); + SetData(newsize, nullptr, false); + glBindBuffer(GL_COPY_READ_BUFFER, oldbuffer); + + // copy contents and delete the old buffer. + glCopyBufferSubData(GL_COPY_READ_BUFFER, mUseType, 0, 0, buffersize); + glBindBuffer(GL_COPY_READ_BUFFER, 0); + glDeleteBuffers(1, &oldbuffer); + buffersize = newsize; + } +} + + +//=========================================================================== +// +// Vertex buffer implementation +// +//=========================================================================== + +void GLVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + static int VFmtToGLFmt[] = { GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT_2_10_10_10_REV }; + static uint8_t VFmtToSize[] = {4, 3, 2, 1, 4, 4}; + + mStride = stride; + mNumBindingPoints = numBindingPoints; + + for(int i = 0; i < numAttributes; i++) + { + if (attrs[i].location >= 0 && attrs[i].location < VATTR_MAX) + { + auto & attrinf = mAttributeInfo[attrs[i].location]; + attrinf.format = VFmtToGLFmt[attrs[i].format]; + attrinf.size = VFmtToSize[attrs[i].format]; + attrinf.offset = attrs[i].offset; + attrinf.bindingpoint = attrs[i].binding; + } + } +} + +void GLVertexBuffer::Bind(int *offsets) +{ + int i = 0; + + // This is what gets called from RenderState.Apply. It shouldn't be called anywhere else if the render state is in use + GLBuffer::Bind(); + for(auto &attrinf : mAttributeInfo) + { + if (attrinf.size == 0) + { + glDisableVertexAttribArray(i); + } + else + { + glEnableVertexAttribArray(i); + size_t ofs = offsets == nullptr ? attrinf.offset : attrinf.offset + mStride * offsets[attrinf.bindingpoint]; + glVertexAttribPointer(i, attrinf.size, attrinf.format, attrinf.format != GL_FLOAT, (GLsizei)mStride, (void*)(intptr_t)ofs); + } + i++; + } +} + +void GLDataBuffer::BindRange(FRenderState *state, size_t start, size_t length) +{ + glBindBufferRange(mUseType, mBindingPoint, mBufferId, start, length); +} + +void GLDataBuffer::BindBase() +{ + glBindBufferBase(mUseType, mBindingPoint, mBufferId); +} + + +GLVertexBuffer::GLVertexBuffer() : GLBuffer(GL_ARRAY_BUFFER) {} +GLIndexBuffer::GLIndexBuffer() : GLBuffer(GL_ELEMENT_ARRAY_BUFFER) {} +GLDataBuffer::GLDataBuffer(int bindingpoint, bool is_ssbo) : GLBuffer(is_ssbo ? GL_SHADER_STORAGE_BUFFER : GL_UNIFORM_BUFFER), mBindingPoint(bindingpoint) {} + +} diff --git a/source/glbackend/gl_buffers.h b/source/glbackend/gl_buffers.h new file mode 100644 index 000000000..950556ff9 --- /dev/null +++ b/source/glbackend/gl_buffers.h @@ -0,0 +1,73 @@ +#pragma once + +#include "buffers.h" + +#ifdef _MSC_VER +// silence bogus warning C4250: 'GLVertexBuffer': inherits 'GLBuffer::GLBuffer::SetData' via dominance +// According to internet infos, the warning is erroneously emitted in this case. +#pragma warning(disable:4250) +#endif + +namespace OpenGLRenderer +{ + +class GLBuffer : virtual public IBuffer +{ +protected: + const int mUseType; + unsigned int mBufferId; + int mAllocationSize = 0; + bool mPersistent = false; + bool nomap = true; + + GLBuffer(int usetype); + ~GLBuffer(); + void SetData(size_t size, const void *data, bool staticdata) override; + void SetSubData(size_t offset, size_t size, const void *data) override; + void Map() override; + void Unmap() override; + void Resize(size_t newsize) override; + void *Lock(unsigned int size) override; + void Unlock() override; +public: + void Bind(); +}; + + +class GLVertexBuffer : public IVertexBuffer, public GLBuffer +{ + // If this could use the modern (since GL 4.3) binding system, things would be simpler... :( + struct GLVertexBufferAttribute + { + int bindingpoint; + int format; + int size; + int offset; + }; + + int mNumBindingPoints; + GLVertexBufferAttribute mAttributeInfo[VATTR_MAX] = {}; // Thanks to OpenGL's state system this needs to contain info about every attribute that may ever be in use throughout the entire renderer. + size_t mStride = 0; + +public: + GLVertexBuffer(); + void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; + void Bind(int *offsets); +}; + +class GLIndexBuffer : public IIndexBuffer, public GLBuffer +{ +public: + GLIndexBuffer(); +}; + +class GLDataBuffer : public IDataBuffer, public GLBuffer +{ + int mBindingPoint; +public: + GLDataBuffer(int bindingpoint, bool is_ssbo); + void BindRange(FRenderState* state, size_t start, size_t length); + void BindBase(); +}; + +} \ No newline at end of file diff --git a/source/glbackend/gl_palmanager.cpp b/source/glbackend/gl_palmanager.cpp index 4a02ee4e2..3e27855c6 100644 --- a/source/glbackend/gl_palmanager.cpp +++ b/source/glbackend/gl_palmanager.cpp @@ -40,6 +40,7 @@ #include "baselayer.h" #include "resourcefile.h" #include "imagehelpers.h" +#include "v_font.h" //=========================================================================== // diff --git a/source/glbackend/gl_renderstate.h b/source/glbackend/gl_renderstate.h index b860e27a7..20ed3afba 100644 --- a/source/glbackend/gl_renderstate.h +++ b/source/glbackend/gl_renderstate.h @@ -1,6 +1,7 @@ #pragma once #include "PalEntry.h" +#include "gl_buffers.h" class PolymostShader; enum PRSFlags @@ -34,6 +35,10 @@ struct PolymostRenderState float NPOTEmulationXOffset; float Brightness = 1.f; PalEntry FogColor; + + IVertexBuffer* VertexBuffer = nullptr; + int VB_Offset[2] = {}; + IIndexBuffer* IndexBuffer = nullptr; void Apply(PolymostShader *shader); }; diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp index 24125f576..28bee5704 100644 --- a/source/glbackend/gl_texture.cpp +++ b/source/glbackend/gl_texture.cpp @@ -39,6 +39,7 @@ #include "polymost.h" #include "textures.h" #include "bitmap.h" +#include "v_font.h" #include "../../glbackend/glbackend.h" // Test CVARs. @@ -155,10 +156,6 @@ FHardwareTexture* GLInstance::LoadTexture(FTexture* tex, int textype, int palid) bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int method, int sampleroverride, float xpanning, float ypanning, FTexture *det, float detscale, FTexture *glow) { - if (picnum == 3692) - { - int a = 0; - } if (tex->GetWidth() <= 0 || tex->GetHeight() <= 0) return false; int usepalette = fixpalette >= 1 ? fixpalette - 1 : curbasepal; int usepalswap = fixpalswap >= 1 ? fixpalswap - 1 : palette; @@ -180,7 +177,7 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int else { // Only look up the palette if we really want to use it (i.e. when creating a true color texture of an ART tile.) - if (!hw_useindexedcolortextures) lookuppal = palmanager.LookupPalette(usepalette, usepalswap, false); + if (TextureType == TT_TRUECOLOR) lookuppal = palmanager.LookupPalette(usepalette, usepalswap, false); } // Load the main texture @@ -291,3 +288,21 @@ bool GLInstance::SetTextureInternal(int picnum, FTexture* tex, int palette, int } +//=========================================================================== +// +// Sets a named texture for 2D rendering. In this case the palette is +// a direct index into the palette map. +// +//=========================================================================== + +bool GLInstance::SetNamedTexture(FTexture* tex, int palette, int sampler) +{ + auto mtex = LoadTexture(tex, palette>= 0? TT_TRUECOLOR : TT_HICREPLACE, palette); + if (!mtex) return false; + + renderState.Flags &= ~RF_UsePalette; + BindTexture(0, mtex, sampler); + return true; +} + + diff --git a/source/glbackend/glbackend.cpp b/source/glbackend/glbackend.cpp index d19a569c3..4748224b3 100644 --- a/source/glbackend/glbackend.cpp +++ b/source/glbackend/glbackend.cpp @@ -208,15 +208,33 @@ void GLInstance::Draw(EDrawType type, size_t start, size_t count) if (activeShader == polymostShader) { renderState.Apply(polymostShader); + if (renderState.VertexBuffer != LastVertexBuffer || LastVB_Offset[0] != renderState.VB_Offset[0] || LastVB_Offset[1] != renderState.VB_Offset[1]) + { + static_cast<OpenGLRenderer::GLVertexBuffer*>(renderState.VertexBuffer)->Bind(renderState.VB_Offset); + LastVertexBuffer = renderState.VertexBuffer; + LastVB_Offset[0] = renderState.VB_Offset[0]; + LastVB_Offset[1] = renderState.VB_Offset[1]; + } + if (renderState.IndexBuffer != LastIndexBuffer) + { + static_cast<OpenGLRenderer::GLIndexBuffer*>(renderState.IndexBuffer)->Bind(); + } } - glBegin(primtypes[type]); - auto p = &Buffer[start]; - for (size_t i = 0; i < count; i++, p++) + if (!LastVertexBuffer) { - glVertexAttrib2f(1, p->u, p->v); - glVertexAttrib3f(0, p->x, p->y, p->z); + glBegin(primtypes[type]); + auto p = &Buffer[start]; + for (size_t i = 0; i < count; i++, p++) + { + glVertexAttrib2f(1, p->u, p->v); + glVertexAttrib3f(0, p->x, p->y, p->z); + } + glEnd(); + } + else + { + glDrawElements(primtypes[type], count, GL_UNSIGNED_INT, (void*)(intptr_t)(start * sizeof(uint32_t))); } - glEnd(); if (MatrixChange) RestoreTextureProps(); } @@ -281,6 +299,12 @@ void GLInstance::EnableDepthTest(bool on) else glDisable (GL_DEPTH_TEST); } +void GLInstance::EnableMultisampling(bool on) +{ + if (on) glEnable(GL_MULTISAMPLE); + else glDisable(GL_MULTISAMPLE); +} + void GLInstance::SetMatrix(int num, const VSMatrix *mat) { matrices[num] = *mat; diff --git a/source/glbackend/glbackend.h b/source/glbackend/glbackend.h index 8767adefb..10b0c4d31 100644 --- a/source/glbackend/glbackend.h +++ b/source/glbackend/glbackend.h @@ -8,6 +8,7 @@ #include "gl_renderstate.h" #include "matrix.h" #include "palentry.h" +#include "renderstyle.h" class FSamplerManager; class FShader; @@ -64,7 +65,6 @@ class PaletteManager //OpenGLRenderer::GLDataBuffer* palswapBuffer = nullptr; - unsigned FindPalette(const uint8_t* paldata); unsigned FindPalswap(const uint8_t* paldata); public: @@ -80,6 +80,8 @@ public: int ActivePalswap() const { return lastsindex; } int LookupPalette(int palette, int palswap, bool brightmap); const PalEntry *GetPaletteData(int palid) const { return palettes[palid].colors; } + unsigned FindPalette(const uint8_t* paldata); + }; @@ -157,27 +159,6 @@ enum EDepthFunc Depth_LessEqual }; -enum ERenderAlpha -{ - STYLEALPHA_Zero, // Blend factor is 0.0 - STYLEALPHA_One, // Blend factor is 1.0 - STYLEALPHA_Src, // Blend factor is alpha - STYLEALPHA_InvSrc, // Blend factor is 1.0 - alpha - STYLEALPHA_SrcCol, // Blend factor is color (HWR only) - STYLEALPHA_InvSrcCol, // Blend factor is 1.0 - color (HWR only) - STYLEALPHA_DstCol, // Blend factor is dest. color (HWR only) - STYLEALPHA_InvDstCol, // Blend factor is 1.0 - dest. color (HWR only) - STYLEALPHA_Dst, // Blend factor is dest. alpha - STYLEALPHA_InvDst, // Blend factor is 1.0 - dest. alpha - STYLEALPHA_MAX -}; - -enum ERenderOp -{ - STYLEOP_Add, // Add source to destination - STYLEOP_Sub, // Subtract source from destination - STYLEOP_RevSub, // Subtract destination from source -}; enum EWinding { @@ -212,6 +193,10 @@ class GLInstance int TextureType; int MatrixChange = 0; + IVertexBuffer* LastVertexBuffer = nullptr; + int LastVB_Offset[2] = {}; + IIndexBuffer* LastIndexBuffer = nullptr; + VSMatrix matrices[NUMMATRICES]; PolymostRenderState renderState; @@ -251,6 +236,17 @@ public: void EnableBlend(bool on); void EnableAlphaTest(bool on); void EnableDepthTest(bool on); + void EnableMultisampling(bool on); + void SetVertexBuffer(IVertexBuffer* vb, int offset1, int offset2) + { + renderState.VertexBuffer = vb; + renderState.VB_Offset[0] = offset1; + renderState.VB_Offset[1] = offset2; + } + void SetIndexBuffer(IIndexBuffer* vb) + { + renderState.IndexBuffer = vb; + } const VSMatrix &GetMatrix(int num) { return matrices[num]; @@ -396,12 +392,18 @@ public: { // not yet implemented - only relevant for hires replacements. } + + int GetPaletteIndex(PalEntry* palette) + { + return palmanager.FindPalette((uint8_t*)palette); + } FHardwareTexture* CreateIndexedTexture(FTexture* tex); FHardwareTexture* CreateTrueColorTexture(FTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false); FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid); bool SetTextureInternal(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride, float xpanning, float ypanning, FTexture *det, float detscale, FTexture *glow); + bool SetNamedTexture(FTexture* tex, int palette, int sampleroverride); bool SetTexture(int globalpicnum, FTexture* tex, int palette, int method, int sampleroverride) { diff --git a/source/glbackend/hw_draw2d.cpp b/source/glbackend/hw_draw2d.cpp new file mode 100644 index 000000000..e00f4a404 --- /dev/null +++ b/source/glbackend/hw_draw2d.cpp @@ -0,0 +1,196 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2018 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/ +// +//-------------------------------------------------------------------------- +// +/* +** 2d drawer +** Renderer interface +** +*/ + +#include "cmdlib.h" +#include "gl_buffers.h" +#include "v_2ddrawer.h" +#include "c_cvars.h" +#include "glbackend.h" +#include "v_draw.h" + +//=========================================================================== +// +// Vertex buffer for 2D drawer +// +//=========================================================================== + +class F2DVertexBuffer +{ + IVertexBuffer *mVertexBuffer; + IIndexBuffer *mIndexBuffer; + + +public: + + F2DVertexBuffer() + { + mVertexBuffer = new OpenGLRenderer::GLVertexBuffer(); + mIndexBuffer = new OpenGLRenderer::GLIndexBuffer(); + + static const FVertexBufferAttribute format[] = { + { 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(F2DDrawer::TwoDVertex, x) }, + { 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(F2DDrawer::TwoDVertex, u) }, + { 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(F2DDrawer::TwoDVertex, color0) } + }; + mVertexBuffer->SetFormat(1, 3, sizeof(F2DDrawer::TwoDVertex), format); + } + ~F2DVertexBuffer() + { + delete mIndexBuffer; + delete mVertexBuffer; + } + + void UploadData(F2DDrawer::TwoDVertex *vertices, int vertcount, int *indices, int indexcount) + { + mVertexBuffer->SetData(vertcount * sizeof(*vertices), vertices, false); + mIndexBuffer->SetData(indexcount * sizeof(unsigned int), indices, false); + } + + std::pair<IVertexBuffer *, IIndexBuffer *> GetBufferObjects() const + { + return std::make_pair(mVertexBuffer, mIndexBuffer); + } +}; + +//=========================================================================== +// +// Draws the 2D stuff. This is the version for OpenGL 3 and later. +// +//=========================================================================== + +void Draw2D(F2DDrawer *drawer, FRenderState &state) +{ + VSMatrix mat(0); + GLInterface.SetMatrix(Matrix_View, mat.get()); + GLInterface.SetMatrix(Matrix_ModelView, mat.get()); + GLInterface.SetMatrix(Matrix_Detail, mat.get()); + mat.ortho(0, xdim, ydim, 0, -1, 1); + GLInterface.SetMatrix(Matrix_Projection, mat.get()); + GLInterface.SetViewport(0, 0, xdim, ydim); + GLInterface.EnableDepthTest(false); + GLInterface.EnableMultisampling(false); + + auto &vertices = drawer->mVertices; + auto &indices = drawer->mIndices; + auto &commands = drawer->mData; + + if (commands.Size() == 0) + { + return; + } + + if (drawer->mIsFirstPass) + { + for (auto &v : vertices) + { + // Change from BGRA to RGBA + std::swap(v.color0.r, v.color0.b); + } + } + F2DVertexBuffer vb; + vb.UploadData(&vertices[0], vertices.Size(), &indices[0], indices.Size()); + GLInterface.SetVertexBuffer(vb.GetBufferObjects().first, 0, 0); + GLInterface.SetIndexBuffer(vb.GetBufferObjects().second); + GLInterface.SetFadeDisable(true); + + for(auto &cmd : commands) + { + + int gltrans = -1; + //state.SetRenderStyle(cmd.mRenderStyle); + //state.EnableBrightmap(!(cmd.mRenderStyle.Flags & STYLEF_ColorIsFixed)); + //state.SetTextureMode(cmd.mDrawMode); + + int sciX, sciY, sciW, sciH; + if (cmd.mFlags & F2DDrawer::DTF_Scissor) + { + // scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates + // Note that the origin here is the lower left corner! + sciX = /*screen->ScreenToWindowX*/(cmd.mScissor[0]); + sciY = /*screen->ScreenToWindowY*/(cmd.mScissor[3]); + sciW = /*screen->ScreenToWindowX*/(cmd.mScissor[2]) - sciX; + sciH = /*screen->ScreenToWindowY*/(cmd.mScissor[1]) - sciY; + } + else + { + sciX = sciY = sciW = sciH = -1; + } + //GLInterface.SetScissor(sciX, sciY, sciW, sciH); + + //state.SetFog(cmd.mColor1, 0); + GLInterface.SetColor(1, 1, 1); + //state.SetColor(1, 1, 1, 1, cmd.mDesaturate); + + GLInterface.SetAlphaThreshold(0.0f); + + if (cmd.mTexture != nullptr) + { + auto tex = cmd.mTexture; + GLInterface.SetNamedTexture(cmd.mTexture, cmd.mRemapIndex, cmd.mFlags & F2DDrawer::DTF_Wrap ? SamplerRepeat : SamplerClampXY); + GLInterface.UseColorOnly(false); + } + else + { + GLInterface.UseColorOnly(true); + } + + switch (cmd.mType) + { + case F2DDrawer::DrawTypeTriangles: + GLInterface.Draw(DT_TRIANGLES, cmd.mIndexIndex, cmd.mIndexCount); + break; + + case F2DDrawer::DrawTypeLines: + GLInterface.Draw(DT_LINES, cmd.mVertIndex, cmd.mVertCount); + break; + + case F2DDrawer::DrawTypePoints: + //GLInterface.Draw(DT_POINTS, cmd.mVertIndex, cmd.mVertCount); + break; + + } + /* + state.SetObjectColor(0xffffffff); + state.SetObjectColor2(0); + state.SetAddColor(0); + state.EnableTextureMatrix(false); + state.SetEffect(EFF_NONE); + */ + + } + //state.SetScissor(-1, -1, -1, -1); + + //state.SetRenderStyle(STYLE_Translucent); + GLInterface.SetVertexBuffer(nullptr, 0, 0); + GLInterface.SetIndexBuffer(nullptr); + GLInterface.UseColorOnly(false); + //state.EnableBrightmap(true); + //state.SetTextureMode(TM_NORMAL); + GLInterface.SetFadeDisable(false); + GLInterface.SetColor(1, 1, 1); + //drawer->mIsFirstPass = false; +}