#pragma once #include "BsGLPrerequisites.h" #include "BsRenderAPI.h" #include "BsGLHardwareBufferManager.h" #include "BsGLSLProgramFactory.h" #include "BsVector4.h" namespace BansheeEngine { /** * @brief Implementation of a render system using OpenGL. Provides abstracted * access to various low level OpenGL methods. */ class BS_RSGL_EXPORT GLRenderAPI : public RenderAPICore { public: GLRenderAPI(); ~GLRenderAPI(); /** * @copydoc RenderAPICore::getName() */ const StringID& getName() const override; /** * @copydoc RenderAPICore::getShadingLanguageName() */ const String& getShadingLanguageName() const override; /** * @copydoc RenderAPICore::setRenderTarget() */ void setRenderTarget(const SPtr& target) override; /** * @copydoc RenderAPICore::setVertexBuffers() */ void setVertexBuffers(UINT32 index, SPtr* buffers, UINT32 numBuffers) override; /** * @copydoc RenderAPICore::setIndexBuffer() */ void setIndexBuffer(const SPtr& buffer) override; /** * @copydoc RenderAPICore::setVertexDeclaration() */ void setVertexDeclaration(const SPtr& vertexDeclaration) override; /** * @copydoc RenderAPICore::setDrawOperation() */ void setDrawOperation(DrawOperationType op) override; /** * @copydoc RenderAPICore::setScissorRect() */ void setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom) override; /** * @copydoc RenderAPICore::setTexture() */ void setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const SPtr& tex) override; /** * @copydoc RenderAPICore::setLoadStoreTexture */ void setLoadStoreTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const SPtr& texPtr, const TextureSurface& surface) override; /** * @copydoc RenderAPICore::setSamplerState() */ void setSamplerState(GpuProgramType gptype, UINT16 unit, const SPtr& state) override; /** * @copydoc RenderAPICore::setBlendState() */ void setBlendState(const SPtr& blendState) override; /** * @copydoc RenderAPICore::setRasterizerState() */ void setRasterizerState(const SPtr& rasterizerState) override; /** * @copydoc RenderAPICore::setDepthStencilState() */ void setDepthStencilState(const SPtr& depthStencilState, UINT32 stencilRefValue) override; /** * @copydoc RenderAPICore::setViewport() */ void setViewport(const Rect2& area) override; /** * @copydoc RenderAPICore::bindGpuProgram() */ void bindGpuProgram(const SPtr& prg) override; /** * @copydoc RenderAPICore::unbindGpuProgram() */ void unbindGpuProgram(GpuProgramType gptype) override; /** * @copydoc RenderAPICore::setConstantBuffers() */ void setConstantBuffers(GpuProgramType gptype, const SPtr& params) override; /** * @copydoc RenderAPICore::beginFrame() */ void beginFrame() override; /** * @copydoc RenderAPICore::endFrame() */ void endFrame() override; /** * @copydoc RenderAPICore::draw() */ void draw(UINT32 vertexOffset, UINT32 vertexCount) override; /** * @copydoc RenderAPICore::drawIndexed() */ void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount) override; /** * @copydoc RenderAPICore::clearRenderTarget() */ void clearRenderTarget(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0) override; /** * @copydoc RenderAPICore::clearViewport() */ void clearViewport(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0) override; /** * @copydoc RenderAPICore::getColorVertexElementType() */ VertexElementType getColorVertexElementType() const override; /** * @copydoc RenderAPICore::getHorizontalTexelOffset() */ float getHorizontalTexelOffset() override; /** * @copydoc RenderAPICore::getVerticalTexelOffset() */ float getVerticalTexelOffset() override; /** * @copydoc RenderAPICore::getMinimumDepthInputValue() */ float getMinimumDepthInputValue() override; /** * @copydoc RenderAPICore::getMaximumDepthInputValue() */ float getMaximumDepthInputValue() override; /** * @copydoc RenderAPICore::convertProjectionMatrix() */ void convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest) override; /** * @copydoc RenderAPICore::getGpuProgramHasColumnMajorMatrices */ bool getGpuProgramHasColumnMajorMatrices() const override; /** * @copydoc RenderAPICore::generateParamBlockDesc() */ GpuParamBlockDesc generateParamBlockDesc(const String& name, Vector& params) override; /************************************************************************/ /* Internal use by OpenGL RenderSystem only */ /************************************************************************/ /** * @brief Query has the main context been initialized. */ bool _isContextInitialized() const { return mGLInitialised; } /** * @brief Returns main context. Caller must ensure the context has been initialized. */ SPtr getMainContext() const { return mMainContext; } /** * @brief Returns a support object you may use for creating */ GLSupport* getGLSupport() const { return mGLSupport; } protected: /** * @copydoc RenderAPICore::initializePrepare */ void initializePrepare() override; /** * @copydoc RenderAPICore::initializeFinalize */ void initializeFinalize(const SPtr& primaryWindow) override; /** * @copydoc RenderAPICore::destroy_internal(). */ void destroyCore() override; /** * @brief Call before doing a draw operation, this method sets everything up. */ void beginDraw(); /** * @brief Needs to accompany every beginDraw after you are done with a single draw operation. */ void endDraw(); /** * @brief Clear a part of a render target. */ void clearArea(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0, const Rect2I& clearArea = Rect2I::EMPTY); /** * @brief Set up clip planes against which all geometry will get clipped. */ void setClipPlanesImpl(const PlaneList& clipPlanes) override; /** * @brief Set up a clip plane at a specific clip plane index. If enabled, * geometry will be clipped against the positive side of the plane. * * @note Valid index range is [0, 5]. */ void setClipPlane(UINT16 index, float A, float B, float C, float D); /** * @brief Enable or disable clipping against a clip plane at the specified index. * * @note Valid index range is [0, 5]. */ void enableClipPlane (UINT16 index, bool enable); /** * @brief Changes the currently active texture unit. Any texture related operations * will then be performed on this unit. */ bool activateGLTextureUnit(UINT16 unit); /** * @brief Changes the active GPU program. */ void setActiveProgram(GpuProgramType gptype, const SPtr& program); /** * @brief Retrieves the active GPU program of the specified type. */ SPtr getActiveProgram(GpuProgramType gptype) const; /** * @brief Converts Banshee blend mode to OpenGL blend mode. */ GLint getBlendMode(BlendFactor blendMode) const; /** * @brief Converts Banshee texture addressing mode to OpenGL texture addressing mode. */ GLint getTextureAddressingMode(TextureAddressingMode tam) const; /** * @brief Gets a combined min/mip filter value usable by OpenGL from the currently * set min and mip filters. */ GLuint getCombinedMinMipFilter() const; /** * @brief OpenGL shares all texture slots, but the engine prefers to keep textures * separate per-stage. This will convert texture unit that is set per stage * into a global texture unit usable by OpenGL. */ UINT32 getGLTextureUnit(GpuProgramType gptype, UINT32 unit); /** * @brief OpenGL shares all buffer bindings, but the engine prefers to keep buffers * separate per-stage. This will convert block buffer binding that is set per stage * into a global block buffer binding usable by OpenGL. */ UINT32 getGLUniformBlockBinding(GpuProgramType gptype, UINT32 binding); /** * @brief Returns the OpenGL specific mode used for drawing, depending on the * currently set draw operation; */ GLint getGLDrawMode() const; /** * @brief Creates render system capabilities that specify which features are * or aren't supported. */ RenderAPICapabilities* createRenderSystemCapabilities() const; /** * @brief Finish initialization by setting up any systems dependant on render system * capabilities. */ void initFromCaps(RenderAPICapabilities* caps); /** * @brief Switch the currently used OpenGL context. You will need to re-bind * any previously bound values manually. (e.g. textures, gpu programs and such) */ void switchContext(const SPtr& context); /************************************************************************/ /* Sampler states */ /************************************************************************/ /** * @brief Sets the texture addressing mode for a texture unit. This determines * how are UV address values outside of [0, 1] range handled when sampling * from texture. */ void setTextureAddressingMode(UINT16 stage, const UVWAddressingMode& uvw); /** * @brief Sets the texture border color for a texture unit. Border color * determines color returned by the texture sampler when border addressing mode * is used and texture address is outside of [0, 1] range. */ void setTextureBorderColor(UINT16 stage, const Color& color); /** * @brief Sets the mipmap bias value for a given texture unit. Bias allows * you to adjust the mipmap selection calculation. Negative values force a * larger mipmap to be used, and positive values smaller. Units are in values * of mip levels, so -1 means use a mipmap one level higher than default. */ void setTextureMipmapBias(UINT16 unit, float bias); /** * @brief Allows you to specify how is the texture bound to the specified texture unit filtered. * Different filter types are used for different situations like magnifying or minifying a texture. */ void setTextureFiltering(UINT16 unit, FilterType ftype, FilterOptions filter); /** * @brief Sets anisotropy value for the specified texture unit. */ void setTextureAnisotropy(UINT16 unit, UINT32 maxAnisotropy); /** * @brief Gets anisotropy value for the specified texture unit. */ GLfloat getCurrentAnisotropy(UINT16 unit); /************************************************************************/ /* Blend states */ /************************************************************************/ /** * @brief Sets up blending mode that allows you to combine new pixels with pixels already in the render target. * Final pixel value = (renderTargetPixel * sourceFactor) op (pixel * destFactor). */ void setSceneBlending(BlendFactor sourceFactor, BlendFactor destFactor, BlendOperation op); /** * @brief Sets up blending mode that allows you to combine new pixels with pixels already in the render target. * Allows you to set up separate blend operations for alpha values. * * Final pixel value = (renderTargetPixel * sourceFactor) op (pixel * destFactor). (And the same for alpha) */ void setSceneBlending(BlendFactor sourceFactor, BlendFactor destFactor, BlendFactor sourceFactorAlpha, BlendFactor destFactorAlpha, BlendOperation op, BlendOperation alphaOp); /** * @brief Sets alpha test that allows you to reject pixels that fail the comparison function * versus the provided reference value. */ void setAlphaTest(CompareFunction func, unsigned char value); /** * @brief Enable alpha to coverage. Alpha to coverage allows you to perform blending without needing * to worry about order of rendering like regular blending does. It requires multi-sampling to * be active in order to work, and you need to supply an alpha texture that determines object transparency. */ void setAlphaToCoverage(bool enabled); /** * @brief Enables or disables writing to certain color channels of the render target. */ void setColorBufferWriteEnabled(bool red, bool green, bool blue, bool alpha); /************************************************************************/ /* Rasterizer states */ /************************************************************************/ /** * @brief Sets vertex winding order. Normally you would use this to cull back facing * polygons. */ void setCullingMode(CullingMode mode); /** * @brief Sets the polygon rasterization mode. Determines how are polygons interpreted. */ void setPolygonMode(PolygonMode level); /** * @brief Sets a depth bias that will offset the depth values of new pixels by the specified amount. * Final depth bias value is a combination of the constant depth bias and slope depth bias. * Slope depth bias has more effect the higher the slope of the rendered polygon. * * @note This is useful if you want to avoid z fighting for objects at the same or similar depth. */ void setDepthBias(float constantBias, float slopeScaleBias); /** * @brief Scissor test allows you to mask off rendering in all but a given rectangular area * identified by the rectangle set by setScissorRect(). */ void setScissorTestEnable(bool enable); /** * @brief Enables or disables multisample antialiasing. */ void setMultisamplingEnable(bool enable); /** * @brief Enables or disables depth clipping (i.e. near/fear plane clipping). */ void setDepthClipEnable(bool enable); /** * @brief Enables or disables antialiased line rendering. */ void setAntialiasedLineEnable(bool enable); /************************************************************************/ /* Depth stencil state */ /************************************************************************/ /** * @brief Should new pixels perform depth testing using the set depth comparison function before * being written. */ void setDepthBufferCheckEnabled(bool enabled = true); /** * @brief Should new pixels write to the depth buffer. */ void setDepthBufferWriteEnabled(bool enabled = true); /** * @brief Sets comparison function used for depth testing. Determines how are new and existing * pixel values compared - if comparison function returns true the new pixel is written. */ void setDepthBufferFunction(CompareFunction func = CMPF_LESS_EQUAL); /** * @brief Turns stencil tests on or off. By default this is disabled. * Stencil testing allow you to mask out a part of the rendered image by using * various stencil operations provided. */ void setStencilCheckEnabled(bool enabled); /** * @brief Allows you to set stencil operations that are performed when stencil test passes or fails. * * @param stencilFailOp Operation executed when stencil test fails. * @param depthFailOp Operation executed when stencil test succeeds but depth test fails. * @param passOp Operation executed when stencil test succeeds and depth test succeeds. * @param front Should the stencil operations be applied to front or back facing polygons. */ void setStencilBufferOperations(StencilOperation stencilFailOp = SOP_KEEP, StencilOperation depthFailOp = SOP_KEEP, StencilOperation passOp = SOP_KEEP, bool front = true); /** * @brief Sets a stencil buffer comparison function. The result of this will cause one of 3 actions * depending on whether the test fails, succeeds but with the depth buffer check still failing, * or succeeds with the depth buffer check passing too. * * @param func Comparison function that determines whether a stencil test fails or passes. Reference value * gets compared to the value already in the buffer using this function. * @param mask The bitmask applied to both the stencil value and the reference value * before comparison * @param ccw If set to true, the stencil operations will be applied to counterclockwise * faces. Otherwise they will be applied to clockwise faces. */ void setStencilBufferFunc(CompareFunction func = CMPF_ALWAYS_PASS, UINT32 mask = 0xFFFFFFFF, bool front = true); /** * @brief The bitmask applied to the stencil value before writing it to the stencil buffer. */ void setStencilBufferWriteMask(UINT32 mask = 0xFFFFFFFF); /** * @brief Sets a reference values used for stencil buffer comparisons. * Actual comparison function and stencil operations are set by setting the DepthStencilState. */ void setStencilRefValue(UINT32 refValue); /************************************************************************/ /* UTILITY METHODS */ /************************************************************************/ /** * @brief Recalculates actual viewport dimensions based on currently * set viewport normalized dimensions and render target and applies * them for further rendering. */ void applyViewport(); /** * @brief Converts the provided matrix m into a representation usable by OpenGL. */ void makeGLMatrix(GLfloat gl_matrix[16], const Matrix4& m); /** * @brief Converts the engine depth/stencil compare function into OpenGL representation. */ GLint convertCompareFunction(CompareFunction func) const; /** * @brief Convers the engine stencil operation in OpenGL representation. Optionally inverts * the operation (increment becomes decrement, etc.). */ GLint convertStencilOp(StencilOperation op, bool invert = false) const; /** * @brief Checks if there are any OpenGL errors and prints them to the log. */ bool checkForErrors() const; private: Rect2 mViewportNorm; UINT32 mScissorTop, mScissorBottom, mScissorLeft, mScissorRight; UINT32 mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight; UINT32 mStencilReadMask; UINT32 mStencilWriteMask; UINT32 mStencilRefValue; CompareFunction mStencilCompareFront; CompareFunction mStencilCompareBack; // View matrix to set world against Matrix4 mViewMatrix; // Last min & mip filtering options, so we can combine them FilterOptions mMinFilter; FilterOptions mMipFilter; // Holds texture type settings for every stage UINT32 mNumTextureTypes; GLenum* mTextureTypes; bool mDepthWrite; bool mColorWrite[4]; GLSupport* mGLSupport; bool mGLInitialised; GLSLProgramFactory* mGLSLProgramFactory; GLSLProgramPipelineManager* mProgramPipelineManager; SPtr mCurrentVertexProgram; SPtr mCurrentFragmentProgram; SPtr mCurrentGeometryProgram; SPtr mCurrentHullProgram; SPtr mCurrentDomainProgram; const GLSLProgramPipeline* mActivePipeline; UINT32 mFragmentTexOffset; UINT32 mVertexTexOffset; UINT32 mGeometryTexOffset; UINT32 mFragmentUBOffset; UINT32 mVertexUBOffset; UINT32 mGeometryUBOffset; UINT32 mHullUBOffset; UINT32 mDomainUBOffset; UINT32 mComputeUBOffset; Vector> mBoundVertexBuffers; SPtr mBoundVertexDeclaration; SPtr mBoundIndexBuffer; DrawOperationType mCurrentDrawOperation; SPtr mMainContext; SPtr mCurrentContext; bool mDrawCallInProgress; UINT16 mActiveTextureUnit; }; }