-
Notifications
You must be signed in to change notification settings - Fork 6
Textures
The texture class has only one member and it is the OpenGL texture ID. Think of it like a pointer to a GPU resource. So you can safely copy it around, it is just an unsigned int. You just have to be careful to call the clear method only once.
- id: the OpenglId.
- GetSize: returns the size (note, it asks OpenGL for the size so it is not extremely fast. Don't avoid it but certainly don't call it 10000 times if possible.
- createFromBuffer: creates the texture from a buffer of pixels.
- createFromFileData: creates the texture from a file data (you can load a .jpg file for example and pass the data to this method)
- loadFromFile: loads a texture from a file from you.
- create1PxSquare: creates a 1by1 white texture. You can specify the color if you want.
- createFromFileDataWithPixelPadding and loadFromFileWithPixelPadding are explained in the texture atlas section.
Note that the pixelated parameter means Nearest Neighbour filtering or Linear filtering.
A texture atlas is basically multiple textures into a single texture. This library allows you to specify the uv coordinates to sample your texture form when rendering a texture. I have however 2 helper classes to more easily use a texture atlas: TextureAtlas and TextureAtlasPadding. I also have just function versions of those classes: computeTextureAtlas and computeTextureAtlasWithPadding.
The first one is simple: TextureAtlas. xCount and yCount specify the number of cells in your texture. Than by typing .get(x,y,flip) you get the desired cell that you want. Example:
We will use this sprites:
//load the texture
gl2d::Texture textureAtlas(RESOURCES_PATH "sprites.png");
//prepare the atlas
gl2d::TextureAtlas atlas(12, 12);
//...
//render
renderer.renderRectangle({100,100,100,100}, textureAtlas, Colors_White, {}, 0, atlas.get(0, 2));
Result:
Now texture atlases have a problem. If 2 neighboring elements are glued together it is possible for the pixels of the neighbor to leak into your element like this:
Note that this happens when the 2 neighbors are glued together. So If you have a space in your textures it is ok. So for the sprite that I am using here this is not necessary.
To solve this problem, I created the loadFromFileWithPixelPadding and TextureAtlasPadding class that automatically loads your atlas and adds pixel padding to your elements. So, you need to load a texture with a ...WithPixelPadding method and use the TextureAtlasPadding to get the atlas element.
blockSize: means the size of an atlas element in pixels
Also, TextureAtlasPadding takes the full texture size in pixels as a bonus parameter.
The API will probably change in the future for more consistency.
gl2d::Texture textureAtlas;
textureAtlas.loadFromFileWithPixelPadding(RESOURCES_PATH "sprites.png", 80); //the character is 80 pixels in size
gl2d::TextureAtlasPadding atlas(12, 12, textureAtlas.GetSize().x, textureAtlas.GetSize().y);
renderer.renderRectangle({100,100,100,100}, textureAtlas, Colors_White, {}, 0, atlas.get(0, 2));
The result is the same as above.
9 Patches are used for UI and basically cut your texture in a way that allows for it to be resized while keeping the border not stretched. You should use 'render9Patch2' because 'render9Patch' is an old implementation. The inner_texture_coords parameter specifies where to cut the texture (the inner rect). The inner rect will be stretched while the outer rects will be drawn repeatedly.
renderer.renderRectangle({50,50,100,100}, button);
renderer.render9Patch2({50,160,100,190}, Colors_White,
{}, 0, button, GL2D_DefaultTextureCoords, {0.2,0.8,0.8,0.2});
renderer.render9Patch2({200, 50, 100, 300}, Colors_White,
{}, 0, button, GL2D_DefaultTextureCoords, {0.2,0.8,0.8,0.2});
renderer.render9Patch2({400, 150, 300, 100}, Colors_White,
{}, 0, button, GL2D_DefaultTextureCoords, {0.2,0.8,0.8,0.2});
Getting the texture dimensions or reading its data can easily be done. Note that even getting the texture dimensions requires asking the driver and that can be slightly slow so it's probably ok to do it every frame but not inside a big for loop.
//returns the texture dimensions
glm::ivec2 GetSize();
//returns how much memory does the texture take (bytes),
//used for allocating your buffer when using readTextureData
//you can also optionally get the width and the height of the texture using outSize
size_t getMemorySize(int mipLevel = 0, glm::ivec2 *outSize = 0);
//reads the texture data back into RAM, you need to specify
//the buffer to read into yourself, allocate it using
//getMemorySize to know the size in bytes.
//The data will be in RGBA format, one byte each component
void readTextureData(void *buffer, int mipLevel = 0);
//reads the texture data back into RAM
//The data will be in RGBA format, one byte each component
//You can also optionally get the width and the height of the texture using outSize
std::vector<unsigned char> readTextureData(int mipLevel = 0, glm::ivec2 *outSize = 0);