The reason for this is the ZBuffer: one ZBuffer is used for all rendertargets.
The solution? Every rendertarget needs its own ZBuffer.
Four files have to be modified for this:
- CD3D9Texture.h
- CD3D9Texture.cpp
- CD3D9Driver.h
- CD3D9Driver.cpp
These files are located in irrlichts source directory. I modified Irrlicht-1.4-beta but older versions are the same I guess.
And here's the code. Just add/replace the code from the files with the following (new/important lines are marked with a comment):
CD3D9Texture.h:
Code: Select all
// .....
//! returns if it is a render target
virtual bool isRenderTarget() const;
//! Returns pointer to the render target surface
IDirect3DSurface9* getRenderTargetSurface();
//! Returns pointer to the render target ZBuffer surface
IDirect3DSurface9* getRenderZBufferTargetSurface(); // <= this is new
private:
void createRenderTarget();
// ....
Code: Select all
// ....
IImage* Image;
IDirect3DDevice9* Device;
IDirect3DTexture9* Texture;
IDirect3DTexture9* ZStencilBuffer; // <= this is new
IDirect3DSurface9* RTTSurface;
// ....
Code: Select all
// ....
CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, core::dimension2d<s32> size, const char* name)
: ITexture(name), Image(0), Texture(0), RTTSurface(0), Driver(driver),ZStencilBuffer(0), // <= set ZStencilBuffer to zero in both constructors
TextureSize(size), ImageSize(size), Pitch(0),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true)
// ........
CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
u32 flags, const char* name)
: ITexture(name), Image(image), Texture(0), RTTSurface(0), Driver(driver),ZStencilBuffer(0), // <= here too
TextureSize(0,0), ImageSize(0,0), Pitch(0),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false)
// .............
Code: Select all
// .............
void CD3D9Texture::createRenderTarget() // replace the original function with this one
{
TextureSize.Width = getTextureSizeFromImageSize(TextureSize.Width);
TextureSize.Height = getTextureSizeFromImageSize(TextureSize.Height);
// get backbuffer format to create the render target in the
// same format
IDirect3DSurface9* bb;
D3DFORMAT d3DFormat = D3DFMT_A8R8G8B8;
if (!FAILED(Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &bb)))
{
D3DSURFACE_DESC desc;
bb->GetDesc(&desc);
d3DFormat = desc.Format;
if (d3DFormat == D3DFMT_X8R8G8B8)
d3DFormat = D3DFMT_A8R8G8B8;
bb->Release();
}
else
{
os::Printer::log("Could not create RenderTarget texture: could not get BackBuffer.",
ELL_WARNING);
return;
}
// create texture
HRESULT hr;
// create texture
hr = Device->CreateTexture(
TextureSize.Width,
TextureSize.Height,
1, // mip map level count, we don't want mipmaps here
D3DUSAGE_RENDERTARGET,
d3DFormat,
D3DPOOL_DEFAULT,
&Texture,
NULL);
if (FAILED(hr))
os::Printer::log("Could not create render target texture");
// create ZStencilBuffer <= this one's new
hr = Device->CreateTexture(
TextureSize.Width,
TextureSize.Height,
1, // mip map level count, we don't want mipmaps here
D3DUSAGE_DEPTHSTENCIL,
D3DFMT_D16, // or D3DFMT_D32, D3DFMT_D24S8 (8Bit stencil) , D3DFMT_D24X8 (32Bit , 8Bit unused) - see DX9 doc for other formats
D3DPOOL_DEFAULT,
&ZStencilBuffer,
NULL);
// get irrlicht format from D3D format
ColorFormat = getColorFormatFromD3DFormat(d3DFormat);
if (FAILED(hr))
os::Printer::log("Could not create render target ZBuffer");
}
// ..............
Code: Select all
// ..............
//! Returns pointer to the render target ZBuffer surface
IDirect3DSurface9* CD3D9Texture::getRenderZBufferTargetSurface() // <= add this function after "IDirect3DSurface9* CD3D9Texture::getRenderTargetSurface()"
{
if (!IsRenderTarget)
return 0;
IDirect3DSurface9 *pRTTSurface = 0;
if (ZStencilBuffer)
ZStencilBuffer->GetSurfaceLevel(0, &pRTTSurface);
if (pRTTSurface)
pRTTSurface->Release();
return pRTTSurface;
}
// ...............
Code: Select all
// .........
IDirect3DSurface9* PrevRenderTarget; // <= this is old ^-^ (leave it)
IDirect3DSurface9* PrevZStencilBuffer; // <= this is new
core::dimension2d<s32> CurrentRendertargetSize;
// ....
Code: Select all
// .....
//! constructor
CD3D9Driver::CD3D9Driver(const core::dimension2d<s32>& screenSize, HWND window,
bool fullscreen, bool stencilbuffer,
io::IFileSystem* io, bool pureSoftware)
: CNullDriver(io, screenSize), CurrentRenderMode(ERM_NONE),
ResetRenderStates(true), Transformation3DChanged(false), StencilBuffer(stencilbuffer),
D3DLibrary(0), pID3D(0), pID3DDevice(0), PrevRenderTarget(0),PrevZStencilBuffer(0), // <= set ZBuffer to zero
LastVertexType((video::E_VERTEX_TYPE)-1), MaxTextureUnits(0), MaxUserClipPlanes(0),
MaxLightDistance(sqrtf(FLT_MAX)), LastSetLight(-1), DeviceLost(false),
Fullscreen(fullscreen)
// ....
Code: Select all
// ....
//! sets a render target
bool CD3D9Driver::setRenderTarget(video::ITexture* texture, // <= replace original function with this one
bool clearBackBuffer, bool clearZBuffer,
SColor color)
{
// check for right driver type
if (texture && texture->getDriverType() != EDT_DIRECT3D9)
{
os::Printer::log("Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR);
return false;
}
// check for valid render target
CD3D9Texture* tex = (CD3D9Texture*)texture;
if (texture && !tex->isRenderTarget())
{
os::Printer::log("Fatal Error: Tried to set a non render target texture as render target.", ELL_ERROR);
return false;
}
// next code is useless now
/*
if (texture && (tex->getSize().Width > ScreenSize.Width ||
tex->getSize().Height > ScreenSize.Height ))
{
os::Printer::log("Error: Tried to set a render target texture which is bigger than the screen.", ELL_ERROR);
return false;
}
*/
// check if we should set the previous RT back
bool ret = true;
if (tex == 0)
{
if (PrevRenderTarget)
{
// Set default render target
if (FAILED(pID3DDevice->SetRenderTarget(0, PrevRenderTarget)))
{
os::Printer::log("Error: Could not set back to previous render target.", ELL_ERROR);
ret = false;
}
// Set default ZStencilBuffer target
if (FAILED(pID3DDevice->SetDepthStencilSurface(PrevZStencilBuffer))) // <= this is new
{
os::Printer::log("Error: Could not set back to previous render target ZBuffer.", ELL_ERROR);
ret = false;
}
CurrentRendertargetSize = core::dimension2d<s32>(0,0);
PrevRenderTarget->Release();
PrevRenderTarget = 0;
PrevZStencilBuffer->Release(); // <= this is new too
PrevZStencilBuffer = 0;
}
}
else
{
// we want to set a new target. so do this.
// store previous target
if (!PrevRenderTarget)
{
if (FAILED(pID3DDevice->GetRenderTarget(0, &PrevRenderTarget)))
{
os::Printer::log("Could not get previous render target.", ELL_ERROR);
return false;
}
if (FAILED(pID3DDevice->GetDepthStencilSurface( &PrevZStencilBuffer))) // <= guess what that is
{
os::Printer::log("Could not get previous render target ZBuffer.", ELL_ERROR);
return false;
}
}
// set new render target
if (FAILED(pID3DDevice->SetRenderTarget(0, tex->getRenderTargetSurface())))
{
os::Printer::log("Error: Could not set render target.", ELL_ERROR);
return false;
}
if (FAILED(pID3DDevice->SetDepthStencilSurface( tex->getRenderZBufferTargetSurface()))) // <= add this?
{
os::Printer::log("Error: Could not set render target ZBuffer.", ELL_ERROR);
return false;
}
CurrentRendertargetSize = tex->getSize();
}
if (clearBackBuffer || clearZBuffer)
{
DWORD flags = 0;
if (clearBackBuffer)
flags |= D3DCLEAR_TARGET;
if (clearZBuffer)
flags |= D3DCLEAR_ZBUFFER;
pID3DDevice->Clear(0, NULL, flags, color.color, 1.0f, 0);
}
return ret;
}
// ..........
Now it should be possible to use 2048x2048 rendertargets with a screen resolution of 320x240.
Enjoy it.