- add function for wrapping an arbitrary point or curve into an arbitrary clip space
- remove custom mod functions in favor of glm::mod - deactivate recorder object during game construction after full config is loaded
This commit is contained in:
parent
824efcc71f
commit
1ca956b5ac
|
@ -145,17 +145,7 @@ namespace sb
|
|||
* Construct a new Attributes object with vertices set to the vertices contained in this vector
|
||||
*/
|
||||
template<typename Type>
|
||||
Attributes(const std::vector<Type>& vertices) : vertices(vertices)
|
||||
{
|
||||
/* debug message */
|
||||
std::ostringstream message;
|
||||
message << "added vertex ";
|
||||
for (const Type& vertex : vertices)
|
||||
{
|
||||
message << vertex << " ";
|
||||
}
|
||||
sb::Log::log(message, sb::Log::DEBUG);
|
||||
}
|
||||
Attributes(const std::vector<Type>& vertices) : vertices(vertices) {}
|
||||
|
||||
/*!
|
||||
* Add a vertex. The vertex can be any of the variant types.
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace sb
|
||||
|
@ -50,13 +55,13 @@ namespace sb
|
|||
template<typename Container>
|
||||
void previous(const Container& container)
|
||||
{
|
||||
offset = sb::mod(--offset, container.size());
|
||||
offset = glm::mod(--offset, container.size());
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
void increment(const Container& container, int amount)
|
||||
{
|
||||
offset = sb::mod(offset + amount, container.size());
|
||||
offset = glm::mod(offset + amount, container.size());
|
||||
}
|
||||
|
||||
void beginning()
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
/* /\ +------------------------------------------------------+
|
||||
* ____/ \____ /| - Open source game framework licensed to freely use, |
|
||||
* \ / / | copy, modify and sell without restriction |
|
||||
* +--\ ^__^ /--+ | |
|
||||
* | ~/ \~ | | - created for <https://foam.shampoo.ooo> |
|
||||
* | ~~~~~~~~~~~~ | +------------------------------------------------------+
|
||||
* | SPACE ~~~~~ | /
|
||||
* | ~~~~~~~ BOX |/
|
||||
* +--------------+
|
||||
*
|
||||
* Connection objects contain a binary state of either on (connected) or off (not connected). When their state
|
||||
* is changed, an optional user supplied function corresponding to the state change is run automatically.
|
||||
*
|
||||
* The functions each have the same return type, number of arguments, and argument types determined by the
|
||||
* template arguments.
|
||||
*
|
||||
* By default, the state must change in order for a callback to be triggered. To allow repeat calls to
|
||||
* trigger a callback, the
|
||||
*
|
||||
* Original test code:
|
||||
*
|
||||
* Connection<> connection_d(std::bind(&Game::print_frame_length_history, this));
|
||||
* connection_d.toggle();
|
||||
* Connection<int, int, int> connection_f {
|
||||
* std::function<int(int, int)>(&sb::mod), std::function<int(int, int)>(&sb::mod) };
|
||||
* Connection<> connection_g = connection_d;
|
||||
* connection_g.toggle();
|
||||
* connection_g.disconnect();
|
||||
* int result;
|
||||
* result = connection_f.connect(3, 5);
|
||||
* std::cout << result << " ";
|
||||
* std::cout << connection_f.disconnect(20, 6) << " ";
|
||||
* result = connection_f.toggle(800, 120);
|
||||
* std::cout << result << std::endl;
|
||||
* result = connection_f.connect(111, 44);
|
||||
* std::cout << result << std::endl;
|
||||
*/
|
||||
/* +------------------------------------------------------+
|
||||
____/ \____ /| - Open source game framework licensed to freely use, |
|
||||
\ / / | copy, modify and sell without restriction |
|
||||
+--\ ^__^ /--+ | |
|
||||
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
|
||||
| ~~~~~~~~~~~~ | +------------------------------------------------------+
|
||||
| SPACE ~~~~~ | /
|
||||
| ~~~~~~~ BOX |/
|
||||
+--------------+
|
||||
|
||||
Connection objects contain a binary state of either on (connected) or off (not connected). When their state
|
||||
is changed, an optional user supplied function corresponding to the state change is run automatically.
|
||||
|
||||
The functions each have the same return type, number of arguments, and argument types determined by the
|
||||
template arguments.
|
||||
|
||||
By default, the state must change in order for a callback to be triggered. To allow repeat calls to
|
||||
trigger a callback, the
|
||||
|
||||
Original test code:
|
||||
|
||||
Connection<> connection_d(std::bind(&Game::print_frame_length_history, this));
|
||||
connection_d.toggle();
|
||||
Connection<int, int, int> connection_f {
|
||||
std::function<int(int, int)>(&glm::mod), std::function<int(int, int)>(&glm::mod) };
|
||||
Connection<> connection_g = connection_d;
|
||||
connection_g.toggle();
|
||||
connection_g.disconnect();
|
||||
int result;
|
||||
result = connection_f.connect(3, 5);
|
||||
std::cout << result << " ";
|
||||
std::cout << connection_f.disconnect(20, 6) << " ";
|
||||
result = connection_f.toggle(800, 120);
|
||||
std::cout << result << std::endl;
|
||||
result = connection_f.connect(111, 44);
|
||||
std::cout << result << std::endl;
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
|
|
@ -36,6 +36,12 @@ Game::Game()
|
|||
SDL_LogSetPriority(sb::Log::DEFAULT_CATEGORY, SDL_LOG_PRIORITY_INFO);
|
||||
}
|
||||
|
||||
/* If recording is disabled by configuration, deactive it. */
|
||||
if (!configuration()["recording"]["enabled"])
|
||||
{
|
||||
deactivate();
|
||||
}
|
||||
|
||||
/* Log the current working directory as seen by std::filesystem */
|
||||
std::ostringstream log_message;
|
||||
log_message << "Current path as seen by std::filesystem is " << std::filesystem::current_path();
|
||||
|
|
|
@ -11,11 +11,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
|
||||
#include "Box.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "extension.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "math.hpp"
|
||||
|
||||
class Sprite;
|
||||
|
||||
|
@ -48,11 +53,11 @@ struct Pixels
|
|||
std::uint8_t* access = static_cast<std::uint8_t*>(source);
|
||||
if (x < 0 || x >= rect.w)
|
||||
{
|
||||
x = sb::mod(x, static_cast<int>(rect.w));
|
||||
x = glm::mod(x, static_cast<int>(rect.w));
|
||||
}
|
||||
if (y < 0 || y >= rect.y)
|
||||
{
|
||||
y = sb::mod(y, static_cast<int>(rect.h));
|
||||
y = glm::mod(y, static_cast<int>(rect.h));
|
||||
}
|
||||
return reinterpret_cast<T>(access + y * get_bytes_per_row() + x * format->BytesPerPixel);
|
||||
}
|
||||
|
|
|
@ -11,10 +11,6 @@ Recorder::Recorder(Node* parent) : Node(parent)
|
|||
get_delegate().subscribe(&Recorder::respond, this);
|
||||
animation.play();
|
||||
Mix_SetPostMix(Recorder::process_audio, this);
|
||||
if (!configuration()["recording"]["enabled"])
|
||||
{
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns length of a recorded video frame in seconds. Defaults to the frame length of the game if this hasn't
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace sb
|
||||
|
@ -51,12 +56,12 @@ namespace sb
|
|||
|
||||
void previous()
|
||||
{
|
||||
offset = sb::mod(--offset, container.size());
|
||||
offset = glm::mod(--offset, container.size());
|
||||
}
|
||||
|
||||
void increment(int amount)
|
||||
{
|
||||
offset = sb::mod(offset + amount, container.size());
|
||||
offset = glm::mod(offset + amount, container.size());
|
||||
}
|
||||
|
||||
void beginning()
|
||||
|
|
|
@ -209,7 +209,7 @@ std::vector<SDL_Texture*> sb::get_portal_frames(
|
|||
for (int ellipse_ii = 0, y = max_y; y > y_margin - 3; ellipse_ii++, y -= dy)
|
||||
{
|
||||
color.a = y / max_y * 255.0f;
|
||||
color.hsv(hues[mod(ellipse_ii - frame_ii, count)]);
|
||||
color.hsv(hues[glm::mod(ellipse_ii - frame_ii, count)]);
|
||||
aaFilledEllipseRGBA(renderer, size.x / 2, y, size.x / 2, y_margin - 3, color.r, color.g, color.b, color.a);
|
||||
}
|
||||
frames.push_back(frame);
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "glm/trigonometric.hpp"
|
||||
#include "glm/vec2.hpp"
|
||||
#include "glm/gtx/vector_angle.hpp"
|
||||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
#include "json/json.hpp"
|
||||
#include "sdl2-gfx/SDL2_gfxPrimitives.h"
|
||||
#include "Box.hpp"
|
||||
|
|
118
src/math.hpp
118
src/math.hpp
|
@ -49,6 +49,7 @@ Should print,
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
/* GLM */
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
|
@ -113,4 +114,121 @@ namespace sb
|
|||
* @param resolution number of points that will be in the computed curve
|
||||
*/
|
||||
std::vector<glm::vec2> bezier(const std::vector<glm::vec2>& vertices, int resolution = 30);
|
||||
|
||||
/*!
|
||||
* Wrap a point so that it is translated into the clip space as if it entered the opposite side of the clip upon exiting it.
|
||||
*
|
||||
* Running the same algorithm with PyGLM,
|
||||
*
|
||||
* In [42]: V = glm.vec3(1.5, 8.88, 3.2)
|
||||
* In [43]: C0 = glm.vec3(-1.0, -1.0, -1.0)
|
||||
* In [44]: C1 = glm.vec3(1.0, 1.0, 1.0)
|
||||
* In [45]: Vw = ((V - C1) % (C1 - C0)) + C0
|
||||
* In [46]: Vw
|
||||
* Out[46]: vec3( -0.5, 0.88, -0.8 )
|
||||
*
|
||||
* @param vertex point to wrap
|
||||
* @param clip_lower the lower corner of the clip space to wrap into
|
||||
* @param clip_upper the upper corner of the clip space to wrap into
|
||||
* @return wrapped point
|
||||
*/
|
||||
template<glm::length_t dimensions, typename Type, glm::qualifier qualifier>
|
||||
glm::vec<dimensions, Type, qualifier> wrap_point(const glm::vec<dimensions, Type, qualifier>& vertex,
|
||||
const glm::vec<dimensions, Type, qualifier>& clip_lower,
|
||||
const glm::vec<dimensions, Type, qualifier>& clip_upper)
|
||||
{
|
||||
return glm::mod(vertex - clip_upper, clip_upper - clip_lower) + clip_lower;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Wrap a curve so that all the points on the curve are translated into the given clip space as if they entered the opposite
|
||||
* side of the clip upon exiting it. The curve is traversed from start to end. At wrap points, the curve splits, creating two
|
||||
* disjoint segments. All the segments generated are returned in a vector.
|
||||
*
|
||||
* When a curve splits, an unwrapped version of the point at the split is added to the first segment, and an unwrapped version
|
||||
* of the point preceeding the split is added to the start of the second segment (technically, the points are still wrapped but
|
||||
* offset by a sector to match with their respective segments). This is done to allow the curve to be drawn up to the edge of
|
||||
* the clip (and past it).
|
||||
*
|
||||
* @warning Because this causes points to lie outside the clip at the edges, this function may change in the future to create
|
||||
* new points that intersect exactly with the edge of the clip.
|
||||
*
|
||||
* Example, testing 2D and 3D vertices,
|
||||
*
|
||||
* std::vector<glm::vec3> test = {
|
||||
* {0.0f, 0.5f, 3.0f}, {0.5f, 0.5f, 3.5f}, {1.0f, 0.5f, 3.2f}, {1.5f, 0.75f, 2.8f}, {2.0f, 1.25f, 3.5f}, {3.0f, 2.0f, 4.5f}};
|
||||
* std::cout << test << " -> " << sb::wrap_curve(test, {-2.0f, -1.0f, 3.0f}, {2.0f, 1.0f, 4.0f}) << std::endl;
|
||||
* std::vector<glm::vec2> test2 = {{0.0f, 0.5f}, {0.5f, 0.5f}, {1.0f, 0.5f}, {1.5f, 0.75f}, {2.0f, 1.25f}, {3.0f, 2.0f}};
|
||||
* std::cout << test2 << " -> " << sb::wrap_curve(test2, {-(16.0f / 9.0f), -1.0f}, {16.0f / 9.0f, 1.0f}) << std::endl;
|
||||
*
|
||||
* Prints,
|
||||
*
|
||||
* { {0, 0.5, 3} {0.5, 0.5, 3.5} {1, 0.5, 3.2} {1.5, 0.75, 2.8} {2, 1.25, 3.5} {3, 2, 4.5} } -> { { \
|
||||
* {0, 0.5, 3} {0.5, 0.5, 3.5} {1, 0.5, 3.2} {1.5, 0.75, 2.8} } { {1, 0.5, 4.2} {1.5, 0.75, 3.8} {2, 1.25, 4.5} } \
|
||||
* { {-2.5, -1.25, 2.8} {-2, -0.75, 3.5} {-1, 0, 4.5} } { {-2, -0.75, 2.5} {-1, 0, 3.5} } }
|
||||
* { {0, 0.5} {0.5, 0.5} {1, 0.5} {1.5, 0.75} {2, 1.25} {3, 2} } -> { { {0, 0.5} {0.5, 0.5} {1, 0.5} {1.5, 0.75} {2, 1.25} } \
|
||||
* { {-2.05556, -1.25} {-1.55556, -0.75} {-0.555556, 0} } }
|
||||
*
|
||||
* @param vertices a vector of vertices of any dimension defining a curve
|
||||
* @param clip_lower the lower corner of the clip space to wrap into
|
||||
* @param clip_upper the upper corner of the clip space to wrap into
|
||||
* @return a vector of curves wrapped to fit
|
||||
*/
|
||||
template<glm::length_t dimensions, typename Type, glm::qualifier qualifier>
|
||||
std::vector<std::vector<glm::vec<dimensions, Type, qualifier>>> wrap_curve(const std::vector<glm::vec<dimensions, Type, qualifier>>& vertices,
|
||||
const glm::vec<dimensions, Type, qualifier>& clip_lower,
|
||||
const glm::vec<dimensions, Type, qualifier>& clip_upper)
|
||||
{
|
||||
/* Create vector of vectors to store the segments. */
|
||||
std::vector<std::vector<glm::vec<dimensions, Type, qualifier>>> segments = {{}};
|
||||
|
||||
/* Create vertices for tracking which sector the unwrapped point falls in. Which sector a vertex falls in represents how many clip-sized
|
||||
* spaces away from the target clip space a vertex is. When a vertex is in a different sector than the previous vertex, the wrapped
|
||||
* curve needs to split into a new disjoint segment. */
|
||||
glm::vec<dimensions, Type, qualifier> sector, sector_prev;
|
||||
|
||||
/* Create vertices for per-vertex wrapping operations. */
|
||||
glm::vec<dimensions, Type, qualifier> vertex, vertex_prev, wrapped;
|
||||
|
||||
/* Get the difference between upper and lower clips to define the range of a clip as a vector. */
|
||||
glm::vec<dimensions, Type, qualifier> clip_delta = clip_upper - clip_lower;
|
||||
|
||||
/* If any clip dimension is zero, throw an error because it will cause NaN to appear in the output. */
|
||||
for (glm::length_t ii = 0; ii < clip_delta.length(); ii++)
|
||||
{
|
||||
if (clip_delta[ii] == 0)
|
||||
{
|
||||
throw std::invalid_argument("Submitted clip area contains a dimension of size zero.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over all input vertices, wrapping each one. */
|
||||
for (std::size_t ii = 0; ii < vertices.size(); ii++)
|
||||
{
|
||||
vertex = vertices[ii];
|
||||
sector = glm::floor((vertex - clip_lower) / clip_delta);
|
||||
wrapped = wrap_point(vertex, clip_lower, clip_upper);
|
||||
|
||||
/* A mismatch in sector means the most recent vertex wrapped, so add a new disjoint segment. */
|
||||
if (ii > 0 && sector != sector_prev)
|
||||
{
|
||||
/* Use the difference in sector to calculate an unwrapped version of the point to extend the end of the segment to the edge of the clip
|
||||
* and past. */
|
||||
segments.back().push_back(wrapped + (sector - sector_prev) * clip_delta);
|
||||
|
||||
/* Add a new disjoint segment. */
|
||||
segments.push_back({});
|
||||
|
||||
/* Use the difference in sector to calculate an unwrapped version of the previous vertex so that the new segment begins slightly
|
||||
* outside of the clip. */
|
||||
segments.back().push_back(wrap_point(vertex_prev, clip_lower, clip_upper) + (sector_prev - sector) * clip_delta);
|
||||
}
|
||||
|
||||
segments.back().push_back(wrapped);
|
||||
sector_prev = sector;
|
||||
vertex_prev = vertex;
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
#include "utility.hpp"
|
||||
|
||||
/* Modulus that handles negative arguments */
|
||||
int sb::mod(int a, int b)
|
||||
{
|
||||
return (b + (a % b)) % b;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
/* /\ +--------------------------------------------------------------+
|
||||
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
|
||||
\ / / | copy, modify and sell without restriction |
|
||||
+--\ ^__^ /--+ | |
|
||||
| ~/ \~ | | - originally created at [http://nugget.fun] |
|
||||
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
|
||||
| SPACE ~~~~~ | /
|
||||
| ~~~~~~~ BOX |/
|
||||
+--------------+
|
||||
|
||||
[utility.hpp]
|
||||
|
||||
For lightweight utility functions that extend C++ functionality and don't depend on
|
||||
any [SPACE BOX] specific functions.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace sb
|
||||
{
|
||||
int mod(int, int);
|
||||
}
|
Loading…
Reference in New Issue