#pragma once #include "StarTextureAtlas.hpp" #include "StarRenderer.hpp" #include "GL/glew.h" namespace Star { STAR_CLASS(OpenGlRenderer); constexpr size_t FrameBufferCount = 1; // OpenGL 2.0 implementation of Renderer. OpenGL context must be created and // active during construction, destruction, and all method calls. class OpenGlRenderer : public Renderer { public: OpenGlRenderer(); ~OpenGlRenderer(); String rendererId() const override; Vec2U screenSize() const override; void loadConfig(Json const& config) override; void loadEffectConfig(String const& name, Json const& effectConfig, StringMap const& shaders) override; void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override; void setEffectTexture(String const& textureName, ImageView const& image) override; void setScissorRect(Maybe const& scissorRect) override; bool switchEffectConfig(String const& name) override; TexturePtr createTexture(Image const& texture, TextureAddressing addressing, TextureFiltering filtering) override; void setSizeLimitEnabled(bool enabled) override; void setMultiTexturingEnabled(bool enabled) override; void setMultiSampling(unsigned multiSampling) override; TextureGroupPtr createTextureGroup(TextureGroupSize size, TextureFiltering filtering) override; RenderBufferPtr createRenderBuffer() override; List& immediatePrimitives() override; void render(RenderPrimitive primitive) override; void renderBuffer(RenderBufferPtr const& renderBuffer, Mat3F const& transformation) override; void flush() override; void setScreenSize(Vec2U screenSize); void startFrame(); void finishFrame(); private: struct GlTextureAtlasSet : public TextureAtlasSet { public: GlTextureAtlasSet(unsigned atlasNumCells); GLuint createAtlasTexture(Vec2U const& size, PixelFormat pixelFormat) override; void destroyAtlasTexture(GLuint const& glTexture) override; void copyAtlasPixels(GLuint const& glTexture, Vec2U const& bottomLeft, Image const& image) override; TextureFiltering textureFiltering; }; struct GlTextureGroup : enable_shared_from_this, public TextureGroup { GlTextureGroup(unsigned atlasNumCells); ~GlTextureGroup(); TextureFiltering filtering() const override; TexturePtr create(Image const& texture) override; GlTextureAtlasSet textureAtlasSet; }; struct GlTexture : public Texture { virtual GLuint glTextureId() const = 0; virtual Vec2U glTextureSize() const = 0; virtual Vec2U glTextureCoordinateOffset() const = 0; }; struct GlGroupedTexture : public GlTexture { ~GlGroupedTexture(); Vec2U size() const override; TextureFiltering filtering() const override; TextureAddressing addressing() const override; GLuint glTextureId() const override; Vec2U glTextureSize() const override; Vec2U glTextureCoordinateOffset() const override; void incrementBufferUseCount(); void decrementBufferUseCount(); unsigned bufferUseCount = 0; shared_ptr parentGroup; GlTextureAtlasSet::TextureHandle parentAtlasTexture = nullptr; }; struct GlLoneTexture : public GlTexture { ~GlLoneTexture(); Vec2U size() const override; TextureFiltering filtering() const override; TextureAddressing addressing() const override; GLuint glTextureId() const override; Vec2U glTextureSize() const override; Vec2U glTextureCoordinateOffset() const override; GLuint textureId = 0; Vec2U textureSize; TextureAddressing textureAddressing = TextureAddressing::Clamp; TextureFiltering textureFiltering = TextureFiltering::Nearest; }; struct GlPackedVertexData { uint32_t textureIndex : 2; uint32_t fullbright : 1; uint32_t rX : 1; uint32_t rY : 1; uint32_t unused : 27; }; struct GlRenderVertex { Vec2F pos; Vec2F uv; Vec4B color; union Packed { uint32_t packed; GlPackedVertexData vars; } pack; }; struct GlRenderBuffer : public RenderBuffer { struct GlVertexBufferTexture { GLuint texture; Vec2U size; }; struct GlVertexBuffer { List textures; GLuint vertexBuffer = 0; size_t vertexCount = 0; }; ~GlRenderBuffer(); void set(List& primitives) override; RefPtr whiteTexture; ByteArray accumulationBuffer; HashSet usedTextures; List vertexBuffers; bool useMultiTexturing{true}; }; struct EffectParameter { GLint parameterUniform = -1; VariantTypeIndex parameterType = 0; Maybe parameterValue; }; struct EffectTexture { GLint textureUniform = -1; unsigned textureUnit = 0; TextureAddressing textureAddressing = TextureAddressing::Clamp; TextureFiltering textureFiltering = TextureFiltering::Linear; GLint textureSizeUniform = -1; RefPtr textureValue; }; struct GlFrameBuffer : RefCounter { GLuint id = 0; RefPtr texture; Json config; bool blitted = false; unsigned multisample = 0; GlFrameBuffer(Json const& config); ~GlFrameBuffer(); }; class Effect { public: GLuint program = 0; Json config; StringMap parameters; StringMap textures; StringMap attributes; StringMap uniforms; GLuint getAttribute(String const& name); GLuint getUniform(String const& name); }; static bool logGlErrorSummary(String prefix); static void uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data); static RefPtr createGlTexture(ImageView const& image, TextureAddressing addressing, TextureFiltering filtering); shared_ptr createGlRenderBuffer(); void flushImmediatePrimitives(); void renderGlBuffer(GlRenderBuffer const& renderBuffer, Mat3F const& transformation); void setupGlUniforms(Effect& effect); RefPtr getGlFrameBuffer(String const& id); void blitGlFrameBuffer(RefPtr const& frameBuffer); void switchGlFrameBuffer(RefPtr const& frameBuffer); Vec2U m_screenSize; GLuint m_program = 0; GLint m_positionAttribute = -1; GLint m_colorAttribute = -1; GLint m_texCoordAttribute = -1; GLint m_dataAttribute = -1; List m_textureUniforms = {}; List m_textureSizeUniforms = {}; GLint m_screenSizeUniform = -1; GLint m_vertexTransformUniform = -1; Json m_config; StringMap m_effects; Effect* m_currentEffect; StringMap> m_frameBuffers; RefPtr m_currentFrameBuffer; RefPtr m_whiteTexture; Maybe m_scissorRect; bool m_limitTextureGroupSize; bool m_useMultiTexturing; unsigned m_multiSampling; // if non-zero, is enabled and acts as sample count List> m_liveTextureGroups; List m_immediatePrimitives; shared_ptr m_immediateRenderBuffer; }; }