draw2dimage rotation + scaling

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

draw2dimage rotation + scaling

Post by FuzzYspo0N »

So, i am tired of saying "no, irrlicht doesnt support the 2 most basic principles of a 2d image"... :)

I have made a patch, for openGL and direct3d (no software yet), i will post the code/patches in irrEXT in the next day or so. For now, here is a demo.

Code: Select all

http://owned.co.za/rotatedemo.zip
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

Thanks! :wink:

PS: The whole IrrEXT project is really cool- I just found it. It would be really nice if some screenshots of the extensions "in action" are added to a contet list in the documentation. (I browsed, but I may have missed if there`s any)
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

I have made a patch, for openGL and direct3d (no software yet), i will post the code/patches in irrEXT in the next day or so. For now, here is a demo.
Hmmm So have I. lol.
I posted about this a few days ago. I'm putting it up next few days, I haven't had time in the last few days.

You aren't racing me are you? :shock:

I have done most of the software version as well.
There's actually hardly nothing to the openGL and directX versions.
It's a few lines of code.

I've done the scaling for software version, and I have implemented 2D rotation in my project. So when I put it into Irrlicht I believe my software rotation will work without (much) modification.

The software versions will be slow as, but may as well do them. Just don't use the rotation or scaling if using the software driver is best idea.

I am making a function that can rotate images/textures and return a new rotated image/texture. That is the best way when using software driver.
Then you can save a rotation for each object rather than rotate every draw. And just make a new rotated image every time rotation changes. If rotation is 0 again, draw the original texture.

To use rotation and scaling effectively (and efficiently) with a software video driver, I think it's the only practical way.
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

NO races here . :) the extent of this test took no more than 15 minutes. And i was just hacking it in.

now that i have neatened it up, i am trying to make it more accessible. Still some issues with scaling, looking into it.
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

race is good :twisted:
tinhtoitrangtay
Posts: 70
Joined: Tue Oct 28, 2008 12:59 pm

Post by tinhtoitrangtay »

Thank you so much. I have a question. Do you have update source code to Irrlicht?
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

@Virion. Whatever dude. Look at my post, the answer is there already from a few days ago.

@FuzzYSpo0n
here is my scaling for the software driver 1.

Code: Select all

//! Rotates and Draws a part of the texture into the rectangle.
void CSoftwareDriver::draw2DImage(const video::ITexture* texture, const core::rect<s32>& destRect,
					const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect,
					const video::SColor * const colors, bool useAlphaChannelOfTexture,
					f32 angleInDegree)
{
	if (texture)
	{
		if (texture->getDriverType() != EDT_SOFTWARE)
		{
			os::Printer::log("Fatal Error: Tried to copy from a surface not owned by this driver.", ELL_ERROR);
			return;
		}

		bool isScaled = (destRect.getSize() != sourceRect.getSize());

		if (isScaled)
		{
			//! make a copy that is scaled to fit the destRect.
			core::dimension2di size = destRect.getSize();
			video::IImage * scaledImage = createImage(texture->getColorFormat(), core::dimension2d<u32>((u32)size.Width, (u32)size.Height));
			((CSoftwareTexture*)texture)->getImage()->copyToScalingBoxFilter(scaledImage);
			if (!scaledImage)
				return;

			const core::rect<s32> scaledSourceRect(0, 0, destRect.getSize().Width, destRect.getSize().Height);

			if (useAlphaChannelOfTexture)
				scaledImage->copyToWithAlpha(
					RenderTargetSurface, destRect.UpperLeftCorner, scaledSourceRect, colors->color, clipRect);
			else
				scaledImage->copyTo(
					RenderTargetSurface, destRect.UpperLeftCorner, scaledSourceRect, clipRect);

			scaledImage->drop();
			return;
		}

		if (useAlphaChannelOfTexture)
			((CSoftwareTexture*)texture)->getImage()->copyToWithAlpha(
				RenderTargetSurface, destRect.UpperLeftCorner, sourceRect, colors->color, clipRect);
		else
			((CSoftwareTexture*)texture)->getImage()->copyTo(
				RenderTargetSurface, destRect.UpperLeftCorner, sourceRect, clipRect);
	}
}
Basically same for the Burning video..

I'll put rotation in.. gimme day or 2.. or 3 ;-).. I'm bit busy.
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

For the openGL driver, i added a function overload to draw2dImage. I removed the clip rect functionality, for now.

The final patch i submit will have dx, etc. but for now.

Image

All the files and the test case are in the zip here :

http://owned.co.za/openGLRotScale.zip

Code: Select all


Add the following code the COpenGLDriver.h

		virtual void draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
			const core::rect<s32>& sourceRect, const f32 rotation = 0, const bool filtering = false,
			const core::vector2df scale = core::vector2df(1.0f, 1.0f),
			SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false);

Add the following code the COpenGLDriver.cpp


void COpenGLDriver::draw2DImage(const video::ITexture* texture,
				const core::position2d<s32>& pos,
				const core::rect<s32>& sourceRect,
				const f32 rotation,
				const bool filtering,
				const core::vector2df scale,
				SColor color,
				bool useAlphaChannelOfTexture)
{
	if (!texture)
		return;

	if (!sourceRect.isValid())
		return;

	core::position2d<s32> targetPos(pos);
	core::position2d<s32> sourcePos(sourceRect.UpperLeftCorner);
	// This needs to be signed as it may go negative.
	core::dimension2d<s32> sourceSize(sourceRect.getSize());
	
	//FuzzYspo0N :: Needed for scaling the image.
	core::vector2df vSourceSize = core::vector2df(f32(sourceSize.Width), f32(sourceSize.Height));

	//FuzzYspo0N :: Start at the origin (thanks Josie)
	core::rectf imageRect = core::rectf(0, 0, vSourceSize.X, vSourceSize.Y);
	core::rectf scaleRect = imageRect;
	core::vector2df destCenter = imageRect.getCenter() + core::vector2df(f32(targetPos.X), f32(targetPos.Y));

	//FuzzYspo0N :: Points for rendering
	core::vector2df topLeft = core::vector2df();
	core::vector2df topRight = core::vector2df();
	core::vector2df bottomLeft = core::vector2df();
	core::vector2df bottomRight = core::vector2df();

	//FuzzYspo0N :: Handle scaling of the verts 
	if(!scale.equals(core::vector2df(1.0f, 1.0f))) 
	{
		//FuzzYspo0N :: Resize the rectangle
		imageRect.LowerRightCorner.X *= scale.X;
		imageRect.LowerRightCorner.Y *= scale.Y;

		//FuzzYspo0N :: Update the translation
		imageRect += core::vector2df(f32(destCenter.X - (imageRect.getWidth() / 2.0f)), f32(destCenter.Y - (imageRect.getHeight() / 2.0f)));

		scaleRect.UpperLeftCorner = imageRect.UpperLeftCorner;
		scaleRect.LowerRightCorner = imageRect.LowerRightCorner;

		//FuzzYspo0N :: Adjust rendering coords
		topLeft = scaleRect.UpperLeftCorner;
		bottomRight = scaleRect.LowerRightCorner;
		
		topRight = core::vector2df(scaleRect.LowerRightCorner.X, scaleRect.UpperLeftCorner.Y);
		bottomLeft = core::vector2df(scaleRect.UpperLeftCorner.X, scaleRect.LowerRightCorner.Y);
	}
	else
	{
		scaleRect += core::vector2df(f32(targetPos.X), f32(targetPos.Y));
		
		//FuzzYspo0N :: Adjust rendering coords
		topLeft = scaleRect.UpperLeftCorner;
		bottomRight = scaleRect.LowerRightCorner;
		
		topRight = core::vector2df(scaleRect.LowerRightCorner.X, scaleRect.UpperLeftCorner.Y);
		bottomLeft = core::vector2df(scaleRect.UpperLeftCorner.X, scaleRect.LowerRightCorner.Y);
	}

	//FuzzYspo0N :: Simple rotation of the verts.
	f32 lRotation = rotation; // Local rotation
	if(lRotation > 0.0f)
	{
		if(lRotation > 360.0f)
		{
			//Just cap it for logical reasons.
			lRotation = fmodf(lRotation, 360.0f);
		}

		//Rotate the points seperately

		topLeft.rotateBy(rotation, destCenter);
		topRight.rotateBy(rotation, destCenter);
		bottomLeft.rotateBy(rotation, destCenter);
		bottomRight.rotateBy(rotation, destCenter);
	}

	//FuzzYspo0N :: Some clarity on the clipping. Dont draw when its off screen, when it was offscreen it was "shifted". 

	const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
	core::rectf renderSize = core::rectf(0.0f, 0.0f, f32(renderTargetSize.Width), f32(renderTargetSize.Height));
	
	if(!renderSize.isPointInside(topLeft) && !renderSize.isPointInside(topRight) && !renderSize.isPointInside(bottomLeft) && !renderSize.isPointInside(bottomRight))
	{
		//FuzzYspo0N :: Offscreen , dont bother rendering
		return;
	}
		
	// ok, we've clipped everything.
	// now draw it.

	// texcoords need to be flipped horizontally for RTTs
	const bool isRTT = texture->isRenderTarget();
	const core::dimension2d<u32>& ss = texture->getOriginalSize();
	const f32 invW = 1.f / static_cast<f32>(ss.Width);
	const f32 invH = 1.f / static_cast<f32>(ss.Height);
	const core::rect<f32> tcoords(
			sourcePos.X * invW,
			(isRTT?(sourcePos.Y + sourceSize.Height):sourcePos.Y) * invH,
			(sourcePos.X + sourceSize.Width) * invW,
			(isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH);

	const core::rect<s32> poss(targetPos, sourceSize);

	disableTextures(1);
	if (!setActiveTexture(0, texture))
		return;
	setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);

	//FuzzYspo0N :: Adding filtering option, default in irrlicht is DISABLED, so enabling it only causes a state change, and back (at the end)
	if(filtering)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
	glBegin(GL_QUADS);

	//Upper left
	glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
	glVertex2f(GLfloat(topLeft.X), GLfloat(topLeft.Y));

	//Top right
	glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
	glVertex2f(GLfloat(topRight.X), GLfloat(topRight.Y));

	//Bottom right
	glTexCoord2f(tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
	glVertex2f(GLfloat(bottomRight.X), GLfloat(bottomRight.Y));

	//Bottom left
	glTexCoord2f(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
	glVertex2f(GLfloat(bottomLeft.X), GLfloat(bottomLeft.Y));

	glEnd();

	//FuzzYspo0N :: Reset the states
	if(filtering)
	{
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	}
}


Edit, i see i messed up a little (as this is WIP its fine). Its the lRotation not being used that i just saw now.
netpipe
Posts: 669
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

your patch is all screwy, the line numbers dont match the svn or 1.6 branches. and you forgot main.cpp
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

Go here...

https://sourceforge.net/tracker/?func=d ... tid=540679

Aside from implementing rotation, I think it should be done in the version which takes a dest rect. Don't you?
Because that one already scales.

I can put it in both if desired, also adding scaling to the other. But one function is enough for now, isn't it?
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

our patch is all screwy, the line numbers dont match the svn
Woops, Tecan you are right. This is meant to be in include/IVideoDriver.h , and the empty declarations need to exist in every driver present in your irrlicht build

Code: Select all

		

virtual void draw2DImage(const video::ITexture* texture, const core::position2d<s32>& destPos,
			const core::rect<s32>& sourceRect, const f32 rotation = 0, const bool filtering = false,
			const core::vector2df scale = core::vector2df(1.0f, 1.0f),
			SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) =0;

And at Tecans request, the example code.

Code: Select all

			//Get mouse position
			core::vector2di pos2 = device->getCursorControl()->getPosition();

			//Get new sizes/rotations
			f32 myRotation = (pos2.X / 800.0f) * 360.0f;
			f32 myScale = (pos2.Y / 600.0f) * 2.0f;

			//sprite is 200, 100 so centered is 300, 250. Draw it here, and apply new changes (rot, sca)
			driver->draw2DImage(tex, core::vector2di(300, 250), core::recti(0,0, tex->getOriginalSize().Width, tex->getOriginalSize().Height), myRotation, true, myScale, video::SColor(255,255,255,255), true);

Also, Ulf. I don't agree with your implementation. Sorry!
Ulf
Posts: 281
Joined: Mon Jun 15, 2009 8:53 am
Location: Australia

Post by Ulf »

Also, Ulf. I don't agree with your implementation. Sorry!
Don't be sorry.
Tell me why.
Being sorry is a defensive position. **EDIT** and sorry for what?

You sure you even looked it over properly?

**EDIT**
I removed my old patch and put the streamlined version up. It just removes a few calls to destRect.getSize() from the software versions.

Software rotation yet to come.. sorry I don't like rushing I have things to work on in my code. Even though it might only take an hour to put it in! There is no rush.
Last edited by Ulf on Mon Dec 21, 2009 2:32 pm, edited 2 times in total.
I can hear birds chirping
:twisted:

I live in the Eye of Insanity.
netpipe
Posts: 669
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Post by netpipe »

yeah he did and it works great, i'll try and get a proper patch soon.

Image[/img]
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

Here is the d3d9 implementation.

Code: Select all

void CD3D9Driver::draw2DImage(const video::ITexture* texture,
				const core::position2d<s32>& pos,
				const core::rect<s32>& sourceRect,
				const f32 rotation,
				const bool filtering,
				const core::vector2df scale,
				SColor color,
				bool useAlphaChannelOfTexture)
{
		if (!texture)
		return;

	if (!sourceRect.isValid())
		return;

	if (!setActiveTexture(0, const_cast<video::ITexture*>(texture)))
		return;

	core::position2d<s32> targetPos = pos;
	core::position2d<s32> sourcePos = sourceRect.UpperLeftCorner;
	// This needs to be signed as it may go negative.
	core::dimension2d<s32> sourceSize(sourceRect.getSize());

//FuzzYspo0N :: Needed for scaling the image.
	core::vector2df vSourceSize = core::vector2df(f32(sourceSize.Width), f32(sourceSize.Height));

	//FuzzYspo0N :: Start at the origin (thanks Josie)
	core::rectf imageRect = core::rectf(0, 0, vSourceSize.X, vSourceSize.Y);
	core::rectf scaleRect = imageRect;
	core::vector2df destCenter = imageRect.getCenter() + core::vector2df(f32(targetPos.X), f32(targetPos.Y));

	//FuzzYspo0N :: Points for rendering
	core::vector2df topLeft = core::vector2df();
	core::vector2df topRight = core::vector2df();
	core::vector2df bottomLeft = core::vector2df();
	core::vector2df bottomRight = core::vector2df();

	//FuzzYspo0N :: Handle scaling of the verts 
	if(!scale.equals(core::vector2df(1.0f, 1.0f))) 
	{
		//FuzzYspo0N :: Resize the rectangle
		imageRect.LowerRightCorner.X *= scale.X;
		imageRect.LowerRightCorner.Y *= scale.Y;

		//FuzzYspo0N :: Update the translation
		imageRect += core::vector2df(f32(destCenter.X - (imageRect.getWidth() / 2.0f)), f32(destCenter.Y - (imageRect.getHeight() / 2.0f)));

		scaleRect.UpperLeftCorner = imageRect.UpperLeftCorner;
		scaleRect.LowerRightCorner = imageRect.LowerRightCorner;

		//FuzzYspo0N :: Adjust rendering coords
		topLeft = scaleRect.UpperLeftCorner;
		bottomRight = scaleRect.LowerRightCorner;
		
		topRight = core::vector2df(scaleRect.LowerRightCorner.X, scaleRect.UpperLeftCorner.Y);
		bottomLeft = core::vector2df(scaleRect.UpperLeftCorner.X, scaleRect.LowerRightCorner.Y);
	}
	else
	{
		scaleRect += core::vector2df(f32(targetPos.X), f32(targetPos.Y));
		
		//FuzzYspo0N :: Adjust rendering coords
		topLeft = scaleRect.UpperLeftCorner;
		bottomRight = scaleRect.LowerRightCorner;
		
		topRight = core::vector2df(scaleRect.LowerRightCorner.X, scaleRect.UpperLeftCorner.Y);
		bottomLeft = core::vector2df(scaleRect.UpperLeftCorner.X, scaleRect.LowerRightCorner.Y);
	}

	//FuzzYspo0N :: Simple rotation of the verts.
	f32 lRotation = rotation; // Local rotation
	if(lRotation > 0.0f)
	{
		if(lRotation > 360.0f)
		{
			//Just cap it for logical reasons.
			lRotation = fmodf(lRotation, 360.0f);
		}

		//Rotate the points seperately

		topLeft.rotateBy(rotation, destCenter);
		topRight.rotateBy(rotation, destCenter);
		bottomLeft.rotateBy(rotation, destCenter);
		bottomRight.rotateBy(rotation, destCenter);
	}

	//FuzzYspo0N :: Some clarity on the clipping. Dont draw when its off screen, when it was offscreen it was "shifted". 

	const core::dimension2d<u32>& renderTargetSize = getCurrentRenderTargetSize();
	core::rectf renderSize = core::rectf(0.0f, 0.0f, f32(renderTargetSize.Width), f32(renderTargetSize.Height));

	// clip these coordinates

	if(!renderSize.isPointInside(topLeft) && !renderSize.isPointInside(topRight) && !renderSize.isPointInside(bottomLeft) && !renderSize.isPointInside(bottomRight))
	{
		//FuzzYspo0N :: Offscreen , dont bother rendering
		return;
	}

	// ok, we've clipped everything.
	// now draw it.

	core::rect<f32> tcoords;
	tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)) / texture->getOriginalSize().Width ;
	tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)) / texture->getOriginalSize().Height;
	tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + ((f32)(sourceSize.Width) / texture->getOriginalSize().Width);
	tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + ((f32)(sourceSize.Height) / texture->getOriginalSize().Height);

	const core::rect<s32> poss(targetPos, sourceSize);

	setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture);

	S3DVertex vtx[4];
	vtx[0] = S3DVertex((f32)topLeft.X, (f32)topLeft.Y, 0.0f,
			0.0f, 0.0f, 0.0f, color,
			tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
	vtx[1] = S3DVertex((f32)topRight.X, (f32)topRight.Y, 0.0f,
			0.0f, 0.0f, 0.0f, color,
			tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y);
	vtx[2] = S3DVertex((f32)bottomRight.X, (f32)bottomRight.Y, 0.0f,
			0.0f, 0.0f, 0.0f, color,
			tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y);
	vtx[3] = S3DVertex((f32)bottomLeft.X, (f32)bottomLeft.Y, 0.0f,
			0.0f, 0.0f, 0.0f, color,
			tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);

	s16 indices[6] = {0,1,2,0,2,3};

	setVertexShader(EVT_STANDARD);

	pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0],
		D3DFMT_INDEX16,&vtx[0],	sizeof(S3DVertex));
}
The same declarations in the headers etc, so its just a copy paste mostly.
tinhtoitrangtay
Posts: 70
Joined: Tue Oct 28, 2008 12:59 pm

Post by tinhtoitrangtay »

I try install patch but it don't work.
Post Reply