SDL3pp
A slim C++ wrapper for SDL3
Loading...
Searching...
No Matches
Transformations

We try make the binding as objective as possible, in order to minimize any semantic deviation from the C interface.

To do so we define the some rules so each C type or function is almost mechanically transformed into a C++ type or function.

General rules

  • The C++ header files should have the same name than SDL's C headers, minus its prefix.
    • An exception is to some support files that we use for ease the abstraction and have no C header equivalent.
  • All definitions are inside the SDL namespace, definition names lose their prefix. Eg SDL_Surface becomes SDL::Surface;

Function rules

  • All method definitions are inline. We have a header only library here;
    • Forward declarations are permitted whenever is convenient;
  • Non method-like functions are represented by simply wrapping them into free functions:
    • They are always inside the namespace SDL;
    • The name thus have the "SDL_" prefix removed;
    • Example: SDL_GetCurrentVideoDriver becomes SDL::GetCurrentVideoDriver();
  • Method-like functions become class/struct methods accordingly to Type rules;
    • The Type name is removed, eg SDL_GetTextureProperties becomes SDL::Texture::GetProperties();
    • Functions that involve I/O, like SDL_LoadBMP(), are considered non-method like and thus stay as free functions like: SDL::LoadBMP();
  • The parameters of the function have the same meaning and same order than SDL's C API, transformed as the following:
    • If it is a instance function, the first parameter become the this pointer and thus is omitted.
    • If the parameter was a const char*, its becomes a StringWrapper;
    • If the parameter is a SDL type, use the type defined in Type rules:
    • If the parameter is used as const pointer, it is allowed to be transformed to:
      • const reference if mandatory;
      • SDL::OptionalRef value if parameter is optional;
      • The non owning TypeRef, if the type is a Resource.
    • If the parameter is the only out parameter, and the return type is the regular boolean for success or failure:
      • Remove the parameter;
      • If the result is a reference type, return one of the wrapped types;
      • Otherwise, wrap the pointed type in a std::optional;
      • Do this only if won't cause ambiguity;
    • If the parameter is a C callback function, the function should have an overload accepting Callback type accordingly to Callback rules;
  • When there are 4 parameters representing a RGBA value:

Type rules

  • Type that aren't opaque and nor have method-like functions are just typedef'd into the namespace. Eg: using InitFlags = SDL_InitFlags;
  • Data types that aren't opaque nor are created and destroyed by SDL functions, but have method-like functions are defined as follows:
    • If the type is a struct, we define a struct extending it, eg struct Rect: SDL_Rect{...};:
      • A constructor accepting the original type by value or const reference must be provided;
      • A constructor with all base class variables should be provided, if there are two or more of them;
      • A default constructor should be provided, probably zeroing everything;
      • Example: SDL::Rect;
    • If the type is not a struct (like an enum or an alias for Uint32), then we define a struct containing a single member variable of the original type:
      • A constructor accepting the original type by value or const reference must be provided;
      • A conversion operator to the original type must be provided;
      • If there is a default invalid state, this should be the default value of the constructor parameter and there must be converting operator to bool;
      • Example SDL::PixelFormat;
    • No further instance variable is added to it;
    • The appropriated method-like functions are wrapped inside its body;
    • A constructor accepting a original type by value or const reference must be provided;
    • No destructor, copy constructor, move constructor or assignment operator should be defined;
  • Resource types that are created and destroyed by SDL functions (such SDL_Create*() and SDL_Destroy*()) are represented as follows:
    • A struct called TypeBase, defined as a CRTP is defined, expecting the template parameter to fulfill the SDL::ObjectBox concept;
      • This struct will have all wrappers for method-like functions defined in its body;
      • If the original type is a non opaque struct we can define methods to manipulate the most common access patterns directly, when convenient to do so;
      • There must be a constructor for each SDL_Create* there;
      • It also uses all its parent's constructor.
    • The class Type extends TypeBase with a SDL::ObjectUnique;
      • This represents an owning reference to the resource and destroy it when it goes out of scope, unless we call SDL::ObjectUnique.release() before it;
    • The class TypeRef extends TypeBase with a SDL::ObjectRef;
      • This represents a non owning reference to the resource. Use this on parameters and as a sort of weak reference to the previous type;
      • We can still destroy it manually by calling the right Destroy() on it;

Callback rules

As we mentioned in Function rules, the original callback functions are always supported. In addition, if has an userdata parameter we create an alternative callback as follows:

  • The callback name will have the "CB" suffix, replacing a "Callback" suffix if any;
  • The callback type is a std::function with the same parameters than the original one, with the following changes:
    • Remove userdata parameter;
    • Follow any applicable parameter transformation rules as described in Function rules.
  • The function taking the callback (and the one removing it if exists) must follow this guideline on how to marshal the std::function object into the userdata.