store size and format of texture object, only regenerate texture and reallocate memory if size and format are changing
This commit is contained in:
parent
e453a62679
commit
081328e63d
|
@ -105,7 +105,8 @@ void Text::refresh()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Generate texture and create storage. Load pixels from the text rendering surface into the texture. The texture object will handle
|
/* Generate texture and create storage. Load pixels from the text rendering surface into the texture. The texture object will handle
|
||||||
* destroying the previous texture. */
|
* destroying the previous texture. The texture object is optimized so that it won't reallocate pixel memory if it was previously
|
||||||
|
* generated at the same size. */
|
||||||
texture().generate({flipped->w, flipped->h}, GL_RGBA8, _scaling_quality);
|
texture().generate({flipped->w, flipped->h}, GL_RGBA8, _scaling_quality);
|
||||||
texture().load(flipped.get());
|
texture().load(flipped.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,27 @@ void Texture::generate()
|
||||||
|
|
||||||
void Texture::generate(glm::vec2 size, GLenum format, GLint filter)
|
void Texture::generate(glm::vec2 size, GLenum format, GLint filter)
|
||||||
{
|
{
|
||||||
generate();
|
/* Only generate a new texture ID and reallocate memory if the current texture ID hasn't been registered by this object as having identically
|
||||||
bind();
|
* sized memory with the same format. */
|
||||||
glTexStorage2D(GL_TEXTURE_2D, 1, format, size.x, size.y);
|
if (!generated() || !_size.has_value() || !_format.has_value() || _size != size || _format != format)
|
||||||
|
{
|
||||||
|
generate();
|
||||||
|
bind();
|
||||||
|
glTexStorage2D(GL_TEXTURE_2D, 1, format, size.x, size.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the resizing algorithm of this texture */
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||||
|
|
||||||
sb::Log::gl_errors();
|
sb::Log::gl_errors();
|
||||||
|
|
||||||
|
/* Store a copy of size */
|
||||||
|
_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::load()
|
void Texture::load()
|
||||||
|
@ -146,7 +161,7 @@ void Texture::load(void* pixels, glm::vec2 size, GLenum format, GLenum type)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
message << "Cannot load pixels with zero or negative size in either dimension";
|
message << "Cannot load pixels with zero or negative size in either dimension.";
|
||||||
message_level = sb::Log::WARN;
|
message_level = sb::Log::WARN;
|
||||||
}
|
}
|
||||||
sb::Log::log(message, message_level);
|
sb::Log::log(message, message_level);
|
||||||
|
@ -171,8 +186,6 @@ void Texture::bind() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* glGetTexlevelparameteriv is not available in OpenGL ES 3.0 */
|
|
||||||
#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(ANDROID)
|
|
||||||
void Texture::load(void* pixels, GLenum format, GLenum type)
|
void Texture::load(void* pixels, GLenum format, GLenum type)
|
||||||
{
|
{
|
||||||
if (generated())
|
if (generated())
|
||||||
|
@ -181,29 +194,36 @@ void Texture::load(void* pixels, GLenum format, GLenum type)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::invalid_argument("This texture has not been generated and has no size property, so a size must be provided");
|
std::ostringstream message;
|
||||||
|
message << "Texture";
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
message << " with path " << path;
|
||||||
|
}
|
||||||
|
message << " has not been generated and has no size property, so a size must be provided to the load function.";
|
||||||
|
throw std::invalid_argument(message.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Texture::size() const
|
glm::vec2 Texture::size() const
|
||||||
{
|
{
|
||||||
if (generated())
|
if (_size.has_value())
|
||||||
{
|
{
|
||||||
bind();
|
return *_size;
|
||||||
int width, height;
|
|
||||||
int miplevel = 0;
|
|
||||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_WIDTH, &width);
|
|
||||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, miplevel, GL_TEXTURE_HEIGHT, &height);
|
|
||||||
return {width, height};
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return {0, 0};
|
std::ostringstream message;
|
||||||
|
message << "Texture";
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
message << " with path " << path;
|
||||||
|
}
|
||||||
|
message << " has not been generated or loaded with a size given, so it currently has no size.";
|
||||||
|
throw std::runtime_error(message.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Textures are considered equal if they have the same ID */
|
|
||||||
bool Texture::operator==(const Texture& texture) const
|
bool Texture::operator==(const Texture& texture) const
|
||||||
{
|
{
|
||||||
return id() == texture.id();
|
return id() == texture.id();
|
||||||
|
|
|
@ -1,29 +1,18 @@
|
||||||
/*!<pre>
|
/* +------------------------------------------------------+
|
||||||
* /\ +------------------------------------------------------+
|
____/ \____ /| - Open source game framework licensed to freely use, |
|
||||||
* ____/ \____ /| - Open source game framework licensed to freely use, |
|
\ / / | copy, modify and sell without restriction |
|
||||||
* \ / / | copy, modify and sell without restriction |
|
+--\ ^__^ /--+ | |
|
||||||
* +--\ ^__^ /--+ | |
|
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
|
||||||
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
|
| ~~~~~~~~~~~~ | +------------------------------------------------------+
|
||||||
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
|
| SPACE ~~~~~ | /
|
||||||
* | SPACE ~~~~~ | /
|
| ~~~~~~~ BOX |/
|
||||||
* | ~~~~~~~ BOX |/
|
+-------------*/
|
||||||
* +--------------+ </pre>
|
|
||||||
*
|
|
||||||
* Texture
|
|
||||||
* =======
|
|
||||||
*
|
|
||||||
* The Texture class abstracts the file opening, data loading and binding steps of Open GL
|
|
||||||
* texture creation. Currently it only supports loading GL_TEXTURE_2D with GL_RGB8 pixels
|
|
||||||
* and automatic GL_NEAREST mipmapping. Support may be added for users to pass in their own
|
|
||||||
* pixel data, to customize mipmapping, and more. The class can also be used in a custom
|
|
||||||
* way by passing the Texture ID to GL functions instead of using the class's member
|
|
||||||
* functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "glm/vec2.hpp"
|
#include "glm/vec2.hpp"
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
@ -37,13 +26,24 @@
|
||||||
namespace sb
|
namespace sb
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The Texture class abstracts the image file opening, data loading and binding steps of Open GL texture creation. Currently it supports only
|
||||||
|
* the GL_TEXTURE_2D target with one mipmap level. Support for other types of textures may be added in the future.
|
||||||
|
*
|
||||||
|
* The texture object's ID can be used to pass this texture directly to OpenGL functions.
|
||||||
|
*/
|
||||||
class Texture : public GLObject
|
class Texture : public GLObject
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/* An image file path can be set with Texture::allocate(fs::path) and later loaded with Texture::load(). */
|
||||||
fs::path path = "";
|
fs::path path = "";
|
||||||
|
|
||||||
|
/* Size and format are unset until memory for pixel data is allocated. */
|
||||||
|
std::optional<glm::vec2> _size;
|
||||||
|
std::optional<GLenum> _format;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -59,8 +59,8 @@ namespace sb
|
||||||
Texture(fs::path path);
|
Texture(fs::path path);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Store an image path as a member variable for loading later. Each texture should have one image
|
* Store an image path as a member variable for loading later. Each texture can have only one image
|
||||||
* path (support for multiple mipmap levels may be added later).
|
* path (support for multiple paths to enable multiple texture mipmap levels may be added later).
|
||||||
*
|
*
|
||||||
* @param path path to an image that can be loaded by the SDL image library
|
* @param path path to an image that can be loaded by the SDL image library
|
||||||
*/
|
*/
|
||||||
|
@ -75,8 +75,8 @@ namespace sb
|
||||||
* Generate a GL_TEXTURE_2D texture ID and allocate the specified format storage for the given size.
|
* Generate a GL_TEXTURE_2D texture ID and allocate the specified format storage for the given size.
|
||||||
*
|
*
|
||||||
* @param size Width and height of the texture in texels
|
* @param size Width and height of the texture in texels
|
||||||
* @param format Sized internal format to be used to store texture data (for example, GL_RGBA8, GL_RGB8)
|
* @param format Sized internal format to be used to store texture data (for example, `GL_RGBA8`, `GL_RGB8`)
|
||||||
* @param filter Resize function to use (see glTexParameter)
|
* @param filter Resize function to use (see `glTexParameter`)
|
||||||
*/
|
*/
|
||||||
void generate(glm::vec2 size, GLenum format = GL_RGBA8, GLint filter = GL_NEAREST);
|
void generate(glm::vec2 size, GLenum format = GL_RGBA8, GLint filter = GL_NEAREST);
|
||||||
|
|
||||||
|
@ -131,14 +131,10 @@ namespace sb
|
||||||
void load(void* pixels, glm::vec2 size, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE);
|
void load(void* pixels, glm::vec2 size, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE);
|
||||||
|
|
||||||
|
|
||||||
/* glGetTexlevelparameteriv is not available in OpenGL ES 3.0 */
|
|
||||||
#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !defined(ANDROID)
|
|
||||||
/*!
|
/*!
|
||||||
* @overload load(void* pixels, glm::vec2 size, GLenum format, GLenum type)
|
* @overload load(void* pixels, glm::vec2 size, GLenum format, GLenum type)
|
||||||
*
|
*
|
||||||
* The texture must have been previously generated with a size to use this generic pixel data load function. The size is
|
* The texture must have been previously generated with a size to use this generic pixel data load function.
|
||||||
* determined with `glGetTexLevelParameter`, which is only available to OpenGL ES 3.1+, so this overload is not available
|
|
||||||
* for Emscripten or Android builds.
|
|
||||||
*
|
*
|
||||||
* see OpenGL's `glTexSubImage2D`
|
* see OpenGL's `glTexSubImage2D`
|
||||||
*
|
*
|
||||||
|
@ -149,17 +145,32 @@ namespace sb
|
||||||
void load(void* pixels, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE);
|
void load(void* pixels, GLenum format = GL_RGBA, GLenum type = GL_UNSIGNED_BYTE);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Return the size in pixels of mipmap level 0 (the only mipmap level supported by this class). If the texture hasn't been,
|
* Return the size in pixels of mipmap level 0 (the only mipmap level supported by this class). If the texture hasn't been
|
||||||
* generated, return {0, 0}. `glGetTexLevelParameter` is only available in OpenGL ES 3.1+, so this function is removed from
|
* generated or loaded with a size given, an exception will be thrown because it currently has no size.
|
||||||
* Emscripten and Android builds.
|
|
||||||
*
|
*
|
||||||
* @return glm::vec2 A vector consisting of {TEXTURE_MIPMAP_WIDTH, TEXTURE_MIPMAP_HEIGHT}
|
* @return glm::vec2 A vector consisting of {TEXTURE_MIPMAP_WIDTH, TEXTURE_MIPMAP_HEIGHT}
|
||||||
*/
|
*/
|
||||||
glm::vec2 size() const;
|
glm::vec2 size() const;
|
||||||
#endif
|
|
||||||
|
/*!
|
||||||
|
* Call `glBindTexture`, binding this texture's ID to the target `GL_TEXTURE_2D`. The texture must have previously been
|
||||||
|
* generated, using Texture::generate() or Texture::generate(glm::vec2, GLenum, GLint), otherwise an exception will be
|
||||||
|
* thrown.
|
||||||
|
*
|
||||||
|
* From the OpenGL manual:
|
||||||
|
*
|
||||||
|
* > While a texture is bound, GL operations on the target to which it is bound affect the bound texture, and queries of
|
||||||
|
* > the target to which it is bound return state from the bound texture. In effect, the texture targets become aliases for
|
||||||
|
* > the textures currently bound to them.
|
||||||
|
*/
|
||||||
void bind() const override;
|
void bind() const override;
|
||||||
bool operator==(const Texture&) const;
|
|
||||||
|
/*!
|
||||||
|
* Textures are considered equal if they have the same ID.
|
||||||
|
*
|
||||||
|
* @param texture texture to compare this texture to
|
||||||
|
*/
|
||||||
|
bool operator==(const Texture& texture) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
namespace sb
|
namespace sb
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
* Timer in seconds which can be paused arbitrarily.
|
* Timer in seconds which can be paused and resumed.
|
||||||
*
|
*
|
||||||
* It must be updated every frame with the timestamp passed to Game::update, regardless of whether it is actively timing or not.
|
* It must be updated every frame with the timestamp passed to Game::update, regardless of whether it is actively timing or not.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue