[fixed]Direct3D drivers ignoring clipping in draw2DImage

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
CuteAlien
Admin
Posts: 9735
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

[fixed]Direct3D drivers ignoring clipping in draw2DImage

Post by CuteAlien »

The following of the Direct3D functions ignore the clipping so far (same function works already for GL):

CD3D8Driver::draw2DImage(video::ITexture* texture, const core::rect<s32>& destRect, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, video::SColor* colors, bool useAlphaChannelOfTexture)

CD3D9Driver::draw2DImage(video::ITexture* texture, const core::rect<s32>& destRect, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect, video::SColor* colors, bool useAlphaChannelOfTexture)

I think that's been mentioned already some years ago, but I found no working solution for that so far. I fixed it for me and it seems to work, but no guarantees - I'm not so firm with DirectX. Maybe I find some time to provide a real patch one day (which is not so easy right now as I modified more stuff in that function), but for now just my solution, maybe someone wants to create a better patch out of it:

In Direct3D9 we can use the scissors, so instead of:

Code: Select all

pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
		D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex));
we can use:

Code: Select all

	// clip
	RECT oldScissorRect;
	DWORD oldScissorTestRenderState;
	if ( clipRect )
	{
		pID3DDevice->GetScissorRect(&oldScissorRect); 
		pID3DDevice->GetRenderState(D3DRS_SCISSORTESTENABLE, &oldScissorTestRenderState);
		pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);

		RECT scissor;
		scissor.left = clipRect->UpperLeftCorner.X;
		scissor.top = clipRect->UpperLeftCorner.Y;
		scissor.right = clipRect->LowerRightCorner.X;
		scissor.bottom = clipRect->LowerRightCorner.Y;
		pID3DDevice->SetScissorRect(&scissor); 
	}

	pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
				D3DFMT_INDEX16,&vtx[0], sizeof(S3DVertex));

	if ( clipRect )
	{
		pID3DDevice->SetScissorRect(&oldScissorRect); 
		pID3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, oldScissorTestRenderState);
	}
In Direct3D8 we have unfortunately no scissors available. So we have to do the clipping by hand (that could also be used in D3D9, but it's probably slower).

So instead of that old code:

Code: Select all

	const core::dimension2d<s32>& ss = texture->getOriginalSize();
	core::rect<f32> tcoords;
	tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width;
	tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height;
	tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width;
	tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height;

	const core::dimension2d<s32>& renderTargetSize = getCurrentRenderTargetSize();
	core::rect<f32> npos;
	f32 xFact = 2.0f / ( renderTargetSize.Width );
	f32 yFact = 2.0f / ( renderTargetSize.Height );
	npos.UpperLeftCorner.X = ( destRect.UpperLeftCorner.X * xFact ) - 1.0f;
	npos.UpperLeftCorner.Y = 1.0f - ( destRect.UpperLeftCorner.Y * yFact );
	npos.LowerRightCorner.X = ( destRect.LowerRightCorner.X * xFact ) - 1.0f;
	npos.LowerRightCorner.Y = 1.0f - ( destRect.LowerRightCorner.Y * yFact );
it should be like that:

Code: Select all

	const core::dimension2d<s32>& ss = texture->getOriginalSize();
	core::rect<f32> tcoords;
	tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width;
	tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height;
	tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width;
	tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height;

	// clip
	core::rect<s32> clippedRect(destRect);
	if ( clipRect )
	{
		clippedRect.clipAgainst(*clipRect);

		// tcoords must be clipped by the same factors
		core::rect<f32> tcoordsOrig(tcoords);

		f32 fac = f32(clippedRect.UpperLeftCorner.X - destRect.UpperLeftCorner.X) / f32(destRect.getWidth());
		tcoords.UpperLeftCorner.X += fac * (f32)tcoordsOrig.getWidth();

		fac = f32(destRect.LowerRightCorner.X - clippedRect.LowerRightCorner.X)  / f32(destRect.getWidth());
		tcoords.LowerRightCorner.X -= fac * (f32)tcoordsOrig.getWidth();

		fac = f32(clippedRect.UpperLeftCorner.Y - destRect.UpperLeftCorner.Y) / f32(destRect.getHeight());
		tcoords.UpperLeftCorner.Y += fac * (f32)tcoordsOrig.getHeight();

		fac = f32(destRect.LowerRightCorner.Y - clippedRect.LowerRightCorner.Y)  / f32(destRect.getHeight());
		tcoords.LowerRightCorner.Y -= fac * (f32)tcoordsOrig.getHeight();
	}

	const core::dimension2d<s32>& renderTargetSize = getCurrentRenderTargetSize();
	core::rect<f32> npos;
	f32 xFact = 2.0f / ( renderTargetSize.Width );
	f32 yFact = 2.0f / ( renderTargetSize.Height );
	npos.UpperLeftCorner.X = ( clippedRect.UpperLeftCorner.X * xFact ) - 1.0f;
	npos.UpperLeftCorner.Y = 1.0f - ( clippedRect.UpperLeftCorner.Y * yFact );
	npos.LowerRightCorner.X = ( clippedRect.LowerRightCorner.X * xFact ) - 1.0f;
	npos.LowerRightCorner.Y = 1.0f - ( clippedRect.LowerRightCorner.Y * yFact );

IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Thanks a lot for the code, it's fixed now in SVN.
CuteAlien
Admin
Posts: 9735
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

X-Mas is early this year - cool ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply