(C++) DX8 Sprite material (texture alpha AND overall alpha)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

(C++) DX8 Sprite material (texture alpha AND overall alpha)

Post by IPv6 »

Hello!

Here is code for new material that use texture with alpha channel AND user-defined alpha-blend parameter. So now you can fade-in/fade-out objects in a flash (or in the animator) even if it has nice semitransparent texture on it. BUT there are some limitations: material uses texture 0 and texture 1 (they should point on the same texture for sprite behaviour), but you can load independent texture to slot 1 for very interesting effects.

To use it:

Code: Select all

	CSpriteMat mt(driver->getExposedVideoData().D3D8.D3DDev8,driver);
	s32 newMat=driver->addMaterialRenderer(&mt);
	IBillboardSceneNode *billMat3=smgr->addBillboardSceneNode(0,core::dimension2d<f32>(9.0f, 9.0f),core::vector3df(0,0,-0.8f));
	billMat3->setMaterialType((E_MATERIAL_TYPE)newMat);
	ITexture* imgLogo=driver->getTexture("logo1.png");
	billMat3->setMaterialTexture(0, imgLogo);
	billMat3->setMaterialTexture(1, imgLogo);
	billMat3->setMaterialFlag(video::EMF_LIGHTING, false);
	billMat3->getMaterial(0).MaterialTypeParam2=0;
	billMat3->getMaterial(0).MaterialTypeParam=0.5f;
Notice setMaterialTexture(0)/setMaterialTexture(1) are set to the same texture. Overall alpha of this billboard is in the billMat3->getMaterial(0).MaterialTypeParam (0-object is not visible at all, 1-object is fully visible)

Class itself

Code: Select all

//! Transparent alpha channel material renderer
class CSpriteMat : public IMaterialRenderer
{
public:
	IDirect3DDevice8* pID3DDevice;
	video::IVideoDriver* Driver;

	CSpriteMat(IDirect3DDevice8* p, video::IVideoDriver* d)
		: pID3DDevice(p),Driver(d) {}

	virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
		bool resetAllRenderstates, IMaterialRendererServices* services) 
	{

		if (material.MaterialType != lastMaterial.MaterialType 
			|| material.MaterialTypeParam != lastMaterial.MaterialTypeParam 
			|| resetAllRenderstates)
		{
			s32 blendValue=(255*material.MaterialTypeParam);
			pID3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR , (blendValue << 24) | 0x00000000 );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_CURRENT );

			pID3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 ); 
			pID3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); 


			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );

			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_TEXTURE );
			pID3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_BLENDFACTORALPHA);


			pID3DDevice->SetTextureStageState( 2, D3DTSS_COLOROP,   D3DTOP_DISABLE ); 
			pID3DDevice->SetTextureStageState( 2, D3DTSS_ALPHAOP,   D3DTOP_DISABLE ); 

			pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); 
			pID3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 
			pID3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); 

			s32 refValue = (s32)(material.MaterialTypeParam2 * 255);
			if (refValue){
				pID3DDevice->SetRenderState(D3DRS_ALPHAREF, refValue);            
				pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
				pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); 
			}
		}

		services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
	}

	virtual void OnUnsetMaterial() 
	{ 
		pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 
	}  

	//! Returns if the material is transparent. 
	virtual bool isTransparent() 
	{
		return true; 
	}
};
Currently this material can be used with DX8 only. there is no problem with creating DX9 material, but i know nothing about OpenGL materials. But it can be then combined with similar class from openGL-only libraries for irrlicht (i read some posts about such libraries)

P.S. may be the code (and renderStates) are not efficient... it would be good to hear any comments from anyone expirienced, expecially with perfomance impact of this material. may be it is possible to optimize renderState switching? or i`m miss something obvious? :)
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

demo project (with src)
http://slil.ru/23075747
guest22
Posts: 5
Joined: Mon Mar 12, 2007 2:55 pm

Post by guest22 »

Hi,

Is it possible to post the demo project again ? (url leads to empty page).
Or just a simple "main" using this "CSpriteMat"

Thanks.
zet.dp.ua
Posts: 66
Joined: Sat Jul 07, 2007 8:10 am

Post by zet.dp.ua »

what is the difference from standard transparent material?

how did you implement 2d sprite rendering in your game?
i'm trying now to modify irrlicht to be able to make casual 2d games
my way is (maybe not the best) in adding sprite node, which can draw rotated, scaled texture or part of texture
my next step will be to add texture animator and add content manager that will be responsible for loading sprites, animation configs

what was your way?
Virion
Competition winner
Posts: 2148
Joined: Mon Dec 18, 2006 5:04 am

Post by Virion »

i'm trying now to modify irrlicht to be able to make casual 2d games
I'll be looking forward on that. =)
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

zet.dp.ua wrote:what was your way?
The same :) custom-made billboards that support rotation and some special optimizations. Working on my Irrlight-based engine (which is now called GameRotor engine btw :) ) i encountered the folllowing major bottlenecks during casual 2d game creation:
- unsufficient speed of build-in billboards. now i automatically pack the into one mech buffer and send to GPU in one call - much faster. Still waiting for VBO in Irrlight though...
- texture switches. after all i added automatical "atlasing" - when a lot of small textures are packed into one big texture on the fly. This is also usefull for adding animation into billboards
- font rendering. default 2d font rendering is not very usefull. i recreated font rendering in 3d (using the same custom billboards)

Usage of this material is simple. Just add it to engine via int alphaMatID=driver->addMaterialRenderer(new CSpriteMat(...)) and then set to all bewly created billboards via setMaterialType(alphaMatID)

This would be great to port this rendersttes into OpenGL material, BTW!
GameRotor-Games and more...
Wiredplane-Shareware utilities...
zet.dp.ua
Posts: 66
Joined: Sat Jul 07, 2007 8:10 am

Post by zet.dp.ua »

i'm doing almost the same now
batching sprites, using texture atlases
as for material, i decided to use modified EMT_ONETEXTURE_BLEND
taking into account vertex color and alpha
performance is similar to popcap's and playfirst's engines

more difficult is to make flexible animation system

thank you for the answer
maxi0361
Posts: 24
Joined: Thu Nov 20, 2008 3:04 am

Post by maxi0361 »

looking forward to your 2d casual game version of irrlicht!
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

we already did one game and making several other games for now.
BTW, after all it is better to use shader (simple one of course) instead of build-in material. for similar usage in opengl/directx and greater flexibility
GameRotor-Games and more...
Wiredplane-Shareware utilities...
Post Reply