api independet base texture class

Started by
4 comments, last by Tarviathun 19 years, 1 month ago
I have been fighting with this thing several times but I can't seem to find a good solution for it.. what I want is to have an API independent texture class as base class something like this: class CTexture {...}; class CTextureGL : public CTexture { ... }; class CTextureD3D : public CTexture { ... }; I would like to be able to have the texture as a Surface which I can render to, and depth maps. the problems is the "binding" of the texture, I can't figure out how I can manage the binding of a texture.. I could do it by using a virtual bind function for the texture so it would be a call like this: pTexture->Bind([some parameters like texcoordset]); but I want to bind it like this: pRenderCore->BindTexture( id, pTexture, pVertexBuffer->GetTexCoordSet(1) ); becouse that would fit my way of programming, altough I don't how I can store the OpenGL/D3D specefic stuff for that texture..
Advertisement
// base interfacestruct ITexture 	: public IBase {	VIRTUAL bool Make(ImageData&) END_VIRTUAL;	VIRTUAL void Bind(unsigned int stage) END_VIRTUAL;	VIRTUAL void UnBind(unsigned int stage) END_VIRTUAL;};bool IsPowerOfTwo(unsigned int w){	if (w==2||w==4||w==8||w==16||w==32||w==64||w==128||		w==256||w==512||w==1024||w==2048) {			return true;	}	return false;}// openGLstruct IGL_Texture	: public ITexture {		/// ctor	IGL_Texture();	/// dtor	~IGL_Texture();	void Bind(unsigned int stage);	void UnBind(unsigned int stage);	bool Make(ImageData&);	/// the texture ID	unsigned int m_ID;};void IGL_Texture::Bind(unsigned int stage){	glActiveTextureARB( GL_TEXTURE0_ARB + stage );	glEnable(GL_TEXTURE_2D);	glBindTexture(GL_TEXTURE_2D,m_ID);}void IGL_Texture::UnBind(unsigned int stage){	glActiveTextureARB( GL_TEXTURE0_ARB + stage );	glBindTexture(GL_TEXTURE_2D,0);	glDisable(GL_TEXTURE_2D);}bool IGL_Texture::Make(ImageData& img) {	GLenum Format,IFormat;	if(!IsPowerOfTwo(img.w)||!IsPowerOfTwo(img.h))		return false;	switch(img.bpp) {	case 3: case 24:		img.bpp=3;		Format=GL_RGB;		IFormat=GL_RGB8;		break;	case 4: case 32:		img.bpp=4;		Format=GL_RGBA;		IFormat=GL_RGBA8;		break;	default:		break;	}	glPixelStorei (GL_UNPACK_ALIGNMENT, 1);	/* set the current texture to the one just created */	glBindTexture (GL_TEXTURE_2D, m_ID);	/* repeat the texture in both directions */	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);	/* use bi-linear filtering to smooth the texture nicely. */	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);#if 1	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);	gluBuild2DMipmaps(GL_TEXTURE_2D,img.bpp,img.w,img.h,Format,GL_UNSIGNED_BYTE,img.pixels);#else	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	glTexImage2D(GL_TEXTURE_2D,0,IFormat,img.w,img.h,0,Format,GL_UNSIGNED_BYTE,img.pixels);#endif	return true;}// DirectXstruct ID3D_Texture	: public ITexture {		/// ctor	ID3D_Texture();	/// dtor	~ID3D_Texture();	void Bind(unsigned int stage);	void UnBind(unsigned int stage);	bool Make(ImageData&);	/// A pointer to the D3D texture	LPDIRECT3DTEXTURE9 m_TheTex;};ID3D_Texture::ID3D_Texture() {	m_TheTex=0;}ID3D_Texture::~ID3D_Texture() {	if(m_TheTex)		m_TheTex->Release();	m_TheTex=0;}void ID3D_Texture::Bind(unsigned int stage){	if(m_TheTex) {		g_pd3dDevice->SetTexture( stage, m_TheTex );		g_pd3dDevice->SetTextureStageState( stage, D3DTSS_COLOROP,   D3DTOP_MODULATE );		g_pd3dDevice->SetTextureStageState( stage, D3DTSS_COLORARG1, D3DTA_TEXTURE   );		g_pd3dDevice->SetTextureStageState( stage, D3DTSS_COLORARG2, D3DTA_DIFFUSE   );		g_pd3dDevice->SetTextureStageState( stage, D3DTSS_ALPHAOP,   D3DTOP_DISABLE  );	}}void ID3D_Texture::UnBind(unsigned int stage){	g_pd3dDevice->SetTexture( stage, 0 );}// __________________________________________________________________________________________________// LoadTexture// calls filterdown which will trash _pBuffer as temp storage for mips//LPDIRECT3DTEXTURE9 CreateTexture2D(unsigned char* buffer, const unsigned int width, const unsigned int height,const unsigned int bpp){	DWORD *pBuffer = (DWORD *)buffer;	LPDIRECT3DTEXTURE9 pTexture;	HRESULT hr;	unsigned int bpp_=bpp;	unsigned char* ptemp=0;		if(bpp==4 || bpp == 32)	{		// flip texture from RGBA to ARGB		unsigned char* p = buffer;		unsigned char* e = p + (width*height*4);		for( ; p != e; p+=4 )		{			unsigned char r = p[0];			unsigned char g = p[1];			unsigned char b = p[2];			unsigned char a = p[3];			p[0] = a;			p[1] = r;			p[2] = g;			p[3] = b;		}		bpp_ = 4;		hr = g_pd3dDevice->CreateTexture(width, height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture, NULL);	}	else	if(bpp==3 || bpp == 24)	{		// flip texture from RGBA to ARGB		unsigned char* p = new unsigned char[ width*height*4 ];		ptemp=p;		unsigned char* pp = buffer;		unsigned char* e = pp + (width*height*3);		for( ; pp != e; pp += 3, p += 4  )		{			unsigned char r = pp[0];			unsigned char g = pp[1];			unsigned char b = pp[2];			unsigned char a = 255;			p[2] = r;			p[1] = g;			p[0] = b;			p[3] = a;		}		bpp_ = 4;		hr = g_pd3dDevice->CreateTexture(width, height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture, NULL);	}	if(FAILED(hr))		return 0;	D3DLOCKED_RECT Lock;	pTexture->LockRect(0,&Lock,NULL,0);		memcpy(Lock.pBits,ptemp,width*4*height);	pTexture->UnlockRect(0); 	delete [] ptemp;	pTexture->GenerateMipSubLevels();		return pTexture;}bool ID3D_Texture::Make(ImageData& img) {	if(!IsPowerOfTwo(img.w)||!IsPowerOfTwo(img.h))		return false;	if(m_TheTex) {		m_TheTex->Release();		m_TheTex=0;	}	m_TheTex = CreateTexture2D(img.pixels,img.w,img.h,img.bpp);	return m_TheTex!=0;}
What data does each API need in order to bind the texture?

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

Quote:Original post by superpig
What data does each API need in order to bind the texture?


I create the texture by passing the following structure to the Make method.

struct ImageData {
unsigned char* pixels;
unsigned int w;
unsigned int h;
unsigned int bpp;
};

DX9 needs an LPDIRECT3DTEXTURE9 for the texture, openGL needs the texture object number. I keep those in the derived classes and just call the abstract bind method to run the API specific binding.
and if I want to use it as a render target/surface?
Overload it in the sub-class. For instance, some of the DX-based APIs that I use require the texture to set itself as the current texture. Therefore, I simply derive that into my base Texture class. Pretty easy, really. It's just a matter of putting an interface between your code and whatever API you're using.

This topic is closed to new replies.

Advertisement