diff options
Diffstat (limited to 'src/GalOgl.cpp')
-rw-r--r-- | src/GalOgl.cpp | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/src/GalOgl.cpp b/src/GalOgl.cpp new file mode 100644 index 0000000..4fb2794 --- /dev/null +++ b/src/GalOgl.cpp @@ -0,0 +1,836 @@ +#include "Gal.hpp" + +#include <easylogging++.h> +#include <GL/glew.h> + +#include "Utility.hpp" + +using namespace Gal; + +class ImplOgl; +class FramebufferDefaultOgl; +class ShaderOgl; + +std::unique_ptr<ImplOgl> impl; +std::shared_ptr<FramebufferDefaultOgl> fbDefault; + +size_t GalTypeGetComponents(Gal::Type type) { + switch (type) { + case Type::Float: + case Type::Double: + case Type::Uint8: + case Type::Uint16: + case Type::Uint32: + case Type::Int8: + case Type::Int16: + case Type::Int32: + return 1; + case Type::Vec2: + case Type::Vec2u8: + case Type::Vec2u16: + case Type::Vec2u32: + case Type::Vec2i8: + case Type::Vec2i16: + case Type::Vec2i32: + return 2; + case Type::Vec3: + case Type::Vec3u8: + case Type::Vec3u16: + case Type::Vec3u32: + case Type::Vec3i8: + case Type::Vec3i16: + case Type::Vec3i32: + return 3; + case Type::Vec4: + case Type::Vec4u8: + case Type::Vec4u16: + case Type::Vec4u32: + case Type::Vec4i8: + case Type::Vec4i16: + case Type::Vec4i32: + case Type::Mat2: + return 4; + case Type::Mat3: + return 9; + case Type::Mat4: + return 16; + default: + return 0; + } + return 0; +} + +size_t GalTypeGetComponentSize(Gal::Type type) { + switch (type) { + case Type::Uint8: + case Type::Int8: + case Type::Vec2u8: + case Type::Vec2i8: + case Type::Vec3u8: + case Type::Vec3i8: + case Type::Vec4u8: + case Type::Vec4i8: + return 1; + case Type::Uint16: + case Type::Int16: + case Type::Vec2u16: + case Type::Vec2i16: + case Type::Vec3u16: + case Type::Vec3i16: + case Type::Vec4u16: + case Type::Vec4i16: + return 2; + case Type::Float: + case Type::Uint32: + case Type::Int32: + case Type::Vec2: + case Type::Vec2u32: + case Type::Vec2i32: + case Type::Vec3: + case Type::Vec3u32: + case Type::Vec3i32: + case Type::Vec4: + case Type::Vec4u32: + case Type::Vec4i32: + case Type::Mat2: + case Type::Mat3: + case Type::Mat4: + return 4; + case Type::Double: + return 8; + default: + return 0; + } +} + +size_t GalTypeGetSize(Gal::Type type) { + return GalTypeGetComponents(type) * GalTypeGetComponentSize(type); +} + +GLenum GalTypeGetComponentGlType(Gal::Type type) { + switch (type) { + case Type::Float: + case Type::Vec2: + case Type::Vec3: + case Type::Vec4: + case Type::Mat2: + case Type::Mat3: + case Type::Mat4: + return GL_FLOAT; + case Type::Double: + return GL_DOUBLE; + case Type::Uint8: + case Type::Vec2u8: + case Type::Vec3u8: + case Type::Vec4u8: + return GL_UNSIGNED_BYTE; + case Type::Uint16: + case Type::Vec2u16: + case Type::Vec3u16: + case Type::Vec4u16: + return GL_UNSIGNED_SHORT; + case Type::Uint32: + case Type::Vec2u32: + case Type::Vec3u32: + case Type::Vec4u32: + return GL_UNSIGNED_INT; + case Type::Int8: + case Type::Vec2i8: + case Type::Vec3i8: + case Type::Vec4i8: + return GL_BYTE; + case Type::Int16: + case Type::Vec2i16: + case Type::Vec3i16: + case Type::Vec4i16: + return GL_SHORT; + case Type::Int32: + case Type::Vec2i32: + case Type::Vec3i32: + case Type::Vec4i32: + return GL_INT; + default: + return 0; + } + return 0; +} + +size_t GalFormatGetSize(Format format) { + switch (format) { + case Format::R8G8B8: + return 3; + case Format::R8G8B8A8: + return 4; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlInternalFormat(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_RGB8; + case Format::R8G8B8A8: + return GL_RGBA8; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlFormat(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_RGB; + case Format::R8G8B8A8: + return GL_RGBA; + default: + return 0; + } + return 0; +} + +GLenum GalFormatGetGlType(Format format) { + switch (format) { + case Format::R8G8B8: + return GL_UNSIGNED_BYTE; + case Format::R8G8B8A8: + return GL_UNSIGNED_BYTE; + default: + return 0; + } + return 0; +} + +GLenum GalFilteringGetGlType(Filtering filtering) { + switch (filtering) { + case Filtering::Nearest: + return GL_NEAREST; + case Filtering::Bilinear: + return GL_LINEAR; + case Filtering::Trilinear: + return GL_LINEAR_MIPMAP_LINEAR; + case Filtering::Anisotropy: + return GL_LINEAR; + default: + return 0; + } + return 0; +} + +GLenum GalWrappingGetGlType(Wrapping wrapping) { + switch (wrapping) { + case Wrapping::Repeat: + return GL_REPEAT; + case Wrapping::Clamp: + return GL_CLAMP_TO_EDGE; + case Wrapping::Mirror: + return GL_MIRRORED_REPEAT; + default: + return 0; + } + return 0; +} + + +class ShaderOgl : public Shader { +public: + bool isVertex = true; + std::string code; +}; + +class BufferBindingOgl : public BufferBinding { +public: + BufferBindingOgl(size_t id) : bufferId(id) {} + + const size_t bufferId; + + static constexpr size_t indexValue = (std::numeric_limits<size_t>::max)(); //parenthess for windows' max macro +}; + +class BufferOgl : public Buffer { +public: + GLuint vbo; + + virtual void SetData(std::vector<std::byte>&& data) override { + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, data.size(), data.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glCheckError(); + } +}; + +class TextureConfigOgl : public TextureConfig { +public: + + Format format; + size_t width = 0, height = 0, depth = 0; + bool interpolateLayers = false; + + Filtering min = Filtering::Nearest, max = Filtering::Nearest; + Wrapping wrap = Wrapping::Clamp; + + + virtual void SetMinFilter(Filtering filter) override { + min = filter; + } + + virtual void SetMaxFilter(Filtering filter) override { + max = filter; + } + + virtual void SetWrapping(Wrapping wrapping) override { + wrap = wrapping; + } + +}; + +class TextureOgl : public Texture { +public: + + GLenum type; + GLuint texture; + Format format; + size_t width = 0, height = 0, depth = 0; + + virtual void SetData(std::vector<std::byte>&& data, size_t mipLevel = 0) override { + if (data.size() != width * height * depth * GalFormatGetSize(format)) + throw std::logic_error("Size of data is not valid for this texture"); + + glBindTexture(type, texture); + glCheckError(); + + switch (type) { + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + case GL_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_PROXY_TEXTURE_CUBE_MAP: + glTexImage2D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.data()); + break; + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D_ARRAY: + glTexImage3D(type, mipLevel, GalFormatGetGlInternalFormat(format), width, height, depth, 0, GalFormatGetGlFormat(format), GalFormatGetGlType(format), data.data()); + break; + default: + throw std::runtime_error("Unknown texture type"); + } + + glCheckError(); + + glBindTexture(type, 0); + } + +}; + +class PipelineConfigOgl : public PipelineConfig { +public: + std::shared_ptr<ShaderOgl> vertexShader, pixelShader; + std::map<std::string, Type> shaderParameters; + std::shared_ptr<Framebuffer> targetFb; + std::vector<std::vector<VertexAttribute>> vertexBuffers; + +public: + virtual void SetVertexShader(std::shared_ptr<Shader> shader) override { + vertexShader = std::static_pointer_cast<ShaderOgl,Shader>(shader); + } + + virtual void SetPixelShader(std::shared_ptr<Shader> shader) override { + pixelShader = std::static_pointer_cast<ShaderOgl, Shader>(shader); + } + + virtual void AddShaderParameter(std::string_view name, Type type) override { + shaderParameters.emplace(std::string(name), type); + } + + virtual void SetTarget(std::shared_ptr<Framebuffer> target) override { + targetFb = target; + } + + virtual std::shared_ptr<BufferBinding> BindVertexBuffer(std::vector<VertexAttribute> &&bufferLayout) override { + auto binding = std::make_shared<BufferBindingOgl>(vertexBuffers.size()); + vertexBuffers.push_back(bufferLayout); + return std::static_pointer_cast<BufferBinding, BufferBindingOgl>(binding); + } + + virtual std::shared_ptr<BufferBinding> BindIndexBuffer() override { + auto binding = std::make_shared<BufferBindingOgl>(BufferBindingOgl::indexValue); + return std::static_pointer_cast<BufferBinding, BufferBindingOgl>(binding); + } + +}; + +class PipelineInstanceOgl : public PipelineInstance { +public: + GLuint vao; + + virtual void Activate() override { + glBindVertexArray(vao); + glCheckError(); + } + + virtual void Render(size_t offset = 0, size_t count = -1) override { + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0); + glCheckError(); + } +}; + +class PipelineOgl : public Pipeline { +public: + std::map<std::string, size_t> shaderParameters; + GLuint program; + struct VertexBindingCommand { + size_t bufferId; + size_t location; + GLenum type; + size_t count; + size_t stride; + size_t offset; + }; + std::vector<VertexBindingCommand> vertexBindCmds; + + virtual void Activate() override { + glUseProgram(program); + glCheckError(); + } + + virtual std::shared_ptr<PipelineInstance> CreateInstance(std::vector<std::pair<std::shared_ptr<BufferBinding>, std::shared_ptr<Buffer>>>&& buffers) override { + auto instance = std::make_shared<PipelineInstanceOgl>(); + + size_t indexBuffer = BufferBindingOgl::indexValue; + std::map<size_t, size_t> bufferBindingId; + + for (auto&& [binding, buffer] : buffers) { + auto bind = std::static_pointer_cast<BufferBindingOgl, BufferBinding>(binding); + auto buff = std::static_pointer_cast<BufferOgl, Buffer>(buffer); + + if (bind->bufferId == BufferBindingOgl::indexValue) + indexBuffer = buff->vbo; + else + bufferBindingId.insert({ bind->bufferId,buff->vbo }); + } + + glGenVertexArrays(1, &instance->vao); + glBindVertexArray(instance->vao); + glCheckError(); + + for (const auto& cmd : vertexBindCmds) { + glBindBuffer(GL_ARRAY_BUFFER, bufferBindingId.find(cmd.bufferId)->second); + glCheckError(); + switch (cmd.type) { + case GL_FLOAT: + case GL_DOUBLE: + glVertexAttribPointer(cmd.location, cmd.count, cmd.type, GL_FALSE, cmd.offset, reinterpret_cast<void*>(cmd.stride)); + break; + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_UNSIGNED_SHORT: + case GL_SHORT: + case GL_UNSIGNED_INT: + case GL_INT: + glVertexAttribIPointer(cmd.location, cmd.count, cmd.type, cmd.offset, reinterpret_cast<void*>(cmd.stride)); + break; + } + + glCheckError(); + glEnableVertexAttribArray(cmd.location); + glCheckError(); + } + + if (indexBuffer != BufferBindingOgl::indexValue) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glCheckError(); + + return instance; + } + + virtual void SetShaderParameter(std::string_view name, float value) override { + Activate(); + glUniform1f(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, double value) override { + Activate(); + glUniform1d(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int8_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int16_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, int32_t value) override { + Activate(); + glUniform1i(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint8_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint16_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, uint32_t value) override { + Activate(); + glUniform1ui(shaderParameters.at(std::string(name)), value); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec2 value) override { + Activate(); + glUniform2f(shaderParameters.at(std::string(name)), value.x, value.y); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::uvec2 value) override { + Activate(); + glUniform2ui(shaderParameters.at(std::string(name)), value.x, value.y); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec3 value) override { + Activate(); + glUniform3f(shaderParameters.at(std::string(name)), value.x, value.y, value.z); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::vec4 value) override { + Activate(); + glUniform4f(shaderParameters.at(std::string(name)), value.x, value.y, value.z, value.w); + glCheckError(); + } + + virtual void SetShaderParameter(std::string_view name, glm::mat4 value) override { + Activate(); + glCheckError(); + } +}; + +class ImplOgl : public Impl { + +public: + + virtual void Init() override { + LOG(INFO) << "Initalizing Gal:OpenGL..."; + LOG(INFO) << "Initializing GLEW"; + glewExperimental = GL_TRUE; + GLenum glewStatus = glewInit(); + glCheckError(); + if (glewStatus != GLEW_OK) { + LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus); + } + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCheckError(); + if (glActiveTexture == nullptr) { + throw std::runtime_error("GLEW initialization failed with unknown reason"); + } + } + + virtual void DeInit() override { + LOG(INFO) << "Destroying Gal:OpenGL..."; + } + + virtual void Cleanup() override { + + } + + + virtual std::shared_ptr<Buffer> CreateBuffer() override { + auto buff = std::make_shared<BufferOgl>(); + glGenBuffers(1, &buff->vbo); + buff->SetData({}); + glCheckError(); + return std::static_pointer_cast<Buffer, BufferOgl>(buff); + } + + + virtual std::shared_ptr<TextureConfig> CreateTexture2DConfig(size_t width, size_t height, Format format) override { + auto config = std::make_shared<TextureConfigOgl>(); + + config->width = width; + config->height = height; + config->format = format; + + return std::static_pointer_cast<TextureConfig, TextureConfigOgl>(config); + } + + virtual std::shared_ptr<TextureConfig> CreateTexture3DConfig(size_t width, size_t height, size_t depth, bool interpolateLayers, Format format) override { + auto config = std::make_shared<TextureConfigOgl>(); + + config->width = width; + config->height = height; + config->depth = depth; + config->interpolateLayers = interpolateLayers; + config->format = format; + + return std::static_pointer_cast<TextureConfig, TextureConfigOgl>(config); + } + + virtual std::shared_ptr<Texture> BuildTexture(std::shared_ptr<TextureConfig> config) override { + auto texConfig = std::static_pointer_cast<TextureConfigOgl, TextureConfig>(config); + auto texture = std::make_shared<TextureOgl>(); + + texture->type = GL_TEXTURE_2D; + texture->format = texConfig->format; + texture->width = texConfig->width; + texture->height = texConfig->height; + texture->depth = texConfig->depth; + + glGenTextures(1, &texture->texture); + glCheckError(); + + glTexParameteri(texture->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(texture->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glCheckError(); + + texture->SetData(std::vector<std::byte>(texture->width * texture->height * texture->depth * GalFormatGetSize(texture->format))); + glCheckError(); + + return std::static_pointer_cast<Texture, TextureOgl>(texture); + } + + + virtual std::shared_ptr<PipelineConfig> CreatePipelineConfig() override { + auto pipelineConfig = std::make_shared<PipelineConfigOgl>(); + return std::static_pointer_cast<PipelineConfig, PipelineConfigOgl>(pipelineConfig); + } + + virtual std::shared_ptr<Pipeline> BuildPipeline(std::shared_ptr<PipelineConfig> pipelineConfig) override { + auto pipeline = std::make_shared<PipelineOgl>(); + auto config = std::static_pointer_cast<PipelineConfigOgl, PipelineConfig>(pipelineConfig); + + //Shader compilation + + bool vertexFailed = false, pixelFailed = false, linkFailed = false; + + const GLchar* vertexSourcePtr = config->vertexShader->code.c_str(); + const GLchar* pixelSourcePtr = config->pixelShader->code.c_str(); + + GLuint vertex, pixel; + GLint success; + GLuint program; + GLchar infoLog[512]; + + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vertexSourcePtr, NULL); + glCompileShader(vertex); + + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + LOG(ERROR) << "Vertex shader compilation failed: " << std::endl << infoLog; + vertexFailed = true; + }; + + pixel = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(pixel, 1, &pixelSourcePtr, NULL); + glCompileShader(pixel); + + glGetShaderiv(pixel, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(pixel, 512, NULL, infoLog); + LOG(ERROR) << "Fragment shader compilation failed: " << std::endl << infoLog; + pixelFailed = true; + }; + + if (vertexFailed || pixelFailed) + throw std::runtime_error("Shaders not compiled"); + + program = glCreateProgram(); + glAttachShader(program, vertex); + glAttachShader(program, pixel); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(program, 512, NULL, infoLog); + LOG(ERROR) << "Shader program not linked: " << std::endl << infoLog; + linkFailed = true; + } + + glDeleteShader(vertex); + glDeleteShader(pixel); + + if (linkFailed) + throw std::runtime_error("Shader not linked"); + + glUseProgram(program); + + glCheckError(); + + pipeline->program = program; + + //Shader parameters + + for (auto&& [name, type] : config->shaderParameters) { + GLint location = glGetUniformLocation(program, name.c_str()); + if (location < 0) { + glDeleteProgram(program); + LOG(ERROR) << "Uniform name \"" << name << "\" not found in shader"; + throw std::runtime_error("Invalid uniform"); + } + switch (type) { + case Type::Vec2: + glUniform2f(location, 0.0f, 0.0f); + break; + case Type::Vec2u8: + case Type::Vec2u16: + case Type::Vec2u32: + glUniform2ui(location, 0, 0); + break; + case Type::Vec4u8: + glUniform4ui(location, 0, 0, 0, 0); + break; + } + pipeline->shaderParameters.insert({ name,location }); + } + + //Vertex attributes + + size_t bufferId = 0; + for (const auto& buffer : config->vertexBuffers) { + size_t vertexSize = 0; + size_t cmdOffset = pipeline->vertexBindCmds.size(); + for (const auto& [name, type] : buffer) { + if (name.empty()) { + vertexSize += GalTypeGetSize(type); + continue; + } + + GLint location = glGetAttribLocation(program, name.c_str()); + if (location < 0) { + glDeleteProgram(program); + LOG(ERROR) << "Vertex attribute name \"" << name << "\" not found in shader"; + throw std::runtime_error("Invalid attribute"); + } + + size_t attribSize = GalTypeGetSize(type); + + pipeline->vertexBindCmds.push_back({ + bufferId, + static_cast<size_t>(location), + GalTypeGetComponentGlType(type), + GalTypeGetComponents(type), + vertexSize, + 0 + }); + + vertexSize += attribSize; + } + + for (size_t i = cmdOffset; i < pipeline->vertexBindCmds.size(); i++) + pipeline->vertexBindCmds[i].offset = vertexSize; + + bufferId++; + } + + glCheckError(); + + return pipeline; + } + + virtual std::shared_ptr<FramebufferConfig> CreateFramebufferConfig() override { + return nullptr; + } + + virtual std::shared_ptr<Framebuffer> BuildFramebuffer(std::shared_ptr<FramebufferConfig> config) override { + return nullptr; + } + + virtual std::shared_ptr<Framebuffer> GetDefaultFramebuffer() override { + if (!fbDefault) + fbDefault = std::make_shared<FramebufferDefaultOgl>(); + return std::static_pointer_cast<Framebuffer, FramebufferDefaultOgl>(fbDefault); + } + + + virtual std::shared_ptr<ShaderParameters> GetGlobalShaderParameters() override { + return nullptr; + } + + virtual std::shared_ptr<Shader> LoadVertexShader(std::string_view code) override { + auto shader = std::make_shared<ShaderOgl>(); + shader->code = code; + shader->isVertex = true; + return std::static_pointer_cast<Shader, ShaderOgl>(shader); + } + + virtual std::shared_ptr<Shader> LoadPixelShader(std::string_view code) override { + auto shader = std::make_shared<ShaderOgl>(); + shader->code = code; + shader->isVertex = false; + return std::static_pointer_cast<Shader, ShaderOgl>(shader); + } +}; + +class FramebufferDefaultOgl : public Framebuffer { + size_t vpX, vpY, vpW, vpH; +public: + + virtual void Clear() override { + GLbitfield clearBits = 0; + clearBits |= GL_COLOR_BUFFER_BIT; + clearBits |= GL_DEPTH_BUFFER_BIT; + clearBits |= GL_STENCIL_BUFFER_BIT; + glClear(clearBits); + } + + virtual void SetViewport(size_t x, size_t y, size_t w, size_t h) override { + vpX = x; + vpY = y; + vpW = w; + vpH = h; + glViewport(x, y, w, h); + } +}; + +Impl* Gal::GetImplementation() +{ + if (!impl) + impl = std::make_unique<ImplOgl>(); + + return impl.get(); +} |