#pragma once #include "BsD3D9Prerequisites.h" #include "BsRenderAPI.h" #include "BsRenderAPICapabilities.h" #include "BsD3D9Mappings.h" namespace BansheeEngine { /** * @brief Implementation of a render system using DirectX 9. Provides abstracted * access to various low level DX9 methods. */ class BS_D3D9_EXPORT D3D9RenderAPI : public RenderAPICore { public: /** * @brief Constructs a new instance of the render system using the provided module instance. */ D3D9RenderAPI(HINSTANCE hInstance); ~D3D9RenderAPI(); /** * @copydoc RenderAPICore::getName() */ const StringID& getName() const override; /** * @copydoc RenderAPICore::getShadingLanguageName() */ const String& getShadingLanguageName() const override; /** * @copydoc RenderAPICore::setRenderTarget() */ void setRenderTarget(const SPtr& target, bool readOnlyDepthStencil = false) 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::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::setTexture() */ void setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const SPtr& texPtr) 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& vp) 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::setScissorRect() */ void setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom) 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::convertProjectionMatrix() */ void convertProjectionMatrix(const Matrix4& matrix, Matrix4& dest) 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::getColorVertexElementType */ VertexElementType getColorVertexElementType() const override; /** * @copydoc RenderAPICore::getColorVertexElementType */ bool getVertexColorFlipRequired() const override { return true; } /** * @copydoc RenderAPICore::generateParamBlockDesc() */ GpuParamBlockDesc generateParamBlockDesc(const String& name, Vector& params) override; /************************************************************************/ /* Internal use by DX9 RenderAPI only */ /************************************************************************/ /** * @brief Returns the resource manager instance. */ static D3D9ResourceManager* getResourceManager(); /** * @brief Returns the device manager instance. */ static D3D9DeviceManager* getDeviceManager(); /** * @brief Returns the internal DirectX 9 device object. */ static IDirect3D9* getDirect3D9(); /** * @brief Returns the number of devices that resources should be created on. */ static UINT getResourceCreationDeviceCount(); /** * @brief Returns DirectX 9 device used for resource creation at the specified index. */ static IDirect3DDevice9* getResourceCreationDevice(UINT index); /** * @brief Returns the currently active DirectX 9 device. */ static IDirect3DDevice9* getActiveD3D9Device(); /** * @brief Converts engine multisample options into DirectX 9 specific ones. * Also test for multi-sample support on the device and returns nearest * supported type if requested type is not available. * * @param d3d9Device Device to check for multisampling. * @param multisampleCount Number of requested samples. * @param d3dPixelFormat Pixel format used by the render target. * @param fullscreen Are we testing multisampling for a full-screen render target. * @param outMultisampleType Output parameter containing DirectX type representing valid multisample type. * @param outMultisampleQuality Output parameter containing multisample quality. */ void determineMultisampleSettings(IDirect3DDevice9* d3d9Device, UINT32 multisampleCount, D3DFORMAT d3dPixelFormat, bool fullScreen, D3DMULTISAMPLE_TYPE* outMultisampleType, DWORD* outMultisampleQuality) const; /** * @brief Register a newly open window with the render system. */ void registerWindow(RenderWindowCore& renderWindow); private: friend class D3D9Texture; friend class D3D9RenderWindow; friend class D3D9Device; friend class D3D9TextureManager; friend class D3D9TextureCoreManager; friend class D3D9DeviceManager; friend class D3D9RenderWindowManager; friend class D3D9RenderWindowCoreManager; /** * @copydoc RenderAPICore::initializePrepare */ void initializePrepare() override; /** * @copydoc RenderAPICore::initializeFinalize */ void initializeFinalize(const SPtr& primaryWindow) override; /** * @copydoc RenderAPICore::destroy_internal */ void destroyCore() override; /** * @brief Returns a list of available drivers and their properties. */ D3D9DriverList* getDirect3DDrivers() const; /** * @brief Sets DirectX 9 render state option. */ HRESULT setRenderState(D3DRENDERSTATETYPE state, DWORD value); /** * @brief Sets DirectX 9 sampler state option for a sampler at the specified index. */ HRESULT setSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value); /** * @brief Sets DirectX 9 texture state option for a texture unit at the specified index. */ HRESULT setTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value); /** * @brief Set a floating point render state option. */ HRESULT setFloatRenderState(D3DRENDERSTATETYPE state, float value) { return setRenderState(state, *((LPDWORD)(&value))); } /** * @brief Returns currently active anisotropy level for the provided texture unit. */ DWORD getCurrentAnisotropy(UINT32 unit); /** * @brief Updates active render system capabilities. Requires active render window to check * certain capabilities. * * @note Also performs an initialization step when called the first time. */ RenderAPICapabilities* updateRenderSystemCapabilities(D3D9RenderWindowCore* renderWindow); /** * @brief Updates render system capabilities with vertex shader related data. */ void updateVertexShaderCaps(RenderAPICapabilities* rsc) const; /** * @brief Updates render system capabilities with pixel shader related data. */ void updatePixelShaderCaps(RenderAPICapabilities* rsc) const; /** * @copydoc RenderAPICore::setClipPlanesImpl */ void setClipPlanesImpl(const PlaneList& clipPlanes) override; /** * @brief Converts a HRESULT error number into an error description. */ String getErrorDescription(long errorNumber) const; /** * @brief Sets a clip plane with the specified index. */ void setClipPlane(UINT16 index, float A, float B, float C, float D); /** * @brief Enables or disables a clip plane at the specified index. */ void enableClipPlane(UINT16 index, bool enable); /** * @brief Returns current module instance. */ HINSTANCE getInstanceHandle() const { return mhInstance; } /** * @brief Returns the D3D9 specific mode used for drawing, depending on the * currently set draw operation. */ D3DPRIMITIVETYPE getD3D9PrimitiveType() const; /************************************************************************/ /* 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 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, unsigned int maxAnisotropy); /** * @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); /************************************************************************/ /* 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 Only applies when rendering to a multisample render target. * If disabled all of the samples will be taken from the center of the pixel, * effectively making the image aliased. Default value is true where samples are * picked randomly within the pixel. */ void setMultisampleAntialiasEnable(bool enable); /** * @brief Only applies when rendering to a non-multisample render target. * If enabled, lines will be antialiased. Default state is disabled. */ 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 ccw = 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 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, bool ccw = true); /** * @brief The bitmask applied to both the stencil value and the reference value * before comparison. */ void setStencilBufferReadMask(UINT32 mask = 0xFFFFFFFF); /** * @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); /** * @brief Clears an area of the currently active render target. * * @param buffers Combination of one or more elements of FrameBufferType * denoting which buffers are to be cleared. * @param color (optional) The color to clear the color buffer with, if enabled. * @param depth (optional) The value to initialize the depth buffer with, if enabled. * @param stencil (optional) The value to initialize the stencil buffer with, if enabled. * @param clearArea (optional) Area in pixels to clear. */ void clearArea(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0, const Rect2I& clearArea = Rect2I::EMPTY); /** * @brief Recalculates actual viewport dimensions based on currently * set viewport normalized dimensions and render target and applies * them for further rendering. */ void applyViewport(); /** * @brief Triggered when device has been lost. */ void notifyOnDeviceLost(D3D9Device* device); /** * @brief Triggered when device is being reset. */ void notifyOnDeviceReset(D3D9Device* device); private: /** * @brief Holds texture unit settings. */ struct sD3DTextureStageDesc { D3D9Mappings::D3DTexType texType; size_t coordIndex; IDirect3DBaseTexture9 *pTex; IDirect3DBaseTexture9 *pVertexTex; }; static D3D9RenderAPI* msD3D9RenderSystem; IDirect3D9* mpD3D; D3D9HLSLProgramFactory* mHLSLProgramFactory; D3D9ResourceManager* mResourceManager; D3D9DeviceManager* mDeviceManager; mutable D3D9DriverList* mDriverList; D3D9Driver* mActiveD3DDriver; UINT32 mNumTexStages; sD3DTextureStageDesc* mTexStageDesc; bool mIsFrameInProgress; bool mRestoreFrameOnReset; HINSTANCE mhInstance; Rect2 mViewportNorm; UINT32 mViewportLeft, mViewportTop, mViewportWidth, mViewportHeight; RECT mScissorRect; DrawOperationType mCurrentDrawOperation; }; }