- 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:
parent
6371f9c279
commit
aaaebc006d
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
20
src/Game.cpp
20
src/Game.cpp
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
12
src/Game.hpp
12
src/Game.hpp
|
@ -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();
|
||||
|
|
119
src/Model.cpp
119
src/Model.cpp
|
@ -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()
|
||||
|
|
164
src/Model.hpp
164
src/Model.hpp
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
67
src/Text.cpp
67
src/Text.cpp
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
24
src/Text.hpp
24
src/Text.hpp
|
@ -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());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue