#ifndef STAR_RENDERER_OPENGL_HPP #define STAR_RENDERER_OPENGL_HPP #include "StarTextureAtlas.hpp" #include "StarRenderer.hpp" #include "GL/glew.h" namespace Star { STAR_CLASS(OpenGl20Renderer); 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 OpenGl20Renderer : public Renderer { public: OpenGl20Renderer(); ~OpenGl20Renderer(); 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, Image 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; 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 GlRenderVertex { Vec2F screenCoordinate; Vec2F textureCoordinate; float textureIndex; Vec4B color; float param1; }; 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; 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(Image const& texture, 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_texCoordAttribute = -1; GLint m_texIndexAttribute = -1; GLint m_colorAttribute = -1; GLint m_param1Attribute = -1; List m_textureUniforms = {}; List m_textureSizeUniforms = {}; GLint m_screenSizeUniform = -1; GLint m_vertexTransformUniform = -1; StringMap m_effects; Effect* m_currentEffect; StringMap> m_frameBuffers; RefPtr m_currentFrameBuffer; RefPtr m_whiteTexture; Maybe m_scissorRect; bool m_limitTextureGroupSize; bool m_useMultiTexturing; List> m_liveTextureGroups; List m_immediatePrimitives; shared_ptr m_immediateRenderBuffer; }; } #endif