diff --git a/demo/squircle/Makefile b/demo/squircle/Makefile index f3fe5f4..abd114a 100644 --- a/demo/squircle/Makefile +++ b/demo/squircle/Makefile @@ -50,7 +50,7 @@ CFLAGS := -Wall -O0 -c -I$(SB_LIB_DIR) -I$(SB_SRC_DIR) $(shell $(SDLCONFIG) --cf CPP_FLAGS := $(CFLAGS) --std=c++17 LFLAGS := $(shell $(SDLCONFIG) --libs) -lpthread SB_H_FILES := $(wildcard $(addprefix $(SB_SRC_DIR),*.hpp)) -SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o),$(SB_H_FILES:.hpp=.o)) +SB_O_FILES := $(filter-out $(addprefix $(SB_SRC_DIR),filesystem.o GLObject.o),$(SB_H_FILES:.hpp=.o)) SRC_H_FILES := $(wildcard $(addprefix $(SRC_DIR),*.hpp)) SRC_O_FILES := $(SRC_H_FILES:.hpp=.o) @@ -77,6 +77,7 @@ $(SB_SRC_DIR)Box.o : $(addprefix $(SB_SRC_DIR),extension.hpp Segment.hpp) $(SB_SRC_DIR)Segment.o : $(addprefix $(SB_SRC_DIR),extension.hpp Box.hpp) $(SB_SRC_DIR)Pixels.o : $(addprefix $(SB_SRC_DIR),Box.hpp extension.hpp) $(SB_SRC_DIR)Audio.o : $(addprefix $(SB_SRC_DIR),Node.hpp Display.hpp Configuration.hpp Box.hpp filesystem.hpp extension.hpp) +$(SB_SRC_DIR)Texture.o : $(addprefix $(SB_SRC_DIR),GLObject.hpp) $(SRC_DIR)Squircle.o : $(SB_H_FILES) %.o : %.cpp %.hpp $(CPPC) $(CPP_FLAGS) $< -c -o $@ diff --git a/src/GLObject.cpp b/src/GLObject.cpp new file mode 100644 index 0000000..dc00ff5 --- /dev/null +++ b/src/GLObject.cpp @@ -0,0 +1,29 @@ +#include "GLObject.hpp" + +/* A deleter function is required for freeing the memory allocated to the object (this could be, for example, + * glDeleteTextures for a Texture object, or a custom function that does something in addition to calling + * the appropriate GL deleter function) */ +GLObject::GLObject(std::function deleter) +{ + this->deleter = deleter; +} + +/* Set the shared pointer to point to a new GLuint with specified ID value */ +void GLObject::id(GLuint id) +{ + /* The deleter will be called when the object and all of its copies have gone out of scope */ + object_id = std::shared_ptr(new GLuint, deleter); + *object_id = id; +} + +/* Return the GL ID that was set for this object */ +GLuint GLObject::id() const +{ + return *object_id; +} + +/* Returns true if an ID has been generated */ +bool GLObject::generated() const +{ + return static_cast(object_id); +}; diff --git a/src/GLObject.hpp b/src/GLObject.hpp new file mode 100644 index 0000000..c4305af --- /dev/null +++ b/src/GLObject.hpp @@ -0,0 +1,53 @@ +/* /\ +--------------------------------------------------------------+ + ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | + +--\ ^__^ /--+ | | + | ~/ \~ | | - originally created at [http://nugget.fun] | + | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ + | SPACE ~~~~~ | / + | ~~~~~~~ BOX |/ + +--------------+ + + [GLObject.hpp] + + The abstract GLObject class is meant to be inherited by specific types of OpenGL objects, + for example Textures or Buffer objects. It stores the object's ID and declares virtual + functions for generating, binding, and destroying the object. + +*/ + +#ifndef GLObject_h_ +#define GLObject_h_ + +#include +#include +#include + +/* include Open GL */ +#if defined(__EMSCRIPTEN__) +#include +#else +#include "glew/glew.h" +#endif + +class GLObject +{ + +protected: + + std::shared_ptr object_id = nullptr; + std::function deleter = nullptr; + +public: + + GLObject(std::function); + virtual void generate() = 0; + virtual void bind() const = 0; + void id(GLuint); + GLuint id() const; + bool generated() const; + virtual ~GLObject() = default; + +}; + +#endif diff --git a/src/Game.hpp b/src/Game.hpp index 98ceb9d..ae30958 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -35,9 +35,11 @@ #include "filesystem.hpp" #include "extension.hpp" -struct FramerateIndicator : Sprite +class FramerateIndicator : public Sprite { +public: + FramerateIndicator(Node*); void respond(SDL_Event&); SDL_Surface* get_surface(); diff --git a/src/Pixels.hpp b/src/Pixels.hpp index 9d345ea..9257395 100644 --- a/src/Pixels.hpp +++ b/src/Pixels.hpp @@ -6,7 +6,7 @@ #include "Color.hpp" #include "extension.hpp" -struct Sprite; +class Sprite; struct Pixels { diff --git a/src/Segment.hpp b/src/Segment.hpp index 9c24cea..4f12d5c 100644 --- a/src/Segment.hpp +++ b/src/Segment.hpp @@ -8,7 +8,7 @@ #include "glm/vec2.hpp" class Box; -struct Sprite; +class Sprite; class Segment { diff --git a/src/Sprite.cpp b/src/Sprite.cpp index a8089ce..a711e86 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -1,3 +1,4 @@ +#include "Game.hpp" #include "Sprite.hpp" Sprite::Sprite() : Sprite(nullptr) {} @@ -115,12 +116,12 @@ const std::vector& Sprite::get_frames() const return frames; } -Frameset& Sprite::get_all_frames_frameset() +Sprite::Frameset& Sprite::get_all_frames_frameset() { return framesets[get_configuration()["animation"]["all-frames-frameset-name"]]; } -Frameset& Sprite::add_frameset(std::string name) +Sprite::Frameset& Sprite::add_frameset(std::string name) { if (framesets.find(name) == framesets.end()) { @@ -129,7 +130,7 @@ Frameset& Sprite::add_frameset(std::string name) return framesets[name]; } -Frameset& Sprite::set_frameset(std::string name) +Sprite::Frameset& Sprite::set_frameset(std::string name) { current_frameset_name = name; frame_animation.set_frame_length(get_current_frameset().get_frame_length()); @@ -140,12 +141,12 @@ Frameset& Sprite::set_frameset(std::string name) return get_current_frameset(); } -Frameset& Sprite::get_current_frameset() +Sprite::Frameset& Sprite::get_current_frameset() { return framesets.at(current_frameset_name); } -const Frameset& Sprite::get_current_frameset() const +const Sprite::Frameset& Sprite::get_current_frameset() const { return framesets.at(current_frameset_name); } @@ -933,17 +934,17 @@ void Sprite::set_to_deallocate_memory() leave_memory_allocated = false; } -Frameset::Frameset() : Frameset(NULL) {} +Sprite::Frameset::Frameset() : Frameset(NULL) {} -Frameset::Frameset(Sprite* sprite) : sprite(sprite) {} +Sprite::Frameset::Frameset(Sprite* sprite) : sprite(sprite) {} -void Frameset::add_frame_indicies(int index) +void Sprite::Frameset::add_frame_indicies(int index) { order.push_back(index); set_size(); } -void Frameset::set_frame_length(float length) +void Sprite::Frameset::set_frame_length(float length) { frame_length = length; if (&sprite->get_current_frameset() == this) @@ -952,38 +953,38 @@ void Frameset::set_frame_length(float length) } } -float Frameset::get_frame_length() const +float Sprite::Frameset::get_frame_length() const { return frame_length; } -void Frameset::reset() +void Sprite::Frameset::reset() { set_order_index(0); } -void Frameset::clear() +void Sprite::Frameset::clear() { order.clear(); reset(); } -int Frameset::get_order_index() const +int Sprite::Frameset::get_order_index() const { return order_index; } -void Frameset::set_order_index(int index) +void Sprite::Frameset::set_order_index(int index) { order_index = index; } -int Frameset::get_current_frame_index() const +int Sprite::Frameset::get_current_frame_index() const { return order[get_order_index()]; } -glm::vec2 Frameset::measure() const +glm::vec2 Sprite::Frameset::measure() const { glm::vec2 s(0, 0); int w, h; @@ -999,22 +1000,22 @@ glm::vec2 Frameset::measure() const return s; } -void Frameset::set_size() +void Sprite::Frameset::set_size() { set_size(measure()); } -void Frameset::set_size(const glm::vec2& s) +void Sprite::Frameset::set_size(const glm::vec2& s) { size = s; } -const glm::vec2& Frameset::get_size() const +const glm::vec2& Sprite::Frameset::get_size() const { return size; } -void Frameset::step() +void Sprite::Frameset::step() { if (order.size() > 0) { @@ -1022,22 +1023,22 @@ void Frameset::step() } } -void Frameset::increment_index() +void Sprite::Frameset::increment_index() { increment_index(reversed ? -1 : 1); } -void Frameset::increment_index(int increment) +void Sprite::Frameset::increment_index(int increment) { set_order_index((order_index + increment) % order.size()); } -int Frameset::get_frame_count() const +int Sprite::Frameset::get_frame_count() const { return order.size(); } -void Frameset::reverse() +void Sprite::Frameset::reverse() { reversed = !reversed; } diff --git a/src/Sprite.hpp b/src/Sprite.hpp index f266f74..9728132 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -9,22 +9,23 @@ #include #include #include - #include "SDL.h" #include "SDL_image.h" - #include "Node.hpp" #include "Box.hpp" #include "Animation.hpp" #include "Color.hpp" class Game; -struct Frameset; -struct Sprite : Node +class Sprite : public Node { - struct Child; +public: + + class Frameset; + class Child; + std::vector frames; std::vector frame_paths; std::vector boxes = {{{0, 0}, {0, 0}}}; @@ -145,12 +146,14 @@ struct Sprite : Node void set_to_leave_memory_allocated(); void set_to_deallocate_memory(); virtual std::string class_name() const { return "Sprite"; } - ~Sprite() { unload(); } }; -struct Sprite::Child +class Sprite::Child { + +public: + std::string name; Sprite sprite; @@ -160,11 +163,14 @@ struct Sprite::Child { return this->name == name; } + }; -struct Frameset +class Sprite::Frameset { +public: + Sprite* sprite; std::vector order; int order_index = 0; @@ -204,7 +210,6 @@ struct Frameset }; #include "Pixels.hpp" -#include "Game.hpp" #include "extension.hpp" #endif diff --git a/src/Texture.cpp b/src/Texture.cpp index b8d2824..1cf7348 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -1,7 +1,10 @@ #include "Texture.hpp" +/* Have to pass our deleter to abstract base class at instantiation */ +Texture::Texture() : GLObject(texture_deleter) {} + /* If an image path is passed at creation, the path will be stored in the class for later loading */ -Texture::Texture(fs::path path) +Texture::Texture(fs::path path) : Texture() { associate(path); } @@ -13,12 +16,18 @@ void Texture::associate(fs::path path) this->path = path; } -/* Generate a GL_TEXTURE_2D texture and allocate GL_RGB8 storage for the given size */ -void Texture::generate(glm::vec2 size) +/* Generate an ID for this Texture and save it */ +void Texture::generate() { GLuint id; glGenTextures(1, &id); this->id(id); +} + +/* Generate a GL_TEXTURE_2D texture ID and allocate GL_RGB8 storage for the given size */ +void Texture::generate(glm::vec2 size) +{ + generate(); bind(); glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, size.x, size.y); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -26,12 +35,6 @@ void Texture::generate(glm::vec2 size) Game::log_gl_errors(); } -/* Returns true if an ID has been generated for this Texture */ -bool Texture::generated() const -{ - return static_cast(texture_id); -} - /* When called with no parameters, use the stored path variable */ void Texture::load() { @@ -92,19 +95,6 @@ void Texture::load(void* pixels, GLenum format, GLenum type) } } -/* Set the shared pointer to point to a new GLuint with specified ID value */ -void Texture::id(GLuint id) -{ - texture_id = std::shared_ptr(new GLuint, Texture::destroy); - *texture_id = id; -} - -/* Return the GL texture ID that was set for this texture */ -GLuint Texture::id() const -{ - return *texture_id; -} - void Texture::bind() const { glBindTexture(GL_TEXTURE_2D, this->id()); @@ -129,16 +119,17 @@ glm::vec2 Texture::size() const } } -/* Delete this texture, freeing the memory */ -void Texture::destroy(GLuint* id) -{ - /* not sure why SDL_Log works here but SDL_LogDebug and SDL_LogInfo don't */ - SDL_Log("destroying texture ID %i", *id); - glDeleteTextures(1, id); -} - /* Textures are considered equal if they have the same ID */ bool Texture::operator==(const Texture& texture) const { return id() == texture.id(); } + +/* This function gets passed to the abstract base class for deleting the texture data when the ID + * pointer goes out of scope (when all instances of this texture and its copies are out of scope) */ +void texture_deleter(GLuint* id) +{ + /* not sure why SDL_Log works here at program end but SDL_LogDebug and SDL_LogInfo don't */ + SDL_Log("destroying texture ID %i", *id); + glDeleteTextures(1, id); +} diff --git a/src/Texture.hpp b/src/Texture.hpp index d23d88b..d84b14d 100644 --- a/src/Texture.hpp +++ b/src/Texture.hpp @@ -20,12 +20,12 @@ #ifndef Texture_h_ #define Texture_h_ -#include #include #include "SDL.h" #include "SDL_image.h" #include "sdl2-gfx/SDL2_rotozoom.h" #include "filesystem.hpp" +#include "GLObject.hpp" #include "Game.hpp" /* include Open GL */ @@ -35,34 +35,32 @@ #include "glew/glew.h" #endif -class Texture +class Texture : public GLObject { - + private: fs::path path = ""; - std::shared_ptr texture_id = nullptr; public: - Texture() {}; + Texture(); Texture(fs::path); void associate(fs::path); + void generate() override; void generate(glm::vec2); - bool generated() const; void load(); void load(fs::path); void load(SDL_RWops*); void load(SDL_Surface*); void load(void*, GLenum = GL_RGBA, GLenum = GL_UNSIGNED_BYTE); void load(void*, glm::vec2, GLenum = GL_RGBA, GLenum = GL_UNSIGNED_BYTE); - void id(GLuint); - GLuint id() const; - void bind() const; + void bind() const override; glm::vec2 size() const; - static void destroy(GLuint*); bool operator==(const Texture&) const; }; +void texture_deleter(GLuint*); + #endif