Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • gamedev/fggl
  • onuralpsezer/fggl
2 results
Show changes
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_INPUT_MOUSE_HPP
#define FGGL_INPUT_MOUSE_HPP
#include <string>
#include <array>
#include <bitset>
#include "fggl/math/types.hpp"
namespace fggl::input {
enum class MouseButton {
LEFT = 0,
MIDDLE = 2,
RIGHT = 1,
EXTRA_1 = 3,
EXTRA_2 = 4,
EXTRA_3 = 5,
EXTRA_4 = 6,
EXTRA_5 = 7
};
enum class MouseAxis {
X,
Y,
SCROLL_X,
SCROLL_Y
};
struct MouseButtonRecord {
MouseButton id;
const char name[15];
};
struct MouseAxisRecord {
MouseAxis id;
const char name[15];
};
constexpr std::array<MouseButtonRecord, 8> MouseButtons = {{
{MouseButton::LEFT, "Left"},
{MouseButton::MIDDLE, "Middle"},
{MouseButton::RIGHT, "Right"},
{MouseButton::EXTRA_1, "Extra 1"},
{MouseButton::EXTRA_2, "Extra 2"},
{MouseButton::EXTRA_3, "Extra 3"},
{MouseButton::EXTRA_4, "Extra 4"},
{MouseButton::EXTRA_5, "Extra 5"},
}};
constexpr std::array<MouseAxisRecord, 4> MouseAxes = {{
{MouseAxis::X, "Left/Right"},
{MouseAxis::Y, "Up/Down"},
{MouseAxis::SCROLL_X, "Scroll X"},
{MouseAxis::SCROLL_Y, "Scroll Y"}
}};
struct MouseState {
float axis[MouseAxes.size()];
std::bitset<MouseButtons.size()> buttons;
void operator=(const MouseState &rhs);
};
class MouseInput {
public:
MouseInput() = default;
MouseInput(const MouseInput &rhs) = delete;
void operator=(const MouseInput &rhs) = delete;
inline void frame(float /*dt*/) {
m_prev = m_curr;
}
inline void axis(MouseAxis axis, float value) {
m_curr.axis[(int) axis] = value;
}
inline float axis(MouseAxis axis) const {
return m_curr.axis[(int) axis];
}
inline float axisDelta(MouseAxis axis) const {
return m_curr.axis[(int) axis] - m_prev.axis[(int) axis];
}
inline void button(MouseButton btn, bool state) {
m_curr.buttons[(int) btn] = state;
}
inline bool down(MouseButton btn) const {
return m_curr.buttons[(int) btn];
}
inline bool downPrev(MouseButton btn) const {
return m_prev.buttons[(int) btn];
}
inline bool pressed(MouseButton btn) const {
return m_curr.buttons[(int) btn] && !m_prev.buttons[(int) btn];
}
inline bool released(MouseButton btn) const {
return !m_curr.buttons[(int) btn] && m_prev.buttons[(int) btn];
}
private:
MouseState m_curr;
MouseState m_prev;
};
// helpers
inline math::vec2 mouse_axis(const MouseInput& input) {
return { input.axis(MouseAxis::X), input.axis(MouseAxis::Y) };
}
inline math::vec2 mouse_axis_delta(const MouseInput& input) {
return { input.axisDelta(MouseAxis::X), input.axisDelta(MouseAxis::Y) };
}
};
#endif
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 12/12/2021.
//
#ifndef FGGL_MATH_EASING_HPP
#define FGGL_MATH_EASING_HPP
#include <fggl/math/types.hpp>
#include <functional>
namespace fggl::math {
constexpr inline float lerp(float a, float b, float w) {
return (b - a) * w + a;
}
constexpr inline float scale(float in, float inMin, float inMax, float outMin, float outMax) {
return ((in - inMin) * (outMax - outMin)) / (inMax - inMin);
}
//
// Functions
//
using transformF = std::function<float(float)>;
inline float scaleFilter(float in, float inMin, float inMax, float outMin, float outMax, const transformF &filter) {
float out = in - inMin;
out /= (inMax - inMin);
out = filter(out);
out *= (outMax - outMin);
return out + outMin;
}
inline float mix(const transformF &funcA, const transformF &funcB, float weightB, float t) {
return ((1 - weightB) * funcA(t)) + (weightB * funcB(t));
}
inline float crossFade(transformF funcA, transformF funcB, float t) {
return ((1 - t) * funcA(t)) + (t * funcB(t));
}
//
// building blocks
//
inline float scale(transformF f, float t) {
return t * f(t);
}
inline float reverseScale(transformF f, float t) {
return (1 - t) * f(t);
}
constexpr inline float Arch2(float t) {
return t * (1 - t);
}
constexpr inline float BounceClampBottom(float t) {
return fabs(t);
}
constexpr inline float BounceClampTop(float t) {
return 1.f - fabs(1.f - t);
}
//
// Easing function library
// see Math for Game Programmers: Fast and Funky 1D Nonlinear Transformations, GDC 2015
//
constexpr inline float SmoothStart2(float t) {
return t * t;
}
constexpr inline float SmoothStart3(float t) {
return t * t * t;
}
constexpr inline float SmoothStart4(float t) {
return t * t * t * t;
}
constexpr inline float SmoothStart5(float t) {
return t * t * t * t * t;
}
constexpr inline float SmoothStop2(float t) {
const auto tFlip = 1 - t;
return 1 - (tFlip * tFlip);
}
constexpr inline float SmoothStop3(float t) {
const auto tFlip = 1 - t;
return 1 - (tFlip * tFlip);
}
constexpr inline float SmoothStop4(float t) {
const auto tFlip = 1 - t;
return 1 - (tFlip * tFlip * tFlip * tFlip);
}
constexpr inline float SmoothStop5(float t) {
const auto tFlip = 1 - t;
return 1 - (tFlip * tFlip * tFlip * tFlip * tFlip);
}
//
// Bezier curves
//
constexpr inline float NormalizedBezier3(float B, float C, float t) {
const float s = 1.f - t;
const float t2 = t * t;
const float s2 = s * s;
const float t3 = t2 * t;
return (3.f * B * s2 * t) + (3.f * C * s * t2) + t3;
}
}
#endif //FGGL_UTILS_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_MATH_FMATH_HPP
#define FGGL_MATH_FMATH_HPP
#include <cmath>
#include "fggl/math/vector.hpp"
namespace fggl::math {
/**
* A 4D floating-point vector.
*/
using vec4f = glm::vec4;
/**
* A 3D floating-point vector.
*/
using vec3f = glm::vec3;
/**
* A 2D floating-point vector.
*/
using vec2f = glm::vec2;
constexpr static const math::vec2f VEC2_ZERO{0.0F, 0.0F};
constexpr static const math::vec3f VEC3_ZERO{0.0F, 0.0F, 0.0F};
constexpr static const math::vec3f VEC3_ONES{1.0F, 1.0F, 1.0F};
/**
* return the remainder (modulo) of value / maximum.
*
* This will return a value in the range [0, maximum), the result will always be positive, even if passed a negative
* input.
*
* @param value the value to wrap.
* @param max the maximum value that it can take.
* @return the wrapped value
*/
inline float wrap(float value, float max) {
return fmodf(max + fmodf(value, max), max);
}
/**
* wrap value in range [min, max)
*
* @param value the value to be tested.
* @param min the minimum allowable value
* @param max the maximum allowable value
*/
inline float wrap(float value, float min, float max) {
if (min > max) {
std::swap(min, max);
};
value -= min;
float rangeSize = max - min;
return value - (rangeSize * std::floor(value / rangeSize)) + min;
}
/**
* Ensure that value is wrapped in the range [min, max].
* if the value is larger than max, return max.
* if the value is smaller than min, return min.
*
* @param value the value to be tested.
* @param min the minimum allowable value
* @param max the maximum allowable value
* @return value, if it is in the range [min, max], otherwise the bound that it is outside of.
*/
constexpr float clamp(float value, float min, float max) {
const float valueOrMin = value < min ? min : value;
return valueOrMin > max ? max : valueOrMin;
}
constexpr float lerpImprecise(float start, float end, float t) {
return start + t * (end - start);
}
constexpr float lerp(float start, float end, float t) {
return (1 - t) * start + t * end;
}
template<typename T>
[[nodiscard]]
constexpr T smooth_add(T first, T second, const float weight) {
const float other = 1 - weight;
return (first * other) + (second * weight);
}
} // namespace fggl::math
#endif //FGGL_MATH_FMATH_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 20/04/22.
//
#ifndef FGGL_MATH_IMATH_HPP
#define FGGL_MATH_IMATH_HPP
#include <cstdint>
namespace fggl::math {
// wrap value in range [0, max)
constexpr int wrap(int value, int max) {
if (value < 0)
return (value - 1) - (-1 - value) % value;
if (value >= max)
return value % max;
return value;
}
// wrap value in range [min, max)
constexpr int wrap(int value, int const min, int const max) {
int range = max - min + 1;
if (value < min) {
value += range * ((min - value) / range + 1);
}
return min + (value - min) % range;
}
constexpr int clamp(int value, int min, int max) {
const int i = value > max ? max : value;
return i < min ? min : value;
}
template<typename T>
constexpr T clampT(T value, T min, T max) {
const T i = value > max ? max : value;
return i < min ? min : value;
}
/**
* Calculate the sum of the first N positive integers.
*
* @param n the number to stop at
* @return sum(0 ... N)
*/
constexpr uint64_t calcSum(uint64_t n) {
return (n * (n + 1)) / 2;
}
/**
* Calculate the squared sum of the first N positive integers.
*
* @param n the number to stop at
* @return sum(0 ... N) * sum(0 ... N)
*/
constexpr uint64_t calcSumSquared(uint64_t n) {
return (n * (n + 1) * (2*n + 1)) / 6;
}
/**
* Calculate the cubed sum of the first N positive integers.
*
* @param n the number to stop at
* @return sum(0 ... N) * sum(0 ... N) * sum(0 ... N)
*/
constexpr uint64_t calcSumCubed(uint64_t n) {
return ((n * n) * ((n + 1) * (n + 1))) / 4;
}
} // namespace fggl::math
#endif //FGGL_MATH_IMATH_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_MATH_SHAPES_HPP
#define FGGL_MATH_SHAPES_HPP
#include "fggl/math/types.hpp"
#include <vector>
#include <array>
// based on https://gamemath.com/book/geomprims.html
namespace fggl::math::phs3d {
struct Line {
math::vec2 normal;
float d;
};
struct LineSegment {
math::vec3 start;
math::vec3 end;
};
struct Ray {
math::vec3 start;
math::vec3 length;
inline math::vec3 end() {
return start + length;
}
static Ray fromPos(math::vec3 start, math::vec3 end);
};
// nice bounding shapes
struct Sphere {
math::vec3 center;
float radius;
float volume() const;
float area() const;
};
struct AABB {
math::vec3 min;
math::vec3 max;
void add(const math::vec3 &p);
void emtpy();
void set(const AABB &other, const math::mat4 &m);
inline math::vec3 center() const {
return (min + max) / 2.0F;
}
inline math::vec3 size() const {
return max - min;
}
inline math::vec3 radius() const {
return max - center();
}
static AABB fromPoints(const std::vector<math::vec3> &points);
};
struct Plane {
glm::vec3 normal;
float d; // distance to origin
inline bool contains(const math::vec3 &point) {
return glm::dot(point, normal) == d;
}
inline float distance(const math::vec3 &q) {
return glm::dot(q, normal) - d;
}
static Plane fromPoints(const math::vec3, const math::vec3, const math::vec3);
static Plane bestFit(const std::vector<math::vec3> &points);
};
struct Barycentric {
std::array<float, 3> b;
bool inTriangle() {
return 0 <= b[0] && b[0] <= 1 &&
0 <= b[1] && b[1] <= 1 &&
0 <= b[2] && b[2] <= 1;
}
inline bool isLegal() const {
return (b[0] + b[1] + b[2]) == 1.0f;
}
};
constexpr float THIRD = 1.0F / 3.0F;
const Barycentric cGrav = {{THIRD, THIRD, THIRD}};
struct Triangle {
std::array<math::vec3, 3> v;
inline float l1() const {
return length(2, 1);
}
inline float l2() const {
return length(0, 2);
}
inline float l3() const {
return length(1, 0);
}
inline math::vec3 edge(int v1, int v2) const {
return v[v1] - v[v2];
}
inline float length(int a, int b) const {
return glm::length(edge(a, b));
}
inline float perimeter() const {
return length(3, 2) + length(1, 3) + length(2, 1);
}
inline float area() const {
return glm::length(glm::cross(edge(3, 2), edge(1, 3))) / 2;
}
inline math::vec3 cGrav() const {
return (v[0] + v[1] + v[2]) / 3.0f;
}
inline math::vec3 inCenter() const {
auto p = perimeter();
Barycentric bs{
l1() / p,
l2() / p,
l3() / p
};
return BarycentricToCart(bs);
}
inline float centerRadius() const {
return area() / perimeter();
}
// circle that passes through all three points = cirumcenter + circumraidus
inline math::vec3 circumcenter() {
// d1 = - e2 DOT e3
// d2 = - e3 DOT e1
// d3 = - e1 DOT e2
// C1 = d2 * d3
// C2 = d3 * d1
// C3 = d1 * d2
// c = c1 + c2 + c3
// c_2 = 2 * c
// bary{
// (c2 + c3 ) / c_2
// (c3 + c1 ) / c_2
// (c1 + c2 ) / c_2
// return BarycentricToCart(bary)
return glm::zero<vec3>();
}
inline float circumradius() {
// d1 = - e2 DOT e3
// d2 = - e3 DOT e1
// d3 = - e1 DOT e2
// C1 = d2 * d3
// C2 = d3 * d1
// C3 = d1 * d2
// c = c1 + c2 + c3
// c_2 = 2 * c
// return sqrt( (d1+d2) * (d2+d3) * ( d3 + d1 ) / c ) / 2
return 0.0F;
}
bool CartToBarycentric(const math::vec3 &cart, Barycentric &outVal);
bool CartToBarycentric2(const math::vec3 &cart, Barycentric &outVal);
math::vec3 BarycentricToCart(const Barycentric &p) const {
return v[0] * p.b[0] +
v[1] * p.b[1] +
v[2] * p.b[2];
}
};
} // namespace fggl::math::phys3d
#endif //FGGL_MATH_SHAPES_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 27/11/22.
//
#ifndef FGGL_MATH_STATS_HPP
#define FGGL_MATH_STATS_HPP
#include <cstdint>
#include <cmath>
namespace fggl::math {
class CumulativeAverage {
public:
inline void add(float item) {
m_current = ( item + (m_count * m_current) ) / (m_count + 1);
m_count++;
}
inline float average() {
return m_current;
}
private:
float m_current;
std::size_t m_count;
};
/**
* Useful Statistics class.
* ported to C++ from Piers' Java implementation.
*
* @tparam T
*/
template<typename T>
class Statistics {
public:
void add(T observation) {
m_count++;
m_sum += observation;
m_sumSquared += (observation * observation);
m_min = std::min(m_min, observation);
m_max = std::max(m_max, observation);
m_dirty = true;
}
inline T average() {
compute();
return m_average;
}
inline T average() const {
if ( m_dirty ) {
return m_sum / m_count;
}
return m_average;
}
inline T standardDeviation() {
compute();
return m_standardDiv;
}
inline T standardDeviation() const {
if ( !m_dirty ) {
return m_standardDiv;
}
T avg = average();
T num = m_sumSquared - (m_count * avg * avg);
return num < 0 ? 0 : sqrt( num / (m_count-1));
}
inline T standardError() {
compute();
return m_standardDiv / sqrt(m_count);
}
inline T standardError() const {
if ( !m_dirty ) {
return m_standardDiv / sqrt(m_count);
}
return standardDeviation() / sqrt(m_count);
}
inline T squareSum () const {
return m_sumSquared;
}
inline std::size_t count() const {
return m_count;
}
inline T sum() const {
return m_sum;
}
inline T min() const {
return m_min;
}
inline T max() const {
return m_max;
}
private:
T m_average{0};
T m_sum{0};
T m_sumSquared{0};
T m_standardDiv{0};
T m_min{0};
T m_max{0};
std::size_t m_count{0};
bool m_dirty{false};
void compute() {
if ( !m_dirty ) {
return;
}
m_average = m_sum / m_count;
T num = m_sumSquared - (m_count * m_average * m_average);
if ( num < 0 ) {
num = 0;
}
m_standardDiv = sqrt( num / (m_count-1) );
m_dirty = false;
}
};
using StatisticsF = Statistics<float>;
using StatisticsD = Statistics<double>;
} // namespace fggl::math
#endif //FGGL_MATH_STATS_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_MATH_TRIANGULATION_HPP
#define FGGL_MATH_TRIANGULATION_HPP
#define _USE_MATH_DEFINES
#include <cmath>
#include <fggl/math/types.hpp>
#include <fggl/data/model.hpp>
namespace fggl::math {
using Polygon = std::vector<math::vec2>;
using PolygonVertex = std::vector<data::Vertex2D>;
constexpr int POSITIVE = 1;
constexpr int NEGATIVE = -1;
constexpr int UNSET = 0;
/**
* Put an angle in the range [-PI, PI].
*/
inline float clampAngle(float radianAngle) {
if (radianAngle <= math::PI) {
return radianAngle + math::HALF_PI;
} else if (radianAngle > math::PI) {
return radianAngle - math::HALF_PI;
} else {
return radianAngle;
}
}
static void checkSign(float value, int &sign, int &firstSign, int &flips) {
if (value > 0) {
if (sign == UNSET) {
firstSign = POSITIVE;
} else if (sign < 0) {
flips++;
}
} else if (value < 0) {
if (sign == UNSET) {
firstSign = NEGATIVE;
} else if (sign > 0) {
flips++;
}
sign = NEGATIVE;
}
}
/**
* Check if a polygon is convex.
*
* see https://math.stackexchange.com/a/1745427
*/
static bool isConvex(const Polygon &polygon) {
if (polygon.size() < 3) {
return false;
}
const auto n = polygon.size();
auto wSign = UNSET;
auto xSign = UNSET;
auto xFirstSign = UNSET;
auto xFlips = 0;
auto ySign = UNSET;
auto yFirstSign = UNSET;
auto yFlips = 0;
auto curr = polygon[n - 1];
auto next = polygon[n];
for (auto &v : polygon) {
auto prev = curr;
curr = next;
next = v;
auto before = curr - prev;
auto after = next - curr;
checkSign(after.x, xSign, xFirstSign, xFlips);
if (xFlips > 2) {
return false;
}
checkSign(after.y, ySign, yFirstSign, yFlips);
if (yFlips > 2) {
return false;
}
auto w = before.x * after.y - after.x * before.y;
if (wSign == UNSET && w != 0) {
wSign = w;
} else if (wSign > 0 && w < 0) {
return false;
} else if (wSign < 0 && w > 0) {
return false;
}
}
if (xSign != UNSET && (xFirstSign != UNSET) && (xSign != xFirstSign)) {
xFlips += 1;
}
if (ySign != UNSET && (yFirstSign != UNSET) && (ySign != yFirstSign)) {
yFlips += 1;
}
if (xFlips != 2 || yFlips != 2) {
return false;
}
return true;
}
static data::Vertex2D pointToVertex(const math::vec2 &point) {
return data::Vertex2D{point, {1.0F, 1.0F, 1.0F}, {0.0F, 0.0F}};
}
/**
* Fast Triangulation for convex polygons.
*/
void fan_triangulation(const PolygonVertex &polygon, data::Mesh2D &mesh);
} // namespace fggl::util
#endif
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef FGGL_MATH_TYPES_HPP
#define FGGL_MATH_TYPES_HPP
#include <tuple>
#include <iostream>
#include "fggl/math/vector.hpp"
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/quaternion.hpp>
#include "fggl/math/fmath.hpp"
#include "fggl/util/guid.hpp"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif
namespace fggl::math {
constexpr float PI = M_PI;
constexpr float HALF_PI = M_PI_2;
constexpr float TAU = PI * 2;
using uint8 = std::uint8_t;
// math types (aliased for ease of use)
/**
* A 4D floating-point vector.
*/
using vec4 = glm::vec4;
/**
* A 4D signed integer vector.
*/
using vec4i = glm::ivec4;
/**
* A 4D unsigned integer vector.
*/
using vec4ui = glm::uvec4;
/**
* A 3D floating-point vector.
*/
using vec3 = glm::vec3;
/**
* A 3D integer vector.
*/
using vec3i = glm::ivec3;
/**
* A 3D unsigned integer vector.
*/
using vec3ui = glm::uvec3;
/**
* A 2D floating-point vector
*/
using vec2 = glm::vec2;
/**
* A 2D integer vector
*/
using vec2i = glm::ivec2;
/**
* a 2D unsigned integer vector
*/
using vec2ui = glm::uvec2;
using vec2b = glm::bvec2;
using vec3b = glm::bvec3;
using vec4b = glm::bvec4;
/**
* A 2x2 floating-point matrix.
*/
using mat2 = glm::mat2;
/**
* A 3x3 floating-point matrix.
*/
using mat3 = glm::mat3;
/**
* A 4x4 floating-point matrix.
*/
using mat4 = glm::mat4;
/**
* A quaternion.
*/
using quat = glm::quat;
constexpr static const math::mat4 IDENTITY_M4{1.0F};
constexpr static const math::quat IDENTITY_Q{1.0F, 0.0, 0.0, 0.0};
constexpr static const math::vec3 AXIS_X{1.0F, 0.0F, 0.0F};
constexpr static const math::vec3 AXIS_Y{0.0F, 1.0F, 0.0F};
constexpr static const math::vec3 AXIS_Z{0.0F, 0.0F, 1.0F};
constexpr auto minElm(vec3 a, vec3 b) -> vec3{
return {
a.x < b.x ? a.x : b.x,
a.y < b.y ? a.y : b.y,
a.z < b.z ? a.z : b.z
};
}
constexpr auto maxElm(vec3 a, vec3 b) -> vec3 {
return {
a.x > b.x ? a.x : b.x,
a.y > b.y ? a.y : b.y,
a.z > b.z ? a.z : b.z
};
}
// fastFloor from OpenSimplex2
inline int fastFloor(double x) {
int xi = (int) x;
return x < xi ? xi - 1 : xi;
}
/**
* Rescale a value between [min, max] into [0, 1].
*
* @param value the value to rescale
* @param min the minimum value of the original range
* @param max the maximum value of the original range
* @return the rescaled value, [0, 1]
*/
constexpr float rescale_norm(float value, float min, float max) {
return (value - min) / (max - min);
}
/**
* Rescale a value between [min, max] into [newMin, newMax].
*
* @param value the value to rescale
* @param min the minimum value of the original range
* @param max the maximum value of the original range
* @param newMin the new minimum value
* @param newMax the new maximum value
* @return the rescaled value, [newMin, newMax]
*/
constexpr float rescale_norm(float value, float min, float max, float newMin, float newMax) {
return newMin + ((value - min) * (newMax - newMin)) / (max - min);
}
/**
* Rescale a normalised device-coordinate value [-1, 1] into another range.
*
* @param value the value to rescale, [-1.0, 1.0]
* @param newMin the new minimum value
* @param newMax the new maximum value
* @return the rescaled value, [newMin, newMax]
*/
constexpr float rescale_ndc(float value, float newMin, float newMax) {
return rescale_norm(value, -1, 1, newMin, newMax);
}
/**
* Rescale a normalised value [0, 1] into another range.
*
* @param value the value to rescale
* @param newMin the new minimum value
* @param newMax the new maximum value
* @return the rescaled value, [newMin, newMax]
*/
constexpr float rescale_01(float value, float newMin, float newMax) {
return rescale_norm(value, 0, 1, newMin, newMax);
}
constexpr float recale_mean(float value, float avg, float max, float min) {
return (value - avg) / (max - min);
}
// reference vectors
constexpr vec3f UP{0.0f, 1.0f, 0.0f};
constexpr vec3f FORWARD{1.0f, 0.0f, 0.0f};
constexpr vec3f RIGHT{0.0f, 0.0f, 1.0f};
inline glm::mat4 modelMatrix(const vec3 offset, const quat rotation) {
return glm::translate(glm::mat4(1.0f), offset) * glm::toMat4(rotation);
}
inline glm::mat4 modelMatrix(glm::vec3 offset, glm::vec3 eulerAngles) {
return modelMatrix(offset, glm::quat(eulerAngles));
}
// FIXME: we have multiple definitions of rays in the codebase!
struct Ray {
vec3 origin;
vec3 direction;
};
struct Transform {
constexpr static const util::GUID guid = util::make_guid("Transform");
Transform() :
m_model(IDENTITY_M4),
m_origin(math::VEC3_ZERO),
m_euler(math::VEC3_ZERO),
m_scale(math::VEC3_ONES) {
}
// local reference vectors
[[nodiscard]]
inline vec3 up() const {
return vec4(UP, 1.0) * model();
}
[[nodiscard]]
inline vec3 forward() const {
return vec4(FORWARD, 1.0) * model();
}
[[nodiscard]]
inline vec3 right() const {
return vec4(RIGHT, 1.0) * model();
}
inline void translate(const vec3 change) {
m_origin += change;
}
inline void origin(const vec3 pos) {
m_origin = pos;
}
[[nodiscard]]
inline vec3 origin() const {
return m_origin;
}
inline void scale(const vec3 scale) {
m_scale = scale;
}
[[nodiscard]]
inline vec3 scale() const {
return m_scale;
}
inline void rotate(math::vec3 axis, float radianAngle) {
// documentation claims this is in degrees, based on experimentation this actually appears to be radians...
auto angles = axis * radianAngle;
m_euler += angles;
}
inline void rotateEuler(vec3 angles) {
m_euler += angles;
}
inline void euler(vec3 angles) {
m_euler = angles;
}
[[nodiscard]]
inline glm::vec3 euler() const {
return m_euler;
}
[[nodiscard]]
inline mat4 local() const {
const glm::mat4 transformX = glm::rotate(math::IDENTITY_M4, glm::radians(m_euler.x), AXIS_X);
const glm::mat4 transformY = glm::rotate(math::IDENTITY_M4, glm::radians(m_euler.y), AXIS_Y);
const glm::mat4 transformZ = glm::rotate(math::IDENTITY_M4, glm::radians(m_euler.z), AXIS_Z);
const auto rotation = transformY * transformX * transformZ;
return glm::translate(math::IDENTITY_M4, m_origin)
* rotation
* glm::scale(math::IDENTITY_M4, m_scale);
}
[[nodiscard]]
inline mat4 model() const {
return local();
}
inline void update(const math::mat4 &parent) {
m_model = parent * local();
}
inline void lookAt(vec3 target) {
// auto direction = m_origin - target;
auto result = glm::lookAt(m_origin, target, math::AXIS_Y);
math::vec3 resultAngles;
glm::extractEulerAngleXYZ(result, resultAngles.x, resultAngles.y, resultAngles.z);
m_euler = glm::degrees(resultAngles);
}
private:
mat4 m_model; // us -> world
vec3 m_origin;
vec3 m_euler;
vec3 m_scale;
};
inline math::mat4 calc_view_matrix(const Transform &transform) {
return glm::lookAt(transform.origin(), transform.origin() + transform.forward(), transform.up());
}
inline math::mat4 calc_view_matrix(const Transform &transform, vec3 target) {
return glm::lookAt(transform.origin(), target, transform.up());
}
}
#endif
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 20/08/22.
//
#ifndef FGGL_MATH_VECTOR_HPP
#define FGGL_MATH_VECTOR_HPP
#include <ostream>
#include <tuple>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
namespace glm {
inline bool operator<(const vec2 &lhs, const vec2 &rhs) {
return std::tie(lhs.x, lhs.y)
< std::tie(rhs.x, rhs.y);
}
inline bool operator<(const vec3 &lhs, const vec3 &rhs) {
return std::tie(lhs.x, lhs.y, lhs.z)
< std::tie(rhs.x, rhs.y, rhs.z);
}
inline bool operator<(const vec4 &lhs, const vec4 &rhs) {
return std::tie(lhs.x, lhs.y, lhs.z, lhs.w)
< std::tie(rhs.x, rhs.y, rhs.z, rhs.w);
}
// output stream operators
inline std::ostream &operator<<(std::ostream &os, const vec2 &v) {
os << "(" << v.x << ", " << v.y << ")";
return os;
}
inline std::ostream &operator<<(std::ostream &os, const vec3 &v) {
os << "(" << v.x << ", " << v.y << "," << v.z << ")";
return os;
}
inline std::ostream &operator<<(std::ostream &os, const vec4 &v) {
os << "(" << v.x << ", " << v.y << "," << v.z << "," << v.w << ")";
return os;
}
}
#endif //FGGL_MATH_VECTOR_HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 22/10/22.
// FIXME HACKY IMPLEMENTATION DETAIL BECAUSE THE ASSET LOADING PIPELINE IS BAD
//
#include "fggl/mesh/mesh.hpp"
#ifndef FGGL_MESH_COMPONENTS_HPP
#define FGGL_MESH_COMPONENTS_HPP
namespace fggl::mesh {
struct StaticMesh3D {
constexpr static const char name[] = "StaticMesh3D";
constexpr static const util::GUID guid = util::make_guid(name);
util::GUID meshReference;
Mesh3D mesh;
std::string pipeline;
inline StaticMesh3D() = default;
inline StaticMesh3D(const Mesh3D &aMesh, std::string aPipeline) :
mesh(aMesh), pipeline(std::move(aPipeline)) {}
};
struct StaticMultiMesh3D {
constexpr static const char name[] = "StaticMultiMesh3D";
constexpr static const util::GUID guid = util::make_guid(name);
util::GUID meshReference;
MultiMesh3D mesh;
std::string pipeline;
inline StaticMultiMesh3D() = default;
inline StaticMultiMesh3D(const MultiMesh3D &aMesh, std::string aPipeline) :
mesh(aMesh), pipeline(std::move(aPipeline)) {}
};
}
#endif //FGGL_MESH_COMPONENTS// _HPP
/*
* This file is part of FGGL.
*
* FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with FGGL.
* If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by webpigeon on 18/10/22.
//
#ifndef FGGL_MESH_MESH_HPP
#define FGGL_MESH_MESH_HPP
#include "fggl/math/types.hpp"
#include "fggl/assets/types.hpp"
#include <vector>
#include <span>
namespace fggl::mesh {
struct Vertex3D {
math::vec3 position;
math::vec3 normal;
math::vec3 colour{ 1.0F, 1.0F, 1.0F };
math::vec2 texPos{ NAN, NAN };
static Vertex3D from_pos(math::vec3 pos) {
return {
.position = pos,
.normal {NAN, NAN, NAN},
.colour {1.0F, 1.0F, 1.0F},
.texPos { pos.x, pos.z }
};
}
};
struct Vertex2D {
math::vec2 position;
math::vec2 colour;
math::vec2 texPos;
};
enum TextureType {
DIFFUSE, NORMAL
};
constexpr auto MISSING_TEXTURE = assets::AssetID::make(0);
struct Material {
std::string name;
math::vec3 ambient;
math::vec3 diffuse;
math::vec3 specular;
std::vector<assets::AssetID> diffuseTextures{};
std::vector<assets::AssetID> normalTextures{};
std::vector<assets::AssetID> specularTextures{};
inline assets::AssetID getPrimaryDiffuse() {
assert( !diffuseTextures.empty() );
return diffuseTextures.empty() ? MISSING_TEXTURE : diffuseTextures[0];
}
inline assets::AssetID getPrimaryNormals() {
assert( !normalTextures.empty() );
return normalTextures.empty() ? MISSING_TEXTURE : normalTextures[0];
}
inline assets::AssetID getPrimarySpecular() {
assert( !specularTextures.empty() );
return specularTextures.empty() ? MISSING_TEXTURE : specularTextures[0];
}
};
template<typename VertexFormat>
struct Mesh {
std::vector<VertexFormat> data;
std::vector<uint32_t> indices;
assets::AssetID material;
inline uint32_t append(const VertexFormat& vert) {
auto nextIdx = data.size();
data.push_back(vert);
return nextIdx;
}
};
template<typename MeshFormat>
struct MultiMesh {
std::vector<MeshFormat> meshes;
std::vector<assets::AssetID> materials;
MeshFormat& generate() {
return meshes.template emplace_back();
}
};
using Mesh2D = Mesh<Vertex2D>;
using MultiMesh2D = MultiMesh<Mesh2D>;
using Mesh3D = Mesh<Vertex3D>;
using MultiMesh3D = MultiMesh<Mesh3D>;
}
#endif //FGGL_MESH_MESH_HPP