Home » Community » Forums » » A Singleton Texture Manager for OpenGL
  Intel sponsors gamedev.net search:   
[Control Panel] [Register] [Bookmarks] [Who's Online] [Active Topics] [Stats] [FAQ] [Search]

Add Forum to Favorites |  Send Topic To a Friend | View Forum FAQ | Track this topic


 Last Thread Next Thread 
 A Singleton Texture Manager for OpenGL
Post Reply 
Great article. One suggestion, though:

To decrease the chance that a singleton class is used incorrectly, the constructor(s) could be made private. That way, an error is generated at compile time if an instance of the singleton is instantiated.

For example:

class Singleton {
public:
static Singleton &getInstance() { return _instance; }
private:
Singleton();
~Singleton();
static Singleton &_instance;
};

Singleton &Singleton::_instance;

void main()
{
// Compile-time error, since the ctor is private.
Singleton s;

// Compile-time error, since the ctor is private.
Singleton *s = new Singleton;
}


 User Rating: 1059   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Great.. but how then is one to get the one instance that is needed for the program?

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

void main()
{
Singleton &s = Singleton::getInstance();
}


 User Rating: 1059   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

void main()
{
Singleton &s = Singleton::getInstance();
}


 User Rating: 1059   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

What is the advantage to using a singleton class in this case? If you only want one instance of it, then why do you need a class at all?

Public stuff goes in the header...
  
void texInitialize (void);
void texDestroy (void);

// Usage / Implumentation

int texLoadTexture (const char *szFilename, int nTextureID = -1);
int texLoadTextureFromMemory (unsigned char *pData, int nWidth, int nHeight, int nBPP, int nTextureID = -1);

void texFreeTexture (int nID);
void texFreeAll (void);

// Debug / Utilitarian

char *texGetErrorMessage (void);
	
int texGetNumTextures (void);
int texGetAvailableSpace (void);
int texGetTexID (int nIndex);
  


Private stuff goes in the source file. This is a lot simpler in my opinion. No classes, no references, guaranteed no multiple instances, just good old C.

Steve 'Sly' Williams  Code Monkey  Krome Studios

 User Rating: 1003   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

You're absolutely right. Doing it in straight C will give the same effect. There are advantages to making a singleton a class, though.

For instance, if requirements change (as they often do), and multiple instances are needed, you simply need to remove the getInstance() method, and make the constructor(s) public. In other words, it's trivial to convert a singleton class into a regular class.


 User Rating: 1059   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I don't get it. If you just refernce the static pointer you still don't have an actual instaniation of the class. Un less when you define the static memeber you explicitly make the class (if i'm makeing sence here);

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Another advantage of the singletons is that all functions that deal with a particular subject are contained in a class. Ive done some projects that had a lot of functions. It was just a pain in the a**, and the clarity of the code suffered a lot. (Imagine that):

  

// Global variables

int blah,bleh,blih,bloh,bluh;
(...)

// Function declarations


void somefunction();
void someotherfunction();
something function_that_gets_anything_and_returns_something();
(...)

  


It always get messy. No matter how you organize it. It is still an organized mess.

Gaiomard Dragon
-===(UDIC)===-

Edited by - Outworlder on July 19, 2001 9:31:36 PM

 User Rating: 974   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

oki, so ive loaded my texture into the texture manager, how do i bind it? examples please, thanks

 User Rating: 1017   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

It all depends on HOW you loaded your texture with the class, if YOU want to deal with the OpenGL texture ID's then you would do it as normal AKA


TEXMANAGER.LoadTexture ("foobar.tga", FOOBAR_TEXTURE);
glBindTexture (GL_TEXTURE_2D, FOOBAR_TEXTURE);


Or if you want THE CLASS to handle the texture IDs

int nFoobarTex = TEXTUREMANAGER.LoadTexture ("foobar.tga");
glBindTexture (GL_TEXTURE_2D, nFoobarTex);


I belive what your looking for is in the return value.

hope that helps

-The guy that wrote the tutorial

CodeSmith the Pixel Pusher
www.cs.trinity.edu/~csmith8

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

The way the singleton is written now can create problems if there is another singleton which requires the use of the texture singleton as static initialisation is currently not necessarily in-order, a better (imho) solution would be to initialize the object on the first call to getInstance() i.e.:

  
static Singleton &getInstance()
{
    static Singleton _instance;
    return _instance;
}
  


This way you can be sure the object is instantiated the first time getInstance is called.

Gyzmo
================================================
two wrongs don't make a right, three lefts do

 User Rating: 1041   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Of course a single texture manager is going to make sense . You can go one further and within CglTexManager, define subclasses - aliases, really - for CglModelTexManager, CglWorldTexManager, CglDecalTexManager, and so forth.

These "middle managers" are just pretty (inter)faces to help classify your texture lists. By this example, CglModelTexManager::BindTexture("ModelXSkin.tga") would simply call the superclass CglTexManager::BindTexture("ModelXSkin.tga", nTex_MODEL), where nTex_MODEL is then returned to CGlModelTexManager, who then manages it's own list when it comes time to do CglModelTexManager::DeleteAll().

Sweet, huh?
<rant>

The only thing that bugs me is the word "Singleton". Why does an instance of a GLOBAL STATIC CLASS get its own nifty name? Capitalised, even? do you capitalize Internet? I hope not, since it isn't a proper noun.

Frankly if somebody says to me "I built a Singleton component to do X.." and I got guys in my shop that have been doing (godlike) code for 20 years going "What the hell is the Singleton Class?", then that says to me this is just another fancy name they give so that the kids with degrees can show off in front of the experienced old fogies...
</rant>

------------
-WarMage
...ummmm, yeah. that one.

Edited by - WarMage on July 22, 2001 8:09:52 PM

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

quote:
Original post by Gyzmo
The way the singleton is written now can create problems if there is another singleton which requires the use of the texture singleton as static initialisation is currently not necessarily in-order, a better (imho) solution would be to initialize the object on the first call to getInstance() i.e.:



your 100% right, that IS a better way to do it. However if you just leave it as a static member you have absolutley no control over initialization and deconstruction. So yeah, it is MUCH MUCH MUCH cleaner but with the sacrifice of alittle control



CodeSmith the Pixel Pusher
www.cs.trinity.edu/~csmith8

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

quote:
Original post by CodeSmith
your 100% right, that IS a better way to do it. However if you just leave it as a static member you have absolutley no control over initialization and deconstruction. So yeah, it is MUCH MUCH MUCH cleaner but with the sacrifice of alittle control


I believe that in Gyzmo's code, it is initialized at the first call to getInstance. If your singleton class relies on some other subsytem to be initialized, you probably are not doing things in the best way.


Mike



 User Rating: 1022   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I am not quite clear about singleton class, maybe someone here will kindly answer my question. Since I want the class to have only one instance, why can't I declare all those member parameters that need to be unique as static member? Can't that do the same job as "singleton class"? Is there any difference between the two?

Thanks a lot.

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

quote:
Original post by Nil_z
I am not quite clear about singleton class, maybe someone here will kindly answer my question. Since I want the class to have only one instance, why can't I declare all those member parameters that need to be unique as static member? Can't that do the same job as "singleton class"? Is there any difference between the two?

Thanks a lot.

The best way to implement a singleton class will guarentee that there can not be more than one instance of a class no matter how incompetant the users of the API may be. It will also be initialized lazily so that it is only initialized if it is used. Gyzmo's code above is the best way I know to implement a singleton.


Mike



 User Rating: 1022   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Hi,

there is a bug in CTextureManager::LoadBitmapFile :

pImage = new UBYTE [BitmapInfoHeader.biSizeImage];

should be replaced by :

DWORD trueSize = BitmapInfoHeader.biSizeImage;
if (trueSize==0)
trueSize = BitmapInfoHeader.biWidth * BitmapInfoHeader.biHeight * 3;

pImage = new UBYTE [trueSize];

Just because in MSDN: biSizeImage = Specifies the size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.

-lonestarr


 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I forgot :
you should also replace any further BitmapInfoHeader.biSizeImage by trueSize

-lonestarr

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

Well, I supouse I'm posting a bit late ^_^ , but what if I have another classes to handle the way to obtain data from texture files?. I'm using FreeImage to do it. So at first I have created an abstract class and a set of sub-classes to handle each type of texture file (png,jpg,bmp). Would it be ok if I just instantiate png class in the textureManager class?, or is it impossible due to singleton structure?.

Thanks in advance (if someone replies ;) )

 User Rating: 1015   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

There's a minor bug/inconsistency in the DESTROY_TEXMANAGER call. I don't think it's very important because GL textures should get cleaned up anyway when you destroy the GL context, but...

In the header file it mentions the following.
Quote:
To 'clean up' just call DESTROY_TEXMANAGER, this will delete the TexID array and call FreeAll.

But DESTROY_TEXMANAGER doesn't actually call FreeAll like it says.

To fix it, insert one line in the CTextureManager::Destroy() function.
void CTextureManager::Destroy (void) {
	if (m_Singleton) {
		m_Singleton->FreeAll();		// <-- This line was missing

		delete [] m_Singleton->nTexIDs;
		m_Singleton->nTexIDs = 0;
	
		delete m_Singleton;
		m_Singleton = 0;
	}
}


 User Rating: 1137   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

I recommend that you forget the singleton and implement this as a normal class. You can then pass the manager object to the constructor of any classes who need it, that way their dependency on the texture manager is clearly and explicitly documented.

 User Rating: 1506   |  Rate This User  Send Private MessageView ProfileView Journal Report this Post to a Moderator | Link

You certainly have a point there. That's exactly how I would do it if I were to do this from scratch today. But don't forget this article is 7 years old. ;) Singletons were something exotic and poorly understood, and hence a FOTM design pattern at the time.

 User Rating: 1137   |  Rate This User  Send Private MessageView Profile Report this Post to a Moderator | Link

All times are ET (US)

Post Reply
 Last Thread Next Thread 
Forum Rules:
You may not post new threads
You may post replies
You may not edit your posts
You may not use HTML in your posts
Jump To:
Administrative Options: