- use vector instead of map to store textures in Model class

- require a font to be passed to the Text class constructor
- convert default font from static member to non-static so it unloads from memory before TTF library unloads
- construct delegate object first so that it deletes last and other objects can call unsubscribe successfully
This commit is contained in:
ohsqueezy 2023-06-11 01:07:15 -04:00
parent 6371f9c279
commit aaaebc006d
13 changed files with 325 additions and 192 deletions

View File

@ -114,5 +114,13 @@ namespace std
std::ostream& operator<<(std::ostream&, const Box&);
}
/* Add Box class to the sb namespace. This should be the default location, but Box is left in the global namespace
* for backward compatibility.
*/
namespace sb
{
using ::Box;
}
#include "extension.hpp"
#include "Segment.hpp"

View File

@ -14,13 +14,13 @@ using namespace sb;
Delegate::Delegate(Node* parent) : Node(parent) {}
void Delegate::add_subscriber(Subscriber s, std::uint32_t type)
void Delegate::add_subscriber(Subscriber subscriber, std::uint32_t type)
{
if (subscribers.count(type) == 0)
{
subscribers[type] = {};
}
subscribers[type].push_back(s);
subscribers[type].push_back(subscriber);
}
void Delegate::dispatch()
@ -39,11 +39,11 @@ void Delegate::dispatch()
if (event.type == iter->first)
{
cancelling_propagation = false;
for (Subscriber s : iter->second)
for (Subscriber subscriber : iter->second)
{
if (s.o->is_active())
if (subscriber.obj->is_active())
{
s.f(event);
subscriber.func(event);
if (cancelling_propagation)
{
break;

View File

@ -23,8 +23,8 @@ namespace sb
{
struct Subscriber
{
std::function<void(SDL_Event&)> f;
Node* o;
std::function<void(SDL_Event&)> func;
Node* obj;
};
class Delegate : public Node
@ -50,26 +50,49 @@ namespace sb
static const std::string& get_event_command(SDL_Event&);
static bool get_event_cancel_state(SDL_Event&);
template<typename T>
void subscribe(void(T::*f)(SDL_Event&), T* o, std::uint32_t type = command_event_type)
/*!
* Subscribe a sb::Node or extention of sb::Node object's member function to receive a reference to an SDL_Event whenever
* an event of the specified type is triggered. The type can be an SDL event type from https://wiki.libsdl.org/SDL2/SDL_EventType,
* or if no type is specified, the type will be the custom user event used by this framework, sb::Delegate::command_event_type.
*
* The function submitted must accept a single argument of type SDL_Event&.
*
* sb::Delegate::command_event_type is an SDL_EventType used by this framework to automatically send framework and user created
* events that are mapped to keys in an sb::Configuration object's "keys" field. For example, by default `ALT+enter` is configured
* to send an event named `fullscreen`. Using a JSON file, `z` could be mapped to an event named `jump`.
*
* Currently, there is no method in the framework for sending custom sb::Delegate::command_event_type events, but they can be
* posted using `SDL_Event` and `SDL_PushEvent`.
*
* @param func a sb::Node or child of sb::Node object's member class function pointer
* @param obj a pointer to the object
* @param type the SDL_EventType to receive events for
*/
template<typename Type>
void subscribe(void(Type::*func)(SDL_Event&), Type* obj, std::uint32_t type = command_event_type)
{
add_subscriber({std::bind(f, o, std::placeholders::_1), static_cast<Node*>(o)}, type);
add_subscriber({std::bind(func, obj, std::placeholders::_1), static_cast<Node*>(obj)}, type);
}
template<typename T>
void unsubscribe(T* p)
/*!
* Unsubscribe all subscribers in list associated with the submitted object.
*
* @param obj pointer to object to search for in subscriber list for removal
*/
template<typename Type>
void unsubscribe(const Type* obj)
{
for (auto t = subscribers.begin(); t != subscribers.end(); t++)
for (auto type = subscribers.begin(); type != subscribers.end(); type++)
{
for (auto s = t->second.begin(); s != t->second.end();)
for (auto subscriber = type->second.begin(); subscriber != type->second.end();)
{
if (p == s->o)
if (obj == subscriber->obj)
{
s = t->second.erase(s);
subscriber = type->second.erase(subscriber);
}
else
{
s++;
subscriber++;
}
}
}

View File

@ -140,7 +140,7 @@ void sb::buffer_deleter(GLuint* id)
/* not sure why SDL_Log works here on program exit but SDL_LogDebug and SDL_LogInfo don't */
SDL_Log("destroying buffer ID %i", *id);
glDeleteBuffers(1, id);
}
}
/* Overload the stream operator to support GLObject. Add a string representation of the object that
* displays its ID to the output stream. */

View File

@ -170,10 +170,10 @@ Game::Game()
}
/* Try to load the default font path. The font will be freed when the Game object is destroyed. */
bp_mono_font = std::shared_ptr<TTF_Font>(
_font = std::shared_ptr<TTF_Font>(
TTF_OpenFont(configuration()["display"]["default font path"].get<std::string>().c_str(),
configuration()["display"]["default font size"]), TTF_CloseFont);
if (bp_mono_font.get() == nullptr)
if (_font.get() == nullptr)
{
sb::Log::log("Could not load BPmono.ttf", sb::Log::ERROR);
}
@ -544,9 +544,9 @@ Audio& Game::get_audio()
return audio;
}
const std::shared_ptr<TTF_Font>& sb::Game::font()
const std::shared_ptr<TTF_Font>& sb::Game::font() const
{
return sb::Game::bp_mono_font;
return _font;
}
void Game::run()
@ -669,10 +669,6 @@ void Game::quit()
{
SDL_DestroyWindow(_window);
}
if (TTF_WasInit())
{
TTF_Quit();
}
Mix_CloseAudio();
Mix_Quit();
SDL_Quit();
@ -681,4 +677,12 @@ void Game::quit()
Game::~Game()
{
_delegate.unsubscribe(this);
/* Delete font before quitting the TTF library so the font's shared pointer will successfully call its delete
* function in the TTF library. */
_font.reset();
if (TTF_WasInit())
{
TTF_Quit();
}
}

View File

@ -54,13 +54,18 @@
class Game : public Node
{
protected:
/* Construct sb::Delegate first, so it is the last object to be destroyed, allowing the other objects to successfully call its
* unsubscribe method in their destructors. */
sb::Delegate _delegate {this};
private:
int ticks;
float frame_length = 1000.0 / 60.0;
SDL_Window* _window;
inline static std::shared_ptr<TTF_Font> bp_mono_font;
std::shared_ptr<TTF_Font> _font;
inline static const std::string USER_CONFIG_PATH = "config.json";
inline static const std::string ANDROID_CONFIG_PATH = "config_android.json";
@ -84,7 +89,6 @@ private:
protected:
Configuration _configuration {this};
sb::Delegate _delegate {this};
public:
@ -143,7 +147,7 @@ public:
const Input& get_input() const;
Input& get_input();
Audio& get_audio();
static const std::shared_ptr<TTF_Font>& font();
const std::shared_ptr<TTF_Font>& font() const;
void run();
void frame(float);
void flag_to_end();

View File

@ -10,11 +10,6 @@
#include "Model.hpp"
/* Default constructor for Model */
sb::Model::Model() {};
/* Construct a Model, adding Attributes each already wrapped in a shared pointer. The attributes should
* be passed as a map with each key being a name and each value being a shared pointer to attributes. */
sb::Model::Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes_pack)
{
for (auto attributes : attributes_pack)
@ -23,9 +18,6 @@ sb::Model::Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>& a
}
}
/* Construct a Model, adding Attributes, which will each be wrapped in a shared pointer and stored in the
* created object. The attributes should be passed as a map with each key being a name and each value being
* an attributes object. */
sb::Model::Model(const std::map<std::string, sb::Attributes>& attributes_pack)
{
for (auto attributes : attributes_pack)
@ -34,8 +26,6 @@ sb::Model::Model(const std::map<std::string, sb::Attributes>& attributes_pack)
}
}
/* Construct a new model object by passing a list of names which will be used to initialize
* empty attributes objects with the given names */
sb::Model::Model(const std::initializer_list<std::string>& names)
{
for (const std::string& name : names)
@ -44,25 +34,35 @@ sb::Model::Model(const std::initializer_list<std::string>& names)
}
}
/* Get the entire map of attributes, each wrapped in its shared pointer held by this object.
* Can be used to iterate through the attributes. */
std::map<std::string, std::shared_ptr<sb::Attributes>>& sb::Model::attributes()
{
return _attributes;
}
/* Get the attributes under name, wrapped in the shared pointer held by this object. This
* function uses the at method of std::map, so name must refer to attributes already
* stored in this model. Use this function to share ownership of the attributes or to gain
* access to the public interface of the attributes. */
const std::map<std::string, std::shared_ptr<sb::Attributes>>& sb::Model::attributes() const
{
return _attributes;
}
std::shared_ptr<sb::Attributes>& sb::Model::attributes(const std::string& name)
{
return attributes().at(name);
}
/* Get the attributes under name, wrapped in the shared pointer held by this object. This
* function uses operator[] or std::map, so this can be used to add new attributes to the
* object if they are wrapped in a shared pointer. */
const std::shared_ptr<sb::Attributes>& sb::Model::attributes(const std::string& name) const
{
return attributes().at(name);
}
void sb::Model::attributes(const sb::Attributes& attributes, const std::string& name)
{
this->attributes(std::make_shared<sb::Attributes>(attributes), name);
}
void sb::Model::attributes(const std::shared_ptr<sb::Attributes>& attributes, const std::string& name)
{
this->attributes()[name] = attributes;
}
std::shared_ptr<sb::Attributes>& sb::Model::operator[](const std::string& name)
{
auto element = attributes().find(name);
@ -74,21 +74,7 @@ std::shared_ptr<sb::Attributes>& sb::Model::operator[](const std::string& name)
return attributes()[name];
}
/* Assign name to attributes, copy and wrap in a shared pointer. The model can share
* ownership of the created attribute memory with callers that request it. */
void sb::Model::attributes(const sb::Attributes& attributes, const std::string& name)
{
this->attributes(std::make_shared<sb::Attributes>(attributes), name);
}
/* Assign name to attributes and share ownership. */
void sb::Model::attributes(const std::shared_ptr<sb::Attributes>& attributes, const std::string& name)
{
this->attributes()[name] = attributes;
}
/* Enable all attributes. */
void sb::Model::enable()
void sb::Model::enable() const
{
for (const auto& attributes : this->attributes())
{
@ -96,8 +82,7 @@ void sb::Model::enable()
}
}
/* Disable all attributes. */
void sb::Model::disable()
void sb::Model::disable() const
{
for (const auto& attributes : this->attributes())
{
@ -105,50 +90,43 @@ void sb::Model::disable()
}
}
/* Return a reference to the texture container. */
std::map<std::string, sb::Texture>& sb::Model::textures()
const std::vector<sb::Texture>& sb::Model::textures() const
{
return _textures;
}
/* Get the texture at name. This can be used to read the texture memory, share ownership of it, or
* anything else a Texture object can be used for with direct calls to GL functions. */
sb::Texture& sb::Model::texture(const std::string& name)
std::vector<sb::Texture>& sb::Model::textures()
{
return _textures;
}
const sb::Texture& sb::Model::texture(int index) const
{
if (textures().empty())
{
throw std::out_of_range("There are no textures attached to this model.");
}
else if (textures().find(name) == textures().end())
else
{
std::ostringstream message;
message << "No texture named " << name << " found attached to this model.";
throw std::out_of_range(message.str());
return textures()[index];
}
}
sb::Texture& sb::Model::texture(int index)
{
if (textures().empty())
{
throw std::out_of_range("There are no textures attached to this model.");
}
else
{
return textures().at(name);
return textures()[index];
}
}
/* Get the default texture. The default texture must have previously been set with the default key as
* the name, which can be done using sb::Model::texture(sb::Texture). */
sb::Texture& sb::Model::texture()
{
return texture(DEFAULT_TEXTURE_NAME);
}
/* Assign name to texture and share ownership. */
void sb::Model::texture(const sb::Texture& texture, const std::string& name)
{
textures()[name] = texture;
}
/* If no name is specified, use the default texture. This can be used to conveniently setup a model
* with only one texture. */
void sb::Model::texture(const sb::Texture& texture)
{
this->texture(texture, DEFAULT_TEXTURE_NAME);
textures().push_back(texture);
}
const glm::mat4& sb::Model::transformation() const
@ -173,11 +151,6 @@ const glm::mat4& sb::Model::scale(const glm::vec3& scale)
return transform(glm::scale(scale));
}
const glm::mat4& sb::Model::scale(float scale)
{
return this->scale(glm::vec3(scale));
}
const glm::mat4& sb::Model::rotate(float angle, glm::vec3 axis)
{
return transform(glm::rotate(angle, axis));
@ -189,7 +162,6 @@ const glm::mat4& sb::Model::translate(glm::vec3 translation)
}
/* Return the size in bytes of the sum of the attributes. */
std::size_t sb::Model::size()
{
std::size_t sum = 0;
@ -200,7 +172,6 @@ std::size_t sb::Model::size()
return sum;
}
/* Return the transformation matrix. */
sb::Model::operator glm::mat4() const
{
return _transformation;
@ -208,13 +179,13 @@ sb::Model::operator glm::mat4() const
sb::PlaneDoubleBuffer::PlaneDoubleBuffer() : Plane()
{
texture(sb::Texture(), "front");
texture(sb::Texture(), "back");
texture(sb::Texture());
texture(sb::Texture());
}
void sb::PlaneDoubleBuffer::generate(const glm::vec2& size)
{
for (sb::Texture* buffer : {&texture("front"), &texture("back")})
for (sb::Texture* buffer : {&texture(FRONT), &texture(BACK)})
{
buffer->generate(size);
}
@ -222,12 +193,12 @@ void sb::PlaneDoubleBuffer::generate(const glm::vec2& size)
sb::Texture& sb::PlaneDoubleBuffer::active()
{
return swapped ? texture("back") : texture("front");
return swapped ? texture(BACK) : texture(FRONT);
}
sb::Texture& sb::PlaneDoubleBuffer::inactive()
{
return swapped ? texture("front") : texture("back");
return swapped ? texture(FRONT) : texture(BACK);
}
void sb::PlaneDoubleBuffer::swap()

View File

@ -39,29 +39,146 @@ namespace sb
private:
inline static const std::string DEFAULT_TEXTURE_NAME = "default";
std::map<std::string, sb::Texture> _textures;
std::vector<sb::Texture> _textures;
std::map<std::string, std::shared_ptr<sb::Attributes>> _attributes;
glm::mat4 _transformation {1.0f};
public:
/*!
* Construct a sb::Model object with no attributes or textures.
*/
Model();
Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>&);
Model(const std::map<std::string, sb::Attributes>&);
Model(const std::initializer_list<std::string>&);
/*!
* Construct a sb::Model, adding sb::Attributes each already wrapped in a shared pointer. The attributes should be passed
* as a map with each key being a name and each value being a shared pointer to attributes.
*
* @param attributes_pack map of names to attribute objects wrapped in shared pointers
*/
Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes_pack);
/*!
* Construct a sb::Model, adding sb::Attributes, which will each be wrapped in a shared pointer and stored in the created
* object. The attributes should be passed as a map with each key being a name and each value being an attributes object.
*
* @param attributes_pack map of names to attribute objects to be wrapped in a shared pointer and added
*/
Model(const std::map<std::string, sb::Attributes>& attributes_pack);
/*!
* Construct a new model object by passing a list of names which will be used to initialize empty attributes objects
* with the given names.
*
* @param names attributes names
*/
Model(const std::initializer_list<std::string>& names);
/*!
* Get a writable reference to the entire map of attributes, each wrapped in its shared pointer held by this object.
*
* @return writable reference to the entire map of attributes
*/
std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes();
std::shared_ptr<sb::Attributes>& attributes(const std::string&);
void attributes(const sb::Attributes&, const std::string&);
void attributes(const std::shared_ptr<sb::Attributes>&, const std::string&);
std::shared_ptr<sb::Attributes>& operator[](const std::string&);
void enable();
void disable();
std::map<std::string, sb::Texture>& textures();
sb::Texture& texture(const std::string&);
sb::Texture& texture();
void texture(const sb::Texture&, const std::string&);
void texture(const sb::Texture&);
/*!
* Get a constant reference to the entire map of attributes, each wrapped in its shared pointer held by this object.
*
* @return constant reference to the entire map of attributes
*/
const std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes() const;
/*!
* Get a writable reference to the attributes at name, wrapped in the shared pointer held by this object.
*
* This function uses the at method of std::map, so name must refer to attributes already stored in this model. Use this
* function to share ownership of the attributes or to gain access to the public interface of the attributes.
*
* @param name name of the attributes held by this model to retrieve
* @return writable reference to the attributes at name
*/
std::shared_ptr<sb::Attributes>& attributes(const std::string& name);
/*!
* Get a constant reference to the attributes at name, wrapped in the shared pointer held by this object.
*
* @see Model::attributes(const std::string&)
*
* @param name name of the attributes held by this model to retrieve
* @return constant reference to the attributes at name
*/
const std::shared_ptr<sb::Attributes>& attributes(const std::string& name) const;
/*!
* Assign name to attributes, copy and wrap in a shared pointer. The model can share ownership of the created attribute
* memory with callers that request it.
*
* @param attributes attributes object to copy and wrap
* @param name name the model will associate with the attributes
*/
void attributes(const sb::Attributes& attributes, const std::string& name);
/*!
* Assign name to attributes (for example, "position" or "uv") and share ownership.
*
* @param attributes attributes object to share with this model
* @param name name the model will associate with the attributes
*/
void attributes(const std::shared_ptr<sb::Attributes>& attributes, const std::string& name);
/*!
* Get the attributes under name, wrapped in the shared pointer held by this object.
*
* This function uses operator[] or std::map, so this can be used to add new attributes to the object if they are
* wrapped in a shared pointer.
*
* @param name name of the attributes to get
* @return writable reference to the attributes at name
*/
std::shared_ptr<sb::Attributes>& operator[](const std::string& name);
/*!
* Enable all attributes.
*/
void enable() const;
/*!
* Disable all attributes.
*/
void disable() const;
/*!
* @return a constant reference to the texture container
*/
const std::vector<sb::Texture>& textures() const;
/*!
* @return a reference to the texture container
*/
std::vector<sb::Texture>& textures();
/*!
* Get a constant refernce to the texture at the given index. If no index is given, get the texture at index 0. If
* there are no textures, an exception will be thrown.
*
* @param index index of texture to get
*/
const sb::Texture& texture(int index = 0) const;
/*!
* Get the texture at the given index. If no index is given, get the texture at index 0. If there are no textures,
* an exception will be thrown.
*
* @param index index of texture to get
*/
sb::Texture& texture(int index = 0);
/*!
* Add texture to model's list of textures and share ownership.
*
* @param texture texture to add to model
*/
void texture(const sb::Texture& texture);
/*!
* @return a constanst reference to the model's transformation matrix
@ -91,13 +208,6 @@ namespace sb
*/
const glm::mat4& scale(const glm::vec3& scale);
/*!
* Scale all dimensions by the same amount.
* @overload scale(const glm::vec3&)
*/
const glm::mat4& scale(float scale);
/*!
* Specialized version of transform(const glm::mat4&) that builds a rotation matrix from an angle in radians and an axis
* vector and applies it to the model's transformation matrix.
@ -120,7 +230,14 @@ namespace sb
*/
const glm::mat4& translate(glm::vec3 translation);
/*!
* @return total size in bytes of the attributes
*/
std::size_t size();
/*!
* @return the transformation matrix
*/
operator glm::mat4() const;
};
@ -163,6 +280,7 @@ namespace sb
private:
bool swapped = false;
enum { FRONT, BACK };
public:

View File

@ -15,7 +15,7 @@ Node::Node() : Node(nullptr) {}
Node::Node(Node* parent) : parent(parent)
{
sb::Log::log("constructing node " + get_branch_as_string(), sb::Log::DEBUG);
SDL_Log("Constructing node %s", get_branch_as_string().c_str());
}
void Node::set_parent(Node* other)
@ -158,6 +158,9 @@ const std::string Node::get_branch_as_string() const
Node::~Node()
{
sb::Log::log("destroying node " + get_branch_as_string(), sb::Log::DEBUG);
/* This logging call will segfault because it requires access to the configuration which may be deleted already:
*
* SDL_Log("Destroying Node %s", get_branch_as_string().c_str());
*/
get_delegate().unsubscribe(this);
}

View File

@ -104,3 +104,10 @@ private:
bool active = true;
};
/* Add Node class to the sb namespace. This should be the default location, but Node is left in the global namespace
* for backward compatibility. */
namespace sb
{
using ::Node;
}

View File

@ -40,51 +40,36 @@ void Text::font(std::shared_ptr<TTF_Font> font)
void Text::refresh()
{
/* Try getting the font pointer from this class. If that hasn't been set, try getting the default font from the Game class.
* If neither has been set, print an error without generating a texture. */
TTF_Font* font = nullptr;
if (_font.get() != nullptr)
{
font = _font.get();
}
else if (sb::Game::font().get() != nullptr)
{
font = sb::Game::font().get();
}
/* Create pixel data using the SDL image library. The pixel data surface is converted from paletted format to ARGB and flipped. */
if (font != nullptr)
SDL_Surface* shaded = TTF_RenderText_Shaded(_font.get(), _content.c_str(), _foreground, _background);
if (!shaded)
{
SDL_Surface* shaded = TTF_RenderText_Shaded(font, _content.c_str(), _foreground, _background);
if (!shaded)
{
sb::Log::sdl_error("Could not create text");
}
else
{
if (!(shaded = SDL_ConvertSurfaceFormat(shaded, SDL_PIXELFORMAT_ARGB8888, 0)))
{
sb::Log::sdl_error("Could not convert pixel format");
}
else
{
if (!(shaded = rotozoomSurfaceXY(shaded, 0, 1, -1, 0)))
{
sb::Log::sdl_error("Could not flip surface");
}
else
{
/* Generate texture and create storage. Load the pixels from the text rendering surface into the default texture. The texture object will handle
* destroying the previous texture. Then destroy the pixels surface. */
texture().generate({shaded->w, shaded->h}, GL_RGBA8, GL_LINEAR);
texture().load(shaded);
}
}
SDL_FreeSurface(shaded);
}
sb::Log::sdl_error("Could not create text");
}
else
{
sb::Log::log("No font set and no default font found", sb::Log::ERROR);
SDL_Surface* converted = converted = SDL_ConvertSurfaceFormat(shaded, SDL_PIXELFORMAT_ARGB8888, 0);
if (!converted)
{
sb::Log::sdl_error("Could not convert pixel format");
}
else
{
SDL_Surface* flipped = rotozoomSurfaceXY(converted, 0, 1, -1, 0);
if (!flipped)
{
sb::Log::sdl_error("Could not flip surface");
}
else
{
/* Generate texture and create storage. Load the pixels from the text rendering surface into the default texture. The texture object will handle
* destroying the previous texture. Then destroy the pixels surface. */
texture().generate({flipped->w, flipped->h}, GL_RGBA8, GL_LINEAR);
texture().load(flipped);
SDL_FreeSurface(flipped);
}
SDL_FreeSurface(converted);
}
SDL_FreeSurface(shaded);
}
}

View File

@ -20,23 +20,27 @@ namespace sb
std::shared_ptr<TTF_Font> _font;
/*!
* Set the texture to the appropriate SDL_Surface created by the SDL TTF library.
* Load the texture with the appropriate SDL_Surface pixels created by the SDL TTF library.
*/
void refresh();
public:
Text(const std::string& content = "", const sb::Color& foreground = DEFAULT_FG, const sb::Color& background = DEFAULT_BG) :
_content(content), _foreground(foreground), _background(background)
{
/* Assign a default constructed Texture object to be the default texture */
texture(sb::Texture());
}
/*!
* Construct a sb::Text object from a font, string, and background and foreground colors.
*
* The font must be wrapped in a shared pointer. A default loaded font is available from Game::font().
*
* @param font a TTF_Font object wrapped in a shared pointer
* @param content text content
* @param foreground text color
* @param background background color
*/
Text(std::shared_ptr<TTF_Font> font, const std::string& content = "", const sb::Color& foreground = DEFAULT_FG,
const sb::Color& background = DEFAULT_BG) : Text(content, foreground, background)
const sb::Color& background = DEFAULT_BG) : _content(content), _foreground(foreground), _background(background), _font(font)
{
_font = font;
/* Add an empty Texture object */
texture(sb::Texture());
}
/*!

View File

@ -72,35 +72,39 @@ namespace sb
void generate(glm::vec2 size, GLenum format = GL_RGBA8, GLint filter = GL_NEAREST);
/*!
* @overload load(fs::path path)
* Load a texture from the path that was previously set.
*
* Load a texture from the path that was set on this object at initialization.
*
* @see Texture(fs::path)
* @see ::Texture(fs::path)
* @see ::associate(fs::path)
* @see ::load(fs::path)
*/
void load();
/*!
* @overload load(SDL_Surface* surface)
*
* Load a texture from a path to an image file. This will create an SDL Surface from the image file at a given path and forward it
* to the load overload which accepts a surface pointer.
*
* Unless the texture has already been generated, the texture will be generated with storage for the size of the image.
*
* @param path Filesystem path to an image file
*/
void load(fs::path path);
/*!
* @overload load(SDL_Surface* surface)
*
* Load texture from an SDL RW stream
* Load texture from an SDL read/write stream object.
*
* Unless the texture has already been generated, the texture will be generated with storage for the size of the image.
*
* @param rw an SDL read/write object pointing to an image file that will be read for pixel data
*/
void load(SDL_RWops* rw);
/*!
* @overload load(void* pixels, glm::vec2 size, GLenum format, GLenum type)
*
* Load texture from an SDL surface
* Load texture from an SDL surface.
*
* Unless the texture has already been generated, the texture will be generated with storage for the size of the image.
*
* @param surface an SDL surface filled with texture pixel data
*/
void load(SDL_Surface* surface);
@ -108,6 +112,8 @@ namespace sb
* Load raw pixel data into texture using OpenGL's `glTexSubImage2D`. The format and type determine how the data will be loaded.
* The format is the pixel format, and the type is the type of the data.
*
* Unless the texture has already been generated, the texture will be generated with storage for the size of the image.
*
* @param pixels Raw pointer to pixel data memory. The type of data pointed to should be given to the format argument.
* @param size Dimensions of the image
* @param format Format of each pixel