diff --git a/README b/README index 9ff778d..5cbc533 100644 --- a/README +++ b/README @@ -1,25 +1,28 @@ SFW (SDL Framework) =================== -SFW is a library of C++ objects that facilitate the creation of SDL projects. -It is modeled after PGFW, a Pygame framework, which is an older project of mine. -It is currently in an early untested stage, but it comes with a simple program -that demonstrates how the framework can help set up a project in both SDL and -OpenGL contexts. +SFW is a C++ library that facilitates the creation of SDL projects and adds +useful game graphics oriented classes and functions. It is modeled after PGFW, a +Pygame framework, which simplifies the set up of Pygame projects and enhances +and adds some features to Pygame. + +It is currently in an early untested stage. It comes with a simple program that +demonstrates how the framework can help set up a project in both SDL and OpenGL +contexts. Requirements ------------ -The SFW source comes with a few libraries in the lib/ folder, but there are -other libraries that must be present in order to compile a project which uses -the framework +The SFW source includes some external libraries in the lib/ folder, but there +are also other libraries that must be present in order to compile a project +which uses the framework -- libSDL2 (developed with 2.0.9) -- libSDL2-image -- libSDL2-ttf -- libSDL2-mixer -- Open GL -- compiler that supports C++17 +* libSDL2 (developed against v2.0.12) +* libSDL2-image +* libSDL2-ttf +* libSDL2-mixer +* OpenGL +* compiler that supports C++17 Demo ---- @@ -35,7 +38,7 @@ License This software is dedicated to the public domain. See http://creativecommons.org/publicdomain/zero/1.0/ for details. -Contact -------- +Author +------ -You can email me at frank at shampoo.ooo +420 at shampoo dot ooo diff --git a/demo/Demo.cpp b/demo/Demo.cpp index 4bd0cc8..afc3076 100644 --- a/demo/Demo.cpp +++ b/demo/Demo.cpp @@ -9,7 +9,8 @@ relative coordinates, relative lengths, relative sizes, delta time, specify config parameters on command line, effects chain, asset dict with metadata, move added sprite locations by offset when location is changed, gradients, - level select code input, logging + level select code input, logging, variable screen resolution, debug display, + loading wheel animation :) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :) @@ -131,7 +132,7 @@ Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms") void Mushroom::update() { move(direction); - int x = location.get_x(); + int x = box.get_x(); glm::ivec2 resolution = get_display().get_window_size(); if (x > resolution.x or x < 0) { diff --git a/demo/Demo.hpp b/demo/Demo.hpp index bb873ef..39126bb 100644 --- a/demo/Demo.hpp +++ b/demo/Demo.hpp @@ -33,7 +33,7 @@ #include "filesystem.hpp" #include "Node.hpp" #include "Game.hpp" -#include "Location.hpp" +#include "Box.hpp" #include "Sprite.hpp" #include "Input.hpp" #include "Delegate.hpp" diff --git a/demo/Makefile b/demo/Makefile index 5cd6d32..3257271 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -36,7 +36,7 @@ $(SDLGFX2_DIR)%.o: $(SDLGFX2_DIR)%.c $(SDLGFX2_DIR)%.h $(GLEW_DIR)%.o: $(GLEW_DIR)%.c $(GLEW_DIR)%.h $(CC_LINUX) $(CFLAGS) $< -o $@ -$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Location.*pp Node.*pp Animation.*pp) +$(SFW_SRC_DIR)Sprite.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Box.*pp Node.*pp Animation.*pp) $(SFW_SRC_DIR)Game.o: $(addprefix $(SFW_SRC_DIR),Sprite.*pp Configuration.*pp Delegate.*pp Display.*pp \ Recorder.*pp Node.*pp Input.*pp) $(SFW_SRC_DIR)Node.o: $(addprefix $(SFW_SRC_DIR),Game.*pp Configuration.*pp Delegate.*pp) @@ -49,11 +49,11 @@ $(SFW_SRC_DIR)Display.o: $(addprefix $(SFW_SRC_DIR),Node.*pp) $(SFW_SRC_DIR)%.o: $(addprefix $(SFW_SRC_DIR),%.cpp %.hpp) $(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@ -Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Location.*pp Input.*pp \ +Demo.o: Demo.cpp Demo.hpp $(addprefix $(SFW_SRC_DIR),Sprite.*pp Node.*pp Game.*pp Box.*pp Input.*pp \ Recorder.*pp Timer.*pp Animation.*pp extension.*pp) $(CPPC_LINUX) $(CPP_FLAGS) $(SDL_FLAGS) $< -o $@ -linux: Demo.o $(addprefix $(SFW_SRC_DIR),Sprite.o Node.o Game.o Location.o Configuration.o Input.o Delegate.o \ +linux: Demo.o $(addprefix $(SFW_SRC_DIR),Sprite.o Node.o Game.o Box.o Configuration.o Input.o Delegate.o \ Display.o Recorder.o Timer.o Animation.o extension.o) \ $(GLEW_DIR)glew.o $(addprefix $(SDLGFX2_DIR),SDL2_rotozoom.o SDL2_gfxPrimitives.o) $(CPPC_LINUX) $(LFLAGS) -D__LINUX__ $^ -lGL -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lstdc++fs -o demo diff --git a/src/Animation.cpp b/src/Animation.cpp index a3b0c8c..5f0181b 100644 --- a/src/Animation.cpp +++ b/src/Animation.cpp @@ -69,6 +69,10 @@ void Animation::update() { reset(); } + if (overflow > frame_length) + { + overflow = 0; + } } } } diff --git a/src/Animation.hpp b/src/Animation.hpp index 520d435..00a7662 100644 --- a/src/Animation.hpp +++ b/src/Animation.hpp @@ -14,8 +14,8 @@ struct Animation { bool playing = false, ending = false, paused = false; - int previous_step_time = 0, overflow = 0, count = 0; - float delay = 0, frame_length; + int previous_step_time = 0, count = 0; + float delay = 0, overflow = 0, frame_length; callback step; Node* containing_object; Timer timer = Timer(); diff --git a/src/Box.cpp b/src/Box.cpp new file mode 100644 index 0000000..6dc1738 --- /dev/null +++ b/src/Box.cpp @@ -0,0 +1,187 @@ +#include "Box.hpp" + +Box::Box(glm::vec2 nw, glm::vec2 size) +{ + set_nw(nw); + set_size(size); +} + +float Box::get_x() +{ + return rect.x; +} + +float Box::get_y() +{ + return rect.y; +} + +float Box::get_w() +{ + return rect.w; +} + +float Box::get_h() +{ + return rect.h; +} + +void Box::set_x(float x) +{ + rect.x = x; +} + +void Box::set_y(float y) +{ + rect.y = y; +} + +void Box::set_w(float w) +{ + rect.w = w; +} + +void Box::set_h(float h) +{ + rect.h = h; +} + +glm::vec2 Box::get_size() +{ + return glm::vec2(get_w(), get_h()); +} + +void Box::set_size(glm::vec2 size) +{ + set_w(size.x); + set_h(size.y); +} + +float Box::get_top() +{ + return get_y(); +} + +float Box::get_right() +{ + return get_x() + get_w(); +} + +float Box::get_bottom() +{ + return get_y() + get_h(); +} + +float Box::get_left() +{ + return get_x(); +} + +void Box::set_top(float top) +{ + set_y(top); +} + +void Box::set_right(float right) +{ + move(glm::vec2(right - get_right(), 0)); +} + +void Box::set_bottom(float bottom) +{ + move(glm::vec2(0, bottom - get_bottom())); +} + +void Box::set_left(float left) +{ + set_x(left); +} + +glm::vec2 Box::get_nw() +{ + return glm::vec2(get_x(), get_y()); +} + +glm::vec2 Box::get_north() +{ + return glm::vec2(get_x() + get_w() / 2, get_y()); +} + +glm::vec2 Box::get_east() +{ + return glm::vec2(get_right(), get_y() + get_h() / 2); +} + +glm::vec2 Box::get_south() +{ + return glm::vec2(get_x() + get_w() / 2, get_bottom()); +} + +glm::vec2 Box::get_west() +{ + return glm::vec2(get_x(), get_y() + get_h() / 2); +} + +glm::vec2 Box::get_center() +{ + return glm::vec2(get_x() + get_w() / 2, get_y() + get_h() / 2); +} + +void Box::set_nw(glm::vec2 nw) +{ + set_x(nw.x); + set_y(nw.y); +} + +void Box::set_north(glm::vec2 n) +{ + move(n - get_north()); +} + +void Box::set_east(glm::vec2 e) +{ + move(e - get_east()); +} + +void Box::set_south(glm::vec2 s) +{ + move(s - get_south()); +} + +void Box::set_west(glm::vec2 w) +{ + move(w - get_west()); +} + +void Box::set_center(glm::vec2 center) +{ + move(center - get_center()); +} + +SDL_FRect* Box::get_rect() +{ + return ▭ +} + +void Box::zero() +{ + set_nw(glm::vec2(0, 0)); + set_size(glm::vec2(0, 0)); +} + +void Box::move(glm::vec2 delta) +{ + set_x(get_x() + delta.x); + set_y(get_y() + delta.y); +} + +std::ostream& Box::to_string (std::ostream& out) const +{ + out << "{(" << rect.x << ", " << rect.y << "), (" << rect.w << ", " << rect.h << ")}"; + return out; +} + +std::ostream& operator<< (std::ostream& out, const Box& box) +{ + return box.to_string(out); +} diff --git a/src/Box.hpp b/src/Box.hpp new file mode 100644 index 0000000..c924c44 --- /dev/null +++ b/src/Box.hpp @@ -0,0 +1,59 @@ +#ifndef Box_h_ +#define Box_h_ + +#include + +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include "glm/common.hpp" +#include "glm/vec2.hpp" + +struct Box +{ + SDL_FRect rect = {0, 0, 0, 0}; + + Box(glm::vec2 = {0, 0}, glm::vec2 = {0, 0}); + float get_x(); + float get_y(); + float get_w(); + float get_h(); + void set_x(float); + void set_y(float); + void set_w(float); + void set_h(float); + glm::vec2 get_size(); + void set_size(glm::vec2); + float get_top(); + float get_right(); + float get_bottom(); + float get_left(); + void set_top(float); + void set_right(float); + void set_bottom(float); + void set_left(float); + glm::vec2 get_nw(); + glm::vec2 get_north(); + glm::vec2 get_east(); + glm::vec2 get_south(); + glm::vec2 get_west(); + glm::vec2 get_center(); + void set_nw(glm::vec2); + void set_north(glm::vec2); + void set_east(glm::vec2); + void set_south(glm::vec2); + void set_west(glm::vec2); + void set_center(glm::vec2); + SDL_FRect* get_rect(); + void zero(); + void move(glm::vec2); + std::string get_class_name() { return "Box"; } + std::ostream& to_string (std::ostream&) const; + +}; + +std::ostream& operator<< (std::ostream&, const Box&); + +#include "extension.hpp" + +#endif diff --git a/src/Configuration.cpp b/src/Configuration.cpp index d994e3e..5c03fe3 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -31,7 +31,8 @@ void Configuration::set_defaults() }; sys_config["display"] = { {"dimensions", {640, 480}}, - {"fps", 60} + {"fps", 60}, + {"title", "sfw"} }; sys_config["recording"] = { {"enabled", false}, diff --git a/src/Display.cpp b/src/Display.cpp index 77adf86..7e013a0 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -2,14 +2,19 @@ #include "Game.hpp" Display::Display(Node* parent) : Node(parent) {} - + glm::ivec2 Display::get_window_size() { glm::ivec2 size; - SDL_GetWindowSize(get_root()->window, &size.x, &size.y); + SDL_GetWindowSize(get_root()->get_window(), &size.x, &size.y); return size; } +Box Display::get_window_box() +{ + return Box(glm::vec2(0, 0), get_window_size()); +} + void Display::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int y) { if (get_root()->is_gl_context) diff --git a/src/Display.hpp b/src/Display.hpp index 4ed353b..ade58f9 100644 --- a/src/Display.hpp +++ b/src/Display.hpp @@ -8,13 +8,14 @@ #define GLEW_STATIC #include "glew/glew.h" +#include "SDL.h" + #include #include "sdl2-gfx/SDL2_gfxPrimitives.h" #include "sdl2-gfx/SDL2_rotozoom.h" -#include "SDL.h" - #include "Node.hpp" +#include "Box.hpp" struct Display : Node { @@ -23,6 +24,7 @@ struct Display : Node Display(Node*); glm::ivec2 get_window_size(); + Box get_window_box(); void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0); SDL_Surface* get_screen_surface(); SDL_Surface* get_screen_surface_from_pixels(unsigned char*, bool); diff --git a/src/Game.cpp b/src/Game.cpp index 1723e09..05c610a 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -38,8 +38,9 @@ Game::Game() SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); print_gl_attributes(); std::vector window_size = get_configuration()["display"]["dimensions"]; - window = SDL_CreateWindow("TARE control", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - window_size[0], window_size[1], SDL_WINDOW_OPENGL); + window = SDL_CreateWindow( + get_configuration()["display"]["title"].get_ref().c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, window_size[0], window_size[1], SDL_WINDOW_OPENGL); if (window == NULL) { print_sdl_error("Could not create window"); @@ -56,6 +57,7 @@ Game::Game() SDL_Log("initialized SDL ttf %d.%d.%d", SDL_TTF_MAJOR_VERSION, SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL); } +#if !defined(__EMSCRIPTEN__) if (Mix_Init(MIX_INIT_FLAC) == 0) { print_sdl_error("Could not initialize SDL mixer"); @@ -66,6 +68,7 @@ Game::Game() SDL_Log("initialized SDL mixer %d.%d.%d", SDL_MIXER_MAJOR_VERSION, SDL_MIXER_MINOR_VERSION, SDL_MIXER_PATCHLEVEL); } +#endif if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, 1024) < 0) { @@ -171,14 +174,6 @@ void Game::load_gl_context() log_display_mode(); } -GLuint Game::create_gl_texture() -{ - GLuint id; - glCreateTextures(GL_TEXTURE_2D, 1, &id); - glBindTexture(GL_TEXTURE_2D, id); - return id; -} - bool Game::log_gl_errors(std::string suffix) { GLenum error; @@ -398,29 +393,81 @@ std::string Game::get_pixel_format_string(Uint32 format) return pixel_format; } +SDL_Window* Game::get_window() +{ + return window; +} + +SDL_Renderer* Game::get_renderer() +{ + return renderer; +} + void Game::run() { + +#if defined(__EMSCRIPTEN__) + + emscripten_set_main_loop_arg(&loop, this, -1, true); + +#else + while (not done) { - ticks = SDL_GetTicks(); - if (ticks - last_frame_timestamp + frame_time_overflow >= frame_length) - { - last_frame_length = ticks - last_frame_timestamp; - frame_time_overflow = last_frame_length + frame_time_overflow - frame_length; - last_frame_timestamp = ticks; - recorder.update(); - delegate.dispatch(); - update(); - } + frame(SDL_GetTicks()); SDL_Delay(8); } + +#endif + } +void Game::frame(float ticks) +{ + // std::cout << "ticks: " << ticks << ", last_frame_timestamp: " << last_frame_timestamp << + // ", frame_time_overflow: " << frame_time_overflow; + if (ticks - last_frame_timestamp + frame_time_overflow >= frame_length) + { + last_frame_length = ticks - last_frame_timestamp; + // std::cout << ", last_frame_length: " << last_frame_length << " [rendering frame]"; + frame_time_overflow = last_frame_length + frame_time_overflow - frame_length; + last_frame_timestamp = ticks; + recorder.update(); + delegate.dispatch(); + update(); + if (frame_time_overflow > frame_length) + { + SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length))); + frame_time_overflow = 0; + } + } + // std::cout << std::endl; +} + +#if defined(__EMSCRIPTEN__) + +void loop(void* context) +{ + Game* game = static_cast(context); + game->frame(emscripten_performance_now()); + if (game->done) + { + emscripten_cancel_main_loop(); + } +} + +#endif + void Game::flag_to_end() { done = true; } +glm::vec2 Game::weight(glm::vec2 motion) +{ + return glm::vec2(weight(motion.x), weight(motion.y)); +} + void Game::set_framerate(int fps) { if (fps < 1) diff --git a/src/Game.hpp b/src/Game.hpp index 0935d40..cb207e2 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -13,8 +13,19 @@ #define GL_GLEXT_PROTOTYPES #define GLEW_STATIC + +#if defined(__EMSCRIPTEN__) + +#include +#include +#include + +#else + #include "glew/glew.h" +#endif + #include "Node.hpp" #include "Configuration.hpp" #include "Delegate.hpp" @@ -43,9 +54,9 @@ struct Game : Node SDL_GLContext glcontext = NULL; // 768, 432 // 864, 486 - int frame_time_overflow = 0, framerate, ticks, last_frame_timestamp, - frame_count_timestamp, last_frame_length; - float frame_length; + int framerate, ticks, last_frame_length; + float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, + last_frame_timestamp, emscripten_previous_time; bool done = false, show_framerate = true, is_gl_context = true; Configuration configuration = Configuration(this); Delegate delegate = Delegate(this); @@ -60,27 +71,36 @@ struct Game : Node void print_gl_attributes(); void load_sdl_context(); void load_gl_context(); - GLuint create_gl_texture(); bool log_gl_errors(std::string); void log_display_mode(); void log_surface_format(SDL_Surface*, std::string = "surface"); std::string get_pixel_format_string(Uint32); + SDL_Window* get_window(); + SDL_Renderer* get_renderer(); void run(); + void frame(float); void flag_to_end(); virtual void update() {}; + glm::vec2 weight(glm::vec2); void set_framerate(int); void handle_quit_event(SDL_Event&); void quit(); std::string get_class_name() { return "Game"; } template - float get_weighted_amount(T amount) + float weight(T amount) { return (last_frame_length / (1000.0 / 60)) * amount; } }; +#if defined(__EMSCRIPTEN__) + +void loop(void*); + +#endif + #include "Sprite.hpp" #endif diff --git a/src/Location.cpp b/src/Location.cpp deleted file mode 100644 index b36ce0f..0000000 --- a/src/Location.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Location.hpp" - -int Location::get_x() -{ - return rect.x; -} - -int Location::get_y() -{ - return rect.y; -} diff --git a/src/Location.hpp b/src/Location.hpp deleted file mode 100644 index a28e465..0000000 --- a/src/Location.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef Location_h_ -#define Location_h_ - -#include - -#include - -#define GLM_ENABLE_EXPERIMENTAL -#include "glm/common.hpp" -#include "glm/vec2.hpp" - -struct Location -{ - SDL_Rect rect = {0, 0, 0, 0}; - glm::vec2 overflow; - - Location() { }; - int get_x(); - int get_y(); - std::string get_class_name() { return "Location"; } - - template - void move_ip(T1 dx, T2 dy = 0) - { - overflow += glm::vec2(dx, dy); - glm::vec2 motion = glm::floor(overflow); - overflow -= motion; - rect.x += motion[0]; - rect.y += motion[1]; - } - -}; - -#endif diff --git a/src/Recorder.cpp b/src/Recorder.cpp index 425a0ae..0c21d8c 100644 --- a/src/Recorder.cpp +++ b/src/Recorder.cpp @@ -359,9 +359,9 @@ void Recorder::update() animation.update(); } -void process_audio(void* user_data, Uint8* stream, int len) +void process_audio(void* context, Uint8* stream, int len) { - Recorder* recorder = static_cast(user_data); + Recorder* recorder = static_cast(context); if (recorder->is_active()) { int max_length = recorder->get_configuration()["recording"]["max-stash-length"]; diff --git a/src/Sprite.cpp b/src/Sprite.cpp index 2c6dbbd..7f86941 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -1,17 +1,19 @@ #include "Sprite.hpp" #include "Game.hpp" -Sprite::Sprite(Node *parent) : Node(parent, true) {} +Sprite::Sprite(Node* parent) : Node(parent, true) +{ + frame_animation.play(); +} -Sprite::Sprite(Node *parent, std::string path) : Node(parent, true) +Sprite::Sprite(Node* parent, std::string path) : Sprite(parent) { associate(path); - animation.play(); } void Sprite::set_frame_length(float length) { - animation.set_frame_length(length); + frame_animation.set_frame_length(length); } void Sprite::associate(std::string path) @@ -62,8 +64,18 @@ void Sprite::load_file(fs::path path) } } -void Sprite::add_frame(SDL_Texture *texture) +void Sprite::add_frame(SDL_Texture* texture) { + int w, h; + SDL_QueryTexture(texture, NULL, NULL, &w, &h); + if (box.get_w() < w) + { + box.set_w(w); + } + if (box.get_h() < h) + { + box.set_h(h); + } frames.push_back(texture); } @@ -74,6 +86,7 @@ void Sprite::unload() SDL_DestroyTexture(frames.back()); frames.pop_back(); } + box.zero(); } void Sprite::advance_frame() @@ -84,15 +97,105 @@ void Sprite::advance_frame() } } +void Sprite::hide() +{ + is_hidden = true; +} + +void Sprite::unhide() +{ + is_hidden = false; +} + +void Sprite::toggle_hidden() +{ + is_hidden = !is_hidden; +} + +void Sprite::set_step(glm::vec2 s) +{ + step.x = s.x; + step.y = s.y; +} + +float Sprite::get_w() +{ + return box.get_w(); +} + +float Sprite::get_h() +{ + return box.get_h(); +} + +glm::vec2 Sprite::get_size() +{ + return box.get_size(); +} + +float Sprite::get_top() +{ + return box.get_top(); +} + +float Sprite::get_right() +{ + return box.get_right(); +} + +float Sprite::get_bottom() +{ + return box.get_bottom(); +} + +float Sprite::get_left() +{ + return box.get_left(); +} + +glm::vec2 Sprite::get_nw() +{ + return box.get_nw(); +} + +glm::vec2 Sprite::get_north() +{ + return box.get_north(); +} + +glm::vec2 Sprite::get_west() +{ + return box.get_west(); +} + +void Sprite::set_nw(glm::vec2 nw) +{ + box.set_nw(nw); +} + +void Sprite::move(glm::vec2 delta, bool weighted) +{ + Game *game = get_root(); + if (weighted) + { + delta = game->weight(delta); + } + box.move(delta); +} + void Sprite::update() { if (active) { - animation.update(); - int w, h; - SDL_Texture *frame = frames[frame_ii]; - SDL_QueryTexture(frame, NULL, NULL, &w, &h); - SDL_Rect frame_rect = {location.get_x(), location.get_y(), w, h}; - SDL_RenderCopy(get_root()->renderer, frame, NULL, &frame_rect); + move(step); + frame_animation.update(); + blink_animation.update(); + if (frames.size() && !is_hidden) + { + SDL_Texture* texture = frames[frame_ii]; + SDL_Renderer* renderer = get_root()->renderer; + SDL_SetRenderTarget(renderer, NULL); + SDL_RenderCopyF(renderer, texture, NULL, box.get_rect()); + } } } diff --git a/src/Sprite.hpp b/src/Sprite.hpp index 70be14c..9aedb8a 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -11,7 +11,7 @@ #include "Node.hpp" #include "Game.hpp" -#include "Location.hpp" +#include "Box.hpp" #include "Animation.hpp" struct Sprite : Node @@ -20,8 +20,11 @@ struct Sprite : Node std::vector frames; std::vector frame_paths; int frame_ii = 0; - Location location; - Animation animation = Animation(&Sprite::advance_frame, this); + Box box; + Animation frame_animation = Animation(&Sprite::advance_frame, this); + Animation blink_animation = Animation(&Sprite::toggle_hidden, this, 500); + bool is_hidden = false; + glm::vec2 step = {0, 0}; Sprite(Node*); Sprite(Node*, std::string); @@ -32,15 +35,25 @@ struct Sprite : Node void add_frame(SDL_Texture*); void unload(); void advance_frame(); + void hide(); + void unhide(); + void toggle_hidden(); + void set_step(glm::vec2); + float get_w(); + float get_h(); + glm::vec2 get_size(); + float get_top(); + float get_right(); + float get_bottom(); + float get_left(); + glm::vec2 get_nw(); + glm::vec2 get_north(); + glm::vec2 get_west(); + void set_nw(glm::vec2); + void move(glm::vec2, bool = true); void update(); std::string get_class_name() { return "Sprite"; } - - template - void move(T1 dx, T2 dy = 0) - { - Game *game = get_root(); - location.move_ip(game->get_weighted_amount(dx), game->get_weighted_amount(dy)); - } + ~Sprite() { unload(); } }; diff --git a/src/Timer.cpp b/src/Timer.cpp index 9511a97..09b56ed 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -8,7 +8,7 @@ Timer::Timer() void Timer::toggle() { - is_timing = not is_timing; + is_timing = !is_timing; } void Timer::toggle(bool state) diff --git a/src/extension.cpp b/src/extension.cpp index 9a58d79..3d059eb 100644 --- a/src/extension.cpp +++ b/src/extension.cpp @@ -1,5 +1,40 @@ #include "extension.hpp" +glm::vec2 sfw::get_step(glm::vec2 start, glm::vec2 end, float speed) +{ + float angle = glm::atan(end.x - start.x, end.y - start.y); + return glm::vec2(speed * glm::sin(angle), speed * glm::cos(angle)); +} + +Box sfw::get_texture_box(SDL_Texture* texture) +{ + int w, h; + SDL_QueryTexture(texture, NULL, NULL, &w, &h); + return Box(glm::vec2(0, 0), glm::vec2(w, h)); +} + +void sfw::fill_texture(SDL_Renderer* renderer, SDL_Texture* texture, int r, int g, int b, int a) +{ + SDL_SetRenderTarget(renderer, texture); + SDL_SetRenderDrawColor(renderer, r, g, b, a); + SDL_RenderFillRect(renderer, NULL); +} + +void sfw::fill_texture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Texture* tile) +{ + SDL_SetRenderTarget(renderer, texture); + Box texture_box = get_texture_box(texture), tile_box = get_texture_box(tile); + SDL_FRect draw_rect; + for (int x = 0; x < texture_box.get_w(); x += tile_box.get_w()) + { + for (int y = 0; y < texture_box.get_h(); y += tile_box.get_h()) + { + draw_rect = {(float) x, (float) y, tile_box.get_w(), tile_box.get_h()}; + SDL_RenderCopyF(renderer, tile, NULL, &draw_rect); + } + } +} + std::vector sfw::glob(fs::path query) { fs::path basename = query.parent_path(); diff --git a/src/extension.hpp b/src/extension.hpp index 88c55b1..57fd43d 100644 --- a/src/extension.hpp +++ b/src/extension.hpp @@ -8,10 +8,21 @@ #include #include +#define GLM_ENABLE_EXPERIMENTAL +#include "glm/trigonometric.hpp" +#include "glm/vec2.hpp" + +#include "SDL.h" + +#include "Box.hpp" #include "filesystem.hpp" namespace sfw { + glm::vec2 get_step(glm::vec2, glm::vec2, float); + Box get_texture_box(SDL_Texture*); + void fill_texture(SDL_Renderer*, SDL_Texture*, int, int, int, int = 0xff); + void fill_texture(SDL_Renderer*, SDL_Texture*, SDL_Texture*); std::vector glob(fs::path); fs::path get_next_file_name( fs::path, int = 0, std::string = "", std::string = "");