Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

For my first large-ish endevor in Open-GL I'm making a simulator of sorts. I've got much of the basic functionality working, but recently ran into a problem. As I've since realized, I originally designed the program so that each object in the simulator had its own class which stored its position, texture, draw code, etc. This became a problem, however, when I began creating lots of objects of the same type, as I quickly realized that I wrote the classes to reload a new instance of the texture data for each instance of an object. To fix this I considered making a simple texture database class of sorts which would contain a pointer to a single instance of each objects texture data that each instance of the object would copy upon its creation.

The problem here is that lots of different classes in the simulator create objects and I am hesitant to simply store the texture database class at the top of the program hierarchy and pass it down to every function that creates an object, as I feel that this will get very complex very fast. Instead I feel it would be better to have a global container class that would keep track of the texture pointers, but I'm not sure how I could store the pointers without instantiating an instance of the container which would require passing it all over the place. I'm hoping that there is a more elegant and simple solution that I'm overlooking, otherwise I'll try the way I've described. Alternatively, if it seems some restructuring of the simulator would be best, that isn't out of the question, but I'd appreciate any advice.

share|improve this question

migrated from stackoverflow.com May 14 '12 at 17:02

This question came from our site for professional and enthusiast programmers.

add comment

3 Answers

up vote 2 down vote accepted

Edit: Removed singleton solution in favor of simpler static std::map using existing buildTex function. Note it is not thread safe as implemented.

GLuint buildTex(string strFileName)
{
    static map<string, GLuint> s_Textures;

    if (s_Textures.find(strFileName) == s_Textures.end())
    {
        GLuint hTexture;
        // TODO: load hTexture from file

        s_Textures[strFileName] = hTexture;
    }

    return s_Textures[strFileName];
}

// Tree.cpp
void Tree::Draw()
{
    GLuint hTex = buildTex("Tree.tex");
    ...
}
share|improve this answer
    
OGRE does this, however, the type is a TextureManager&. Don't know what C++ folks prefer. –  Stefan Hanke May 13 '12 at 17:22
1  
The classic, easy solution. Also a little bit of "The Dark Side"TM, because testability and reusability is more difficult with singletons, because you cannot easily have two independent TextureContainers. –  Christopher Oezbek May 13 '12 at 17:26
    
I guess I should have explained the texture container better. As it stands, I have a function buildTex which takes a filename and returns a GLuint containing the pointer to the texture data. The idea was that each object would request a texture from the container which would first check and see if the requested file already had a texture pointer and if not call buildTex and add it to the container. However, because the filenames aren't known by the container upon compiling I didn't think a singleton would work. On the other hand, I don't know if what I'm asking about is possible either. –  fedora May 14 '12 at 4:08
    
Changed my answer based on this response...is this more what you were looking for? –  Rollie May 14 '12 at 7:38
    
-1 horrible global variable –  DeadMG May 14 '12 at 17:08
show 1 more comment

How about a texture factory?

This approach might require some reorganization of your object hierarchy, but here's the gist in rough c++ish pseudocode :

class World
{
    void createVisibleObject(objProps) // objProps -> object properties
    {
        Texture myTex;

        if(textureCache.contains(objProps.textureName))
        {
            myTex = textureCache.find(objProps.textureName);
        }
        else
        {
            myTex = textureFactory.create(textureName);
            textureCache.add(objProps.textureName, myTex);
        }

        VisibleObject visObj(myTex);
        // add visObj to your visible object collection
    }

    TextureCache textureCache;
    TextureFactory textureFactory;
};

Your individual visible objects don't (and shouldn't) need to know about how textures are loaded. Just pass them a preconstructed texture. Whatever is responsible for the creation of these objects is the one that worries about those details. The TextureCache/Factory are held in the only place that needs to know about them. The cache can be as fancy as you'd like with maps and smart pointers.

The benefits of this approach are varied:

  • Clear separation of concerns
  • The cache works 'globally', without being global
  • Resource creation happens in only one place
  • No reliance on singletons
share|improve this answer
add comment

What I did was create a Resource object, which then creates objects which need said resource- so in this case, std::shared_ptr<Texture> (where Texture is an interface and the implementation holds the actual texture data) and then you call tex_ptr->CreateSprite(); to create a sprite which uses that texture.

The problem here is that lots of different classes in the simulator create objects

There's your problem. Nothing to do with textures. Your code is a spaghetti mess. You need to centralize your dependencies. Create one class that deals with the sim, and one class that deals with OpenGL.

If "pass a reference" is too arduous for you, then refactor your code so it isn't. A simulator should know nothing about OpenGL or textures.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.