Commit 657fad23 authored by nadro's avatar nadro

- Added ability to set custom depth/stencil texture for render targets (currently OpenGL only).

- Added new color formats: ECF_D16, ECF_D32, ECF_D24S8 (currently OpenGL only).


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4984 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 46c24d2c
-------------------------- --------------------------
Changes in 1.9 (not yet released) Changes in 1.9 (not yet released)
- Added ability to set custom depth/stencil texture for render targets.
- Added new color formats: ECF_R8, ECF_R8G8, ECF_D16, ECF_D32, ECF_D24S8.
- Can now enable/disable backround drawing for IGUITable. - Can now enable/disable backround drawing for IGUITable.
- Bugfix: Cloning CBillboardSceneNode now copies colors and sizes. - Bugfix: Cloning CBillboardSceneNode now copies colors and sizes.
- EditBox works now with numpad on X11 - EditBox works now with numpad on X11
......
...@@ -125,6 +125,12 @@ public: ...@@ -125,6 +125,12 @@ public:
case ECF_DXT4: case ECF_DXT4:
case ECF_DXT5: case ECF_DXT5:
return 32; return 32;
case ECF_D16:
return 16;
case ECF_D32:
return 32;
case ECF_D24S8:
return 32;
case ECF_R8: case ECF_R8:
return 8; return 8;
case ECF_R8G8: case ECF_R8G8:
...@@ -166,6 +172,20 @@ public: ...@@ -166,6 +172,20 @@ public:
} }
} }
//! test if the color format is only viable for depth/stencil textures
static bool isDepthFormat(const ECOLOR_FORMAT format)
{
switch(format)
{
case ECF_D16:
case ECF_D32:
case ECF_D24S8:
return true;
default:
return false;
}
}
//! test if the color format is only viable for RenderTarget textures //! test if the color format is only viable for RenderTarget textures
/** Since we don't have support for e.g. floating point IImage formats /** Since we don't have support for e.g. floating point IImage formats
one should test if the color format can be used for arbitrary usage, or one should test if the color format can be used for arbitrary usage, or
......
...@@ -552,7 +552,7 @@ namespace video ...@@ -552,7 +552,7 @@ namespace video
information is multiplied.*/ information is multiplied.*/
virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const =0; virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const =0;
//! Sets a new render target. //! Sets a new render target. (this prototype will be removed in future)
/** This will only work if the driver supports the /** This will only work if the driver supports the
EVDF_RENDER_TO_TARGET feature, which can be queried with EVDF_RENDER_TO_TARGET feature, which can be queried with
queryFeature(). Usually, rendering to textures is done in this queryFeature(). Usually, rendering to textures is done in this
...@@ -586,7 +586,32 @@ namespace video ...@@ -586,7 +586,32 @@ namespace video
\return True if sucessful and false if not. */ \return True if sucessful and false if not. */
virtual bool setRenderTarget(video::ITexture* texture, virtual bool setRenderTarget(video::ITexture* texture,
bool clearBackBuffer=true, bool clearZBuffer=true, bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) =0; SColor color=video::SColor(0,0,0,0),
video::ITexture* depthStencil = 0) =0;
//! Sets a new render target.
virtual bool setRenderTarget(video::ITexture* texture,
video::ITexture* depthStencil,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0))
{
return setRenderTarget(texture, clearBackBuffer, clearZBuffer, color, depthStencil);
}
//! Sets new multiple render targets. (this prototype will be removed in future)
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0),
video::ITexture* depthStencil = 0) =0;
//! Sets new multiple render targets.
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
video::ITexture* depthStencil,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0))
{
return setRenderTarget(texture, clearBackBuffer, clearZBuffer, color, depthStencil);
}
//! set or reset special render targets //! set or reset special render targets
/** This method enables access to special color buffers such as /** This method enables access to special color buffers such as
...@@ -604,11 +629,6 @@ namespace video ...@@ -604,11 +629,6 @@ namespace video
bool clearZBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) =0; SColor color=video::SColor(0,0,0,0)) =0;
//! Sets new multiple render targets.
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true,
SColor color=video::SColor(0,0,0,0)) =0;
//! Sets a new viewport. //! Sets a new viewport.
/** Every rendering operation is done into this new area. /** Every rendering operation is done into this new area.
\param area: Rectangle defining the new area of rendering \param area: Rectangle defining the new area of rendering
......
...@@ -50,6 +50,17 @@ namespace video ...@@ -50,6 +50,17 @@ namespace video
/** The following formats may only be used for render target textures. */ /** The following formats may only be used for render target textures. */
/** Depth and stencil formats. */
//! 16 bit format using 16 bits for depth.
ECF_D16,
//! 32 bit format using 32 bits for depth.
ECF_D32,
//! 32 bit format using 24 bits for depth and 8 bits for stencil.
ECF_D24S8,
/** Unsigned normalized integer formats. */ /** Unsigned normalized integer formats. */
//! 8 bit format using 8 bits for the red channel. //! 8 bit format using 8 bits for the red channel.
......
...@@ -613,20 +613,9 @@ ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::p ...@@ -613,20 +613,9 @@ ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::p
} }
//! set or reset special render targets
bool CNullDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color)
{
if (ERT_FRAME_BUFFER==target)
return setRenderTarget(0,clearTarget, clearZBuffer, color);
else
return false;
}
//! sets a render target //! sets a render target
bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color) bool clearZBuffer, SColor color, video::ITexture* depthStencil)
{ {
return false; return false;
} }
...@@ -634,12 +623,23 @@ bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer ...@@ -634,12 +623,23 @@ bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer
//! Sets multiple render targets //! Sets multiple render targets
bool CNullDriver::setRenderTarget(const core::array<video::IRenderTarget>& texture, bool CNullDriver::setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer, bool clearZBuffer, SColor color) bool clearBackBuffer, bool clearZBuffer, SColor color, video::ITexture* depthStencil)
{ {
return false; return false;
} }
//! set or reset special render targets
bool CNullDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color)
{
if (ERT_FRAME_BUFFER==target)
return setRenderTarget(0,clearTarget, clearZBuffer, color, 0);
else
return false;
}
//! sets a viewport //! sets a viewport
void CNullDriver::setViewPort(const core::rect<s32>& area) void CNullDriver::setViewPort(const core::rect<s32>& area)
{ {
......
...@@ -102,16 +102,16 @@ namespace video ...@@ -102,16 +102,16 @@ namespace video
//! sets a render target //! sets a render target
virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color) _IRR_OVERRIDE_; bool clearZBuffer, SColor color, video::ITexture* depthStencil) _IRR_OVERRIDE_;
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer, bool clearZBuffer, SColor color, video::ITexture* depthStencil) _IRR_OVERRIDE_;
//! set or reset special render targets //! set or reset special render targets
virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color) _IRR_OVERRIDE_; bool clearZBuffer, SColor color) _IRR_OVERRIDE_;
//! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=SColor(0,0,0,0)) _IRR_OVERRIDE_;
//! sets a viewport //! sets a viewport
virtual void setViewPort(const core::rect<s32>& area) _IRR_OVERRIDE_; virtual void setViewPort(const core::rect<s32>& area) _IRR_OVERRIDE_;
......
...@@ -4286,27 +4286,8 @@ ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& si ...@@ -4286,27 +4286,8 @@ ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d<u32>& si
if (queryFeature(EVDF_FRAMEBUFFER_OBJECT)) if (queryFeature(EVDF_FRAMEBUFFER_OBJECT))
{ {
rtt = new COpenGLFBOTexture(size, name, this, format); rtt = new COpenGLFBOTexture(size, name, this, format);
if (rtt) addTexture(rtt);
{ rtt->drop();
bool success = false;
addTexture(rtt);
ITexture* tex = createDepthTexture(rtt);
if (tex)
{
success = static_cast<video::COpenGLFBODepthTexture*>(tex)->attach(rtt);
if ( !success )
{
removeDepthTexture(tex);
}
tex->drop();
}
rtt->drop();
if (!success)
{
removeTexture(rtt);
rtt=0;
}
}
} }
else else
#endif #endif
...@@ -4338,61 +4319,9 @@ u32 COpenGLDriver::getMaximalPrimitiveCount() const ...@@ -4338,61 +4319,9 @@ u32 COpenGLDriver::getMaximalPrimitiveCount() const
} }
//! set or reset render target
bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color)
{
if (target != CurrentTarget)
setRenderTarget(0, false, false, 0x0);
if (ERT_RENDER_TEXTURE == target)
{
os::Printer::log("For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR);
return false;
}
if (ERT_MULTI_RENDER_TEXTURES == target)
{
os::Printer::log("For multiple render textures call setRenderTarget with the texture array as first parameter.", ELL_ERROR);
return false;
}
if (Params.Stereobuffer && (ERT_STEREO_RIGHT_BUFFER == target))
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK_RIGHT);
else
glDrawBuffer(GL_FRONT_RIGHT);
}
else if (Params.Stereobuffer && ERT_STEREO_BOTH_BUFFERS == target)
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK);
else
glDrawBuffer(GL_FRONT);
}
else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers))
{
glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0);
}
else
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK_LEFT);
else
glDrawBuffer(GL_FRONT_LEFT);
// exit with false, but also with working color buffer
if (target != ERT_FRAME_BUFFER)
return false;
}
CurrentTarget=target;
clearBuffers(clearTarget, clearZBuffer, false, color);
return true;
}
//! set or reset render target //! set or reset render target
bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color) bool clearZBuffer, SColor color, video::ITexture* depthStencil)
{ {
// check for right driver type // check for right driver type
...@@ -4434,6 +4363,21 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff ...@@ -4434,6 +4363,21 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff
// we want to set a new target. so do this. // we want to set a new target. so do this.
BridgeCalls->setViewport(0, 0, texture->getSize().Width, texture->getSize().Height); BridgeCalls->setViewport(0, 0, texture->getSize().Width, texture->getSize().Height);
RenderTargetTexture = static_cast<COpenGLTexture*>(texture); RenderTargetTexture = static_cast<COpenGLTexture*>(texture);
if (RenderTargetTexture->isFrameBufferObject())
{
if (depthStencil)
{
static_cast<COpenGLFBOTexture*>(RenderTargetTexture)->setDepthTexture(depthStencil);
}
else
{
ITexture* renderBuffer = createDepthTexture(RenderTargetTexture, true);
static_cast<COpenGLFBOTexture*>(RenderTargetTexture)->setDepthTexture(renderBuffer);
renderBuffer->drop();
}
}
// calls glDrawBuffer as well // calls glDrawBuffer as well
RenderTargetTexture->bindRTT(); RenderTargetTexture->bindRTT();
CurrentRendertargetSize = texture->getSize(); CurrentRendertargetSize = texture->getSize();
...@@ -4459,14 +4403,14 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff ...@@ -4459,14 +4403,14 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff
//! Sets multiple render targets //! Sets multiple render targets
bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& targets, bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& targets,
bool clearBackBuffer, bool clearZBuffer, SColor color) bool clearBackBuffer, bool clearZBuffer, SColor color, video::ITexture* depthStencil)
{ {
// if simply disabling the MRT via array call // if simply disabling the MRT via array call
if (targets.size()==0) if (targets.size()==0)
return setRenderTarget(0, clearBackBuffer, clearZBuffer, color); return setRenderTarget(0, clearBackBuffer, clearZBuffer, color, depthStencil);
// if disabling old MRT, but enabling new one as well // if disabling old MRT, but enabling new one as well
if ((MRTargets.size()!=0) && (targets != MRTargets)) if ((MRTargets.size()!=0) && (targets != MRTargets))
setRenderTarget(0, clearBackBuffer, clearZBuffer, color); setRenderTarget(0, clearBackBuffer, clearZBuffer, color, depthStencil);
// if no change, simply clear buffers // if no change, simply clear buffers
else if (targets == MRTargets) else if (targets == MRTargets)
{ {
...@@ -4537,13 +4481,13 @@ bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& tar ...@@ -4537,13 +4481,13 @@ bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& tar
{ {
if (targets[i].TargetType==ERT_RENDER_TEXTURE) if (targets[i].TargetType==ERT_RENDER_TEXTURE)
{ {
setRenderTarget(targets[i].RenderTexture, false, false, 0x0); setRenderTarget(targets[i].RenderTexture, false, false, 0x0, depthStencil);
break; // bind only first RTT break; // bind only first RTT
} }
} }
// init other main buffer, if necessary // init other main buffer, if necessary
if (targets[0].TargetType!=ERT_RENDER_TEXTURE) if (targets[0].TargetType!=ERT_RENDER_TEXTURE)
setRenderTarget(targets[0].TargetType, false, false, 0x0); setRenderTarget(targets[0].TargetType, false, false, 0x0, depthStencil);
// attach other textures and store buffers into array // attach other textures and store buffers into array
if (maxMultipleRTTs > 1) if (maxMultipleRTTs > 1)
...@@ -4652,6 +4596,58 @@ bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& tar ...@@ -4652,6 +4596,58 @@ bool COpenGLDriver::setRenderTarget(const core::array<video::IRenderTarget>& tar
} }
//! set or reset render target
bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color)
{
if (target != CurrentTarget)
setRenderTarget(0, false, false, 0x0, 0);
if (ERT_RENDER_TEXTURE == target)
{
os::Printer::log("For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR);
return false;
}
if (ERT_MULTI_RENDER_TEXTURES == target)
{
os::Printer::log("For multiple render textures call setRenderTarget with the texture array as first parameter.", ELL_ERROR);
return false;
}
if (Params.Stereobuffer && (ERT_STEREO_RIGHT_BUFFER == target))
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK_RIGHT);
else
glDrawBuffer(GL_FRONT_RIGHT);
}
else if (Params.Stereobuffer && ERT_STEREO_BOTH_BUFFERS == target)
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK);
else
glDrawBuffer(GL_FRONT);
}
else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers))
{
glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0);
}
else
{
if (Params.Doublebuffer)
glDrawBuffer(GL_BACK_LEFT);
else
glDrawBuffer(GL_FRONT_LEFT);
// exit with false, but also with working color buffer
if (target != ERT_FRAME_BUFFER)
return false;
}
CurrentTarget=target;
clearBuffers(clearTarget, clearZBuffer, false, color);
return true;
}
// returns the current size of the screen or rendertarget // returns the current size of the screen or rendertarget
const core::dimension2d<u32>& COpenGLDriver::getCurrentRenderTargetSize() const const core::dimension2d<u32>& COpenGLDriver::getCurrentRenderTargetSize() const
{ {
...@@ -4807,10 +4803,10 @@ ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared) ...@@ -4807,10 +4803,10 @@ ITexture* COpenGLDriver::createDepthTexture(ITexture* texture, bool shared)
return DepthTextures[i]; return DepthTextures[i];
} }
} }
DepthTextures.push_back(new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); DepthTextures.push_back(new COpenGLRenderBuffer(texture->getSize(), "depth1", this));
return DepthTextures.getLast(); return DepthTextures.getLast();
} }
return (new COpenGLFBODepthTexture(texture->getSize(), "depth1", this)); return (new COpenGLRenderBuffer(texture->getSize(), "depth1", this));
} }
......
...@@ -360,17 +360,17 @@ namespace video ...@@ -360,17 +360,17 @@ namespace video
virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size, virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size,
const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_; const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN) _IRR_OVERRIDE_;
//! set or reset render target //! sets a render target
virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color) _IRR_OVERRIDE_;
//! set or reset render target texture
virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color) _IRR_OVERRIDE_; bool clearZBuffer, SColor color, video::ITexture* depthStencil) _IRR_OVERRIDE_;
//! Sets multiple render targets //! Sets multiple render targets
virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture, virtual bool setRenderTarget(const core::array<video::IRenderTarget>& texture,
bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=SColor(0,0,0,0)) _IRR_OVERRIDE_; bool clearBackBuffer, bool clearZBuffer, SColor color, video::ITexture* depthStencil) _IRR_OVERRIDE_;
//! set or reset special render targets
virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color) _IRR_OVERRIDE_;
//! Clears the ZBuffer. //! Clears the ZBuffer.
virtual void clearZBuffer() _IRR_OVERRIDE_; virtual void clearZBuffer() _IRR_OVERRIDE_;
......
This diff is collapsed.
...@@ -116,6 +116,12 @@ public: ...@@ -116,6 +116,12 @@ public:
//! Is it a FrameBufferObject? //! Is it a FrameBufferObject?
virtual bool isFrameBufferObject() const; virtual bool isFrameBufferObject() const;
//! Is it a depth texture?
bool isDepthTexture() const _IRR_OVERRIDE_;
//! Is it a renderbuffer?
bool isRenderBuffer() const _IRR_OVERRIDE_;
//! Bind RenderTargetTexture //! Bind RenderTargetTexture
virtual void bindRTT(); virtual void bindRTT();
...@@ -170,6 +176,9 @@ protected: ...@@ -170,6 +176,9 @@ protected:
bool ReadOnlyLock; bool ReadOnlyLock;
bool KeepImage; bool KeepImage;
bool IsDepthTexture;
bool IsRenderBuffer;
mutable SStatesCache StatesCache; mutable SStatesCache StatesCache;
}; };
...@@ -194,21 +203,28 @@ public: ...@@ -194,21 +203,28 @@ public:
//! Unbind RenderTargetTexture //! Unbind RenderTargetTexture
virtual void unbindRTT() _IRR_OVERRIDE_; virtual void unbindRTT() _IRR_OVERRIDE_;
ITexture* DepthTexture; //! Return depth texture.
ITexture* getDepthTexture() const;
//! Set depth texture.
bool setDepthTexture(ITexture* depthTexture);
protected: protected:
GLuint ColorFrameBuffer; GLuint BufferID;
COpenGLTexture* DepthTexture;
}; };
//! OpenGL FBO depth texture. //! OpenGL Render Buffer.
class COpenGLFBODepthTexture : public COpenGLTexture class COpenGLRenderBuffer : public COpenGLTexture
{ {
public: public:
//! FrameBufferObject depth constructor //! FrameBufferObject depth constructor
COpenGLFBODepthTexture(const core::dimension2d<u32>& size, const io::path& name, COpenGLDriver* driver=0, bool useStencil=false); COpenGLRenderBuffer(const core::dimension2d<u32>& size, const io::path& name, COpenGLDriver* driver=0, bool useStencil=false);
//! destructor //! destructor
virtual ~COpenGLFBODepthTexture(); virtual ~COpenGLRenderBuffer();
//! Bind RenderTargetTexture //! Bind RenderTargetTexture
virtual void bindRTT() _IRR_OVERRIDE_; virtual void bindRTT() _IRR_OVERRIDE_;
...@@ -216,12 +232,10 @@ public: ...@@ -216,12 +232,10 @@ public:
//! Unbind RenderTargetTexture //! Unbind RenderTargetTexture
virtual void unbindRTT() _IRR_OVERRIDE_; virtual void unbindRTT() _IRR_OVERRIDE_;
bool attach(ITexture*); bool getBufferID() const;
protected: protected:
GLuint DepthRenderBuffer; GLuint BufferID;
GLuint StencilRenderBuffer;
bool UseStencil;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment