diff --git a/Source/Native/Backend.cpp b/Source/Native/Backend.cpp new file mode 100644 index 00000000..db0bb623 --- /dev/null +++ b/Source/Native/Backend.cpp @@ -0,0 +1,268 @@ +/* +** BuilderNative Renderer +** Copyright (c) 2019 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "Precomp.h" +#include "Backend.h" +#include "OpenGL/GLBackend.h" + +Backend* Backend::Get() +{ + static std::unique_ptr backend; + if (!backend) + backend.reset(new GLBackend()); + return backend.get(); +} + +///////////////////////////////////////////////////////////////////////////// + +extern "C" +{ + RenderDevice* RenderDevice_New(void* disp, void* window) + { + return Backend::Get()->NewRenderDevice(disp, window); + } + + void RenderDevice_Delete(RenderDevice* device) + { + Backend::Get()->DeleteRenderDevice(device); + } + + const char* RenderDevice_GetError(RenderDevice* device) + { + return device->GetError(); + } + + void RenderDevice_DeclareUniform(RenderDevice* device, UniformName name, const char* variablename, UniformType type) + { + device->DeclareUniform(name, variablename, type); + } + + void RenderDevice_DeclareShader(RenderDevice* device, ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) + { + device->DeclareShader(index, name, vertexshader, fragmentshader); + } + + void RenderDevice_SetShader(RenderDevice* device, ShaderName name) + { + device->SetShader(name); + } + + void RenderDevice_SetUniform(RenderDevice* device, UniformName name, const void* values, int count) + { + device->SetUniform(name, values, count); + } + + void RenderDevice_SetVertexBuffer(RenderDevice* device, VertexBuffer* buffer) + { + device->SetVertexBuffer(buffer); + } + + void RenderDevice_SetIndexBuffer(RenderDevice* device, IndexBuffer* buffer) + { + device->SetIndexBuffer(buffer); + } + + void RenderDevice_SetAlphaBlendEnable(RenderDevice* device, bool value) + { + device->SetAlphaBlendEnable(value); + } + + void RenderDevice_SetAlphaTestEnable(RenderDevice* device, bool value) + { + device->SetAlphaTestEnable(value); + } + + void RenderDevice_SetCullMode(RenderDevice* device, Cull mode) + { + device->SetCullMode(mode); + } + + void RenderDevice_SetBlendOperation(RenderDevice* device, BlendOperation op) + { + device->SetBlendOperation(op); + } + + void RenderDevice_SetSourceBlend(RenderDevice* device, Blend blend) + { + device->SetSourceBlend(blend); + } + + void RenderDevice_SetDestinationBlend(RenderDevice* device, Blend blend) + { + device->SetDestinationBlend(blend); + } + + void RenderDevice_SetFillMode(RenderDevice* device, FillMode mode) + { + device->SetFillMode(mode); + } + + void RenderDevice_SetMultisampleAntialias(RenderDevice* device, bool value) + { + device->SetMultisampleAntialias(value); + } + + void RenderDevice_SetZEnable(RenderDevice* device, bool value) + { + device->SetZEnable(value); + } + + void RenderDevice_SetZWriteEnable(RenderDevice* device, bool value) + { + device->SetZWriteEnable(value); + } + + void RenderDevice_SetTexture(RenderDevice* device, Texture* texture) + { + device->SetTexture(texture); + } + + void RenderDevice_SetSamplerFilter(RenderDevice* device, TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) + { + device->SetSamplerFilter(minfilter, magfilter, mipfilter, maxanisotropy); + } + + void RenderDevice_SetSamplerState(RenderDevice* device, TextureAddress address) + { + device->SetSamplerState(address); + } + + bool RenderDevice_Draw(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount) + { + return device->Draw(type, startIndex, primitiveCount); + } + + bool RenderDevice_DrawIndexed(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount) + { + return device->DrawIndexed(type, startIndex, primitiveCount); + } + + bool RenderDevice_DrawData(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount, const void* data) + { + return device->DrawData(type, startIndex, primitiveCount, data); + } + + bool RenderDevice_StartRendering(RenderDevice* device, bool clear, int backcolor, Texture* target, bool usedepthbuffer) + { + return device->StartRendering(clear, backcolor, target, usedepthbuffer); + } + + bool RenderDevice_FinishRendering(RenderDevice* device) + { + return device->FinishRendering(); + } + + bool RenderDevice_Present(RenderDevice* device) + { + return device->Present(); + } + + bool RenderDevice_ClearTexture(RenderDevice* device, int backcolor, Texture* texture) + { + return device->ClearTexture(backcolor, texture); + } + + bool RenderDevice_CopyTexture(RenderDevice* device, Texture* dst, CubeMapFace face) + { + return device->CopyTexture(dst, face); + } + + bool RenderDevice_SetVertexBufferData(RenderDevice* device, VertexBuffer* buffer, void* data, int64_t size, VertexFormat format) + { + return device->SetVertexBufferData(buffer, data, size, format); + } + + bool RenderDevice_SetVertexBufferSubdata(RenderDevice* device, VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size) + { + return device->SetVertexBufferSubdata(buffer, destOffset, data, size); + } + + bool RenderDevice_SetIndexBufferData(RenderDevice* device, IndexBuffer* buffer, void* data, int64_t size) + { + return device->SetIndexBufferData(buffer, data, size); + } + + bool RenderDevice_SetPixels(RenderDevice* device, Texture* texture, const void* data) + { + return device->SetPixels(texture, data); + } + + bool RenderDevice_SetCubePixels(RenderDevice* device, Texture* texture, CubeMapFace face, const void* data) + { + return device->SetCubePixels(texture, face, data); + } + + void* RenderDevice_MapPBO(RenderDevice* device, Texture* texture) + { + return device->MapPBO(texture); + } + + bool RenderDevice_UnmapPBO(RenderDevice* device, Texture* texture) + { + return device->UnmapPBO(texture); + } + + //////////////////////////////////////////////////////////////////////////// + + IndexBuffer* IndexBuffer_New() + { + return Backend::Get()->NewIndexBuffer(); + } + + void IndexBuffer_Delete(IndexBuffer* buffer) + { + Backend::Get()->DeleteIndexBuffer(buffer); + } + + //////////////////////////////////////////////////////////////////////////// + + VertexBuffer* VertexBuffer_New() + { + return Backend::Get()->NewVertexBuffer(); + } + + void VertexBuffer_Delete(VertexBuffer* buffer) + { + Backend::Get()->DeleteVertexBuffer(buffer); + } + + //////////////////////////////////////////////////////////////////////////// + + Texture* Texture_New() + { + return Backend::Get()->NewTexture(); + } + + void Texture_Delete(Texture* tex) + { + return Backend::Get()->DeleteTexture(tex); + } + + void Texture_Set2DImage(Texture* tex, int width, int height) + { + tex->Set2DImage(width, height); + } + + void Texture_SetCubeImage(Texture* tex, int size) + { + tex->SetCubeImage(size); + } +} diff --git a/Source/Native/Backend.h b/Source/Native/Backend.h new file mode 100644 index 00000000..3b82d7d6 --- /dev/null +++ b/Source/Native/Backend.h @@ -0,0 +1,130 @@ +/* +** BuilderNative Renderer +** Copyright (c) 2019 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include +#include + +enum class CubeMapFace : int { PositiveX, PositiveY, PositiveZ, NegativeX, NegativeY, NegativeZ }; +enum class VertexFormat : int32_t { Flat, World }; +enum class DeclarationUsage : int32_t { Position, Color, TextureCoordinate, Normal }; + +enum class Cull : int { None, Clockwise }; +enum class Blend : int { InverseSourceAlpha, SourceAlpha, One }; +enum class BlendOperation : int { Add, ReverseSubtract }; +enum class FillMode : int { Solid, Wireframe }; +enum class TextureAddress : int { Wrap, Clamp }; +enum class ShaderFlags : int { None, Debug }; +enum class PrimitiveType : int { LineList, TriangleList, TriangleStrip }; +enum class TextureFilter : int { None, Point, Linear, Anisotropic }; +enum class UniformType : int { Vec4f, Vec3f, Vec2f, Float, Mat4 }; + +typedef int UniformName; +typedef int ShaderName; + +class VertexBuffer; +class IndexBuffer; +class Texture; + +class RenderDevice +{ +public: + virtual ~RenderDevice() = default; + + virtual const char* GetError() = 0; + + virtual void DeclareUniform(UniformName name, const char* glslname, UniformType type) = 0; + virtual void DeclareShader(ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) = 0; + virtual void SetShader(ShaderName name) = 0; + virtual void SetUniform(UniformName name, const void* values, int count) = 0; + virtual void SetVertexBuffer(VertexBuffer* buffer) = 0; + virtual void SetIndexBuffer(IndexBuffer* buffer) = 0; + virtual void SetAlphaBlendEnable(bool value) = 0; + virtual void SetAlphaTestEnable(bool value) = 0; + virtual void SetCullMode(Cull mode) = 0; + virtual void SetBlendOperation(BlendOperation op) = 0; + virtual void SetSourceBlend(Blend blend) = 0; + virtual void SetDestinationBlend(Blend blend) = 0; + virtual void SetFillMode(FillMode mode) = 0; + virtual void SetMultisampleAntialias(bool value) = 0; + virtual void SetZEnable(bool value) = 0; + virtual void SetZWriteEnable(bool value) = 0; + virtual void SetTexture(Texture* texture) = 0; + virtual void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) = 0; + virtual void SetSamplerState(TextureAddress address) = 0; + virtual bool Draw(PrimitiveType type, int startIndex, int primitiveCount) = 0; + virtual bool DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) = 0; + virtual bool DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) = 0; + virtual bool StartRendering(bool clear, int backcolor, Texture* target, bool usedepthbuffer) = 0; + virtual bool FinishRendering() = 0; + virtual bool Present() = 0; + virtual bool ClearTexture(int backcolor, Texture* texture) = 0; + virtual bool CopyTexture(Texture* dst, CubeMapFace face) = 0; + virtual bool SetVertexBufferData(VertexBuffer* buffer, void* data, int64_t size, VertexFormat format) = 0; + virtual bool SetVertexBufferSubdata(VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size) = 0; + virtual bool SetIndexBufferData(IndexBuffer* buffer, void* data, int64_t size) = 0; + virtual bool SetPixels(Texture* texture, const void* data) = 0; + virtual bool SetCubePixels(Texture* texture, CubeMapFace face, const void* data) = 0; + virtual void* MapPBO(Texture* texture) = 0; + virtual bool UnmapPBO(Texture* texture) = 0; +}; + +class VertexBuffer +{ +public: + virtual ~VertexBuffer() = default; + + static const int FlatStride = 24; + static const int WorldStride = 36; +}; + +class IndexBuffer +{ +public: + virtual ~IndexBuffer() = default; +}; + +class Texture +{ +public: + virtual ~Texture() = default; + virtual void Set2DImage(int width, int height) = 0; + virtual void SetCubeImage(int size) = 0; +}; + +class Backend +{ +public: + static Backend* Get(); + + virtual RenderDevice* NewRenderDevice(void* disp, void* window) = 0; + virtual void DeleteRenderDevice(RenderDevice* device) = 0; + + virtual VertexBuffer* NewVertexBuffer() = 0; + virtual void DeleteVertexBuffer(VertexBuffer* buffer) = 0; + + virtual IndexBuffer* NewIndexBuffer() = 0; + virtual void DeleteIndexBuffer(IndexBuffer* buffer) = 0; + + virtual Texture* NewTexture() = 0; + virtual void DeleteTexture(Texture* texture) = 0; +}; diff --git a/Source/Native/BuilderNative.vcxproj b/Source/Native/BuilderNative.vcxproj index 22b79ce0..91359d93 100644 --- a/Source/Native/BuilderNative.vcxproj +++ b/Source/Native/BuilderNative.vcxproj @@ -192,15 +192,21 @@ - + + + + + + + + + NotUsing NotUsing NotUsing NotUsing - - - + Create Create @@ -208,26 +214,25 @@ Create - - - - - + - - - - + + + + + + + + + + - - - - + - + diff --git a/Source/Native/BuilderNative.vcxproj.filters b/Source/Native/BuilderNative.vcxproj.filters index 715cf0e9..171cae45 100644 --- a/Source/Native/BuilderNative.vcxproj.filters +++ b/Source/Native/BuilderNative.vcxproj.filters @@ -1,47 +1,87 @@  - - - - - - - gl_load - - - - + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL\gl_load + + + + OpenGL + + + OpenGL + + - - - - - - gl_load - - - gl_load - - - + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL + + + OpenGL\gl_load + + + OpenGL\gl_load + + + + OpenGL + + + OpenGL + - - {6455e9b5-8f21-4621-8d8d-c16489a2b548} + + {116db6ea-72bb-4d44-8563-ba39091f2f0f} + + + {0acc1cd1-c19f-4410-95aa-718746ce8eaf} - - gl_load + + OpenGL\gl_load \ No newline at end of file diff --git a/Source/Native/OpenGL/GLBackend.cpp b/Source/Native/OpenGL/GLBackend.cpp new file mode 100644 index 00000000..39effc25 --- /dev/null +++ b/Source/Native/OpenGL/GLBackend.cpp @@ -0,0 +1,76 @@ +/* +** BuilderNative Renderer +** Copyright (c) 2019 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "Precomp.h" +#include "GLBackend.h" +#include "GLRenderDevice.h" +#include "GLVertexBuffer.h" +#include "GLIndexBuffer.h" +#include "GLTexture.h" + +RenderDevice* GLBackend::NewRenderDevice(void* disp, void* window) +{ + GLRenderDevice* device = new GLRenderDevice(disp, window); + if (!device->Context) + { + delete device; + return nullptr; + } + else + { + return device; + } +} + +void GLBackend::DeleteRenderDevice(RenderDevice* device) +{ + delete device; +} + +VertexBuffer* GLBackend::NewVertexBuffer() +{ + return new GLVertexBuffer(); +} + +void GLBackend::DeleteVertexBuffer(VertexBuffer* buffer) +{ + GLRenderDevice::DeleteObject(static_cast(buffer)); +} + +IndexBuffer* GLBackend::NewIndexBuffer() +{ + return new GLIndexBuffer(); +} + +void GLBackend::DeleteIndexBuffer(IndexBuffer* buffer) +{ + GLRenderDevice::DeleteObject(static_cast(buffer)); +} + +Texture* GLBackend::NewTexture() +{ + return new GLTexture(); +} + +void GLBackend::DeleteTexture(Texture* texture) +{ + GLRenderDevice::DeleteObject(static_cast(texture)); +} diff --git a/Source/Native/OpenGL/GLBackend.h b/Source/Native/OpenGL/GLBackend.h new file mode 100644 index 00000000..89e5fcb4 --- /dev/null +++ b/Source/Native/OpenGL/GLBackend.h @@ -0,0 +1,40 @@ +/* +** BuilderNative Renderer +** Copyright (c) 2019 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include "../Backend.h" + +class GLBackend : public Backend +{ +public: + RenderDevice* NewRenderDevice(void* disp, void* window) override; + void DeleteRenderDevice(RenderDevice* device) override; + + VertexBuffer* NewVertexBuffer() override; + void DeleteVertexBuffer(VertexBuffer* buffer) override; + + IndexBuffer* NewIndexBuffer() override; + void DeleteIndexBuffer(IndexBuffer* buffer) override; + + Texture* NewTexture() override; + void DeleteTexture(Texture* texture) override; +}; diff --git a/Source/Native/IndexBuffer.cpp b/Source/Native/OpenGL/GLIndexBuffer.cpp similarity index 75% rename from Source/Native/IndexBuffer.cpp rename to Source/Native/OpenGL/GLIndexBuffer.cpp index 4a4d5cf6..cbc123c0 100644 --- a/Source/Native/IndexBuffer.cpp +++ b/Source/Native/OpenGL/GLIndexBuffer.cpp @@ -20,10 +20,10 @@ */ #include "Precomp.h" -#include "IndexBuffer.h" -#include "RenderDevice.h" +#include "GLIndexBuffer.h" +#include "GLRenderDevice.h" -IndexBuffer::~IndexBuffer() +GLIndexBuffer::~GLIndexBuffer() { if (Device && mBuffer != 0) { @@ -32,26 +32,9 @@ IndexBuffer::~IndexBuffer() } } -GLuint IndexBuffer::GetBuffer() +GLuint GLIndexBuffer::GetBuffer() { if (mBuffer == 0) glGenBuffers(1, &mBuffer); return mBuffer; } - -///////////////////////////////////////////////////////////////////////////// - -extern "C" -{ - -IndexBuffer* IndexBuffer_New() -{ - return new IndexBuffer(); -} - -void IndexBuffer_Delete(IndexBuffer* buffer) -{ - RenderDevice::DeleteObject(buffer); -} - -} diff --git a/Source/Native/IndexBuffer.h b/Source/Native/OpenGL/GLIndexBuffer.h similarity index 87% rename from Source/Native/IndexBuffer.h rename to Source/Native/OpenGL/GLIndexBuffer.h index 992f357b..4d20f47b 100644 --- a/Source/Native/IndexBuffer.h +++ b/Source/Native/OpenGL/GLIndexBuffer.h @@ -21,16 +21,18 @@ #pragma once -class RenderDevice; +#include "../Backend.h" -class IndexBuffer +class GLRenderDevice; + +class GLIndexBuffer : public IndexBuffer { public: - ~IndexBuffer(); + ~GLIndexBuffer(); GLuint GetBuffer(); - RenderDevice* Device = nullptr; + GLRenderDevice* Device = nullptr; private: GLuint mBuffer = 0; diff --git a/Source/Native/RenderDevice.cpp b/Source/Native/OpenGL/GLRenderDevice.cpp similarity index 64% rename from Source/Native/RenderDevice.cpp rename to Source/Native/OpenGL/GLRenderDevice.cpp index 1653c298..1a87fd64 100644 --- a/Source/Native/RenderDevice.cpp +++ b/Source/Native/OpenGL/GLRenderDevice.cpp @@ -1,1146 +1,957 @@ -/* -** BuilderNative Renderer -** Copyright (c) 2019 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "Precomp.h" -#include "RenderDevice.h" -#include "VertexBuffer.h" -#include "IndexBuffer.h" -#include "Texture.h" -#include "ShaderManager.h" -#include -#include -#include -#include - -static bool GLLogStarted = false; -static void APIENTRY GLLogCallback(GLenum source, GLenum type, GLuint id, - GLenum severity, GLsizei length, const GLchar* message, const void* userParam) -{ - FILE* f = fopen("OpenGLDebug.log", GLLogStarted ? "a" : "w"); - if (!f) return; - GLLogStarted = true; - fprintf(f, "%s\r\n", message); - fclose(f); -} - -RenderDevice::RenderDevice(void* disp, void* window) -{ - Context = IOpenGLContext::Create(disp, window); - if (Context) - { - Context->MakeCurrent(); - -#ifdef _DEBUG - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(&GLLogCallback, nullptr); -#endif - - glGenVertexArrays(1, &mStreamVAO); - glGenBuffers(1, &mStreamVertexBuffer); - glBindVertexArray(mStreamVAO); - glBindBuffer(GL_ARRAY_BUFFER, mStreamVertexBuffer); - SharedVertexBuffer::SetupFlatVAO(); - - int i = 0; - for (auto& sharedbuf : mSharedVertexBuffers) - { - sharedbuf.reset(new SharedVertexBuffer((VertexFormat)i, (int64_t)16 * 1024 * 1024)); - glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); - glBufferData(GL_ARRAY_BUFFER, sharedbuf->Size, nullptr, GL_STATIC_DRAW); - i++; - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - mShaderManager = std::make_unique(); - - CheckGLError(); - } -} - -RenderDevice::~RenderDevice() -{ - if (Context) - { - Context->MakeCurrent(); - - ProcessDeleteList(); - - glDeleteBuffers(1, &mStreamVertexBuffer); - glDeleteVertexArrays(1, &mStreamVAO); - - for (auto& sharedbuf : mSharedVertexBuffers) - { - for (VertexBuffer* buf : sharedbuf->VertexBuffers) - buf->Device = nullptr; - - GLuint handle = sharedbuf->GetBuffer(); - glDeleteBuffers(1, &handle); - handle = sharedbuf->GetVAO(); - glDeleteVertexArrays(1, &handle); - } - - for (auto& it : mSamplers) - { - for (GLuint handle : it.second.WrapModes) - { - if (handle != 0) - glDeleteSamplers(1, &handle); - } - } - - mShaderManager->ReleaseResources(); - Context->ClearCurrent(); - } -} - -void RenderDevice::DeclareShader(ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - mShaderManager->DeclareShader(index, name, vertexshader, fragmentshader); -} - -void RenderDevice::SetVertexBuffer(VertexBuffer* buffer) -{ - if (buffer != nullptr) - { - mVertexBufferStartIndex = buffer->BufferStartIndex; - if (mVertexBuffer != (int)buffer->Format) - { - mVertexBuffer = (int)buffer->Format; - mNeedApply = true; - mVertexBufferChanged = true; - } - } - else - { - mVertexBufferStartIndex = 0; - if (mVertexBuffer != -1) - { - mVertexBuffer = -1; - mNeedApply = true; - mVertexBufferChanged = true; - } - } -} - -void RenderDevice::SetIndexBuffer(IndexBuffer* buffer) -{ - if (mIndexBuffer != buffer) - { - mIndexBuffer = buffer; - mNeedApply = true; - mIndexBufferChanged = true; - } -} - -void RenderDevice::SetAlphaBlendEnable(bool value) -{ - if (mAlphaBlend != value) - { - mAlphaBlend = value; - mNeedApply = true; - mBlendStateChanged = true; - } -} - -void RenderDevice::SetAlphaTestEnable(bool value) -{ - if (mAlphaTest != value) - { - mAlphaTest = value; - mNeedApply = true; - mShaderChanged = true; - mUniformsChanged = true; - } -} - -void RenderDevice::SetCullMode(Cull mode) -{ - if (mCullMode != mode) - { - mCullMode = mode; - mNeedApply = true; - mRasterizerStateChanged = true; - } -} - -void RenderDevice::SetBlendOperation(BlendOperation op) -{ - if (mBlendOperation != op) - { - mBlendOperation = op; - mNeedApply = true; - mBlendStateChanged = true; - } -} - -void RenderDevice::SetSourceBlend(Blend blend) -{ - if (mSourceBlend != blend) - { - mSourceBlend = blend; - mNeedApply = true; - mBlendStateChanged = true; - } -} - -void RenderDevice::SetDestinationBlend(Blend blend) -{ - if (mDestinationBlend != blend) - { - mDestinationBlend = blend; - mNeedApply = true; - mBlendStateChanged = true; - } -} - -void RenderDevice::SetFillMode(FillMode mode) -{ - if (mFillMode != mode) - { - mFillMode = mode; - mNeedApply = true; - mRasterizerStateChanged = true; - } -} - -void RenderDevice::SetMultisampleAntialias(bool value) -{ -} - -void RenderDevice::SetZEnable(bool value) -{ - if (mDepthTest != value) - { - mDepthTest = value; - mNeedApply = true; - mDepthStateChanged = true; - } -} - -void RenderDevice::SetZWriteEnable(bool value) -{ - if (mDepthWrite != value) - { - mDepthWrite = value; - mNeedApply = true; - mDepthStateChanged = true; - } -} - -void RenderDevice::SetTexture(Texture* texture) -{ - if (mTextureUnit.Tex != texture) - { - mTextureUnit.Tex = texture; - mNeedApply = true; - mTexturesChanged = true; - } -} - -void RenderDevice::SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) -{ - SamplerFilterKey key; - key.MinFilter = GetGLMinFilter(minfilter, mipfilter); - key.MagFilter = (magfilter == TextureFilter::Point || magfilter == TextureFilter::None) ? GL_NEAREST : GL_LINEAR; - key.MaxAnisotropy = maxanisotropy; - if (mSamplerFilterKey != key) - { - mSamplerFilterKey = key; - mSamplerFilter = &mSamplers[mSamplerFilterKey]; - - mNeedApply = true; - mTexturesChanged = true; - } -} - -GLint RenderDevice::GetGLMinFilter(TextureFilter filter, TextureFilter mipfilter) -{ - if (mipfilter == TextureFilter::Linear) - { - if (filter == TextureFilter::Point || filter == TextureFilter::None) - return GL_LINEAR_MIPMAP_NEAREST; - else - return GL_LINEAR_MIPMAP_LINEAR; - } - else if (mipfilter == TextureFilter::Point) - { - if (filter == TextureFilter::Point || filter == TextureFilter::None) - return GL_NEAREST_MIPMAP_NEAREST; - else - return GL_NEAREST_MIPMAP_LINEAR; - } - else - { - if (filter == TextureFilter::Point || filter == TextureFilter::None) - return GL_NEAREST; - else - return GL_LINEAR; - } -} - -void RenderDevice::SetSamplerState(TextureAddress address) -{ - if (mTextureUnit.WrapMode != address) - { - mTextureUnit.WrapMode = address; - mNeedApply = true; - mTexturesChanged = true; - } -} - -bool RenderDevice::Draw(PrimitiveType type, int startIndex, int primitiveCount) -{ - static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; - static const int toVertexCount[] = { 2, 3, 1 }; - static const int toVertexStart[] = { 0, 0, 2 }; - - if (mNeedApply && !ApplyChanges()) return false; - glDrawArrays(modes[(int)type], mVertexBufferStartIndex + startIndex, toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type]); - return CheckGLError(); -} - -bool RenderDevice::DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) -{ - static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; - static const int toVertexCount[] = { 2, 3, 1 }; - static const int toVertexStart[] = { 0, 0, 2 }; - - if (mNeedApply && !ApplyChanges()) return false; - glDrawElementsBaseVertex(modes[(int)type], toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type], GL_UNSIGNED_INT, (const void*)(startIndex * sizeof(uint32_t)), mVertexBufferStartIndex); - return CheckGLError(); -} - -bool RenderDevice::DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) -{ - static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; - static const int toVertexCount[] = { 2, 3, 1 }; - static const int toVertexStart[] = { 0, 0, 2 }; - - int vertcount = toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type]; - - if (mNeedApply && !ApplyChanges()) return false; - - glBindBuffer(GL_ARRAY_BUFFER, mStreamVertexBuffer); - glBufferData(GL_ARRAY_BUFFER, vertcount * (size_t)SharedVertexBuffer::FlatStride, static_cast(data) + startIndex * (size_t)SharedVertexBuffer::FlatStride, GL_STREAM_DRAW); - glBindVertexArray(mStreamVAO); - glDrawArrays(modes[(int)type], 0, vertcount); - if (!CheckGLError()) return false; - - return ApplyVertexBuffer(); -} - -bool RenderDevice::StartRendering(bool clear, int backcolor, Texture* target, bool usedepthbuffer) -{ - Context->MakeCurrent(); - mContextIsCurrent = true; - - if (target) - { - GLuint framebuffer = 0; - try - { - framebuffer = target->GetFramebuffer(this, usedepthbuffer); - } - catch (std::runtime_error& e) - { - SetError("Error setting render target: %s", e.what()); - return false; - } - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - mViewportWidth = target->GetWidth(); - mViewportHeight = target->GetHeight(); - if (!ApplyViewport()) return false; - } - else - { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - mViewportWidth = Context->GetWidth(); - mViewportHeight = Context->GetHeight(); - if (!ApplyViewport()) return false; - } - - if (clear && usedepthbuffer) - { - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f); - glClearDepthf(1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else if (clear) - { - glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f); - glClear(GL_COLOR_BUFFER_BIT); - } - - mNeedApply = true; - mShaderChanged = true; - mUniformsChanged = true; - mTexturesChanged = true; - mIndexBufferChanged = true; - mVertexBufferChanged = true; - mDepthStateChanged = true; - mBlendStateChanged = true; - mRasterizerStateChanged = true; - - return CheckGLError(); -} - -bool RenderDevice::FinishRendering() -{ - mContextIsCurrent = false; - return true; -} - -bool RenderDevice::Present() -{ - Context->MakeCurrent(); - Context->SwapBuffers(); - ProcessDeleteList(); - return CheckGLError(); -} - -bool RenderDevice::ClearTexture(int backcolor, Texture* texture) -{ - if (!StartRendering(true, backcolor, texture, false)) return false; - return FinishRendering(); -} - -bool RenderDevice::CopyTexture(Texture* dst, CubeMapFace face) -{ - static const GLenum facegl[] = { - GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - }; - - if (!mContextIsCurrent) Context->MakeCurrent(); - GLint oldTexture = 0; - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldTexture); - - glBindTexture(GL_TEXTURE_CUBE_MAP, dst->GetTexture(this)); - glCopyTexSubImage2D(facegl[(int)face], 0, 0, 0, 0, 0, dst->GetWidth(), dst->GetHeight()); - if (face == CubeMapFace::NegativeZ) - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - - glBindTexture(GL_TEXTURE_CUBE_MAP, oldTexture); - bool result = CheckGLError(); - return result; -} - -void RenderDevice::GarbageCollectBuffer(int size, VertexFormat format) -{ - auto& sharedbuf = mSharedVertexBuffers[(int)format]; - if (sharedbuf->NextPos + size <= sharedbuf->Size) - return; - - GLint oldarray = 0, oldvao = 0; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldarray); - glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldvao); - - int totalSize = size; - for (VertexBuffer* buf : sharedbuf->VertexBuffers) - totalSize += buf->Size; - - // If buffer is only half full we only need to GC. Otherwise we also need to expand the buffer size. - int newSize = std::max(totalSize, sharedbuf->Size); - if (newSize < totalSize * 2) newSize *= 2; - - std::unique_ptr old = std::move(sharedbuf); - sharedbuf.reset(new SharedVertexBuffer(format, newSize)); - - glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); - glBufferData(GL_ARRAY_BUFFER, sharedbuf->Size, nullptr, GL_STATIC_DRAW); - - glBindBuffer(GL_COPY_READ_BUFFER, old->GetBuffer()); - - // Copy all ranges still in use to the new buffer - int stride = (format == VertexFormat::Flat ? SharedVertexBuffer::FlatStride : SharedVertexBuffer::WorldStride); - int readPos = 0; - int writePos = 0; - int copySize = 0; - for (VertexBuffer* buf : old->VertexBuffers) - { - if (buf->BufferOffset != readPos + copySize) - { - if (copySize != 0) - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, readPos, writePos, copySize); - readPos = buf->BufferOffset; - writePos += copySize; - copySize = 0; - } - - buf->BufferOffset = sharedbuf->NextPos; - buf->BufferStartIndex = buf->BufferOffset / stride; - sharedbuf->NextPos += buf->Size; - copySize += buf->Size; - } - if (copySize != 0) - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, readPos, writePos, copySize); - sharedbuf->VertexBuffers.swap(old->VertexBuffers); - glBindBuffer(GL_COPY_READ_BUFFER, 0); - - GLuint handle = old->GetVAO(); - glDeleteVertexArrays(1, &handle); - if (handle == oldvao) oldvao = sharedbuf->GetVAO(); - - handle = old->GetBuffer(); - glDeleteBuffers(1, &handle); - if (handle == oldarray) oldarray = sharedbuf->GetBuffer(); - - glBindBuffer(GL_ARRAY_BUFFER, oldarray); - glBindVertexArray(oldvao); - - mVertexBufferChanged = true; - mNeedApply = true; -} - -bool RenderDevice::SetVertexBufferData(VertexBuffer* buffer, void* data, int64_t size, VertexFormat format) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - - if (buffer->Device) - { - buffer->Device->mSharedVertexBuffers[(int)buffer->Format]->VertexBuffers.erase(buffer->ListIt); - buffer->Device = nullptr; - } - - GarbageCollectBuffer(size, format); - - auto& sharedbuf = mSharedVertexBuffers[(int)format]; - - GLint oldbinding = 0; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldbinding); - glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); - - buffer->ListIt = sharedbuf->VertexBuffers.insert(sharedbuf->VertexBuffers.end(), buffer); - buffer->Device = this; - buffer->Size = size; - buffer->Format = format; - buffer->BufferOffset = sharedbuf->NextPos; - buffer->BufferStartIndex = buffer->BufferOffset / (format == VertexFormat::Flat ? SharedVertexBuffer::FlatStride : SharedVertexBuffer::WorldStride); - sharedbuf->NextPos += size; - - glBufferSubData(GL_ARRAY_BUFFER, buffer->BufferOffset, size, data); - glBindBuffer(GL_ARRAY_BUFFER, oldbinding); - bool result = CheckGLError(); - return result; -} - -bool RenderDevice::SetVertexBufferSubdata(VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - GLint oldbinding = 0; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldbinding); - glBindBuffer(GL_ARRAY_BUFFER, mSharedVertexBuffers[(int)buffer->Format]->GetBuffer()); - glBufferSubData(GL_ARRAY_BUFFER, buffer->BufferOffset + destOffset, size, data); - glBindBuffer(GL_ARRAY_BUFFER, oldbinding); - bool result = CheckGLError(); - return result; -} - -bool RenderDevice::SetIndexBufferData(IndexBuffer* buffer, void* data, int64_t size) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - GLint oldbinding = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &oldbinding); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->GetBuffer()); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oldbinding); - bool result = CheckGLError(); - return result; -} - -bool RenderDevice::SetPixels(Texture* texture, const void* data) -{ - texture->SetPixels(data); - return InvalidateTexture(texture); -} - -bool RenderDevice::SetCubePixels(Texture* texture, CubeMapFace face, const void* data) -{ - texture->SetCubePixels(face, data); - return InvalidateTexture(texture); -} - -void* RenderDevice::MapPBO(Texture* texture) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - GLint pbo = texture->GetPBO(this); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); - void* buf = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - bool result = CheckGLError(); - if (!result && buf) - { - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - buf = nullptr; - } - return buf; -} - -bool RenderDevice::UnmapPBO(Texture* texture) -{ - if (!mContextIsCurrent) Context->MakeCurrent(); - GLint pbo = texture->GetPBO(this); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); - glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - glBindTexture(GL_TEXTURE_2D, texture->GetTexture(this)); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture->GetWidth(), texture->GetHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr); - bool result = CheckGLError(); - mNeedApply = true; - mTexturesChanged = true; - return result; -} - -bool RenderDevice::InvalidateTexture(Texture* texture) -{ - if (texture->IsTextureCreated()) - { - if (!mContextIsCurrent) Context->MakeCurrent(); - texture->Invalidate(); - bool result = CheckGLError(); - mNeedApply = true; - mTexturesChanged = true; - return result; - } - else - { - return true; - } -} - -bool RenderDevice::CheckGLError() -{ - if (!Context->IsCurrent()) - { - SetError("Unexpected current OpenGL context"); - } - - GLenum error = glGetError(); - if (error == GL_NO_ERROR) - return true; - - SetError("OpenGL error: %d", error); - return false; -} - -void RenderDevice::SetError(const char* fmt, ...) -{ - va_list va; - va_start(va, fmt); - mSetErrorBuffer[0] = 0; - mSetErrorBuffer[sizeof(mSetErrorBuffer) - 1] = 0; - _vsnprintf(mSetErrorBuffer, sizeof(mSetErrorBuffer)-1, fmt, va); - va_end(va); - mLastError = mSetErrorBuffer; -} - -const char* RenderDevice::GetError() -{ - mReturnError.swap(mLastError); - mLastError.clear(); - return mReturnError.c_str(); -} - -Shader* RenderDevice::GetActiveShader() -{ - if (mAlphaTest) - return &mShaderManager->AlphaTestShaders[(int)mShaderName]; - else - return &mShaderManager->Shaders[(int)mShaderName]; -} - -void RenderDevice::SetShader(ShaderName name) -{ - if (name != mShaderName) - { - mShaderName = name; - mNeedApply = true; - mShaderChanged = true; - mUniformsChanged = true; - } -} - -void RenderDevice::SetUniform(UniformName name, const void* values, int count) -{ - float* dest = mUniformData.data() + mUniformInfo[(int)name].Offset; - if (memcmp(dest, values, sizeof(float) * count) != 0) - { - memcpy(dest, values, sizeof(float) * count); - mUniformInfo[(int)name].LastUpdate++; - mNeedApply = true; - mUniformsChanged = true; - } -} - -bool RenderDevice::ApplyChanges() -{ - if (mShaderChanged && !ApplyShader()) return false; - if (mVertexBufferChanged && !ApplyVertexBuffer()) return false; - if (mIndexBufferChanged && !ApplyIndexBuffer()) return false; - if (mUniformsChanged && !ApplyUniforms()) return false; - if (mTexturesChanged && !ApplyTextures()) return false; - if (mRasterizerStateChanged && !ApplyRasterizerState()) return false; - if (mBlendStateChanged && !ApplyBlendState()) return false; - if (mDepthStateChanged && !ApplyDepthState()) return false; - - mNeedApply = false; - return true; -} - -bool RenderDevice::ApplyViewport() -{ - glViewport(0, 0, mViewportWidth, mViewportHeight); - return CheckGLError(); -} - -bool RenderDevice::ApplyShader() -{ - Shader* curShader = GetActiveShader(); - if (!curShader->CheckCompile(this)) - { - SetError("Failed to bind shader:\r\n%s", curShader->GetCompileError().c_str()); - return false; - } - - curShader->Bind(); - mShaderChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyRasterizerState() -{ - if (mCullMode == Cull::None) - { - glDisable(GL_CULL_FACE); - } - else - { - glEnable(GL_CULL_FACE); - glFrontFace(GL_CW); - } - - GLenum fillMode2GL[] = { GL_FILL, GL_LINE }; - glPolygonMode(GL_FRONT_AND_BACK, fillMode2GL[(int)mFillMode]); - - mRasterizerStateChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyBlendState() -{ - if (mAlphaBlend) - { - static const GLenum blendOp2GL[] = { GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT }; - static const GLenum blendFunc2GL[] = { GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE }; - - glEnable(GL_BLEND); - glBlendEquation(blendOp2GL[(int)mBlendOperation]); - glBlendFunc(blendFunc2GL[(int)mSourceBlend], blendFunc2GL[(int)mDestinationBlend]); - } - else - { - glDisable(GL_BLEND); - } - - mBlendStateChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyDepthState() -{ - if (mDepthTest) - { - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - glDepthMask(mDepthWrite ? GL_TRUE : GL_FALSE); - } - else - { - glDisable(GL_DEPTH_TEST); - } - - mDepthStateChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyIndexBuffer() -{ - if (mIndexBuffer) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetBuffer()); - } - else - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - mIndexBufferChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyVertexBuffer() -{ - if (mVertexBuffer != -1) - glBindVertexArray(mSharedVertexBuffers[mVertexBuffer]->GetVAO()); - - mVertexBufferChanged = false; - - return CheckGLError(); -} - -void RenderDevice::DeclareUniform(UniformName name, const char* glslname, UniformType type) -{ - size_t index = (size_t)name; - if (mUniformInfo.size() <= index) - mUniformInfo.resize(index + 1); - - UniformInfo& info = mUniformInfo[index]; - info.Name = glslname; - info.Type = type; - info.Offset = (int)mUniformData.size(); - - mUniformData.resize(mUniformData.size() + (type == UniformType::Mat4 ? 16 : 4)); -} - -bool RenderDevice::ApplyUniforms() -{ - Shader* shader = GetActiveShader(); - GLuint* locations = shader->UniformLocations.data(); - int* lastupdates = shader->UniformLastUpdates.data(); - - int count = (int)mUniformInfo.size(); - for (int i = 0; i < count; i++) - { - if (lastupdates[i] != mUniformInfo.data()[i].LastUpdate) - { - float* data = mUniformData.data() + mUniformInfo[i].Offset; - GLuint location = locations[i]; - switch (mUniformInfo[i].Type) - { - default: - case UniformType::Vec4f: glUniform4fv(location, 1, data); break; - case UniformType::Vec3f: glUniform3fv(location, 1, data); break; - case UniformType::Vec2f: glUniform2fv(location, 1, data); break; - case UniformType::Float: glUniform1fv(location, 1, data); break; - case UniformType::Mat4: glUniformMatrix4fv(location, 1, GL_FALSE, data); break; - } - lastupdates[i] = mUniformInfo[i].LastUpdate; - } - } - - mUniformsChanged = false; - - return CheckGLError(); -} - -bool RenderDevice::ApplyTextures() -{ - glActiveTexture(GL_TEXTURE0); - if (mTextureUnit.Tex) - { - GLenum target = mTextureUnit.Tex->IsCubeTexture() ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; - - glBindTexture(target, mTextureUnit.Tex->GetTexture(this)); - - GLuint& samplerHandle = mSamplerFilter->WrapModes[(int)mTextureUnit.WrapMode]; - if (samplerHandle == 0) - { - static const int wrapMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE }; - - glGenSamplers(1, &samplerHandle); - glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, mSamplerFilterKey.MinFilter); - glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, mSamplerFilterKey.MagFilter); - glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrapMode[(int)mTextureUnit.WrapMode]); - glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrapMode[(int)mTextureUnit.WrapMode]); - glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrapMode[(int)mTextureUnit.WrapMode]); - } - - if (mTextureUnit.SamplerHandle != samplerHandle) - { - mTextureUnit.SamplerHandle = samplerHandle; - glBindSampler(0, samplerHandle); - } - } - else - { - glBindTexture(GL_TEXTURE_2D, 0); - } - - mTexturesChanged = false; - - return CheckGLError(); -} - -std::mutex& RenderDevice::GetMutex() -{ - static std::mutex m; - return m; -} - -void RenderDevice::DeleteObject(VertexBuffer* buffer) -{ - std::unique_lock lock(RenderDevice::GetMutex()); - if (buffer->Device) - buffer->Device->mDeleteList.VertexBuffers.push_back(buffer); - else - delete buffer; -} - -void RenderDevice::DeleteObject(IndexBuffer* buffer) -{ - std::unique_lock lock(RenderDevice::GetMutex()); - if (buffer->Device) - buffer->Device->mDeleteList.IndexBuffers.push_back(buffer); - else - delete buffer; -} - -void RenderDevice::DeleteObject(Texture* texture) -{ - std::unique_lock lock(RenderDevice::GetMutex()); - if (texture->Device) - texture->Device->mDeleteList.Textures.push_back(texture); - else - delete texture; -} - -void RenderDevice::ProcessDeleteList() -{ - std::unique_lock lock(RenderDevice::GetMutex()); - for (auto buffer : mDeleteList.IndexBuffers) delete buffer; - for (auto buffer : mDeleteList.VertexBuffers) delete buffer; - for (auto texture : mDeleteList.Textures) delete texture; - mDeleteList.IndexBuffers.clear(); - mDeleteList.VertexBuffers.clear(); - mDeleteList.Textures.clear(); -} - -///////////////////////////////////////////////////////////////////////////// - -extern "C" -{ - -RenderDevice* RenderDevice_New(void* disp, void* window) -{ - RenderDevice *device = new RenderDevice(disp, window); - if (!device->Context) - { - delete device; - return nullptr; - } - else - { - return device; - } -} - -void RenderDevice_Delete(RenderDevice* device) -{ - delete device; -} - -const char* RenderDevice_GetError(RenderDevice* device) -{ - return device->GetError(); -} - -void RenderDevice_DeclareUniform(RenderDevice* device, UniformName name, const char* variablename, UniformType type) -{ - device->DeclareUniform(name, variablename, type); -} - -void RenderDevice_DeclareShader(RenderDevice* device, ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) -{ - device->DeclareShader(index, name, vertexshader, fragmentshader); -} - -void RenderDevice_SetShader(RenderDevice* device, ShaderName name) -{ - device->SetShader(name); -} - -void RenderDevice_SetUniform(RenderDevice* device, UniformName name, const void* values, int count) -{ - device->SetUniform(name, values, count); -} - -void RenderDevice_SetVertexBuffer(RenderDevice* device, VertexBuffer* buffer) -{ - device->SetVertexBuffer(buffer); -} - -void RenderDevice_SetIndexBuffer(RenderDevice* device, IndexBuffer* buffer) -{ - device->SetIndexBuffer(buffer); -} - -void RenderDevice_SetAlphaBlendEnable(RenderDevice* device, bool value) -{ - device->SetAlphaBlendEnable(value); -} - -void RenderDevice_SetAlphaTestEnable(RenderDevice* device, bool value) -{ - device->SetAlphaTestEnable(value); -} - -void RenderDevice_SetCullMode(RenderDevice* device, Cull mode) -{ - device->SetCullMode(mode); -} - -void RenderDevice_SetBlendOperation(RenderDevice* device, BlendOperation op) -{ - device->SetBlendOperation(op); -} - -void RenderDevice_SetSourceBlend(RenderDevice* device, Blend blend) -{ - device->SetSourceBlend(blend); -} - -void RenderDevice_SetDestinationBlend(RenderDevice* device, Blend blend) -{ - device->SetDestinationBlend(blend); -} - -void RenderDevice_SetFillMode(RenderDevice* device, FillMode mode) -{ - device->SetFillMode(mode); -} - -void RenderDevice_SetMultisampleAntialias(RenderDevice* device, bool value) -{ - device->SetMultisampleAntialias(value); -} - -void RenderDevice_SetZEnable(RenderDevice* device, bool value) -{ - device->SetZEnable(value); -} - -void RenderDevice_SetZWriteEnable(RenderDevice* device, bool value) -{ - device->SetZWriteEnable(value); -} - -void RenderDevice_SetTexture(RenderDevice* device, Texture* texture) -{ - device->SetTexture(texture); -} - -void RenderDevice_SetSamplerFilter(RenderDevice* device, TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) -{ - device->SetSamplerFilter(minfilter, magfilter, mipfilter, maxanisotropy); -} - -void RenderDevice_SetSamplerState(RenderDevice* device, TextureAddress address) -{ - device->SetSamplerState(address); -} - -bool RenderDevice_Draw(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount) -{ - return device->Draw(type, startIndex, primitiveCount); -} - -bool RenderDevice_DrawIndexed(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount) -{ - return device->DrawIndexed(type, startIndex, primitiveCount); -} - -bool RenderDevice_DrawData(RenderDevice* device, PrimitiveType type, int startIndex, int primitiveCount, const void* data) -{ - return device->DrawData(type, startIndex, primitiveCount, data); -} - -bool RenderDevice_StartRendering(RenderDevice* device, bool clear, int backcolor, Texture* target, bool usedepthbuffer) -{ - return device->StartRendering(clear, backcolor, target, usedepthbuffer); -} - -bool RenderDevice_FinishRendering(RenderDevice* device) -{ - return device->FinishRendering(); -} - -bool RenderDevice_Present(RenderDevice* device) -{ - return device->Present(); -} - -bool RenderDevice_ClearTexture(RenderDevice* device, int backcolor, Texture* texture) -{ - return device->ClearTexture(backcolor, texture); -} - -bool RenderDevice_CopyTexture(RenderDevice* device, Texture* dst, CubeMapFace face) -{ - return device->CopyTexture(dst, face); -} - -bool RenderDevice_SetVertexBufferData(RenderDevice* device, VertexBuffer* buffer, void* data, int64_t size, VertexFormat format) -{ - return device->SetVertexBufferData(buffer, data, size, format); -} - -bool RenderDevice_SetVertexBufferSubdata(RenderDevice* device, VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size) -{ - return device->SetVertexBufferSubdata(buffer, destOffset, data, size); -} - -bool RenderDevice_SetIndexBufferData(RenderDevice* device, IndexBuffer* buffer, void* data, int64_t size) -{ - return device->SetIndexBufferData(buffer, data, size); -} - -bool RenderDevice_SetPixels(RenderDevice* device, Texture* texture, const void* data) -{ - return device->SetPixels(texture, data); -} - -bool RenderDevice_SetCubePixels(RenderDevice* device, Texture* texture, CubeMapFace face, const void* data) -{ - return device->SetCubePixels(texture, face, data); -} - -void* RenderDevice_MapPBO(RenderDevice* device, Texture* texture) -{ - return device->MapPBO(texture); -} - -bool RenderDevice_UnmapPBO(RenderDevice* device, Texture* texture) -{ - return device->UnmapPBO(texture); -} - -} +/* +** BuilderNative Renderer +** Copyright (c) 2019 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "Precomp.h" +#include "GLRenderDevice.h" +#include "GLVertexBuffer.h" +#include "GLIndexBuffer.h" +#include "GLTexture.h" +#include "GLShaderManager.h" +#include +#include +#include +#include + +static bool GLLogStarted = false; +static void APIENTRY GLLogCallback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +{ + FILE* f = fopen("OpenGLDebug.log", GLLogStarted ? "a" : "w"); + if (!f) return; + GLLogStarted = true; + fprintf(f, "%s\r\n", message); + fclose(f); +} + +GLRenderDevice::GLRenderDevice(void* disp, void* window) +{ + Context = IOpenGLContext::Create(disp, window); + if (Context) + { + Context->MakeCurrent(); + +#ifdef _DEBUG + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(&GLLogCallback, nullptr); +#endif + + glGenVertexArrays(1, &mStreamVAO); + glGenBuffers(1, &mStreamVertexBuffer); + glBindVertexArray(mStreamVAO); + glBindBuffer(GL_ARRAY_BUFFER, mStreamVertexBuffer); + GLSharedVertexBuffer::SetupFlatVAO(); + + int i = 0; + for (auto& sharedbuf : mSharedVertexBuffers) + { + sharedbuf.reset(new GLSharedVertexBuffer((VertexFormat)i, (int64_t)16 * 1024 * 1024)); + glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); + glBufferData(GL_ARRAY_BUFFER, sharedbuf->Size, nullptr, GL_STATIC_DRAW); + i++; + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + mShaderManager = std::make_unique(); + + CheckGLError(); + } +} + +GLRenderDevice::~GLRenderDevice() +{ + if (Context) + { + Context->MakeCurrent(); + + ProcessDeleteList(); + + glDeleteBuffers(1, &mStreamVertexBuffer); + glDeleteVertexArrays(1, &mStreamVAO); + + for (auto& sharedbuf : mSharedVertexBuffers) + { + for (GLVertexBuffer* buf : sharedbuf->VertexBuffers) + buf->Device = nullptr; + + GLuint handle = sharedbuf->GetBuffer(); + glDeleteBuffers(1, &handle); + handle = sharedbuf->GetVAO(); + glDeleteVertexArrays(1, &handle); + } + + for (auto& it : mSamplers) + { + for (GLuint handle : it.second.WrapModes) + { + if (handle != 0) + glDeleteSamplers(1, &handle); + } + } + + mShaderManager->ReleaseResources(); + Context->ClearCurrent(); + } +} + +void GLRenderDevice::DeclareShader(ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + mShaderManager->DeclareShader(index, name, vertexshader, fragmentshader); +} + +void GLRenderDevice::SetVertexBuffer(VertexBuffer* ibuffer) +{ + GLVertexBuffer* buffer = static_cast(ibuffer); + if (buffer != nullptr) + { + mVertexBufferStartIndex = buffer->BufferStartIndex; + if (mVertexBuffer != (int)buffer->Format) + { + mVertexBuffer = (int)buffer->Format; + mNeedApply = true; + mVertexBufferChanged = true; + } + } + else + { + mVertexBufferStartIndex = 0; + if (mVertexBuffer != -1) + { + mVertexBuffer = -1; + mNeedApply = true; + mVertexBufferChanged = true; + } + } +} + +void GLRenderDevice::SetIndexBuffer(IndexBuffer* buffer) +{ + if (mIndexBuffer != buffer) + { + mIndexBuffer = static_cast(buffer); + mNeedApply = true; + mIndexBufferChanged = true; + } +} + +void GLRenderDevice::SetAlphaBlendEnable(bool value) +{ + if (mAlphaBlend != value) + { + mAlphaBlend = value; + mNeedApply = true; + mBlendStateChanged = true; + } +} + +void GLRenderDevice::SetAlphaTestEnable(bool value) +{ + if (mAlphaTest != value) + { + mAlphaTest = value; + mNeedApply = true; + mShaderChanged = true; + mUniformsChanged = true; + } +} + +void GLRenderDevice::SetCullMode(Cull mode) +{ + if (mCullMode != mode) + { + mCullMode = mode; + mNeedApply = true; + mRasterizerStateChanged = true; + } +} + +void GLRenderDevice::SetBlendOperation(BlendOperation op) +{ + if (mBlendOperation != op) + { + mBlendOperation = op; + mNeedApply = true; + mBlendStateChanged = true; + } +} + +void GLRenderDevice::SetSourceBlend(Blend blend) +{ + if (mSourceBlend != blend) + { + mSourceBlend = blend; + mNeedApply = true; + mBlendStateChanged = true; + } +} + +void GLRenderDevice::SetDestinationBlend(Blend blend) +{ + if (mDestinationBlend != blend) + { + mDestinationBlend = blend; + mNeedApply = true; + mBlendStateChanged = true; + } +} + +void GLRenderDevice::SetFillMode(FillMode mode) +{ + if (mFillMode != mode) + { + mFillMode = mode; + mNeedApply = true; + mRasterizerStateChanged = true; + } +} + +void GLRenderDevice::SetMultisampleAntialias(bool value) +{ +} + +void GLRenderDevice::SetZEnable(bool value) +{ + if (mDepthTest != value) + { + mDepthTest = value; + mNeedApply = true; + mDepthStateChanged = true; + } +} + +void GLRenderDevice::SetZWriteEnable(bool value) +{ + if (mDepthWrite != value) + { + mDepthWrite = value; + mNeedApply = true; + mDepthStateChanged = true; + } +} + +void GLRenderDevice::SetTexture(Texture* texture) +{ + if (mTextureUnit.Tex != texture) + { + mTextureUnit.Tex = static_cast(texture); + mNeedApply = true; + mTexturesChanged = true; + } +} + +void GLRenderDevice::SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) +{ + SamplerFilterKey key; + key.MinFilter = GetGLMinFilter(minfilter, mipfilter); + key.MagFilter = (magfilter == TextureFilter::Point || magfilter == TextureFilter::None) ? GL_NEAREST : GL_LINEAR; + key.MaxAnisotropy = maxanisotropy; + if (mSamplerFilterKey != key) + { + mSamplerFilterKey = key; + mSamplerFilter = &mSamplers[mSamplerFilterKey]; + + mNeedApply = true; + mTexturesChanged = true; + } +} + +GLint GLRenderDevice::GetGLMinFilter(TextureFilter filter, TextureFilter mipfilter) +{ + if (mipfilter == TextureFilter::Linear) + { + if (filter == TextureFilter::Point || filter == TextureFilter::None) + return GL_LINEAR_MIPMAP_NEAREST; + else + return GL_LINEAR_MIPMAP_LINEAR; + } + else if (mipfilter == TextureFilter::Point) + { + if (filter == TextureFilter::Point || filter == TextureFilter::None) + return GL_NEAREST_MIPMAP_NEAREST; + else + return GL_NEAREST_MIPMAP_LINEAR; + } + else + { + if (filter == TextureFilter::Point || filter == TextureFilter::None) + return GL_NEAREST; + else + return GL_LINEAR; + } +} + +void GLRenderDevice::SetSamplerState(TextureAddress address) +{ + if (mTextureUnit.WrapMode != address) + { + mTextureUnit.WrapMode = address; + mNeedApply = true; + mTexturesChanged = true; + } +} + +bool GLRenderDevice::Draw(PrimitiveType type, int startIndex, int primitiveCount) +{ + static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; + static const int toVertexCount[] = { 2, 3, 1 }; + static const int toVertexStart[] = { 0, 0, 2 }; + + if (mNeedApply && !ApplyChanges()) return false; + glDrawArrays(modes[(int)type], mVertexBufferStartIndex + startIndex, toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type]); + return CheckGLError(); +} + +bool GLRenderDevice::DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) +{ + static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; + static const int toVertexCount[] = { 2, 3, 1 }; + static const int toVertexStart[] = { 0, 0, 2 }; + + if (mNeedApply && !ApplyChanges()) return false; + glDrawElementsBaseVertex(modes[(int)type], toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type], GL_UNSIGNED_INT, (const void*)(startIndex * sizeof(uint32_t)), mVertexBufferStartIndex); + return CheckGLError(); +} + +bool GLRenderDevice::DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) +{ + static const int modes[] = { GL_LINES, GL_TRIANGLES, GL_TRIANGLE_STRIP }; + static const int toVertexCount[] = { 2, 3, 1 }; + static const int toVertexStart[] = { 0, 0, 2 }; + + int vertcount = toVertexStart[(int)type] + primitiveCount * toVertexCount[(int)type]; + + if (mNeedApply && !ApplyChanges()) return false; + + glBindBuffer(GL_ARRAY_BUFFER, mStreamVertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vertcount * (size_t)VertexBuffer::FlatStride, static_cast(data) + startIndex * (size_t)VertexBuffer::FlatStride, GL_STREAM_DRAW); + glBindVertexArray(mStreamVAO); + glDrawArrays(modes[(int)type], 0, vertcount); + if (!CheckGLError()) return false; + + return ApplyVertexBuffer(); +} + +bool GLRenderDevice::StartRendering(bool clear, int backcolor, Texture* itarget, bool usedepthbuffer) +{ + Context->MakeCurrent(); + mContextIsCurrent = true; + + GLTexture* target = static_cast(itarget); + if (target) + { + GLuint framebuffer = 0; + try + { + framebuffer = target->GetFramebuffer(this, usedepthbuffer); + } + catch (std::runtime_error& e) + { + SetError("Error setting render target: %s", e.what()); + return false; + } + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + mViewportWidth = target->GetWidth(); + mViewportHeight = target->GetHeight(); + if (!ApplyViewport()) return false; + } + else + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + mViewportWidth = Context->GetWidth(); + mViewportHeight = Context->GetHeight(); + if (!ApplyViewport()) return false; + } + + if (clear && usedepthbuffer) + { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f); + glClearDepthf(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else if (clear) + { + glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f); + glClear(GL_COLOR_BUFFER_BIT); + } + + mNeedApply = true; + mShaderChanged = true; + mUniformsChanged = true; + mTexturesChanged = true; + mIndexBufferChanged = true; + mVertexBufferChanged = true; + mDepthStateChanged = true; + mBlendStateChanged = true; + mRasterizerStateChanged = true; + + return CheckGLError(); +} + +bool GLRenderDevice::FinishRendering() +{ + mContextIsCurrent = false; + return true; +} + +bool GLRenderDevice::Present() +{ + Context->MakeCurrent(); + Context->SwapBuffers(); + ProcessDeleteList(); + return CheckGLError(); +} + +bool GLRenderDevice::ClearTexture(int backcolor, Texture* texture) +{ + if (!StartRendering(true, backcolor, texture, false)) return false; + return FinishRendering(); +} + +bool GLRenderDevice::CopyTexture(Texture* idst, CubeMapFace face) +{ + GLTexture* dst = static_cast(idst); + + static const GLenum facegl[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z + }; + + if (!mContextIsCurrent) Context->MakeCurrent(); + GLint oldTexture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &oldTexture); + + glBindTexture(GL_TEXTURE_CUBE_MAP, dst->GetTexture(this)); + glCopyTexSubImage2D(facegl[(int)face], 0, 0, 0, 0, 0, dst->GetWidth(), dst->GetHeight()); + if (face == CubeMapFace::NegativeZ) + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + glBindTexture(GL_TEXTURE_CUBE_MAP, oldTexture); + bool result = CheckGLError(); + return result; +} + +void GLRenderDevice::GarbageCollectBuffer(int size, VertexFormat format) +{ + auto& sharedbuf = mSharedVertexBuffers[(int)format]; + if (sharedbuf->NextPos + size <= sharedbuf->Size) + return; + + int totalSize = size; + for (GLVertexBuffer* buf : sharedbuf->VertexBuffers) + totalSize += buf->Size; + + // If buffer is only half full we only need to GC. Otherwise we also need to expand the buffer size. + int newSize = std::max(totalSize, sharedbuf->Size); + if (newSize < totalSize * 2) newSize *= 2; + + std::unique_ptr old = std::move(sharedbuf); + sharedbuf.reset(new GLSharedVertexBuffer(format, newSize)); + + GLint oldarray = 0, oldvao = 0; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldarray); + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &oldvao); + + glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); + glBufferData(GL_ARRAY_BUFFER, sharedbuf->Size, nullptr, GL_STATIC_DRAW); + + glBindBuffer(GL_COPY_READ_BUFFER, old->GetBuffer()); + + // Copy all ranges still in use to the new buffer + int stride = (format == VertexFormat::Flat ? VertexBuffer::FlatStride : VertexBuffer::WorldStride); + int readPos = 0; + int writePos = 0; + int copySize = 0; + for (GLVertexBuffer* buf : old->VertexBuffers) + { + if (buf->BufferOffset != readPos + copySize) + { + if (copySize != 0) + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, readPos, writePos, copySize); + readPos = buf->BufferOffset; + writePos += copySize; + copySize = 0; + } + + buf->BufferOffset = sharedbuf->NextPos; + buf->BufferStartIndex = buf->BufferOffset / stride; + sharedbuf->NextPos += buf->Size; + copySize += buf->Size; + } + if (copySize != 0) + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ARRAY_BUFFER, readPos, writePos, copySize); + sharedbuf->VertexBuffers.swap(old->VertexBuffers); + glBindBuffer(GL_COPY_READ_BUFFER, 0); + + GLuint handle = old->GetVAO(); + glDeleteVertexArrays(1, &handle); + if (handle == oldvao) oldvao = sharedbuf->GetVAO(); + + handle = old->GetBuffer(); + glDeleteBuffers(1, &handle); + if (handle == oldarray) oldarray = sharedbuf->GetBuffer(); + + glBindBuffer(GL_ARRAY_BUFFER, oldarray); + glBindVertexArray(oldvao); + + mVertexBufferChanged = true; + mNeedApply = true; +} + +bool GLRenderDevice::SetVertexBufferData(VertexBuffer* ibuffer, void* data, int64_t size, VertexFormat format) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + + GLVertexBuffer* buffer = static_cast(ibuffer); + + if (buffer->Device) + { + buffer->Device->mSharedVertexBuffers[(int)buffer->Format]->VertexBuffers.erase(buffer->ListIt); + buffer->Device = nullptr; + } + + GarbageCollectBuffer(size, format); + + auto& sharedbuf = mSharedVertexBuffers[(int)format]; + + GLint oldbinding = 0; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldbinding); + glBindBuffer(GL_ARRAY_BUFFER, sharedbuf->GetBuffer()); + + buffer->ListIt = sharedbuf->VertexBuffers.insert(sharedbuf->VertexBuffers.end(), buffer); + buffer->Device = this; + buffer->Size = size; + buffer->Format = format; + buffer->BufferOffset = sharedbuf->NextPos; + buffer->BufferStartIndex = buffer->BufferOffset / (format == VertexFormat::Flat ? VertexBuffer::FlatStride : VertexBuffer::WorldStride); + sharedbuf->NextPos += size; + + glBufferSubData(GL_ARRAY_BUFFER, buffer->BufferOffset, size, data); + glBindBuffer(GL_ARRAY_BUFFER, oldbinding); + bool result = CheckGLError(); + return result; +} + +bool GLRenderDevice::SetVertexBufferSubdata(VertexBuffer* ibuffer, int64_t destOffset, void* data, int64_t size) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + GLVertexBuffer* buffer = static_cast(ibuffer); + GLint oldbinding = 0; + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &oldbinding); + glBindBuffer(GL_ARRAY_BUFFER, mSharedVertexBuffers[(int)buffer->Format]->GetBuffer()); + glBufferSubData(GL_ARRAY_BUFFER, buffer->BufferOffset + destOffset, size, data); + glBindBuffer(GL_ARRAY_BUFFER, oldbinding); + bool result = CheckGLError(); + return result; +} + +bool GLRenderDevice::SetIndexBufferData(IndexBuffer* ibuffer, void* data, int64_t size) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + GLIndexBuffer* buffer = static_cast(ibuffer); + GLint oldbinding = 0; + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &oldbinding); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->GetBuffer()); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oldbinding); + bool result = CheckGLError(); + return result; +} + +bool GLRenderDevice::SetPixels(Texture* itexture, const void* data) +{ + GLTexture* texture = static_cast(itexture); + texture->SetPixels(data); + return InvalidateTexture(texture); +} + +bool GLRenderDevice::SetCubePixels(Texture* itexture, CubeMapFace face, const void* data) +{ + GLTexture* texture = static_cast(itexture); + texture->SetCubePixels(face, data); + return InvalidateTexture(texture); +} + +void* GLRenderDevice::MapPBO(Texture* itexture) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + GLTexture* texture = static_cast(itexture); + GLint pbo = texture->GetPBO(this); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + void* buf = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + bool result = CheckGLError(); + if (!result && buf) + { + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + buf = nullptr; + } + return buf; +} + +bool GLRenderDevice::UnmapPBO(Texture* itexture) +{ + if (!mContextIsCurrent) Context->MakeCurrent(); + GLTexture* texture = static_cast(itexture); + GLint pbo = texture->GetPBO(this); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindTexture(GL_TEXTURE_2D, texture->GetTexture(this)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture->GetWidth(), texture->GetHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr); + bool result = CheckGLError(); + mNeedApply = true; + mTexturesChanged = true; + return result; +} + +bool GLRenderDevice::InvalidateTexture(GLTexture* texture) +{ + if (texture->IsTextureCreated()) + { + if (!mContextIsCurrent) Context->MakeCurrent(); + texture->Invalidate(); + bool result = CheckGLError(); + mNeedApply = true; + mTexturesChanged = true; + return result; + } + else + { + return true; + } +} + +bool GLRenderDevice::CheckGLError() +{ + if (!Context->IsCurrent()) + { + SetError("Unexpected current OpenGL context"); + } + + GLenum error = glGetError(); + if (error == GL_NO_ERROR) + return true; + + SetError("OpenGL error: %d", error); + return false; +} + +void GLRenderDevice::SetError(const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + mSetErrorBuffer[0] = 0; + mSetErrorBuffer[sizeof(mSetErrorBuffer) - 1] = 0; + _vsnprintf(mSetErrorBuffer, sizeof(mSetErrorBuffer)-1, fmt, va); + va_end(va); + mLastError = mSetErrorBuffer; +} + +const char* GLRenderDevice::GetError() +{ + mReturnError.swap(mLastError); + mLastError.clear(); + return mReturnError.c_str(); +} + +GLShader* GLRenderDevice::GetActiveShader() +{ + if (mAlphaTest) + return &mShaderManager->AlphaTestShaders[(int)mShaderName]; + else + return &mShaderManager->Shaders[(int)mShaderName]; +} + +void GLRenderDevice::SetShader(ShaderName name) +{ + if (name != mShaderName) + { + mShaderName = name; + mNeedApply = true; + mShaderChanged = true; + mUniformsChanged = true; + } +} + +void GLRenderDevice::SetUniform(UniformName name, const void* values, int count) +{ + float* dest = mUniformData.data() + mUniformInfo[(int)name].Offset; + if (memcmp(dest, values, sizeof(float) * count) != 0) + { + memcpy(dest, values, sizeof(float) * count); + mUniformInfo[(int)name].LastUpdate++; + mNeedApply = true; + mUniformsChanged = true; + } +} + +bool GLRenderDevice::ApplyChanges() +{ + if (mShaderChanged && !ApplyShader()) return false; + if (mVertexBufferChanged && !ApplyVertexBuffer()) return false; + if (mIndexBufferChanged && !ApplyIndexBuffer()) return false; + if (mUniformsChanged && !ApplyUniforms()) return false; + if (mTexturesChanged && !ApplyTextures()) return false; + if (mRasterizerStateChanged && !ApplyRasterizerState()) return false; + if (mBlendStateChanged && !ApplyBlendState()) return false; + if (mDepthStateChanged && !ApplyDepthState()) return false; + + mNeedApply = false; + return true; +} + +bool GLRenderDevice::ApplyViewport() +{ + glViewport(0, 0, mViewportWidth, mViewportHeight); + return CheckGLError(); +} + +bool GLRenderDevice::ApplyShader() +{ + GLShader* curShader = GetActiveShader(); + if (!curShader->CheckCompile(this)) + { + SetError("Failed to bind shader:\r\n%s", curShader->GetCompileError().c_str()); + return false; + } + + curShader->Bind(); + mShaderChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyRasterizerState() +{ + if (mCullMode == Cull::None) + { + glDisable(GL_CULL_FACE); + } + else + { + glEnable(GL_CULL_FACE); + glFrontFace(GL_CW); + } + + GLenum fillMode2GL[] = { GL_FILL, GL_LINE }; + glPolygonMode(GL_FRONT_AND_BACK, fillMode2GL[(int)mFillMode]); + + mRasterizerStateChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyBlendState() +{ + if (mAlphaBlend) + { + static const GLenum blendOp2GL[] = { GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT }; + static const GLenum blendFunc2GL[] = { GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE }; + + glEnable(GL_BLEND); + glBlendEquation(blendOp2GL[(int)mBlendOperation]); + glBlendFunc(blendFunc2GL[(int)mSourceBlend], blendFunc2GL[(int)mDestinationBlend]); + } + else + { + glDisable(GL_BLEND); + } + + mBlendStateChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyDepthState() +{ + if (mDepthTest) + { + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(mDepthWrite ? GL_TRUE : GL_FALSE); + } + else + { + glDisable(GL_DEPTH_TEST); + } + + mDepthStateChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyIndexBuffer() +{ + if (mIndexBuffer) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetBuffer()); + } + else + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + mIndexBufferChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyVertexBuffer() +{ + if (mVertexBuffer != -1) + glBindVertexArray(mSharedVertexBuffers[mVertexBuffer]->GetVAO()); + + mVertexBufferChanged = false; + + return CheckGLError(); +} + +void GLRenderDevice::DeclareUniform(UniformName name, const char* glslname, UniformType type) +{ + size_t index = (size_t)name; + if (mUniformInfo.size() <= index) + mUniformInfo.resize(index + 1); + + UniformInfo& info = mUniformInfo[index]; + info.Name = glslname; + info.Type = type; + info.Offset = (int)mUniformData.size(); + + mUniformData.resize(mUniformData.size() + (type == UniformType::Mat4 ? 16 : 4)); +} + +bool GLRenderDevice::ApplyUniforms() +{ + GLShader* shader = GetActiveShader(); + GLuint* locations = shader->UniformLocations.data(); + int* lastupdates = shader->UniformLastUpdates.data(); + + int count = (int)mUniformInfo.size(); + for (int i = 0; i < count; i++) + { + if (lastupdates[i] != mUniformInfo.data()[i].LastUpdate) + { + float* data = mUniformData.data() + mUniformInfo[i].Offset; + GLuint location = locations[i]; + switch (mUniformInfo[i].Type) + { + default: + case UniformType::Vec4f: glUniform4fv(location, 1, data); break; + case UniformType::Vec3f: glUniform3fv(location, 1, data); break; + case UniformType::Vec2f: glUniform2fv(location, 1, data); break; + case UniformType::Float: glUniform1fv(location, 1, data); break; + case UniformType::Mat4: glUniformMatrix4fv(location, 1, GL_FALSE, data); break; + } + lastupdates[i] = mUniformInfo[i].LastUpdate; + } + } + + mUniformsChanged = false; + + return CheckGLError(); +} + +bool GLRenderDevice::ApplyTextures() +{ + glActiveTexture(GL_TEXTURE0); + if (mTextureUnit.Tex) + { + GLenum target = mTextureUnit.Tex->IsCubeTexture() ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + + glBindTexture(target, mTextureUnit.Tex->GetTexture(this)); + + GLuint& samplerHandle = mSamplerFilter->WrapModes[(int)mTextureUnit.WrapMode]; + if (samplerHandle == 0) + { + static const int wrapMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE }; + + glGenSamplers(1, &samplerHandle); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, mSamplerFilterKey.MinFilter); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, mSamplerFilterKey.MagFilter); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrapMode[(int)mTextureUnit.WrapMode]); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrapMode[(int)mTextureUnit.WrapMode]); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrapMode[(int)mTextureUnit.WrapMode]); + } + + if (mTextureUnit.SamplerHandle != samplerHandle) + { + mTextureUnit.SamplerHandle = samplerHandle; + glBindSampler(0, samplerHandle); + } + } + else + { + glBindTexture(GL_TEXTURE_2D, 0); + } + + mTexturesChanged = false; + + return CheckGLError(); +} + +std::mutex& GLRenderDevice::GetMutex() +{ + static std::mutex m; + return m; +} + +void GLRenderDevice::DeleteObject(GLVertexBuffer* buffer) +{ + std::unique_lock lock(GLRenderDevice::GetMutex()); + if (buffer->Device) + buffer->Device->mDeleteList.VertexBuffers.push_back(buffer); + else + delete buffer; +} + +void GLRenderDevice::DeleteObject(GLIndexBuffer* buffer) +{ + std::unique_lock lock(GLRenderDevice::GetMutex()); + if (buffer->Device) + buffer->Device->mDeleteList.IndexBuffers.push_back(buffer); + else + delete buffer; +} + +void GLRenderDevice::DeleteObject(GLTexture* texture) +{ + std::unique_lock lock(GLRenderDevice::GetMutex()); + if (texture->Device) + texture->Device->mDeleteList.Textures.push_back(texture); + else + delete texture; +} + +void GLRenderDevice::ProcessDeleteList() +{ + std::unique_lock lock(GLRenderDevice::GetMutex()); + for (auto buffer : mDeleteList.IndexBuffers) delete buffer; + for (auto buffer : mDeleteList.VertexBuffers) delete buffer; + for (auto texture : mDeleteList.Textures) delete texture; + mDeleteList.IndexBuffers.clear(); + mDeleteList.VertexBuffers.clear(); + mDeleteList.Textures.clear(); +} diff --git a/Source/Native/RenderDevice.h b/Source/Native/OpenGL/GLRenderDevice.h similarity index 63% rename from Source/Native/RenderDevice.h rename to Source/Native/OpenGL/GLRenderDevice.h index b68e5d8c..ac052d5a 100644 --- a/Source/Native/RenderDevice.h +++ b/Source/Native/OpenGL/GLRenderDevice.h @@ -21,84 +21,60 @@ #pragma once +#include "../Backend.h" #include "OpenGLContext.h" -#include -#include -class SharedVertexBuffer; -class VertexBuffer; -class IndexBuffer; -class Texture; -class ShaderManager; -class Shader; -enum class CubeMapFace; -enum class VertexFormat; +class GLSharedVertexBuffer; +class GLShader; +class GLShaderManager; +class GLVertexBuffer; +class GLIndexBuffer; +class GLTexture; -enum class Cull : int { None, Clockwise }; -enum class Blend : int { InverseSourceAlpha, SourceAlpha, One }; -enum class BlendOperation : int { Add, ReverseSubtract }; -enum class FillMode : int { Solid, Wireframe }; -enum class TextureAddress : int { Wrap, Clamp }; -enum class ShaderFlags : int { None, Debug }; -enum class PrimitiveType : int { LineList, TriangleList, TriangleStrip }; -enum class TextureFilter : int { None, Point, Linear, Anisotropic }; - -typedef int UniformName; -typedef int ShaderName; - -enum class UniformType : int -{ - Vec4f, - Vec3f, - Vec2f, - Float, - Mat4 -}; - -class RenderDevice +class GLRenderDevice : public RenderDevice { public: - RenderDevice(void* disp, void* window); - ~RenderDevice(); + GLRenderDevice(void* disp, void* window); + ~GLRenderDevice(); - void DeclareUniform(UniformName name, const char* glslname, UniformType type); - void DeclareShader(ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader); - void SetShader(ShaderName name); - void SetUniform(UniformName name, const void* values, int count); - void SetVertexBuffer(VertexBuffer* buffer); - void SetIndexBuffer(IndexBuffer* buffer); - void SetAlphaBlendEnable(bool value); - void SetAlphaTestEnable(bool value); - void SetCullMode(Cull mode); - void SetBlendOperation(BlendOperation op); - void SetSourceBlend(Blend blend); - void SetDestinationBlend(Blend blend); - void SetFillMode(FillMode mode); - void SetMultisampleAntialias(bool value); - void SetZEnable(bool value); - void SetZWriteEnable(bool value); - void SetTexture(Texture* texture); - void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy); - void SetSamplerState(TextureAddress address); - bool Draw(PrimitiveType type, int startIndex, int primitiveCount); - bool DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount); - bool DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data); - bool StartRendering(bool clear, int backcolor, Texture* target, bool usedepthbuffer); - bool FinishRendering(); - bool Present(); - bool ClearTexture(int backcolor, Texture* texture); - bool CopyTexture(Texture* dst, CubeMapFace face); + void DeclareUniform(UniformName name, const char* glslname, UniformType type) override; + void DeclareShader(ShaderName index, const char* name, const char* vertexshader, const char* fragmentshader) override; + void SetShader(ShaderName name) override; + void SetUniform(UniformName name, const void* values, int count) override; + void SetVertexBuffer(VertexBuffer* buffer) override; + void SetIndexBuffer(IndexBuffer* buffer) override; + void SetAlphaBlendEnable(bool value) override; + void SetAlphaTestEnable(bool value) override; + void SetCullMode(Cull mode) override; + void SetBlendOperation(BlendOperation op) override; + void SetSourceBlend(Blend blend) override; + void SetDestinationBlend(Blend blend) override; + void SetFillMode(FillMode mode) override; + void SetMultisampleAntialias(bool value) override; + void SetZEnable(bool value) override; + void SetZWriteEnable(bool value) override; + void SetTexture(Texture* texture) override; + void SetSamplerFilter(TextureFilter minfilter, TextureFilter magfilter, TextureFilter mipfilter, float maxanisotropy) override; + void SetSamplerState(TextureAddress address) override; + bool Draw(PrimitiveType type, int startIndex, int primitiveCount) override; + bool DrawIndexed(PrimitiveType type, int startIndex, int primitiveCount) override; + bool DrawData(PrimitiveType type, int startIndex, int primitiveCount, const void* data) override; + bool StartRendering(bool clear, int backcolor, Texture* target, bool usedepthbuffer) override; + bool FinishRendering() override; + bool Present() override; + bool ClearTexture(int backcolor, Texture* texture) override; + bool CopyTexture(Texture* dst, CubeMapFace face) override; - bool SetVertexBufferData(VertexBuffer* buffer, void* data, int64_t size, VertexFormat format); - bool SetVertexBufferSubdata(VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size); - bool SetIndexBufferData(IndexBuffer* buffer, void* data, int64_t size); + bool SetVertexBufferData(VertexBuffer* buffer, void* data, int64_t size, VertexFormat format) override; + bool SetVertexBufferSubdata(VertexBuffer* buffer, int64_t destOffset, void* data, int64_t size) override; + bool SetIndexBufferData(IndexBuffer* buffer, void* data, int64_t size) override; - bool SetPixels(Texture* texture, const void* data); - bool SetCubePixels(Texture* texture, CubeMapFace face, const void* data); - void* MapPBO(Texture* texture); - bool UnmapPBO(Texture* texture); + bool SetPixels(Texture* texture, const void* data) override; + bool SetCubePixels(Texture* texture, CubeMapFace face, const void* data) override; + void* MapPBO(Texture* texture) override; + bool UnmapPBO(Texture* texture) override; - bool InvalidateTexture(Texture* texture); + bool InvalidateTexture(GLTexture* texture); void GarbageCollectBuffer(int size, VertexFormat format); @@ -117,14 +93,14 @@ public: void SetError(const char* fmt, ...); const char* GetError(); - Shader* GetActiveShader(); + GLShader* GetActiveShader(); GLint GetGLMinFilter(TextureFilter filter, TextureFilter mipfilter); static std::mutex& GetMutex(); - static void DeleteObject(VertexBuffer* buffer); - static void DeleteObject(IndexBuffer* buffer); - static void DeleteObject(Texture* texture); + static void DeleteObject(GLVertexBuffer* buffer); + static void DeleteObject(GLIndexBuffer* buffer); + static void DeleteObject(GLTexture* texture); void ProcessDeleteList(); @@ -132,14 +108,14 @@ public: struct DeleteList { - std::vector VertexBuffers; - std::vector IndexBuffers; - std::vector Textures; + std::vector VertexBuffers; + std::vector IndexBuffers; + std::vector Textures; } mDeleteList; struct TextureUnit { - Texture* Tex = nullptr; + GLTexture* Tex = nullptr; TextureAddress WrapMode = TextureAddress::Wrap; GLuint SamplerHandle = 0; } mTextureUnit; @@ -167,11 +143,11 @@ public: int mVertexBuffer = -1; int64_t mVertexBufferStartIndex = 0; - IndexBuffer* mIndexBuffer = nullptr; + GLIndexBuffer* mIndexBuffer = nullptr; - std::unique_ptr mSharedVertexBuffers[2]; + std::unique_ptr mSharedVertexBuffers[2]; - std::unique_ptr mShaderManager; + std::unique_ptr mShaderManager; ShaderName mShaderName = {}; struct UniformInfo diff --git a/Source/Native/Shader.cpp b/Source/Native/OpenGL/GLShader.cpp similarity index 90% rename from Source/Native/Shader.cpp rename to Source/Native/OpenGL/GLShader.cpp index 690bdb0d..2160dcf1 100644 --- a/Source/Native/Shader.cpp +++ b/Source/Native/OpenGL/GLShader.cpp @@ -20,11 +20,11 @@ */ #include "Precomp.h" -#include "Shader.h" -#include "RenderDevice.h" +#include "GLShader.h" +#include "GLRenderDevice.h" #include -void Shader::Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest) +void GLShader::Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest) { mIdentifier = identifier; mVertexText = vertexShader; @@ -32,7 +32,7 @@ void Shader::Setup(const std::string& identifier, const std::string& vertexShade mAlphatest = alphatest; } -bool Shader::CheckCompile(RenderDevice* device) +bool GLShader::CheckCompile(GLRenderDevice* device) { bool firstCall = !mProgramBuilt; if (firstCall) @@ -47,7 +47,7 @@ bool Shader::CheckCompile(RenderDevice* device) return !mErrors.size(); } -std::string Shader::GetCompileError() +std::string GLShader::GetCompileError() { std::string lines = "Error compiling "; if (!mVertexShader) @@ -66,7 +66,7 @@ std::string Shader::GetCompileError() return lines; } -void Shader::Bind() +void GLShader::Bind() { if (!mProgram || !mProgramBuilt || mErrors.size()) return; @@ -74,7 +74,7 @@ void Shader::Bind() glUseProgram(mProgram); } -void Shader::CreateProgram(RenderDevice* device) +void GLShader::CreateProgram(GLRenderDevice* device) { const char* prefixNAT = R"( #version 150 @@ -136,7 +136,7 @@ void Shader::CreateProgram(RenderDevice* device) } } -GLuint Shader::CompileShader(const std::string& code, GLenum type) +GLuint GLShader::CompileShader(const std::string& code, GLenum type) { GLuint shader = glCreateShader(type); const GLchar* sources[] = { (GLchar*)code.data() }; @@ -159,7 +159,7 @@ GLuint Shader::CompileShader(const std::string& code, GLenum type) return shader; } -void Shader::ReleaseResources() +void GLShader::ReleaseResources() { if (mProgram) glDeleteProgram(mProgram); diff --git a/Source/Native/Shader.h b/Source/Native/OpenGL/GLShader.h similarity index 88% rename from Source/Native/Shader.h rename to Source/Native/OpenGL/GLShader.h index 2940242e..77b5c510 100644 --- a/Source/Native/Shader.h +++ b/Source/Native/OpenGL/GLShader.h @@ -22,17 +22,15 @@ #pragma once #include -#include "RenderDevice.h" +#include "GLRenderDevice.h" -enum class DeclarationUsage : int32_t { Position, Color, TextureCoordinate, Normal }; - -class Shader +class GLShader { public: void ReleaseResources(); void Setup(const std::string& identifier, const std::string& vertexShader, const std::string& fragmentShader, bool alphatest); - bool CheckCompile(RenderDevice *device); + bool CheckCompile(GLRenderDevice *device); void Bind(); std::string GetCompileError(); @@ -41,7 +39,7 @@ public: std::vector UniformLocations; private: - void CreateProgram(RenderDevice* device); + void CreateProgram(GLRenderDevice* device); GLuint CompileShader(const std::string& code, GLenum type); std::string mIdentifier; diff --git a/Source/Native/ShaderManager.cpp b/Source/Native/OpenGL/GLShaderManager.cpp similarity index 88% rename from Source/Native/ShaderManager.cpp rename to Source/Native/OpenGL/GLShaderManager.cpp index bf3b7a2e..8e4b8433 100644 --- a/Source/Native/ShaderManager.cpp +++ b/Source/Native/OpenGL/GLShaderManager.cpp @@ -20,9 +20,9 @@ */ #include "Precomp.h" -#include "ShaderManager.h" +#include "GLShaderManager.h" -void ShaderManager::DeclareShader(int i, const char* name, const char* vs, const char* ps) +void GLShaderManager::DeclareShader(int i, const char* name, const char* vs, const char* ps) { if (Shaders.size() <= (size_t)i) { @@ -34,7 +34,7 @@ void ShaderManager::DeclareShader(int i, const char* name, const char* vs, const AlphaTestShaders[i].Setup(name, vs, ps, true); } -void ShaderManager::ReleaseResources() +void GLShaderManager::ReleaseResources() { for (size_t i = 0; i < Shaders.size(); i++) { diff --git a/Source/Native/ShaderManager.h b/Source/Native/OpenGL/GLShaderManager.h similarity index 54% rename from Source/Native/ShaderManager.h rename to Source/Native/OpenGL/GLShaderManager.h index d2dce89a..10f737f7 100644 --- a/Source/Native/ShaderManager.h +++ b/Source/Native/OpenGL/GLShaderManager.h @@ -1,14 +1,14 @@ #pragma once -#include "Shader.h" +#include "GLShader.h" -class ShaderManager +class GLShaderManager { public: void ReleaseResources(); void DeclareShader(int index, const char* name, const char* vs, const char* ps); - std::vector AlphaTestShaders; - std::vector Shaders; + std::vector AlphaTestShaders; + std::vector Shaders; }; diff --git a/Source/Native/Texture.cpp b/Source/Native/OpenGL/GLTexture.cpp similarity index 85% rename from Source/Native/Texture.cpp rename to Source/Native/OpenGL/GLTexture.cpp index c85554a3..829da213 100644 --- a/Source/Native/Texture.cpp +++ b/Source/Native/OpenGL/GLTexture.cpp @@ -20,47 +20,47 @@ */ #include "Precomp.h" -#include "Texture.h" -#include "RenderDevice.h" +#include "GLTexture.h" +#include "GLRenderDevice.h" #include -Texture::Texture() +GLTexture::GLTexture() { } -Texture::~Texture() +GLTexture::~GLTexture() { if (Device) Invalidate(); } -void Texture::Set2DImage(int width, int height) +void GLTexture::Set2DImage(int width, int height) { mCubeTexture = false; mWidth = width; mHeight = height; } -void Texture::SetCubeImage(int size) +void GLTexture::SetCubeImage(int size) { mCubeTexture = true; mWidth = size; mHeight = size; } -void Texture::SetPixels(const void* data) +void GLTexture::SetPixels(const void* data) { mPixels[0].resize(mWidth * (size_t)mHeight); memcpy(mPixels[0].data(), data, sizeof(uint32_t) * mWidth * mHeight); } -void Texture::SetCubePixels(CubeMapFace face, const void* data) +void GLTexture::SetCubePixels(CubeMapFace face, const void* data) { mPixels[(int)face].resize(mWidth * (size_t)mHeight); memcpy(mPixels[(int)face].data(), data, sizeof(uint32_t) * mWidth * mHeight); } -void Texture::Invalidate() +void GLTexture::Invalidate() { if (mDepthRenderbuffer) glDeleteRenderbuffers(1, &mDepthRenderbuffer); if (mFramebuffer) glDeleteFramebuffers(1, &mFramebuffer); @@ -73,7 +73,7 @@ void Texture::Invalidate() Device = nullptr; } -GLuint Texture::GetTexture(RenderDevice* device) +GLuint GLTexture::GetTexture(GLRenderDevice* device) { if (mTexture == 0) { @@ -122,7 +122,7 @@ GLuint Texture::GetTexture(RenderDevice* device) return mTexture; } -GLuint Texture::GetFramebuffer(RenderDevice* device, bool usedepthbuffer) +GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer) { if (!usedepthbuffer) { @@ -164,7 +164,7 @@ GLuint Texture::GetFramebuffer(RenderDevice* device, bool usedepthbuffer) } } -GLuint Texture::GetPBO(RenderDevice* device) +GLuint GLTexture::GetPBO(GLRenderDevice* device) { if (mPBO == 0) { @@ -177,30 +177,3 @@ GLuint Texture::GetPBO(RenderDevice* device) return mPBO; } - -///////////////////////////////////////////////////////////////////////////// - -extern "C" -{ - -Texture* Texture_New() -{ - return new Texture(); -} - -void Texture_Delete(Texture* tex) -{ - RenderDevice::DeleteObject(tex); -} - -void Texture_Set2DImage(Texture* handle, int width, int height) -{ - handle->Set2DImage(width, height); -} - -void Texture_SetCubeImage(Texture* handle, int size) -{ - handle->SetCubeImage(size); -} - -} diff --git a/Source/Native/Texture.h b/Source/Native/OpenGL/GLTexture.h similarity index 78% rename from Source/Native/Texture.h rename to Source/Native/OpenGL/GLTexture.h index bc9c1fd4..6a7a83f7 100644 --- a/Source/Native/Texture.h +++ b/Source/Native/OpenGL/GLTexture.h @@ -21,26 +21,18 @@ #pragma once -enum class CubeMapFace : int -{ - PositiveX, - PositiveY, - PositiveZ, - NegativeX, - NegativeY, - NegativeZ -}; +#include "../Backend.h" -class RenderDevice; +class GLRenderDevice; -class Texture +class GLTexture : public Texture { public: - Texture(); - ~Texture(); + GLTexture(); + ~GLTexture(); - void Set2DImage(int width, int height); - void SetCubeImage(int size); + void Set2DImage(int width, int height) override; + void SetCubeImage(int size) override; void SetPixels(const void* data); void SetCubePixels(CubeMapFace face, const void* data); @@ -52,11 +44,11 @@ public: bool IsTextureCreated() const { return mTexture; } void Invalidate(); - GLuint GetTexture(RenderDevice* device); - GLuint GetFramebuffer(RenderDevice* device, bool usedepthbuffer); - GLuint GetPBO(RenderDevice* device); + GLuint GetTexture(GLRenderDevice* device); + GLuint GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer); + GLuint GetPBO(GLRenderDevice* device); - RenderDevice* Device = nullptr; + GLRenderDevice* Device = nullptr; private: int mWidth = 0; @@ -67,6 +59,5 @@ private: GLuint mTexture = 0; GLuint mFramebuffer = 0; GLuint mDepthRenderbuffer = 0; - // GLuint mPBO = 0; }; diff --git a/Source/Native/VertexBuffer.cpp b/Source/Native/OpenGL/GLVertexBuffer.cpp similarity index 71% rename from Source/Native/VertexBuffer.cpp rename to Source/Native/OpenGL/GLVertexBuffer.cpp index 4f99257d..b59b9408 100644 --- a/Source/Native/VertexBuffer.cpp +++ b/Source/Native/OpenGL/GLVertexBuffer.cpp @@ -20,22 +20,18 @@ */ #include "Precomp.h" -#include "VertexBuffer.h" -#include "Shader.h" -#include "RenderDevice.h" +#include "GLVertexBuffer.h" +#include "GLShader.h" +#include "GLRenderDevice.h" -SharedVertexBuffer::SharedVertexBuffer(VertexFormat format, int size) : Format(format), Size(size) -{ -} - -GLuint SharedVertexBuffer::GetBuffer() +GLuint GLSharedVertexBuffer::GetBuffer() { if (mBuffer == 0) glGenBuffers(1, &mBuffer); return mBuffer; } -GLuint SharedVertexBuffer::GetVAO() +GLuint GLSharedVertexBuffer::GetVAO() { if (!mVAO) { @@ -51,31 +47,31 @@ GLuint SharedVertexBuffer::GetVAO() return mVAO; } -void SharedVertexBuffer::SetupFlatVAO() +void GLSharedVertexBuffer::SetupFlatVAO() { glEnableVertexAttribArray((int)DeclarationUsage::Position); glEnableVertexAttribArray((int)DeclarationUsage::Color); glEnableVertexAttribArray((int)DeclarationUsage::TextureCoordinate); - glVertexAttribPointer((int)DeclarationUsage::Position, 3, GL_FLOAT, GL_FALSE, FlatStride, (const void*)0); - glVertexAttribPointer((int)DeclarationUsage::Color, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, FlatStride, (const void*)12); - glVertexAttribPointer((int)DeclarationUsage::TextureCoordinate, 2, GL_FLOAT, GL_FALSE, FlatStride, (const void*)16); + glVertexAttribPointer((int)DeclarationUsage::Position, 3, GL_FLOAT, GL_FALSE, VertexBuffer::FlatStride, (const void*)0); + glVertexAttribPointer((int)DeclarationUsage::Color, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, VertexBuffer::FlatStride, (const void*)12); + glVertexAttribPointer((int)DeclarationUsage::TextureCoordinate, 2, GL_FLOAT, GL_FALSE, VertexBuffer::FlatStride, (const void*)16); } -void SharedVertexBuffer::SetupWorldVAO() +void GLSharedVertexBuffer::SetupWorldVAO() { glEnableVertexAttribArray((int)DeclarationUsage::Position); glEnableVertexAttribArray((int)DeclarationUsage::Color); glEnableVertexAttribArray((int)DeclarationUsage::TextureCoordinate); glEnableVertexAttribArray((int)DeclarationUsage::Normal); - glVertexAttribPointer((int)DeclarationUsage::Position, 3, GL_FLOAT, GL_FALSE, WorldStride, (const void*)0); - glVertexAttribPointer((int)DeclarationUsage::Color, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, WorldStride, (const void*)12); - glVertexAttribPointer((int)DeclarationUsage::TextureCoordinate, 2, GL_FLOAT, GL_FALSE, WorldStride, (const void*)16); - glVertexAttribPointer((int)DeclarationUsage::Normal, 3, GL_FLOAT, GL_FALSE, WorldStride, (const void*)24); + glVertexAttribPointer((int)DeclarationUsage::Position, 3, GL_FLOAT, GL_FALSE, VertexBuffer::WorldStride, (const void*)0); + glVertexAttribPointer((int)DeclarationUsage::Color, GL_BGRA, GL_UNSIGNED_BYTE, GL_TRUE, VertexBuffer::WorldStride, (const void*)12); + glVertexAttribPointer((int)DeclarationUsage::TextureCoordinate, 2, GL_FLOAT, GL_FALSE, VertexBuffer::WorldStride, (const void*)16); + glVertexAttribPointer((int)DeclarationUsage::Normal, 3, GL_FLOAT, GL_FALSE, VertexBuffer::WorldStride, (const void*)24); } ///////////////////////////////////////////////////////////////////////////// -VertexBuffer::~VertexBuffer() +GLVertexBuffer::~GLVertexBuffer() { if (Device) { @@ -83,20 +79,3 @@ VertexBuffer::~VertexBuffer() Device = nullptr; } } - -///////////////////////////////////////////////////////////////////////////// - -extern "C" -{ - -VertexBuffer* VertexBuffer_New() -{ - return new VertexBuffer(); -} - -void VertexBuffer_Delete(VertexBuffer* buffer) -{ - RenderDevice::DeleteObject(buffer); -} - -} diff --git a/Source/Native/VertexBuffer.h b/Source/Native/OpenGL/GLVertexBuffer.h similarity index 77% rename from Source/Native/VertexBuffer.h rename to Source/Native/OpenGL/GLVertexBuffer.h index 96a77c98..ea16d6f4 100644 --- a/Source/Native/VertexBuffer.h +++ b/Source/Native/OpenGL/GLVertexBuffer.h @@ -23,15 +23,15 @@ #include -enum class VertexFormat : int32_t { Flat, World }; +#include "../Backend.h" -class RenderDevice; -class VertexBuffer; +class GLRenderDevice; +class GLVertexBuffer; -class SharedVertexBuffer +class GLSharedVertexBuffer { public: - SharedVertexBuffer(VertexFormat format, int size); + GLSharedVertexBuffer(VertexFormat format, int size) : Format(format), Size(size) { } GLuint GetBuffer(); GLuint GetVAO(); @@ -41,10 +41,7 @@ public: int NextPos = 0; int Size = 0; - std::list VertexBuffers; - - static const int FlatStride = 24; - static const int WorldStride = 36; + std::list VertexBuffers; static void SetupFlatVAO(); static void SetupWorldVAO(); @@ -54,15 +51,15 @@ private: GLuint mVAO = 0; }; -class VertexBuffer +class GLVertexBuffer : public VertexBuffer { public: - ~VertexBuffer(); + ~GLVertexBuffer(); VertexFormat Format = VertexFormat::Flat; - RenderDevice* Device = nullptr; - std::list::iterator ListIt; + GLRenderDevice* Device = nullptr; + std::list::iterator ListIt; int BufferOffset = 0; int BufferStartIndex = 0; diff --git a/Source/Native/OpenGLContext.cpp b/Source/Native/OpenGL/OpenGLContext.cpp similarity index 100% rename from Source/Native/OpenGLContext.cpp rename to Source/Native/OpenGL/OpenGLContext.cpp diff --git a/Source/Native/OpenGLContext.h b/Source/Native/OpenGL/OpenGLContext.h similarity index 100% rename from Source/Native/OpenGLContext.h rename to Source/Native/OpenGL/OpenGLContext.h diff --git a/Source/Native/gl_load/gl_extlist.txt b/Source/Native/OpenGL/gl_load/gl_extlist.txt similarity index 100% rename from Source/Native/gl_load/gl_extlist.txt rename to Source/Native/OpenGL/gl_load/gl_extlist.txt diff --git a/Source/Native/gl_load/gl_load.c b/Source/Native/OpenGL/gl_load/gl_load.c similarity index 100% rename from Source/Native/gl_load/gl_load.c rename to Source/Native/OpenGL/gl_load/gl_load.c diff --git a/Source/Native/gl_load/gl_load.h b/Source/Native/OpenGL/gl_load/gl_load.h similarity index 100% rename from Source/Native/gl_load/gl_load.h rename to Source/Native/OpenGL/gl_load/gl_load.h diff --git a/Source/Native/gl_load/gl_system.h b/Source/Native/OpenGL/gl_load/gl_system.h similarity index 95% rename from Source/Native/gl_load/gl_system.h rename to Source/Native/OpenGL/gl_load/gl_system.h index 0ad2f330..25cf0e42 100644 --- a/Source/Native/gl_load/gl_system.h +++ b/Source/Native/OpenGL/gl_load/gl_system.h @@ -24,7 +24,7 @@ #include //GL headers -#include "gl_load/gl_load.h" +#include "OpenGL/gl_load/gl_load.h" #if defined(__APPLE__) #include diff --git a/Source/Native/Precomp.h b/Source/Native/Precomp.h index 8126aa23..569fc710 100644 --- a/Source/Native/Precomp.h +++ b/Source/Native/Precomp.h @@ -34,7 +34,7 @@ #undef max #endif -#include "gl_load/gl_system.h" +#include "OpenGL/gl_load/gl_system.h" #define APART(x) (static_cast(x) >> 24) #define RPART(x) ((static_cast(x) >> 16) & 0xff)