From 3d78a073d90d8f232604fbdc76a6a583ffab364b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 24 May 2021 09:16:08 -0400 Subject: Consistently refer to C++ as "cpp" and fix installation --- bindings/cpp/include/.clang-tidy | 14 + bindings/cpp/include/pugl/cairo.hpp | 45 +++ bindings/cpp/include/pugl/gl.hpp | 70 ++++ bindings/cpp/include/pugl/pugl.hpp | 721 +++++++++++++++++++++++++++++++++++ bindings/cpp/include/pugl/stub.hpp | 45 +++ bindings/cpp/include/pugl/vulkan.hpp | 168 ++++++++ 6 files changed, 1063 insertions(+) create mode 100644 bindings/cpp/include/.clang-tidy create mode 100644 bindings/cpp/include/pugl/cairo.hpp create mode 100644 bindings/cpp/include/pugl/gl.hpp create mode 100644 bindings/cpp/include/pugl/pugl.hpp create mode 100644 bindings/cpp/include/pugl/stub.hpp create mode 100644 bindings/cpp/include/pugl/vulkan.hpp (limited to 'bindings/cpp') diff --git a/bindings/cpp/include/.clang-tidy b/bindings/cpp/include/.clang-tidy new file mode 100644 index 0000000..816223d --- /dev/null +++ b/bindings/cpp/include/.clang-tidy @@ -0,0 +1,14 @@ +Checks: > + *, + -*-uppercase-literal-suffix, + -clang-diagnostic-unused-macros, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-static-cast-downcast, + -google-runtime-references, + -hicpp-named-parameter, + -llvmlibc-*, + -modernize-use-trailing-return-type, + -readability-implicit-bool-conversion, + -readability-named-parameter, +FormatStyle: file +HeaderFilterRegex: 'pugl/.*' diff --git a/bindings/cpp/include/pugl/cairo.hpp b/bindings/cpp/include/pugl/cairo.hpp new file mode 100644 index 0000000..b42af0d --- /dev/null +++ b/bindings/cpp/include/pugl/cairo.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2012-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef PUGL_CAIRO_HPP +#define PUGL_CAIRO_HPP + +#include "pugl/cairo.h" +#include "pugl/pugl.h" + +namespace pugl { + +/** + @defgroup cairopp Cairo + Cairo graphics support. + @ingroup puglpp + @{ +*/ + +/// @copydoc puglCairoBackend +inline const PuglBackend* +cairoBackend() noexcept +{ + return puglCairoBackend(); +} + +/** + @} +*/ + +} // namespace pugl + +#endif // PUGL_CAIRO_HPP diff --git a/bindings/cpp/include/pugl/gl.hpp b/bindings/cpp/include/pugl/gl.hpp new file mode 100644 index 0000000..3e23a57 --- /dev/null +++ b/bindings/cpp/include/pugl/gl.hpp @@ -0,0 +1,70 @@ +/* + Copyright 2012-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef PUGL_GL_HPP +#define PUGL_GL_HPP + +#include "pugl/gl.h" +#include "pugl/pugl.h" +#include "pugl/pugl.hpp" + +namespace pugl { + +/** + @defgroup glpp OpenGL + OpenGL graphics support. + @ingroup puglpp + @{ +*/ + +/// @copydoc PuglGlFunc +using GlFunc = PuglGlFunc; + +/// @copydoc puglGetProcAddress +inline GlFunc +getProcAddress(const char* name) noexcept +{ + return puglGetProcAddress(name); +} + +/// @copydoc puglEnterContext +inline Status +enterContext(View& view) noexcept +{ + return static_cast(puglEnterContext(view.cobj())); +} + +/// @copydoc puglLeaveContext +inline Status +leaveContext(View& view) noexcept +{ + return static_cast(puglLeaveContext(view.cobj())); +} + +/// @copydoc puglGlBackend +inline const PuglBackend* +glBackend() noexcept +{ + return puglGlBackend(); +} + +/** + @} +*/ + +} // namespace pugl + +#endif // PUGL_GL_HPP diff --git a/bindings/cpp/include/pugl/pugl.hpp b/bindings/cpp/include/pugl/pugl.hpp new file mode 100644 index 0000000..51cfdb8 --- /dev/null +++ b/bindings/cpp/include/pugl/pugl.hpp @@ -0,0 +1,721 @@ +/* + Copyright 2012-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef PUGL_PUGL_HPP +#define PUGL_PUGL_HPP + +#include "pugl/pugl.h" + +#include + +#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) +# include +#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) +# include +#endif + +namespace pugl { + +/** + @defgroup puglpp Pugl C++ API + Pugl C++ API wrapper. + @{ +*/ + +namespace detail { + +/// Free function for a C object +template +using FreeFunc = void (*)(T*); + +/// Generic C++ wrapper for a C object +template Free> +class Wrapper +{ +public: + Wrapper(const Wrapper&) = delete; + Wrapper& operator=(const Wrapper&) = delete; + + Wrapper(Wrapper&& wrapper) noexcept + : _ptr{wrapper._ptr} + { + wrapper._ptr = nullptr; + } + + Wrapper& operator=(Wrapper&& wrapper) noexcept + { + _ptr = wrapper._ptr; + wrapper._ptr = nullptr; + return *this; + } + + ~Wrapper() noexcept { Free(_ptr); } + + T* cobj() noexcept { return _ptr; } + const T* cobj() const noexcept { return _ptr; } + +protected: + explicit Wrapper(T* ptr) noexcept + : _ptr{ptr} + {} + +private: + T* _ptr; +}; + +} // namespace detail + +using Rect = PuglRect; ///< @copydoc PuglRect + +/** + @defgroup eventspp Events + @{ +*/ + +/** + A strongly-typed analogue of PuglEvent. + + This is bit-for-bit identical to the corresponding PuglEvent, so events are + simply cast to this type to avoid any copying overhead. + + @tparam t The `type` field of the corresponding PuglEvent. + + @tparam Base The specific struct type of the corresponding PuglEvent. +*/ +template +struct Event final : Base { + /// The type of the corresponding C event structure + using BaseEvent = Base; + + /// The `type` field of the corresponding C event structure + static constexpr const PuglEventType type = t; +}; + +using Mod = PuglMod; ///< @copydoc PuglMod +using Mods = PuglMods; ///< @copydoc PuglMods +using Key = PuglKey; ///< @copydoc PuglKey +using EventType = PuglEventType; ///< @copydoc PuglEventType +using EventFlag = PuglEventFlag; ///< @copydoc PuglEventFlag +using EventFlags = PuglEventFlags; ///< @copydoc PuglEventFlags +using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode + +/// @copydoc PuglEventCreate +using CreateEvent = Event; + +/// @copydoc PuglEventDestroy +using DestroyEvent = Event; + +/// @copydoc PuglEventConfigure +using ConfigureEvent = Event; + +/// @copydoc PuglEventMap +using MapEvent = Event; + +/// @copydoc PuglEventUnmap +using UnmapEvent = Event; + +/// @copydoc PuglEventUpdate +using UpdateEvent = Event; + +/// @copydoc PuglEventExpose +using ExposeEvent = Event; + +/// @copydoc PuglEventClose +using CloseEvent = Event; + +/// @copydoc PuglEventFocus +using FocusInEvent = Event; + +/// @copydoc PuglEventFocus +using FocusOutEvent = Event; + +/// @copydoc PuglEventKey +using KeyPressEvent = Event; + +/// @copydoc PuglEventKey +using KeyReleaseEvent = Event; + +/// @copydoc PuglEventText +using TextEvent = Event; + +/// @copydoc PuglEventCrossing +using PointerInEvent = Event; + +/// @copydoc PuglEventCrossing +using PointerOutEvent = Event; + +/// @copydoc PuglEventButton +using ButtonPressEvent = Event; + +/// @copydoc PuglEventButton +using ButtonReleaseEvent = Event; + +/// @copydoc PuglEventMotion +using MotionEvent = Event; + +/// @copydoc PuglEventScroll +using ScrollEvent = Event; + +/// @copydoc PuglEventClient +using ClientEvent = Event; + +/// @copydoc PuglEventTimer +using TimerEvent = Event; + +/// @copydoc PuglEventLoopEnter +using LoopEnterEvent = Event; + +/// @copydoc PuglEventLoopLeave +using LoopLeaveEvent = Event; + +/** + @} + @defgroup statuspp Status + @{ +*/ + +/// @copydoc PuglStatus +enum class Status { + success, ///< @copydoc PUGL_SUCCESS + failure, ///< @copydoc PUGL_FAILURE + unknownError, ///< @copydoc PUGL_UNKNOWN_ERROR + badBackend, ///< @copydoc PUGL_BAD_BACKEND + badConfiguration, ///< @copydoc PUGL_BAD_CONFIGURATION + badParameter, ///< @copydoc PUGL_BAD_PARAMETER + backendFailed, ///< @copydoc PUGL_BACKEND_FAILED + registrationFailed, ///< @copydoc PUGL_REGISTRATION_FAILED + realizeFailed, ///< @copydoc PUGL_REALIZE_FAILED + setFormatFailed, ///< @copydoc PUGL_SET_FORMAT_FAILED + createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED + unsupportedType, ///< @copydoc PUGL_UNSUPPORTED_TYPE +}; + +static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, ""); + +/// @copydoc puglStrerror +inline const char* +strerror(const Status status) noexcept +{ + return puglStrerror(static_cast(status)); +} + +/** + @} + @defgroup worldpp World + @{ +*/ + +/// @copydoc PuglWorldType +enum class WorldType { + program, ///< @copydoc PUGL_PROGRAM + module, ///< @copydoc PUGL_MODULE +}; + +static_assert(WorldType(PUGL_MODULE) == WorldType::module, ""); + +/// @copydoc PuglWorldFlag +enum class WorldFlag { + threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS +}; + +static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, ""); + +using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags + +#if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) + +/// An exception thrown when construction fails +class FailedConstructionError : public std::exception +{ +public: + FailedConstructionError(const char* const msg) noexcept + : _msg{msg} + {} + + virtual const char* what() const noexcept override; + +private: + const char* _msg; +}; + +# define PUGL_CHECK_CONSTRUCTION(cond, msg) \ + do { \ + if (!(cond)) { \ + throw FailedConstructionError(msg); \ + } \ + } while (0) + +#elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) +# define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond); +#else +/** + Configurable macro for handling construction failure. + + If `PUGL_HPP_THROW_FAILED_CONSTRUCTION` is defined, then this throws a + `pugl::FailedConstructionError` if construction fails. + + If `PUGL_HPP_ASSERT_CONSTRUCTION` is defined, then this asserts if + construction fails. + + Otherwise, this does nothing. +*/ +# define PUGL_CHECK_CONSTRUCTION(cond, msg) +#endif + +/// @copydoc PuglWorld +class World : public detail::Wrapper +{ +public: + World(const World&) = delete; + World& operator=(const World&) = delete; + + World(World&&) = delete; + World& operator=(World&&) = delete; + + ~World() = default; + + World(WorldType type, WorldFlag flag) + : Wrapper{puglNewWorld(static_cast(type), + static_cast(flag))} + { + PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); + } + + World(WorldType type, WorldFlags flags) + : Wrapper{puglNewWorld(static_cast(type), flags)} + { + PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); + } + + explicit World(WorldType type) + : World{type, WorldFlags{}} + {} + + /// @copydoc puglGetNativeWorld + void* nativeWorld() noexcept { return puglGetNativeWorld(cobj()); } + + /// @copydoc puglSetClassName + Status setClassName(const char* const name) noexcept + { + return static_cast(puglSetClassName(cobj(), name)); + } + + /// @copydoc puglGetTime + double time() const noexcept { return puglGetTime(cobj()); } + + /// @copydoc puglUpdate + Status update(const double timeout) noexcept + { + return static_cast(puglUpdate(cobj(), timeout)); + } +}; + +/** + @} + @defgroup viewpp View + @{ +*/ + +using Backend = PuglBackend; ///< @copydoc PuglBackend +using NativeView = PuglNativeView; ///< @copydoc PuglNativeView + +/// @copydoc PuglViewHint +enum class ViewHint { + useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE + useDebugContext, ///< @copydoc PUGL_USE_DEBUG_CONTEXT + contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR + contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR + redBits, ///< @copydoc PUGL_RED_BITS + greenBits, ///< @copydoc PUGL_GREEN_BITS + blueBits, ///< @copydoc PUGL_BLUE_BITS + alphaBits, ///< @copydoc PUGL_ALPHA_BITS + depthBits, ///< @copydoc PUGL_DEPTH_BITS + stencilBits, ///< @copydoc PUGL_STENCIL_BITS + samples, ///< @copydoc PUGL_SAMPLES + doubleBuffer, ///< @copydoc PUGL_DOUBLE_BUFFER + swapInterval, ///< @copydoc PUGL_SWAP_INTERVAL + resizable, ///< @copydoc PUGL_RESIZABLE + ignoreKeyRepeat, ///< @copydoc PUGL_IGNORE_KEY_REPEAT + refreshRate, ///< @copydoc PUGL_REFRESH_RATE +}; + +static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, ""); + +using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue + +/// @copydoc PuglCursor +enum class Cursor { + arrow, ///< @copydoc PUGL_CURSOR_ARROW + caret, ///< @copydoc PUGL_CURSOR_CARET + crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR + hand, ///< @copydoc PUGL_CURSOR_HAND + no, ///< @copydoc PUGL_CURSOR_NO + leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT + upDown, ///< @copydoc PUGL_CURSOR_UP_DOWN +}; + +static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, ""); + +/// @copydoc PuglView +class View : protected detail::Wrapper +{ +public: + /** + @name Setup + Methods for creating and destroying a view. + @{ + */ + + explicit View(World& world) + : Wrapper{puglNewView(world.cobj())} + , _world(world) + { + PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View"); + } + + const World& world() const noexcept { return _world; } + World& world() noexcept { return _world; } + + /** + Set the object that will be called to handle events. + + This is a type-safe wrapper for the C functions puglSetHandle() and + puglSetEventFunc() that will automatically dispatch events to the + `onEvent` method of `handler` that takes the appropriate event type. + The handler must have such a method defined for every event type, but if + the handler is the view itself, a `using` declaration can be used to + "inherit" the default implementation to avoid having to define every + method. For example: + + @code + class MyView : public pugl::View + { + public: + explicit MyView(pugl::World& world) + : pugl::View{world} + { + setEventHandler(*this); + } + + using pugl::View::onEvent; + + pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; + pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; + }; + @endcode + + This facility is just a convenience, applications may use the C API + directly to set a handle and event function to set up a different + approach for event handling. + */ + template + Status setEventHandler(Handler& handler) + { + puglSetHandle(cobj(), &handler); + return static_cast(puglSetEventFunc(cobj(), eventFunc)); + } + + /// @copydoc puglSetBackend + Status setBackend(const PuglBackend* backend) noexcept + { + return static_cast(puglSetBackend(cobj(), backend)); + } + + /// @copydoc puglSetViewHint + Status setHint(ViewHint hint, int value) noexcept + { + return static_cast( + puglSetViewHint(cobj(), static_cast(hint), value)); + } + + /// @copydoc puglGetViewHint + int getHint(ViewHint hint) noexcept + { + return puglGetViewHint(cobj(), static_cast(hint)); + } + + /** + @} + @name Frame + Methods for working with the position and size of a view. + @{ + */ + + /// @copydoc puglGetFrame + Rect frame() const noexcept { return puglGetFrame(cobj()); } + + /// @copydoc puglSetFrame + Status setFrame(Rect frame) noexcept + { + return static_cast(puglSetFrame(cobj(), frame)); + } + + /// @copydoc puglSetDefaultSize + Status setDefaultSize(int width, int height) noexcept + { + return static_cast(puglSetDefaultSize(cobj(), width, height)); + } + + /// @copydoc puglSetMinSize + Status setMinSize(int width, int height) noexcept + { + return static_cast(puglSetMinSize(cobj(), width, height)); + } + + /// @copydoc puglSetMaxSize + Status setMaxSize(int width, int height) noexcept + { + return static_cast(puglSetMaxSize(cobj(), width, height)); + } + + /// @copydoc puglSetAspectRatio + Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept + { + return static_cast( + puglSetAspectRatio(cobj(), minX, minY, maxX, maxY)); + } + + /** + @} + @name Windows + Methods for working with top-level windows. + @{ + */ + + /// @copydoc puglSetWindowTitle + Status setWindowTitle(const char* title) noexcept + { + return static_cast(puglSetWindowTitle(cobj(), title)); + } + + /// @copydoc puglSetParentWindow + Status setParentWindow(NativeView parent) noexcept + { + return static_cast(puglSetParentWindow(cobj(), parent)); + } + + /// @copydoc puglSetTransientFor + Status setTransientFor(NativeView parent) noexcept + { + return static_cast(puglSetTransientFor(cobj(), parent)); + } + + /// @copydoc puglRealize + Status realize() noexcept { return static_cast(puglRealize(cobj())); } + + /// @copydoc puglShow + Status show() noexcept { return static_cast(puglShow(cobj())); } + + /// @copydoc puglHide + Status hide() noexcept { return static_cast(puglHide(cobj())); } + + /// @copydoc puglGetVisible + bool visible() const noexcept { return puglGetVisible(cobj()); } + + /// @copydoc puglGetNativeWindow + NativeView nativeWindow() noexcept { return puglGetNativeWindow(cobj()); } + + /** + @} + @name Graphics + Methods for working with the graphics context and scheduling + redisplays. + @{ + */ + + /// @copydoc puglGetContext + void* context() noexcept { return puglGetContext(cobj()); } + + /// @copydoc puglPostRedisplay + Status postRedisplay() noexcept + { + return static_cast(puglPostRedisplay(cobj())); + } + + /// @copydoc puglPostRedisplayRect + Status postRedisplayRect(const Rect rect) noexcept + { + return static_cast(puglPostRedisplayRect(cobj(), rect)); + } + + /** + @} + @name Interaction + Methods for interacting with the user and window system. + @{ + */ + + /// @copydoc puglGrabFocus + Status grabFocus() noexcept + { + return static_cast(puglGrabFocus(cobj())); + } + + /// @copydoc puglHasFocus + bool hasFocus() const noexcept { return puglHasFocus(cobj()); } + + /// @copydoc puglSetCursor + Status setCursor(const Cursor cursor) noexcept + { + return static_cast( + puglSetCursor(cobj(), static_cast(cursor))); + } + + /// @copydoc puglRequestAttention + Status requestAttention() noexcept + { + return static_cast(puglRequestAttention(cobj())); + } + + /** + Activate a repeating timer event. + + This starts a timer which will send a timer event to `view` every + `timeout` seconds. This can be used to perform some action in a view at a + regular interval with relatively low frequency. Note that the frequency + of timer events may be limited by how often update() is called. + + If the given timer already exists, it is replaced. + + @param id The identifier for this timer. This is an application-specific + ID that should be a low number, typically the value of a constant or `enum` + that starts from 0. There is a platform-specific limit to the number of + supported timers, and overhead associated with each, so applications should + create only a few timers and perform several tasks in one if necessary. + + @param timeout The period, in seconds, of this timer. This is not + guaranteed to have a resolution better than 10ms (the maximum timer + resolution on Windows) and may be rounded up if it is too short. On X11 + and MacOS, a resolution of about 1ms can usually be relied on. + + @return #PUGL_FAILURE if timers are not supported by the system, + #PUGL_UNKNOWN_ERROR if setting the timer failed. + */ + Status startTimer(const uintptr_t id, const double timeout) noexcept + { + return static_cast(puglStartTimer(cobj(), id, timeout)); + } + + /** + Stop an active timer. + + @param id The ID previously passed to startTimer(). + + @return #PUGL_FAILURE if timers are not supported by this system, + #PUGL_UNKNOWN_ERROR if stopping the timer failed. + */ + Status stopTimer(const uintptr_t id) noexcept + { + return static_cast(puglStopTimer(cobj(), id)); + } + + /** + @} + */ + + PuglView* cobj() noexcept { return Wrapper::cobj(); } + const PuglView* cobj() const noexcept { return Wrapper::cobj(); } + +private: + template + static Status dispatch(Target& target, const PuglEvent* event) + { + switch (event->type) { + case PUGL_NOTHING: + return Status::success; + case PUGL_CREATE: + return target.onEvent(static_cast(event->any)); + case PUGL_DESTROY: + return target.onEvent(static_cast(event->any)); + case PUGL_CONFIGURE: + return target.onEvent( + static_cast(event->configure)); + case PUGL_MAP: + return target.onEvent(static_cast(event->any)); + case PUGL_UNMAP: + return target.onEvent(static_cast(event->any)); + case PUGL_UPDATE: + return target.onEvent(static_cast(event->any)); + case PUGL_EXPOSE: + return target.onEvent(static_cast(event->expose)); + case PUGL_CLOSE: + return target.onEvent(static_cast(event->any)); + case PUGL_FOCUS_IN: + return target.onEvent(static_cast(event->focus)); + case PUGL_FOCUS_OUT: + return target.onEvent(static_cast(event->focus)); + case PUGL_KEY_PRESS: + return target.onEvent(static_cast(event->key)); + case PUGL_KEY_RELEASE: + return target.onEvent(static_cast(event->key)); + case PUGL_TEXT: + return target.onEvent(static_cast(event->text)); + case PUGL_POINTER_IN: + return target.onEvent( + static_cast(event->crossing)); + case PUGL_POINTER_OUT: + return target.onEvent( + static_cast(event->crossing)); + case PUGL_BUTTON_PRESS: + return target.onEvent( + static_cast(event->button)); + case PUGL_BUTTON_RELEASE: + return target.onEvent( + static_cast(event->button)); + case PUGL_MOTION: + return target.onEvent(static_cast(event->motion)); + case PUGL_SCROLL: + return target.onEvent(static_cast(event->scroll)); + case PUGL_CLIENT: + return target.onEvent(static_cast(event->client)); + case PUGL_TIMER: + return target.onEvent(static_cast(event->timer)); + case PUGL_LOOP_ENTER: + return target.onEvent(static_cast(event->any)); + case PUGL_LOOP_LEAVE: + return target.onEvent(static_cast(event->any)); + } + + return Status::failure; + } + + template + static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept + { + auto* target = static_cast(puglGetHandle(view)); + +#ifdef __cpp_exceptions + try { + return static_cast(dispatch(*target, event)); + } catch (...) { + return PUGL_UNKNOWN_ERROR; + } +#else + return static_cast(pugl::dispatch(*target, event)); +#endif + } + + World& _world; +}; + +/** + @} + @} +*/ + +} // namespace pugl + +#endif // PUGL_PUGL_HPP diff --git a/bindings/cpp/include/pugl/stub.hpp b/bindings/cpp/include/pugl/stub.hpp new file mode 100644 index 0000000..e4a33c1 --- /dev/null +++ b/bindings/cpp/include/pugl/stub.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2012-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef PUGL_STUB_HPP +#define PUGL_STUB_HPP + +#include "pugl/pugl.h" +#include "pugl/stub.h" + +namespace pugl { + +/** + @defgroup stubpp Stub + Stub graphics support. + @ingroup puglpp + @{ +*/ + +/// @copydoc puglStubBackend +inline const PuglBackend* +stubBackend() noexcept +{ + return puglStubBackend(); +} + +/** + @} +*/ + +} // namespace pugl + +#endif // PUGL_STUB_HPP diff --git a/bindings/cpp/include/pugl/vulkan.hpp b/bindings/cpp/include/pugl/vulkan.hpp new file mode 100644 index 0000000..d65b2d6 --- /dev/null +++ b/bindings/cpp/include/pugl/vulkan.hpp @@ -0,0 +1,168 @@ +/* + Copyright 2012-2020 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + Note that this header includes Vulkan headers, so if you are writing a + program or plugin that dynamically loads vulkan, you should first define + `VK_NO_PROTOTYPES` before including it. +*/ + +#ifndef PUGL_VULKAN_HPP +#define PUGL_VULKAN_HPP + +#include "pugl/pugl.h" +#include "pugl/pugl.hpp" +#include "pugl/vulkan.h" + +#include + +#include + +namespace pugl { + +/** + @defgroup vulkanpp Vulkan + Vulkan graphics support. + + Note that the Pugl C++ wrapper does not use vulkan-hpp because it is a + heavyweight dependency which not everyone uses, and its design is not very + friendly to dynamic loading in plugins anyway. However, if you do use + vulkan-hpp smart handles, it is relatively straightforward to wrap the + result of createSurface() manually. + + @ingroup puglpp + @{ +*/ + +/// @copydoc PuglVulkanLoader +class VulkanLoader final + : public detail::Wrapper +{ +public: + /** + Create a new dynamic loader for Vulkan functions. + + This dynamically loads the Vulkan library and gets the load functions + from it. + + Note that this constructor does not throw exceptions, though failure is + possible. To check if the Vulkan library failed to load, test this + loader, which is explicitly convertible to `bool`. It is safe to use a + failed loader, but the accessors will always return null. + */ + explicit VulkanLoader(World& world) noexcept + : Wrapper{puglNewVulkanLoader(world.cobj())} + {} + + /** + Return the `vkGetInstanceProcAddr` function. + + @return Null if the Vulkan library failed to load, or does not contain + this function (which is unlikely and indicates a broken system). + */ + PFN_vkGetInstanceProcAddr getInstanceProcAddrFunc() const noexcept + { + return cobj() ? puglGetInstanceProcAddrFunc(cobj()) : nullptr; + } + + /** + Return the `vkGetDeviceProcAddr` function. + + @return Null if the Vulkan library failed to load, or does not contain + this function (which is unlikely and indicates a broken system). + */ + PFN_vkGetDeviceProcAddr getDeviceProcAddrFunc() const noexcept + { + return cobj() ? puglGetDeviceProcAddrFunc(cobj()) : nullptr; + } + + /// Return true if this loader is valid to use + explicit operator bool() const noexcept { return cobj(); } +}; + +/** + A simple wrapper for an array of static C strings. + + This provides a minimal API that supports iteration, like `std::vector`, but + avoids allocation, exceptions, and a dependency on the C++ standard library. +*/ +class StaticStringArray final +{ +public: + using value_type = const char*; + using const_iterator = const char* const*; + using size_type = uint32_t; + + StaticStringArray(const char* const* strings, const uint32_t size) noexcept + : _strings{strings} + , _size{size} + {} + + const char* const* begin() const noexcept { return _strings; } + const char* const* end() const noexcept { return _strings + _size; } + const char* const* data() const noexcept { return _strings; } + uint32_t size() const noexcept { return _size; } + +private: + const char* const* _strings; + uint32_t _size; +}; + +/** + Return the Vulkan instance extensions required to draw to a PuglView. + + If successful, the returned array always contains "VK_KHR_surface", along + with whatever other platform-specific extensions are required. + + @return An array of extension name strings. +*/ +inline StaticStringArray +getInstanceExtensions() noexcept +{ + uint32_t count = 0; + const char* const* const extensions = puglGetInstanceExtensions(&count); + + return StaticStringArray{extensions, count}; +} + +/// @copydoc puglCreateSurface +inline VkResult +createSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, + View& view, + VkInstance instance, + const VkAllocationCallbacks* const allocator, + VkSurfaceKHR* const surface) noexcept +{ + const VkResult r = puglCreateSurface( + vkGetInstanceProcAddr, view.cobj(), instance, allocator, surface); + + return (!r && !surface) ? VK_ERROR_INITIALIZATION_FAILED : r; +} + +/// @copydoc puglVulkanBackend +inline const PuglBackend* +vulkanBackend() noexcept +{ + return puglVulkanBackend(); +} + +/** + @} +*/ + +} // namespace pugl + +#endif // PUGL_VULKAN_HPP -- cgit v1.2.1