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
Showing
with 2050 additions and 0 deletions
/*
* 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_GRID_HEX_HPP
#define FGGL_GRID_HEX_HPP
#include <array>
#include <vector>
#include <cmath>
#include <compare>
#include <fggl/math/fmath.hpp>
/**
* Hexagonal Grid Implementation.
* Based largely off Amit's incredible grid documentation.
*/
namespace fggl::grid {
enum class HexDirPointy {
RIGHT = 0, TOP_RIGHT = 1, TOP_LEFT = 2, LEFT = 3, BOTTOM_LEFT = 4, BOTTOM_RIGHT = 5
};
enum class HexDirFlat {
BOTTOM_RIGHT = 0, TOP_RIGHT = 1, TOP = 2, TOP_LEFT = 3, BOTTOM_LEFT = 4, BOTTOM = 5
};
constexpr std::array< std::array<int, 2>, 6> HEX_DIRECTIONS {{
{1, 0}, {1, -1}, {0, 1},
{-1, 0}, {-1, 1}, {0, 1}
}};
constexpr std::array< std::array<int, 2>, 6> HEX_DIAGONALS {{
{2, -1}, {+1, -2}, {-1, -1},
{-2, 1}, {-1, 2}, {1, 1}
}};
template<typename T>
struct HexPointT {
constexpr HexPointT(T posQ, T posR) : m_pos({posQ, posR}) {}
constexpr explicit HexPointT(const std::array<int, 2>& pos) : m_pos(pos[0], pos[1]) {}
[[nodiscard]]
constexpr auto q() const -> T {
return m_pos[0];
}
[[nodiscard]]
constexpr auto r() const -> T{
return m_pos[1];
}
[[nodiscard]]
constexpr auto s() const -> T {
return -m_pos[0]-m_pos[1];
}
inline HexPointT neighbour(HexDirPointy dir) {
auto& offset = HEX_DIRECTIONS.at( (int)dir );
return { m_pos[0] + offset[0], m_pos[1] + offset[1] };
}
inline HexPointT neighbour(HexDirFlat dir) {
auto& offset = HEX_DIAGONALS.at( (int)dir );
return { m_pos[0] + offset[0], m_pos[1] + offset[1] };
}
HexPointT operator+(const HexPointT<T>& other) const {
return { m_pos[0] + other.m_pos[0], m_pos[1] + other.m_pos[1] };
}
HexPointT operator-(const HexPointT<T>& other) const {
return { m_pos[0] - other.m_pos[0], m_pos[1] - other.m_pos[1] };
}
bool operator==(const HexPointT<T>& other) const {
return m_pos[0] == other.m_pos[0] && m_pos[1] == m_pos[1];
}
auto operator<=>(const HexPointT<T>& other) const = default;
[[nodiscard]]
auto distance(const HexPointT& other) const -> T {
auto vec = *this - other;
return (
::abs(vec.q())
+ ::abs(vec.q() - vec.r())
+ ::abs(vec.r()) / 2
);
}
[[nodiscard]]
auto hexesInRange(int range) const -> std::vector<HexPointT<T>> {
std::vector<HexPointT<T>> results;
for ( auto q = -range; q <= range; ++q ) {
auto stopCount = std::min(range, -q+range);
for ( auto r = std::max(-range, -q-range); r <= stopCount; ++r ) {
results.push_back( *this + HexPointT<T>(q, r) );
}
}
return results;
}
private:
std::array<T, 2> m_pos;
};
using FloatHex = HexPointT<float>;
using IntHex = HexPointT<int>;
template<typename T>
constexpr FloatHex hexLerp(const HexPointT<T>& start, const HexPointT<T>& end, float t) {
return {
math::lerp(start.q(), end.q(), t),
math::lerp(start.r(), end.r(), t)
};
}
[[nodiscard]]
constexpr IntHex round2(const FloatHex& hex) {
auto q = std::round( hex.q() );
auto r = std::round( hex.r() );
auto s = std::round( hex.s() );
auto qDiff = std::abs( q - hex.q() );
auto rDiff = std::abs( r - hex.r() );
auto sDiff = std::abs( s - hex.r() );
if ( qDiff > rDiff && qDiff > sDiff) {
q = -r-s;
} else if ( rDiff > sDiff ) {
r = -q-s;
} else {
s = -q-r;
}
return {(int)q, (int)r};
}
std::vector<IntHex> lineTo(const IntHex& start, const IntHex& end);
} // namespace fggl::grid
#endif //FGGL_GRID_HEX_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 10/12/22.
//
#ifndef FGGL_GRID_HEXAGON_BOARD_HPP
#define FGGL_GRID_HEXAGON_BOARD_HPP
#include <map>
#include <set>
#include <optional>
#include <utility>
#include <variant>
#include "fggl/grid/hexagon.hpp"
#include "fggl/grid/tokens.hpp"
#include "fggl/grid/actions.hpp"
#include "fggl/math/types.hpp"
namespace fggl::grid {
class HexGrid;
using HexTarget = std::variant<TokenIdentifer, IntHex>;
using HexAction = Action<HexGrid, HexTarget>;
struct MaterialData {
std::string name;
math::vec3 colour;
};
struct TerrainType {
std::shared_ptr<MaterialData> data;
};
struct HexTile {
std::shared_ptr<MaterialData> terrain;
std::vector< std::shared_ptr<Token> > m_tokens;
[[nodiscard]]
inline std::optional<const MaterialData> data() const {
if (terrain == nullptr) {
{}
}
return *terrain;
}
};
class HexGrid {
public:
inline bool isValidPos(const IntHex& pos) const {
return m_tiles.contains(pos);
}
void setTerrain(const IntHex& pos, const TerrainType& terrain) {
auto& mapTile = m_tiles[pos];
mapTile.terrain = terrain.data;
}
std::optional<const MaterialData> getTerrain(const IntHex& pos) const {
const auto itr = m_tiles.find(pos);
if ( itr == m_tiles.end() ) {
return {};
}
return itr->second.data();
}
std::set<IntHex> getAllTiles() {
std::set<IntHex> posSet;
for ( auto& [pos,data] : m_tiles ) {
posSet.emplace( pos );
}
return posSet;
}
std::set<HexTile> tilesInRange(const IntHex& pos, int range) const;
std::set<HexTile> neighboursOf(const IntHex& pos) const;
private:
std::map<IntHex, HexTile> m_tiles;
std::map<uint64_t, std::shared_ptr<Token>> m_tokens;
};
} // namespace fggl::grid
#endif //FGGL_GRID_HEXAGON_BOARD_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/>.
*/
/*
* 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/12/22.
//
#ifndef FGGL_FGGL_GRID_LAYOUT_HPP
#define FGGL_FGGL_GRID_LAYOUT_HPP
#include "fggl/math/types.hpp"
#include "fggl/grid/hexagon.hpp"
namespace fggl::grid {
// factor out the call to sqrt so the matrices can be constexpr
constexpr float M_SQRT_3 = 1.73205080757F;
constexpr float M_SQRT_3_OVER_2 = M_SQRT_3 / 2.0F;
constexpr math::mat2 MAT_HEX_POINTY{
M_SQRT_3, 0.0F,
M_SQRT_3_OVER_2, 3.F / 2.F
};
constexpr math::mat2 MAT_HEX_FLAT{
3.F / 2.F, M_SQRT_3_OVER_2,
0.0F, M_SQRT_3
};
struct Orientation {
math::mat2 m_forward;
math::mat2 m_backward;
int m_angle;
inline Orientation(int angle, math::mat2 forward) : m_forward(forward), m_backward(glm::inverse(forward)), m_angle(angle) {};
static inline Orientation make_pointy() {
return { 30, MAT_HEX_POINTY};
}
static inline Orientation make_flat() {
return { 0, MAT_HEX_FLAT };
}
};
constexpr int HEX_SIDES = 6;
constexpr int DEG_PER_HEX_SIDE = 360 / HEX_SIDES; // 60 degrees per side
struct Layout {
Orientation m_orientation;
math::vec2 m_size;
math::vec2 m_origin;
Layout(Orientation orientation, math::vec2 size, math::vec2 origin) : m_orientation(orientation), m_size(size), m_origin(origin){}
Layout(Orientation orientation, float size) : m_orientation(orientation), m_size(size, size), m_origin() {}
inline void translate(float dx, float dy){
m_origin.x += dx;
m_origin.y += dy;
}
[[nodiscard]]
inline math::vec2 origin() const {
return m_origin;
}
[[nodiscard]]
inline math::vec2 size() const {
return m_size;
}
[[nodiscard]]
inline math::vec2 toScreen(IntHex gridPos) const {
const math::vec2 hexPoint{gridPos.q(), gridPos.r()};
auto point = (m_orientation.m_forward * hexPoint) * m_size;
return point + m_origin;
}
[[nodiscard]]
inline FloatHex toGrid(math::vec2 screen) const {
auto point = (screen - m_origin) / m_size;
auto hexPos = m_orientation.m_backward * point;
return {hexPos.x, hexPos.y};
}
[[nodiscard]]
inline math::vec2 cornerOffset(int corner) const {
const int angInc = DEG_PER_HEX_SIDE * corner;
const float angle = (angInc + m_orientation.m_angle) * ( fggl::math::PI / 180.0F);
return {
m_size.x * cosf(angle),
m_size.y * sinf(angle)
};
}
void paintHex(fggl::gfx::Paint& paint, IntHex pos, math::vec3 colour, math::vec2 offset) const {
const auto hexScreenCenter = toScreen(pos);
gfx::Path2D path({0,0});
path.colour(colour);
for (int i=0; i < HEX_SIDES; ++i) {
auto cornerPos = hexScreenCenter + cornerOffset(i);
if ( i == 0) {
path.moveTo(cornerPos + offset);
} else {
path.pathTo(cornerPos + offset);
}
}
paint.stroke(path);
}
};
}
#endif //FGGL_FGGL_GRID_LAYOUT_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 19/12/22.
//
#ifndef FGGL_GRID_TOKENS_HPP
#define FGGL_GRID_TOKENS_HPP
#include <cstdint>
#include <map>
#include "fggl/util/guid.hpp"
namespace fggl::grid {
using TokenIdentifer = fggl::util::OpaqueName<uint64_t, struct Token>;
class TokenType {
public:
using PropType = int64_t;
inline void setProperty(util::GUID name, PropType newVal) {
m_properties[name] = newVal;
}
[[nodiscard]]
inline PropType getProperty(util::GUID name, PropType unsetVal=0) const {
try {
return m_properties.at(name);
} catch ( std::out_of_range& e ) {
return unsetVal;
}
}
private:
std::map<util::GUID, PropType> m_properties;
std::map<util::GUID, uint64_t> m_cost;
};
class Token {
public:
Token() = default;
explicit Token(std::shared_ptr<TokenType> type) : m_type(std::move(type)) {}
inline void setProperty(util::GUID name, TokenType::PropType newVal) {
m_properties[name] = newVal;
}
[[nodiscard]]
inline TokenType::PropType getProperty(util::GUID name, TokenType::PropType unsetVal=0) const {
try {
auto prop = m_properties.at(name);
return prop;
} catch ( std::out_of_range& ex) {
return m_type->getProperty(name, unsetVal);
}
}
[[nodiscard]]
inline TokenType::PropType getPropertyDirect(util::GUID name, TokenType::PropType unsetVal=0) const {
try {
auto prop = m_properties.at(name);
return prop;
} catch ( std::out_of_range& ex) {
return unsetVal;
}
}
private:
TokenIdentifer m_id;
std::shared_ptr<TokenType> m_type;
std::map<util::GUID, TokenType::PropType> m_properties;
};
} // namespace fggl::grid
#endif //FGGL_GRID_TOKENS_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_GUI_CONTAINERS_HPP
#define FGGL_GUI_CONTAINERS_HPP
#include <fggl/gui/widget.hpp>
namespace fggl::gui {
class Container : public Widget {
public:
Container() = default;
virtual ~Container() = default;
inline void clear() {
m_children.clear();
}
void add(std::unique_ptr<Widget> widget);
virtual inline void layout() {}
bool contains(const math::vec2 &point) override;
Widget *getChildAt(const math::vec2 &point) override;
inline void update(float deltaTime) override {
for (auto& child : m_children) {
child->update(deltaTime);
}
}
void render(gfx::Paint &paint) override;
void onMouseOver(math::vec2 pos) override;
void onEnter(math::vec2i pos) override;
void onExit(math::vec2i pos) override;
private:
bool m_dirty;
Widget* m_hovered = nullptr;
protected:
std::vector<std::unique_ptr<Widget>> m_children;
};
class GridBox : public Container {
public:
GridBox(uint32_t rows, uint32_t cols, uint32_t padX = 8, uint32_t padY = 8);
void layout() override;
private:
uint32_t m_rows;
uint32_t m_cols;
math::vec2i m_padding;
};
class Panel : public Container {
public:
Panel() = default;
~Panel() = default;
void render(gfx::Paint &paint) override;
};
enum class LayoutAxis {
LINE_AXIS,
PAGE_AXIS
};
/**
* A box-like container.
* This container lines child elements up along an axis.
*
* This is a fairly common approach in may layout frameworks, for example:
* * Java's BoxLayout
* * GTK's Boxes
* * QT's QBoxLayout
* * Android's XML box things
*/
/*class Box : public Container {
public:
Box(LayoutAxis axis);
void layout() override;
private:
const LayoutAxis m_axis;
};*/
}; //namespace fggl::gui
#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 21/04/22.
//
#ifndef FGGL_GUI_FONTS_HPP
#define FGGL_GUI_FONTS_HPP
#include <memory>
#include <map>
#include <string>
#include "fggl/math/types.hpp"
#include "fggl/data/storage.hpp"
#include "fggl/modules/module.hpp"
#include <ft2build.h>
#include FT_FREETYPE_H
namespace fggl::gui {
constexpr const char* DEFAULT_FONT_NAME = "LiberationSans-Regular.ttf";
struct GlyphMetrics {
math::vec2 size;
math::vec2 bearing;
long advance;
};
class FontFace {
public:
explicit FontFace(FT_Face face);
~FontFace();
FontFace(const FontFace &) = delete;
FontFace(FontFace &&) = delete;
FontFace &operator=(const FontFace &) = delete;
FontFace &operator=(FontFace &&) = delete;
inline GlyphMetrics &metrics(char letter) {
auto itr = m_metrics.find(letter);
if (itr == m_metrics.end()) {
return populateMetrics(letter);
}
return itr->second;
}
math::vec2 stringSize(const std::string &text);
void texture(char letter, int &width, int &height, unsigned char **buff);
private:
FT_Face m_face;
std::map<char, GlyphMetrics> m_metrics;
GlyphMetrics &populateMetrics(char letter);
};
class FontLibrary {
public:
constexpr static const auto service = modules::make_service("fggl::gui::font");
explicit FontLibrary(data::Storage *storage);
~FontLibrary();
// copy and moving not needed
FontLibrary(const FontLibrary &) = delete;
FontLibrary(FontLibrary &&) = delete;
FontLibrary &operator=(const FontLibrary &) = delete;
FontLibrary &operator=(FontLibrary &&) = delete;
inline std::shared_ptr<FontFace> getFont(const std::string &name) {
auto fontItr = m_cache.find(name);
if (fontItr != m_cache.end()) {
return fontItr->second;
}
// need to load the font...
auto path = m_storage->resolvePath(data::StorageType::Data, name);
FT_Face face;
if (FT_New_Face(m_context, path.string().c_str(), 0, &face)) {
return nullptr;
}
FT_Set_Pixel_Sizes(face, 0, 18);
// create the new font object
auto ptr = std::make_shared<FontFace>(face);
m_cache[name] = ptr;
return ptr;
}
inline void setDefaultFont(const std::string& name) {
m_defaultFont = getFont(name);
}
inline std::shared_ptr<FontFace> getDefaultFont() const {
return m_defaultFont;
}
private:
FT_Library m_context;
data::Storage *m_storage;
std::map<const std::string, std::shared_ptr<FontFace>> m_cache;
std::shared_ptr<FontFace> m_defaultFont;
};
} // nmespace fggl::gui
#endif //FGGL_GUI_FONTS_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_GUI_GUI_HPP
#define FGGL_GUI_GUI_HPP
namespace fggl::gui {
}; //namespace fggl::gui
#include <fggl/gui/widget.hpp>
#include <fggl/gui/containers.hpp>
#include <fggl/gui/widgets.hpp>
#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 04/03/23.
//
#ifndef FGGL_GUI_MODEL_PARSER_HPP
#define FGGL_GUI_MODEL_PARSER_HPP
#include <fggl/gui/model/structure.hpp>
#include <fggl/gui/fonts.hpp>
#include <fggl/modules/module.hpp>
namespace fggl::gui::model {
constexpr auto WIDGET_FACTORY_SERVICE = modules::make_service("gui::WidgetService");
class WidgetFactory {
public:
constexpr static auto service = WIDGET_FACTORY_SERVICE;
inline WidgetFactory(FontLibrary* lib) : m_fontLibrary(lib) {}
inline Widget* build(std::string templateName) {
return new Widget(m_templates.at(templateName).get());
}
inline Widget* buildEmpty() {
return new Widget(m_fontLibrary);
}
inline void push(std::string name, const Widget&& definition) {
m_templates.emplace(name, std::make_unique<Widget>(definition));
}
Widget* getTemplate(const std::string& name) {
auto itr = m_templates.find(name);
if ( itr == m_templates.end() ){
return nullptr;
}
return itr->second.get();
}
private:
std::map<std::string, std::unique_ptr<Widget>> m_templates;
FontLibrary* m_fontLibrary;
};
Widget* parseFile(WidgetFactory& factory, const std::string& path);
} // namespace fggl::gui::model
#endif //FGGL_GUI_MODEL_PARSER_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 04/03/23.
//
#ifndef FGGL_GUI_MODEL_STRUCTURE_HPP
#define FGGL_GUI_MODEL_STRUCTURE_HPP
#include <map>
#include <variant>
#include <vector>
#include <string>
#include <optional>
#include <fggl/math/types.hpp>
#include <fggl/gui/fonts.hpp>
namespace fggl::gui::model {
using AttrKey = std::string;
using AttrValue = std::variant<bool, int, float, std::string, math::vec2, math::vec3>;
constexpr float UNDEFINED = INFINITY;
constexpr math::vec2 UNDEFINED_SIZE{INFINITY, INFINITY};
class Widget {
public:
using ChildItr = std::vector<Widget>::iterator;
using ChildItrConst = std::vector<Widget>::const_iterator;
inline Widget(FontLibrary* library) :
m_parent(nullptr),
m_children(),
m_fontLibrary(library),
m_attrs(),
m_cachedSize(),
m_dirty(true) {
}
explicit inline Widget(Widget* parent) :
m_parent(parent),
m_children(),
m_fontLibrary(parent->m_fontLibrary),
m_attrs(),
m_cachedSize(),
m_dirty(true) {
}
inline bool isRoot() const {
return m_parent == nullptr;
}
inline bool isLeaf() const {
return m_children.empty();
}
inline bool hasAttr(const AttrKey& key) const {
return m_attrs.contains(key);
}
inline std::map<AttrKey, AttrValue> attrs() {
return m_attrs;
}
template<typename type>
inline type get(const AttrKey& key) const {
return std::get<type>(m_attrs.at(key));
}
template<typename type>
type get_or_default(const AttrKey& key) const {
auto itr = m_attrs.find(key);
if ( itr == m_attrs.end() ) {
return type();
} else {
return std::get<type>(itr->second);
}
}
template<typename type>
inline void set(const AttrKey& key, type value) {
m_attrs[key] = value;
}
inline void addChild(const Widget& element) {
auto childItr = m_children.insert( m_children.cend(), element );
childItr->m_parent = this;
}
inline ChildItr begin() {
return m_children.begin();
}
inline ChildItrConst begin() const noexcept {
return m_children.begin();
}
inline ChildItrConst cbegin() const noexcept {
return m_children.cbegin();
}
inline ChildItr end() {
return m_children.end();
}
inline ChildItrConst end() const {
return m_children.end();
}
inline ChildItrConst cend() const {
return m_children.cend();
}
inline std::optional<math::vec2> preferredSize() {
calcPrefSize(m_fontLibrary->getDefaultFont());
return m_cachedSize;
}
private:
Widget *m_parent;
std::vector<Widget> m_children;
FontLibrary* m_fontLibrary;
std::map< AttrKey, AttrValue > m_attrs;
math::vec2 m_cachedSize;
bool m_dirty;
void calcPrefSize(std::shared_ptr<FontFace> face);
};
void attr_box_set(Widget& widget, const AttrKey& key, auto top, auto right, auto bottom, auto left) {
widget.set(key + "::top", top);
widget.set(key + "::right", right);
widget.set(key + "::bottom", bottom);
widget.set(key + "::left", left);
}
inline void attr_box_set(Widget& widget, const AttrKey& key, auto vert, auto horz) {
attr_box_set(widget, key, vert, horz, vert, horz);
}
inline void attr_box_set(Widget& widget, const AttrKey& key, auto value) {
attr_box_set(widget, key, value, value, value, value);
}
} // namespace fggl::gui::model
#endif //FGGL_GUI_MODEL_STRUCTURE_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/06/22.
//
#ifndef FGGL_GUI_MODULE_HPP
#define FGGL_GUI_MODULE_HPP
#include "fggl/gui/fonts.hpp"
#include "fggl/gui/model/parser.hpp"
#include "fggl/data/module.hpp"
#include "fggl/assets/packed/module.hpp"
namespace fggl::gui {
constexpr auto MIME_TTF = assets::from_mime("font/ttf");
constexpr auto ASSET_FONT_TTF = assets::make_asset_type("font/ttf");
static assets::AssetTypeID is_font(std::filesystem::path path) {
if ( path.extension() == ".ttf" ){
return ASSET_FONT_TTF;
}
return assets::INVALID_ASSET_TYPE;
}
struct FreeType {
constexpr static const char *name = "fggl::gui::FreeType";
constexpr static const std::array<modules::ServiceName, 2> provides = {
FontLibrary::service,
model::WidgetFactory::service
};
constexpr static const std::array<modules::ServiceName, 2> depends = {
data::Storage::service,
assets::CheckinAdapted::service
};
static bool factory(modules::ServiceName name, modules::Services &serviceManager);
};
bool FreeType::factory(modules::ServiceName service, modules::Services &services) {
if (service == FontLibrary::service) {
auto storage = services.get<data::Storage>();
services.create<FontLibrary>(storage);
auto* checkin = services.get<assets::CheckinAdapted>();
checkin->setLoader( MIME_TTF, assets::NEEDS_CHECKIN, is_font );
return true;
}
if ( service == model::WidgetFactory::service ) {
auto fonts = services.get<FontLibrary>();
services.create<model::WidgetFactory>(fonts);
return true;
}
return false;
}
}
#endif //FGGL_GUI_MODULE_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 04/03/23.
//
#ifndef FGGL_GUI_RENDERER_RENDERER_HPP
#define FGGL_GUI_RENDERER_RENDERER_HPP
#include <fggl/gui/model/structure.hpp>
#include <fggl/gfx/paint.hpp>
namespace fggl::gui::renderer {
struct Box {
float top;
float right;
float bottom;
float left;
inline Box trim(Box border) const {
return {
top + border.top,
right - border.right,
bottom - border.bottom,
left + border.left
};
}
inline Box expand(Box border) const {
return {
top - border.top,
right + border.right,
bottom + border.bottom,
left - border.left
};
}
inline float width() const {
return right - left;
}
inline float height() const {
return bottom - top;
}
};
inline math::vec2 get_vec2(const model::Widget& root, const std::string& name) {
if ( !root.hasAttr(name) ) {
return {};
}
return root.get<math::vec2>(name);
}
inline math::vec3 get_vec3_rgb(const model::Widget& root, const std::string& name) {
if ( !root.hasAttr(name) ) {
return {};
}
return root.get<math::vec3>(name);
}
inline Box get_box(const model::Widget& root, const std::string& name) {
return {
root.get_or_default<float>(name + "::top"),
root.get_or_default<float>(name + "::right"),
root.get_or_default<float>(name + "::bottom"),
root.get_or_default<float>(name + "::left")
};
}
inline Box getBounds(math::vec2 pos, math::vec2 size) {
return {
pos.y,
pos.x + size.x,
pos.y + size.y,
pos.x
};
}
void draw_box(gfx::Path2D &path, glm::vec2 topLeft, glm::vec2 bottomRight);
void draw_border_patch(gfx::Paint& paint, Box& bounds, Box& size, math::vec3 colour);
void draw_border_solid(gfx::Paint& paint, Box& bounds, Box& size, math::vec3 colour);
void draw_background_solid(gfx::Paint& paint, Box& bounds, math::vec3 colour);
void layout(model::Widget& root);
void visit(const model::Widget& root, gfx::Paint& paint, Box offset = {0.0F, 1024.0F, 768.0F, 0.0F});
} // namespace fggl::gui::renderer
#endif //FGGL_GUI_RENDERER_RENDERER_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_GUI_WIDGET_HPP
#define FGGL_GUI_WIDGET_HPP
#include <fggl/math/types.hpp>
#include <fggl/gfx/paint.hpp>
#include <memory>
namespace fggl::gui {
constexpr uint8_t RGB_MAX_VAL = 255;
/**
* Convert an RGB value using 0-255 to a 0-1 value.
*
* @param red red component
* @param green green component
* @param blue blue component
* @return the normalized RGB value
*/
constexpr math::vec3 rgbToNormal(uint8_t red, uint8_t green, uint8_t blue) {
return {red / RGB_MAX_VAL, green / RGB_MAX_VAL, blue / RGB_MAX_VAL};
}
/**
* Convert a Hue-saturation-value colour to RGB
*
* @param hue hue component, assumed 0 - 360
* @param saturation assumed 0 - 1
* @param value assumed 0 - 1
* @return RGB, in the range 0,1 for each component
*/
inline math::vec3 HSVtoNormal(float hue, float saturation, float value) {
assert(0 < hue && hue <= 360);
assert(0 < saturation && saturation <= 1);
assert(0 < value && value <= 1);
const float chroma = value * saturation;
const float x = chroma * (1 - std::fabs(std::fmod(hue / 60.0F, 2.0F) - 1.0F));
math::vec3 tmp{0, 0, 0};
if (0 <= hue && hue < 60) {
tmp = {chroma, x, 0};
} else if (60 <= hue && hue < 120) {
tmp = {x, chroma, 0};
} else if (120 <= hue && hue < 180) {
tmp = {0, chroma, x};
} else if (180 <= hue && hue < 240) {
tmp = {0, x, chroma};
} else if (240 <= hue && hue < 300) {
tmp = {x, 0, chroma};
} else if (300 <= hue && hue < 360) {
tmp = {chroma, 0, x};
}
return tmp + (value - chroma);
}
void draw_box(gfx::Path2D &path, math::vec2 topLeft, math::vec2 bottomRight);
void draw_progress(gfx::Path2D &path, math::vec2 topLeft, math::vec2 size, float value);
void draw_slider(gfx::Path2D &path, math::vec2 topLeft, math::vec2 size, float value);
void draw_button(gfx::Path2D &path, math::vec2 topLeft, math::vec2 size, bool active, bool pressed);
struct Bounds2D {
math::vec2 topLeft;
math::vec2 size;
Bounds2D() = default;
inline Bounds2D(math::vec2 pos, math::vec2 a_size) : topLeft(pos), size(a_size) {}
inline bool contains(math::vec2 point) {
return !((point.x > topLeft.x + size.x) ||
(point.x < topLeft.x) ||
(point.y > topLeft.y + size.y) ||
(point.y < topLeft.y)
);
}
};
class Widget {
public:
Widget() = default;
inline Widget(math::vec2 pos, math::vec2 size) : m_bounds(pos, size) {}
virtual ~Widget() = default;
inline math::vec2 topLeft() const {
return m_bounds.topLeft;
};
inline math::vec2 bottomRight() const {
return m_bounds.topLeft + m_bounds.size;
}
inline void size(math::vec2 pos, math::vec2 size) {
m_bounds.topLeft = pos;
m_bounds.size = size;
}
inline math::vec2 size() const {
return m_bounds.size;
}
virtual inline bool contains(const math::vec2 &point) {
return m_bounds.contains(point);
};
virtual inline Widget *getChildAt(const math::vec2 &point) {
if (!contains(point)) {
return nullptr;
}
return this;
}
virtual void update(float deltaTime) = 0;
virtual void render(gfx::Paint &paint) = 0;
inline virtual void layout() {};
inline virtual void activate() {};
inline virtual void onMouseOver(math::vec2 pos) {
if ( !m_hover ) {
onEnter(pos);
}
}
inline virtual void onEnter(math::vec2i /*pos*/) {
m_hover = true;
}
inline virtual void onExit(math::vec2i /*pos*/) {
m_hover = false;
}
protected:
bool m_hover = false;
private:
Bounds2D m_bounds;
};
}; //namespace fggl::gui
#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_GUI_WIDGETS_HPP
#define FGGL_GUI_WIDGETS_HPP
#include <functional>
#include <utility>
#include "fggl/gui/widget.hpp"
#include "fggl/gui/fonts.hpp"
namespace fggl::gui {
using Callback = std::function<void(void)>;
class Label : public Widget {
public:
Label() = default;
Label(math::vec2 pos, math::vec2 size);
~Label() = default;
void render(gfx::Paint &paint) override {
auto pos = topLeft();
auto size2 = size();
math::vec2 baseLine{pos.x + 10, pos.y + size2.y / 2 + 5};
paint.text(m_value, baseLine);
}
inline void font(std::shared_ptr<FontFace> font) {
m_font = std::move(font);
m_needsLayout = true;
}
inline void text(const std::string &value) {
m_value = value;
m_needsLayout = true;
}
inline std::string text() const {
return m_value;
}
math::vec2 naturalSize() {
if (m_needsLayout) {
layout();
}
return m_naturalSize;
}
void layout() override;
inline void update(float /*deltaTime*/) override {}
private:
std::shared_ptr<gui::FontFace> m_font;
std::string m_value;
bool m_needsLayout;
math::vec2 m_naturalSize;
};
class Button : public Widget {
public:
Button() = default;
Button(math::vec2 pos, math::vec2 size);
void render(gfx::Paint &paint) override;
void activate() override;
void label(const std::string &value);
[[nodiscard]]
std::string label() const;
inline void update(float /*deltaTime*/) override {}
void addCallback(Callback callback);
void layout() override;
private:
Label m_label;
std::string m_value;
std::vector<Callback> m_callbacks;
bool m_active;
};
class Toggle : public Button {
public:
Toggle() = default;
};
}; //namespace fggl::gui
#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 19/06/22.
//
#ifndef FGGL_INPUT_BASICS_H
#define FGGL_INPUT_BASICS_H
namespace fggl::input {
enum class InputType {
BUTTON, // 0 || 1
UNIDIRECTIONAL_AXIS, // [0,1], absolute
BIDIRECTIONAL_AXIS, // [-1, 1], absolute
RELATIVE_AXIS // [-1, 1], relative
};
} // namespace fggl::input
#endif //FGGL_INPUT_BASICS_H
/*
* 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/11/2021.
//
#ifndef FGGL_INPUT_CAMERA_INPUT_HPP
#define FGGL_INPUT_CAMERA_INPUT_HPP
#include "fggl/entity/entity.hpp"
#include "fggl/math/types.hpp"
namespace fggl::input {
constexpr float ROT_SPEED = 0.05f;
constexpr float PAN_SPEED = 0.05f;
constexpr math::mat4 MAT_IDENTITY(1.0f);
struct FreeCamKeys {
constexpr const static char name[] = "FreeCameraKeys";
scancode_t forward;
scancode_t backward;
scancode_t left;
scancode_t right;
scancode_t rotate_cw;
scancode_t rotate_ccw;
};
void process_scroll(entity::EntityManager &ecs,
const Input &input,
entity::EntityID cam,
float minZoom = 10.0F,
float maxZoom = 50.0F);
/**
* Process the camera based on rotation around a fixed point.
*
* @param ecs the world that contains the camera
* @param input the input module to read the mouse location from
* @param cam the ID of the camera entity
*/
void process_arcball(entity::EntityManager &ecs, const Input &input, entity::EntityID cam);
/**
* Process free (floating) camera movement.
*
* @param ecs the world that contains the camera
* @param input the input module to read the mouse location from
* @param cam the ID of the camera entity
*/
void process_freecam(entity::EntityManager &ecs, const Input &input, entity::EntityID cam);
/**
* Input processing for moving the camera when the mouse is close to the edge of the screen.
*
* This function deals with ensuring the camera moves if the user moves their mouse button close
* to the edge of the screen. It will apply this as movement to the camera entity passed in as
* an argument.
*
* @param ecs the world that contains the camera
* @param input the input module to read the mouse location from
* @param cam the ID of the camera entity
*/
void process_edgescroll(entity::EntityManager &ecs, const Input &input, entity::EntityID cam);
}
#endif //FGGL_INPUT_CAMERA_INPUT_HPP
#ifndef FGGL_INPUT_GAMEPAD_H
#define FGGL_INPUT_GAMEPAD_H
/*
* 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_GAMEPAD_HPP
#define FGGL_INPUT_GAMEPAD_HPP
#include <string>
#include <array>
......@@ -50,49 +64,64 @@ namespace fggl::input {
};
constexpr std::array<GamepadButtonRecord, 15> GamepadButtonsMicrosoft = {{
{GamepadButton::A, "A"},
{GamepadButton::B, "B"},
{GamepadButton::X, "X"},
{GamepadButton::Y, "Y"},
{GamepadButton::BUMPER_LEFT, "Left Bumper"},
{GamepadButton::BUMPER_RIGHT, "Right Bumper"},
{GamepadButton::BACK, "Back"},
{GamepadButton::START, "Start"},
{GamepadButton::GUIDE, "Guide"},
{GamepadButton::THUMB_LEFT, "Thumb Left"},
{GamepadButton::THUMB_RIGHT, "Thumb Right"},
{GamepadButton::DPAD_UP, "Dpad Up"},
{GamepadButton::DPAD_RIGHT, "Dpad Right"},
{GamepadButton::DPAD_DOWN, "Dpad Down"},
{GamepadButton::DPAD_LEFT, "Dpad Left"},
}};
{GamepadButton::A, "A"},
{GamepadButton::B, "B"},
{GamepadButton::X, "X"},
{GamepadButton::Y, "Y"},
{GamepadButton::BUMPER_LEFT,
"Left Bumper"},
{GamepadButton::BUMPER_RIGHT,
"Right Bumper"},
{GamepadButton::BACK, "Back"},
{GamepadButton::START, "Start"},
{GamepadButton::GUIDE, "Guide"},
{GamepadButton::THUMB_LEFT,
"Thumb Left"},
{GamepadButton::THUMB_RIGHT,
"Thumb Right"},
{GamepadButton::DPAD_UP, "Dpad Up"},
{GamepadButton::DPAD_RIGHT,
"Dpad Right"},
{GamepadButton::DPAD_DOWN,
"Dpad Down"},
{GamepadButton::DPAD_LEFT,
"Dpad Left"},
}};
constexpr std::array<GamepadAxisRecord, 6> GamepadAxes = {{
{GamepadAxis::LEFT_X, "left stick left/right"},
{GamepadAxis::LEFT_Y, "left stick up/down"},
{GamepadAxis::RIGHT_X, "right stick left/right"},
{GamepadAxis::RIGHT_Y, "right stick up/down"},
{GamepadAxis::TRIGGER_LEFT, "left trigger"},
{GamepadAxis::TRIGGER_RIGHT, "right trigger"},
}};
{GamepadAxis::LEFT_X, "left stick left/right"},
{GamepadAxis::LEFT_Y, "left stick up/down"},
{GamepadAxis::RIGHT_X, "right stick left/right"},
{GamepadAxis::RIGHT_Y, "right stick up/down"},
{GamepadAxis::TRIGGER_LEFT, "left trigger"},
{GamepadAxis::TRIGGER_RIGHT, "right trigger"},
}};
constexpr std::array<GamepadButtonRecord, 15> GamepadButtonsPlaystation = {{
{GamepadButton::SQUARE, "Square"},
{GamepadButton::CIRCLE, "Circle"},
{GamepadButton::TRIANGLE, "Triangle"},
{GamepadButton::CROSS, "Cross"},
{GamepadButton::BUMPER_LEFT, "Left Bumper"},
{GamepadButton::BUMPER_RIGHT, "Right Bumper"},
{GamepadButton::BACK, "Back"},
{GamepadButton::START, "Start"},
{GamepadButton::GUIDE, "Guide"},
{GamepadButton::THUMB_LEFT, "Thumb Left"},
{GamepadButton::THUMB_RIGHT, "Thumb Right"},
{GamepadButton::DPAD_UP, "Dpad Up"},
{GamepadButton::DPAD_RIGHT, "Dpad Right"},
{GamepadButton::DPAD_DOWN, "Dpad Down"},
{GamepadButton::DPAD_LEFT, "Dpad Left"},
}};
{GamepadButton::SQUARE, "Square"},
{GamepadButton::CIRCLE, "Circle"},
{GamepadButton::TRIANGLE,
"Triangle"},
{GamepadButton::CROSS, "Cross"},
{GamepadButton::BUMPER_LEFT,
"Left Bumper"},
{GamepadButton::BUMPER_RIGHT,
"Right Bumper"},
{GamepadButton::BACK, "Back"},
{GamepadButton::START, "Start"},
{GamepadButton::GUIDE, "Guide"},
{GamepadButton::THUMB_LEFT,
"Thumb Left"},
{GamepadButton::THUMB_RIGHT,
"Thumb Right"},
{GamepadButton::DPAD_UP, "Dpad Up"},
{GamepadButton::DPAD_RIGHT,
"Dpad Right"},
{GamepadButton::DPAD_DOWN,
"Dpad Down"},
{GamepadButton::DPAD_LEFT,
"Dpad Left"},
}};
struct GamepadState {
std::bitset<GamepadButtonsMicrosoft.size()> buttons;
......@@ -104,76 +133,76 @@ namespace fggl::input {
struct GamepadInput {
public:
inline bool present(size_t id) const {
assert( id < MaxControllers );
assert(id < MaxControllers);
return m_active[id];
}
inline void name(size_t id, const std::string& name) {
assert( id < MaxControllers );
inline void name(size_t id, const std::string &name) {
assert(id < MaxControllers);
m_names[id] = name;
}
inline std::string name(size_t id) const {
std::string name = m_names[id].empty() ? "gamepad "+std::to_string(id) : m_names[id];
if ( !present(id) ) {
std::string name = m_names[id].empty() ? "gamepad " + std::to_string(id) : m_names[id];
if (!present(id)) {
return name + " (disconnected)";
}
return name;
}
inline float axis(size_t id, GamepadAxis axis) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return m_current[id].axes[(int)axis];
return m_current[id].axes[(int) axis];
}
inline float axisDelta(size_t id, GamepadAxis axis) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return m_current[id].axes[(int)axis] - m_previous[id].axes[(int)axis];
return m_current[id].axes[(int) axis] - m_previous[id].axes[(int) axis];
}
inline bool button(size_t id, GamepadButton btn) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return m_current[id].buttons[(int)btn];
return m_current[id].buttons[(int) btn];
}
inline bool buttonPressed(size_t id, GamepadButton btn) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return m_current[id].buttons[(int)btn] && !m_previous[id].buttons[(int)btn];
return m_current[id].buttons[(int) btn] && !m_previous[id].buttons[(int) btn];
}
inline bool buttonReleased(size_t id, GamepadButton btn) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return !m_current[id].buttons[(int)btn] && m_previous[id].buttons[(int)btn];
return !m_current[id].buttons[(int) btn] && m_previous[id].buttons[(int) btn];
}
inline bool buttonChanged(size_t id, GamepadButton btn) const {
if ( !present(id) ) {
if (!present(id)) {
return 0.0f;
}
return m_current[id].buttons[(int)btn] != m_previous[id].buttons[(int)btn];
return m_current[id].buttons[(int) btn] != m_previous[id].buttons[(int) btn];
}
inline void frame(float dt) {
inline void frame(float /*dt*/) {
m_previous = m_current;
}
inline void update(size_t id, const GamepadState& state) {
assert( present(id) );
inline void update(size_t id, const GamepadState &state) {
assert(present(id));
m_current[id] = state;
}
inline void setActive(size_t id, bool state) {
assert( id < MaxControllers );
assert(id < MaxControllers);
m_active[id] = state;
}
......
/*
* 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_H
#define FGGL_INPUT_H
#include <memory>
#include <fggl/input/keyboard.hpp>
#include <fggl/input/mouse.hpp>
#include <fggl/input/gamepad.hpp>
#include "fggl/modules/module.hpp"
namespace fggl::input {
constexpr const auto SERVICE_INPUT = modules::make_service("fggl::input::Input");
class Input {
public:
constexpr static const auto service = SERVICE_INPUT;
Input() = default;
void frame(float dt);
KeyboardInput keyboard;
MouseInput mouse;
GamepadInput gamepads;
};
}
#endif
#ifndef FGGL_INPUT_KEYBOARD_H
#define FGGL_INPUT_KEYBOARD_H
/*
* 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_KEYBOARD_HPP
#define FGGL_INPUT_KEYBOARD_HPP
#include <array>
#include <vector>
#include <set>
#include <unordered_set>
#include <iostream>
namespace fggl::input {
using scancode_t = int;
struct KeyboardState {
std::set<scancode_t> m_keys;
class KeyboardState {
public:
KeyboardState() = default;
inline void clear() {
m_keys.clear();
}
inline void clear() {
m_keys.clear();
}
inline void set(scancode_t code, bool state) {
if ( state ) {
m_keys.insert( code );
} else {
m_keys.erase( code );
inline void set(scancode_t code, bool state) {
if (state) {
m_keys.insert(code);
} else {
m_keys.erase(code);
}
}
}
inline bool down(scancode_t scancode) const {
if ( m_keys.empty() )
return false;
inline bool down(scancode_t scancode) const {
if (m_keys.empty())
return false;
return m_keys.find(scancode) != m_keys.end();
}
return m_keys.count(scancode) > 0;
}
private:
std::unordered_set<scancode_t> m_keys;
};
class KeyboardInput {
public:
inline void frame(float dt) {
inline void frame(float /*dt*/) {
m_prev = m_curr;
}
......
/*
* 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/06/22.
//
#ifndef FGGL_INPUT_MODULE_HPP
#define FGGL_INPUT_MODULE_HPP
#include <array>
#include "fggl/modules/module.hpp"
#include "fggl/input/input.hpp"
namespace fggl::input {
struct Generic {
constexpr static const char *name = "fggl::input::Generic";
constexpr static const std::array<modules::ServiceName, 1> provides = {
SERVICE_INPUT
};
constexpr static const std::array<modules::ServiceName, 0> depends = {};
static bool factory(modules::ServiceName service, modules::Services &services);
};
bool Generic::factory(modules::ServiceName service, modules::Services &services) {
if (service == SERVICE_INPUT) {
services.create<input::Input>();
return true;
}
return false;
}
}
#endif //FGGL_INPUT_MODULE_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_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