-
Notifications
You must be signed in to change notification settings - Fork 26
Graphics and You
An article by @Thumperrr.
This is out of date. Disregard until we get this page updated.
It's come to my attention that there's very little documentation on how graphics and graphic related resources are handled in this project. To a new set of eyes it might seem pretty obscure by just looking through the code. The graphics are set up in a rather neat way, though. The goal of this readme is to discuss the overall system that's already in place, and how they should be handled in supplementary code.
Currently, there are three key players in the handling of graphic content in ChessPlusPlus.
- graphics.json
- GraphicsConfig class
- TextureManager class
Located in ./config, this is a configuration file that stores the paths for every graphical entity relative to the ChessPlusPlus executable. It's meant to store and group graphical content paths in a meaningful way. If you take a peak at graphics.json, you'll see how the image file paths are grouped. It's a directory-like structure, so, for example, every graphic that has to do with the chess board is grouped underneath "board".
This file is modifiable. If a path for an image has changed, simply update it in graphics.json.
This file is appendable. You can add additional content to this file without messing anything else up (assuming you don't change the existing structure. I.e., if you move "pieces" into a different category, things will go wrong).
Example: After adding a graphic for the title screen, the hypothetical graphics.json might look like this:
{
"chesspp":
{
"board":
{
//... the other stuff that's on board. Taken out for space
},
"title screen":
{
"splash": "res/img/title screen/splash.png"
}
}
}
Note that it's also entirely possible to use the same path for many different entries. However, the title shouldn't be the same for more than one entry for the same reason that you can't have two folders with the same name in a directory.
Okay so, I have graphics.json updated, how do I retreive that path inside of the program? Read on!
This class is used for retreiving image paths from graphics.json at runtime, and doing so is very simple. Consider the following json file:
{
"chesspp":
{
"title screen":
{
"splash": "res/img/title screen/splash.png"
}
}
}
Retrieving the path for the splash screen image is as simple as follows:
#include "config/GraphicsConfig.hpp"
// Assuming inside of some function, here
config::GraphicsConfig gfx_config; //create an instance of GraphicsConfig.
// GraphicsConfig::spritePath returns the path that's located
// at whatver place in the json tree specified.
std::string splash_path = gfx_config.spritePath("title screen", "splash");
// ^
// Notice here each node is a separate parameter. |
// spritePath uses variadic templates to deduce as many parameters as necessary.
// `splash_path` now contains the string "res/img/title screen/splash.png"
If you think of it like a directory structure, spritePath("chesspp", "title screen", "splash")
will return the data located at chesspp/title screen/splash/
in graphics.json.
So now that I have the sprite path, how do I load and use that image? That's what TextureManager is for.
####TextureManager
TextureManager does memory management for you. It is responsible for loading an image into memory (in the form of an sf::Texture), and it is responsible for deleting it from memory gracefully when either the program ends or free
is explicitly called.
Because it's important that TextureManager exists only once and must be accessed by numerous different entities, TextureManager is a singleton.
TextureManager::load(std::string image_path)
is the method used for loading an image, and it returns a reference to an sf::Texture.
Thus, creating an sf::Texture from an image is simplified to the following:
sf::Texture &splash = TextureManager::instance().load("res/img/title screen/splash.png");
It's worth noting that any future call to TextureManager::load for the same image path will not reload the image from the disk again, it returns a reference to the already loaded texture. So no need to worry about polluting memory here.
##Putting it all Together All of the code snippets above can be pieced together to easily load an image who's path is stored in graphics.json.
config::GraphicsConfig gfx_config;
sf::Texture &splash = TextureManager::instance().load(gfx_config.spritePath("title screen", "splash"));
Note, you do NOT pass "chesspp" to this method. GraphicsConfig::spritePath() supplies it for you. If you do, the path will be invalid and your resource will not load.
##When things go wrong! If for some reason you supply GraphicsConfig::spritePath with an invalid path, or it can't resolve yours, it will return the value stored in "chesspp/missing", which is currently the path to a graphic to load for missing content. If this image is displaying instead of yours, double check your json file and call the GraphicsConfig::spritePath to make sure the paths match up.
If something else is going wrong, check the log file. Texture manager will log when it loads/deletes a texture.