added children to sprites; sprite can set canvas it will draw on; fixed memory leak in precise collision detection on scaled sprites

This commit is contained in:
Frank DeMarco 2020-09-04 23:10:39 -04:00
parent 877d63cf4e
commit 0e6e506c68
15 changed files with 240 additions and 62 deletions

View File

@ -1,3 +1,7 @@
#include <fstream>
#include <ostream>
#include <iomanip>
#include "Configuration.hpp"
Configuration::Configuration(Node *parent) : Configuration(parent, "config.json") {}

View File

@ -1,11 +1,6 @@
#ifndef Configuration_h_
#define Configuration_h_
#include <vector>
#include <fstream>
#include <ostream>
#include <iomanip>
#include "json/json.hpp"
#include "filesystem.hpp"

View File

@ -53,7 +53,7 @@ void Display::get_screen_pixels(unsigned char* pixels, int w, int h, int x, int
else
{
SDL_Renderer* renderer = const_cast<SDL_Renderer*>(get_renderer());
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderPresent(renderer);
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA32, pixels, bpp / 8 * w);
}

View File

@ -50,7 +50,6 @@ Game::Game()
frame_length_history.reserve(5000);
set_framerate(get_configuration()["display"]["framerate"]);
delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT);
SDL_Log("GLEW %s", glewGetString(GLEW_VERSION));
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0");
// putenv("SDL_VIDEO_CENTERED=0");
SDL_version version;
@ -76,7 +75,7 @@ Game::Game()
// SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
// SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
// SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
print_gl_attributes();
SDL_Log("GLEW %s", glewGetString(GLEW_VERSION));
auto window_size = get_configuration()["display"]["dimensions"].get<glm::ivec2>();
window = SDL_CreateWindow(
get_configuration()["display"]["title"].get_ref<const std::string&>().c_str(), SDL_WINDOWPOS_CENTERED,
@ -86,8 +85,7 @@ Game::Game()
print_sdl_error("Could not create window");
flag_to_end();
}
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == NULL)
// if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_SOFTWARE)) == NULL)
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr)
{
print_sdl_error("Could not create renderer");
flag_to_end();
@ -211,7 +209,6 @@ void Game::load_sdl_context()
}
if ((renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr)
// if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_SOFTWARE)) == NULL)
{
print_sdl_error("Could not create renderer");
flag_to_end();
@ -235,8 +232,8 @@ void Game::load_gl_context()
renderer = NULL;
}
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
print_gl_attributes();
if ((glcontext = SDL_GL_CreateContext(window)) == NULL)
{

View File

@ -1,15 +1,15 @@
#ifndef Game_h_
#define Game_h_
#include <vector>
#include <string>
#include <iostream>
#include <list>
#include <sstream>
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include <SDL_mixer.h>
#include <SDL_ttf.h>
#include "SDL.h"
#include "SDL_mixer.h"
#include "SDL_ttf.h"
#define GL_GLEXT_PROTOTYPES
#define GLEW_STATIC
@ -23,9 +23,12 @@
#include "Node.hpp"
#include "Input.hpp"
#include "Display.hpp"
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Recorder.hpp"
#include "Sprite.hpp"
#include "extension.hpp"
#include "Sprite.hpp"
struct FramerateIndicator : Sprite
{

View File

@ -1,3 +1,6 @@
#include "extension.hpp"
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Input.hpp"
std::string Input::any = "any";

View File

@ -3,7 +3,6 @@
#include <string>
#include <map>
#include <list>
#include <functional>
#include <algorithm>

View File

@ -1,5 +1,10 @@
#include "Node.hpp"
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
#include "Input.hpp"
#include "Box.hpp"
#include "Game.hpp"
#include "Node.hpp"
Node::Node() : Node(NULL) {}
@ -14,6 +19,16 @@ void Node::set_parent(Node* other)
parent = other;
}
void Node::set_canvas(SDL_Texture* texture)
{
canvas = texture;
}
SDL_Texture* Node::get_canvas()
{
return canvas;
}
bool Node::is_active() const
{
return active;

View File

@ -1,24 +1,26 @@
#ifndef Node_h_
#define Node_h_
#include <string>
#include <iostream>
#include "glm/vec2.hpp"
#include "json/json.hpp"
#include "SDL.h"
#include "Box.hpp"
#include "filesystem.hpp"
struct Game;
struct Delegate;
struct Display;
struct Input;
struct Box;
struct Node
{
Node *parent;
SDL_Texture* canvas = nullptr;
bool active = true;
Node();
@ -27,6 +29,8 @@ struct Node
virtual void reset() { deactivate(); }
virtual void activate() { active = true; }
virtual void deactivate() { active = false; }
void set_canvas(SDL_Texture*);
SDL_Texture* get_canvas();
bool is_active() const;
nlohmann::json& get_configuration();
Delegate& get_delegate();
@ -49,7 +53,7 @@ struct Node
template<typename T = Game>
T* get_root()
{
if (parent == NULL)
if (parent == nullptr)
{
return static_cast<T*>(this);
}
@ -61,9 +65,4 @@ struct Node
};
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
#include "Input.hpp"
#endif

View File

@ -1,5 +1,7 @@
#include "Recorder.hpp"
#include "gif-h/gif.h"
#include "Game.hpp"
#include "extension.hpp"
#include "Recorder.hpp"
Recorder::Recorder(Node* parent) : Node(parent)
{

View File

@ -1,6 +1,8 @@
#ifndef Recorder_h_
#define Recorder_h_
#include <list>
#include <vector>
#include <sstream>
#include <string>
#include <thread>
@ -13,13 +15,11 @@
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/ext.hpp"
#include "json/json.hpp"
#include "filesystem.hpp"
#include "Node.hpp"
#include "Animation.hpp"
#include "extension.hpp"
struct Stash
{
@ -68,6 +68,4 @@ struct Recorder : Node
void process_audio(void*, Uint8*, int);
#include "Game.hpp"
#endif

View File

@ -1,3 +1,6 @@
#include <algorithm>
#include <stdexcept>
#include "Pixels.hpp"
#include "Game.hpp"
#include "extension.hpp"
@ -58,6 +61,10 @@ void Sprite::load()
{
load_file(path);
}
for (Child& child : children)
{
child.sprite.load();
}
}
void Sprite::load_file(fs::path path)
@ -239,16 +246,31 @@ void Sprite::advance_frame()
void Sprite::hide()
{
hidden = true;
for (Child& child : children)
{
child.sprite.hide();
}
}
void Sprite::unhide()
{
hidden = false;
for (Child& child : children)
{
child.sprite.unhide();
}
}
void Sprite::toggle_hidden()
{
hidden = !hidden;
if (is_hidden())
{
hide();
}
else
{
unhide();
}
}
bool Sprite::is_hidden() const
@ -407,6 +429,11 @@ void Sprite::set_nw(const glm::vec2& nw)
move(nw - get_nw());
}
void Sprite::set_north(const glm::vec2& north)
{
move(north - get_north());
}
void Sprite::set_ne(const glm::vec2& ne)
{
move(ne - get_ne());
@ -670,6 +697,7 @@ bool Sprite::collide(const Sprite& sprite, bool precise, Box* overlap, bool all,
{
SDL_Texture* other_sprite_collision_check_texture = nullptr;
int limit;
bool collision = false;
if (all_other)
{
limit = sprite.get_boxes().size();
@ -694,10 +722,15 @@ bool Sprite::collide(const Sprite& sprite, bool precise, Box* overlap, bool all,
}
if (collide(sprite.get_box(ii), precise, overlap, all, other_sprite_collision_check_texture))
{
return true;
collision = true;
break;
}
}
return false;
if (sprite.get_scale() != 1)
{
SDL_DestroyTexture(other_sprite_collision_check_texture);
}
return collision;
}
bool Sprite::collide(const Sprite& sprite, Box& overlap, bool precise, bool all, bool all_other) const
@ -705,6 +738,15 @@ bool Sprite::collide(const Sprite& sprite, Box& overlap, bool precise, bool all,
return collide(sprite, precise, &overlap, all, all_other);
}
void Sprite::wipe()
{
wipe_animation.play();
for (Child& child : children)
{
child.sprite.wipe();
}
}
void Sprite::advance_wipe_frame()
{
wipe_index += wipe_increment;
@ -746,6 +788,64 @@ void Sprite::reset_wipe_index()
}
}
Sprite& Sprite::insert_child(std::string name, std::list<Child>::iterator position)
{
children.emplace(position, name, this);
return get_child(name);
}
Sprite& Sprite::insert_child(std::string name, std::string before)
{
return insert_child(name, std::find(children.begin(), children.end(), before));
}
Sprite& Sprite::insert_child(std::string name, int index)
{
auto position = children.begin();
for (int ii = 0; position != children.end(); ii++, position++)
{
if (ii == index)
{
break;
}
}
return insert_child(name, position);
}
Sprite& Sprite::insert_child(std::string name)
{
return insert_child(name, children.size());
}
Sprite& Sprite::get_child(std::string name)
{
auto position = std::find(children.begin(), children.end(), name);
if (position == children.end())
{
throw std::runtime_error("child not found");
}
return position->sprite;
}
bool Sprite::has_child(std::string name) const
{
return std::find(children.begin(), children.end(), name) != children.end();
}
void Sprite::remove_child(std::string name)
{
auto position = std::find(children.begin(), children.end(), name);
if (position != children.end())
{
children.erase(position);
}
}
void Sprite::set_draw_children_on_frame(bool on_frame)
{
draw_children_on_frame = on_frame;
}
void Sprite::update()
{
if (active)
@ -757,19 +857,20 @@ void Sprite::update()
frame_animation.update();
blink_animation.update();
wipe_animation.update();
toggle_hidden_animation.update();
if (is_loaded() && !is_hidden() && get_current_frameset().get_frame_count())
{
SDL_Texture* texture = get_current_frame();
SDL_Renderer* renderer = get_root()->renderer;
SDL_SetTextureAlphaMod(texture, alpha_mod);
SDL_SetTextureColorMod(texture, color_mod.r, color_mod.g, color_mod.b);
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderTarget(renderer, get_canvas());
if (wrap.x || wrap.y)
{
SDL_Rect wrap_frame_rect = wrap_frame;
SDL_RenderSetClipRect(renderer, &wrap_frame_rect);
}
for (auto box_ii = 0; box_ii < static_cast<int>(boxes.size()); box_ii++)
for (std::size_t box_ii = 0; box_ii < boxes.size(); box_ii++)
{
if (!wipe_animation.is_playing())
{
@ -779,7 +880,7 @@ void Sprite::update()
{
for (const Box& blind : get_current_wipe_blinds())
{
float bottom_save = std::round(blind.get_bottom());
bottom_save = std::round(blind.get_bottom());
subsection = blind;
subsection.y += bottom_save - (subsection.y + subsection.h);
subsection_destination = subsection;
@ -787,10 +888,10 @@ void Sprite::update()
subsection_destination.y += get_top();
if (get_scale() != 1)
{
Box full_size = blind;
full_size.set_nw(full_size.get_nw() / get_scale());
full_size.set_size(full_size.get_size() / get_scale());
subsection = full_size;
unscaled_blind = blind;
unscaled_blind.set_nw(unscaled_blind.get_nw() / get_scale());
unscaled_blind.set_size(unscaled_blind.get_size() / get_scale());
subsection = unscaled_blind;
}
SDL_RenderCopy(renderer, texture, &subsection, &subsection_destination);
}
@ -800,6 +901,24 @@ void Sprite::update()
{
SDL_RenderSetClipRect(renderer, nullptr);
}
for (Child& child : children)
{
if (draw_children_on_frame)
{
child.sprite.set_canvas(texture);
}
else
{
child.sprite.set_canvas(get_canvas());
child_relative_position = child.sprite.get_nw();
child.sprite.move(get_nw());
}
child.sprite.update();
if (!draw_children_on_frame)
{
child.sprite.set_nw(child_relative_position);
}
}
}
}
}
@ -823,14 +942,6 @@ void Frameset::add_frame_indicies(int index)
order.push_back(index);
}
void Frameset::add_frame_indicies(const std::vector<int>& indicies)
{
for (const int& index : indicies)
{
add_frame_indicies(index);
}
}
void Frameset::set_frame_length(float length)
{
frame_length = length;

View File

@ -7,9 +7,10 @@
#include <sstream>
#include <algorithm>
#include <utility>
#include <list>
#include <SDL.h>
#include <SDL_image.h>
#include "SDL.h"
#include "SDL_image.h"
#include "Node.hpp"
#include "Box.hpp"
@ -22,27 +23,28 @@ struct Frameset;
struct Sprite : Node
{
struct Child;
std::vector<SDL_Texture*> frames;
std::vector<fs::path> frame_paths;
std::vector<Box> boxes = {{{0, 0}, {0, 0}}};
Animation frame_animation = Animation(&Sprite::advance_frame, this),
blink_animation = Animation(&Sprite::toggle_hidden, this, 500),
wipe_animation = Animation(&Sprite::advance_wipe_frame, this, 40);
bool hidden = false;
glm::vec2 step = {0, 0};
float scale = 1;
wipe_animation = Animation(&Sprite::advance_wipe_frame, this, 40),
toggle_hidden_animation = Animation(&Sprite::toggle_hidden, this);
glm::vec2 step = {0, 0}, child_relative_position;
float scale = 1.0f, bottom_save;
std::string scale_quality = "nearest";
std::uint8_t alpha_mod = 255;
SDL_Color color_mod = {255, 255, 255, 255};
std::map<std::string, Frameset> framesets;
std::string current_frameset_name;
glm::bvec2 wrap = {false, false};
int texture_access = SDL_TEXTUREACCESS_TARGET;
int wipe_index = 0, wipe_increment = -1;
Box wrap_frame;
bool leave_memory_allocated = false;
int texture_access = SDL_TEXTUREACCESS_TARGET, wipe_index = 0, wipe_increment = -1;
Box wrap_frame, unscaled_blind;
bool leave_memory_allocated = false, hidden = false, draw_children_on_frame = true;
std::vector<std::vector<Box>> wipe_blinds;
SDL_Rect subsection, subsection_destination;
std::list<Child> children = {};
Sprite();
Sprite(Node*);
@ -56,7 +58,7 @@ struct Sprite : Node
const std::vector<SDL_Texture*>& get_frames() const;
Frameset& get_all_frames_frameset();
Frameset& add_frameset(std::string);
Frameset& set_frameset(std::string);
virtual Frameset& set_frameset(std::string);
Frameset& get_current_frameset();
void set_frame_length(float);
const Frameset& get_current_frameset() const;
@ -105,6 +107,7 @@ struct Sprite : Node
void set_center_x(float);
void set_center_y(float);
void set_nw(const glm::vec2&);
void set_north(const glm::vec2&);
void set_ne(const glm::vec2&);
void set_se(const glm::vec2&);
void set_south(const glm::vec2&);
@ -123,10 +126,19 @@ struct Sprite : Node
bool collide(const Box&, Box&, bool = false, bool = false) const;
bool collide(const Sprite&, bool = false, Box* = NULL, bool = false, bool = false) const;
bool collide(const Sprite&, Box&, bool = false, bool = false, bool = false) const;
void wipe();
void advance_wipe_frame();
const std::vector<Box>& get_current_wipe_blinds();
void reverse_wipe_direction();
void reset_wipe_index();
Sprite& insert_child(std::string, std::list<Child>::iterator);
Sprite& insert_child(std::string, std::string);
Sprite& insert_child(std::string, int);
Sprite& insert_child(std::string);
Sprite& get_child(std::string);
bool has_child(std::string) const;
void remove_child(std::string);
void set_draw_children_on_frame(bool);
virtual void update();
void set_to_leave_memory_allocated();
void set_to_deallocate_memory();
@ -135,6 +147,19 @@ struct Sprite : Node
};
struct Sprite::Child
{
std::string name;
Sprite sprite;
Child(std::string name, Node* parent) : name(name), sprite(Sprite(parent)) {}
inline bool operator==(const std::string& name) const
{
return this->name == name;
}
};
struct Frameset
{
@ -148,7 +173,6 @@ struct Frameset
Frameset();
Frameset(Sprite*);
void add_frame_indicies(int);
void add_frame_indicies(const std::vector<int>&);
void set_frame_length(float);
float get_frame_length() const;
void reset();
@ -166,6 +190,15 @@ struct Frameset
int get_frame_count() const;
void reverse();
template <typename N>
void add_frame_indicies(const std::vector<N>& indicies)
{
for (const N& index : indicies)
{
add_frame_indicies(index);
}
}
};
#endif

View File

@ -15,6 +15,24 @@ Box sfw::get_texture_box(SDL_Texture* texture)
return Box(glm::vec2(0, 0), glm::vec2(width, height));
}
glm::vec2 sfw::fit_and_preserve_aspect(glm::vec2 inner, glm::vec2 outer)
{
glm::vec2 delta = inner - outer;
float aspect = inner.x / inner.y;
glm::vec2 fit;
if (delta.x > delta.y)
{
fit.x = outer.x;
fit.y = fit.x / aspect;
}
else
{
fit.y = outer.y;
fit.x = fit.y * aspect;
}
return fit;
}
std::vector<std::vector<Box>> sfw::get_blinds_boxes(glm::vec2 size, float step, int count)
{
std::vector<Box> blinds;

View File

@ -35,6 +35,7 @@ namespace sfw
void set_magnitude(glm::vec2&, float);
Box get_texture_box(SDL_Texture*);
glm::vec2 fit_and_preserve_aspect(glm::vec2, glm::vec2);
std::vector<std::vector<Box>> get_blinds_boxes(glm::vec2, float = 0.05f, int = 4);
void populate_pixel_2d_array(SDL_Renderer*, SDL_Texture*, std::vector<std::vector<SDL_Color>>&);
void populate_pixel_2d_array(SDL_Renderer*, SDL_Texture*, std::vector<std::vector<SDL_Color>>&, const Box&);