Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Is it possible to make this resource manager handle all resource types?  (Read 5474 times)

0 Members and 1 Guest are viewing this topic.

Mark Weyland

  • Guest
Here's my little resource Manager:
#include <string>
#include <map>

template <typename Resource>
class ResourceManager
{
    public:
        bool      load(std::string address)
        {
            Resource temporaryResource;
            bool success = temporaryResource.loadFromFile(address); // does not handle errors
            resourceHolder.insert( {address, temporaryResource} );
            return success;
        }
        Resource*  get(std::string ID)
        {
            return &resourceHolder[ID];
        }
    private:
        std::map <std::string, Resource> resourceHolder;
};
 

Now I have to use it like this:
ResourceManager <sf::Font>    fontmanager;
ResourceManager <sf::Texture> texturemanager;
if (!fontmanager.load("consolas.ttf"))       return -1;
if (!texturemanager.load("spritesheet.png")) return -2;
Sf::Sprite sprite(*texturemanager.get("spritesheet.png"));
sf::Text text("string", *fontmanager.get("consolas.ttf"), 24);
window.draw(sprite);
window.draw(text);
Instead I would like to have a single super resource manager that could handle all types of stuff that have loadFromFile function, so I could use it like this:
ResourceManager UltimateResourceManager;
if (!UltimateResourceManager.load("consolas.ttf"))    return -1;
if (!UltimateResourceManager.load("spritesheet.png")) return -2;
Sf::Sprite sprite(*UltimateResourceManager.get("spritesheet.png"));
sf::Text text("string", *UltimateResourceManager.get("consolas.ttf"), 24);
window.draw(sprite);
window.draw(text);
I've tried to find a base class in SFML that provides pure virtual loadFromFile function but my search was unsuccessful.

So, is my idea possible, and more importantly, can it be made in easy way?
Oh, and yeah, I know that my resource manager can't delete any resources, but I think that's OK as long as my game doesn't eat more than 100MB RAM, and that's a problem not to worry about for a long time for me  :)

DaveKram

  • Newbie
  • *
  • Posts: 6
    • View Profile
    • Email
Re: Is it possible to make this resource manager handle all resource types?
« Reply #1 on: January 29, 2015, 05:24:29 pm »
Totally misread your post - sorry about that. But if you're looking into a universal resource manager that can load any type from SFML, I would look into using generics.

That way, you can write generic code to deal with a multitude of types.

« Last Edit: January 29, 2015, 05:27:55 pm by DaveKram »

Mark Weyland

  • Guest
Re: Is it possible to make this resource manager handle all resource types?
« Reply #2 on: January 29, 2015, 05:28:10 pm »
Totally misread your post - sorry about that. But if you're looking into a universal resource manager that can load any type from SFML, I would look into using generics.

Thank You for your response! What is a generic? Is it going to be hard to implement one? You know, I'm totally green...

verbrannt

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Is it possible to make this resource manager handle all resource types?
« Reply #3 on: January 29, 2015, 05:29:53 pm »
im newbie in c++, but may be it will work (it seems to work):

class ResourceManager
{
    public:
        template<typename Resource>
        bool      load(std::string address)
        {
            Resource temporaryResource;
            bool success = temporaryResource.loadFromFile(address);
            resourceHolder.insert( {address, &temporaryResource} ); // insert pointer instead of value
            return success;
        }
        template<typename Resource>
        Resource*  get(std::string ID)
        {
            return static_cast<Resource *>(resourceHolder[ID]);
        }
    private:
        std::map <std::string, void *> resourceHolder; // can store pointer to anything
};

// use
ResourceManager UltimateResourceManager;
if (!UltimateResourceManager.load<sf::Texture>("img.png")) return -2;
sf::Sprite sprite(*UltimateResourceManager.get<sf::Texture>("img.png"));
 

but if the object dies, pointer to this object still be in resourceHolder

UPD

insert pointer line should be

resourceHolder.insert( {address, static_cast<void *>(&temporaryResource)} );
« Last Edit: January 29, 2015, 05:43:07 pm by verbrannt »

DaveKram

  • Newbie
  • *
  • Posts: 6
    • View Profile
    • Email
Re: Is it possible to make this resource manager handle all resource types?
« Reply #4 on: January 29, 2015, 05:31:26 pm »
http://en.wikipedia.org/wiki/Template_%28C%2B%2B%29

Take a read up on templates/generics. It allows you essentially to write generic code that can work with many types. So you "hopefully" write once - with a tweak here or there - and then can pass in a multitude of different types.

So for your resource manager, you could build a generic class that handles resources, without having to make specific cases for load, for instance, based on type. It would just be one load, using generics/templates (code-wise)

Before just jumping into code though, I would take the time to read about generics and how to use them effectively.

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Is it possible to make this resource manager handle all resource types?
« Reply #5 on: January 29, 2015, 05:32:45 pm »
Have you looked at the Thor resources module?
http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html

Mark Weyland

  • Guest
Re: Is it possible to make this resource manager handle all resource types?
« Reply #6 on: January 29, 2015, 05:41:29 pm »
im newbie in c++, but may be it will work (it seems to work):

class ResourceManager
{
    public:
        template<typename Resource>
        bool      load(std::string address)
        {
            Resource temporaryResource;
            bool success = temporaryResource.loadFromFile(address);
            resourceHolder.insert( {address, &temporaryResource} ); // insert pointer instead of value
            return success;
        }
        template<typename Resource>
        Resource*  get(std::string ID)
        {
            return static_cast<Resource *>(resourceHolder[ID]);
        }
    private:
        std::map <std::string, void *> resourceHolder; // can store pointer to anything
};

// use
ResourceManager UltimateResourceManager;
if (!UltimateResourceManager.load<sf::Texture>("img.png")) return -2;
sf::Sprite sprite(*UltimateResourceManager.get<sf::Texture>("img.png"));
 

but if the object dies, pointer to this object still be in resourceHolder

Brilliant! It compiles, but have you tried actually drawing? Program throws segmentation fault error

verbrannt

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Is it possible to make this resource manager handle all resource types?
« Reply #7 on: January 29, 2015, 05:53:03 pm »
i've updated my post, may be it helps
but i really have only basic thoughts about how to do this
i'm not cpp programmer, sorry =(

i think object destroyed (cause it on stack) and we need to store it on heap instead of stack (http://www.sfml-dev.org/tutorials/2.0/graphics-sprite.php#the-white-square-problem)

try this, but i'm summon good c++ programmer in this topic)

class ResourceManager
{
    public:
        template<typename Resource>
        bool      load(std::string address)
        {
            auto temporaryResource = new Resource(); // will be in memory until delete ptr
            bool success = temporaryResource->loadFromFile(address);
            resourceHolder.insert( {address, static_cast<void *>(temporaryResource)} );
            return success;
        }
        template<typename Resource>
        Resource*  get(std::string ID)
        {
            return static_cast<Resource *>(resourceHolder[ID]);
        }
    private:
        std::map <std::string, void *> resourceHolder;
};

i've tested drawing, ant it's works fine
« Last Edit: January 29, 2015, 06:51:52 pm by verbrannt »

DaveKram

  • Newbie
  • *
  • Posts: 6
    • View Profile
    • Email
Re: Is it possible to make this resource manager handle all resource types?
« Reply #8 on: January 29, 2015, 06:29:47 pm »
I would suggest you guys having trouble with generics read over something like this:

http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part

Trying to just throw in generics into a class and seeing if it works, without really understanding the code you're writing is not a good idea.

If you read and understand what and how these work, all of the syntax and how awesome they can be will suddenly make sense. Take the time to learn about them first. Then implementing generics into a simple resource manager won't be very hard.

Mark Weyland

  • Guest
Re: Is it possible to make this resource manager handle all resource types?
« Reply #9 on: January 29, 2015, 08:07:53 pm »
Okay...

After some reading I've discovered that this is an advanced topic and involves more pointers...
After some thinking I've concluded that multiple resource managers add only a couple (<10) additional lines of code.

So here's my solution:
ResourceManager <sf::Font>        fontmanager;
ResourceManager <sf::Texture>     texturemanager;
ResourceManager <sf::SoundBuffer> buffermanager;
/// and so on...
 

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: Is it possible to make this resource manager handle all resource types?
« Reply #10 on: January 29, 2015, 08:11:55 pm »
Read about interfaces.

Mark Weyland

  • Guest
Re: Is it possible to make this resource manager handle all resource types?
« Reply #11 on: January 29, 2015, 08:20:21 pm »
Read about interfaces.

I did. I have a GameState interface class that, besides pure public virtual function run() that returns which game state to switch to afterwards, also holds global variables (protected), that can be accessed by all other game states. That is so awesome and made programming really easier for me. Here look at this beauty:

/// This is "GameState.hpp"
/// DEPENDENCIES
#include <SFML/Graphics.hpp>

/// GLOBAL CONSTANTS
const unsigned    FLAGS  = sf::Style::Close;
const unsigned    WIDTH  = 640;
const unsigned    HEIGHT = 360;
const unsigned    FPS    =  30;
const std::string TITLE  = "LabMouse";

enum ListOfGameStates
{
    STATE_MENU,
    STATE_EXIT
};

class GameState
{
    public:
        GameState();
        virtual ListOfGameStates run() = 0;
    protected:
        /// GLOBAL (USED BETWEEN ALL GAME STAGES) VARIABLES
        sf::RenderWindow window;
        sf::Event         event;
        sf::Font          font; /// TEMPORARY; GONNA BE TURNED INTO FONT RESOURCE MANAGER
        bool          gotEvent; /// Is true if event queue is not empty
};
« Last Edit: January 29, 2015, 08:28:33 pm by Mark Weyland »