Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
Work on #392: next stage of the backend adapter layer
Browse files Browse the repository at this point in the history
Seriously WIP, checking in at the heat of a long streak (see subtask 4),
for "management" reasons... At least things compile cleanly with GCC.

! Oh, BTW, but not with MSVC any more!... -> #405

+ Much of #253: Reconcile the `gfx` namespace
  It's become an implicit subtask of #392, with a different focus now;
  see #403 for a fresh perspective!
  • Loading branch information
xparq committed Jul 8, 2024
1 parent fda0e77 commit b4df980
Show file tree
Hide file tree
Showing 108 changed files with 2,042 additions and 1,217 deletions.
8 changes: 8 additions & 0 deletions include/SAL.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef _IQEUSH8CYEVHG8974MHGCUV8YRVGHE48M7VRH98UHC598RV_
#define _IQEUSH8CYEVHG8974MHGCUV8YRVGHE48M7VRH98UHC598RV_


#include "SAL/dispatch.hpp"


#endif // _IQEUSH8CYEVHG8974MHGCUV8YRVGHE48M7VRH98UHC598RV_
27 changes: 27 additions & 0 deletions include/SAL/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Service Adapter Library (or "Software Abstraction Layer", on every other day)


Like a HAL, but rather than standardizing an imaginary _underlying_ platform,
the goal of this middleware layer is to facilitate replacing certain external
components -- not just those belonging to a backend, but any libraries.

The contents of this layer is diven by the needs of the application -- so each
app should have its own optimal, tailored set of adapters. The app is free to
decide to use SAL adapters, or integrate (or interface with) external services
directly.

(So, it's neither "standardizing", nor hierarchically layered. That's why it
hasn't become a "platform abstraction layer" (or PAL) either: not all services
used are low-level, platform-like; the only common theme connecting them is
just that they are meant to be easily replaceable without app rewrites.)

---------------------
Actually...

It could also be called even more generally a "Software Compatibility Layer",
and then it could naturally also have a bunch of selected "utility" headers
(and even modules, later -> overlapping a personal foundation lib!...) the
app can still freely use, without any explicit "adaptering"!...

And then all the truly generic crap buried under sfw/util (etc.) could finally
find a better home!
6 changes: 6 additions & 0 deletions include/SAL/TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Rename the legacy sfw:: namespaces!
Can't just omi them, and leave it to the app to include these from inside
some app-specific wrapper ns., because these headers also include lots of
other (std, 3rd-party) stuff that would then break!

- Migrate the soruces, too, from src/lib to src/SAL (for the time being)!
9 changes: 9 additions & 0 deletions include/SAL/cfg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

#ifndef _D7FT437YTGWERHTGNV7YTYN972XMCV9786NWBT687DYVMJ56V_
#define _D7FT437YTGWERHTGNV7YTYN972XMCV9786NWBT687DYVMJ56V_



#endif // _D7FT437YTGWERHTGNV7YTYN972XMCV9786NWBT687DYVMJ56V_
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions include/SAL/cfg/BACKEND/TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Split this into multiple modules, each with a separately configurable backend!
E.g. math, geometry, graphics, inputs/events, audio, time etc.

Note that one (compound) backend (like SFML) can provide services for more than
one of these interface modules (i.e. math, graphics, inputs, audio etc.).

An overall single BACKEND/.../DEFAULT.h header should then set multiple cfg.
macros, one for each interface module that a) the selected (compound) backend
has the functionality for, and b) has the necessary adapters (vaguely analogous
e.g. to NT's HAL drivers) implemented.

(See also: #392.)
2 changes: 1 addition & 1 deletion include/sfw/cfg/global.h → include/SAL/cfg/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
//!! But, in fact, it should be included from everywhere!
//!! Make it forced by the build! Plus a check + #error to GUI.hpp!

#define SFW_VECTOR_STREAMABLE
#define SAL_VECTOR_STREAMABLE
35 changes: 19 additions & 16 deletions include/sfw/adapter/dispatch.hpp → include/SAL/dispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// Dispatching backend-specific headers (for #include-ing by client code)
//
// Usage examples:
// #include SFW_ADAPTER_IMPL(math/Vector) -> sfw/adapter/math/Vector/SFW_CFG_GFX_BACKEND/Impl.hpp
// #include SFW_ADAPTER_IMPL(math/Vector, Impl.cpp) -> sfw/adapter/math/Vector/SFW_CFG_GFX_BACKEND/Impl.cpp
// #include SFW_ADAPTER_IMPL(math, Vector.hpp) -> sfw/adapter/math/SFW_CFG_GFX_BACKEND/Vector.hpp
// #include SFW_ADAPTER_IMPL(math, Vector.cpp) -> sfw/adapter/math/SFW_CFG_GFX_BACKEND/Vector.cpp
// #include SAL_ADAPTER(math/Vector) -> SAL/math/Vector/SFW_CFG_GFX_BACKEND/Impl.hpp
// #include SAL_ADAPTER(math/Vector, Impl.cpp) -> SAL/math/Vector/SFW_CFG_GFX_BACKEND/Impl.cpp
// #include SAL_ADAPTER(math, Vector.hpp) -> SAL/math/SFW_CFG_GFX_BACKEND/Vector.hpp
// #include SAL_ADAPTER(math, Vector.cpp) -> SAL/math/SFW_CFG_GFX_BACKEND/Vector.cpp
//
// https://stackoverflow.com/a/50728314/1479945 <- Reminder that `#include MACRO` is a thing...
//----------------------------------------------------------------------------
Expand All @@ -14,24 +14,27 @@
#define _CPO8E9PC8MER8958YS9VDTNYC980MYX89Q809357W89ENRBY_


//#define SFW_ADAPTER_IMPL(Component, ...) SFW_ADAPTER_IMPL1(Component)
//!!#define SFW_ADAPTER_IMPL(Component, Suffix) _sfw_STR(_sfw_CONCAT(_sfw_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Suffix))
#include "cfg.h"


//#define SAL_ADAPTER(Component, ...) SAL_ADAPTER1(Component)
//!!#define SAL_ADAPTER(Component, Suffix) _sal_STR(_sal_CONCAT(_sal_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Suffix))
//!! Also generalize the implicit switcher macro (SFW_CFG_GFX_BACKEND)!
//!!?? Rename to sg. like SFW_BACKEND_PATH(...), or even back to SFW_BACKEND_SPECIFIC? (Or not even BACKEND...)

#define _sfw_EXPAND(X) X
#define _sfw_GET_MACRO(_1, _2, NAME, ...) NAME
#define SFW_ADAPTER_IMPL(...) _sfw_EXPAND(_sfw_GET_MACRO(__VA_ARGS__, SFW_ADAPTER_IMPL_2, SFW_ADAPTER_IMPL_1)(__VA_ARGS__))
#define _sal_EXPAND(X) X
#define _sal_GET_MACRO(_1, _2, NAME, ...) NAME
#define SAL_ADAPTER(...) _sal_EXPAND(_sal_GET_MACRO(__VA_ARGS__, SAL_ADAPTER_2, SAL_ADAPTER_1)(__VA_ARGS__))
//https://stackoverflow.com/a/69945225/1479945

//!! Get rid of this awkward, hardcoded legacy safeguard:
#ifndef SFW_CFG_GFX_BACKEND
//!!Should only be a warning about including some default!
//!!But #warning is c++23(!...), and isn't supported by MSVC yet. :-/
//!!(Note that GCC has supported it for ages.)
//!!#warning No backend has been selected. Use: #include "sfw/cfg/USE_{backendname}"
//!!#warning No backend has been selected. Use: #include "cfg/USE_{backendname}"
//!!#warning Selecting SFML as default graphics backend...
#include "sfw/cfg/BACKEND/DEFAULT.h"
#include "cfg/BACKEND/DEFAULT.h"
#endif


Expand All @@ -49,14 +52,14 @@
//----------------------------------------------------------------------------
// Internal helpers

// "DRY" shorthand:
#define SFW_COMPONENT_PATH_PREFIX sfw/adapter //!! Should probably be a coming macro!

#define SFW_COMPONENT_PATH_PREFIX SAL

// Create path string from two non-empty, unquoted components:
#define _sfw_PATH_STR(Pre, Post) _sz_STR(Pre/Post) //!!?? Does it also need to be CONCAT'ed? Seems to work, but: always?! (I.e. spaces, commas in the arguments?!)
#define _sal_PATH_STR(Pre, Post) _sz_STR(Pre/Post) //!!?? Does it also need to be CONCAT'ed? Seems to work, but: always?! (I.e. spaces, commas in the arguments?!)

#define SFW_ADAPTER_IMPL_1(Component) _sfw_PATH_STR(SFW_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Impl.hpp)
#define SFW_ADAPTER_IMPL_2(Component, Filename) _sfw_PATH_STR(SFW_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Filename)
#define SAL_ADAPTER_1(Component) _sal_PATH_STR(SFW_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Impl.hpp)
#define SAL_ADAPTER_2(Component, Filename) _sal_PATH_STR(SFW_COMPONENT_PATH_PREFIX/Component/SFW_CFG_GFX_BACKEND, Filename)


#endif // _CPO8E9PC8MER8958YS9VDTNYC980MYX89Q809357W89ENRBY_
219 changes: 219 additions & 0 deletions include/SAL/geometry/Rectangle.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
//----------------------------------------------------------------------------
// Platform-independent rectangle type wrapper (the interface half of the adapter
// -- see the ..._Impl class for the implementation half, #included below)
//----------------------------------------------------------------------------

#ifndef _RV56988BFU68MOUJH98V73903906IDFGDFG45Y_
#define _RV56988BFU68MOUJH98V73903906IDFGDFG45Y_


//!!--------------------------------------------------------------------------
//!!?? Move this to another header? (Used by both the adapter interface and impl.)
//!! Possibly along with Vector and Scalar then!
//!!
//!! And reconcile the different namespaces then!!!
//!!
#include "SAL/math/Vector.hpp"

namespace SAL::geometry
{
template <class R>
concept Rectangle = requires(R r) {
// typename R::number_type;
// typename R::vector_type;
r.x(); r.y(); r.dx(); r.dy();
};

} // namespace SAL::geometry
//!!--------------------------------------------------------------------------


// The backend-specific adapter impl.:
#include "SAL.hpp"
#include SAL_ADAPTER(geometry, Rectangle_Impl.hpp)

#include <utility> // move
#include <type_traits> // is_same


namespace SAL::geometry
{
template <class Impl>
class Rectangle_Interface : public Impl
{
public:
constexpr Rectangle_Interface() = default;

//!!?? Accept native vector types (our Vector auto-converts to those, so they work, too),
//!!?? but that might not actually be a good thing -- could be confusingly permissive, and
//!!?? also untenable with more complex classes, which then would also be expected to support
//!!?? all sorts of other native types transparently (with minor combinatoric explosions)!
//!!?? (And the confusion part: generic APIs are not expected to work with "random" foreign
//!!?? types; however, supporting the types of the current backend could be excused.)
constexpr Rectangle_Interface(Impl::vector_type position, Impl::vector_type size)
: Impl(position.native(), size.native()) {}

constexpr Rectangle_Interface(Impl::vector_type size)
: Impl({0,0}, size.native()) {}

/*!! OLD:
// Convert from lval with different number type:
template <class OtherRectT>// requires (!std::is_same_v<typename OtherRectT::number_type, typename Impl::number_type>)
constexpr Rectangle_Interface(const OtherRectT& other) //! `const` would break rval inputs like auto r = fRect(), despite having an rval ctor, too! :-o
: Impl( {(typename Impl::number_type)other.x(), (typename Impl::number_type)other.y()},
{(typename Impl::number_type)other.width(), (typename Impl::number_type)other.height()} ) { static_assert(false, "HERE"); }
!!*/
// Convert from rval with different number type:
//!! These versions both failed to enable this ctor for e.g. const iRect const_ir; auto cfr = fRect(const_ir4);
// template <Rectangle OtherRectT> Rectangle_Interface(OtherRectT&& other) ...
// ... requires (!std::is_same_v<typename OtherRectT::number_type, typename Impl::number_type>)
template <Rectangle OtherRectT,
typename = std::enable_if_t< !std::is_same_v<typename std::decay_t<OtherRectT>::number_type, typename Impl::number_type> >
//!! decay_t (or at least std::remove_cvref_t) is CRITICAL for accepting both const/non-const OtherRect ctor args.! :-o
>
constexpr Rectangle_Interface(OtherRectT&& other) //!!{ static_assert(false, "HERE"); }
: Impl( {(typename Impl::number_type)std::forward<OtherRectT>(other).x(), (typename Impl::number_type)std::forward<OtherRectT>(other).y()},
{(typename Impl::number_type)std::forward<OtherRectT>(other).width(), (typename Impl::number_type)std::forward<OtherRectT>(other).height()} ) {} //!!{ static_assert(false, "HERE"); }

//!! Also: if the converting ctor above indeed transparently covers rvals/lvals & const/non-consts,
//!! then do the same for the plain (Other == Self) copy/move ctors below:

//!!?? WHY ARE THESE NEVER ACTUALLY SELECTED IN GCC, BUT ARE IN MSVC?! :-o (Not a failed assert ever! :-o )
template <Rectangle SameRectT,
typename = std::enable_if_t< std::is_same_v<typename std::decay_t<SameRectT>::number_type, typename Impl::number_type> >
//!! decay_t (or at least std::remove_cvref_t) is CRITICAL for accepting both const/non-const OtherRect ctor args.! :-o
>
constexpr Rectangle_Interface(const SameRectT& other) : Impl(std::forward(other.native())) { static_assert(false, "HERE"); }
/*!! OLD:
// Copy:
template <class SameRectT> requires (std::is_same_v<typename SameRectT::number_type, typename Impl::number_type>)
constexpr Rectangle_Interface(const SameRectT& other) : Impl(other.native()) { static_assert(false, "HERE"); }
// Move (still should just be a copy though):
template <class SameRectT> requires (std::is_same_v<typename SameRectT::number_type, typename Impl::number_type>)
constexpr Rectangle_Interface(SameRectT&& other) : Impl(std::move(other.native())) { static_assert(false, "HERE"); }
!!*/
// All other signatures are passed to the native impl.:
using Impl::Impl; // Elevate the backend-specific ctors for implicit backend -> abstract conversions!

// The default op= is fine!

constexpr auto adapter() { return static_cast< Impl*>(this); }
constexpr auto adapter() const { return static_cast<const Impl*>(this); }

//!!
//!! Some ops. would be suboptimal for native rects of {x1,y1, x2,y2} with this simplistic API!
//!! Worse yet: some are not even implemented (or implementable (sanely)) for that layout! :-o
//!!

constexpr auto x() const { return adapter()->_x(); }
constexpr auto y() const { return adapter()->_y(); }
constexpr auto dx() const { return adapter()->_dx(); }
constexpr auto dy() const { return adapter()->_dy(); }

constexpr auto& x() { return adapter()->_x(); }
constexpr auto& y() { return adapter()->_y(); }
constexpr auto& dx() { return adapter()->_dx(); }
constexpr auto& dy() { return adapter()->_dy(); }

// Alternative accessors & setters...

constexpr auto width() const { return dx(); }
constexpr auto height() const { return dy(); }
constexpr auto left() const { return x(); }
constexpr auto top() const { return y(); }
constexpr auto right() const { return x() + dx(); }
constexpr auto bottom() const { return y() + dy(); }

constexpr auto& width() { return dx(); }
constexpr auto& height() { return dy(); }
constexpr auto& left() { return x(); }
constexpr auto& top() { return y(); }
constexpr auto& right() { static_assert(false, "Not implemented!"); }
constexpr auto& bottom() { static_assert(false, "Not implemented!"); }

constexpr auto& width(Scalar auto n) { dx() = n; return *this; }
constexpr auto& height(Scalar auto n) { dy() = n; return *this; }
constexpr auto& left(Scalar auto n) { x() = n; return *this; }
constexpr auto& top(Scalar auto n) { y() = n; return *this; }
constexpr auto& right(Scalar auto n) { dx() = n - x(); return *this; }
constexpr auto& bottom(Scalar auto n) { dy() = n - y(); return *this; }

//! Alas, these ones make copies. Use the native() object to access the raw vectors
//! directly, if you know the configured backend has them.
constexpr Vec2<typename Impl::number_type> position() const { return {x(), y()}; }
constexpr Vec2<typename Impl::number_type> size() const { return {dx(), dy()}; }

constexpr operator typename Impl::native_type& () { return Impl::native(); }
constexpr operator const typename Impl::native_type& () const { return Impl::native(); }

constexpr operator bool () { return (bool)dx() && (bool)dy(); } // Area != 0?
// So, the position doesn't matter. Also, negative size is OK. Also, not ||, unlike Vector's.

}; // class Rectangle_Interface

//!! Ugh, this is pretty horribly vague here:
//!! template <Scalar NumT = float>
constexpr bool operator == (const auto& a, const auto& b) { return a.native() == b.native(); }


//----------------------------------------------------------------------------
//!!?? FIX...
// C++ deduction guides for Rect() and Rect{{x, y}, {dx, dy}} to work...
//----------------------------------------------------------------------------

//!! Using ctors now instead, so DELETE:
// template <Scalar NumT = float>
// Rectangle_Interface(Vec2<NumT>&& pos, Vec2<NumT>&& size) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;
//
// template <Scalar NumT = float>
// Rectangle_Interface() -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;

//!!?? DELETE:
//!! template <Scalar NumT>
//!! Rectangle_Interface(const Vec2<NumT>&, const Vec2<NumT>&) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;

//!!?? Is this a viable alternative?
//!! template <Scalar NumT>
//!! Rectangle_Interface(Vector auto&& pos, Vector auto&& size) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;

#if 0 //!!?? These didn't help with declaring the cvt ctor with (const OtherT&):
template <Scalar NumT = float, class OtherRectT>
requires (!std::is_same_v<typename OtherRectT::number_type, NumT>)
Rectangle_Interface(OtherRectT&& other) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;

template <Scalar NumT = float, class OtherRectT>
requires (!std::is_same_v<typename OtherRectT::number_type, NumT>)
Rectangle_Interface(const OtherRectT& other) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<NumT>>;

template <class SameRectT>
Rectangle_Interface(const SameRectT& other) -> Rectangle_Interface<adapter::/*active_backend::*/Rectangle_Impl<typename SameRectT::number_type>>;
#endif


//----------------------------------------------------------------------------
// Convenience type aliases...
//----------------------------------------------------------------------------

template <typename NumT = float>
using Rect = Rectangle_Interface<adapter::/*geometry::active_backend::*/Rectangle_Impl<NumT>>;

using fRect = Rectangle_Interface<adapter::/*geometry::active_backend::*/Rectangle_Impl<float>>;
using iRect = Rectangle_Interface<adapter::/*geometry::active_backend::*/Rectangle_Impl<int>>;
using uRect = Rectangle_Interface<adapter::/*geometry::active_backend::*/Rectangle_Impl<unsigned>>;
using dRect = Rectangle_Interface<adapter::/*geometry::active_backend::*/Rectangle_Impl<double>>;


//-------------------------------------------------------------------
// Operators (as free functions)...
//-------------------------------------------------------------------

//!!
//!!?? operator + for union (e.g. for combining AABBs)...
//!!


} // namespace SAL::geometry


#endif // _RV56988BFU68MOUJH98V73903906IDFGDFG45Y_
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

//!! Include the Rectangle concept(s) instead, which should grab the Vector, too!
//!! (Ideally then, there should be no need to use the Vec aliases here at all.)
#include "sfw/math/Vector.hpp" //!! Vector Adapter Interface, actually... Only the concept header shouild be called Vector!
#include "SAL/math/Vector.hpp" //!! Vector Adapter Interface, actually... Only the concept header shouild be called Vector!

#include <SFML/Graphics/Rect.hpp>
#include <SFML/System/Vector2.hpp> // Rect has it; just making its use explicit here.

#include <utility> // forward


namespace sfw::adapter
namespace SAL::adapter
{
namespace SFML
{
Expand Down Expand Up @@ -67,7 +67,7 @@ namespace SFML
using Rectangle_Impl = SFML::Rectangle_Impl<NumT>;
//}

} // namespace sfw::adapter
} // namespace SAL::adapter


#endif // _FWMW9S8TYHJMFC3569YF890UYM498G56UY894T_
Loading

0 comments on commit b4df980

Please sign in to comment.