diff options
63 files changed, 11434 insertions, 11567 deletions
diff --git a/.clang-format b/.clang-format index a505e26..f0275a9 100644 --- a/.clang-format +++ b/.clang-format @@ -1,127 +1,27 @@ --- -# Language: Cpp -# BasedOnStyle: Mozilla -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: true -AlignEscapedNewlines: Left -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: false -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Inline -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: TopLevel -AlwaysBreakAfterReturnType: TopLevel -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: false -BinPackParameters: false +AlignEscapedNewlinesLeft: true +BasedOnStyle: Mozilla BraceWrapping: - AfterCaseLabel: false - AfterClass: true - AfterControlStatement: false - AfterEnum: false - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: true - AfterStruct: false - AfterUnion: false + AfterNamespace: false + AfterClass: true + AfterEnum: false AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: true + AfterFunction: true + AfterStruct: false + SplitEmptyFunction: false SplitEmptyRecord: false - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeComma -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeComma -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - - Regex: '.*' - Priority: 1 -IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false IndentPPDirectives: AfterHash -IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: false -PenaltyBreakAssignment: 100 -PenaltyBreakBeforeFirstCallParameter: 100 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 0 -PointerAlignment: Left -ReflowComments: true -SortIncludes: true -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Cpp11 +KeepEmptyLinesAtTheStartOfBlocks: false +SpacesInContainerLiterals: false StatementMacros: - PUGL_API + - PUGL_CONST_FUNC - PUGL_DEPRECATED_BY - PUGL_UNUSED -TabWidth: 4 -UseTab: ForIndentation + - _Pragma ... - diff --git a/.editorconfig b/.editorconfig index 5213b6b..c2d35dd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,8 @@ trim_trailing_whitespace = true insert_final_newline = true [*.{c,h,m,cpp,hpp,mm,glsl,frag,vert}] -indent_style = tab +indent_style = space +indent_size = 2 [wscript] indent_style = space diff --git a/bindings/cxx/include/pugl/cairo.hpp b/bindings/cxx/include/pugl/cairo.hpp index 7416589..126bfe3 100644 --- a/bindings/cxx/include/pugl/cairo.hpp +++ b/bindings/cxx/include/pugl/cairo.hpp @@ -33,7 +33,7 @@ namespace pugl { inline const PuglBackend* cairoBackend() noexcept { - return puglCairoBackend(); + return puglCairoBackend(); } /** diff --git a/bindings/cxx/include/pugl/gl.hpp b/bindings/cxx/include/pugl/gl.hpp index d8459a8..c845d80 100644 --- a/bindings/cxx/include/pugl/gl.hpp +++ b/bindings/cxx/include/pugl/gl.hpp @@ -37,28 +37,28 @@ using GlFunc = PuglGlFunc; inline GlFunc getProcAddress(const char* name) noexcept { - return puglGetProcAddress(name); + return puglGetProcAddress(name); } /// @copydoc puglEnterContext inline Status enterContext(View& view) noexcept { - return static_cast<Status>(puglEnterContext(view.cobj())); + return static_cast<Status>(puglEnterContext(view.cobj())); } /// @copydoc puglLeaveContext inline Status leaveContext(View& view) noexcept { - return static_cast<Status>(puglLeaveContext(view.cobj())); + return static_cast<Status>(puglLeaveContext(view.cobj())); } /// @copydoc puglGlBackend inline const PuglBackend* glBackend() noexcept { - return puglGlBackend(); + return puglGlBackend(); } /** diff --git a/bindings/cxx/include/pugl/pugl.hpp b/bindings/cxx/include/pugl/pugl.hpp index 1a07734..9e65589 100644 --- a/bindings/cxx/include/pugl/pugl.hpp +++ b/bindings/cxx/include/pugl/pugl.hpp @@ -22,9 +22,9 @@ #include <cstdint> #if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION) -# include <exception> +# include <exception> #elif defined(PUGL_HPP_ASSERT_CONSTRUCTION) -# include <cassert> +# include <cassert> #endif namespace pugl { @@ -46,34 +46,34 @@ template<class T, FreeFunc<T> Free> class Wrapper { public: - Wrapper(const Wrapper&) = delete; - Wrapper& operator=(const Wrapper&) = delete; + Wrapper(const Wrapper&) = delete; + Wrapper& operator=(const Wrapper&) = delete; - Wrapper(Wrapper&& wrapper) noexcept - : _ptr{wrapper._ptr} - { - wrapper._ptr = nullptr; - } + Wrapper(Wrapper&& wrapper) noexcept + : _ptr{wrapper._ptr} + { + wrapper._ptr = nullptr; + } - Wrapper& operator=(Wrapper&& wrapper) noexcept - { - _ptr = wrapper._ptr; - wrapper._ptr = nullptr; - return *this; - } + Wrapper& operator=(Wrapper&& wrapper) noexcept + { + _ptr = wrapper._ptr; + wrapper._ptr = nullptr; + return *this; + } - ~Wrapper() noexcept { Free(_ptr); } + ~Wrapper() noexcept { Free(_ptr); } - T* cobj() noexcept { return _ptr; } - const T* cobj() const noexcept { return _ptr; } + T* cobj() noexcept { return _ptr; } + const T* cobj() const noexcept { return _ptr; } protected: - explicit Wrapper(T* ptr) noexcept - : _ptr{ptr} - {} + explicit Wrapper(T* ptr) noexcept + : _ptr{ptr} + {} private: - T* _ptr; + T* _ptr; }; } // namespace detail @@ -97,11 +97,11 @@ using Rect = PuglRect; ///< @copydoc PuglRect */ template<PuglEventType t, class Base> struct Event final : Base { - /// The type of the corresponding C event structure - using BaseEvent = 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; + /// The `type` field of the corresponding C event structure + static constexpr const PuglEventType type = t; }; using Mod = PuglMod; ///< @copydoc PuglMod @@ -189,18 +189,18 @@ using LoopLeaveEvent = Event<PUGL_LOOP_LEAVE, PuglEventLoopLeave>; /// @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 + 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, ""); @@ -209,7 +209,7 @@ static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, ""); inline const char* strerror(const Status status) noexcept { - return puglStrerror(static_cast<PuglStatus>(status)); + return puglStrerror(static_cast<PuglStatus>(status)); } /** @@ -220,15 +220,15 @@ strerror(const Status status) noexcept /// @copydoc PuglWorldType enum class WorldType { - program, ///< @copydoc PUGL_PROGRAM - module, ///< @copydoc PUGL_MODULE + 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 + threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS }; static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, ""); @@ -241,25 +241,25 @@ using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags class FailedConstructionError : public std::exception { public: - FailedConstructionError(const char* const msg) noexcept - : _msg{msg} - {} + FailedConstructionError(const char* const msg) noexcept + : _msg{msg} + {} - virtual const char* what() const noexcept override; + virtual const char* what() const noexcept override; private: - const char* _msg; + const char* _msg; }; -# define PUGL_CHECK_CONSTRUCTION(cond, msg) \ - do { \ - if (!(cond)) { \ - throw FailedConstructionError(msg); \ - } \ - } while (0) +# 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); +# define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond); #else /** Configurable macro for handling construction failure. @@ -272,55 +272,55 @@ private: Otherwise, this does nothing. */ -# define PUGL_CHECK_CONSTRUCTION(cond, msg) +# define PUGL_CHECK_CONSTRUCTION(cond, msg) #endif /// @copydoc PuglWorld class World : public detail::Wrapper<PuglWorld, puglFreeWorld> { 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<PuglWorldType>(type), - static_cast<PuglWorldFlags>(flag))} - { - PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); - } - - World(WorldType type, WorldFlags flags) - : Wrapper{puglNewWorld(static_cast<PuglWorldType>(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<Status>(puglSetClassName(cobj(), name)); - } - - /// @copydoc puglGetTime - double time() const noexcept { return puglGetTime(cobj()); } - - /// @copydoc puglUpdate - Status update(const double timeout) noexcept - { - return static_cast<Status>(puglUpdate(cobj(), timeout)); - } + 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<PuglWorldType>(type), + static_cast<PuglWorldFlags>(flag))} + { + PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World"); + } + + World(WorldType type, WorldFlags flags) + : Wrapper{puglNewWorld(static_cast<PuglWorldType>(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<Status>(puglSetClassName(cobj(), name)); + } + + /// @copydoc puglGetTime + double time() const noexcept { return puglGetTime(cobj()); } + + /// @copydoc puglUpdate + Status update(const double timeout) noexcept + { + return static_cast<Status>(puglUpdate(cobj(), timeout)); + } }; /** @@ -334,22 +334,22 @@ 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 + 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, ""); @@ -358,13 +358,13 @@ 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 + 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, ""); @@ -373,332 +373,312 @@ static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, ""); class View : protected detail::Wrapper<PuglView, puglFreeView> { 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<class Handler> - Status setEventHandler(Handler& handler) - { - puglSetHandle(cobj(), &handler); - return static_cast<Status>( - puglSetEventFunc(cobj(), eventFunc<Handler>)); - } - - /// @copydoc puglSetBackend - Status setBackend(const PuglBackend* backend) noexcept - { - return static_cast<Status>(puglSetBackend(cobj(), backend)); - } - - /// @copydoc puglSetViewHint - Status setHint(ViewHint hint, int value) noexcept - { - return static_cast<Status>( - puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value)); - } - - /// @copydoc puglGetViewHint - int getHint(ViewHint hint) noexcept - { - return puglGetViewHint(cobj(), static_cast<PuglViewHint>(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<Status>(puglSetFrame(cobj(), frame)); - } - - /// @copydoc puglSetDefaultSize - Status setDefaultSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetDefaultSize(cobj(), width, height)); - } - - /// @copydoc puglSetMinSize - Status setMinSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetMinSize(cobj(), width, height)); - } - - /// @copydoc puglSetMaxSize - Status setMaxSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetMaxSize(cobj(), width, height)); - } - - /// @copydoc puglSetAspectRatio - Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept - { - return static_cast<Status>( - 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<Status>(puglSetWindowTitle(cobj(), title)); - } - - /// @copydoc puglSetParentWindow - Status setParentWindow(NativeView parent) noexcept - { - return static_cast<Status>(puglSetParentWindow(cobj(), parent)); - } - - /// @copydoc puglSetTransientFor - Status setTransientFor(NativeView parent) noexcept - { - return static_cast<Status>(puglSetTransientFor(cobj(), parent)); - } - - /// @copydoc puglRealize - Status realize() noexcept - { - return static_cast<Status>(puglRealize(cobj())); - } - - /// @copydoc puglShow - Status show() noexcept - { - return static_cast<Status>(puglShow(cobj())); - } - - /// @copydoc puglHide - Status hide() noexcept - { - return static_cast<Status>(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<Status>(puglPostRedisplay(cobj())); - } - - /// @copydoc puglPostRedisplayRect - Status postRedisplayRect(const Rect rect) noexcept - { - return static_cast<Status>(puglPostRedisplayRect(cobj(), rect)); - } - - /** - @} - @name Interaction - Methods for interacting with the user and window system. - @{ - */ - - /// @copydoc puglGrabFocus - Status grabFocus() noexcept - { - return static_cast<Status>(puglGrabFocus(cobj())); - } - - /// @copydoc puglHasFocus - bool hasFocus() const noexcept { return puglHasFocus(cobj()); } - - /// @copydoc puglSetCursor - Status setCursor(const Cursor cursor) noexcept - { - return static_cast<Status>( - puglSetCursor(cobj(), static_cast<PuglCursor>(cursor))); - } - - /// @copydoc puglRequestAttention - Status requestAttention() noexcept - { - return static_cast<Status>(puglRequestAttention(cobj())); - } - - /// @copydoc puglStartTimer - Status startTimer(const uintptr_t id, const double timeout) noexcept - { - return static_cast<Status>(puglStartTimer(cobj(), id, timeout)); - } - - /// @copydoc puglStopTimer - Status stopTimer(const uintptr_t id) noexcept - { - return static_cast<Status>(puglStopTimer(cobj(), id)); - } - - /** - @} - */ - - PuglView* cobj() noexcept { return Wrapper::cobj(); } - const PuglView* cobj() const noexcept { return Wrapper::cobj(); } + /** + @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<class Handler> + Status setEventHandler(Handler& handler) + { + puglSetHandle(cobj(), &handler); + return static_cast<Status>(puglSetEventFunc(cobj(), eventFunc<Handler>)); + } + + /// @copydoc puglSetBackend + Status setBackend(const PuglBackend* backend) noexcept + { + return static_cast<Status>(puglSetBackend(cobj(), backend)); + } + + /// @copydoc puglSetViewHint + Status setHint(ViewHint hint, int value) noexcept + { + return static_cast<Status>( + puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value)); + } + + /// @copydoc puglGetViewHint + int getHint(ViewHint hint) noexcept + { + return puglGetViewHint(cobj(), static_cast<PuglViewHint>(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<Status>(puglSetFrame(cobj(), frame)); + } + + /// @copydoc puglSetDefaultSize + Status setDefaultSize(int width, int height) noexcept + { + return static_cast<Status>(puglSetDefaultSize(cobj(), width, height)); + } + + /// @copydoc puglSetMinSize + Status setMinSize(int width, int height) noexcept + { + return static_cast<Status>(puglSetMinSize(cobj(), width, height)); + } + + /// @copydoc puglSetMaxSize + Status setMaxSize(int width, int height) noexcept + { + return static_cast<Status>(puglSetMaxSize(cobj(), width, height)); + } + + /// @copydoc puglSetAspectRatio + Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept + { + return static_cast<Status>( + 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<Status>(puglSetWindowTitle(cobj(), title)); + } + + /// @copydoc puglSetParentWindow + Status setParentWindow(NativeView parent) noexcept + { + return static_cast<Status>(puglSetParentWindow(cobj(), parent)); + } + + /// @copydoc puglSetTransientFor + Status setTransientFor(NativeView parent) noexcept + { + return static_cast<Status>(puglSetTransientFor(cobj(), parent)); + } + + /// @copydoc puglRealize + Status realize() noexcept { return static_cast<Status>(puglRealize(cobj())); } + + /// @copydoc puglShow + Status show() noexcept { return static_cast<Status>(puglShow(cobj())); } + + /// @copydoc puglHide + Status hide() noexcept { return static_cast<Status>(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<Status>(puglPostRedisplay(cobj())); + } + + /// @copydoc puglPostRedisplayRect + Status postRedisplayRect(const Rect rect) noexcept + { + return static_cast<Status>(puglPostRedisplayRect(cobj(), rect)); + } + + /** + @} + @name Interaction + Methods for interacting with the user and window system. + @{ + */ + + /// @copydoc puglGrabFocus + Status grabFocus() noexcept + { + return static_cast<Status>(puglGrabFocus(cobj())); + } + + /// @copydoc puglHasFocus + bool hasFocus() const noexcept { return puglHasFocus(cobj()); } + + /// @copydoc puglSetCursor + Status setCursor(const Cursor cursor) noexcept + { + return static_cast<Status>( + puglSetCursor(cobj(), static_cast<PuglCursor>(cursor))); + } + + /// @copydoc puglRequestAttention + Status requestAttention() noexcept + { + return static_cast<Status>(puglRequestAttention(cobj())); + } + + /// @copydoc puglStartTimer + Status startTimer(const uintptr_t id, const double timeout) noexcept + { + return static_cast<Status>(puglStartTimer(cobj(), id, timeout)); + } + + /// @copydoc puglStopTimer + Status stopTimer(const uintptr_t id) noexcept + { + return static_cast<Status>(puglStopTimer(cobj(), id)); + } + + /** + @} + */ + + PuglView* cobj() noexcept { return Wrapper::cobj(); } + const PuglView* cobj() const noexcept { return Wrapper::cobj(); } private: - template<class Target> - 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<const CreateEvent&>(event->any)); - case PUGL_DESTROY: - return target.onEvent(static_cast<const DestroyEvent&>(event->any)); - case PUGL_CONFIGURE: - return target.onEvent( - static_cast<const ConfigureEvent&>(event->configure)); - case PUGL_MAP: - return target.onEvent(static_cast<const MapEvent&>(event->any)); - case PUGL_UNMAP: - return target.onEvent(static_cast<const UnmapEvent&>(event->any)); - case PUGL_UPDATE: - return target.onEvent(static_cast<const UpdateEvent&>(event->any)); - case PUGL_EXPOSE: - return target.onEvent( - static_cast<const ExposeEvent&>(event->expose)); - case PUGL_CLOSE: - return target.onEvent(static_cast<const CloseEvent&>(event->any)); - case PUGL_FOCUS_IN: - return target.onEvent( - static_cast<const FocusInEvent&>(event->focus)); - case PUGL_FOCUS_OUT: - return target.onEvent( - static_cast<const FocusOutEvent&>(event->focus)); - case PUGL_KEY_PRESS: - return target.onEvent( - static_cast<const KeyPressEvent&>(event->key)); - case PUGL_KEY_RELEASE: - return target.onEvent( - static_cast<const KeyReleaseEvent&>(event->key)); - case PUGL_TEXT: - return target.onEvent(static_cast<const TextEvent&>(event->text)); - case PUGL_POINTER_IN: - return target.onEvent( - static_cast<const PointerInEvent&>(event->crossing)); - case PUGL_POINTER_OUT: - return target.onEvent( - static_cast<const PointerOutEvent&>(event->crossing)); - case PUGL_BUTTON_PRESS: - return target.onEvent( - static_cast<const ButtonPressEvent&>(event->button)); - case PUGL_BUTTON_RELEASE: - return target.onEvent( - static_cast<const ButtonReleaseEvent&>(event->button)); - case PUGL_MOTION: - return target.onEvent( - static_cast<const MotionEvent&>(event->motion)); - case PUGL_SCROLL: - return target.onEvent( - static_cast<const ScrollEvent&>(event->scroll)); - case PUGL_CLIENT: - return target.onEvent( - static_cast<const ClientEvent&>(event->client)); - case PUGL_TIMER: - return target.onEvent(static_cast<const TimerEvent&>(event->timer)); - case PUGL_LOOP_ENTER: - return target.onEvent( - static_cast<const LoopEnterEvent&>(event->any)); - case PUGL_LOOP_LEAVE: - return target.onEvent( - static_cast<const LoopLeaveEvent&>(event->any)); - } - - return Status::failure; - } - - template<class Target> - static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept - { - auto* target = static_cast<Target*>(puglGetHandle(view)); + template<class Target> + 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<const CreateEvent&>(event->any)); + case PUGL_DESTROY: + return target.onEvent(static_cast<const DestroyEvent&>(event->any)); + case PUGL_CONFIGURE: + return target.onEvent( + static_cast<const ConfigureEvent&>(event->configure)); + case PUGL_MAP: + return target.onEvent(static_cast<const MapEvent&>(event->any)); + case PUGL_UNMAP: + return target.onEvent(static_cast<const UnmapEvent&>(event->any)); + case PUGL_UPDATE: + return target.onEvent(static_cast<const UpdateEvent&>(event->any)); + case PUGL_EXPOSE: + return target.onEvent(static_cast<const ExposeEvent&>(event->expose)); + case PUGL_CLOSE: + return target.onEvent(static_cast<const CloseEvent&>(event->any)); + case PUGL_FOCUS_IN: + return target.onEvent(static_cast<const FocusInEvent&>(event->focus)); + case PUGL_FOCUS_OUT: + return target.onEvent(static_cast<const FocusOutEvent&>(event->focus)); + case PUGL_KEY_PRESS: + return target.onEvent(static_cast<const KeyPressEvent&>(event->key)); + case PUGL_KEY_RELEASE: + return target.onEvent(static_cast<const KeyReleaseEvent&>(event->key)); + case PUGL_TEXT: + return target.onEvent(static_cast<const TextEvent&>(event->text)); + case PUGL_POINTER_IN: + return target.onEvent( + static_cast<const PointerInEvent&>(event->crossing)); + case PUGL_POINTER_OUT: + return target.onEvent( + static_cast<const PointerOutEvent&>(event->crossing)); + case PUGL_BUTTON_PRESS: + return target.onEvent( + static_cast<const ButtonPressEvent&>(event->button)); + case PUGL_BUTTON_RELEASE: + return target.onEvent( + static_cast<const ButtonReleaseEvent&>(event->button)); + case PUGL_MOTION: + return target.onEvent(static_cast<const MotionEvent&>(event->motion)); + case PUGL_SCROLL: + return target.onEvent(static_cast<const ScrollEvent&>(event->scroll)); + case PUGL_CLIENT: + return target.onEvent(static_cast<const ClientEvent&>(event->client)); + case PUGL_TIMER: + return target.onEvent(static_cast<const TimerEvent&>(event->timer)); + case PUGL_LOOP_ENTER: + return target.onEvent(static_cast<const LoopEnterEvent&>(event->any)); + case PUGL_LOOP_LEAVE: + return target.onEvent(static_cast<const LoopLeaveEvent&>(event->any)); + } + + return Status::failure; + } + + template<class Target> + static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept + { + auto* target = static_cast<Target*>(puglGetHandle(view)); #ifdef __cpp_exceptions - try { - return static_cast<PuglStatus>(dispatch(*target, event)); - } catch (...) { - return PUGL_UNKNOWN_ERROR; - } + try { + return static_cast<PuglStatus>(dispatch(*target, event)); + } catch (...) { + return PUGL_UNKNOWN_ERROR; + } #else - return static_cast<PuglStatus>(pugl::dispatch(*target, event)); + return static_cast<PuglStatus>(pugl::dispatch(*target, event)); #endif - } + } - World& _world; + World& _world; }; /** diff --git a/bindings/cxx/include/pugl/stub.hpp b/bindings/cxx/include/pugl/stub.hpp index 8b37da4..6946fe0 100644 --- a/bindings/cxx/include/pugl/stub.hpp +++ b/bindings/cxx/include/pugl/stub.hpp @@ -33,7 +33,7 @@ namespace pugl { inline const PuglBackend* stubBackend() noexcept { - return puglStubBackend(); + return puglStubBackend(); } /** diff --git a/bindings/cxx/include/pugl/vulkan.hpp b/bindings/cxx/include/pugl/vulkan.hpp index 65d1e57..21341b3 100644 --- a/bindings/cxx/include/pugl/vulkan.hpp +++ b/bindings/cxx/include/pugl/vulkan.hpp @@ -49,48 +49,48 @@ namespace pugl { /// @copydoc PuglVulkanLoader class VulkanLoader final - : public detail::Wrapper<PuglVulkanLoader, puglFreeVulkanLoader> + : public detail::Wrapper<PuglVulkanLoader, puglFreeVulkanLoader> { 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(); } + /** + 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(); } }; /** @@ -102,23 +102,23 @@ public: class StaticStringArray final { public: - using value_type = const char*; - using const_iterator = const char* const*; - using size_type = uint32_t; + 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} - {} + 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; } + 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; + const char* const* _strings; + uint32_t _size; }; /** @@ -132,10 +132,10 @@ private: inline StaticStringArray getInstanceExtensions() noexcept { - uint32_t count = 0; - const char* const* const extensions = puglGetInstanceExtensions(&count); + uint32_t count = 0; + const char* const* const extensions = puglGetInstanceExtensions(&count); - return StaticStringArray{extensions, count}; + return StaticStringArray{extensions, count}; } /// @copydoc puglCreateSurface @@ -146,17 +146,17 @@ createSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, const VkAllocationCallbacks* const allocator, VkSurfaceKHR* const surface) noexcept { - const VkResult r = puglCreateSurface( - vkGetInstanceProcAddr, view.cobj(), instance, allocator, surface); + const VkResult r = puglCreateSurface( + vkGetInstanceProcAddr, view.cobj(), instance, allocator, surface); - return (!r && !surface) ? VK_ERROR_INITIALIZATION_FAILED : r; + return (!r && !surface) ? VK_ERROR_INITIALIZATION_FAILED : r; } /// @copydoc puglVulkanBackend inline const PuglBackend* vulkanBackend() noexcept { - return puglVulkanBackend(); + return puglVulkanBackend(); } /** diff --git a/examples/cube_view.h b/examples/cube_view.h index 87bf3b5..e0c86eb 100644 --- a/examples/cube_view.h +++ b/examples/cube_view.h @@ -26,48 +26,48 @@ // clang-format off static const float cubeStripVertices[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - -1.0f, -1.0f, 1.0f, // Front bottom left - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f // Back top right + -1.0f, 1.0f, 1.0f, // Front top left + 1.0f, 1.0f, 1.0f, // Front top right + -1.0f, -1.0f, 1.0f, // Front bottom left + 1.0f, -1.0f, 1.0f, // Front bottom right + 1.0f, -1.0f, -1.0f, // Back bottom right + 1.0f, 1.0f, 1.0f, // Front top right + 1.0f, 1.0f, -1.0f, // Back top right + -1.0f, 1.0f, 1.0f, // Front top left + -1.0f, 1.0f, -1.0f, // Back top left + -1.0f, -1.0f, 1.0f, // Front bottom left + -1.0f, -1.0f, -1.0f, // Back bottom left + 1.0f, -1.0f, -1.0f, // Back bottom right + -1.0f, 1.0f, -1.0f, // Back top left + 1.0f, 1.0f, -1.0f // Back top right }; static const float cubeFrontLineLoop[] = { - -1.0f, 1.0f, 1.0f, // Front top left - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, -1.0f, 1.0f, // Front bottom right - -1.0f, -1.0f, 1.0f, // Front bottom left + -1.0f, 1.0f, 1.0f, // Front top left + 1.0f, 1.0f, 1.0f, // Front top right + 1.0f, -1.0f, 1.0f, // Front bottom right + -1.0f, -1.0f, 1.0f, // Front bottom left }; static const float cubeBackLineLoop[] = { - -1.0f, 1.0f, -1.0f, // Back top left - 1.0f, 1.0f, -1.0f, // Back top right - 1.0f, -1.0f, -1.0f, // Back bottom right - -1.0f, -1.0f, -1.0f, // Back bottom left + -1.0f, 1.0f, -1.0f, // Back top left + 1.0f, 1.0f, -1.0f, // Back top right + 1.0f, -1.0f, -1.0f, // Back bottom right + -1.0f, -1.0f, -1.0f, // Back bottom left }; static const float cubeSideLines[] = { - -1.0f, 1.0f, 1.0f, // Front top left - -1.0f, 1.0f, -1.0f, // Back top left + -1.0f, 1.0f, 1.0f, // Front top left + -1.0f, 1.0f, -1.0f, // Back top left - -1.0f, -1.0f, 1.0f, // Front bottom left - -1.0f, -1.0f, -1.0f, // Back bottom left + -1.0f, -1.0f, 1.0f, // Front bottom left + -1.0f, -1.0f, -1.0f, // Back bottom left - 1.0f, 1.0f, 1.0f, // Front top right - 1.0f, 1.0f, -1.0f, // Back top right + 1.0f, 1.0f, 1.0f, // Front top right + 1.0f, 1.0f, -1.0f, // Back top right - 1.0f, -1.0f, 1.0f, // Front bottom right - 1.0f, -1.0f, -1.0f, // Back bottom right + 1.0f, -1.0f, 1.0f, // Front bottom right + 1.0f, -1.0f, -1.0f, // Back bottom right }; // clang-format on @@ -75,19 +75,19 @@ static const float cubeSideLines[] = { static inline void reshapeCube(const float width, const float height) { - const float aspect = width / height; + const float aspect = width / height; - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, (int)width, (int)height); - float projection[16]; - perspective(projection, 1.8f, aspect, 1.0f, 100.0f); - glLoadMatrixf(projection); + float projection[16]; + perspective(projection, 1.8f, aspect, 1.0f, 100.0f); + glLoadMatrixf(projection); } static inline void @@ -97,40 +97,40 @@ displayCube(PuglView* const view, const float yAngle, const bool entered) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, distance * -1.0f); - glRotatef(xAngle, 0.0f, 1.0f, 0.0f); - glRotatef(yAngle, 1.0f, 0.0f, 0.0f); - - const float bg = entered ? 0.2f : 0.0f; - glClearColor(bg, bg, bg, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (puglHasFocus(view)) { - // Draw cube surfaces - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeStripVertices); - glColorPointer(3, GL_FLOAT, 0, cubeStripVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 14); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - - glColor3f(0.0f, 0.0f, 0.0f); - } else { - glColor3f(1.0f, 1.0f, 1.0f); - } - - // Draw cube wireframe - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, cubeFrontLineLoop); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeBackLineLoop); - glDrawArrays(GL_LINE_LOOP, 0, 4); - glVertexPointer(3, GL_FLOAT, 0, cubeSideLines); - glDrawArrays(GL_LINES, 0, 8); - glDisableClientState(GL_VERTEX_ARRAY); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, distance * -1.0f); + glRotatef(xAngle, 0.0f, 1.0f, 0.0f); + glRotatef(yAngle, 1.0f, 0.0f, 0.0f); + + const float bg = entered ? 0.2f : 0.0f; + glClearColor(bg, bg, bg, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (puglHasFocus(view)) { + // Draw cube surfaces + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, cubeStripVertices); + glColorPointer(3, GL_FLOAT, 0, cubeStripVertices); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 14); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + glColor3f(0.0f, 0.0f, 0.0f); + } else { + glColor3f(1.0f, 1.0f, 1.0f); + } + + // Draw cube wireframe + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, cubeFrontLineLoop); + glDrawArrays(GL_LINE_LOOP, 0, 4); + glVertexPointer(3, GL_FLOAT, 0, cubeBackLineLoop); + glDrawArrays(GL_LINE_LOOP, 0, 4); + glVertexPointer(3, GL_FLOAT, 0, cubeSideLines); + glDrawArrays(GL_LINES, 0, 8); + glDisableClientState(GL_VERTEX_ARRAY); } #endif // EXAMPLES_CUBE_VIEW_H diff --git a/examples/demo_utils.h b/examples/demo_utils.h index 9057a32..e76d304 100644 --- a/examples/demo_utils.h +++ b/examples/demo_utils.h @@ -25,7 +25,7 @@ #include <string.h> typedef struct { - double lastReportTime; + double lastReportTime; } PuglFpsPrinter; typedef float vec4[4]; @@ -34,32 +34,32 @@ typedef vec4 mat4[4]; static inline void mat4Identity(mat4 m) { - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = c == r ? 1.0f : 0.0f; - } - } + for (int c = 0; c < 4; ++c) { + for (int r = 0; r < 4; ++r) { + m[c][r] = c == r ? 1.0f : 0.0f; + } + } } static inline void mat4Translate(mat4 m, const float x, const float y, const float z) { - m[3][0] = x; - m[3][1] = y; - m[3][2] = z; + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; } static inline void mat4Mul(mat4 m, mat4 a, mat4 b) { - for (int c = 0; c < 4; ++c) { - for (int r = 0; r < 4; ++r) { - m[c][r] = 0.0f; - for (int k = 0; k < 4; ++k) { - m[c][r] += a[k][r] * b[c][k]; - } - } - } + for (int c = 0; c < 4; ++c) { + for (int r = 0; r < 4; ++r) { + m[c][r] = 0.0f; + for (int k = 0; k < 4; ++k) { + m[c][r] += a[k][r] * b[c][k]; + } + } + } } static inline void @@ -71,37 +71,37 @@ mat4Ortho(mat4 m, const float n, const float f) { - m[0][0] = 2.0f / (r - l); - m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[0][0] = 2.0f / (r - l); + m[0][1] = m[0][2] = m[0][3] = 0.0f; - m[1][1] = 2.0f / (t - b); - m[1][0] = m[1][2] = m[1][3] = 0.0f; + m[1][1] = 2.0f / (t - b); + m[1][0] = m[1][2] = m[1][3] = 0.0f; - m[2][2] = -2.0f / (f - n); - m[2][0] = m[2][1] = m[2][3] = 0.0f; + m[2][2] = -2.0f / (f - n); + m[2][0] = m[2][1] = m[2][3] = 0.0f; - m[3][0] = -(r + l) / (r - l); - m[3][1] = -(t + b) / (t - b); - m[3][2] = -(f + n) / (f - n); - m[3][3] = 1.0f; + m[3][0] = -(r + l) / (r - l); + m[3][1] = -(t + b) / (t - b); + m[3][2] = -(f + n) / (f - n); + m[3][3] = 1.0f; } /// Calculate a projection matrix for a given perspective static inline void perspective(float* m, float fov, float aspect, float zNear, float zFar) { - const float h = tanf(fov); - const float w = h / aspect; - const float depth = zNear - zFar; - const float q = (zFar + zNear) / depth; - const float qn = 2 * zFar * zNear / depth; - - // clang-format off - m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0; - m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0; - m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1; - m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0; - // clang-format on + const float h = tanf(fov); + const float w = h / aspect; + const float depth = zNear - zFar; + const float q = (zFar + zNear) / depth; + const float qn = 2 * zFar * zNear / depth; + + // clang-format off + m[0] = w; m[1] = 0; m[2] = 0; m[3] = 0; + m[4] = 0; m[5] = h; m[6] = 0; m[7] = 0; + m[8] = 0; m[9] = 0; m[10] = q; m[11] = -1; + m[12] = 0; m[13] = 0; m[14] = qn; m[15] = 0; + // clang-format on } static inline void @@ -109,18 +109,18 @@ puglPrintFps(const PuglWorld* world, PuglFpsPrinter* printer, unsigned* const framesDrawn) { - const double thisTime = puglGetTime(world); - if (thisTime > printer->lastReportTime + 5) { - const double fps = *framesDrawn / (thisTime - printer->lastReportTime); - fprintf(stderr, - "FPS: %.2f (%u frames in %.0f seconds)\n", - fps, - *framesDrawn, - thisTime - printer->lastReportTime); - - printer->lastReportTime = thisTime; - *framesDrawn = 0; - } + const double thisTime = puglGetTime(world); + if (thisTime > printer->lastReportTime + 5) { + const double fps = *framesDrawn / (thisTime - printer->lastReportTime); + fprintf(stderr, + "FPS: %.2f (%u frames in %.0f seconds)\n", + fps, + *framesDrawn, + thisTime - printer->lastReportTime); + + printer->lastReportTime = thisTime; + *framesDrawn = 0; + } } #endif // EXAMPLES_DEMO_UTILS_H diff --git a/examples/file_utils.c b/examples/file_utils.c index 2b00bdc..8ecbca4 100644 --- a/examples/file_utils.c +++ b/examples/file_utils.c @@ -15,18 +15,18 @@ */ #if !defined(__APPLE__) && !defined(_GNU_SOURCE) -# define _GNU_SOURCE +# define _GNU_SOURCE #endif #include "file_utils.h" #ifdef _WIN32 -# include <io.h> -# include <windows.h> -# define F_OK 0 +# include <io.h> +# include <windows.h> +# define F_OK 0 #else -# include <libgen.h> -# include <unistd.h> +# include <libgen.h> +# include <unistd.h> #endif #include <stdio.h> @@ -36,33 +36,33 @@ char* resourcePath(const char* const programPath, const char* const name) { - char* const binary = strdup(programPath); + char* const binary = strdup(programPath); #ifdef _WIN32 - char programDir[_MAX_DIR]; - _splitpath(binary, programDir, NULL, NULL, NULL); - _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL); - programDir[strlen(programDir) - 1] = '\0'; + char programDir[_MAX_DIR]; + _splitpath(binary, programDir, NULL, NULL, NULL); + _splitpath(binary, NULL, programDir + strlen(programDir), NULL, NULL); + programDir[strlen(programDir) - 1] = '\0'; #else - char* const programDir = dirname(binary); + char* const programDir = dirname(binary); #endif - const size_t programDirLen = strlen(programDir); - const size_t nameLen = strlen(name); - const size_t totalLen = programDirLen + nameLen + 4; + const size_t programDirLen = strlen(programDir); + const size_t nameLen = strlen(name); + const size_t totalLen = programDirLen + nameLen + 4; - char* const programRelative = (char*)calloc(totalLen, 1); - snprintf(programRelative, totalLen, "%s/%s", programDir, name); - if (!access(programRelative, F_OK)) { - free(binary); - return programRelative; - } + char* const programRelative = (char*)calloc(totalLen, 1); + snprintf(programRelative, totalLen, "%s/%s", programDir, name); + if (!access(programRelative, F_OK)) { + free(binary); + return programRelative; + } - free(programRelative); - free(binary); + free(programRelative); + free(binary); - const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4; - char* const sysPath = (char*)calloc(sysPathLen, 1); - snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name); - return sysPath; + const size_t sysPathLen = strlen(PUGL_DATA_DIR) + nameLen + 4; + char* const sysPath = (char*)calloc(sysPathLen, 1); + snprintf(sysPath, sysPathLen, "%s/%s", PUGL_DATA_DIR, name); + return sysPath; } diff --git a/examples/pugl_cairo_demo.c b/examples/pugl_cairo_demo.c index 48a02db..4da0caf 100644 --- a/examples/pugl_cairo_demo.c +++ b/examples/pugl_cairo_demo.c @@ -28,20 +28,20 @@ #include <string.h> typedef struct { - PuglWorld* world; - PuglTestOptions opts; - unsigned framesDrawn; - int quit; - bool entered; - bool mouseDown; + PuglWorld* world; + PuglTestOptions opts; + unsigned framesDrawn; + int quit; + bool entered; + bool mouseDown; } PuglTestApp; typedef struct { - int x; - int y; - int w; - int h; - const char* label; + int x; + int y; + int w; + int h; + const char* label; } Button; static const Button buttons[] = {{128, 128, 64, 64, "1"}, @@ -53,213 +53,208 @@ static const Button buttons[] = {{128, 128, 64, 64, "1"}, static void roundedBox(cairo_t* cr, double x, double y, double w, double h) { - static const double radius = 10; - static const double degrees = 3.14159265 / 180.0; - - cairo_new_sub_path(cr); - cairo_arc(cr, - x + w - radius, - y + radius, - radius, -90 * degrees, 0 * degrees); - cairo_arc(cr, - x + w - radius, y + h - radius, - radius, 0 * degrees, 90 * degrees); - cairo_arc(cr, - x + radius, y + h - radius, - radius, 90 * degrees, 180 * degrees); - cairo_arc(cr, - x + radius, y + radius, - radius, 180 * degrees, 270 * degrees); - cairo_close_path(cr); + static const double radius = 10; + static const double degrees = 3.14159265 / 180.0; + + cairo_new_sub_path(cr); + cairo_arc(cr, x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees); + + cairo_arc( + cr, x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees); + + cairo_arc( + cr, x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees); + + cairo_arc(cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees); + cairo_close_path(cr); } static void buttonDraw(PuglTestApp* app, cairo_t* cr, const Button* but, const double time) { - cairo_save(cr); - cairo_translate(cr, but->x, but->y); - cairo_rotate(cr, sin(time) * 3.141592); - - // Draw base - if (app->mouseDown) { - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - } else { - cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1); - } - roundedBox(cr, 0, 0, but->w, but->h); - cairo_fill_preserve(cr); - - // Draw border - cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); - cairo_set_line_width(cr, 4.0); - cairo_stroke(cr); - - // Draw label - cairo_text_extents_t extents; - cairo_set_font_size(cr, 32.0); - cairo_text_extents(cr, but->label, &extents); - cairo_move_to(cr, - (but->w / 2.0) - extents.width / 2, - (but->h / 2.0) + extents.height / 2); - cairo_set_source_rgba(cr, 0, 0, 0, 1); - cairo_show_text(cr, but->label); - - cairo_restore(cr); + cairo_save(cr); + cairo_translate(cr, but->x, but->y); + cairo_rotate(cr, sin(time) * 3.141592); + + // Draw base + if (app->mouseDown) { + cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); + } else { + cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1); + } + roundedBox(cr, 0, 0, but->w, but->h); + cairo_fill_preserve(cr); + + // Draw border + cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); + cairo_set_line_width(cr, 4.0); + cairo_stroke(cr); + + // Draw label + cairo_text_extents_t extents; + cairo_set_font_size(cr, 32.0); + cairo_text_extents(cr, but->label, &extents); + cairo_move_to(cr, + (but->w / 2.0) - extents.width / 2, + (but->h / 2.0) + extents.height / 2); + cairo_set_source_rgba(cr, 0, 0, 0, 1); + cairo_show_text(cr, but->label); + + cairo_restore(cr); } static void postButtonRedisplay(PuglView* view) { - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - - for (const Button* b = buttons; b->label; ++b) { - const double span = sqrt(b->w * b->w + b->h * b->h); - const PuglRect rect = {(b->x - span) * scaleX, - (b->y - span) * scaleY, - span * 2.0 * scaleX, - span * 2.0 * scaleY}; - - puglPostRedisplayRect(view, rect); - } + const PuglRect frame = puglGetFrame(view); + const double width = frame.width; + const double height = frame.height; + const double scaleX = (width - (512 / width)) / 512.0; + const double scaleY = (height - (512 / height)) / 512.0; + + for (const Button* b = buttons; b->label; ++b) { + const double span = sqrt(b->w * b->w + b->h * b->h); + const PuglRect rect = {(b->x - span) * scaleX, + (b->y - span) * scaleY, + span * 2.0 * scaleX, + span * 2.0 * scaleY}; + + puglPostRedisplayRect(view, rect); + } } static void onDisplay(PuglTestApp* app, PuglView* view, const PuglEventExpose* event) { - cairo_t* cr = (cairo_t*)puglGetContext(view); - - cairo_rectangle(cr, event->x, event->y, event->width, event->height); - cairo_clip_preserve(cr); - - // Draw background - const PuglRect frame = puglGetFrame(view); - const double width = frame.width; - const double height = frame.height; - if (app->entered) { - cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); - } else { - cairo_set_source_rgb(cr, 0, 0, 0); - } - cairo_fill(cr); - - // Scale to view size - const double scaleX = (width - (512 / width)) / 512.0; - const double scaleY = (height - (512 / height)) / 512.0; - cairo_scale(cr, scaleX, scaleY); - - // Draw button - for (const Button* b = buttons; b->label; ++b) { - buttonDraw(app, - cr, - b, - app->opts.continuous ? puglGetTime(app->world) : 0.0); - } - - ++app->framesDrawn; + cairo_t* cr = (cairo_t*)puglGetContext(view); + + cairo_rectangle(cr, event->x, event->y, event->width, event->height); + cairo_clip_preserve(cr); + + // Draw background + const PuglRect frame = puglGetFrame(view); + const double width = frame.width; + const double height = frame.height; + if (app->entered) { + cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); + } else { + cairo_set_source_rgb(cr, 0, 0, 0); + } + cairo_fill(cr); + + // Scale to view size + const double scaleX = (width - (512 / width)) / 512.0; + const double scaleY = (height - (512 / height)) / 512.0; + cairo_scale(cr, scaleX, scaleY); + + // Draw button + for (const Button* b = buttons; b->label; ++b) { + buttonDraw( + app, cr, b, app->opts.continuous ? puglGetTime(app->world) : 0.0); + } + + ++app->framesDrawn; } static void onClose(PuglView* view) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - app->quit = 1; + app->quit = 1; } static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_BUTTON_PRESS: - app->mouseDown = true; - postButtonRedisplay(view); - break; - case PUGL_BUTTON_RELEASE: - app->mouseDown = false; - postButtonRedisplay(view); - break; - case PUGL_POINTER_IN: - app->entered = true; - puglPostRedisplay(view); - break; - case PUGL_POINTER_OUT: - app->entered = false; - puglPostRedisplay(view); - break; - case PUGL_UPDATE: - if (app->opts.continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(app, view, &event->expose); - break; - case PUGL_CLOSE: - onClose(view); - break; - default: break; - } - - return PUGL_SUCCESS; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + + printEvent(event, "Event: ", app->opts.verbose); + + switch (event->type) { + case PUGL_KEY_PRESS: + if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } + break; + case PUGL_BUTTON_PRESS: + app->mouseDown = true; + postButtonRedisplay(view); + break; + case PUGL_BUTTON_RELEASE: + app->mouseDown = false; + postButtonRedisplay(view); + break; + case PUGL_POINTER_IN: + app->entered = true; + puglPostRedisplay(view); + break; + case PUGL_POINTER_OUT: + app->entered = false; + puglPostRedisplay(view); + break; + case PUGL_UPDATE: + if (app->opts.continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_EXPOSE: + onDisplay(app, view, &event->expose); + break; + case PUGL_CLOSE: + onClose(view); + break; + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTestApp app; - memset(&app, 0, sizeof(app)); - - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - puglSetClassName(app.world, "PuglCairoTest"); - - PuglView* view = puglNewView(app.world); - - puglSetWindowTitle(view, "Pugl Cairo Demo"); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 256, 256); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetHandle(view, &app); - puglSetBackend(view, puglCairoBackend()); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetEventFunc(view, onEvent); - - PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - - PuglFpsPrinter fpsPrinter = { puglGetTime(app.world) }; - const double timeout = app.opts.continuous ? (1 / 60.0) : -1.0; - while (!app.quit) { - puglUpdate(app.world, timeout); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - puglFreeView(view); - puglFreeWorld(app.world); - return 0; + PuglTestApp app; + memset(&app, 0, sizeof(app)); + + app.opts = puglParseTestOptions(&argc, &argv); + if (app.opts.help) { + puglPrintTestUsage("pugl_test", ""); + return 1; + } + + app.world = puglNewWorld(PUGL_PROGRAM, 0); + puglSetClassName(app.world, "PuglCairoTest"); + + PuglView* view = puglNewView(app.world); + + puglSetWindowTitle(view, "Pugl Cairo Demo"); + puglSetDefaultSize(view, 512, 512); + puglSetMinSize(view, 256, 256); + puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); + puglSetHandle(view, &app); + puglSetBackend(view, puglCairoBackend()); + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); + puglSetEventFunc(view, onEvent); + + PuglStatus st = puglRealize(view); + if (st) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } + + puglShow(view); + + PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; + const double timeout = app.opts.continuous ? (1 / 60.0) : -1.0; + while (!app.quit) { + puglUpdate(app.world, timeout); + + if (app.opts.continuous) { + puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); + } + } + + puglFreeView(view); + puglFreeWorld(app.world); + return 0; } diff --git a/examples/pugl_cursor_demo.c b/examples/pugl_cursor_demo.c index f20b0ea..60ec3d3 100644 --- a/examples/pugl_cursor_demo.c +++ b/examples/pugl_cursor_demo.c @@ -26,143 +26,143 @@ static const int N_ROWS = 2; static const int N_COLS = 4; typedef struct { - PuglWorld* world; - PuglTestOptions opts; - bool quit; + PuglWorld* world; + PuglTestOptions opts; + bool quit; } PuglTestApp; static void onConfigure(const double width, const double height) { - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glViewport(0, 0, (int)width, (int)height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, (int)width, (int)height); } static void onExpose(void) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glColor3f(0.6f, 0.6f, 0.6f); - - for (int row = 1; row < N_ROWS; ++row) { - const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(-1.0f, y); - glVertex2f(1.0f, y); - glEnd(); - } - - for (int col = 1; col < N_COLS; ++col) { - const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f; - glBegin(GL_LINES); - glVertex2f(x, -1.0f); - glVertex2f(x, 1.0f); - glEnd(); - } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glColor3f(0.6f, 0.6f, 0.6f); + + for (int row = 1; row < N_ROWS; ++row) { + const float y = (float)row * (2.0f / (float)N_ROWS) - 1.0f; + glBegin(GL_LINES); + glVertex2f(-1.0f, y); + glVertex2f(1.0f, y); + glEnd(); + } + + for (int col = 1; col < N_COLS; ++col) { + const float x = (float)col * (2.0f / (float)N_COLS) - 1.0f; + glBegin(GL_LINES); + glVertex2f(x, -1.0f); + glVertex2f(x, 1.0f); + glEnd(); + } } static void onMotion(PuglView* view, double x, double y) { - const PuglRect frame = puglGetFrame(view); - int row = (int)(y * N_ROWS / frame.height); - int col = (int)(x * N_COLS / frame.width); + const PuglRect frame = puglGetFrame(view); + int row = (int)(y * N_ROWS / frame.height); + int col = (int)(x * N_COLS / frame.width); - row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row; - col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col; + row = (row < 0) ? 0 : (row >= N_ROWS) ? (N_ROWS - 1) : row; + col = (col < 0) ? 0 : (col >= N_COLS) ? (N_COLS - 1) : col; - const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS); - puglSetCursor(view, cursor); + const PuglCursor cursor = (PuglCursor)((row * N_COLS + col) % N_CURSORS); + puglSetCursor(view, cursor); } static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - onConfigure(event->configure.width, event->configure.height); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_MOTION: - onMotion(view, event->motion.x, event->motion.y); - break; - case PUGL_EXPOSE: - onExpose(); - break; - case PUGL_POINTER_OUT: - puglSetCursor(view, PUGL_CURSOR_ARROW); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + + printEvent(event, "Event: ", app->opts.verbose); + + switch (event->type) { + case PUGL_CONFIGURE: + onConfigure(event->configure.width, event->configure.height); + break; + case PUGL_KEY_PRESS: + if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } + break; + case PUGL_MOTION: + onMotion(view, event->motion.x, event->motion.y); + break; + case PUGL_EXPOSE: + onExpose(); + break; + case PUGL_POINTER_OUT: + puglSetCursor(view, PUGL_CURSOR_ARROW); + break; + case PUGL_CLOSE: + app->quit = 1; + break; + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTestApp app = {0}; + PuglTestApp app = {0}; - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } + app.opts = puglParseTestOptions(&argc, &argv); + if (app.opts.help) { + puglPrintTestUsage(argv[0], ""); + return 1; + } - app.world = puglNewWorld(PUGL_PROGRAM, 0); + app.world = puglNewWorld(PUGL_PROGRAM, 0); - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); + puglSetWorldHandle(app.world, &app); + puglSetClassName(app.world, "Pugl Test"); - PuglView* view = puglNewView(app.world); + PuglView* view = puglNewView(app.world); - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetDefaultSize(view, 512, 256); - puglSetMinSize(view, 128, 64); - puglSetBackend(view, puglGlBackend()); + puglSetWindowTitle(view, "Pugl Window Demo"); + puglSetDefaultSize(view, 512, 256); + puglSetMinSize(view, 128, 64); + puglSetBackend(view, puglGlBackend()); - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); - puglSetHandle(view, &app); - puglSetEventFunc(view, onEvent); + puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); + puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); + puglSetViewHint(view, PUGL_SAMPLES, app.opts.samples); + puglSetViewHint(view, PUGL_DOUBLE_BUFFER, app.opts.doubleBuffer); + puglSetViewHint(view, PUGL_SWAP_INTERVAL, app.opts.sync); + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, app.opts.ignoreKeyRepeat); + puglSetHandle(view, &app); + puglSetEventFunc(view, onEvent); - const PuglStatus st = puglRealize(view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } + const PuglStatus st = puglRealize(view); + if (st) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } - puglShow(view); + puglShow(view); - while (!app.quit) { - puglUpdate(app.world, -1.0); - } + while (!app.quit) { + puglUpdate(app.world, -1.0); + } - puglFreeView(view); - puglFreeWorld(app.world); + puglFreeView(view); + puglFreeWorld(app.world); - return 0; + return 0; } diff --git a/examples/pugl_cxx_demo.cpp b/examples/pugl_cxx_demo.cpp index 8269ae4..4914724 100644 --- a/examples/pugl_cxx_demo.cpp +++ b/examples/pugl_cxx_demo.cpp @@ -27,121 +27,121 @@ class CubeView : public pugl::View { public: - explicit CubeView(pugl::World& world) - : pugl::View{world} - { - setEventHandler(*this); - } - - template<PuglEventType t, class Base> - pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept - { - return pugl::Status::success; - } - - static pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; - pugl::Status onEvent(const pugl::UpdateEvent& event) noexcept; - pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; - pugl::Status onEvent(const pugl::KeyPressEvent& event) noexcept; - pugl::Status onEvent(const pugl::CloseEvent& event) noexcept; - - bool quit() const { return _quit; } + explicit CubeView(pugl::World& world) + : pugl::View{world} + { + setEventHandler(*this); + } + + template<PuglEventType t, class Base> + pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept + { + return pugl::Status::success; + } + + static pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept; + pugl::Status onEvent(const pugl::UpdateEvent& event) noexcept; + pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept; + pugl::Status onEvent(const pugl::KeyPressEvent& event) noexcept; + pugl::Status onEvent(const pugl::CloseEvent& event) noexcept; + + bool quit() const { return _quit; } private: - double _xAngle{0.0}; - double _yAngle{0.0}; - double _lastDrawTime{0.0}; - bool _quit{false}; + double _xAngle{0.0}; + double _yAngle{0.0}; + double _lastDrawTime{0.0}; + bool _quit{false}; }; pugl::Status CubeView::onEvent(const pugl::ConfigureEvent& event) noexcept { - reshapeCube(static_cast<float>(event.width), - static_cast<float>(event.height)); + reshapeCube(static_cast<float>(event.width), + static_cast<float>(event.height)); - return pugl::Status::success; + return pugl::Status::success; } pugl::Status CubeView::onEvent(const pugl::UpdateEvent&) noexcept { - return postRedisplay(); + return postRedisplay(); } pugl::Status CubeView::onEvent(const pugl::ExposeEvent&) noexcept { - const double thisTime = world().time(); - const double dTime = thisTime - _lastDrawTime; - const double dAngle = dTime * 100.0; + const double thisTime = world().time(); + const double dTime = thisTime - _lastDrawTime; + const double dAngle = dTime * 100.0; - _xAngle = fmod(_xAngle + dAngle, 360.0); - _yAngle = fmod(_yAngle + dAngle, 360.0); - displayCube(cobj(), - 8.0f, - static_cast<float>(_xAngle), - static_cast<float>(_yAngle), - false); + _xAngle = fmod(_xAngle + dAngle, 360.0); + _yAngle = fmod(_yAngle + dAngle, 360.0); + displayCube(cobj(), + 8.0f, + static_cast<float>(_xAngle), + static_cast<float>(_yAngle), + false); - _lastDrawTime = thisTime; + _lastDrawTime = thisTime; - return pugl::Status::success; + return pugl::Status::success; } pugl::Status CubeView::onEvent(const pugl::KeyPressEvent& event) noexcept { - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _quit = true; - } + if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { + _quit = true; + } - return pugl::Status::success; + return pugl::Status::success; } pugl::Status CubeView::onEvent(const pugl::CloseEvent&) noexcept { - _quit = true; + _quit = true; - return pugl::Status::success; + return pugl::Status::success; } int main(int argc, char** argv) { - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_cxx_demo", ""); - return 1; - } - - pugl::World world{pugl::WorldType::program}; - CubeView view{world}; - PuglFpsPrinter fpsPrinter{}; - - world.setClassName("PuglCppTest"); - - view.setWindowTitle("Pugl C++ Test"); - view.setDefaultSize(512, 512); - view.setMinSize(64, 64); - view.setAspectRatio(1, 1, 16, 9); - view.setBackend(pugl::glBackend()); - view.setHint(pugl::ViewHint::resizable, opts.resizable); - view.setHint(pugl::ViewHint::samples, opts.samples); - view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer); - view.setHint(pugl::ViewHint::swapInterval, opts.sync); - view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat); - view.realize(); - view.show(); - - unsigned framesDrawn = 0; - while (!view.quit()) { - world.update(0.0); - - ++framesDrawn; - puglPrintFps(world.cobj(), &fpsPrinter, &framesDrawn); - } - - return 0; + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage("pugl_cxx_demo", ""); + return 1; + } + + pugl::World world{pugl::WorldType::program}; + CubeView view{world}; + PuglFpsPrinter fpsPrinter{}; + + world.setClassName("PuglCppTest"); + + view.setWindowTitle("Pugl C++ Test"); + view.setDefaultSize(512, 512); + view.setMinSize(64, 64); + view.setAspectRatio(1, 1, 16, 9); + view.setBackend(pugl::glBackend()); + view.setHint(pugl::ViewHint::resizable, opts.resizable); + view.setHint(pugl::ViewHint::samples, opts.samples); + view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer); + view.setHint(pugl::ViewHint::swapInterval, opts.sync); + view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat); + view.realize(); + view.show(); + + unsigned framesDrawn = 0; + while (!view.quit()) { + world.update(0.0); + + ++framesDrawn; + puglPrintFps(world.cobj(), &fpsPrinter, &framesDrawn); + } + + return 0; } diff --git a/examples/pugl_embed_demo.c b/examples/pugl_embed_demo.c index 55480f6..0e12ddb 100644 --- a/examples/pugl_embed_demo.c +++ b/examples/pugl_embed_demo.c @@ -30,333 +30,325 @@ static const int borderWidth = 64; static const uintptr_t reverseTimerId = 1u; -typedef struct -{ - PuglWorld* world; - PuglView* parent; - PuglView* child; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - int quit; - bool continuous; - bool mouseEntered; - bool verbose; - bool reversing; +typedef struct { + PuglWorld* world; + PuglView* parent; + PuglView* child; + double xAngle; + double yAngle; + double lastMouseX; + double lastMouseY; + double lastDrawTime; + float dist; + int quit; + bool continuous; + bool mouseEntered; + bool verbose; + bool reversing; } PuglTestApp; +// clang-format off static const float backgroundVertices[] = { - -1.0f, 1.0f, -1.0f, // Top left - 1.0f, 1.0f, -1.0f, // Top right - -1.0f, -1.0f, -1.0f, // Bottom left - 1.0f, -1.0f, -1.0f, // Bottom right + -1.0f, 1.0f, -1.0f, // Top left + 1.0f, 1.0f, -1.0f, // Top right + -1.0f, -1.0f, -1.0f, // Bottom left + 1.0f, -1.0f, -1.0f, // Bottom right }; +// clang-format on static PuglRect getChildFrame(const PuglRect parentFrame) { - const PuglRect childFrame = { - borderWidth, - borderWidth, - parentFrame.width - 2 * borderWidth, - parentFrame.height - 2 * borderWidth - }; - - return childFrame; + const PuglRect childFrame = {borderWidth, + borderWidth, + parentFrame.width - 2 * borderWidth, + parentFrame.height - 2 * borderWidth}; + + return childFrame; } static void onDisplay(PuglView* view) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = (thisTime - app->lastDrawTime) * - (app->reversing ? -1.0 : 1.0); + const double thisTime = puglGetTime(app->world); + if (app->continuous) { + const double dTime = + (thisTime - app->lastDrawTime) * (app->reversing ? -1.0 : 1.0); - app->xAngle = fmod(app->xAngle + dTime * 100.0, 360.0); - app->yAngle = fmod(app->yAngle + dTime * 100.0, 360.0); - } + app->xAngle = fmod(app->xAngle + dTime * 100.0, 360.0); + app->yAngle = fmod(app->yAngle + dTime * 100.0, 360.0); + } - displayCube(view, - app->dist, - (float)app->xAngle, - (float)app->yAngle, - app->mouseEntered); + displayCube( + view, app->dist, (float)app->xAngle, (float)app->yAngle, app->mouseEntered); - app->lastDrawTime = thisTime; + app->lastDrawTime = thisTime; } static void swapFocus(PuglTestApp* app) { - if (puglHasFocus(app->parent)) { - puglGrabFocus(app->child); - } else { - puglGrabFocus(app->parent); - } - - if (!app->continuous) { - puglPostRedisplay(app->parent); - puglPostRedisplay(app->child); - } + if (puglHasFocus(app->parent)) { + puglGrabFocus(app->child); + } else { + puglGrabFocus(app->parent); + } + + if (!app->continuous) { + puglPostRedisplay(app->parent); + puglPostRedisplay(app->child); + } } static void onKeyPress(PuglView* view, const PuglEventKey* event, const char* prefix) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - PuglRect frame = puglGetFrame(view); - - if (event->key == '\t') { - swapFocus(app); - } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') { - puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1); - fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix); - } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + PuglRect frame = puglGetFrame(view); + + if (event->key == '\t') { + swapFocus(app); + } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') { + puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1); + fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix); + } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') { + const char* type = NULL; + size_t len = 0; + const char* text = (const char*)puglGetClipboard(view, &type, &len); + fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); + } else if (event->state & PUGL_MOD_SHIFT) { + if (event->key == PUGL_KEY_UP) { + frame.height += 10; + } else if (event->key == PUGL_KEY_DOWN) { + frame.height -= 10; + } else if (event->key == PUGL_KEY_LEFT) { + frame.width -= 10; + } else if (event->key == PUGL_KEY_RIGHT) { + frame.width += 10; + } else { + return; + } + puglSetFrame(view, frame); + } else { + if (event->key == PUGL_KEY_UP) { + frame.y -= 10; + } else if (event->key == PUGL_KEY_DOWN) { + frame.y += 10; + } else if (event->key == PUGL_KEY_LEFT) { + frame.x -= 10; + } else if (event->key == PUGL_KEY_RIGHT) { + frame.x += 10; + } else { + return; + } + puglSetFrame(view, frame); + } } static PuglStatus onParentEvent(PuglView* view, const PuglEvent* event) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect parentFrame = puglGetFrame(view); - - printEvent(event, "Parent: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, - (float)event->configure.height); - - puglSetFrame(app->child, getChildFrame(parentFrame)); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - if (puglHasFocus(app->parent)) { - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, backgroundVertices); - glColorPointer(3, GL_FLOAT, 0, backgroundVertices); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - } else { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Parent: "); - break; - case PUGL_MOTION: - break; - case PUGL_CLOSE: - app->quit = 1; - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + const PuglRect parentFrame = puglGetFrame(view); + + printEvent(event, "Parent: ", app->verbose); + + switch (event->type) { + case PUGL_CONFIGURE: + reshapeCube((float)event->configure.width, (float)event->configure.height); + + puglSetFrame(app->child, getChildFrame(parentFrame)); + break; + case PUGL_UPDATE: + if (app->continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_EXPOSE: + if (puglHasFocus(app->parent)) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, backgroundVertices); + glColorPointer(3, GL_FLOAT, 0, backgroundVertices); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + } else { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + break; + case PUGL_KEY_PRESS: + onKeyPress(view, &event->key, "Parent: "); + break; + case PUGL_MOTION: + break; + case PUGL_CLOSE: + app->quit = 1; + break; + default: + break; + } + + return PUGL_SUCCESS; } static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Child: ", app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, - (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Child: "); - break; - case PUGL_MOTION: - app->xAngle -= event->motion.x - app->lastMouseX; - app->yAngle += event->motion.y - app->lastMouseY; - app->lastMouseX = event->motion.x; - app->lastMouseY = event->motion.y; - if (!app->continuous) { - puglPostRedisplay(view); - puglPostRedisplay(app->parent); - } - break; - case PUGL_SCROLL: - app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy); - if (!app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_POINTER_IN: - app->mouseEntered = true; - break; - case PUGL_POINTER_OUT: - app->mouseEntered = false; - break; - case PUGL_TIMER: - app->reversing = !app->reversing; - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + + printEvent(event, "Child: ", app->verbose); + + switch (event->type) { + case PUGL_CONFIGURE: + reshapeCube((float)event->configure.width, (float)event->configure.height); + break; + case PUGL_UPDATE: + if (app->continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_EXPOSE: + onDisplay(view); + break; + case PUGL_CLOSE: + app->quit = 1; + break; + case PUGL_KEY_PRESS: + onKeyPress(view, &event->key, "Child: "); + break; + case PUGL_MOTION: + app->xAngle -= event->motion.x - app->lastMouseX; + app->yAngle += event->motion.y - app->lastMouseY; + app->lastMouseX = event->motion.x; + app->lastMouseY = event->motion.y; + if (!app->continuous) { + puglPostRedisplay(view); + puglPostRedisplay(app->parent); + } + break; + case PUGL_SCROLL: + app->dist = fmaxf(10.0f, app->dist + (float)event->scroll.dy); + if (!app->continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_POINTER_IN: + app->mouseEntered = true; + break; + case PUGL_POINTER_OUT: + app->mouseEntered = false; + break; + case PUGL_TIMER: + app->reversing = !app->reversing; + break; + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTestApp app = {0}; - - app.dist = 10; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage("pugl_test", ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.parent = puglNewView(app.world); - app.child = puglNewView(app.world); - - puglSetClassName(app.world, "Pugl Test"); - - const PuglRect parentFrame = { 0, 0, 512, 512 }; - puglSetDefaultSize(app.parent, 512, 512); - puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3); - puglSetMaxSize(app.parent, 1024, 1024); - puglSetAspectRatio(app.parent, 1, 1, 16, 9); - puglSetBackend(app.parent, puglGlBackend()); - - puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.parent, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(app.parent, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.parent, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.parent, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.parent, &app); - puglSetEventFunc(app.parent, onParentEvent); - - PuglStatus st = PUGL_SUCCESS; - const uint8_t title[] = { 'P', 'u', 'g', 'l', ' ', - 'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0 }; - - puglSetWindowTitle(app.parent, (const char*)title); - - if ((st = puglRealize(app.parent))) { - return logError("Failed to create parent window (%s)\n", - puglStrerror(st)); - } - - puglSetFrame(app.child, getChildFrame(parentFrame)); - puglSetParentWindow(app.child, puglGetNativeWindow(app.parent)); - - puglSetViewHint(app.child, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples); - puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, opts.sync); - puglSetBackend(app.child, puglGlBackend()); - puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(app.child, &app); - puglSetEventFunc(app.child, onEvent); - - if ((st = puglRealize(app.child))) { - return logError("Failed to create child window (%s)\n", - puglStrerror(st)); - } - - puglShow(app.parent); - puglShow(app.child); - - puglStartTimer(app.child, reverseTimerId, 3.6); - - PuglFpsPrinter fpsPrinter = { puglGetTime(app.world) }; - unsigned framesDrawn = 0; - bool requestedAttention = false; - while (!app.quit) { - const double thisTime = puglGetTime(app.world); - - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (!requestedAttention && thisTime > 5.0) { - puglRequestAttention(app.parent); - requestedAttention = true; - } - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - puglFreeView(app.child); - puglFreeView(app.parent); - puglFreeWorld(app.world); - - return 0; + PuglTestApp app = {0}; + + app.dist = 10; + + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage("pugl_test", ""); + return 1; + } + + app.continuous = opts.continuous; + app.verbose = opts.verbose; + + app.world = puglNewWorld(PUGL_PROGRAM, 0); + app.parent = puglNewView(app.world); + app.child = puglNewView(app.world); + + puglSetClassName(app.world, "Pugl Test"); + + const PuglRect parentFrame = {0, 0, 512, 512}; + puglSetDefaultSize(app.parent, 512, 512); + puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3); + puglSetMaxSize(app.parent, 1024, 1024); + puglSetAspectRatio(app.parent, 1, 1, 16, 9); + puglSetBackend(app.parent, puglGlBackend()); + + puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); + puglSetViewHint(app.parent, PUGL_RESIZABLE, opts.resizable); + puglSetViewHint(app.parent, PUGL_SAMPLES, opts.samples); + puglSetViewHint(app.parent, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); + puglSetViewHint(app.parent, PUGL_SWAP_INTERVAL, opts.sync); + puglSetViewHint(app.parent, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); + puglSetHandle(app.parent, &app); + puglSetEventFunc(app.parent, onParentEvent); + + PuglStatus st = PUGL_SUCCESS; + const uint8_t title[] = { + 'P', 'u', 'g', 'l', ' ', 'P', 'r', 0xC3, 0xBC, 'f', 'u', 'n', 'g', 0}; + + puglSetWindowTitle(app.parent, (const char*)title); + + if ((st = puglRealize(app.parent))) { + return logError("Failed to create parent window (%s)\n", puglStrerror(st)); + } + + puglSetFrame(app.child, getChildFrame(parentFrame)); + puglSetParentWindow(app.child, puglGetNativeWindow(app.parent)); + + puglSetViewHint(app.child, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); + puglSetViewHint(app.child, PUGL_SAMPLES, opts.samples); + puglSetViewHint(app.child, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); + puglSetViewHint(app.child, PUGL_SWAP_INTERVAL, opts.sync); + puglSetBackend(app.child, puglGlBackend()); + puglSetViewHint(app.child, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); + puglSetHandle(app.child, &app); + puglSetEventFunc(app.child, onEvent); + + if ((st = puglRealize(app.child))) { + return logError("Failed to create child window (%s)\n", puglStrerror(st)); + } + + puglShow(app.parent); + puglShow(app.child); + + puglStartTimer(app.child, reverseTimerId, 3.6); + + PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; + unsigned framesDrawn = 0; + bool requestedAttention = false; + while (!app.quit) { + const double thisTime = puglGetTime(app.world); + + puglUpdate(app.world, app.continuous ? 0.0 : -1.0); + ++framesDrawn; + + if (!requestedAttention && thisTime > 5.0) { + puglRequestAttention(app.parent); + requestedAttention = true; + } + + if (app.continuous) { + puglPrintFps(app.world, &fpsPrinter, &framesDrawn); + } + } + + puglFreeView(app.child); + puglFreeView(app.parent); + puglFreeWorld(app.world); + + return 0; } diff --git a/examples/pugl_print_events.c b/examples/pugl_print_events.c index 8f8874b..dfa217e 100644 --- a/examples/pugl_print_events.c +++ b/examples/pugl_print_events.c @@ -22,56 +22,58 @@ #include <stdbool.h> #include <stdio.h> -typedef struct -{ - PuglWorld* world; - PuglView* view; - int quit; +typedef struct { + PuglWorld* world; + PuglView* view; + int quit; } PuglPrintEventsApp; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view); + PuglPrintEventsApp* app = (PuglPrintEventsApp*)puglGetHandle(view); - printEvent(event, "Event: ", true); + printEvent(event, "Event: ", true); - switch (event->type) { - case PUGL_CLOSE: app->quit = 1; break; - default: break; - } + switch (event->type) { + case PUGL_CLOSE: + app->quit = 1; + break; + default: + break; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } int main(void) { - PuglPrintEventsApp app = {NULL, NULL, 0}; + PuglPrintEventsApp app = {NULL, NULL, 0}; - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.view = puglNewView(app.world); + app.world = puglNewWorld(PUGL_PROGRAM, 0); + app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Print Events"); - puglSetWindowTitle(app.view, "Pugl Event Printer"); - puglSetDefaultSize(app.view, 512, 512); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); + puglSetClassName(app.world, "Pugl Print Events"); + puglSetWindowTitle(app.view, "Pugl Event Printer"); + puglSetDefaultSize(app.view, 512, 512); + puglSetBackend(app.view, puglStubBackend()); + puglSetHandle(app.view, &app); + puglSetEventFunc(app.view, onEvent); - PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } + PuglStatus st = puglRealize(app.view); + if (st) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } - puglShow(app.view); + puglShow(app.view); - while (!app.quit) { - puglUpdate(app.world, -1.0); - } + while (!app.quit) { + puglUpdate(app.world, -1.0); + } - puglFreeView(app.view); - puglFreeWorld(app.world); + puglFreeView(app.view); + puglFreeWorld(app.world); - return 0; + return 0; } diff --git a/examples/pugl_shader_demo.c b/examples/pugl_shader_demo.c index 8ebbe60..d038b3f 100644 --- a/examples/pugl_shader_demo.c +++ b/examples/pugl_shader_demo.c @@ -56,30 +56,28 @@ static const int defaultWidth = 512; static const int defaultHeight = 512; static const uintptr_t resizeTimerId = 1u; -typedef struct -{ - mat4 projection; +typedef struct { + mat4 projection; } RectUniforms; -typedef struct -{ - const char* programPath; - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numRects; - Rect* rects; - Program drawRect; - GLuint vao; - GLuint vbo; - GLuint instanceVbo; - GLuint ibo; - double lastDrawDuration; - double lastFrameEndTime; - unsigned framesDrawn; - int glMajorVersion; - int glMinorVersion; - int quit; +typedef struct { + const char* programPath; + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + size_t numRects; + Rect* rects; + Program drawRect; + GLuint vao; + GLuint vbo; + GLuint instanceVbo; + GLuint ibo; + double lastDrawDuration; + double lastFrameEndTime; + unsigned framesDrawn; + int glMajorVersion; + int glMinorVersion; + int quit; } PuglTestApp; static PuglStatus @@ -91,393 +89,379 @@ teardownGl(PuglTestApp* app); static void onConfigure(PuglView* view, double width, double height) { - (void)view; + (void)view; - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glViewport(0, 0, (int)width, (int)height); + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glViewport(0, 0, (int)width, (int)height); } static void onExpose(PuglView* view) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - const PuglRect frame = puglGetFrame(view); - const float width = (float)frame.width; - const float height = (float)frame.height; - const double time = puglGetTime(puglGetWorld(view)); - - // Construct projection matrix for 2D window surface (in pixels) - mat4 proj; - mat4Ortho(proj, - 0.0f, - (float)frame.width, - 0.0f, - (float)frame.height, - -1.0f, - 1.0f); - - // Clear and bind everything that is the same for every rect - glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(app->drawRect.program); - glBindVertexArray(app->vao); - - for (size_t i = 0; i < app->numRects; ++i) { - moveRect(&app->rects[i], i, app->numRects, width, height, time); - } - - glBufferData(GL_UNIFORM_BUFFER, sizeof(proj), &proj, GL_STREAM_DRAW); - - glBufferSubData(GL_ARRAY_BUFFER, - 0, - (GLsizeiptr)(app->numRects * sizeof(Rect)), - app->rects); - - glDrawElementsInstanced(GL_TRIANGLE_STRIP, - 4, - GL_UNSIGNED_INT, - NULL, - (GLsizei)(app->numRects * 4)); - - ++app->framesDrawn; - - app->lastFrameEndTime = puglGetTime(puglGetWorld(view)); - app->lastDrawDuration = app->lastFrameEndTime - time; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + const PuglRect frame = puglGetFrame(view); + const float width = (float)frame.width; + const float height = (float)frame.height; + const double time = puglGetTime(puglGetWorld(view)); + + // Construct projection matrix for 2D window surface (in pixels) + mat4 proj; + mat4Ortho( + proj, 0.0f, (float)frame.width, 0.0f, (float)frame.height, -1.0f, 1.0f); + + // Clear and bind everything that is the same for every rect + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(app->drawRect.program); + glBindVertexArray(app->vao); + + for (size_t i = 0; i < app->numRects; ++i) { + moveRect(&app->rects[i], i, app->numRects, width, height, time); + } + + glBufferData(GL_UNIFORM_BUFFER, sizeof(proj), &proj, GL_STREAM_DRAW); + + glBufferSubData( + GL_ARRAY_BUFFER, 0, (GLsizeiptr)(app->numRects * sizeof(Rect)), app->rects); + + glDrawElementsInstanced( + GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, NULL, (GLsizei)(app->numRects * 4)); + + ++app->framesDrawn; + + app->lastFrameEndTime = puglGetTime(puglGetWorld(view)); + app->lastDrawDuration = app->lastFrameEndTime - time; } static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); - - printEvent(event, "Event: ", app->opts.verbose); - - switch (event->type) { - case PUGL_CREATE: - setupGl(app); - break; - case PUGL_DESTROY: - teardownGl(app); - break; - case PUGL_CONFIGURE: - onConfigure(view, event->configure.width, event->configure.height); - break; - case PUGL_UPDATE: - puglPostRedisplay(view); - break; - case PUGL_EXPOSE: onExpose(view); break; - case PUGL_CLOSE: app->quit = 1; break; - case PUGL_LOOP_ENTER: - puglStartTimer(view, - resizeTimerId, - 1.0 / (double)puglGetViewHint(view, PUGL_REFRESH_RATE)); - break; - case PUGL_LOOP_LEAVE: - puglStopTimer(view, resizeTimerId); - break; - case PUGL_KEY_PRESS: - if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } - break; - case PUGL_TIMER: - if (event->timer.id == resizeTimerId) { - puglPostRedisplay(view); - } - break; - default: break; - } - - return PUGL_SUCCESS; + PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); + + printEvent(event, "Event: ", app->opts.verbose); + + switch (event->type) { + case PUGL_CREATE: + setupGl(app); + break; + case PUGL_DESTROY: + teardownGl(app); + break; + case PUGL_CONFIGURE: + onConfigure(view, event->configure.width, event->configure.height); + break; + case PUGL_UPDATE: + puglPostRedisplay(view); + break; + case PUGL_EXPOSE: + onExpose(view); + break; + case PUGL_CLOSE: + app->quit = 1; + break; + case PUGL_LOOP_ENTER: + puglStartTimer(view, + resizeTimerId, + 1.0 / (double)puglGetViewHint(view, PUGL_REFRESH_RATE)); + break; + case PUGL_LOOP_LEAVE: + puglStopTimer(view, resizeTimerId); + break; + case PUGL_KEY_PRESS: + if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } + break; + case PUGL_TIMER: + if (event->timer.id == resizeTimerId) { + puglPostRedisplay(view); + } + break; + default: + break; + } + + return PUGL_SUCCESS; } static Rect* makeRects(const size_t numRects) { - Rect* rects = (Rect*)calloc(numRects, sizeof(Rect)); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, (float)defaultWidth); - } + Rect* rects = (Rect*)calloc(numRects, sizeof(Rect)); + for (size_t i = 0; i < numRects; ++i) { + rects[i] = makeRect(i, (float)defaultWidth); + } - return rects; + return rects; } static char* loadShader(const char* const programPath, const char* const name) { - char* const path = resourcePath(programPath, name); - fprintf(stderr, "Loading shader %s\n", path); + char* const path = resourcePath(programPath, name); + fprintf(stderr, "Loading shader %s\n", path); - FILE* const file = fopen(path, "r"); - if (!file) { - logError("Failed to open '%s'\n", path); - return NULL; - } + FILE* const file = fopen(path, "r"); + if (!file) { + logError("Failed to open '%s'\n", path); + return NULL; + } - free(path); - fseek(file, 0, SEEK_END); - const size_t fileSize = (size_t)ftell(file); + free(path); + fseek(file, 0, SEEK_END); + const size_t fileSize = (size_t)ftell(file); - fseek(file, 0, SEEK_SET); - char* source = (char*)calloc(1, fileSize + 1u); + fseek(file, 0, SEEK_SET); + char* source = (char*)calloc(1, fileSize + 1u); - fread(source, 1, fileSize, file); - fclose(file); + fread(source, 1, fileSize, file); + fclose(file); - return source; + return source; } static int parseOptions(PuglTestApp* app, int argc, char** argv) { - char* endptr = NULL; - - // Parse command line options - app->numRects = 1024; - app->opts = puglParseTestOptions(&argc, &argv); - if (app->opts.help) { - return 1; - } - - // Parse number of rectangles argument, if given - if (argc >= 1) { - app->numRects = (size_t)strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0])) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Parse OpenGL major version argument, if given - if (argc >= 2) { - app->glMajorVersion = (int)strtol(argv[1], &endptr, 10); - if (endptr != argv[1] + strlen(argv[1])) { - logError("Invalid GL major version: %s\n", argv[1]); - return 1; - } else if (app->glMajorVersion == 4) { - app->glMinorVersion = 2; - } else if (app->glMajorVersion != 3) { - logError("Unsupported GL major version %d\n", app->glMajorVersion); - return 1; - } - } - - return 0; + char* endptr = NULL; + + // Parse command line options + app->numRects = 1024; + app->opts = puglParseTestOptions(&argc, &argv); + if (app->opts.help) { + return 1; + } + + // Parse number of rectangles argument, if given + if (argc >= 1) { + app->numRects = (size_t)strtol(argv[0], &endptr, 10); + if (endptr != argv[0] + strlen(argv[0])) { + logError("Invalid number of rectangles: %s\n", argv[0]); + return 1; + } + } + + // Parse OpenGL major version argument, if given + if (argc >= 2) { + app->glMajorVersion = (int)strtol(argv[1], &endptr, 10); + if (endptr != argv[1] + strlen(argv[1])) { + logError("Invalid GL major version: %s\n", argv[1]); + return 1; + } else if (app->glMajorVersion == 4) { + app->glMinorVersion = 2; + } else if (app->glMajorVersion != 3) { + logError("Unsupported GL major version %d\n", app->glMajorVersion); + return 1; + } + } + + return 0; } static void setupPugl(PuglTestApp* app) { - // Create world, view, and rect data - app->world = puglNewWorld(PUGL_PROGRAM, 0); - app->view = puglNewView(app->world); - app->rects = makeRects(app->numRects); - - // Set up world and view - puglSetClassName(app->world, "PuglGL3Demo"); - puglSetWindowTitle(app->view, "Pugl OpenGL 3"); - puglSetDefaultSize(app->view, defaultWidth, defaultHeight); - puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4); - puglSetAspectRatio(app->view, 1, 1, 16, 9); - puglSetBackend(app->view, puglGlBackend()); - puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); - puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MAJOR, app->glMajorVersion); - puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, app->glMinorVersion); - puglSetViewHint(app->view, PUGL_RESIZABLE, app->opts.resizable); - puglSetViewHint(app->view, PUGL_SAMPLES, app->opts.samples); - puglSetViewHint(app->view, PUGL_DOUBLE_BUFFER, app->opts.doubleBuffer); - puglSetViewHint(app->view, PUGL_SWAP_INTERVAL, app->opts.sync); - puglSetViewHint(app->view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); - puglSetHandle(app->view, app); - puglSetEventFunc(app->view, onEvent); + // Create world, view, and rect data + app->world = puglNewWorld(PUGL_PROGRAM, 0); + app->view = puglNewView(app->world); + app->rects = makeRects(app->numRects); + + // Set up world and view + puglSetClassName(app->world, "PuglGL3Demo"); + puglSetWindowTitle(app->view, "Pugl OpenGL 3"); + puglSetDefaultSize(app->view, defaultWidth, defaultHeight); + puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4); + puglSetAspectRatio(app->view, 1, 1, 16, 9); + puglSetBackend(app->view, puglGlBackend()); + puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); + puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking); + puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MAJOR, app->glMajorVersion); + puglSetViewHint(app->view, PUGL_CONTEXT_VERSION_MINOR, app->glMinorVersion); + puglSetViewHint(app->view, PUGL_RESIZABLE, app->opts.resizable); + puglSetViewHint(app->view, PUGL_SAMPLES, app->opts.samples); + puglSetViewHint(app->view, PUGL_DOUBLE_BUFFER, app->opts.doubleBuffer); + puglSetViewHint(app->view, PUGL_SWAP_INTERVAL, app->opts.sync); + puglSetViewHint(app->view, PUGL_IGNORE_KEY_REPEAT, PUGL_TRUE); + puglSetHandle(app->view, app); + puglSetEventFunc(app->view, onEvent); } static PuglStatus setupGl(PuglTestApp* app) { - // Load GL functions via GLAD - if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) { - logError("Failed to load GL\n"); - return PUGL_FAILURE; - } - - const char* const headerFile = (app->glMajorVersion == 3 - ? "shaders/header_330.glsl" - : "shaders/header_420.glsl"); - - // Load shader sources - char* const headerSource = loadShader(app->programPath, headerFile); - - char* const vertexSource = loadShader(app->programPath, - "shaders/rect.vert"); - - char* const fragmentSource = loadShader(app->programPath, - "shaders/rect.frag"); - - if (!vertexSource || !fragmentSource) { - logError("Failed to load shader sources\n"); - return PUGL_FAILURE; - } - - // Compile rectangle shaders and program - app->drawRect = compileProgram(headerSource, vertexSource, fragmentSource); - free(fragmentSource); - free(vertexSource); - free(headerSource); - if (!app->drawRect.program) { - return PUGL_FAILURE; - } - - // Get location of rectangle shader uniform block - const GLuint globalsIndex = glGetUniformBlockIndex(app->drawRect.program, - "UniformBufferObject"); - - // Generate/bind a uniform buffer for setting rectangle properties - GLuint uboHandle = 0; - glGenBuffers(1, &uboHandle); - glBindBuffer(GL_UNIFORM_BUFFER, uboHandle); - glBindBufferBase(GL_UNIFORM_BUFFER, globalsIndex, uboHandle); - - // Generate/bind a VAO to track state - glGenVertexArrays(1, &app->vao); - glBindVertexArray(app->vao); - - // Generate/bind a VBO to store vertex position data - glGenBuffers(1, &app->vbo); - glBindBuffer(GL_ARRAY_BUFFER, app->vbo); - glBufferData(GL_ARRAY_BUFFER, - sizeof(rectVertices), - rectVertices, - GL_STATIC_DRAW); - - // Attribute 0 is position, 2 floats from the VBO - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); - - // Generate/bind a VBO to store instance attribute data - glGenBuffers(1, &app->instanceVbo); - glBindBuffer(GL_ARRAY_BUFFER, app->instanceVbo); - glBufferData(GL_ARRAY_BUFFER, - (GLsizeiptr)(app->numRects * sizeof(Rect)), - app->rects, - GL_STREAM_DRAW); - - // Attribute 1 is Rect::position - glEnableVertexAttribArray(1); - glVertexAttribDivisor(1, 4); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL); - - // Attribute 2 is Rect::size - glEnableVertexAttribArray(2); - glVertexAttribDivisor(2, 4); - glVertexAttribPointer(2, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(Rect), - (const void*)offsetof(Rect, size)); - - // Attribute 3 is Rect::fillColor - glEnableVertexAttribArray(3); - glVertexAttribDivisor(3, 4); - glVertexAttribPointer(3, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(Rect), - (const void*)offsetof(Rect, fillColor)); - - // Set up the IBO to index into the VBO - glGenBuffers(1, &app->ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - sizeof(rectIndices), - rectIndices, - GL_STATIC_DRAW); - - return PUGL_SUCCESS; + // Load GL functions via GLAD + if (!gladLoadGLLoader((GLADloadproc)&puglGetProcAddress)) { + logError("Failed to load GL\n"); + return PUGL_FAILURE; + } + + const char* const headerFile = + (app->glMajorVersion == 3 ? "shaders/header_330.glsl" + : "shaders/header_420.glsl"); + + // Load shader sources + char* const headerSource = loadShader(app->programPath, headerFile); + + char* const vertexSource = loadShader(app->programPath, "shaders/rect.vert"); + + char* const fragmentSource = + loadShader(app->programPath, "shaders/rect.frag"); + + if (!vertexSource || !fragmentSource) { + logError("Failed to load shader sources\n"); + return PUGL_FAILURE; + } + + // Compile rectangle shaders and program + app->drawRect = compileProgram(headerSource, vertexSource, fragmentSource); + free(fragmentSource); + free(vertexSource); + free(headerSource); + if (!app->drawRect.program) { + return PUGL_FAILURE; + } + + // Get location of rectangle shader uniform block + const GLuint globalsIndex = + glGetUniformBlockIndex(app->drawRect.program, "UniformBufferObject"); + + // Generate/bind a uniform buffer for setting rectangle properties + GLuint uboHandle = 0; + glGenBuffers(1, &uboHandle); + glBindBuffer(GL_UNIFORM_BUFFER, uboHandle); + glBindBufferBase(GL_UNIFORM_BUFFER, globalsIndex, uboHandle); + + // Generate/bind a VAO to track state + glGenVertexArrays(1, &app->vao); + glBindVertexArray(app->vao); + + // Generate/bind a VBO to store vertex position data + glGenBuffers(1, &app->vbo); + glBindBuffer(GL_ARRAY_BUFFER, app->vbo); + glBufferData( + GL_ARRAY_BUFFER, sizeof(rectVertices), rectVertices, GL_STATIC_DRAW); + + // Attribute 0 is position, 2 floats from the VBO + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); + + // Generate/bind a VBO to store instance attribute data + glGenBuffers(1, &app->instanceVbo); + glBindBuffer(GL_ARRAY_BUFFER, app->instanceVbo); + glBufferData(GL_ARRAY_BUFFER, + (GLsizeiptr)(app->numRects * sizeof(Rect)), + app->rects, + GL_STREAM_DRAW); + + // Attribute 1 is Rect::position + glEnableVertexAttribArray(1); + glVertexAttribDivisor(1, 4); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), NULL); + + // Attribute 2 is Rect::size + glEnableVertexAttribArray(2); + glVertexAttribDivisor(2, 4); + glVertexAttribPointer( + 2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (const void*)offsetof(Rect, size)); + + // Attribute 3 is Rect::fillColor + glEnableVertexAttribArray(3); + glVertexAttribDivisor(3, 4); + glVertexAttribPointer(3, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(Rect), + (const void*)offsetof(Rect, fillColor)); + + // Set up the IBO to index into the VBO + glGenBuffers(1, &app->ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, app->ibo); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, sizeof(rectIndices), rectIndices, GL_STATIC_DRAW); + + return PUGL_SUCCESS; } static void teardownGl(PuglTestApp* app) { - glDeleteBuffers(1, &app->ibo); - glDeleteBuffers(1, &app->vbo); - glDeleteBuffers(1, &app->instanceVbo); - glDeleteVertexArrays(1, &app->vao); - deleteProgram(app->drawRect); + glDeleteBuffers(1, &app->ibo); + glDeleteBuffers(1, &app->vbo); + glDeleteBuffers(1, &app->instanceVbo); + glDeleteVertexArrays(1, &app->vao); + deleteProgram(app->drawRect); } int main(int argc, char** argv) { - PuglTestApp app = {0}; - - app.programPath = argv[0]; - app.glMajorVersion = 3; - app.glMinorVersion = 3; - - // Parse command line options - if (parseOptions(&app, argc, argv)) { - puglPrintTestUsage("pugl_shader_demo", "[NUM_RECTS] [GL_MAJOR]"); - return 1; - } - - // Create and configure world and view - setupPugl(&app); - - // Create window (which will send a PUGL_CREATE event) - const PuglStatus st = puglRealize(app.view); - if (st) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Show window - printViewHints(app.view); - puglShow(app.view); - - // Calculate ideal frame duration to drive the main loop at a good rate - const int refreshRate = puglGetViewHint(app.view, PUGL_REFRESH_RATE); - const double frameDuration = 1.0 / (double)refreshRate; - - // Grind away, drawing continuously - const double startTime = puglGetTime(app.world); - PuglFpsPrinter fpsPrinter = {startTime}; - while (!app.quit) { - /* To minimize input latency and get smooth performance during window - resizing, we want to poll for events as long as possible before - starting to draw the next frame. This ensures that as many events - are consumed as possible before starting to draw, or, equivalently, - that the next rendered frame represents the latest events possible. - This is particularly important for mouse input and "live" window - resizing, where many events tend to pile up within a frame. - - To do this, we keep track of the time when the last frame was - finished drawing, and how long it took to expose (and assume this is - relatively stable). Then, we can calculate how much time there is - from now until the time when we should start drawing to not miss the - deadline, and use that as the timeout for puglUpdate(). - */ - - const double now = puglGetTime(app.world); - const double nextFrameEndTime = app.lastFrameEndTime + frameDuration; - const double nextExposeTime = nextFrameEndTime - app.lastDrawDuration; - const double timeUntilNext = nextExposeTime - now; - const double timeout = app.opts.sync ? timeUntilNext : 0.0; - - puglUpdate(app.world, fmax(0.0, timeout)); - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - - // Destroy window (which will send a PUGL_DESTROY event) - puglFreeView(app.view); - - // Free everything else - puglFreeWorld(app.world); - free(app.rects); - - return 0; + PuglTestApp app = {0}; + + app.programPath = argv[0]; + app.glMajorVersion = 3; + app.glMinorVersion = 3; + + // Parse command line options + if (parseOptions(&app, argc, argv)) { + puglPrintTestUsage("pugl_shader_demo", "[NUM_RECTS] [GL_MAJOR]"); + return 1; + } + + // Create and configure world and view + setupPugl(&app); + + // Create window (which will send a PUGL_CREATE event) + const PuglStatus st = puglRealize(app.view); + if (st) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } + + // Show window + printViewHints(app.view); + puglShow(app.view); + + // Calculate ideal frame duration to drive the main loop at a good rate + const int refreshRate = puglGetViewHint(app.view, PUGL_REFRESH_RATE); + const double frameDuration = 1.0 / (double)refreshRate; + + // Grind away, drawing continuously + const double startTime = puglGetTime(app.world); + PuglFpsPrinter fpsPrinter = {startTime}; + while (!app.quit) { + /* To minimize input latency and get smooth performance during window + resizing, we want to poll for events as long as possible before + starting to draw the next frame. This ensures that as many events + are consumed as possible before starting to draw, or, equivalently, + that the next rendered frame represents the latest events possible. + This is particularly important for mouse input and "live" window + resizing, where many events tend to pile up within a frame. + + To do this, we keep track of the time when the last frame was + finished drawing, and how long it took to expose (and assume this is + relatively stable). Then, we can calculate how much time there is + from now until the time when we should start drawing to not miss the + deadline, and use that as the timeout for puglUpdate(). + */ + + const double now = puglGetTime(app.world); + const double nextFrameEndTime = app.lastFrameEndTime + frameDuration; + const double nextExposeTime = nextFrameEndTime - app.lastDrawDuration; + const double timeUntilNext = nextExposeTime - now; + const double timeout = app.opts.sync ? timeUntilNext : 0.0; + + puglUpdate(app.world, fmax(0.0, timeout)); + puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); + } + + // Destroy window (which will send a PUGL_DESTROY event) + puglFreeView(app.view); + + // Free everything else + puglFreeWorld(app.world); + free(app.rects); + + return 0; } diff --git a/examples/pugl_vulkan_cxx_demo.cpp b/examples/pugl_vulkan_cxx_demo.cpp index 21fd4df..3dab5ce 100644 --- a/examples/pugl_vulkan_cxx_demo.cpp +++ b/examples/pugl_vulkan_cxx_demo.cpp @@ -61,152 +61,154 @@ namespace { constexpr uintptr_t resizeTimerId = 1u; struct PhysicalDeviceSelection { - sk::PhysicalDevice physicalDevice; - uint32_t graphicsFamilyIndex; + sk::PhysicalDevice physicalDevice; + uint32_t graphicsFamilyIndex; }; /// Basic Vulkan context associated with the window struct VulkanContext { - VkResult init(pugl::VulkanLoader& loader, const PuglTestOptions& opts); + VkResult init(pugl::VulkanLoader& loader, const PuglTestOptions& opts); - sk::VulkanApi vk; - sk::Instance instance; - sk::DebugReportCallbackEXT debugCallback; + sk::VulkanApi vk; + sk::Instance instance; + sk::DebugReportCallbackEXT debugCallback; }; /// Basic setup of graphics device struct GraphicsDevice { - VkResult init(const pugl::VulkanLoader& loader, - const VulkanContext& context, - pugl::View& view, - const PuglTestOptions& opts); - - sk::SurfaceKHR surface; - sk::PhysicalDevice physicalDevice{}; - uint32_t graphicsIndex{}; - VkSurfaceFormatKHR surfaceFormat{}; - VkPresentModeKHR presentMode{}; - VkPresentModeKHR resizePresentMode{}; - sk::Device device{}; - sk::Queue graphicsQueue{}; - sk::CommandPool commandPool{}; + VkResult init(const pugl::VulkanLoader& loader, + const VulkanContext& context, + pugl::View& view, + const PuglTestOptions& opts); + + sk::SurfaceKHR surface; + sk::PhysicalDevice physicalDevice{}; + uint32_t graphicsIndex{}; + VkSurfaceFormatKHR surfaceFormat{}; + VkPresentModeKHR presentMode{}; + VkPresentModeKHR resizePresentMode{}; + sk::Device device{}; + sk::Queue graphicsQueue{}; + sk::CommandPool commandPool{}; }; /// Buffer allocated on the GPU struct Buffer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkDeviceSize size, - VkBufferUsageFlags usage, - VkMemoryPropertyFlags properties); - - sk::Buffer buffer; - sk::DeviceMemory deviceMemory; + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + VkDeviceSize size, + VkBufferUsageFlags usage, + VkMemoryPropertyFlags properties); + + sk::Buffer buffer; + sk::DeviceMemory deviceMemory; }; /// A set of frames that can be rendered concurrently struct Swapchain { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - VkSurfaceCapabilitiesKHR capabilities, - VkExtent2D extent, - VkSwapchainKHR oldSwapchain, - bool resizing); - - VkSurfaceCapabilitiesKHR capabilities{}; - VkExtent2D extent{}; - sk::SwapchainKHR swapchain{}; - std::vector<sk::ImageView> imageViews{}; + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + VkSurfaceCapabilitiesKHR capabilities, + VkExtent2D extent, + VkSwapchainKHR oldSwapchain, + bool resizing); + + VkSurfaceCapabilitiesKHR capabilities{}; + VkExtent2D extent{}; + sk::SwapchainKHR swapchain{}; + std::vector<sk::ImageView> imageViews{}; }; /// A pass that renders to a target struct RenderPass { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const Swapchain& swapchain); + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const Swapchain& swapchain); - sk::RenderPass renderPass; - std::vector<sk::Framebuffer> framebuffers; - sk::CommandBuffers<std::vector<VkCommandBuffer>> commandBuffers; + sk::RenderPass renderPass; + std::vector<sk::Framebuffer> framebuffers; + sk::CommandBuffers<std::vector<VkCommandBuffer>> commandBuffers; }; /// Uniform buffer for constant data used in shaders struct UniformBufferObject { - mat4 projection; + mat4 projection; }; /// Rectangle data that does not depend on renderer configuration struct RectData { - VkResult - init(const sk::VulkanApi& vk, const GraphicsDevice& gpu, size_t nRects); - - sk::DescriptorSetLayout descriptorSetLayout{}; - Buffer uniformBuffer{}; - sk::MappedMemory uniformData{}; - Buffer modelBuffer{}; - Buffer instanceBuffer{}; - sk::MappedMemory vertexData{}; - size_t numRects{}; + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + size_t nRects); + + sk::DescriptorSetLayout descriptorSetLayout{}; + Buffer uniformBuffer{}; + sk::MappedMemory uniformData{}; + Buffer modelBuffer{}; + Buffer instanceBuffer{}; + sk::MappedMemory vertexData{}; + size_t numRects{}; }; /// Shader modules for drawing rectangles struct RectShaders { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const std::string& programPath); + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const std::string& programPath); - sk::ShaderModule vert{}; - sk::ShaderModule frag{}; + sk::ShaderModule vert{}; + sk::ShaderModule frag{}; }; /// A pipeline to render rectangles with our shaders struct RectPipeline { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& shaders, - const Swapchain& swapchain, - const RenderPass& renderPass); - - sk::DescriptorPool descriptorPool{}; - sk::DescriptorSets<std::vector<VkDescriptorSet>> descriptorSets{}; - sk::PipelineLayout pipelineLayout{}; - std::array<sk::Pipeline, 1> pipelines{}; - uint32_t numImages{}; + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const RectData& rectData, + const RectShaders& shaders, + const Swapchain& swapchain, + const RenderPass& renderPass); + + sk::DescriptorPool descriptorPool{}; + sk::DescriptorSets<std::vector<VkDescriptorSet>> descriptorSets{}; + sk::PipelineLayout pipelineLayout{}; + std::array<sk::Pipeline, 1> pipelines{}; + uint32_t numImages{}; }; /// Synchronization primitives used to coordinate drawing frames struct RenderSync { - VkResult - init(const sk::VulkanApi& vk, const sk::Device& device, uint32_t numImages); - - std::vector<sk::Semaphore> imageAvailable{}; - std::vector<sk::Semaphore> renderFinished{}; - std::vector<sk::Fence> inFlight{}; - size_t currentFrame{}; + VkResult init(const sk::VulkanApi& vk, + const sk::Device& device, + uint32_t numImages); + + std::vector<sk::Semaphore> imageAvailable{}; + std::vector<sk::Semaphore> renderFinished{}; + std::vector<sk::Fence> inFlight{}; + size_t currentFrame{}; }; /// Renderer that owns the above and everything required to draw struct Renderer { - VkResult init(const sk::VulkanApi& vk, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - VkResult recreate(const sk::VulkanApi& vk, - const sk::SurfaceKHR& surface, - const GraphicsDevice& gpu, - const RectData& rectData, - const RectShaders& rectShaders, - VkExtent2D extent, - bool resizing); - - Swapchain swapchain; - RenderPass renderPass; - RectPipeline rectPipeline; - RenderSync sync; + VkResult init(const sk::VulkanApi& vk, + const GraphicsDevice& gpu, + const RectData& rectData, + const RectShaders& rectShaders, + VkExtent2D extent, + bool resizing); + + VkResult recreate(const sk::VulkanApi& vk, + const sk::SurfaceKHR& surface, + const GraphicsDevice& gpu, + const RectData& rectData, + const RectShaders& rectShaders, + VkExtent2D extent, + bool resizing); + + Swapchain swapchain; + RenderPass renderPass; + RectPipeline rectPipeline; + RenderSync sync; }; VkResult @@ -215,22 +217,21 @@ selectSurfaceFormat(const sk::VulkanApi& vk, const sk::SurfaceKHR& surface, VkSurfaceFormatKHR& surfaceFormat) { - std::vector<VkSurfaceFormatKHR> formats; - if (VkResult r = vk.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, - surface, - formats)) { - return r; - } - - for (const auto& format : formats) { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && - format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - surfaceFormat = format; - return VK_SUCCESS; - } - } - - return VK_ERROR_FORMAT_NOT_SUPPORTED; + std::vector<VkSurfaceFormatKHR> formats; + if (VkResult r = vk.getPhysicalDeviceSurfaceFormatsKHR( + physicalDevice, surface, formats)) { + return r; + } + + for (const auto& format : formats) { + if (format.format == VK_FORMAT_B8G8R8A8_UNORM && + format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + surfaceFormat = format; + return VK_SUCCESS; + } + } + + return VK_ERROR_FORMAT_NOT_SUPPORTED; } VkResult @@ -241,54 +242,53 @@ selectPresentMode(const sk::VulkanApi& vk, const bool sync, VkPresentModeKHR& presentMode) { - // Map command line options to mode priorities - static constexpr VkPresentModeKHR priorities[][2][4] = { - { - // No double buffer, no sync - {VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR}, - - // No double buffer, sync (nonsense, map to FIFO relaxed) - {VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - { - // Double buffer, no sync - { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - }, - - // Double buffer, sync - {VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR}, - }, - }; - - std::vector<VkPresentModeKHR> modes; - if (VkResult r = vk.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, - surface, - modes)) { - return r; - } - - const auto& tryModes = priorities[bool(multiBuffer)][bool(sync)]; - for (const auto m : tryModes) { - if (std::find(modes.begin(), modes.end(), m) != modes.end()) { - presentMode = m; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DRIVER; + // Map command line options to mode priorities + static constexpr VkPresentModeKHR priorities[][2][4] = { + { + // No double buffer, no sync + {VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_FIFO_KHR}, + + // No double buffer, sync (nonsense, map to FIFO relaxed) + {VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_FIFO_KHR, + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR}, + }, + { + // Double buffer, no sync + { + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_FIFO_KHR, + }, + + // Double buffer, sync + {VK_PRESENT_MODE_FIFO_KHR, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR}, + }, + }; + + std::vector<VkPresentModeKHR> modes; + if (VkResult r = vk.getPhysicalDeviceSurfacePresentModesKHR( + physicalDevice, surface, modes)) { + return r; + } + + const auto& tryModes = priorities[bool(multiBuffer)][bool(sync)]; + for (const auto m : tryModes) { + if (std::find(modes.begin(), modes.end(), m) != modes.end()) { + presentMode = m; + return VK_SUCCESS; + } + } + + return VK_ERROR_INCOMPATIBLE_DRIVER; } VkResult @@ -297,26 +297,26 @@ openDevice(const sk::VulkanApi& vk, const uint32_t graphicsFamilyIndex, sk::Device& device) { - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = "VK_KHR_swapchain"; - - const VkDeviceQueueCreateInfo queueCreateInfo{ - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - nullptr, - 0u, - graphicsFamilyIndex, - SK_COUNTED(1u, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - nullptr, - 0u, - SK_COUNTED(1u, &queueCreateInfo), - SK_COUNTED(0u, nullptr), // Deprecated - SK_COUNTED(1u, &swapchainName), - nullptr}; - - return vk.createDevice(physicalDevice, createInfo, device); + const float graphicsQueuePriority = 1.0f; + const char* const swapchainName = "VK_KHR_swapchain"; + + const VkDeviceQueueCreateInfo queueCreateInfo{ + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + nullptr, + 0u, + graphicsFamilyIndex, + SK_COUNTED(1u, &graphicsQueuePriority), + }; + + const VkDeviceCreateInfo createInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + nullptr, + 0u, + SK_COUNTED(1u, &queueCreateInfo), + SK_COUNTED(0u, nullptr), // Deprecated + SK_COUNTED(1u, &swapchainName), + nullptr}; + + return vk.createDevice(physicalDevice, createInfo, device); } /// Return whether the physical device supports the extensions we require @@ -325,21 +325,19 @@ deviceSupportsRequiredExtensions(const sk::VulkanApi& vk, const sk::PhysicalDevice& device, bool& supported) { - VkResult r = VK_SUCCESS; + VkResult r = VK_SUCCESS; - std::vector<VkExtensionProperties> props; - if ((r = vk.enumerateDeviceExtensionProperties(device, props))) { - return r; - } + std::vector<VkExtensionProperties> props; + if ((r = vk.enumerateDeviceExtensionProperties(device, props))) { + return r; + } - supported = std::any_of(props.begin(), - props.end(), - [&](const VkExtensionProperties& e) { - return !strcmp(e.extensionName, - "VK_KHR_swapchain"); - }); + supported = std::any_of( + props.begin(), props.end(), [&](const VkExtensionProperties& e) { + return !strcmp(e.extensionName, "VK_KHR_swapchain"); + }); - return VK_SUCCESS; + return VK_SUCCESS; } /// Return the index of the graphics queue, if there is one @@ -349,29 +347,29 @@ findGraphicsQueue(const sk::VulkanApi& vk, const sk::PhysicalDevice& device, uint32_t& queueIndex) { - VkResult r = VK_SUCCESS; - - std::vector<VkQueueFamilyProperties> queueProps; - if ((r = vk.getPhysicalDeviceQueueFamilyProperties(device, queueProps))) { - return r; - } - - for (uint32_t q = 0u; q < queueProps.size(); ++q) { - if (queueProps[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - bool supported = false; - if ((r = vk.getPhysicalDeviceSurfaceSupportKHR( - device, q, surface, supported))) { - return r; - } - - if (supported) { - queueIndex = q; - return VK_SUCCESS; - } - } - } - - return VK_ERROR_FEATURE_NOT_PRESENT; + VkResult r = VK_SUCCESS; + + std::vector<VkQueueFamilyProperties> queueProps; + if ((r = vk.getPhysicalDeviceQueueFamilyProperties(device, queueProps))) { + return r; + } + + for (uint32_t q = 0u; q < queueProps.size(); ++q) { + if (queueProps[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + bool supported = false; + if ((r = vk.getPhysicalDeviceSurfaceSupportKHR( + device, q, surface, supported))) { + return r; + } + + if (supported) { + queueIndex = q; + return VK_SUCCESS; + } + } + } + + return VK_ERROR_FEATURE_NOT_PRESENT; } /// Select a physical graphics device to use (simply the first found) @@ -381,31 +379,31 @@ selectPhysicalDevice(const sk::VulkanApi& vk, const sk::SurfaceKHR& surface, PhysicalDeviceSelection& selection) { - VkResult r = VK_SUCCESS; - - std::vector<sk::PhysicalDevice> devices; - if ((r = vk.enumeratePhysicalDevices(instance, devices))) { - return r; - } - - for (const auto& device : devices) { - auto supported = false; - if ((r = deviceSupportsRequiredExtensions(vk, device, supported))) { - return r; - } - - if (supported) { - auto queueIndex = 0u; - if ((r = findGraphicsQueue(vk, surface, device, queueIndex))) { - return r; - } - - selection = PhysicalDeviceSelection{device, queueIndex}; - return VK_SUCCESS; - } - } - - return VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; + VkResult r = VK_SUCCESS; + + std::vector<sk::PhysicalDevice> devices; + if ((r = vk.enumeratePhysicalDevices(instance, devices))) { + return r; + } + + for (const auto& device : devices) { + auto supported = false; + if ((r = deviceSupportsRequiredExtensions(vk, device, supported))) { + return r; + } + + if (supported) { + auto queueIndex = 0u; + if ((r = findGraphicsQueue(vk, surface, device, queueIndex))) { + return r; + } + + selection = PhysicalDeviceSelection{device, queueIndex}; + return VK_SUCCESS; + } + } + + return VK_ERROR_INCOMPATIBLE_DISPLAY_KHR; } VkResult @@ -414,55 +412,55 @@ GraphicsDevice::init(const pugl::VulkanLoader& loader, pugl::View& view, const PuglTestOptions& opts) { - const auto& vk = context.vk; - VkResult r = VK_SUCCESS; - - // Create a Vulkan surface for the window using the Pugl API - VkSurfaceKHR surfaceHandle = {}; - if ((r = pugl::createSurface(loader.getInstanceProcAddrFunc(), - view, - context.instance, - nullptr, - &surfaceHandle))) { - return r; - } - - // Wrap surface in a safe RAII handle - surface = sk::SurfaceKHR{surfaceHandle, - {context.instance, vk.vkDestroySurfaceKHR}}; - - PhysicalDeviceSelection physicalDeviceSelection = {}; - // Select a physical device to use - if ((r = selectPhysicalDevice( - vk, context.instance, surface, physicalDeviceSelection))) { - return r; - } - - physicalDevice = physicalDeviceSelection.physicalDevice; - graphicsIndex = physicalDeviceSelection.graphicsFamilyIndex; - - if ((r = selectSurfaceFormat(vk, physicalDevice, surface, surfaceFormat)) || - (r = selectPresentMode(vk, - physicalDevice, - surface, - opts.doubleBuffer, - opts.sync, - presentMode)) || - (r = selectPresentMode( - vk, physicalDevice, surface, true, false, resizePresentMode)) || - (r = openDevice(vk, physicalDevice, graphicsIndex, device))) { - return r; - } - - const VkCommandPoolCreateInfo commandPoolInfo{ - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, {}, graphicsIndex}; - - if ((r = vk.createCommandPool(device, commandPoolInfo, commandPool))) { - return r; - } - - graphicsQueue = vk.getDeviceQueue(device, graphicsIndex, 0); - return VK_SUCCESS; + const auto& vk = context.vk; + VkResult r = VK_SUCCESS; + + // Create a Vulkan surface for the window using the Pugl API + VkSurfaceKHR surfaceHandle = {}; + if ((r = pugl::createSurface(loader.getInstanceProcAddrFunc(), + view, + context.instance, + nullptr, + &surfaceHandle))) { + return r; + } + + // Wrap surface in a safe RAII handle + surface = + sk::SurfaceKHR{surfaceHandle, {context.instance, vk.vkDestroySurfaceKHR}}; + + PhysicalDeviceSelection physicalDeviceSelection = {}; + // Select a physical device to use + if ((r = selectPhysicalDevice( + vk, context.instance, surface, physicalDeviceSelection))) { + return r; + } + + physicalDevice = physicalDeviceSelection.physicalDevice; + graphicsIndex = physicalDeviceSelection.graphicsFamilyIndex; + + if ((r = selectSurfaceFormat(vk, physicalDevice, surface, surfaceFormat)) || + (r = selectPresentMode(vk, + physicalDevice, + surface, + opts.doubleBuffer, + opts.sync, + presentMode)) || + (r = selectPresentMode( + vk, physicalDevice, surface, true, false, resizePresentMode)) || + (r = openDevice(vk, physicalDevice, graphicsIndex, device))) { + return r; + } + + const VkCommandPoolCreateInfo commandPoolInfo{ + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, nullptr, {}, graphicsIndex}; + + if ((r = vk.createCommandPool(device, commandPoolInfo, commandPool))) { + return r; + } + + graphicsQueue = vk.getDeviceQueue(device, graphicsIndex, 0); + return VK_SUCCESS; } uint32_t @@ -471,18 +469,17 @@ findMemoryType(const sk::VulkanApi& vk, const uint32_t typeFilter, const VkMemoryPropertyFlags& properties) { - VkPhysicalDeviceMemoryProperties memProperties = - vk.getPhysicalDeviceMemoryProperties(physicalDevice); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) { - if ((typeFilter & (1 << i)) && - (memProperties.memoryTypes[i].propertyFlags & properties) == - properties) { - return i; - } - } - - return UINT32_MAX; + VkPhysicalDeviceMemoryProperties memProperties = + vk.getPhysicalDeviceMemoryProperties(physicalDevice); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) { + if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & + properties) == properties) { + return i; + } + } + + return UINT32_MAX; } VkResult @@ -492,42 +489,40 @@ Buffer::init(const sk::VulkanApi& vk, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags properties) { - const VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - nullptr, - {}, - size, - usage, - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr)}; - - const auto& device = gpu.device; - - VkResult r = VK_SUCCESS; - if ((r = vk.createBuffer(device, bufferInfo, buffer))) { - return r; - } - - const auto requirements = vk.getBufferMemoryRequirements(device, buffer); - const auto memoryTypeIndex = findMemoryType(vk, - gpu.physicalDevice, - requirements.memoryTypeBits, - properties); - - if (memoryTypeIndex == UINT32_MAX) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - const VkMemoryAllocateInfo allocInfo{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - nullptr, - requirements.size, - memoryTypeIndex}; - - if ((r = vk.allocateMemory(device, allocInfo, deviceMemory)) || - (r = vk.bindBufferMemory(device, buffer, deviceMemory, 0))) { - return r; - } - - return VK_SUCCESS; + const VkBufferCreateInfo bufferInfo{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + nullptr, + {}, + size, + usage, + VK_SHARING_MODE_EXCLUSIVE, + SK_COUNTED(0, nullptr)}; + + const auto& device = gpu.device; + + VkResult r = VK_SUCCESS; + if ((r = vk.createBuffer(device, bufferInfo, buffer))) { + return r; + } + + const auto requirements = vk.getBufferMemoryRequirements(device, buffer); + const auto memoryTypeIndex = findMemoryType( + vk, gpu.physicalDevice, requirements.memoryTypeBits, properties); + + if (memoryTypeIndex == UINT32_MAX) { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + const VkMemoryAllocateInfo allocInfo{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + nullptr, + requirements.size, + memoryTypeIndex}; + + if ((r = vk.allocateMemory(device, allocInfo, deviceMemory)) || + (r = vk.bindBufferMemory(device, buffer, deviceMemory, 0))) { + return r; + } + + return VK_SUCCESS; } VkResult @@ -538,62 +533,59 @@ Swapchain::init(const sk::VulkanApi& vk, VkSwapchainKHR oldSwapchain, bool resizing) { - capabilities = surfaceCapabilities; - extent = surfaceExtent; - - const auto minNumImages = (!capabilities.maxImageCount || - capabilities.maxImageCount >= 3u) - ? 3u - : capabilities.maxImageCount; - - const VkSwapchainCreateInfoKHR swapchainCreateInfo{ - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - nullptr, - {}, - gpu.surface, - minNumImages, - gpu.surfaceFormat.format, - gpu.surfaceFormat.colorSpace, - surfaceExtent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - SK_COUNTED(0, nullptr), - capabilities.currentTransform, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - resizing ? gpu.resizePresentMode : gpu.presentMode, - VK_TRUE, - oldSwapchain}; - - VkResult r = VK_SUCCESS; - std::vector<VkImage> images; - if ((r = vk.createSwapchainKHR(gpu.device, - swapchainCreateInfo, - swapchain)) || - (r = vk.getSwapchainImagesKHR(gpu.device, swapchain, images))) { - return r; - } - - imageViews = std::vector<sk::ImageView>(images.size()); - for (size_t i = 0; i < images.size(); ++i) { - const VkImageViewCreateInfo imageViewCreateInfo{ - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - nullptr, - {}, - images[i], - VK_IMAGE_VIEW_TYPE_2D, - gpu.surfaceFormat.format, - {}, - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; - - if ((r = vk.createImageView(gpu.device, - imageViewCreateInfo, - imageViews[i]))) { - return r; - } - } - - return VK_SUCCESS; + capabilities = surfaceCapabilities; + extent = surfaceExtent; + + const auto minNumImages = + (!capabilities.maxImageCount || capabilities.maxImageCount >= 3u) + ? 3u + : capabilities.maxImageCount; + + const VkSwapchainCreateInfoKHR swapchainCreateInfo{ + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + nullptr, + {}, + gpu.surface, + minNumImages, + gpu.surfaceFormat.format, + gpu.surfaceFormat.colorSpace, + surfaceExtent, + 1, + (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), + VK_SHARING_MODE_EXCLUSIVE, + SK_COUNTED(0, nullptr), + capabilities.currentTransform, + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + resizing ? gpu.resizePresentMode : gpu.presentMode, + VK_TRUE, + oldSwapchain}; + + VkResult r = VK_SUCCESS; + std::vector<VkImage> images; + if ((r = vk.createSwapchainKHR(gpu.device, swapchainCreateInfo, swapchain)) || + (r = vk.getSwapchainImagesKHR(gpu.device, swapchain, images))) { + return r; + } + + imageViews = std::vector<sk::ImageView>(images.size()); + for (size_t i = 0; i < images.size(); ++i) { + const VkImageViewCreateInfo imageViewCreateInfo{ + VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + nullptr, + {}, + images[i], + VK_IMAGE_VIEW_TYPE_2D, + gpu.surfaceFormat.format, + {}, + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}}; + + if ((r = vk.createImageView( + gpu.device, imageViewCreateInfo, imageViews[i]))) { + return r; + } + } + + return VK_SUCCESS; } VkResult @@ -601,121 +593,116 @@ RenderPass::init(const sk::VulkanApi& vk, const GraphicsDevice& gpu, const Swapchain& swapchain) { - const auto numImages = static_cast<uint32_t>(swapchain.imageViews.size()); - - assert(numImages > 0); - - // Create command buffers - const VkCommandBufferAllocateInfo commandBufferAllocateInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - nullptr, - gpu.commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - numImages}; - - VkResult r = VK_SUCCESS; - if ((r = vk.allocateCommandBuffers(gpu.device, - commandBufferAllocateInfo, - commandBuffers))) { - return r; - } - - static constexpr VkAttachmentReference colorAttachmentRef{ - 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - - static constexpr VkSubpassDescription subpass{ - {}, - VK_PIPELINE_BIND_POINT_GRAPHICS, - SK_COUNTED(0, nullptr), - SK_COUNTED(1, &colorAttachmentRef, nullptr, nullptr), - SK_COUNTED(0u, nullptr)}; - - static constexpr VkSubpassDependency dependency{ - VK_SUBPASS_EXTERNAL, - 0, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), - {}, - {}}; - - const VkAttachmentDescription colorAttachment{ - {}, - gpu.surfaceFormat.format, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - }; - - const VkRenderPassCreateInfo renderPassCreateInfo{ - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &colorAttachment), - SK_COUNTED(1, &subpass), - SK_COUNTED(1, &dependency)}; - - if ((r = vk.createRenderPass(gpu.device, - renderPassCreateInfo, - renderPass))) { - return r; - } - - // Create framebuffers - framebuffers = std::vector<sk::Framebuffer>(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - const VkFramebufferCreateInfo framebufferCreateInfo{ - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - nullptr, - {}, - renderPass, - SK_COUNTED(1, &swapchain.imageViews[i].get()), - swapchain.extent.width, - swapchain.extent.height, - 1}; - - if ((r = vk.createFramebuffer(gpu.device, - framebufferCreateInfo, - framebuffers[i]))) { - return r; - } - } - - return VK_SUCCESS; + const auto numImages = static_cast<uint32_t>(swapchain.imageViews.size()); + + assert(numImages > 0); + + // Create command buffers + const VkCommandBufferAllocateInfo commandBufferAllocateInfo{ + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + nullptr, + gpu.commandPool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, + numImages}; + + VkResult r = VK_SUCCESS; + if ((r = vk.allocateCommandBuffers( + gpu.device, commandBufferAllocateInfo, commandBuffers))) { + return r; + } + + static constexpr VkAttachmentReference colorAttachmentRef{ + 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + + static constexpr VkSubpassDescription subpass{ + {}, + VK_PIPELINE_BIND_POINT_GRAPHICS, + SK_COUNTED(0, nullptr), + SK_COUNTED(1, &colorAttachmentRef, nullptr, nullptr), + SK_COUNTED(0u, nullptr)}; + + static constexpr VkSubpassDependency dependency{ + VK_SUBPASS_EXTERNAL, + 0, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT), + {}, + {}}; + + const VkAttachmentDescription colorAttachment{ + {}, + gpu.surfaceFormat.format, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_CLEAR, + VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_DONT_CARE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; + + const VkRenderPassCreateInfo renderPassCreateInfo{ + VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + nullptr, + {}, + SK_COUNTED(1, &colorAttachment), + SK_COUNTED(1, &subpass), + SK_COUNTED(1, &dependency)}; + + if ((r = vk.createRenderPass(gpu.device, renderPassCreateInfo, renderPass))) { + return r; + } + + // Create framebuffers + framebuffers = std::vector<sk::Framebuffer>(numImages); + for (uint32_t i = 0; i < numImages; ++i) { + const VkFramebufferCreateInfo framebufferCreateInfo{ + VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + nullptr, + {}, + renderPass, + SK_COUNTED(1, &swapchain.imageViews[i].get()), + swapchain.extent.width, + swapchain.extent.height, + 1}; + + if ((r = vk.createFramebuffer( + gpu.device, framebufferCreateInfo, framebuffers[i]))) { + return r; + } + } + + return VK_SUCCESS; } std::vector<uint32_t> readFile(const char* const programPath, const std::string& filename) { - std::unique_ptr<char, decltype(&free)> path{resourcePath(programPath, - filename.c_str()), - &free}; + std::unique_ptr<char, decltype(&free)> path{ + resourcePath(programPath, filename.c_str()), &free}; - std::cerr << "Loading shader: " << path.get() << std::endl; + std::cerr << "Loading shader: " << path.get() << std::endl; - std::unique_ptr<FILE, decltype(&fclose)> file{fopen(path.get(), "rb"), - &fclose}; + std::unique_ptr<FILE, decltype(&fclose)> file{fopen(path.get(), "rb"), + &fclose}; - if (!file) { - std::cerr << "Failed to open file '" << filename << "'\n"; - return {}; - } + if (!file) { + std::cerr << "Failed to open file '" << filename << "'\n"; + return {}; + } - fseek(file.get(), 0, SEEK_END); - const auto fileSize = static_cast<size_t>(ftell(file.get())); - fseek(file.get(), 0, SEEK_SET); + fseek(file.get(), 0, SEEK_END); + const auto fileSize = static_cast<size_t>(ftell(file.get())); + fseek(file.get(), 0, SEEK_SET); - const auto numWords = fileSize / sizeof(uint32_t); - std::vector<uint32_t> buffer(numWords); + const auto numWords = fileSize / sizeof(uint32_t); + std::vector<uint32_t> buffer(numWords); - fread(buffer.data(), sizeof(uint32_t), numWords, file.get()); + fread(buffer.data(), sizeof(uint32_t), numWords, file.get()); - return buffer; + return buffer; } VkResult @@ -724,14 +711,14 @@ createShaderModule(const sk::VulkanApi& vk, const std::vector<uint32_t>& code, sk::ShaderModule& shaderModule) { - const VkShaderModuleCreateInfo createInfo{ - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - nullptr, - {}, - code.size() * sizeof(uint32_t), - code.data()}; - - return vk.createShaderModule(gpu.device, createInfo, shaderModule); + const VkShaderModuleCreateInfo createInfo{ + VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + nullptr, + {}, + code.size() * sizeof(uint32_t), + code.data()}; + + return vk.createShaderModule(gpu.device, createInfo, shaderModule); } VkResult @@ -739,23 +726,21 @@ RectShaders::init(const sk::VulkanApi& vk, const GraphicsDevice& gpu, const std::string& programPath) { - auto vertShaderCode = readFile(programPath.c_str(), - "shaders/rect.vert.spv"); + auto vertShaderCode = readFile(programPath.c_str(), "shaders/rect.vert.spv"); - auto fragShaderCode = readFile(programPath.c_str(), - "shaders/rect.frag.spv"); + auto fragShaderCode = readFile(programPath.c_str(), "shaders/rect.frag.spv"); - if (vertShaderCode.empty() || fragShaderCode.empty()) { - return VK_ERROR_INITIALIZATION_FAILED; - } + if (vertShaderCode.empty() || fragShaderCode.empty()) { + return VK_ERROR_INITIALIZATION_FAILED; + } - VkResult r = VK_SUCCESS; - if ((r = createShaderModule(vk, gpu, vertShaderCode, vert)) || - (r = createShaderModule(vk, gpu, fragShaderCode, frag))) { - return r; - } + VkResult r = VK_SUCCESS; + if ((r = createShaderModule(vk, gpu, vertShaderCode, vert)) || + (r = createShaderModule(vk, gpu, fragShaderCode, frag))) { + return r; + } - return VK_SUCCESS; + return VK_SUCCESS; } VkResult @@ -766,222 +751,214 @@ RectPipeline::init(const sk::VulkanApi& vk, const Swapchain& swapchain, const RenderPass& renderPass) { - const auto oldNumImages = numImages; - VkResult r = VK_SUCCESS; - - numImages = static_cast<uint32_t>(swapchain.imageViews.size()); - pipelines = {}; - pipelineLayout = {}; - descriptorSets = {}; - - if (numImages != oldNumImages) { - // Create layout descriptor pool - - const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - numImages}; - - const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - nullptr, - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - numImages, - 1u, - &poolSize}; - if ((r = vk.createDescriptorPool(gpu.device, - descriptorPoolCreateInfo, - descriptorPool))) { - return r; - } - } - - const std::vector<VkDescriptorSetLayout> layouts( - numImages, rectData.descriptorSetLayout.get()); - - const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - nullptr, - descriptorPool, - numImages, - layouts.data()}; - if ((r = vk.allocateDescriptorSets(gpu.device, - descriptorSetAllocateInfo, - descriptorSets))) { - return r; - } - - const VkDescriptorBufferInfo bufferInfo{rectData.uniformBuffer.buffer, - 0, - sizeof(UniformBufferObject)}; - - const std::array<VkWriteDescriptorSet, 1> descriptorWrites{ - {{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - descriptorSets[0], - 0, - 0, - 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - nullptr, - &bufferInfo, - nullptr}}}; - - const std::array<VkCopyDescriptorSet, 0> descriptorCopies{}; - - vk.updateDescriptorSets(gpu.device, descriptorWrites, descriptorCopies); - - static constexpr std::array<VkVertexInputAttributeDescription, 4> - vertexAttributeDescriptions{ - {// Model - {0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0}, - - // Rect instance attributes - {1u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, pos)}, - {2u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, size)}, - {3u, - 1u, - VK_FORMAT_R32G32B32A32_SFLOAT, - offsetof(Rect, fillColor)}}}; - - static constexpr std::array<VkVertexInputBindingDescription, 2> - vertexBindingDescriptions{ - VkVertexInputBindingDescription{0, - sizeof(vec2), - VK_VERTEX_INPUT_RATE_VERTEX}, - VkVertexInputBindingDescription{1u, - sizeof(Rect), - VK_VERTEX_INPUT_RATE_INSTANCE}}; - - static constexpr VkPipelineInputAssemblyStateCreateInfo inputAssembly{ - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - nullptr, - {}, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - false}; - - static constexpr VkPipelineRasterizationStateCreateInfo rasterizer{ - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - nullptr, - {}, - 0, - 0, - VK_POLYGON_MODE_FILL, - VK_CULL_MODE_BACK_BIT, - VK_FRONT_FACE_CLOCKWISE, - 0, - 0, - 0, - 0, - 1.0f}; - - static constexpr VkPipelineMultisampleStateCreateInfo multisampling{ - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - nullptr, - {}, - VK_SAMPLE_COUNT_1_BIT, - false, - 0.0f, - nullptr, - false, - false}; - - static constexpr VkPipelineColorBlendAttachmentState colorBlendAttachment{ - true, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_OP_ADD, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_ZERO, - VK_BLEND_OP_ADD, - (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)}; - - const VkPipelineShaderStageCreateInfo shaderStages[] = { - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_VERTEX_BIT, - shaders.vert.get(), - "main", - nullptr}, - {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - nullptr, - {}, - VK_SHADER_STAGE_FRAGMENT_BIT, - shaders.frag.get(), - "main", - nullptr}}; - - const VkPipelineVertexInputStateCreateInfo vertexInputInfo{ - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(static_cast<uint32_t>(vertexBindingDescriptions.size()), - vertexBindingDescriptions.data()), - SK_COUNTED(static_cast<uint32_t>(vertexAttributeDescriptions.size()), - vertexAttributeDescriptions.data())}; - - const VkViewport viewport{0.0f, - 0.0f, - float(swapchain.extent.width), - float(swapchain.extent.height), - 0.0f, - 1.0f}; - - const VkRect2D scissor{{0, 0}, swapchain.extent}; - - const VkPipelineViewportStateCreateInfo viewportState{ - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &viewport), - SK_COUNTED(1, &scissor)}; - - const VkPipelineColorBlendStateCreateInfo colorBlending{ - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - nullptr, - {}, - false, - VK_LOGIC_OP_COPY, - SK_COUNTED(1, &colorBlendAttachment), - {1.0f, 0.0f, 0.0f, 0.0f}}; - - const VkPipelineLayoutCreateInfo layoutInfo{ - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(1, &rectData.descriptorSetLayout.get()), - SK_COUNTED(0, nullptr)}; - - if ((r = vk.createPipelineLayout(gpu.device, layoutInfo, pipelineLayout))) { - return r; - } - - const std::array<VkGraphicsPipelineCreateInfo, 1> pipelineInfos{ - {{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - nullptr, - {}, - SK_COUNTED(2, shaderStages), - &vertexInputInfo, - &inputAssembly, - nullptr, - &viewportState, - &rasterizer, - &multisampling, - nullptr, - &colorBlending, - nullptr, - pipelineLayout, - renderPass.renderPass, - 0u, - {}, - 0}}}; - - if ((r = vk.createGraphicsPipelines( - gpu.device, {}, pipelineInfos, pipelines))) { - return r; - } - - return VK_SUCCESS; + const auto oldNumImages = numImages; + VkResult r = VK_SUCCESS; + + numImages = static_cast<uint32_t>(swapchain.imageViews.size()); + pipelines = {}; + pipelineLayout = {}; + descriptorSets = {}; + + if (numImages != oldNumImages) { + // Create layout descriptor pool + + const VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + numImages}; + + const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + nullptr, + VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + numImages, + 1u, + &poolSize}; + if ((r = vk.createDescriptorPool( + gpu.device, descriptorPoolCreateInfo, descriptorPool))) { + return r; + } + } + + const std::vector<VkDescriptorSetLayout> layouts( + numImages, rectData.descriptorSetLayout.get()); + + const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + nullptr, + descriptorPool, + numImages, + layouts.data()}; + if ((r = vk.allocateDescriptorSets( + gpu.device, descriptorSetAllocateInfo, descriptorSets))) { + return r; + } + + const VkDescriptorBufferInfo bufferInfo{ + rectData.uniformBuffer.buffer, 0, sizeof(UniformBufferObject)}; + + const std::array<VkWriteDescriptorSet, 1> descriptorWrites{ + {{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + descriptorSets[0], + 0, + 0, + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + nullptr, + &bufferInfo, + nullptr}}}; + + const std::array<VkCopyDescriptorSet, 0> descriptorCopies{}; + + vk.updateDescriptorSets(gpu.device, descriptorWrites, descriptorCopies); + + static constexpr std::array<VkVertexInputAttributeDescription, 4> + vertexAttributeDescriptions{ + {// Model + {0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0}, + + // Rect instance attributes + {1u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, pos)}, + {2u, 1u, VK_FORMAT_R32G32_SFLOAT, offsetof(Rect, size)}, + {3u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Rect, fillColor)}}}; + + static constexpr std::array<VkVertexInputBindingDescription, 2> + vertexBindingDescriptions{ + VkVertexInputBindingDescription{ + 0, sizeof(vec2), VK_VERTEX_INPUT_RATE_VERTEX}, + VkVertexInputBindingDescription{ + 1u, sizeof(Rect), VK_VERTEX_INPUT_RATE_INSTANCE}}; + + static constexpr VkPipelineInputAssemblyStateCreateInfo inputAssembly{ + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + nullptr, + {}, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + false}; + + static constexpr VkPipelineRasterizationStateCreateInfo rasterizer{ + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + nullptr, + {}, + 0, + 0, + VK_POLYGON_MODE_FILL, + VK_CULL_MODE_BACK_BIT, + VK_FRONT_FACE_CLOCKWISE, + 0, + 0, + 0, + 0, + 1.0f}; + + static constexpr VkPipelineMultisampleStateCreateInfo multisampling{ + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + nullptr, + {}, + VK_SAMPLE_COUNT_1_BIT, + false, + 0.0f, + nullptr, + false, + false}; + + static constexpr VkPipelineColorBlendAttachmentState colorBlendAttachment{ + true, + VK_BLEND_FACTOR_SRC_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_OP_ADD, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_ZERO, + VK_BLEND_OP_ADD, + (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT)}; + + const VkPipelineShaderStageCreateInfo shaderStages[] = { + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + {}, + VK_SHADER_STAGE_VERTEX_BIT, + shaders.vert.get(), + "main", + nullptr}, + {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + nullptr, + {}, + VK_SHADER_STAGE_FRAGMENT_BIT, + shaders.frag.get(), + "main", + nullptr}}; + + const VkPipelineVertexInputStateCreateInfo vertexInputInfo{ + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + nullptr, + {}, + SK_COUNTED(static_cast<uint32_t>(vertexBindingDescriptions.size()), + vertexBindingDescriptions.data()), + SK_COUNTED(static_cast<uint32_t>(vertexAttributeDescriptions.size()), + vertexAttributeDescriptions.data())}; + + const VkViewport viewport{0.0f, + 0.0f, + float(swapchain.extent.width), + float(swapchain.extent.height), + 0.0f, + 1.0f}; + + const VkRect2D scissor{{0, 0}, swapchain.extent}; + + const VkPipelineViewportStateCreateInfo viewportState{ + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + nullptr, + {}, + SK_COUNTED(1, &viewport), + SK_COUNTED(1, &scissor)}; + + const VkPipelineColorBlendStateCreateInfo colorBlending{ + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + nullptr, + {}, + false, + VK_LOGIC_OP_COPY, + SK_COUNTED(1, &colorBlendAttachment), + {1.0f, 0.0f, 0.0f, 0.0f}}; + + const VkPipelineLayoutCreateInfo layoutInfo{ + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + nullptr, + {}, + SK_COUNTED(1, &rectData.descriptorSetLayout.get()), + SK_COUNTED(0, nullptr)}; + + if ((r = vk.createPipelineLayout(gpu.device, layoutInfo, pipelineLayout))) { + return r; + } + + const std::array<VkGraphicsPipelineCreateInfo, 1> pipelineInfos{ + {{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + nullptr, + {}, + SK_COUNTED(2, shaderStages), + &vertexInputInfo, + &inputAssembly, + nullptr, + &viewportState, + &rasterizer, + &multisampling, + nullptr, + &colorBlending, + nullptr, + pipelineLayout, + renderPass.renderPass, + 0u, + {}, + 0}}}; + + if ((r = vk.createGraphicsPipelines( + gpu.device, {}, pipelineInfos, pipelines))) { + return r; + } + + return VK_SUCCESS; } VkResult @@ -989,86 +966,85 @@ RectData::init(const sk::VulkanApi& vk, const GraphicsDevice& gpu, const size_t nRects) { - numRects = nRects; - - static constexpr VkDescriptorSetLayoutBinding uboLayoutBinding{ - 0, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - 1, - VK_SHADER_STAGE_VERTEX_BIT, - nullptr}; - - const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - nullptr, - {}, - 1, - &uboLayoutBinding}; - - VkResult r = VK_SUCCESS; - if ((r = vk.createDescriptorSetLayout(gpu.device, - descriptorSetLayoutInfo, - descriptorSetLayout)) || - (r = uniformBuffer.init(vk, - gpu, - sizeof(UniformBufferObject), - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) || - (r = vk.mapMemory(gpu.device, - uniformBuffer.deviceMemory, - 0, - sizeof(UniformBufferObject), - {}, - uniformData))) { - return r; - } - - const VkBufferUsageFlags usageFlags = (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_SRC_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - const VkMemoryPropertyFlags propertyFlags = - (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - if ((r = modelBuffer.init( - vk, gpu, sizeof(rectVertices), usageFlags, propertyFlags))) { - return r; - } - - { - // Copy model vertices (directly, we do this only once) - sk::MappedMemory modelData; - if ((r = vk.mapMemory(gpu.device, - modelBuffer.deviceMemory, - 0, - static_cast<VkDeviceSize>(sizeof(rectVertices)), - {}, - modelData))) { - return r; - } - - memcpy(modelData.get(), rectVertices, sizeof(rectVertices)); - } - - if ((r = instanceBuffer.init( - vk, gpu, sizeof(Rect) * numRects, usageFlags, propertyFlags))) { - return r; - } - - // Map attribute vertices (we will update them every frame) - const auto rectsSize = static_cast<VkDeviceSize>(sizeof(Rect) * numRects); - if ((r = vk.mapMemory(gpu.device, - instanceBuffer.deviceMemory, - 0, - rectsSize, - {}, - vertexData))) { - return r; - } - - return VK_SUCCESS; + numRects = nRects; + + static constexpr VkDescriptorSetLayoutBinding uboLayoutBinding{ + 0, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + 1, + VK_SHADER_STAGE_VERTEX_BIT, + nullptr}; + + const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + nullptr, + {}, + 1, + &uboLayoutBinding}; + + VkResult r = VK_SUCCESS; + if ((r = vk.createDescriptorSetLayout( + gpu.device, descriptorSetLayoutInfo, descriptorSetLayout)) || + (r = uniformBuffer.init(vk, + gpu, + sizeof(UniformBufferObject), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) || + (r = vk.mapMemory(gpu.device, + uniformBuffer.deviceMemory, + 0, + sizeof(UniformBufferObject), + {}, + uniformData))) { + return r; + } + + const VkBufferUsageFlags usageFlags = + (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT); + + const VkMemoryPropertyFlags propertyFlags = + (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + if ((r = modelBuffer.init( + vk, gpu, sizeof(rectVertices), usageFlags, propertyFlags))) { + return r; + } + + { + // Copy model vertices (directly, we do this only once) + sk::MappedMemory modelData; + if ((r = vk.mapMemory(gpu.device, + modelBuffer.deviceMemory, + 0, + static_cast<VkDeviceSize>(sizeof(rectVertices)), + {}, + modelData))) { + return r; + } + + memcpy(modelData.get(), rectVertices, sizeof(rectVertices)); + } + + if ((r = instanceBuffer.init( + vk, gpu, sizeof(Rect) * numRects, usageFlags, propertyFlags))) { + return r; + } + + // Map attribute vertices (we will update them every frame) + const auto rectsSize = static_cast<VkDeviceSize>(sizeof(Rect) * numRects); + if ((r = vk.mapMemory(gpu.device, + instanceBuffer.deviceMemory, + 0, + rectsSize, + {}, + vertexData))) { + return r; + } + + return VK_SUCCESS; } VkResult @@ -1076,38 +1052,34 @@ RenderSync::init(const sk::VulkanApi& vk, const sk::Device& device, const uint32_t numImages) { - const auto maxInFlight = std::max(1u, numImages - 1u); - VkResult r = VK_SUCCESS; - - imageAvailable = std::vector<sk::Semaphore>(numImages); - renderFinished = std::vector<sk::Semaphore>(numImages); - for (uint32_t i = 0; i < numImages; ++i) { - static constexpr VkSemaphoreCreateInfo semaphoreInfo{ - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, {}}; - - if ((r = vk.createSemaphore(device, - semaphoreInfo, - imageAvailable[i])) || - (r = vk.createSemaphore(device, - semaphoreInfo, - renderFinished[i]))) { - return r; - } - } - - inFlight = std::vector<sk::Fence>(maxInFlight); - for (uint32_t i = 0; i < maxInFlight; ++i) { - static constexpr VkFenceCreateInfo fenceInfo{ - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - nullptr, - VK_FENCE_CREATE_SIGNALED_BIT}; - - if ((r = vk.createFence(device, fenceInfo, inFlight[i]))) { - return r; - } - } - - return VK_SUCCESS; + const auto maxInFlight = std::max(1u, numImages - 1u); + VkResult r = VK_SUCCESS; + + imageAvailable = std::vector<sk::Semaphore>(numImages); + renderFinished = std::vector<sk::Semaphore>(numImages); + for (uint32_t i = 0; i < numImages; ++i) { + static constexpr VkSemaphoreCreateInfo semaphoreInfo{ + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, {}}; + + if ((r = vk.createSemaphore(device, semaphoreInfo, imageAvailable[i])) || + (r = vk.createSemaphore(device, semaphoreInfo, renderFinished[i]))) { + return r; + } + } + + inFlight = std::vector<sk::Fence>(maxInFlight); + for (uint32_t i = 0; i < maxInFlight; ++i) { + static constexpr VkFenceCreateInfo fenceInfo{ + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + nullptr, + VK_FENCE_CREATE_SIGNALED_BIT}; + + if ((r = vk.createFence(device, fenceInfo, inFlight[i]))) { + return r; + } + } + + return VK_SUCCESS; } VkResult @@ -1118,21 +1090,20 @@ Renderer::init(const sk::VulkanApi& vk, const VkExtent2D extent, bool resizing) { - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(gpu.physicalDevice, - gpu.surface, - capabilities)) || - (r = swapchain.init(vk, gpu, capabilities, extent, {}, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size()); - return sync.init(vk, gpu.device, numFrames); + VkResult r = VK_SUCCESS; + VkSurfaceCapabilitiesKHR capabilities = {}; + + if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( + gpu.physicalDevice, gpu.surface, capabilities)) || + (r = swapchain.init(vk, gpu, capabilities, extent, {}, resizing)) || + (r = renderPass.init(vk, gpu, swapchain)) || + (r = rectPipeline.init( + vk, gpu, rectData, rectShaders, swapchain, renderPass))) { + return r; + } + + const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size()); + return sync.init(vk, gpu.device, numFrames); } VkResult @@ -1144,27 +1115,26 @@ Renderer::recreate(const sk::VulkanApi& vk, const VkExtent2D extent, bool resizing) { - VkResult r = VK_SUCCESS; - const auto oldNumImages = swapchain.imageViews.size(); - - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(gpu.physicalDevice, - surface, - capabilities)) || - (r = swapchain.init( - vk, gpu, capabilities, extent, swapchain.swapchain, resizing)) || - (r = renderPass.init(vk, gpu, swapchain)) || - (r = rectPipeline.init( - vk, gpu, rectData, rectShaders, swapchain, renderPass))) { - return r; - } - - const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size()); - if (swapchain.imageViews.size() != oldNumImages) { - return sync.init(vk, gpu.device, numFrames); - } - - return VK_SUCCESS; + VkResult r = VK_SUCCESS; + const auto oldNumImages = swapchain.imageViews.size(); + + VkSurfaceCapabilitiesKHR capabilities = {}; + if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( + gpu.physicalDevice, surface, capabilities)) || + (r = swapchain.init( + vk, gpu, capabilities, extent, swapchain.swapchain, resizing)) || + (r = renderPass.init(vk, gpu, swapchain)) || + (r = rectPipeline.init( + vk, gpu, rectData, rectShaders, swapchain, renderPass))) { + return r; + } + + const auto numFrames = static_cast<uint32_t>(swapchain.imageViews.size()); + if (swapchain.imageViews.size() != oldNumImages) { + return sync.init(vk, gpu.device, numFrames); + } + + return VK_SUCCESS; } VKAPI_ATTR @@ -1178,43 +1148,43 @@ debugCallback(VkDebugReportFlagsEXT flags, const char* msg, void*) { - std::cerr << sk::string(static_cast<VkDebugReportFlagBitsEXT>(flags)) - << ": " << layerPrefix << ": " << msg << std::endl; + std::cerr << sk::string(static_cast<VkDebugReportFlagBitsEXT>(flags)) << ": " + << layerPrefix << ": " << msg << std::endl; - return VK_FALSE; + return VK_FALSE; } bool hasExtension(const char* name, const std::vector<VkExtensionProperties>& properties) { - for (const auto& p : properties) { - if (!strcmp(p.extensionName, name)) { - return true; - } - } + for (const auto& p : properties) { + if (!strcmp(p.extensionName, name)) { + return true; + } + } - return false; + return false; } bool hasLayer(const char* name, const std::vector<VkLayerProperties>& properties) { - for (const auto& p : properties) { - if (!strcmp(p.layerName, name)) { - return true; - } - } + for (const auto& p : properties) { + if (!strcmp(p.layerName, name)) { + return true; + } + } - return false; + return false; } template<class Value> void logInfo(const char* heading, const Value& value) { - std::cout << std::setw(26) << std::left << (std::string(heading) + ":") - << value << std::endl; + std::cout << std::setw(26) << std::left << (std::string(heading) + ":") + << value << std::endl; } VkResult @@ -1222,62 +1192,62 @@ createInstance(sk::VulkanInitApi& initApi, const PuglTestOptions& opts, sk::Instance& instance) { - VkResult r = VK_SUCCESS; - - std::vector<VkLayerProperties> layerProps; - std::vector<VkExtensionProperties> extProps; - if ((r = initApi.enumerateInstanceLayerProperties(layerProps)) || - (r = initApi.enumerateInstanceExtensionProperties(extProps))) { - return r; - } - - const auto puglExtensions = pugl::getInstanceExtensions(); - auto extensions = std::vector<const char*>(puglExtensions.begin(), - puglExtensions.end()); - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps)) { - extensions.push_back("VK_EXT_debug_report"); - } - - // Add validation layers if error checking is enabled - std::vector<const char*> layers; - if (opts.errorChecking) { - for (const char* l : {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation"}) { - if (hasLayer(l, layerProps)) { - layers.push_back(l); - } - } - } - - for (const auto& e : extensions) { - logInfo("Using instance extension", e); - } - - for (const auto& l : layers) { - logInfo("Using instance layer", l); - } - - static constexpr VkApplicationInfo appInfo{ - VK_STRUCTURE_TYPE_APPLICATION_INFO, - nullptr, - "Pugl Vulkan Demo", - 0, - nullptr, - 0, - VK_MAKE_VERSION(1, 0, 0), - }; - - const VkInstanceCreateInfo createInfo{ - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - nullptr, - VkInstanceCreateFlags{}, - &appInfo, - SK_COUNTED(uint32_t(layers.size()), layers.data()), - SK_COUNTED(uint32_t(extensions.size()), extensions.data())}; - - return initApi.createInstance(createInfo, instance); + VkResult r = VK_SUCCESS; + + std::vector<VkLayerProperties> layerProps; + std::vector<VkExtensionProperties> extProps; + if ((r = initApi.enumerateInstanceLayerProperties(layerProps)) || + (r = initApi.enumerateInstanceExtensionProperties(extProps))) { + return r; + } + + const auto puglExtensions = pugl::getInstanceExtensions(); + auto extensions = + std::vector<const char*>(puglExtensions.begin(), puglExtensions.end()); + + // Add extra extensions we want to use if they are supported + if (hasExtension("VK_EXT_debug_report", extProps)) { + extensions.push_back("VK_EXT_debug_report"); + } + + // Add validation layers if error checking is enabled + std::vector<const char*> layers; + if (opts.errorChecking) { + for (const char* l : {"VK_LAYER_KHRONOS_validation", + "VK_LAYER_LUNARG_standard_validation"}) { + if (hasLayer(l, layerProps)) { + layers.push_back(l); + } + } + } + + for (const auto& e : extensions) { + logInfo("Using instance extension", e); + } + + for (const auto& l : layers) { + logInfo("Using instance layer", l); + } + + static constexpr VkApplicationInfo appInfo{ + VK_STRUCTURE_TYPE_APPLICATION_INFO, + nullptr, + "Pugl Vulkan Demo", + 0, + nullptr, + 0, + VK_MAKE_VERSION(1, 0, 0), + }; + + const VkInstanceCreateInfo createInfo{ + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + nullptr, + VkInstanceCreateFlags{}, + &appInfo, + SK_COUNTED(uint32_t(layers.size()), layers.data()), + SK_COUNTED(uint32_t(extensions.size()), extensions.data())}; + + return initApi.createInstance(createInfo, instance); } VkResult @@ -1286,28 +1256,27 @@ getDebugReportCallback(sk::VulkanApi& api, const bool verbose, sk::DebugReportCallbackEXT& callback) { - if (api.vkCreateDebugReportCallbackEXT) { - VkDebugReportFlagsEXT flags = - (VK_DEBUG_REPORT_WARNING_BIT_EXT | - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | - VK_DEBUG_REPORT_ERROR_BIT_EXT); - - if (verbose) { - flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; - flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; - } - - const VkDebugReportCallbackCreateInfoEXT createInfo{ - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, - nullptr, - flags, - debugCallback, - nullptr}; - - return api.createDebugReportCallbackEXT(instance, createInfo, callback); - } - - return VK_ERROR_FEATURE_NOT_PRESENT; + if (api.vkCreateDebugReportCallbackEXT) { + VkDebugReportFlagsEXT flags = (VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | + VK_DEBUG_REPORT_ERROR_BIT_EXT); + + if (verbose) { + flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; + } + + const VkDebugReportCallbackCreateInfoEXT createInfo{ + VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT, + nullptr, + flags, + debugCallback, + nullptr}; + + return api.createDebugReportCallbackEXT(instance, createInfo, callback); + } + + return VK_ERROR_FEATURE_NOT_PRESENT; } void @@ -1318,40 +1287,36 @@ recordCommandBuffer(sk::CommandScope& cmd, const RectData& rectData, const size_t imageIndex) { - const VkClearColorValue clearColorValue{{0.0f, 0.0f, 0.0f, 1.0f}}; - const VkClearValue clearValue{clearColorValue}; - - const VkRenderPassBeginInfo renderPassBegin{ - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - renderPass.renderPass, - renderPass.framebuffers[imageIndex], - VkRect2D{{0, 0}, swapchain.extent}, - SK_COUNTED(1, &clearValue)}; - - auto pass = cmd.beginRenderPass(renderPassBegin, - VK_SUBPASS_CONTENTS_INLINE); - - pass.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, - rectPipeline.pipelines[0]); - - const std::array<VkDeviceSize, 1> offsets{0}; - pass.bindVertexBuffers( - 0u, SK_COUNTED(1u, &rectData.modelBuffer.buffer.get(), offsets.data())); - - pass.bindVertexBuffers(1u, - SK_COUNTED(1u, - &rectData.instanceBuffer.buffer.get(), - offsets.data())); - - pass.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, - rectPipeline.pipelineLayout, - 0u, - SK_COUNTED(1u, rectPipeline.descriptorSets.get()), - 0u, - nullptr); - - pass.draw(4u, static_cast<uint32_t>(rectData.numRects), 0u, 0u); + const VkClearColorValue clearColorValue{{0.0f, 0.0f, 0.0f, 1.0f}}; + const VkClearValue clearValue{clearColorValue}; + + const VkRenderPassBeginInfo renderPassBegin{ + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + nullptr, + renderPass.renderPass, + renderPass.framebuffers[imageIndex], + VkRect2D{{0, 0}, swapchain.extent}, + SK_COUNTED(1, &clearValue)}; + + auto pass = cmd.beginRenderPass(renderPassBegin, VK_SUBPASS_CONTENTS_INLINE); + + pass.bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, rectPipeline.pipelines[0]); + + const std::array<VkDeviceSize, 1> offsets{0}; + pass.bindVertexBuffers( + 0u, SK_COUNTED(1u, &rectData.modelBuffer.buffer.get(), offsets.data())); + + pass.bindVertexBuffers( + 1u, SK_COUNTED(1u, &rectData.instanceBuffer.buffer.get(), offsets.data())); + + pass.bindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, + rectPipeline.pipelineLayout, + 0u, + SK_COUNTED(1u, rectPipeline.descriptorSets.get()), + 0u, + nullptr); + + pass.draw(4u, static_cast<uint32_t>(rectData.numRects), 0u, 0u); } VkResult @@ -1361,30 +1326,29 @@ recordCommandBuffers(const sk::VulkanApi& vk, const RectPipeline& rectPipeline, const RectData& rectData) { - VkResult r = VK_SUCCESS; - - for (size_t i = 0; i < swapchain.imageViews.size(); ++i) { - const VkCommandBufferBeginInfo beginInfo{ - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - nullptr, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - nullptr}; - - auto* const commandBuffer = renderPass.commandBuffers[i]; - auto cmd = vk.beginCommandBuffer(commandBuffer, beginInfo); - if (!cmd) { - return cmd.error(); - } - - recordCommandBuffer( - cmd, swapchain, renderPass, rectPipeline, rectData, i); - - if ((r = cmd.end())) { - return r; - } - } - - return VK_SUCCESS; + VkResult r = VK_SUCCESS; + + for (size_t i = 0; i < swapchain.imageViews.size(); ++i) { + const VkCommandBufferBeginInfo beginInfo{ + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + nullptr, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + nullptr}; + + auto* const commandBuffer = renderPass.commandBuffers[i]; + auto cmd = vk.beginCommandBuffer(commandBuffer, beginInfo); + if (!cmd) { + return cmd.error(); + } + + recordCommandBuffer(cmd, swapchain, renderPass, rectPipeline, rectData, i); + + if ((r = cmd.end())) { + return r; + } + } + + return VK_SUCCESS; } class PuglVulkanDemo; @@ -1392,76 +1356,76 @@ class PuglVulkanDemo; class View : public pugl::View { public: - View(pugl::World& world, PuglVulkanDemo& app) - : pugl::View{world} - , _app{app} - { - setEventHandler(*this); - } - - template<PuglEventType t, class Base> - pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept - { - return pugl::Status::success; - } - - pugl::Status onEvent(const pugl::ConfigureEvent& event); - pugl::Status onEvent(const pugl::UpdateEvent& event); - pugl::Status onEvent(const pugl::ExposeEvent& event); - pugl::Status onEvent(const pugl::LoopEnterEvent& event); - pugl::Status onEvent(const pugl::TimerEvent& event); - pugl::Status onEvent(const pugl::LoopLeaveEvent& event); - pugl::Status onEvent(const pugl::KeyPressEvent& event); - pugl::Status onEvent(const pugl::CloseEvent& event); + View(pugl::World& world, PuglVulkanDemo& app) + : pugl::View{world} + , _app{app} + { + setEventHandler(*this); + } + + template<PuglEventType t, class Base> + pugl::Status onEvent(const pugl::Event<t, Base>&) noexcept + { + return pugl::Status::success; + } + + pugl::Status onEvent(const pugl::ConfigureEvent& event); + pugl::Status onEvent(const pugl::UpdateEvent& event); + pugl::Status onEvent(const pugl::ExposeEvent& event); + pugl::Status onEvent(const pugl::LoopEnterEvent& event); + pugl::Status onEvent(const pugl::TimerEvent& event); + pugl::Status onEvent(const pugl::LoopLeaveEvent& event); + pugl::Status onEvent(const pugl::KeyPressEvent& event); + pugl::Status onEvent(const pugl::CloseEvent& event); private: - PuglVulkanDemo& _app; + PuglVulkanDemo& _app; }; class PuglVulkanDemo { public: - PuglVulkanDemo(const char* executablePath, - const PuglTestOptions& o, - size_t numRects); - - const char* programPath; - PuglTestOptions opts; - pugl::World world; - pugl::VulkanLoader loader; - View view; - VulkanContext vulkan; - GraphicsDevice gpu; - Renderer renderer; - RectData rectData; - RectShaders rectShaders; - uint32_t framesDrawn{0}; - VkExtent2D extent{512u, 512u}; - std::vector<Rect> rects; - bool resizing{false}; - bool quit{false}; + PuglVulkanDemo(const char* executablePath, + const PuglTestOptions& o, + size_t numRects); + + const char* programPath; + PuglTestOptions opts; + pugl::World world; + pugl::VulkanLoader loader; + View view; + VulkanContext vulkan; + GraphicsDevice gpu; + Renderer renderer; + RectData rectData; + RectShaders rectShaders; + uint32_t framesDrawn{0}; + VkExtent2D extent{512u, 512u}; + std::vector<Rect> rects; + bool resizing{false}; + bool quit{false}; }; std::vector<Rect> makeRects(const size_t numRects, const uint32_t windowWidth) { - std::vector<Rect> rects(numRects); - for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, static_cast<float>(windowWidth)); - } + std::vector<Rect> rects(numRects); + for (size_t i = 0; i < numRects; ++i) { + rects[i] = makeRect(i, static_cast<float>(windowWidth)); + } - return rects; + return rects; } PuglVulkanDemo::PuglVulkanDemo(const char* const executablePath, const PuglTestOptions& o, const size_t numRects) - : programPath{executablePath} - , opts{o} - , world{pugl::WorldType::program, pugl::WorldFlag::threads} - , loader{world} - , view{world, *this} - , rects{makeRects(numRects, extent.width)} + : programPath{executablePath} + , opts{o} + , world{pugl::WorldType::program, pugl::WorldFlag::threads} + , loader{world} + , view{world, *this} + , rects{makeRects(numRects, extent.width)} {} VkResult @@ -1472,148 +1436,140 @@ recreateRenderer(PuglVulkanDemo& app, const RectData& rectData, const RectShaders& rectShaders) { - VkResult r = VK_SUCCESS; - VkSurfaceCapabilitiesKHR capabilities = {}; - if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR(gpu.physicalDevice, - gpu.surface, - capabilities))) { - return r; - } - - // There is a known race issue here, so we clamp and hope for the best - const VkExtent2D clampedExtent{ - std::min(capabilities.maxImageExtent.width, - std::max(capabilities.minImageExtent.width, extent.width)), - std::min(capabilities.maxImageExtent.height, - std::max(capabilities.minImageExtent.height, extent.height))}; - - if ((r = vk.deviceWaitIdle(gpu.device)) || - (r = app.renderer.recreate(vk, - gpu.surface, - gpu, - rectData, - rectShaders, - clampedExtent, - app.resizing))) { - return r; - } - - // Reset current (initially signaled) fence because we already waited - vk.resetFence(gpu.device, - app.renderer.sync.inFlight[app.renderer.sync.currentFrame]); - - // Record new command buffers - return recordCommandBuffers(vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - rectData); + VkResult r = VK_SUCCESS; + VkSurfaceCapabilitiesKHR capabilities = {}; + if ((r = vk.getPhysicalDeviceSurfaceCapabilitiesKHR( + gpu.physicalDevice, gpu.surface, capabilities))) { + return r; + } + + // There is a known race issue here, so we clamp and hope for the best + const VkExtent2D clampedExtent{ + std::min(capabilities.maxImageExtent.width, + std::max(capabilities.minImageExtent.width, extent.width)), + std::min(capabilities.maxImageExtent.height, + std::max(capabilities.minImageExtent.height, extent.height))}; + + if ((r = vk.deviceWaitIdle(gpu.device)) || + (r = app.renderer.recreate(vk, + gpu.surface, + gpu, + rectData, + rectShaders, + clampedExtent, + app.resizing))) { + return r; + } + + // Reset current (initially signaled) fence because we already waited + vk.resetFence(gpu.device, + app.renderer.sync.inFlight[app.renderer.sync.currentFrame]); + + // Record new command buffers + return recordCommandBuffers(vk, + app.renderer.swapchain, + app.renderer.renderPass, + app.renderer.rectPipeline, + rectData); } pugl::Status View::onEvent(const pugl::ConfigureEvent& event) { - // We just record the size here and lazily resize the surface when exposed - _app.extent = {static_cast<uint32_t>(event.width), - static_cast<uint32_t>(event.height)}; + // We just record the size here and lazily resize the surface when exposed + _app.extent = {static_cast<uint32_t>(event.width), + static_cast<uint32_t>(event.height)}; - return pugl::Status::success; + return pugl::Status::success; } pugl::Status View::onEvent(const pugl::UpdateEvent&) { - return postRedisplay(); + return postRedisplay(); } VkResult beginFrame(PuglVulkanDemo& app, const sk::Device& device, uint32_t& imageIndex) { - const auto& vk = app.vulkan.vk; - - VkResult r = VK_SUCCESS; - - // Wait until we can start rendering the next frame - if ((r = vk.waitForFence( - device, - app.renderer.sync.inFlight[app.renderer.sync.currentFrame])) || - (r = vk.resetFence( - device, - app.renderer.sync.inFlight[app.renderer.sync.currentFrame]))) { - return r; - } - - // Rebuild the renderer first if the window size has changed - if (app.extent.width != app.renderer.swapchain.extent.width || - app.extent.height != app.renderer.swapchain.extent.height) { - if ((r = recreateRenderer(app, - vk, - app.gpu, - app.extent, - app.rectData, - app.rectShaders))) { - return r; - } - } - - // Acquire the next image to render, rebuilding if necessary - while ( - (r = vk.acquireNextImageKHR( - device, - app.renderer.swapchain.swapchain, - UINT64_MAX, - app.renderer.sync.imageAvailable[app.renderer.sync.currentFrame], - {}, - &imageIndex))) { - switch (r) { - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - if ((r = recreateRenderer(app, - vk, - app.gpu, - app.renderer.swapchain.extent, - app.rectData, - app.rectShaders))) { - return r; - } - continue; - default: - return r; - } - } - - return VK_SUCCESS; + const auto& vk = app.vulkan.vk; + + VkResult r = VK_SUCCESS; + + // Wait until we can start rendering the next frame + if ((r = vk.waitForFence( + device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame])) || + (r = vk.resetFence( + device, app.renderer.sync.inFlight[app.renderer.sync.currentFrame]))) { + return r; + } + + // Rebuild the renderer first if the window size has changed + if (app.extent.width != app.renderer.swapchain.extent.width || + app.extent.height != app.renderer.swapchain.extent.height) { + if ((r = recreateRenderer( + app, vk, app.gpu, app.extent, app.rectData, app.rectShaders))) { + return r; + } + } + + // Acquire the next image to render, rebuilding if necessary + while ((r = vk.acquireNextImageKHR( + device, + app.renderer.swapchain.swapchain, + UINT64_MAX, + app.renderer.sync.imageAvailable[app.renderer.sync.currentFrame], + {}, + &imageIndex))) { + switch (r) { + case VK_SUBOPTIMAL_KHR: + case VK_ERROR_OUT_OF_DATE_KHR: + if ((r = recreateRenderer(app, + vk, + app.gpu, + app.renderer.swapchain.extent, + app.rectData, + app.rectShaders))) { + return r; + } + continue; + default: + return r; + } + } + + return VK_SUCCESS; } void update(PuglVulkanDemo& app, const double time) { - // Animate rectangles - for (size_t i = 0; i < app.rects.size(); ++i) { - moveRect(&app.rects[i], - i, - app.rects.size(), - static_cast<float>(app.extent.width), - static_cast<float>(app.extent.height), - time); - } - - // Update vertex buffer - memcpy(app.rectData.vertexData.get(), - app.rects.data(), - sizeof(Rect) * app.rects.size()); - - // Update uniform buffer - UniformBufferObject ubo = {{}}; - mat4Ortho(ubo.projection, - 0.0f, - float(app.renderer.swapchain.extent.width), - 0.0f, - float(app.renderer.swapchain.extent.height), - -1.0f, - 1.0f); - - memcpy(app.rectData.uniformData.get(), &ubo, sizeof(ubo)); + // Animate rectangles + for (size_t i = 0; i < app.rects.size(); ++i) { + moveRect(&app.rects[i], + i, + app.rects.size(), + static_cast<float>(app.extent.width), + static_cast<float>(app.extent.height), + time); + } + + // Update vertex buffer + memcpy(app.rectData.vertexData.get(), + app.rects.data(), + sizeof(Rect) * app.rects.size()); + + // Update uniform buffer + UniformBufferObject ubo = {{}}; + mat4Ortho(ubo.projection, + 0.0f, + float(app.renderer.swapchain.extent.width), + 0.0f, + float(app.renderer.swapchain.extent.height), + -1.0f, + 1.0f); + + memcpy(app.rectData.uniformData.get(), &ubo, sizeof(ubo)); } VkResult @@ -1622,133 +1578,132 @@ endFrame(const sk::VulkanApi& vk, const Renderer& renderer, const uint32_t imageIndex) { - const auto currentFrame = renderer.sync.currentFrame; - VkResult r = VK_SUCCESS; - - static constexpr VkPipelineStageFlags waitStage = - VK_PIPELINE_STAGE_TRANSFER_BIT; - - const VkSubmitInfo submitInfo{ - VK_STRUCTURE_TYPE_SUBMIT_INFO, - nullptr, - SK_COUNTED(1, &renderer.sync.imageAvailable[currentFrame].get()), - &waitStage, - SK_COUNTED(1, &renderer.renderPass.commandBuffers[imageIndex]), - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get())}; - - if ((r = vk.queueSubmit(gpu.graphicsQueue, - submitInfo, - renderer.sync.inFlight[currentFrame]))) { - return r; - } - - const VkPresentInfoKHR presentInfo{ - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - nullptr, - SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get()), - SK_COUNTED(1, &renderer.swapchain.swapchain.get(), &imageIndex), - nullptr}; - - switch ((r = vk.queuePresentKHR(gpu.graphicsQueue, presentInfo))) { - case VK_SUCCESS: // Sucessfully presented - case VK_SUBOPTIMAL_KHR: // Probably a resize race, ignore - case VK_ERROR_OUT_OF_DATE_KHR: // Probably a resize race, ignore - break; - default: - return r; - } - - return VK_SUCCESS; + const auto currentFrame = renderer.sync.currentFrame; + VkResult r = VK_SUCCESS; + + static constexpr VkPipelineStageFlags waitStage = + VK_PIPELINE_STAGE_TRANSFER_BIT; + + const VkSubmitInfo submitInfo{ + VK_STRUCTURE_TYPE_SUBMIT_INFO, + nullptr, + SK_COUNTED(1, &renderer.sync.imageAvailable[currentFrame].get()), + &waitStage, + SK_COUNTED(1, &renderer.renderPass.commandBuffers[imageIndex]), + SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get())}; + + if ((r = vk.queueSubmit(gpu.graphicsQueue, + submitInfo, + renderer.sync.inFlight[currentFrame]))) { + return r; + } + + const VkPresentInfoKHR presentInfo{ + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + nullptr, + SK_COUNTED(1, &renderer.sync.renderFinished[imageIndex].get()), + SK_COUNTED(1, &renderer.swapchain.swapchain.get(), &imageIndex), + nullptr}; + + switch ((r = vk.queuePresentKHR(gpu.graphicsQueue, presentInfo))) { + case VK_SUCCESS: // Sucessfully presented + case VK_SUBOPTIMAL_KHR: // Probably a resize race, ignore + case VK_ERROR_OUT_OF_DATE_KHR: // Probably a resize race, ignore + break; + default: + return r; + } + + return VK_SUCCESS; } pugl::Status View::onEvent(const pugl::ExposeEvent&) { - const auto& vk = _app.vulkan.vk; - const auto& gpu = _app.gpu; + const auto& vk = _app.vulkan.vk; + const auto& gpu = _app.gpu; - // Acquire the next image, waiting and/or rebuilding if necessary - auto nextImageIndex = 0u; - if (beginFrame(_app, gpu.device, nextImageIndex)) { - return pugl::Status::unknownError; - } + // Acquire the next image, waiting and/or rebuilding if necessary + auto nextImageIndex = 0u; + if (beginFrame(_app, gpu.device, nextImageIndex)) { + return pugl::Status::unknownError; + } - // Ready to go, update the data to the current time - update(_app, world().time()); + // Ready to go, update the data to the current time + update(_app, world().time()); - // Submit the frame to the queue and present it - endFrame(vk, gpu, _app.renderer, nextImageIndex); + // Submit the frame to the queue and present it + endFrame(vk, gpu, _app.renderer, nextImageIndex); - ++_app.framesDrawn; - ++_app.renderer.sync.currentFrame; - _app.renderer.sync.currentFrame %= _app.renderer.sync.inFlight.size(); + ++_app.framesDrawn; + ++_app.renderer.sync.currentFrame; + _app.renderer.sync.currentFrame %= _app.renderer.sync.inFlight.size(); - return pugl::Status::success; + return pugl::Status::success; } pugl::Status View::onEvent(const pugl::LoopEnterEvent&) { - _app.resizing = true; - startTimer(resizeTimerId, - 1.0 / static_cast<double>(getHint(pugl::ViewHint::refreshRate))); + _app.resizing = true; + startTimer(resizeTimerId, + 1.0 / static_cast<double>(getHint(pugl::ViewHint::refreshRate))); - return pugl::Status::success; + return pugl::Status::success; } pugl::Status View::onEvent(const pugl::TimerEvent&) { - return postRedisplay(); + return postRedisplay(); } pugl::Status View::onEvent(const pugl::LoopLeaveEvent&) { - stopTimer(resizeTimerId); + stopTimer(resizeTimerId); - // Trigger a swapchain recreation with the normal present mode - _app.renderer.swapchain.extent = {}; - _app.resizing = false; + // Trigger a swapchain recreation with the normal present mode + _app.renderer.swapchain.extent = {}; + _app.resizing = false; - return pugl::Status::success; + return pugl::Status::success; } pugl::Status View::onEvent(const pugl::KeyPressEvent& event) { - if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { - _app.quit = true; - } + if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') { + _app.quit = true; + } - return pugl::Status::success; + return pugl::Status::success; } pugl::Status View::onEvent(const pugl::CloseEvent&) { - _app.quit = true; + _app.quit = true; - return pugl::Status::success; + return pugl::Status::success; } VkResult VulkanContext::init(pugl::VulkanLoader& loader, const PuglTestOptions& opts) { - VkResult r = VK_SUCCESS; + VkResult r = VK_SUCCESS; - sk::VulkanInitApi initApi{}; + sk::VulkanInitApi initApi{}; - // Load Vulkan API and set up the fundamentals - if ((r = initApi.init(loader.getInstanceProcAddrFunc())) || - (r = createInstance(initApi, opts, instance)) || - (r = vk.init(initApi, instance)) || - (r = getDebugReportCallback( - vk, instance, opts.verbose, debugCallback))) { - return r; - } + // Load Vulkan API and set up the fundamentals + if ((r = initApi.init(loader.getInstanceProcAddrFunc())) || + (r = createInstance(initApi, opts, instance)) || + (r = vk.init(initApi, instance)) || + (r = getDebugReportCallback(vk, instance, opts.verbose, debugCallback))) { + return r; + } - return VK_SUCCESS; + return VK_SUCCESS; } int @@ -1756,90 +1711,90 @@ run(const char* const programPath, const PuglTestOptions opts, const size_t numRects) { - PuglVulkanDemo app{programPath, opts, numRects}; - - VkResult r = VK_SUCCESS; - const auto width = static_cast<int>(app.extent.width); - const auto height = static_cast<int>(app.extent.height); - - // Realize window so we can set up Vulkan - app.world.setClassName("PuglVulkanDemo"); - app.view.setWindowTitle("Pugl Vulkan Demo"); - app.view.setAspectRatio(1, 1, 16, 9); - app.view.setDefaultSize(width, height); - app.view.setMinSize(width / 4, height / 4); - app.view.setBackend(pugl::vulkanBackend()); - app.view.setHint(pugl::ViewHint::resizable, opts.resizable); - const pugl::Status st = app.view.realize(); - if (st != pugl::Status::success) { - return logError("Failed to create window (%s)\n", pugl::strerror(st)); - } - - if (!app.loader) { - return logError("Failed to load Vulkan library\n"); - } - - // Load Vulkan for the view - if ((r = app.vulkan.init(app.loader, opts))) { - return logError("Failed to set up Vulkan API (%s)\n", sk::string(r)); - } - - const auto& vk = app.vulkan.vk; - - // Set up the graphics device - if ((r = app.gpu.init(app.loader, app.vulkan, app.view, opts))) { - return logError("Failed to set up device (%s)\n", sk::string(r)); - } - - logInfo("Present mode", sk::string(app.gpu.presentMode)); - logInfo("Resize present mode", sk::string(app.gpu.resizePresentMode)); - - // Set up the rectangle data we will render every frame - if ((r = app.rectData.init(vk, app.gpu, app.rects.size()))) { - return logError("Failed to allocate render data (%s)\n", sk::string(r)); - } - - // Load shader modules - if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) { - return logError("Failed to load shaders (%s)\n", sk::string(r)); - } - - if ((r = app.renderer.init(app.vulkan.vk, - app.gpu, - app.rectData, - app.rectShaders, - app.extent, - false))) { - return logError("Failed to create renderer (%s)\n", sk::string(r)); - } - - logInfo("Swapchain frames", - std::to_string(app.renderer.swapchain.imageViews.size())); - logInfo("Frames in flight", - std::to_string(app.renderer.sync.inFlight.size())); - - recordCommandBuffers(app.vulkan.vk, - app.renderer.swapchain, - app.renderer.renderPass, - app.renderer.rectPipeline, - app.rectData); - - const int refreshRate = app.view.getHint(pugl::ViewHint::refreshRate); - const double frameDuration = 1.0 / static_cast<double>(refreshRate); - const double timeout = app.opts.sync ? frameDuration : 0.0; - - PuglFpsPrinter fpsPrinter = {app.world.time()}; - app.view.show(); - while (!app.quit) { - app.world.update(timeout); - puglPrintFps(app.world.cobj(), &fpsPrinter, &app.framesDrawn); - } - - if ((r = app.vulkan.vk.deviceWaitIdle(app.gpu.device))) { - return logError("Failed to wait for device idle (%s)\n", sk::string(r)); - } - - return 0; + PuglVulkanDemo app{programPath, opts, numRects}; + + VkResult r = VK_SUCCESS; + const auto width = static_cast<int>(app.extent.width); + const auto height = static_cast<int>(app.extent.height); + + // Realize window so we can set up Vulkan + app.world.setClassName("PuglVulkanDemo"); + app.view.setWindowTitle("Pugl Vulkan Demo"); + app.view.setAspectRatio(1, 1, 16, 9); + app.view.setDefaultSize(width, height); + app.view.setMinSize(width / 4, height / 4); + app.view.setBackend(pugl::vulkanBackend()); + app.view.setHint(pugl::ViewHint::resizable, opts.resizable); + const pugl::Status st = app.view.realize(); + if (st != pugl::Status::success) { + return logError("Failed to create window (%s)\n", pugl::strerror(st)); + } + + if (!app.loader) { + return logError("Failed to load Vulkan library\n"); + } + + // Load Vulkan for the view + if ((r = app.vulkan.init(app.loader, opts))) { + return logError("Failed to set up Vulkan API (%s)\n", sk::string(r)); + } + + const auto& vk = app.vulkan.vk; + + // Set up the graphics device + if ((r = app.gpu.init(app.loader, app.vulkan, app.view, opts))) { + return logError("Failed to set up device (%s)\n", sk::string(r)); + } + + logInfo("Present mode", sk::string(app.gpu.presentMode)); + logInfo("Resize present mode", sk::string(app.gpu.resizePresentMode)); + + // Set up the rectangle data we will render every frame + if ((r = app.rectData.init(vk, app.gpu, app.rects.size()))) { + return logError("Failed to allocate render data (%s)\n", sk::string(r)); + } + + // Load shader modules + if ((r = app.rectShaders.init(vk, app.gpu, app.programPath))) { + return logError("Failed to load shaders (%s)\n", sk::string(r)); + } + + if ((r = app.renderer.init(app.vulkan.vk, + app.gpu, + app.rectData, + app.rectShaders, + app.extent, + false))) { + return logError("Failed to create renderer (%s)\n", sk::string(r)); + } + + logInfo("Swapchain frames", + std::to_string(app.renderer.swapchain.imageViews.size())); + logInfo("Frames in flight", + std::to_string(app.renderer.sync.inFlight.size())); + + recordCommandBuffers(app.vulkan.vk, + app.renderer.swapchain, + app.renderer.renderPass, + app.renderer.rectPipeline, + app.rectData); + + const int refreshRate = app.view.getHint(pugl::ViewHint::refreshRate); + const double frameDuration = 1.0 / static_cast<double>(refreshRate); + const double timeout = app.opts.sync ? frameDuration : 0.0; + + PuglFpsPrinter fpsPrinter = {app.world.time()}; + app.view.show(); + while (!app.quit) { + app.world.update(timeout); + puglPrintFps(app.world.cobj(), &fpsPrinter, &app.framesDrawn); + } + + if ((r = app.vulkan.vk.deviceWaitIdle(app.gpu.device))) { + return logError("Failed to wait for device idle (%s)\n", sk::string(r)); + } + + return 0; } } // namespace @@ -1847,25 +1802,25 @@ run(const char* const programPath, int main(int argc, char** argv) { - // Parse command line options - const char* const programPath = argv[0]; - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(programPath, ""); - return 0; - } - - // Parse number of rectangles argument, if given - int64_t numRects = 1000; - if (argc >= 1) { - char* endptr = nullptr; - numRects = strtol(argv[0], &endptr, 10); - if (endptr != argv[0] + strlen(argv[0]) || numRects < 1) { - logError("Invalid number of rectangles: %s\n", argv[0]); - return 1; - } - } - - // Run application - return run(programPath, opts, static_cast<size_t>(numRects)); + // Parse command line options + const char* const programPath = argv[0]; + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage(programPath, ""); + return 0; + } + + // Parse number of rectangles argument, if given + int64_t numRects = 1000; + if (argc >= 1) { + char* endptr = nullptr; + numRects = strtol(argv[0], &endptr, 10); + if (endptr != argv[0] + strlen(argv[0]) || numRects < 1) { + logError("Invalid number of rectangles: %s\n", argv[0]); + return 1; + } + } + + // Run application + return run(programPath, opts, static_cast<size_t>(numRects)); } diff --git a/examples/pugl_vulkan_demo.c b/examples/pugl_vulkan_demo.c index ec96ec3..4a8324e 100644 --- a/examples/pugl_vulkan_demo.c +++ b/examples/pugl_vulkan_demo.c @@ -50,55 +50,55 @@ /// Dynamically loaded Vulkan API functions typedef struct { - PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; - PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; + PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; + PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; } InstanceAPI; /// Vulkan swapchain and everything that depends on it typedef struct { - VkSwapchainKHR rawSwapchain; - uint32_t nImages; - VkExtent2D extent; - VkImage* images; - VkImageView* imageViews; - VkFence* fences; - VkCommandBuffer* commandBuffers; + VkSwapchainKHR rawSwapchain; + uint32_t nImages; + VkExtent2D extent; + VkImage* images; + VkImageView* imageViews; + VkFence* fences; + VkCommandBuffer* commandBuffers; } Swapchain; /// Synchronization semaphores typedef struct { - VkSemaphore presentComplete; - VkSemaphore renderFinished; + VkSemaphore presentComplete; + VkSemaphore renderFinished; } Sync; /// Vulkan state, purely Vulkan functions can depend on only this typedef struct { - InstanceAPI api; - VkInstance instance; - VkDebugReportCallbackEXT debugCallback; - VkSurfaceKHR surface; - VkSurfaceFormatKHR surfaceFormat; - VkPresentModeKHR presentMode; - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDevice physicalDevice; - uint32_t graphicsIndex; - VkDevice device; - VkQueue graphicsQueue; - VkCommandPool commandPool; - Swapchain* swapchain; - Sync sync; + InstanceAPI api; + VkInstance instance; + VkDebugReportCallbackEXT debugCallback; + VkSurfaceKHR surface; + VkSurfaceFormatKHR surfaceFormat; + VkPresentModeKHR presentMode; + VkPhysicalDeviceProperties deviceProperties; + VkPhysicalDevice physicalDevice; + uint32_t graphicsIndex; + VkDevice device; + VkQueue graphicsQueue; + VkCommandPool commandPool; + Swapchain* swapchain; + Sync sync; } VulkanState; /// Complete application typedef struct { - PuglTestOptions opts; - PuglWorld* world; - PuglView* view; - VulkanState vk; - uint32_t framesDrawn; - uint32_t width; - uint32_t height; - bool quit; + PuglTestOptions opts; + PuglWorld* world; + PuglView* view; + VulkanState vk; + uint32_t framesDrawn; + uint32_t width; + uint32_t height; + bool quit; } VulkanApp; static VKAPI_ATTR VkBool32 VKAPI_CALL @@ -111,27 +111,27 @@ debugCallback(VkDebugReportFlagsEXT flags, const char* msg, void* userData) { - (void)userData; - (void)objType; - (void)obj; - (void)location; - (void)code; - - if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { - fprintf(stderr, "note: "); - } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { - fprintf(stderr, "warning: "); - } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { - fprintf(stderr, "performance warning: "); - } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { - fprintf(stderr, "error: "); - } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { - fprintf(stderr, "debug: "); - } - - fprintf(stderr, "%s: ", layerPrefix); - fprintf(stderr, "%s\n", msg); - return VK_FALSE; + (void)userData; + (void)objType; + (void)obj; + (void)location; + (void)code; + + if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) { + fprintf(stderr, "note: "); + } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + fprintf(stderr, "warning: "); + } else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) { + fprintf(stderr, "performance warning: "); + } else if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + fprintf(stderr, "error: "); + } else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) { + fprintf(stderr, "debug: "); + } + + fprintf(stderr, "%s: ", layerPrefix); + fprintf(stderr, "%s\n", msg); + return VK_FALSE; } static bool @@ -139,13 +139,13 @@ hasExtension(const char* const name, const VkExtensionProperties* const properties, const uint32_t count) { - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].extensionName, name)) { - return true; - } - } + for (uint32_t i = 0; i < count; ++i) { + if (!strcmp(properties[i].extensionName, name)) { + return true; + } + } - return false; + return false; } static bool @@ -153,13 +153,13 @@ hasLayer(const char* const name, const VkLayerProperties* const properties, const uint32_t count) { - for (uint32_t i = 0; i < count; ++i) { - if (!strcmp(properties[i].layerName, name)) { - return true; - } - } + for (uint32_t i = 0; i < count; ++i) { + if (!strcmp(properties[i].layerName, name)) { + return true; + } + } - return false; + return false; } static void @@ -167,129 +167,129 @@ pushString(const char*** const array, uint32_t* const count, const char* const string) { - *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*)); - (*array)[*count] = string; - ++*count; + *array = (const char**)realloc(*array, (*count + 1) * sizeof(const char*)); + (*array)[*count] = string; + ++*count; } static VkResult createInstance(VulkanApp* const app) { - const VkApplicationInfo appInfo = { - VK_STRUCTURE_TYPE_APPLICATION_INFO, - NULL, - "Pugl Vulkan Test", - VK_MAKE_VERSION(0, 1, 0), - "Pugl Vulkan Test Engine", - VK_MAKE_VERSION(0, 1, 0), - VK_MAKE_VERSION(1, 0, 0), - }; - - // Get the number of supported extensions and layers - VkResult vr = VK_SUCCESS; - uint32_t nExtProps = 0; - uint32_t nLayerProps = 0; - if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) || - (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) { - return vr; - } - - // Get properties of supported extensions - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps); - - uint32_t nExtensions = 0; - const char** extensions = NULL; - - // Add extensions required by pugl - uint32_t nPuglExts = 0; - const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts); - for (uint32_t i = 0; i < nPuglExts; ++i) { - pushString(&extensions, &nExtensions, puglExts[i]); - } - - // Add extra extensions we want to use if they are supported - if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) { - pushString(&extensions, &nExtensions, "VK_EXT_debug_report"); - } - - // Get properties of supported layers - VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties); - vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps); - - // Add validation layers if error checking is enabled - uint32_t nLayers = 0; - const char** layers = NULL; - if (app->opts.errorChecking) { - const char* debugLayers[] = {"VK_LAYER_KHRONOS_validation", - "VK_LAYER_LUNARG_standard_validation", - NULL}; - - for (const char** l = debugLayers; *l; ++l) { - if (hasLayer(*l, layerProps, nLayerProps)) { - pushString(&layers, &nLayers, *l); - } - } - } - - for (uint32_t i = 0; i < nExtensions; ++i) { - printf("Using instance extension: %s\n", extensions[i]); - } - - for (uint32_t i = 0; i < nLayers; ++i) { - printf("Using instance layer: %s\n", layers[i]); - } - - const VkInstanceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - NULL, - 0, - &appInfo, - COUNTED(nLayers, layers), - COUNTED(nExtensions, extensions), - }; - - if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &app->vk.instance))) { - logError("Could not create Vulkan Instance: %d\n", vr); - } - - free(layers); - free(extensions); - free(layerProps); - free(extProps); - - return vr; + const VkApplicationInfo appInfo = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, + NULL, + "Pugl Vulkan Test", + VK_MAKE_VERSION(0, 1, 0), + "Pugl Vulkan Test Engine", + VK_MAKE_VERSION(0, 1, 0), + VK_MAKE_VERSION(1, 0, 0), + }; + + // Get the number of supported extensions and layers + VkResult vr = VK_SUCCESS; + uint32_t nExtProps = 0; + uint32_t nLayerProps = 0; + if ((vr = vkEnumerateInstanceLayerProperties(&nLayerProps, NULL)) || + (vr = vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, NULL))) { + return vr; + } + + // Get properties of supported extensions + VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); + vkEnumerateInstanceExtensionProperties(NULL, &nExtProps, extProps); + + uint32_t nExtensions = 0; + const char** extensions = NULL; + + // Add extensions required by pugl + uint32_t nPuglExts = 0; + const char* const* puglExts = puglGetInstanceExtensions(&nPuglExts); + for (uint32_t i = 0; i < nPuglExts; ++i) { + pushString(&extensions, &nExtensions, puglExts[i]); + } + + // Add extra extensions we want to use if they are supported + if (hasExtension("VK_EXT_debug_report", extProps, nExtProps)) { + pushString(&extensions, &nExtensions, "VK_EXT_debug_report"); + } + + // Get properties of supported layers + VkLayerProperties* layerProps = AALLOC(nLayerProps, VkLayerProperties); + vkEnumerateInstanceLayerProperties(&nLayerProps, layerProps); + + // Add validation layers if error checking is enabled + uint32_t nLayers = 0; + const char** layers = NULL; + if (app->opts.errorChecking) { + const char* debugLayers[] = {"VK_LAYER_KHRONOS_validation", + "VK_LAYER_LUNARG_standard_validation", + NULL}; + + for (const char** l = debugLayers; *l; ++l) { + if (hasLayer(*l, layerProps, nLayerProps)) { + pushString(&layers, &nLayers, *l); + } + } + } + + for (uint32_t i = 0; i < nExtensions; ++i) { + printf("Using instance extension: %s\n", extensions[i]); + } + + for (uint32_t i = 0; i < nLayers; ++i) { + printf("Using instance layer: %s\n", layers[i]); + } + + const VkInstanceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + NULL, + 0, + &appInfo, + COUNTED(nLayers, layers), + COUNTED(nExtensions, extensions), + }; + + if ((vr = vkCreateInstance(&createInfo, ALLOC_VK, &app->vk.instance))) { + logError("Could not create Vulkan Instance: %d\n", vr); + } + + free(layers); + free(extensions); + free(layerProps); + free(extProps); + + return vr; } static VkResult enableDebugging(VulkanState* const vk) { - vk->api.vkCreateDebugReportCallbackEXT = - (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkCreateDebugReportCallbackEXT"); - - vk->api.vkDestroyDebugReportCallbackEXT = - (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( - vk->instance, "vkDestroyDebugReportCallbackEXT"); - - if (vk->api.vkCreateDebugReportCallbackEXT) { - const VkDebugReportCallbackCreateInfoEXT info = { - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - NULL, - VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, - debugCallback, - NULL, - }; - - VkResult vr = VK_SUCCESS; - if ((vr = vk->api.vkCreateDebugReportCallbackEXT( - vk->instance, &info, ALLOC_VK, &vk->debugCallback))) { - logError("Could not create debug reporter: %d\n", vr); - return vr; - } - } - - return VK_SUCCESS; + vk->api.vkCreateDebugReportCallbackEXT = + (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr( + vk->instance, "vkCreateDebugReportCallbackEXT"); + + vk->api.vkDestroyDebugReportCallbackEXT = + (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr( + vk->instance, "vkDestroyDebugReportCallbackEXT"); + + if (vk->api.vkCreateDebugReportCallbackEXT) { + const VkDebugReportCallbackCreateInfoEXT info = { + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + NULL, + VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT, + debugCallback, + NULL, + }; + + VkResult vr = VK_SUCCESS; + if ((vr = vk->api.vkCreateDebugReportCallbackEXT( + vk->instance, &info, ALLOC_VK, &vk->debugCallback))) { + logError("Could not create debug reporter: %d\n", vr); + return vr; + } + } + + return VK_SUCCESS; } static VkResult @@ -297,52 +297,51 @@ getGraphicsQueueIndex(VkSurfaceKHR surface, VkPhysicalDevice device, uint32_t* graphicsIndex) { - VkResult r = VK_SUCCESS; - - uint32_t nProps = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, NULL); - - VkQueueFamilyProperties* props = AALLOC(nProps, VkQueueFamilyProperties); - vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, props); - - for (uint32_t q = 0; q < nProps; ++q) { - if (props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - VkBool32 supported = false; - if ((r = vkGetPhysicalDeviceSurfaceSupportKHR( - device, q, surface, &supported))) { - free(props); - return r; - } else if (supported) { - *graphicsIndex = q; - free(props); - return VK_SUCCESS; - } - } - } - - free(props); - return VK_ERROR_FEATURE_NOT_PRESENT; + VkResult r = VK_SUCCESS; + + uint32_t nProps = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, NULL); + + VkQueueFamilyProperties* props = AALLOC(nProps, VkQueueFamilyProperties); + vkGetPhysicalDeviceQueueFamilyProperties(device, &nProps, props); + + for (uint32_t q = 0; q < nProps; ++q) { + if (props[q].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + VkBool32 supported = false; + if ((r = vkGetPhysicalDeviceSurfaceSupportKHR( + device, q, surface, &supported))) { + free(props); + return r; + } else if (supported) { + *graphicsIndex = q; + free(props); + return VK_SUCCESS; + } + } + } + + free(props); + return VK_ERROR_FEATURE_NOT_PRESENT; } static bool supportsRequiredExtensions(const VkPhysicalDevice device) { - uint32_t nExtProps = 0; - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, NULL); - - VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); - vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, extProps); - - for (uint32_t i = 0; i < nExtProps; ++i) { - if (!strcmp(extProps[i].extensionName, - VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { - free(extProps); - return true; - } - } - - free(extProps); - return false; + uint32_t nExtProps = 0; + vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, NULL); + + VkExtensionProperties* extProps = AALLOC(nExtProps, VkExtensionProperties); + vkEnumerateDeviceExtensionProperties(device, NULL, &nExtProps, extProps); + + for (uint32_t i = 0; i < nExtProps; ++i) { + if (!strcmp(extProps[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) { + free(extProps); + return true; + } + } + + free(extProps); + return false; } static bool @@ -350,12 +349,12 @@ isDeviceSuitable(const VulkanState* const vk, const VkPhysicalDevice device, uint32_t* const graphicsIndex) { - if (!supportsRequiredExtensions(device) || - getGraphicsQueueIndex(vk->surface, device, graphicsIndex)) { - return false; - } + if (!supportsRequiredExtensions(device) || + getGraphicsQueueIndex(vk->surface, device, graphicsIndex)) { + return false; + } - return true; + return true; } /** @@ -366,134 +365,134 @@ isDeviceSuitable(const VulkanState* const vk, static VkResult selectPhysicalDevice(VulkanState* const vk) { - VkResult vr = VK_SUCCESS; - if (!vk->surface) { - logError("Cannot select a physical device without a surface\n"); - return VK_ERROR_SURFACE_LOST_KHR; - } - - uint32_t nDevices = 0; - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { - logError("Failed to get count of physical devices: %d\n", vr); - return vr; - } - - if (!nDevices) { - logError("No physical devices found\n"); - return VK_ERROR_DEVICE_LOST; - } - - VkPhysicalDevice* devices = AALLOC(nDevices, VkPhysicalDevice); - if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { - logError("Failed to enumerate physical devices: %d\n", vr); - free(devices); - return vr; - } - - uint32_t i = 0; - for (i = 0; i < nDevices; ++i) { - VkPhysicalDeviceProperties deviceProps = {0}; - vkGetPhysicalDeviceProperties(devices[i], &deviceProps); - - uint32_t graphicsIndex = 0; - if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) { - printf("Using device %u/%u: \"%s\"\n", - i + 1, - nDevices, - deviceProps.deviceName); - vk->deviceProperties = deviceProps; - vk->physicalDevice = devices[i]; - vk->graphicsIndex = graphicsIndex; - printf("Using graphics queue family: %u\n", vk->graphicsIndex); - break; - } - - printf("Device \"%s\" not suitable\n", deviceProps.deviceName); - } - - if (i >= nDevices) { - logError("No suitable devices found\n"); - vr = VK_ERROR_DEVICE_LOST; - } - - free(devices); - return vr; + VkResult vr = VK_SUCCESS; + if (!vk->surface) { + logError("Cannot select a physical device without a surface\n"); + return VK_ERROR_SURFACE_LOST_KHR; + } + + uint32_t nDevices = 0; + if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, NULL))) { + logError("Failed to get count of physical devices: %d\n", vr); + return vr; + } + + if (!nDevices) { + logError("No physical devices found\n"); + return VK_ERROR_DEVICE_LOST; + } + + VkPhysicalDevice* devices = AALLOC(nDevices, VkPhysicalDevice); + if ((vr = vkEnumeratePhysicalDevices(vk->instance, &nDevices, devices))) { + logError("Failed to enumerate physical devices: %d\n", vr); + free(devices); + return vr; + } + + uint32_t i = 0; + for (i = 0; i < nDevices; ++i) { + VkPhysicalDeviceProperties deviceProps = {0}; + vkGetPhysicalDeviceProperties(devices[i], &deviceProps); + + uint32_t graphicsIndex = 0; + if (isDeviceSuitable(vk, devices[i], &graphicsIndex)) { + printf("Using device %u/%u: \"%s\"\n", + i + 1, + nDevices, + deviceProps.deviceName); + vk->deviceProperties = deviceProps; + vk->physicalDevice = devices[i]; + vk->graphicsIndex = graphicsIndex; + printf("Using graphics queue family: %u\n", vk->graphicsIndex); + break; + } + + printf("Device \"%s\" not suitable\n", deviceProps.deviceName); + } + + if (i >= nDevices) { + logError("No suitable devices found\n"); + vr = VK_ERROR_DEVICE_LOST; + } + + free(devices); + return vr; } /// Opens the logical device and sets up the queue and command pool static VkResult openDevice(VulkanState* const vk) { - if (vk->device) { - logError("Renderer already has an opened device\n"); - return VK_NOT_READY; - } - - const float graphicsQueuePriority = 1.0f; - const char* const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; - - const VkDeviceQueueCreateInfo queueCreateInfo = { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - COUNTED(1, &graphicsQueuePriority), - }; - - const VkDeviceCreateInfo createInfo = { - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - NULL, - 0, - COUNTED(1, &queueCreateInfo), - COUNTED(0, NULL), - COUNTED(1, &swapchainName), - NULL, - }; - - VkDevice device = NULL; - VkResult vr = VK_SUCCESS; - if ((vr = vkCreateDevice( - vk->physicalDevice, &createInfo, ALLOC_VK, &device))) { - logError("Could not open device \"%s\": %d\n", - vk->deviceProperties.deviceName, - vr); - return vr; - } - - vk->device = device; - vkGetDeviceQueue(vk->device, vk->graphicsIndex, 0, &vk->graphicsQueue); - - const VkCommandPoolCreateInfo commandInfo = { - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - NULL, - 0, - vk->graphicsIndex, - }; - - if ((vr = vkCreateCommandPool( - vk->device, &commandInfo, ALLOC_VK, &vk->commandPool))) { - logError("Could not create command pool: %d\n", vr); - return vr; - } - - return VK_SUCCESS; + if (vk->device) { + logError("Renderer already has an opened device\n"); + return VK_NOT_READY; + } + + const float graphicsQueuePriority = 1.0f; + const char* const swapchainName = VK_KHR_SWAPCHAIN_EXTENSION_NAME; + + const VkDeviceQueueCreateInfo queueCreateInfo = { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + NULL, + 0, + vk->graphicsIndex, + COUNTED(1, &graphicsQueuePriority), + }; + + const VkDeviceCreateInfo createInfo = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + NULL, + 0, + COUNTED(1, &queueCreateInfo), + COUNTED(0, NULL), + COUNTED(1, &swapchainName), + NULL, + }; + + VkDevice device = NULL; + VkResult vr = VK_SUCCESS; + if ((vr = + vkCreateDevice(vk->physicalDevice, &createInfo, ALLOC_VK, &device))) { + logError("Could not open device \"%s\": %d\n", + vk->deviceProperties.deviceName, + vr); + return vr; + } + + vk->device = device; + vkGetDeviceQueue(vk->device, vk->graphicsIndex, 0, &vk->graphicsQueue); + + const VkCommandPoolCreateInfo commandInfo = { + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + NULL, + 0, + vk->graphicsIndex, + }; + + if ((vr = vkCreateCommandPool( + vk->device, &commandInfo, ALLOC_VK, &vk->commandPool))) { + logError("Could not create command pool: %d\n", vr); + return vr; + } + + return VK_SUCCESS; } static const char* presentModeString(const VkPresentModeKHR presentMode) { - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "FIFO relaxed"; - default: - return "Other"; - } + switch (presentMode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return "Immediate"; + case VK_PRESENT_MODE_MAILBOX_KHR: + return "Mailbox"; + case VK_PRESENT_MODE_FIFO_KHR: + return "FIFO"; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + return "FIFO relaxed"; + default: + return "Other"; + } } static bool @@ -501,90 +500,82 @@ hasPresentMode(const VkPresentModeKHR mode, const VkPresentModeKHR* const presentModes, const uint32_t nPresentModes) { - for (uint32_t i = 0; i < nPresentModes; ++i) { - if (presentModes[i] == mode) { - return true; - } - } + for (uint32_t i = 0; i < nPresentModes; ++i) { + if (presentModes[i] == mode) { + return true; + } + } - return false; + return false; } /// Configure the surface for the currently opened device static VkResult configureSurface(VulkanState* const vk) { - uint32_t nFormats = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR(vk->physicalDevice, - vk->surface, - &nFormats, - NULL); - if (!nFormats) { - logError("No surface formats available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkSurfaceFormatKHR* surfaceFormats = AALLOC(nFormats, VkSurfaceFormatKHR); - vkGetPhysicalDeviceSurfaceFormatsKHR(vk->physicalDevice, - vk->surface, - &nFormats, - surfaceFormats); - - const VkSurfaceFormatKHR want = {VK_FORMAT_B8G8R8A8_UNORM, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; - - uint32_t formatIndex = 0; - for (formatIndex = 0; formatIndex < nFormats; ++formatIndex) { - if (surfaceFormats[formatIndex].format == want.format && - surfaceFormats[formatIndex].colorSpace == want.colorSpace) { - vk->surfaceFormat = want; - break; - } - } - free(surfaceFormats); - if (formatIndex >= nFormats) { - logError("Could not find a suitable surface format\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - uint32_t nPresentModes = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(vk->physicalDevice, - vk->surface, - &nPresentModes, - NULL); - if (!nPresentModes) { - logError("No present modes available\n"); - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - VkPresentModeKHR* presentModes = AALLOC(nPresentModes, VkPresentModeKHR); - vkGetPhysicalDeviceSurfacePresentModesKHR(vk->physicalDevice, - vk->surface, - &nPresentModes, - presentModes); - - const VkPresentModeKHR tryModes[] = { - VK_PRESENT_MODE_MAILBOX_KHR, - VK_PRESENT_MODE_FIFO_RELAXED_KHR, - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - }; - - VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; - for (uint32_t i = 0; i < sizeof(tryModes) / sizeof(VkPresentModeKHR); ++i) { - if (hasPresentMode(tryModes[i], presentModes, nPresentModes)) { - presentMode = tryModes[i]; - break; - } - } - - free(presentModes); - vk->presentMode = presentMode; - printf("Using present mode: \"%s\" (%u)\n", - presentModeString(presentMode), - presentMode); - - return VK_SUCCESS; + uint32_t nFormats = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR( + vk->physicalDevice, vk->surface, &nFormats, NULL); + if (!nFormats) { + logError("No surface formats available\n"); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + + VkSurfaceFormatKHR* surfaceFormats = AALLOC(nFormats, VkSurfaceFormatKHR); + vkGetPhysicalDeviceSurfaceFormatsKHR( + vk->physicalDevice, vk->surface, &nFormats, surfaceFormats); + + const VkSurfaceFormatKHR want = {VK_FORMAT_B8G8R8A8_UNORM, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}; + + uint32_t formatIndex = 0; + for (formatIndex = 0; formatIndex < nFormats; ++formatIndex) { + if (surfaceFormats[formatIndex].format == want.format && + surfaceFormats[formatIndex].colorSpace == want.colorSpace) { + vk->surfaceFormat = want; + break; + } + } + free(surfaceFormats); + if (formatIndex >= nFormats) { + logError("Could not find a suitable surface format\n"); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + + uint32_t nPresentModes = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR( + vk->physicalDevice, vk->surface, &nPresentModes, NULL); + if (!nPresentModes) { + logError("No present modes available\n"); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + + VkPresentModeKHR* presentModes = AALLOC(nPresentModes, VkPresentModeKHR); + vkGetPhysicalDeviceSurfacePresentModesKHR( + vk->physicalDevice, vk->surface, &nPresentModes, presentModes); + + const VkPresentModeKHR tryModes[] = { + VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_FIFO_RELAXED_KHR, + VK_PRESENT_MODE_FIFO_KHR, + VK_PRESENT_MODE_IMMEDIATE_KHR, + }; + + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + for (uint32_t i = 0; i < sizeof(tryModes) / sizeof(VkPresentModeKHR); ++i) { + if (hasPresentMode(tryModes[i], presentModes, nPresentModes)) { + presentMode = tryModes[i]; + break; + } + } + + free(presentModes); + vk->presentMode = presentMode; + printf("Using present mode: \"%s\" (%u)\n", + presentModeString(presentMode), + presentMode); + + return VK_SUCCESS; } static VkResult @@ -592,140 +583,137 @@ createRawSwapchain(VulkanState* const vk, const uint32_t width, const uint32_t height) { - VkSurfaceCapabilitiesKHR surfaceCapabilities; - VkResult vr = VK_SUCCESS; - if ((vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - vk->physicalDevice, vk->surface, &surfaceCapabilities))) { - logError("Could not get surface capabilities: %d\n", vr); - return vr; - } - - /* There is a known race condition with window/surface sizes, so we clamp - to what Vulkan reports and hope for the best. */ - - vk->swapchain->extent.width = - CLAMP(width, - surfaceCapabilities.minImageExtent.width, - surfaceCapabilities.maxImageExtent.width); - - vk->swapchain->extent.height = - CLAMP(height, - surfaceCapabilities.minImageExtent.height, - surfaceCapabilities.maxImageExtent.height); - - vk->swapchain->nImages = surfaceCapabilities.minImageCount; - - const VkSwapchainCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - NULL, - 0, - vk->surface, - vk->swapchain->nImages, - vk->surfaceFormat.format, - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - vk->swapchain->extent, - 1, - (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), - VK_SHARING_MODE_EXCLUSIVE, - COUNTED(0, NULL), - surfaceCapabilities.currentTransform, - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - vk->presentMode, - VK_TRUE, - 0, - }; - - if ((vr = vkCreateSwapchainKHR(vk->device, - &createInfo, - ALLOC_VK, - &vk->swapchain->rawSwapchain))) { - logError("Could not create swapchain: %d\n", vr); - return vr; - } - - return VK_SUCCESS; + VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkResult vr = VK_SUCCESS; + if ((vr = vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + vk->physicalDevice, vk->surface, &surfaceCapabilities))) { + logError("Could not get surface capabilities: %d\n", vr); + return vr; + } + + /* There is a known race condition with window/surface sizes, so we clamp + to what Vulkan reports and hope for the best. */ + + vk->swapchain->extent.width = CLAMP(width, + surfaceCapabilities.minImageExtent.width, + surfaceCapabilities.maxImageExtent.width); + + vk->swapchain->extent.height = + CLAMP(height, + surfaceCapabilities.minImageExtent.height, + surfaceCapabilities.maxImageExtent.height); + + vk->swapchain->nImages = surfaceCapabilities.minImageCount; + + const VkSwapchainCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + NULL, + 0, + vk->surface, + vk->swapchain->nImages, + vk->surfaceFormat.format, + VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + vk->swapchain->extent, + 1, + (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT), + VK_SHARING_MODE_EXCLUSIVE, + COUNTED(0, NULL), + surfaceCapabilities.currentTransform, + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + vk->presentMode, + VK_TRUE, + 0, + }; + + if ((vr = vkCreateSwapchainKHR( + vk->device, &createInfo, ALLOC_VK, &vk->swapchain->rawSwapchain))) { + logError("Could not create swapchain: %d\n", vr); + return vr; + } + + return VK_SUCCESS; } static VkResult recordCommandBuffers(VulkanState* const vk) { - const VkClearColorValue clearValue = {{ - 0xA4 / (float)0x100, // R - 0x1E / (float)0x100, // G - 0x22 / (float)0x100, // B - 0xFF / (float)0x100, // A - }}; - - const VkImageSubresourceRange range = { - VK_IMAGE_ASPECT_COLOR_BIT, - 0, - 1, - 0, - 1, - }; - - const VkCommandBufferBeginInfo beginInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - NULL, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, - NULL, - }; - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - const VkImageMemoryBarrier toClearBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_MEMORY_READ_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - const VkImageMemoryBarrier toPresentBarrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - NULL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_MEMORY_READ_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - vk->graphicsIndex, - vk->graphicsIndex, - vk->swapchain->images[i], - range, - }; - - vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toClearBarrier)); - - vkCmdClearColorImage(vk->swapchain->commandBuffers[i], - vk->swapchain->images[i], - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &clearValue, - COUNTED(1, &range)); - - vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - COUNTED(0, NULL), - COUNTED(0, NULL), - COUNTED(1, &toPresentBarrier)); - - vkEndCommandBuffer(vk->swapchain->commandBuffers[i]); - } - - return VK_SUCCESS; + const VkClearColorValue clearValue = {{ + 0xA4 / (float)0x100, // R + 0x1E / (float)0x100, // G + 0x22 / (float)0x100, // B + 0xFF / (float)0x100, // A + }}; + + const VkImageSubresourceRange range = { + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + 1, + 0, + 1, + }; + + const VkCommandBufferBeginInfo beginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + NULL, + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, + NULL, + }; + + for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { + const VkImageMemoryBarrier toClearBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + VK_ACCESS_MEMORY_READ_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + vk->graphicsIndex, + vk->graphicsIndex, + vk->swapchain->images[i], + range, + }; + + const VkImageMemoryBarrier toPresentBarrier = { + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + NULL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_MEMORY_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + vk->graphicsIndex, + vk->graphicsIndex, + vk->swapchain->images[i], + range, + }; + + vkBeginCommandBuffer(vk->swapchain->commandBuffers[i], &beginInfo); + + vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + COUNTED(0, NULL), + COUNTED(0, NULL), + COUNTED(1, &toClearBarrier)); + + vkCmdClearColorImage(vk->swapchain->commandBuffers[i], + vk->swapchain->images[i], + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clearValue, + COUNTED(1, &range)); + + vkCmdPipelineBarrier(vk->swapchain->commandBuffers[i], + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + COUNTED(0, NULL), + COUNTED(0, NULL), + COUNTED(1, &toPresentBarrier)); + + vkEndCommandBuffer(vk->swapchain->commandBuffers[i]); + } + + return VK_SUCCESS; } static VkResult @@ -733,204 +721,200 @@ createSwapchain(VulkanState* const vk, const uint32_t width, const uint32_t height) { - VkResult vr = VK_SUCCESS; - - vk->swapchain = AALLOC(1, Swapchain); - if ((vr = createRawSwapchain(vk, width, height))) { - return vr; - } - - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - NULL))) { - logError("Failed to query swapchain images: %d\n", vr); - return vr; - } - - vk->swapchain->images = AALLOC(vk->swapchain->nImages, VkImage); - if ((vr = vkGetSwapchainImagesKHR(vk->device, - vk->swapchain->rawSwapchain, - &vk->swapchain->nImages, - vk->swapchain->images))) { - logError("Failed to get swapchain images: %d\n", vr); - return vr; - } - - const VkCommandBufferAllocateInfo allocInfo = { - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - NULL, - vk->commandPool, - VK_COMMAND_BUFFER_LEVEL_PRIMARY, - vk->swapchain->nImages, - }; - - vk->swapchain->commandBuffers = AALLOC(vk->swapchain->nImages, - VkCommandBuffer); - - if ((vr = vkAllocateCommandBuffers(vk->device, - &allocInfo, - vk->swapchain->commandBuffers))) { - logError("Could not allocate command buffers: %d\n", vr); - return vr; - } - - const VkFenceCreateInfo fenceInfo = { - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - NULL, - VK_FENCE_CREATE_SIGNALED_BIT, - }; - vk->swapchain->fences = AALLOC(vk->swapchain->nImages, VkFence); - - for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { - if ((vr = vkCreateFence(vk->device, - &fenceInfo, - ALLOC_VK, - &vk->swapchain->fences[i]))) { - logError("Could not create render finished fence: %d\n", vr); - return vr; - } - } - - if ((vr = recordCommandBuffers(vk))) { - logError("Failed to record command buffers\n"); - return vr; - } - - return VK_SUCCESS; + VkResult vr = VK_SUCCESS; + + vk->swapchain = AALLOC(1, Swapchain); + if ((vr = createRawSwapchain(vk, width, height))) { + return vr; + } + + if ((vr = vkGetSwapchainImagesKHR(vk->device, + vk->swapchain->rawSwapchain, + &vk->swapchain->nImages, + NULL))) { + logError("Failed to query swapchain images: %d\n", vr); + return vr; + } + + vk->swapchain->images = AALLOC(vk->swapchain->nImages, VkImage); + if ((vr = vkGetSwapchainImagesKHR(vk->device, + vk->swapchain->rawSwapchain, + &vk->swapchain->nImages, + vk->swapchain->images))) { + logError("Failed to get swapchain images: %d\n", vr); + return vr; + } + + const VkCommandBufferAllocateInfo allocInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + NULL, + vk->commandPool, + VK_COMMAND_BUFFER_LEVEL_PRIMARY, + vk->swapchain->nImages, + }; + + vk->swapchain->commandBuffers = + AALLOC(vk->swapchain->nImages, VkCommandBuffer); + + if ((vr = vkAllocateCommandBuffers( + vk->device, &allocInfo, vk->swapchain->commandBuffers))) { + logError("Could not allocate command buffers: %d\n", vr); + return vr; + } + + const VkFenceCreateInfo fenceInfo = { + VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + NULL, + VK_FENCE_CREATE_SIGNALED_BIT, + }; + vk->swapchain->fences = AALLOC(vk->swapchain->nImages, VkFence); + + for (uint32_t i = 0; i < vk->swapchain->nImages; ++i) { + if ((vr = vkCreateFence( + vk->device, &fenceInfo, ALLOC_VK, &vk->swapchain->fences[i]))) { + logError("Could not create render finished fence: %d\n", vr); + return vr; + } + } + + if ((vr = recordCommandBuffers(vk))) { + logError("Failed to record command buffers\n"); + return vr; + } + + return VK_SUCCESS; } static void destroySwapchain(VulkanState* const vk, Swapchain* const swapchain) { - if (!swapchain) { - return; - } - - for (uint32_t i = 0; i < swapchain->nImages; ++i) { - if (swapchain->fences[i]) { - vkDestroyFence(vk->device, swapchain->fences[i], ALLOC_VK); - } - - if (swapchain->imageViews && swapchain->imageViews[i]) { - vkDestroyImageView(vk->device, swapchain->imageViews[i], ALLOC_VK); - } - } - - free(swapchain->fences); - swapchain->fences = NULL; - free(swapchain->imageViews); - swapchain->imageViews = NULL; - - if (swapchain->images) { - free(swapchain->images); - swapchain->images = NULL; - } - - if (swapchain->commandBuffers) { - vkFreeCommandBuffers(vk->device, - vk->commandPool, - swapchain->nImages, - swapchain->commandBuffers); - free(swapchain->commandBuffers); - } - - if (swapchain->rawSwapchain) { - vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK); - } - - free(swapchain); + if (!swapchain) { + return; + } + + for (uint32_t i = 0; i < swapchain->nImages; ++i) { + if (swapchain->fences[i]) { + vkDestroyFence(vk->device, swapchain->fences[i], ALLOC_VK); + } + + if (swapchain->imageViews && swapchain->imageViews[i]) { + vkDestroyImageView(vk->device, swapchain->imageViews[i], ALLOC_VK); + } + } + + free(swapchain->fences); + swapchain->fences = NULL; + free(swapchain->imageViews); + swapchain->imageViews = NULL; + + if (swapchain->images) { + free(swapchain->images); + swapchain->images = NULL; + } + + if (swapchain->commandBuffers) { + vkFreeCommandBuffers(vk->device, + vk->commandPool, + swapchain->nImages, + swapchain->commandBuffers); + free(swapchain->commandBuffers); + } + + if (swapchain->rawSwapchain) { + vkDestroySwapchainKHR(vk->device, swapchain->rawSwapchain, ALLOC_VK); + } + + free(swapchain); } static VkResult createSyncObjects(VulkanState* const vk) { - const VkSemaphoreCreateInfo info = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0, - }; - - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.presentComplete); - vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.renderFinished); - return VK_SUCCESS; + const VkSemaphoreCreateInfo info = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + NULL, + 0, + }; + + vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.presentComplete); + vkCreateSemaphore(vk->device, &info, ALLOC_VK, &vk->sync.renderFinished); + return VK_SUCCESS; } static void destroySyncObjects(VulkanState* const vk) { - if (vk->sync.renderFinished) { - vkDestroySemaphore(vk->device, vk->sync.renderFinished, ALLOC_VK); - vk->sync.renderFinished = VK_NULL_HANDLE; - } - if (vk->sync.presentComplete) { - vkDestroySemaphore(vk->device, vk->sync.presentComplete, ALLOC_VK); - vk->sync.presentComplete = VK_NULL_HANDLE; - } + if (vk->sync.renderFinished) { + vkDestroySemaphore(vk->device, vk->sync.renderFinished, ALLOC_VK); + vk->sync.renderFinished = VK_NULL_HANDLE; + } + if (vk->sync.presentComplete) { + vkDestroySemaphore(vk->device, vk->sync.presentComplete, ALLOC_VK); + vk->sync.presentComplete = VK_NULL_HANDLE; + } } static void closeDevice(VulkanState* const vk) { - if (vk->device) { - vkDeviceWaitIdle(vk->device); - destroySyncObjects(vk); - destroySwapchain(vk, vk->swapchain); - if (vk->commandPool) { - vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); - vk->commandPool = VK_NULL_HANDLE; - } - vk->graphicsQueue = VK_NULL_HANDLE; - vkDestroyDevice(vk->device, ALLOC_VK); - vk->device = VK_NULL_HANDLE; - } + if (vk->device) { + vkDeviceWaitIdle(vk->device); + destroySyncObjects(vk); + destroySwapchain(vk, vk->swapchain); + if (vk->commandPool) { + vkDestroyCommandPool(vk->device, vk->commandPool, ALLOC_VK); + vk->commandPool = VK_NULL_HANDLE; + } + vk->graphicsQueue = VK_NULL_HANDLE; + vkDestroyDevice(vk->device, ALLOC_VK); + vk->device = VK_NULL_HANDLE; + } } static void destroyWorld(VulkanApp* const app) { - VulkanState* vk = &app->vk; - - if (vk) { - closeDevice(vk); - - if (app->view) { - puglHide(app->view); - puglFreeView(app->view); - app->view = NULL; - } - if (vk->debugCallback && vk->api.vkDestroyDebugReportCallbackEXT) { - vk->api.vkDestroyDebugReportCallbackEXT(vk->instance, - vk->debugCallback, - ALLOC_VK); - vk->debugCallback = VK_NULL_HANDLE; - } - if (vk->surface) { - vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); - vk->surface = VK_NULL_HANDLE; - } - if (vk->instance) { - fflush(stderr); - vkDestroyInstance(vk->instance, ALLOC_VK); - vk->instance = VK_NULL_HANDLE; - } - if (app->world) { - puglFreeWorld(app->world); - app->world = NULL; - } - } + VulkanState* vk = &app->vk; + + if (vk) { + closeDevice(vk); + + if (app->view) { + puglHide(app->view); + puglFreeView(app->view); + app->view = NULL; + } + if (vk->debugCallback && vk->api.vkDestroyDebugReportCallbackEXT) { + vk->api.vkDestroyDebugReportCallbackEXT( + vk->instance, vk->debugCallback, ALLOC_VK); + vk->debugCallback = VK_NULL_HANDLE; + } + if (vk->surface) { + vkDestroySurfaceKHR(vk->instance, vk->surface, ALLOC_VK); + vk->surface = VK_NULL_HANDLE; + } + if (vk->instance) { + fflush(stderr); + vkDestroyInstance(vk->instance, ALLOC_VK); + vk->instance = VK_NULL_HANDLE; + } + if (app->world) { + puglFreeWorld(app->world); + app->world = NULL; + } + } } static PuglStatus onConfigure(PuglView* const view, const double width, const double height) { - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); + VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - // We just record the size here and lazily resize the surface when exposed - app->width = (uint32_t)width; - app->height = (uint32_t)height; + // We just record the size here and lazily resize the surface when exposed + app->width = (uint32_t)width; + app->height = (uint32_t)height; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus @@ -938,202 +922,202 @@ recreateSwapchain(VulkanState* const vk, const uint32_t width, const uint32_t height) { - vkDeviceWaitIdle(vk->device); - destroySwapchain(vk, vk->swapchain); + vkDeviceWaitIdle(vk->device); + destroySwapchain(vk, vk->swapchain); - if (createSwapchain(vk, width, height)) { - logError("Failed to recreate swapchain\n"); - return PUGL_UNKNOWN_ERROR; - } + if (createSwapchain(vk, width, height)) { + logError("Failed to recreate swapchain\n"); + return PUGL_UNKNOWN_ERROR; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus onExpose(PuglView* const view) { - VulkanApp* app = (VulkanApp*)puglGetHandle(view); - VulkanState* vk = &app->vk; - uint32_t imageIndex = 0; - VkResult result = VK_SUCCESS; - - // Recreate swapchain if the window size has changed - const Swapchain* swapchain = vk->swapchain; - if (swapchain->extent.width != app->width || - swapchain->extent.height != app->height) { - recreateSwapchain(vk, app->width, app->height); - } - - // Acquire the next image to render, rebuilding if necessary - while ((result = vkAcquireNextImageKHR(vk->device, - vk->swapchain->rawSwapchain, - UINT64_MAX, - vk->sync.presentComplete, - VK_NULL_HANDLE, - &imageIndex))) { - switch (result) { - case VK_SUCCESS: - break; - case VK_SUBOPTIMAL_KHR: - case VK_ERROR_OUT_OF_DATE_KHR: - recreateSwapchain(vk, app->width, app->height); - continue; - default: - logError("Could not acquire swapchain image: %d\n", result); - return PUGL_UNKNOWN_ERROR; - } - } - - // Wait until we can start rendering this frame - vkWaitForFences(vk->device, - COUNTED(1, &vk->swapchain->fences[imageIndex]), - VK_TRUE, - UINT64_MAX); - vkResetFences(vk->device, 1, &vk->swapchain->fences[imageIndex]); - - const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; - - // Submit command buffer to render this frame - const VkSubmitInfo submitInfo = { - VK_STRUCTURE_TYPE_SUBMIT_INFO, - NULL, - COUNTED(1, &vk->sync.presentComplete), - &waitStage, - COUNTED(1, &vk->swapchain->commandBuffers[imageIndex]), - COUNTED(1, &vk->sync.renderFinished)}; - if ((result = vkQueueSubmit(vk->graphicsQueue, - 1, - &submitInfo, - vk->swapchain->fences[imageIndex]))) { - logError("Could not submit to queue: %d\n", result); - return PUGL_FAILURE; - } - - // Present this frame - const VkPresentInfoKHR presentInfo = { - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - NULL, - COUNTED(1, &vk->sync.renderFinished), - COUNTED(1, &vk->swapchain->rawSwapchain, &imageIndex, NULL), - }; - if ((result = vkQueuePresentKHR(vk->graphicsQueue, &presentInfo))) { - logError("Could not present image: %d\n", result); - } - - if (app->opts.continuous) { - ++app->framesDrawn; - } - - return PUGL_SUCCESS; + VulkanApp* app = (VulkanApp*)puglGetHandle(view); + VulkanState* vk = &app->vk; + uint32_t imageIndex = 0; + VkResult result = VK_SUCCESS; + + // Recreate swapchain if the window size has changed + const Swapchain* swapchain = vk->swapchain; + if (swapchain->extent.width != app->width || + swapchain->extent.height != app->height) { + recreateSwapchain(vk, app->width, app->height); + } + + // Acquire the next image to render, rebuilding if necessary + while ((result = vkAcquireNextImageKHR(vk->device, + vk->swapchain->rawSwapchain, + UINT64_MAX, + vk->sync.presentComplete, + VK_NULL_HANDLE, + &imageIndex))) { + switch (result) { + case VK_SUCCESS: + break; + case VK_SUBOPTIMAL_KHR: + case VK_ERROR_OUT_OF_DATE_KHR: + recreateSwapchain(vk, app->width, app->height); + continue; + default: + logError("Could not acquire swapchain image: %d\n", result); + return PUGL_UNKNOWN_ERROR; + } + } + + // Wait until we can start rendering this frame + vkWaitForFences(vk->device, + COUNTED(1, &vk->swapchain->fences[imageIndex]), + VK_TRUE, + UINT64_MAX); + vkResetFences(vk->device, 1, &vk->swapchain->fences[imageIndex]); + + const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_TRANSFER_BIT; + + // Submit command buffer to render this frame + const VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + NULL, + COUNTED(1, &vk->sync.presentComplete), + &waitStage, + COUNTED(1, &vk->swapchain->commandBuffers[imageIndex]), + COUNTED(1, &vk->sync.renderFinished)}; + if ((result = vkQueueSubmit(vk->graphicsQueue, + 1, + &submitInfo, + vk->swapchain->fences[imageIndex]))) { + logError("Could not submit to queue: %d\n", result); + return PUGL_FAILURE; + } + + // Present this frame + const VkPresentInfoKHR presentInfo = { + VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + NULL, + COUNTED(1, &vk->sync.renderFinished), + COUNTED(1, &vk->swapchain->rawSwapchain, &imageIndex, NULL), + }; + if ((result = vkQueuePresentKHR(vk->graphicsQueue, &presentInfo))) { + logError("Could not present image: %d\n", result); + } + + if (app->opts.continuous) { + ++app->framesDrawn; + } + + return PUGL_SUCCESS; } static PuglStatus onEvent(PuglView* const view, const PuglEvent* const e) { - VulkanApp* const app = (VulkanApp*)puglGetHandle(view); - - printEvent(e, "Event: ", app->opts.verbose); - - switch (e->type) { - case PUGL_EXPOSE: - return onExpose(view); - case PUGL_CONFIGURE: - return onConfigure(view, e->configure.width, e->configure.height); - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - switch (e->key.key) { - case PUGL_KEY_ESCAPE: - case 'q': - app->quit = 1; - break; - } - break; - default: - break; - } - return PUGL_SUCCESS; + VulkanApp* const app = (VulkanApp*)puglGetHandle(view); + + printEvent(e, "Event: ", app->opts.verbose); + + switch (e->type) { + case PUGL_EXPOSE: + return onExpose(view); + case PUGL_CONFIGURE: + return onConfigure(view, e->configure.width, e->configure.height); + case PUGL_CLOSE: + app->quit = 1; + break; + case PUGL_KEY_PRESS: + switch (e->key.key) { + case PUGL_KEY_ESCAPE: + case 'q': + app->quit = 1; + break; + } + break; + default: + break; + } + return PUGL_SUCCESS; } int main(int argc, char** argv) { - VulkanApp app = {0}; - VulkanState* vk = &app.vk; - const uint32_t defaultWidth = 640; - const uint32_t defaultHeight = 360; - const PuglRect frame = {0, 0, defaultWidth, defaultHeight}; - - // Parse command line options - app.opts = puglParseTestOptions(&argc, &argv); - if (app.opts.help) { - puglPrintTestUsage(argv[0], ""); - return 0; - } - - // Create world and view - if (!(app.world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS))) { - return logError("Failed to create world\n"); - } else if (!(app.view = puglNewView(app.world))) { - puglFreeWorld(app.world); - return logError("Failed to create Pugl World and View\n"); - } - - // Create Vulkan instance - if (createInstance(&app)) { - puglFreeWorld(app.world); - return logError("Failed to create instance\n"); - } - - // Create window - puglSetWindowTitle(app.view, "Pugl Vulkan"); - puglSetFrame(app.view, frame); - puglSetHandle(app.view, &app); - puglSetBackend(app.view, puglVulkanBackend()); - puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable); - puglSetEventFunc(app.view, onEvent); - const PuglStatus st = puglRealize(app.view); - if (st) { - puglFreeWorld(app.world); - puglFreeView(app.view); - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - // Create Vulkan surface for Window - PuglVulkanLoader* loader = puglNewVulkanLoader(app.world); - if (puglCreateSurface(puglGetInstanceProcAddrFunc(loader), - app.view, - vk->instance, - ALLOC_VK, - &vk->surface)) { - return logError("Failed to create surface\n"); - } - - // Set up Vulkan - VkResult vr = VK_SUCCESS; - if ((vr = enableDebugging(vk)) || // - (vr = selectPhysicalDevice(vk)) || // - (vr = openDevice(vk)) || // - (vr = configureSurface(vk)) || // - (vr = createSwapchain(vk, defaultWidth, defaultHeight)) || // - (vr = createSyncObjects(vk))) { - destroyWorld(&app); - return logError("Failed to set up graphics (%d)\n", vr); - } - - printf("Swapchain images: %u\n", app.vk.swapchain->nImages); - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - puglShow(app.view); - while (!app.quit) { - puglUpdate(app.world, -1.0); - - if (app.opts.continuous) { - puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); - } - } - - destroyWorld(&app); - return 0; + VulkanApp app = {0}; + VulkanState* vk = &app.vk; + const uint32_t defaultWidth = 640; + const uint32_t defaultHeight = 360; + const PuglRect frame = {0, 0, defaultWidth, defaultHeight}; + + // Parse command line options + app.opts = puglParseTestOptions(&argc, &argv); + if (app.opts.help) { + puglPrintTestUsage(argv[0], ""); + return 0; + } + + // Create world and view + if (!(app.world = puglNewWorld(PUGL_PROGRAM, PUGL_WORLD_THREADS))) { + return logError("Failed to create world\n"); + } else if (!(app.view = puglNewView(app.world))) { + puglFreeWorld(app.world); + return logError("Failed to create Pugl World and View\n"); + } + + // Create Vulkan instance + if (createInstance(&app)) { + puglFreeWorld(app.world); + return logError("Failed to create instance\n"); + } + + // Create window + puglSetWindowTitle(app.view, "Pugl Vulkan"); + puglSetFrame(app.view, frame); + puglSetHandle(app.view, &app); + puglSetBackend(app.view, puglVulkanBackend()); + puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable); + puglSetEventFunc(app.view, onEvent); + const PuglStatus st = puglRealize(app.view); + if (st) { + puglFreeWorld(app.world); + puglFreeView(app.view); + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } + + // Create Vulkan surface for Window + PuglVulkanLoader* loader = puglNewVulkanLoader(app.world); + if (puglCreateSurface(puglGetInstanceProcAddrFunc(loader), + app.view, + vk->instance, + ALLOC_VK, + &vk->surface)) { + return logError("Failed to create surface\n"); + } + + // Set up Vulkan + VkResult vr = VK_SUCCESS; + if ((vr = enableDebugging(vk)) || // + (vr = selectPhysicalDevice(vk)) || // + (vr = openDevice(vk)) || // + (vr = configureSurface(vk)) || // + (vr = createSwapchain(vk, defaultWidth, defaultHeight)) || // + (vr = createSyncObjects(vk))) { + destroyWorld(&app); + return logError("Failed to set up graphics (%d)\n", vr); + } + + printf("Swapchain images: %u\n", app.vk.swapchain->nImages); + + PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; + puglShow(app.view); + while (!app.quit) { + puglUpdate(app.world, -1.0); + + if (app.opts.continuous) { + puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); + } + } + + destroyWorld(&app); + return 0; } diff --git a/examples/pugl_window_demo.c b/examples/pugl_window_demo.c index 3dfc39a..be320dd 100644 --- a/examples/pugl_window_demo.c +++ b/examples/pugl_window_demo.c @@ -30,22 +30,22 @@ #include <string.h> typedef struct { - PuglView* view; - double xAngle; - double yAngle; - double lastMouseX; - double lastMouseY; - double lastDrawTime; - float dist; - bool entered; + PuglView* view; + double xAngle; + double yAngle; + double lastMouseX; + double lastMouseY; + double lastDrawTime; + float dist; + bool entered; } CubeView; typedef struct { - PuglWorld* world; - CubeView cubes[2]; - int quit; - bool continuous; - bool verbose; + PuglWorld* world; + CubeView cubes[2]; + int quit; + bool continuous; + bool verbose; } PuglTestApp; static const double pad = 64.0; @@ -53,207 +53,201 @@ static const double pad = 64.0; static void onDisplay(PuglView* view) { - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); + PuglWorld* world = puglGetWorld(view); + PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); + CubeView* cube = (CubeView*)puglGetHandle(view); - const double thisTime = puglGetTime(app->world); - if (app->continuous) { - const double dTime = thisTime - cube->lastDrawTime; + const double thisTime = puglGetTime(app->world); + if (app->continuous) { + const double dTime = thisTime - cube->lastDrawTime; - cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0); - cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0); - } + cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0); + cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0); + } - displayCube(view, - cube->dist, - (float)cube->xAngle, - (float)cube->yAngle, - cube->entered); + displayCube( + view, cube->dist, (float)cube->xAngle, (float)cube->yAngle, cube->entered); - cube->lastDrawTime = thisTime; + cube->lastDrawTime = thisTime; } static void onKeyPress(PuglView* view, const PuglEventKey* event) { - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - PuglRect frame = puglGetFrame(view); - - if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { - app->quit = 1; - } else if (event->state & PUGL_MOD_SHIFT) { - if (event->key == PUGL_KEY_UP) { - frame.height += 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.height -= 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.width -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.width += 10; - } else { - return; - } - puglSetFrame(view, frame); - } else { - if (event->key == PUGL_KEY_UP) { - frame.y -= 10; - } else if (event->key == PUGL_KEY_DOWN) { - frame.y += 10; - } else if (event->key == PUGL_KEY_LEFT) { - frame.x -= 10; - } else if (event->key == PUGL_KEY_RIGHT) { - frame.x += 10; - } else { - return; - } - puglSetFrame(view, frame); - } + PuglWorld* world = puglGetWorld(view); + PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); + PuglRect frame = puglGetFrame(view); + + if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } else if (event->state & PUGL_MOD_SHIFT) { + if (event->key == PUGL_KEY_UP) { + frame.height += 10; + } else if (event->key == PUGL_KEY_DOWN) { + frame.height -= 10; + } else if (event->key == PUGL_KEY_LEFT) { + frame.width -= 10; + } else if (event->key == PUGL_KEY_RIGHT) { + frame.width += 10; + } else { + return; + } + puglSetFrame(view, frame); + } else { + if (event->key == PUGL_KEY_UP) { + frame.y -= 10; + } else if (event->key == PUGL_KEY_DOWN) { + frame.y += 10; + } else if (event->key == PUGL_KEY_LEFT) { + frame.x -= 10; + } else if (event->key == PUGL_KEY_RIGHT) { + frame.x += 10; + } else { + return; + } + puglSetFrame(view, frame); + } } static void redisplayView(PuglTestApp* app, PuglView* view) { - if (!app->continuous) { - puglPostRedisplay(view); - } + if (!app->continuous) { + puglPostRedisplay(view); + } } static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglWorld* world = puglGetWorld(view); - PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); - CubeView* cube = (CubeView*)puglGetHandle(view); - - const char* const prefix = cube == &app->cubes[0] ? "View 1: " : "View 2: "; - printEvent(event, prefix, app->verbose); - - switch (event->type) { - case PUGL_CONFIGURE: - reshapeCube((float)event->configure.width, - (float)event->configure.height); - break; - case PUGL_UPDATE: - if (app->continuous) { - puglPostRedisplay(view); - } - break; - case PUGL_EXPOSE: - onDisplay(view); - break; - case PUGL_CLOSE: - app->quit = 1; - break; - case PUGL_KEY_PRESS: - onKeyPress(view, &event->key); - break; - case PUGL_MOTION: - cube->xAngle -= event->motion.x - cube->lastMouseX; - cube->yAngle += event->motion.y - cube->lastMouseY; - cube->lastMouseX = event->motion.x; - cube->lastMouseY = event->motion.y; - redisplayView(app, view); - break; - case PUGL_SCROLL: - cube->dist = fmaxf(10.0f, cube->dist + (float)event->scroll.dy); - redisplayView(app, view); - break; - case PUGL_POINTER_IN: - cube->entered = true; - redisplayView(app, view); - break; - case PUGL_POINTER_OUT: - cube->entered = false; - redisplayView(app, view); - break; - case PUGL_FOCUS_IN: - case PUGL_FOCUS_OUT: - redisplayView(app, view); - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglWorld* world = puglGetWorld(view); + PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); + CubeView* cube = (CubeView*)puglGetHandle(view); + + const char* const prefix = cube == &app->cubes[0] ? "View 1: " : "View 2: "; + printEvent(event, prefix, app->verbose); + + switch (event->type) { + case PUGL_CONFIGURE: + reshapeCube((float)event->configure.width, (float)event->configure.height); + break; + case PUGL_UPDATE: + if (app->continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_EXPOSE: + onDisplay(view); + break; + case PUGL_CLOSE: + app->quit = 1; + break; + case PUGL_KEY_PRESS: + onKeyPress(view, &event->key); + break; + case PUGL_MOTION: + cube->xAngle -= event->motion.x - cube->lastMouseX; + cube->yAngle += event->motion.y - cube->lastMouseY; + cube->lastMouseX = event->motion.x; + cube->lastMouseY = event->motion.y; + redisplayView(app, view); + break; + case PUGL_SCROLL: + cube->dist = fmaxf(10.0f, cube->dist + (float)event->scroll.dy); + redisplayView(app, view); + break; + case PUGL_POINTER_IN: + cube->entered = true; + redisplayView(app, view); + break; + case PUGL_POINTER_OUT: + cube->entered = false; + redisplayView(app, view); + break; + case PUGL_FOCUS_IN: + case PUGL_FOCUS_OUT: + redisplayView(app, view); + break; + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTestApp app = {0}; - - const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); - if (opts.help) { - puglPrintTestUsage(argv[0], ""); - return 1; - } - - app.continuous = opts.continuous; - app.verbose = opts.verbose; - - app.world = puglNewWorld(PUGL_PROGRAM, 0); - app.cubes[0].view = puglNewView(app.world); - app.cubes[1].view = puglNewView(app.world); - - puglSetWorldHandle(app.world, &app); - puglSetClassName(app.world, "Pugl Test"); - - PuglStatus st = PUGL_SUCCESS; - for (unsigned i = 0; i < 2; ++i) { - CubeView* cube = &app.cubes[i]; - PuglView* view = cube->view; - const PuglRect frame = {pad + (128.0 + pad) * i, - pad + (128.0 + pad) * i, - 512.0, - 512.0}; - - cube->dist = 10; - - puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetFrame(view, frame); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 128, 128); - puglSetBackend(view, puglGlBackend()); - - puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); - puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); - puglSetViewHint(view, PUGL_SAMPLES, opts.samples); - puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); - puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync); - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); - puglSetHandle(view, cube); - puglSetEventFunc(view, onEvent); - - if (i == 1) { - puglSetTransientFor(app.cubes[1].view, - puglGetNativeWindow(app.cubes[0].view)); - } - - if ((st = puglRealize(view))) { - return logError("Failed to create window (%s)\n", puglStrerror(st)); - } - - puglShow(view); - } - - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; - unsigned framesDrawn = 0; - while (!app.quit) { - puglUpdate(app.world, app.continuous ? 0.0 : -1.0); - ++framesDrawn; - - if (app.continuous) { - puglPrintFps(app.world, &fpsPrinter, &framesDrawn); - } - } - - for (size_t i = 0; i < 2; ++i) { - puglFreeView(app.cubes[i].view); - } - - puglFreeWorld(app.world); - - return 0; + PuglTestApp app = {0}; + + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage(argv[0], ""); + return 1; + } + + app.continuous = opts.continuous; + app.verbose = opts.verbose; + + app.world = puglNewWorld(PUGL_PROGRAM, 0); + app.cubes[0].view = puglNewView(app.world); + app.cubes[1].view = puglNewView(app.world); + + puglSetWorldHandle(app.world, &app); + puglSetClassName(app.world, "Pugl Test"); + + PuglStatus st = PUGL_SUCCESS; + for (unsigned i = 0; i < 2; ++i) { + CubeView* cube = &app.cubes[i]; + PuglView* view = cube->view; + const PuglRect frame = { + pad + (128.0 + pad) * i, pad + (128.0 + pad) * i, 512.0, 512.0}; + + cube->dist = 10; + + puglSetWindowTitle(view, "Pugl Window Demo"); + puglSetFrame(view, frame); + puglSetDefaultSize(view, 512, 512); + puglSetMinSize(view, 128, 128); + puglSetBackend(view, puglGlBackend()); + + puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); + puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); + puglSetViewHint(view, PUGL_SAMPLES, opts.samples); + puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); + puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync); + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); + puglSetHandle(view, cube); + puglSetEventFunc(view, onEvent); + + if (i == 1) { + puglSetTransientFor(app.cubes[1].view, + puglGetNativeWindow(app.cubes[0].view)); + } + + if ((st = puglRealize(view))) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } + + puglShow(view); + } + + PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; + unsigned framesDrawn = 0; + while (!app.quit) { + puglUpdate(app.world, app.continuous ? 0.0 : -1.0); + ++framesDrawn; + + if (app.continuous) { + puglPrintFps(app.world, &fpsPrinter, &framesDrawn); + } + } + + for (size_t i = 0; i < 2; ++i) { + puglFreeView(app.cubes[i].view); + } + + puglFreeWorld(app.world); + + return 0; } diff --git a/examples/rects.h b/examples/rects.h index 3537a5b..b99d9f0 100644 --- a/examples/rects.h +++ b/examples/rects.h @@ -23,16 +23,16 @@ typedef float vec2[2]; typedef struct { - float pos[2]; - float size[2]; - float fillColor[4]; + float pos[2]; + float size[2]; + float fillColor[4]; } Rect; static const vec2 rectVertices[] = { - {0.0f, 0.0f}, // TL - {1.0f, 0.0f}, // TR - {0.0f, 1.0f}, // BL - {1.0f, 1.0f} // BR + {0.0f, 0.0f}, // TL + {1.0f, 0.0f}, // TR + {0.0f, 1.0f}, // BL + {1.0f, 1.0f} // BR }; static const unsigned rectIndices[4] = {0, 1, 2, 3}; @@ -41,19 +41,19 @@ static const unsigned rectIndices[4] = {0, 1, 2, 3}; static inline Rect makeRect(const size_t index, const float frameWidth) { - static const float alpha = 0.3f; - const float minSize = frameWidth / 64.0f; - const float maxSize = frameWidth / 6.0f; - const float s = (sinf((float)index) / 2.0f + 0.5f); - const float c = (cosf((float)index) / 2.0f + 0.5f); + static const float alpha = 0.3f; + const float minSize = frameWidth / 64.0f; + const float maxSize = frameWidth / 6.0f; + const float s = (sinf((float)index) / 2.0f + 0.5f); + const float c = (cosf((float)index) / 2.0f + 0.5f); - const Rect rect = { - {0.0f, 0.0f}, // Position is set later during expose - {minSize + s * maxSize, minSize + c * maxSize}, - {0.0f, s / 2.0f + 0.25f, c / 2.0f + 0.25f, alpha}, - }; + const Rect rect = { + {0.0f, 0.0f}, // Position is set later during expose + {minSize + s * maxSize, minSize + c * maxSize}, + {0.0f, s / 2.0f + 0.25f, c / 2.0f + 0.25f, alpha}, + }; - return rect; + return rect; } /// Move `rect` with the given index around in an arbitrary way that looks cool @@ -65,15 +65,15 @@ moveRect(Rect* const rect, const float frameHeight, const double time) { - const float normal = (float)index / (float)numRects; - const float offset[2] = {normal * 128.0f, normal * 128.0f}; + const float normal = (float)index / (float)numRects; + const float offset[2] = {normal * 128.0f, normal * 128.0f}; - rect->pos[0] = (frameWidth - rect->size[0] + offset[0]) * - (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) / - 2.0f; - rect->pos[1] = (frameHeight - rect->size[1] + offset[1]) * - (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) / - 2.0f; + rect->pos[0] = (frameWidth - rect->size[0] + offset[0]) * + (sinf((float)time * rect->size[0] / 64.0f + normal) + 1.0f) / + 2.0f; + rect->pos[1] = (frameHeight - rect->size[1] + offset[1]) * + (cosf((float)time * rect->size[1] / 64.0f + normal) + 1.0f) / + 2.0f; } #endif // EXAMPLES_RECTS_H diff --git a/examples/shader_utils.h b/examples/shader_utils.h index 217ba47..2575f47 100644 --- a/examples/shader_utils.h +++ b/examples/shader_utils.h @@ -23,45 +23,44 @@ #include <stdlib.h> #include <string.h> -typedef struct -{ - GLuint vertexShader; - GLuint fragmentShader; - GLuint program; +typedef struct { + GLuint vertexShader; + GLuint fragmentShader; + GLuint program; } Program; static GLuint compileShader(const char* header, const char* source, const GLenum type) { - const GLchar* sources[] = {header, source}; - const GLint lengths[] = {(GLint)strlen(header), (GLint)strlen(source)}; - GLuint shader = glCreateShader(type); - glShaderSource(shader, 2, sources, lengths); - glCompileShader(shader); - - int status = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetShaderInfoLog(shader, length, &length, log); - fprintf(stderr, "error: Failed to compile shader (%s)\n", log); - free(log); - - return 0; - } - - return shader; + const GLchar* sources[] = {header, source}; + const GLint lengths[] = {(GLint)strlen(header), (GLint)strlen(source)}; + GLuint shader = glCreateShader(type); + glShaderSource(shader, 2, sources, lengths); + glCompileShader(shader); + + int status = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLint length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + char* log = (char*)calloc(1, (size_t)length); + glGetShaderInfoLog(shader, length, &length, log); + fprintf(stderr, "error: Failed to compile shader (%s)\n", log); + free(log); + + return 0; + } + + return shader; } static void deleteProgram(Program program) { - glDeleteShader(program.vertexShader); - glDeleteShader(program.fragmentShader); - glDeleteProgram(program.program); + glDeleteShader(program.vertexShader); + glDeleteShader(program.fragmentShader); + glDeleteProgram(program.program); } static Program @@ -69,39 +68,39 @@ compileProgram(const char* headerSource, const char* vertexSource, const char* fragmentSource) { - static const Program nullProgram = {0, 0, 0}; - - Program program = { - compileShader(headerSource, vertexSource, GL_VERTEX_SHADER), - compileShader(headerSource, fragmentSource, GL_FRAGMENT_SHADER), - glCreateProgram(), - }; - - if (!program.vertexShader || !program.fragmentShader || !program.program) { - deleteProgram(program); - return nullProgram; - } - - glAttachShader(program.program, program.vertexShader); - glAttachShader(program.program, program.fragmentShader); - glLinkProgram(program.program); - - GLint status = 0; - glGetProgramiv(program.program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLint length = 0; - glGetProgramiv(program.program, GL_INFO_LOG_LENGTH, &length); - - char* log = (char*)calloc(1, (size_t)length); - glGetProgramInfoLog(program.program, length, &length, &log[0]); - fprintf(stderr, "error: Failed to link program (%s)\n", log); - free(log); - - deleteProgram(program); - return nullProgram; - } - - return program; + static const Program nullProgram = {0, 0, 0}; + + Program program = { + compileShader(headerSource, vertexSource, GL_VERTEX_SHADER), + compileShader(headerSource, fragmentSource, GL_FRAGMENT_SHADER), + glCreateProgram(), + }; + + if (!program.vertexShader || !program.fragmentShader || !program.program) { + deleteProgram(program); + return nullProgram; + } + + glAttachShader(program.program, program.vertexShader); + glAttachShader(program.program, program.fragmentShader); + glLinkProgram(program.program); + + GLint status = 0; + glGetProgramiv(program.program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLint length = 0; + glGetProgramiv(program.program, GL_INFO_LOG_LENGTH, &length); + + char* log = (char*)calloc(1, (size_t)length); + glGetProgramInfoLog(program.program, length, &length, &log[0]); + fprintf(stderr, "error: Failed to link program (%s)\n", log); + free(log); + + deleteProgram(program); + return nullProgram; + } + + return program; } #endif // EXAMPLES_SHADER_UTILS_H diff --git a/examples/shaders/header_330.glsl b/examples/shaders/header_330.glsl index bfe7a00..59d5f6f 100644 --- a/examples/shaders/header_330.glsl +++ b/examples/shaders/header_330.glsl @@ -2,4 +2,3 @@ #define INTER(qualifiers) #define UBO(qualifiers) layout(std140) - diff --git a/examples/shaders/header_420.glsl b/examples/shaders/header_420.glsl index 55fbe8a..2beaad0 100644 --- a/examples/shaders/header_420.glsl +++ b/examples/shaders/header_420.glsl @@ -2,4 +2,3 @@ #define INTER(qualifiers) layout(qualifiers) #define UBO(qualifiers) layout(std140, qualifiers) - diff --git a/examples/shaders/rect.frag b/examples/shaders/rect.frag index ecec50d..33bfbb2 100644 --- a/examples/shaders/rect.frag +++ b/examples/shaders/rect.frag @@ -17,17 +17,17 @@ layout(location = 0) out vec4 FragColor; void main() { - const float borderWidth = 2.0; + const float borderWidth = 2.0; - vec4 borderColor = f_fillColor + vec4(0.0, 0.4, 0.4, 0.0); - float t = step(borderWidth, f_uv[1]); - float r = step(borderWidth, f_size.x - f_uv[0]); - float b = step(borderWidth, f_size.y - f_uv[1]); - float l = step(borderWidth, f_uv[0]); - float fillMix = t * r * b * l; - float borderMix = 1.0 - fillMix; - vec4 fill = fillMix * f_fillColor; - vec4 border = borderMix * borderColor; + vec4 borderColor = f_fillColor + vec4(0.0, 0.4, 0.4, 0.0); + float t = step(borderWidth, f_uv[1]); + float r = step(borderWidth, f_size.x - f_uv[0]); + float b = step(borderWidth, f_size.y - f_uv[1]); + float l = step(borderWidth, f_uv[0]); + float fillMix = t * r * b * l; + float borderMix = 1.0 - fillMix; + vec4 fill = fillMix * f_fillColor; + vec4 border = borderMix * borderColor; - FragColor = fill + border; + FragColor = fill + border; } diff --git a/examples/shaders/rect.vert b/examples/shaders/rect.vert index 09f1917..2c7b5f1 100644 --- a/examples/shaders/rect.vert +++ b/examples/shaders/rect.vert @@ -3,8 +3,9 @@ UBO(binding = 0) uniform UniformBufferObject { - mat4 projection; -} ubo; + mat4 projection; +} +ubo; layout(location = 0) in vec2 v_position; layout(location = 1) in vec2 v_origin; @@ -18,18 +19,18 @@ INTER(location = 2) noperspective out vec4 f_fillColor; void main() { - // clang-format off - mat4 m = mat4(v_size[0], 0.0, 0.0, 0.0, - 0.0, v_size[1], 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - v_origin[0], v_origin[1], 0.0, 1.0); - // clang-format on + // clang-format off + mat4 m = mat4(v_size[0], 0.0, 0.0, 0.0, + 0.0, v_size[1], 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + v_origin[0], v_origin[1], 0.0, 1.0); + // clang-format on - mat4 MVP = ubo.projection * m; + mat4 MVP = ubo.projection * m; - f_uv = v_position * v_size; - f_size = v_size; - f_fillColor = v_fillColor; + f_uv = v_position * v_size; + f_size = v_size; + f_fillColor = v_fillColor; - gl_Position = MVP * vec4(v_position, 0.0, 1.0); + gl_Position = MVP * vec4(v_position, 0.0, 1.0); } diff --git a/examples/sybok.hpp b/examples/sybok.hpp index 8985547..05b2c3d 100644 --- a/examples/sybok.hpp +++ b/examples/sybok.hpp @@ -66,13 +66,13 @@ #define VK_NO_PROTOTYPES // On 64-bit platforms, all handles are "dispatchable" pointers -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || \ + (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ + defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ + defined(__powerpc64__) -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - typedef struct object##_T* object; +# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ + typedef struct object##_T* object; // On 32-bit platforms, some "non-dispatchable" handles are 64 bit integers #else @@ -80,14 +80,14 @@ /// Trivial wrapper class for a 64-bit integer handle for type safety template<class Tag> struct NonDispatchableHandle { - explicit operator uint64_t() const noexcept { return handle; } - explicit operator bool() const noexcept { return handle; } + explicit operator uint64_t() const noexcept { return handle; } + explicit operator bool() const noexcept { return handle; } - uint64_t handle; + uint64_t handle; }; -# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ - using object = NonDispatchableHandle<struct Sk##object##Tag>; +# define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \ + using object = NonDispatchableHandle<struct Sk##object##Tag>; #endif @@ -101,11 +101,11 @@ struct NonDispatchableHandle { #include <utility> #if __cplusplus >= 201703L -# define SYBOK_NODISCARD [[nodiscard]] +# define SYBOK_NODISCARD [[nodiscard]] #elif defined(__GNUC__) -# define SYBOK_NODISCARD [[gnu::warn_unused_result]] +# define SYBOK_NODISCARD [[gnu::warn_unused_result]] #else -# define SYBOK_NODISCARD +# define SYBOK_NODISCARD #endif /// Helper macro to make array arguments format nicely @@ -119,295 +119,294 @@ class RenderCommandScope; static inline const char* string(const VkResult result) { - switch (result) { - case VK_SUCCESS: - return "Success"; - case VK_NOT_READY: - return "Not Ready"; - case VK_TIMEOUT: - return "Timeout"; - case VK_EVENT_SET: - return "Event set"; - case VK_EVENT_RESET: - return "Event reset"; - case VK_INCOMPLETE: - return "Incomplete"; - case VK_ERROR_OUT_OF_HOST_MEMORY: - return "Out of host memory"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: - return "Out of device memory"; - case VK_ERROR_INITIALIZATION_FAILED: - return "Initialization failed"; - case VK_ERROR_DEVICE_LOST: - return "Device lost"; - case VK_ERROR_MEMORY_MAP_FAILED: - return "Memory map failed"; - case VK_ERROR_LAYER_NOT_PRESENT: - return "Layer not present"; - case VK_ERROR_EXTENSION_NOT_PRESENT: - return "Extension not present"; - case VK_ERROR_FEATURE_NOT_PRESENT: - return "Feature not present"; - case VK_ERROR_INCOMPATIBLE_DRIVER: - return "Incompatible driver"; - case VK_ERROR_TOO_MANY_OBJECTS: - return "Too many objects"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: - return "Format not supported"; - case VK_ERROR_FRAGMENTED_POOL: - return "Fragmented pool"; - case VK_ERROR_OUT_OF_POOL_MEMORY: // Vulkan 1.1 - return "Out of pool memory"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE: // Vulkan 1.1 - return "Invalid external handle"; - case VK_ERROR_SURFACE_LOST_KHR: // VK_KHR_surface - return "Surface lost"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: // VK_KHR_surface - return "Native window in use"; - case VK_SUBOPTIMAL_KHR: // VK_KHR_swapchain - return "Suboptimal"; - case VK_ERROR_OUT_OF_DATE_KHR: // VK_KHR_swapchain - return "Out of date"; - case VK_ERROR_VALIDATION_FAILED_EXT: // VK_EXT_debug_report - return "Validation failed"; - default: - break; - } - - return "Unknown error"; + switch (result) { + case VK_SUCCESS: + return "Success"; + case VK_NOT_READY: + return "Not Ready"; + case VK_TIMEOUT: + return "Timeout"; + case VK_EVENT_SET: + return "Event set"; + case VK_EVENT_RESET: + return "Event reset"; + case VK_INCOMPLETE: + return "Incomplete"; + case VK_ERROR_OUT_OF_HOST_MEMORY: + return "Out of host memory"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "Out of device memory"; + case VK_ERROR_INITIALIZATION_FAILED: + return "Initialization failed"; + case VK_ERROR_DEVICE_LOST: + return "Device lost"; + case VK_ERROR_MEMORY_MAP_FAILED: + return "Memory map failed"; + case VK_ERROR_LAYER_NOT_PRESENT: + return "Layer not present"; + case VK_ERROR_EXTENSION_NOT_PRESENT: + return "Extension not present"; + case VK_ERROR_FEATURE_NOT_PRESENT: + return "Feature not present"; + case VK_ERROR_INCOMPATIBLE_DRIVER: + return "Incompatible driver"; + case VK_ERROR_TOO_MANY_OBJECTS: + return "Too many objects"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: + return "Format not supported"; + case VK_ERROR_FRAGMENTED_POOL: + return "Fragmented pool"; + case VK_ERROR_OUT_OF_POOL_MEMORY: // Vulkan 1.1 + return "Out of pool memory"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: // Vulkan 1.1 + return "Invalid external handle"; + case VK_ERROR_SURFACE_LOST_KHR: // VK_KHR_surface + return "Surface lost"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: // VK_KHR_surface + return "Native window in use"; + case VK_SUBOPTIMAL_KHR: // VK_KHR_swapchain + return "Suboptimal"; + case VK_ERROR_OUT_OF_DATE_KHR: // VK_KHR_swapchain + return "Out of date"; + case VK_ERROR_VALIDATION_FAILED_EXT: // VK_EXT_debug_report + return "Validation failed"; + default: + break; + } + + return "Unknown error"; } static inline const char* string(const VkPresentModeKHR presentMode) { - switch (presentMode) { - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return "Immediate"; - case VK_PRESENT_MODE_MAILBOX_KHR: - return "Mailbox"; - case VK_PRESENT_MODE_FIFO_KHR: - return "FIFO"; - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - return "Relaxed FIFO"; - default: - break; - } - - return "Unknown present mode"; + switch (presentMode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return "Immediate"; + case VK_PRESENT_MODE_MAILBOX_KHR: + return "Mailbox"; + case VK_PRESENT_MODE_FIFO_KHR: + return "FIFO"; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + return "Relaxed FIFO"; + default: + break; + } + + return "Unknown present mode"; } static inline const char* string(const VkDebugReportFlagBitsEXT flag) { - switch (flag) { - case VK_DEBUG_REPORT_INFORMATION_BIT_EXT: - return "Information"; - case VK_DEBUG_REPORT_WARNING_BIT_EXT: - return "Warning"; - case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT: - return "Performance Warning"; - case VK_DEBUG_REPORT_ERROR_BIT_EXT: - return "Error"; - case VK_DEBUG_REPORT_DEBUG_BIT_EXT: - return "Debug"; - default: - break; - } - - return "Unknown report"; + switch (flag) { + case VK_DEBUG_REPORT_INFORMATION_BIT_EXT: + return "Information"; + case VK_DEBUG_REPORT_WARNING_BIT_EXT: + return "Warning"; + case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT: + return "Performance Warning"; + case VK_DEBUG_REPORT_ERROR_BIT_EXT: + return "Error"; + case VK_DEBUG_REPORT_DEBUG_BIT_EXT: + return "Debug"; + default: + break; + } + + return "Unknown report"; } template<class T> class GlobalDeleter { public: - using DestroyFunc = void (*)(T, const VkAllocationCallbacks*); + using DestroyFunc = void (*)(T, const VkAllocationCallbacks*); - GlobalDeleter() = default; - ~GlobalDeleter() = default; + GlobalDeleter() = default; + ~GlobalDeleter() = default; - GlobalDeleter(DestroyFunc destroyFunc) noexcept - : _destroyFunc{destroyFunc} - {} + GlobalDeleter(DestroyFunc destroyFunc) noexcept + : _destroyFunc{destroyFunc} + {} - GlobalDeleter(const GlobalDeleter&) = delete; - GlobalDeleter& operator=(const GlobalDeleter&) = delete; + GlobalDeleter(const GlobalDeleter&) = delete; + GlobalDeleter& operator=(const GlobalDeleter&) = delete; - GlobalDeleter(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - } + GlobalDeleter(GlobalDeleter&& other) noexcept + { + std::swap(_destroyFunc, other._destroyFunc); + } - GlobalDeleter& operator=(GlobalDeleter&& other) noexcept - { - std::swap(_destroyFunc, other._destroyFunc); - return *this; - } + GlobalDeleter& operator=(GlobalDeleter&& other) noexcept + { + std::swap(_destroyFunc, other._destroyFunc); + return *this; + } - void operator()(T handle) noexcept - { - if (_destroyFunc && handle) { - _destroyFunc(handle, nullptr); - } - } + void operator()(T handle) noexcept + { + if (_destroyFunc && handle) { + _destroyFunc(handle, nullptr); + } + } private: - DestroyFunc _destroyFunc{}; + DestroyFunc _destroyFunc{}; }; template<class T, class Parent> class DependantDeleter { public: - using DestroyFunc = void (*)(Parent, T, const VkAllocationCallbacks*); + using DestroyFunc = void (*)(Parent, T, const VkAllocationCallbacks*); - DependantDeleter() = default; - ~DependantDeleter() = default; + DependantDeleter() = default; + ~DependantDeleter() = default; - DependantDeleter(Parent parent, DestroyFunc destroyFunc) noexcept - : _parent{parent} - , _destroyFunc{destroyFunc} - {} + DependantDeleter(Parent parent, DestroyFunc destroyFunc) noexcept + : _parent{parent} + , _destroyFunc{destroyFunc} + {} - DependantDeleter(const DependantDeleter&) = delete; - DependantDeleter& operator=(const DependantDeleter&) = delete; + DependantDeleter(const DependantDeleter&) = delete; + DependantDeleter& operator=(const DependantDeleter&) = delete; - DependantDeleter(DependantDeleter&& other) noexcept { swap(other); } + DependantDeleter(DependantDeleter&& other) noexcept { swap(other); } - DependantDeleter& operator=(DependantDeleter&& other) noexcept - { - swap(other); - return *this; - } + DependantDeleter& operator=(DependantDeleter&& other) noexcept + { + swap(other); + return *this; + } - void operator()(T handle) noexcept - { - if (_parent && _destroyFunc && handle) { - _destroyFunc(_parent, handle, nullptr); - } - } + void operator()(T handle) noexcept + { + if (_parent && _destroyFunc && handle) { + _destroyFunc(_parent, handle, nullptr); + } + } private: - void swap(DependantDeleter& other) noexcept - { - std::swap(_parent, other._parent); - std::swap(_destroyFunc, other._destroyFunc); - } - - Parent _parent{}; - DestroyFunc _destroyFunc{}; + void swap(DependantDeleter& other) noexcept + { + std::swap(_parent, other._parent); + std::swap(_destroyFunc, other._destroyFunc); + } + + Parent _parent{}; + DestroyFunc _destroyFunc{}; }; template<class T, class Pool, class FreeFuncResult> class PoolDeleter { public: - using FreeFunc = FreeFuncResult (*)(VkDevice, Pool, uint32_t, const T*); - - PoolDeleter() noexcept = default; - ~PoolDeleter() noexcept = default; - - PoolDeleter(VkDevice device, - Pool pool, - uint32_t count, - FreeFunc freeFunc) noexcept - : _device{device} - , _pool{pool} - , _count{count} - , _freeFunc{freeFunc} - {} - - PoolDeleter(const PoolDeleter&) = delete; - PoolDeleter& operator=(const PoolDeleter&) = delete; - - PoolDeleter(PoolDeleter&& other) noexcept { swap(other); } - - PoolDeleter& operator=(PoolDeleter&& other) noexcept - { - swap(other); - return *this; - } - - void operator()(T* handle) noexcept - { - if (_device && _pool && handle) { - _freeFunc(_device, _pool, _count, handle); - } - } + using FreeFunc = FreeFuncResult (*)(VkDevice, Pool, uint32_t, const T*); + + PoolDeleter() noexcept = default; + ~PoolDeleter() noexcept = default; + + PoolDeleter(VkDevice device, + Pool pool, + uint32_t count, + FreeFunc freeFunc) noexcept + : _device{device} + , _pool{pool} + , _count{count} + , _freeFunc{freeFunc} + {} + + PoolDeleter(const PoolDeleter&) = delete; + PoolDeleter& operator=(const PoolDeleter&) = delete; + + PoolDeleter(PoolDeleter&& other) noexcept { swap(other); } + + PoolDeleter& operator=(PoolDeleter&& other) noexcept + { + swap(other); + return *this; + } + + void operator()(T* handle) noexcept + { + if (_device && _pool && handle) { + _freeFunc(_device, _pool, _count, handle); + } + } private: - void swap(PoolDeleter& other) noexcept - { - std::swap(_device, other._device); - std::swap(_pool, other._pool); - std::swap(_count, other._count); - std::swap(_freeFunc, other._freeFunc); - } - - VkDevice _device{}; - Pool _pool{}; - uint32_t _count{}; - FreeFunc _freeFunc{}; + void swap(PoolDeleter& other) noexcept + { + std::swap(_device, other._device); + std::swap(_pool, other._pool); + std::swap(_count, other._count); + std::swap(_freeFunc, other._freeFunc); + } + + VkDevice _device{}; + Pool _pool{}; + uint32_t _count{}; + FreeFunc _freeFunc{}; }; template<class T, class TDeleter> class UniqueDispatchableHandle { public: - using Deleter = TDeleter; - using Handle = T; + using Deleter = TDeleter; + using Handle = T; - static_assert(std::is_pointer<T>::value, ""); + static_assert(std::is_pointer<T>::value, ""); - UniqueDispatchableHandle() = default; + UniqueDispatchableHandle() = default; - UniqueDispatchableHandle(Handle handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - {} + UniqueDispatchableHandle(Handle handle, Deleter deleter) noexcept + : _handle{handle} + , _deleter{std::move(deleter)} + {} - ~UniqueDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } + ~UniqueDispatchableHandle() noexcept + { + if (_handle) { + _deleter(_handle); + } + } - UniqueDispatchableHandle(const UniqueDispatchableHandle&) noexcept = delete; - UniqueDispatchableHandle& - operator=(const UniqueDispatchableHandle&) noexcept = delete; + UniqueDispatchableHandle(const UniqueDispatchableHandle&) noexcept = delete; + UniqueDispatchableHandle& operator =( + const UniqueDispatchableHandle&) noexcept = delete; - UniqueDispatchableHandle(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - } + UniqueDispatchableHandle(UniqueDispatchableHandle&& other) noexcept + { + swap(other); + } - UniqueDispatchableHandle& - operator=(UniqueDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } + UniqueDispatchableHandle& operator=(UniqueDispatchableHandle&& other) noexcept + { + swap(other); + return *this; + } - const Handle& get() const noexcept { return _handle; } + const Handle& get() const noexcept { return _handle; } - operator Handle() const noexcept { return _handle; } + operator Handle() const noexcept { return _handle; } private: - void swap(UniqueDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - Handle _handle{}; - Deleter _deleter{}; + void swap(UniqueDispatchableHandle& other) noexcept + { + std::swap(_handle, other._handle); + std::swap(_deleter, other._deleter); + } + + Handle _handle{}; + Deleter _deleter{}; }; -#if defined(__LP64__) || defined(_WIN64) || \ - (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ - defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ - defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || \ + (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || \ + defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || \ + defined(__powerpc64__) template<class T, class TDeleter> using UniqueNonDispatchableHandle = UniqueDispatchableHandle<T, TDeleter>; @@ -418,55 +417,55 @@ template<class T, class TDeleter> class UniqueNonDispatchableHandle { public: - using Deleter = TDeleter; - using Handle = T; - - UniqueNonDispatchableHandle() = default; - - UniqueNonDispatchableHandle(T handle, Deleter deleter) noexcept - : _handle{handle} - , _deleter{std::move(deleter)} - { - assert(handle); - } - - ~UniqueNonDispatchableHandle() noexcept - { - if (_handle) { - _deleter(_handle); - } - } - - UniqueNonDispatchableHandle(const UniqueNonDispatchableHandle&) noexcept = - delete; - UniqueNonDispatchableHandle& - operator=(const UniqueNonDispatchableHandle&) noexcept = delete; - - UniqueNonDispatchableHandle(UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - } - - UniqueNonDispatchableHandle& - operator=(UniqueNonDispatchableHandle&& other) noexcept - { - swap(other); - return *this; - } - - const Handle& get() const noexcept { return _handle; } - - operator Handle() const noexcept { return _handle; } + using Deleter = TDeleter; + using Handle = T; + + UniqueNonDispatchableHandle() = default; + + UniqueNonDispatchableHandle(T handle, Deleter deleter) noexcept + : _handle{handle} + , _deleter{std::move(deleter)} + { + assert(handle); + } + + ~UniqueNonDispatchableHandle() noexcept + { + if (_handle) { + _deleter(_handle); + } + } + + UniqueNonDispatchableHandle(const UniqueNonDispatchableHandle&) noexcept = + delete; + UniqueNonDispatchableHandle& operator =( + const UniqueNonDispatchableHandle&) noexcept = delete; + + UniqueNonDispatchableHandle(UniqueNonDispatchableHandle&& other) noexcept + { + swap(other); + } + + UniqueNonDispatchableHandle& operator=( + UniqueNonDispatchableHandle&& other) noexcept + { + swap(other); + return *this; + } + + const Handle& get() const noexcept { return _handle; } + + operator Handle() const noexcept { return _handle; } private: - void swap(UniqueNonDispatchableHandle& other) noexcept - { - std::swap(_handle, other._handle); - std::swap(_deleter, other._deleter); - } - - T _handle{}; - Deleter _deleter{}; + void swap(UniqueNonDispatchableHandle& other) noexcept + { + std::swap(_handle, other._handle); + std::swap(_deleter, other._deleter); + } + + T _handle{}; + Deleter _deleter{}; }; #endif @@ -475,83 +474,83 @@ template<class Vector, class Deleter> class UniqueArrayHandle { public: - using T = typename Vector::value_type; + using T = typename Vector::value_type; - UniqueArrayHandle() = default; + UniqueArrayHandle() = default; - UniqueArrayHandle(uint32_t size, Vector&& array, Deleter deleter) noexcept - : _array{std::move(array)} - , _deleter{std::move(deleter)} - , _size{size} - { - assert(!_array.empty()); - } + UniqueArrayHandle(uint32_t size, Vector&& array, Deleter deleter) noexcept + : _array{std::move(array)} + , _deleter{std::move(deleter)} + , _size{size} + { + assert(!_array.empty()); + } - ~UniqueArrayHandle() noexcept - { - if (!_array.empty()) { - _deleter(_array.data()); - } - } + ~UniqueArrayHandle() noexcept + { + if (!_array.empty()) { + _deleter(_array.data()); + } + } - UniqueArrayHandle(const UniqueArrayHandle&) noexcept = delete; - UniqueArrayHandle& operator=(const UniqueArrayHandle&) noexcept = delete; + UniqueArrayHandle(const UniqueArrayHandle&) noexcept = delete; + UniqueArrayHandle& operator=(const UniqueArrayHandle&) noexcept = delete; - UniqueArrayHandle(UniqueArrayHandle&& other) noexcept { swap(other); } + UniqueArrayHandle(UniqueArrayHandle&& other) noexcept { swap(other); } - UniqueArrayHandle& operator=(UniqueArrayHandle&& other) noexcept - { - swap(other); - return *this; - } + UniqueArrayHandle& operator=(UniqueArrayHandle&& other) noexcept + { + swap(other); + return *this; + } - const T& operator[](const size_t index) const noexcept - { - return _array[index]; - } + const T& operator[](const size_t index) const noexcept + { + return _array[index]; + } - T& operator[](const size_t index) noexcept { return _array[index]; } + T& operator[](const size_t index) noexcept { return _array[index]; } - const T* get() const noexcept { return _array.data(); } - T* get() noexcept { return _array.data(); } + const T* get() const noexcept { return _array.data(); } + T* get() noexcept { return _array.data(); } private: - void swap(UniqueArrayHandle& other) noexcept - { - std::swap(_array, other._array); - std::swap(_deleter, other._deleter); - std::swap(_size, other._size); - } - - Vector _array{}; - Deleter _deleter{}; - uint32_t _size{}; + void swap(UniqueArrayHandle& other) noexcept + { + std::swap(_array, other._array); + std::swap(_deleter, other._deleter); + std::swap(_size, other._size); + } + + Vector _array{}; + Deleter _deleter{}; + uint32_t _size{}; }; template<typename T> class OptionalParameter { public: - using Handle = typename T::Handle; + using Handle = typename T::Handle; - OptionalParameter(const T& value) noexcept - : _handle{value.get()} - {} + OptionalParameter(const T& value) noexcept + : _handle{value.get()} + {} - OptionalParameter() noexcept - : _handle{} - {} + OptionalParameter() noexcept + : _handle{} + {} - OptionalParameter(const OptionalParameter&) = delete; - OptionalParameter& operator=(const OptionalParameter&) = delete; + OptionalParameter(const OptionalParameter&) = delete; + OptionalParameter& operator=(const OptionalParameter&) = delete; - OptionalParameter(OptionalParameter&&) = delete; - OptionalParameter& operator=(OptionalParameter&&) = delete; + OptionalParameter(OptionalParameter&&) = delete; + OptionalParameter& operator=(OptionalParameter&&) = delete; - const Handle get() const noexcept { return _handle; } + const Handle get() const noexcept { return _handle; } private: - Handle _handle{}; + Handle _handle{}; }; template<typename T> @@ -559,20 +558,20 @@ using GlobalObject = UniqueDispatchableHandle<T, GlobalDeleter<T>>; template<typename T> using InstanceChild = - UniqueNonDispatchableHandle<T, DependantDeleter<T, VkInstance>>; + UniqueNonDispatchableHandle<T, DependantDeleter<T, VkInstance>>; template<typename T> using DispatchableDeviceChild = - UniqueDispatchableHandle<T, DependantDeleter<T, VkDevice>>; + UniqueDispatchableHandle<T, DependantDeleter<T, VkDevice>>; template<typename T> using NonDispatchableDeviceChild = - UniqueNonDispatchableHandle<T, DependantDeleter<T, VkDevice>>; + UniqueNonDispatchableHandle<T, DependantDeleter<T, VkDevice>>; template<typename Vector, typename Pool, typename FreeFuncResult> using PoolChild = UniqueArrayHandle< - Vector, - PoolDeleter<typename Vector::value_type, Pool, FreeFuncResult>>; + Vector, + PoolDeleter<typename Vector::value_type, Pool, FreeFuncResult>>; using Device = GlobalObject<VkDevice>; using Instance = GlobalObject<VkInstance>; @@ -606,7 +605,7 @@ using CommandBuffers = PoolChild<VkCommandBufferVector, VkCommandPool, void>; template<class VkDescriptorSetVector> using DescriptorSets = - PoolChild<VkDescriptorSetVector, VkDescriptorPool, VkResult>; + PoolChild<VkDescriptorSetVector, VkDescriptorPool, VkResult>; // VK_KHR_swapchain using SwapchainKHR = NonDispatchableDeviceChild<VkSwapchainKHR>; @@ -622,11 +621,11 @@ struct IndexSequence {}; template<size_t N, size_t... Next> struct IndexSequenceHelper - : public IndexSequenceHelper<N - 1U, N - 1U, Next...> {}; + : public IndexSequenceHelper<N - 1U, N - 1U, Next...> {}; template<size_t... Next> struct IndexSequenceHelper<0U, Next...> { - using type = IndexSequence<Next...>; + using type = IndexSequence<Next...>; }; template<size_t N> @@ -639,7 +638,7 @@ make_handle_array_h(Parent parent, std::array<typename T::Handle, count> handles, IndexSequence<Is...>) noexcept { - return {T{handles[Is], {parent, destroyFunc}}...}; + return {T{handles[Is], {parent, destroyFunc}}...}; } template<class T, class Parent, class DestroyFunc, size_t count> @@ -648,8 +647,8 @@ make_handle_array(Parent parent, DestroyFunc destroyFunc, std::array<typename T::Handle, count> handles) noexcept { - return make_handle_array_h<T, Parent, DestroyFunc, count>( - parent, destroyFunc, handles, makeIndexSequence<count>()); + return make_handle_array_h<T, Parent, DestroyFunc, count>( + parent, destroyFunc, handles, makeIndexSequence<count>()); } namespace detail { @@ -658,20 +657,20 @@ template<class Value, class Vector, class Func, class... Args> inline VkResult wrapVectorAccessor(Vector& vector, Func func, Args... args) noexcept { - uint32_t count = 0u; - VkResult r = func(args..., &count, nullptr); - if (r > VK_INCOMPLETE) { - vector.clear(); - return r; - } - - vector = Vector(count); - if ((r = func(args..., &count, vector.data()))) { - vector.clear(); - return r; - } - - return VK_SUCCESS; + uint32_t count = 0u; + VkResult r = func(args..., &count, nullptr); + if (r > VK_INCOMPLETE) { + vector.clear(); + return r; + } + + vector = Vector(count); + if ((r = func(args..., &count, vector.data()))) { + vector.clear(); + return r; + } + + return VK_SUCCESS; } } // namespace detail @@ -679,148 +678,147 @@ wrapVectorAccessor(Vector& vector, Func func, Args... args) noexcept class VulkanApi; struct MappedMemory { - MappedMemory() noexcept = default; - - MappedMemory(const VulkanApi& api, - VkDevice device, - VkDeviceMemory memory, - void* data) noexcept - : _api{&api} - , _device{device} - , _memory{memory} - , _data{data} - {} - - MappedMemory(const MappedMemory&) = delete; - MappedMemory& operator=(const MappedMemory&) = delete; - - MappedMemory(MappedMemory&& mappedMemory) noexcept - : _api{mappedMemory._api} - , _device{mappedMemory._device} - , _memory{mappedMemory._memory} - , _data{mappedMemory._data} - { - mappedMemory._device = {}; - mappedMemory._memory = {}; - mappedMemory._data = {}; - } - - MappedMemory& operator=(MappedMemory&& mappedMemory) noexcept - { - std::swap(_api, mappedMemory._api); - std::swap(_device, mappedMemory._device); - std::swap(_memory, mappedMemory._memory); - std::swap(_data, mappedMemory._data); - return *this; - } - - ~MappedMemory() noexcept; - - const void* get() const noexcept { return _data; } - void* get() noexcept { return _data; } + MappedMemory() noexcept = default; + + MappedMemory(const VulkanApi& api, + VkDevice device, + VkDeviceMemory memory, + void* data) noexcept + : _api{&api} + , _device{device} + , _memory{memory} + , _data{data} + {} + + MappedMemory(const MappedMemory&) = delete; + MappedMemory& operator=(const MappedMemory&) = delete; + + MappedMemory(MappedMemory&& mappedMemory) noexcept + : _api{mappedMemory._api} + , _device{mappedMemory._device} + , _memory{mappedMemory._memory} + , _data{mappedMemory._data} + { + mappedMemory._device = {}; + mappedMemory._memory = {}; + mappedMemory._data = {}; + } + + MappedMemory& operator=(MappedMemory&& mappedMemory) noexcept + { + std::swap(_api, mappedMemory._api); + std::swap(_device, mappedMemory._device); + std::swap(_memory, mappedMemory._memory); + std::swap(_data, mappedMemory._data); + return *this; + } + + ~MappedMemory() noexcept; + + const void* get() const noexcept { return _data; } + void* get() noexcept { return _data; } private: - const VulkanApi* _api{}; - VkDevice _device{}; - VkDeviceMemory _memory{}; - void* _data{}; + const VulkanApi* _api{}; + VkDevice _device{}; + VkDeviceMemory _memory{}; + void* _data{}; }; class VulkanInitApi { public: - template<typename NotFoundFunc> - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr, - NotFoundFunc notFound) noexcept - { -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name(getInstanceProcAddr(NULL, #name)))) { \ - notFound(#name); \ - } \ - } while (0) - - vkGetInstanceProcAddr = pGetInstanceProcAddr; - SK_INIT(vkCreateInstance); - vkDestroyInstance = {}; // Loaded after we create an instance - SK_INIT(vkEnumerateInstanceExtensionProperties); - SK_INIT(vkEnumerateInstanceLayerProperties); - - if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties || - !vkEnumerateInstanceLayerProperties) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - return VK_SUCCESS; + template<typename NotFoundFunc> + VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr, + NotFoundFunc notFound) noexcept + { +#define SK_INIT(name) \ + do { \ + if (!(name = PFN_##name(getInstanceProcAddr(NULL, #name)))) { \ + notFound(#name); \ + } \ + } while (0) + + vkGetInstanceProcAddr = pGetInstanceProcAddr; + SK_INIT(vkCreateInstance); + vkDestroyInstance = {}; // Loaded after we create an instance + SK_INIT(vkEnumerateInstanceExtensionProperties); + SK_INIT(vkEnumerateInstanceLayerProperties); + + if (!vkCreateInstance || !vkEnumerateInstanceExtensionProperties || + !vkEnumerateInstanceLayerProperties) { + return VK_ERROR_INITIALIZATION_FAILED; + } + + return VK_SUCCESS; #undef SK_INIT - } - - VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr) noexcept - { - return init(pGetInstanceProcAddr, [](const char*) {}); - } - - PFN_vkVoidFunction - getInstanceProcAddr(VkInstance instance, - const char* const name) const noexcept - { - return vkGetInstanceProcAddr(instance, name); - } - - VkResult createInstance(const VkInstanceCreateInfo& createInfo, - Instance& instance) noexcept - { - VkInstance h = {}; - if (const VkResult r = vkCreateInstance(&createInfo, nullptr, &h)) { - return r; - } else if (!h) { - // Shouldn't actually happen, but this lets the compiler know that - return VK_ERROR_INITIALIZATION_FAILED; - } - - if (!vkDestroyInstance) { - vkDestroyInstance = PFN_vkDestroyInstance( - getInstanceProcAddr(instance, "vkDestroyInstance")); - } - - instance = {h, {vkDestroyInstance}}; - return VK_SUCCESS; - } - - template<class Vector> - VkResult - enumerateInstanceExtensionProperties(Vector& properties) const noexcept - { - return detail::wrapVectorAccessor<VkExtensionProperties>( - properties, vkEnumerateInstanceExtensionProperties, nullptr); - } - - template<class Vector> - VkResult - enumerateInstanceExtensionProperties(const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor<VkExtensionProperties>( - properties, vkEnumerateInstanceExtensionProperties, layerName); - } - - template<class Vector> - VkResult enumerateInstanceLayerProperties(Vector& properties) const noexcept - { - return detail::wrapVectorAccessor<VkLayerProperties>( - properties, vkEnumerateInstanceLayerProperties); - } + } + + VkResult init(PFN_vkGetInstanceProcAddr pGetInstanceProcAddr) noexcept + { + return init(pGetInstanceProcAddr, [](const char*) {}); + } + + PFN_vkVoidFunction getInstanceProcAddr(VkInstance instance, + const char* const name) const noexcept + { + return vkGetInstanceProcAddr(instance, name); + } + + VkResult createInstance(const VkInstanceCreateInfo& createInfo, + Instance& instance) noexcept + { + VkInstance h = {}; + if (const VkResult r = vkCreateInstance(&createInfo, nullptr, &h)) { + return r; + } else if (!h) { + // Shouldn't actually happen, but this lets the compiler know that + return VK_ERROR_INITIALIZATION_FAILED; + } + + if (!vkDestroyInstance) { + vkDestroyInstance = PFN_vkDestroyInstance( + getInstanceProcAddr(instance, "vkDestroyInstance")); + } + + instance = {h, {vkDestroyInstance}}; + return VK_SUCCESS; + } + + template<class Vector> + VkResult enumerateInstanceExtensionProperties( + Vector& properties) const noexcept + { + return detail::wrapVectorAccessor<VkExtensionProperties>( + properties, vkEnumerateInstanceExtensionProperties, nullptr); + } + + template<class Vector> + VkResult enumerateInstanceExtensionProperties( + const char* const layerName, + Vector& properties) const noexcept + { + return detail::wrapVectorAccessor<VkExtensionProperties>( + properties, vkEnumerateInstanceExtensionProperties, layerName); + } + + template<class Vector> + VkResult enumerateInstanceLayerProperties(Vector& properties) const noexcept + { + return detail::wrapVectorAccessor<VkLayerProperties>( + properties, vkEnumerateInstanceLayerProperties); + } private: - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; #define SK_FUNC(name) \ - PFN_##name name {} + PFN_##name name {} - SK_FUNC(vkCreateInstance); - SK_FUNC(vkDestroyInstance); - SK_FUNC(vkEnumerateInstanceExtensionProperties); - SK_FUNC(vkEnumerateInstanceLayerProperties); + SK_FUNC(vkCreateInstance); + SK_FUNC(vkDestroyInstance); + SK_FUNC(vkEnumerateInstanceExtensionProperties); + SK_FUNC(vkEnumerateInstanceLayerProperties); #undef SK_FUNC }; @@ -828,1529 +826,1472 @@ private: class VulkanApi { public: - template<typename NotFoundFunc> - VkResult init(const VulkanInitApi& initApi, - const Instance& instance, - NotFoundFunc notFound) noexcept - { - VkResult r = VK_SUCCESS; - - const auto notFoundWrapper = [&r, notFound](const char* name) { - r = VK_INCOMPLETE; - notFound(name); - }; - -#define SK_INIT(name) \ - do { \ - if (!(name = PFN_##name( \ - initApi.getInstanceProcAddr(instance, #name)))) { \ - notFoundWrapper(#name); \ - } \ - } while (0) - - SK_INIT(vkAllocateCommandBuffers); - SK_INIT(vkAllocateDescriptorSets); - SK_INIT(vkAllocateMemory); - SK_INIT(vkBeginCommandBuffer); - SK_INIT(vkBindBufferMemory); - SK_INIT(vkBindImageMemory); - SK_INIT(vkCmdBeginQuery); - SK_INIT(vkCmdBeginRenderPass); - SK_INIT(vkCmdBindDescriptorSets); - SK_INIT(vkCmdBindIndexBuffer); - SK_INIT(vkCmdBindPipeline); - SK_INIT(vkCmdBindVertexBuffers); - SK_INIT(vkCmdBlitImage); - SK_INIT(vkCmdClearAttachments); - SK_INIT(vkCmdClearColorImage); - SK_INIT(vkCmdClearDepthStencilImage); - SK_INIT(vkCmdCopyBuffer); - SK_INIT(vkCmdCopyBufferToImage); - SK_INIT(vkCmdCopyImage); - SK_INIT(vkCmdCopyImageToBuffer); - SK_INIT(vkCmdCopyQueryPoolResults); - SK_INIT(vkCmdDispatch); - SK_INIT(vkCmdDispatchIndirect); - SK_INIT(vkCmdDraw); - SK_INIT(vkCmdDrawIndexed); - SK_INIT(vkCmdDrawIndexedIndirect); - SK_INIT(vkCmdDrawIndirect); - SK_INIT(vkCmdEndQuery); - SK_INIT(vkCmdEndRenderPass); - SK_INIT(vkCmdExecuteCommands); - SK_INIT(vkCmdFillBuffer); - SK_INIT(vkCmdNextSubpass); - SK_INIT(vkCmdPipelineBarrier); - SK_INIT(vkCmdPushConstants); - SK_INIT(vkCmdResetEvent); - SK_INIT(vkCmdResetQueryPool); - SK_INIT(vkCmdResolveImage); - SK_INIT(vkCmdSetBlendConstants); - SK_INIT(vkCmdSetDepthBias); - SK_INIT(vkCmdSetDepthBounds); - SK_INIT(vkCmdSetEvent); - SK_INIT(vkCmdSetLineWidth); - SK_INIT(vkCmdSetScissor); - SK_INIT(vkCmdSetStencilCompareMask); - SK_INIT(vkCmdSetStencilReference); - SK_INIT(vkCmdSetStencilWriteMask); - SK_INIT(vkCmdSetViewport); - SK_INIT(vkCmdUpdateBuffer); - SK_INIT(vkCmdWaitEvents); - SK_INIT(vkCmdWriteTimestamp); - SK_INIT(vkCreateBuffer); - SK_INIT(vkCreateBufferView); - SK_INIT(vkCreateCommandPool); - SK_INIT(vkCreateComputePipelines); - SK_INIT(vkCreateDescriptorPool); - SK_INIT(vkCreateDescriptorSetLayout); - SK_INIT(vkCreateDevice); - SK_INIT(vkCreateEvent); - SK_INIT(vkCreateFence); - SK_INIT(vkCreateFramebuffer); - SK_INIT(vkCreateGraphicsPipelines); - SK_INIT(vkCreateImage); - SK_INIT(vkCreateImageView); - SK_INIT(vkCreateInstance); - SK_INIT(vkCreatePipelineCache); - SK_INIT(vkCreatePipelineLayout); - SK_INIT(vkCreateQueryPool); - SK_INIT(vkCreateRenderPass); - SK_INIT(vkCreateSampler); - SK_INIT(vkCreateSemaphore); - SK_INIT(vkCreateShaderModule); - SK_INIT(vkDestroyBuffer); - SK_INIT(vkDestroyBufferView); - SK_INIT(vkDestroyCommandPool); - SK_INIT(vkDestroyDescriptorPool); - SK_INIT(vkDestroyDescriptorSetLayout); - SK_INIT(vkDestroyDevice); - SK_INIT(vkDestroyEvent); - SK_INIT(vkDestroyFence); - SK_INIT(vkDestroyFramebuffer); - SK_INIT(vkDestroyImage); - SK_INIT(vkDestroyImageView); - SK_INIT(vkDestroyPipeline); - SK_INIT(vkDestroyPipelineCache); - SK_INIT(vkDestroyPipelineLayout); - SK_INIT(vkDestroyQueryPool); - SK_INIT(vkDestroyRenderPass); - SK_INIT(vkDestroySampler); - SK_INIT(vkDestroySemaphore); - SK_INIT(vkDestroyShaderModule); - SK_INIT(vkDeviceWaitIdle); - SK_INIT(vkEndCommandBuffer); - SK_INIT(vkEnumerateDeviceExtensionProperties); - SK_INIT(vkEnumerateDeviceLayerProperties); - SK_INIT(vkEnumeratePhysicalDevices); - SK_INIT(vkFlushMappedMemoryRanges); - SK_INIT(vkFreeCommandBuffers); - SK_INIT(vkFreeDescriptorSets); - SK_INIT(vkFreeMemory); - SK_INIT(vkGetBufferMemoryRequirements); - SK_INIT(vkGetDeviceMemoryCommitment); - SK_INIT(vkGetDeviceProcAddr); - SK_INIT(vkGetDeviceQueue); - SK_INIT(vkGetEventStatus); - SK_INIT(vkGetFenceStatus); - SK_INIT(vkGetImageMemoryRequirements); - SK_INIT(vkGetImageSparseMemoryRequirements); - SK_INIT(vkGetImageSubresourceLayout); - SK_INIT(vkGetInstanceProcAddr); - SK_INIT(vkGetPhysicalDeviceFeatures); - SK_INIT(vkGetPhysicalDeviceFormatProperties); - SK_INIT(vkGetPhysicalDeviceImageFormatProperties); - SK_INIT(vkGetPhysicalDeviceMemoryProperties); - SK_INIT(vkGetPhysicalDeviceProperties); - SK_INIT(vkGetPhysicalDeviceQueueFamilyProperties); - SK_INIT(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_INIT(vkGetPipelineCacheData); - SK_INIT(vkGetQueryPoolResults); - SK_INIT(vkGetRenderAreaGranularity); - SK_INIT(vkInvalidateMappedMemoryRanges); - SK_INIT(vkMapMemory); - SK_INIT(vkMergePipelineCaches); - SK_INIT(vkQueueBindSparse); - SK_INIT(vkQueueSubmit); - SK_INIT(vkQueueWaitIdle); - SK_INIT(vkResetCommandBuffer); - SK_INIT(vkResetCommandPool); - SK_INIT(vkResetDescriptorPool); - SK_INIT(vkResetEvent); - SK_INIT(vkResetFences); - SK_INIT(vkSetEvent); - SK_INIT(vkUnmapMemory); - SK_INIT(vkUpdateDescriptorSets); - SK_INIT(vkWaitForFences); - - // VK_EXT_debug_report - SK_INIT(vkCreateDebugReportCallbackEXT); - SK_INIT(vkDebugReportMessageEXT); - SK_INIT(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_INIT(vkDestroySurfaceKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_INIT(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_INIT(vkAcquireNextImageKHR); - SK_INIT(vkCreateSwapchainKHR); - SK_INIT(vkDestroySwapchainKHR); - SK_INIT(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_INIT(vkGetDeviceGroupSurfacePresentModesKHR); - SK_INIT(vkGetPhysicalDevicePresentRectanglesKHR); - SK_INIT(vkGetSwapchainImagesKHR); - SK_INIT(vkQueuePresentKHR); + template<typename NotFoundFunc> + VkResult init(const VulkanInitApi& initApi, + const Instance& instance, + NotFoundFunc notFound) noexcept + { + VkResult r = VK_SUCCESS; + + const auto notFoundWrapper = [&r, notFound](const char* name) { + r = VK_INCOMPLETE; + notFound(name); + }; + +#define SK_INIT(name) \ + do { \ + if (!(name = PFN_##name(initApi.getInstanceProcAddr(instance, #name)))) { \ + notFoundWrapper(#name); \ + } \ + } while (0) + + SK_INIT(vkAllocateCommandBuffers); + SK_INIT(vkAllocateDescriptorSets); + SK_INIT(vkAllocateMemory); + SK_INIT(vkBeginCommandBuffer); + SK_INIT(vkBindBufferMemory); + SK_INIT(vkBindImageMemory); + SK_INIT(vkCmdBeginQuery); + SK_INIT(vkCmdBeginRenderPass); + SK_INIT(vkCmdBindDescriptorSets); + SK_INIT(vkCmdBindIndexBuffer); + SK_INIT(vkCmdBindPipeline); + SK_INIT(vkCmdBindVertexBuffers); + SK_INIT(vkCmdBlitImage); + SK_INIT(vkCmdClearAttachments); + SK_INIT(vkCmdClearColorImage); + SK_INIT(vkCmdClearDepthStencilImage); + SK_INIT(vkCmdCopyBuffer); + SK_INIT(vkCmdCopyBufferToImage); + SK_INIT(vkCmdCopyImage); + SK_INIT(vkCmdCopyImageToBuffer); + SK_INIT(vkCmdCopyQueryPoolResults); + SK_INIT(vkCmdDispatch); + SK_INIT(vkCmdDispatchIndirect); + SK_INIT(vkCmdDraw); + SK_INIT(vkCmdDrawIndexed); + SK_INIT(vkCmdDrawIndexedIndirect); + SK_INIT(vkCmdDrawIndirect); + SK_INIT(vkCmdEndQuery); + SK_INIT(vkCmdEndRenderPass); + SK_INIT(vkCmdExecuteCommands); + SK_INIT(vkCmdFillBuffer); + SK_INIT(vkCmdNextSubpass); + SK_INIT(vkCmdPipelineBarrier); + SK_INIT(vkCmdPushConstants); + SK_INIT(vkCmdResetEvent); + SK_INIT(vkCmdResetQueryPool); + SK_INIT(vkCmdResolveImage); + SK_INIT(vkCmdSetBlendConstants); + SK_INIT(vkCmdSetDepthBias); + SK_INIT(vkCmdSetDepthBounds); + SK_INIT(vkCmdSetEvent); + SK_INIT(vkCmdSetLineWidth); + SK_INIT(vkCmdSetScissor); + SK_INIT(vkCmdSetStencilCompareMask); + SK_INIT(vkCmdSetStencilReference); + SK_INIT(vkCmdSetStencilWriteMask); + SK_INIT(vkCmdSetViewport); + SK_INIT(vkCmdUpdateBuffer); + SK_INIT(vkCmdWaitEvents); + SK_INIT(vkCmdWriteTimestamp); + SK_INIT(vkCreateBuffer); + SK_INIT(vkCreateBufferView); + SK_INIT(vkCreateCommandPool); + SK_INIT(vkCreateComputePipelines); + SK_INIT(vkCreateDescriptorPool); + SK_INIT(vkCreateDescriptorSetLayout); + SK_INIT(vkCreateDevice); + SK_INIT(vkCreateEvent); + SK_INIT(vkCreateFence); + SK_INIT(vkCreateFramebuffer); + SK_INIT(vkCreateGraphicsPipelines); + SK_INIT(vkCreateImage); + SK_INIT(vkCreateImageView); + SK_INIT(vkCreateInstance); + SK_INIT(vkCreatePipelineCache); + SK_INIT(vkCreatePipelineLayout); + SK_INIT(vkCreateQueryPool); + SK_INIT(vkCreateRenderPass); + SK_INIT(vkCreateSampler); + SK_INIT(vkCreateSemaphore); + SK_INIT(vkCreateShaderModule); + SK_INIT(vkDestroyBuffer); + SK_INIT(vkDestroyBufferView); + SK_INIT(vkDestroyCommandPool); + SK_INIT(vkDestroyDescriptorPool); + SK_INIT(vkDestroyDescriptorSetLayout); + SK_INIT(vkDestroyDevice); + SK_INIT(vkDestroyEvent); + SK_INIT(vkDestroyFence); + SK_INIT(vkDestroyFramebuffer); + SK_INIT(vkDestroyImage); + SK_INIT(vkDestroyImageView); + SK_INIT(vkDestroyPipeline); + SK_INIT(vkDestroyPipelineCache); + SK_INIT(vkDestroyPipelineLayout); + SK_INIT(vkDestroyQueryPool); + SK_INIT(vkDestroyRenderPass); + SK_INIT(vkDestroySampler); + SK_INIT(vkDestroySemaphore); + SK_INIT(vkDestroyShaderModule); + SK_INIT(vkDeviceWaitIdle); + SK_INIT(vkEndCommandBuffer); + SK_INIT(vkEnumerateDeviceExtensionProperties); + SK_INIT(vkEnumerateDeviceLayerProperties); + SK_INIT(vkEnumeratePhysicalDevices); + SK_INIT(vkFlushMappedMemoryRanges); + SK_INIT(vkFreeCommandBuffers); + SK_INIT(vkFreeDescriptorSets); + SK_INIT(vkFreeMemory); + SK_INIT(vkGetBufferMemoryRequirements); + SK_INIT(vkGetDeviceMemoryCommitment); + SK_INIT(vkGetDeviceProcAddr); + SK_INIT(vkGetDeviceQueue); + SK_INIT(vkGetEventStatus); + SK_INIT(vkGetFenceStatus); + SK_INIT(vkGetImageMemoryRequirements); + SK_INIT(vkGetImageSparseMemoryRequirements); + SK_INIT(vkGetImageSubresourceLayout); + SK_INIT(vkGetInstanceProcAddr); + SK_INIT(vkGetPhysicalDeviceFeatures); + SK_INIT(vkGetPhysicalDeviceFormatProperties); + SK_INIT(vkGetPhysicalDeviceImageFormatProperties); + SK_INIT(vkGetPhysicalDeviceMemoryProperties); + SK_INIT(vkGetPhysicalDeviceProperties); + SK_INIT(vkGetPhysicalDeviceQueueFamilyProperties); + SK_INIT(vkGetPhysicalDeviceSparseImageFormatProperties); + SK_INIT(vkGetPipelineCacheData); + SK_INIT(vkGetQueryPoolResults); + SK_INIT(vkGetRenderAreaGranularity); + SK_INIT(vkInvalidateMappedMemoryRanges); + SK_INIT(vkMapMemory); + SK_INIT(vkMergePipelineCaches); + SK_INIT(vkQueueBindSparse); + SK_INIT(vkQueueSubmit); + SK_INIT(vkQueueWaitIdle); + SK_INIT(vkResetCommandBuffer); + SK_INIT(vkResetCommandPool); + SK_INIT(vkResetDescriptorPool); + SK_INIT(vkResetEvent); + SK_INIT(vkResetFences); + SK_INIT(vkSetEvent); + SK_INIT(vkUnmapMemory); + SK_INIT(vkUpdateDescriptorSets); + SK_INIT(vkWaitForFences); + + // VK_EXT_debug_report + SK_INIT(vkCreateDebugReportCallbackEXT); + SK_INIT(vkDebugReportMessageEXT); + SK_INIT(vkDestroyDebugReportCallbackEXT); + + // VK_KHR_surface + SK_INIT(vkDestroySurfaceKHR); + SK_INIT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + SK_INIT(vkGetPhysicalDeviceSurfaceFormatsKHR); + SK_INIT(vkGetPhysicalDeviceSurfacePresentModesKHR); + SK_INIT(vkGetPhysicalDeviceSurfaceSupportKHR); + + // VK_KHR_swapchain + SK_INIT(vkAcquireNextImageKHR); + SK_INIT(vkCreateSwapchainKHR); + SK_INIT(vkDestroySwapchainKHR); + SK_INIT(vkGetDeviceGroupPresentCapabilitiesKHR); + SK_INIT(vkGetDeviceGroupSurfacePresentModesKHR); + SK_INIT(vkGetPhysicalDevicePresentRectanglesKHR); + SK_INIT(vkGetSwapchainImagesKHR); + SK_INIT(vkQueuePresentKHR); #undef SK_INIT - return r; - } - - VkResult - init(const VulkanInitApi& initApi, const Instance& instance) noexcept - { - return init(initApi, instance, [](const char*) {}); - } - - template<class VkCommandBufferVector> - VkResult allocateCommandBuffers( - const Device& device, - const VkCommandBufferAllocateInfo& allocateInfo, - CommandBuffers<VkCommandBufferVector>& commandBuffers) const noexcept - { - VkCommandBufferVector rawCommandBuffers = VkCommandBufferVector( - allocateInfo.commandBufferCount); - - if (const VkResult r = vkAllocateCommandBuffers( - device, &allocateInfo, rawCommandBuffers.data())) { - return r; - } - - commandBuffers = CommandBuffers<VkCommandBufferVector>{ - allocateInfo.commandBufferCount, - std::move(rawCommandBuffers), - PoolDeleter<VkCommandBuffer, VkCommandPool, void>{ - device, - allocateInfo.commandPool, - allocateInfo.commandBufferCount, - vkFreeCommandBuffers}}; - return VK_SUCCESS; - } - - template<class VkDescriptorSetVector> - VkResult allocateDescriptorSets( - const Device& device, - const VkDescriptorSetAllocateInfo& allocateInfo, - DescriptorSets<VkDescriptorSetVector>& descriptorSets) const noexcept - { - auto descriptorSetVector = VkDescriptorSetVector( - allocateInfo.descriptorSetCount); - - if (const VkResult r = vkAllocateDescriptorSets( - device, &allocateInfo, descriptorSetVector.data())) { - return r; - } - - descriptorSets = DescriptorSets<VkDescriptorSetVector>{ - allocateInfo.descriptorSetCount, - std::move(descriptorSetVector), - PoolDeleter<VkDescriptorSet, VkDescriptorPool, VkResult>{ - device, - allocateInfo.descriptorPool, - allocateInfo.descriptorSetCount, - vkFreeDescriptorSets}}; - return VK_SUCCESS; - } - - VkResult bindBufferMemory(const Device& device, - const Buffer& buffer, - const DeviceMemory& memory, - VkDeviceSize memoryOffset) const noexcept - { - return vkBindBufferMemory - ? vkBindBufferMemory(device, buffer, memory, memoryOffset) - : VK_ERROR_FEATURE_NOT_PRESENT; - } - - VkResult createBuffer(const Device& device, - const VkBufferCreateInfo& createInfo, - Buffer& buffer) const noexcept - { - VkBuffer h = {}; - const VkResult r = vkCreateBuffer(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBuffer}, buffer); - } - - VkResult createBufferView(const Device& device, - const VkBufferViewCreateInfo& createInfo, - BufferView& bufferView) const noexcept - { - VkBufferView h = {}; - const VkResult r = vkCreateBufferView(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyBufferView}, bufferView); - } - - VkResult createCommandPool(const Device& device, - const VkCommandPoolCreateInfo& createInfo, - CommandPool& commandPool) const noexcept - { - VkCommandPool h = {}; - const VkResult r = - vkCreateCommandPool(device, &createInfo, nullptr, &h); - return wrapResult(r, h, {device, vkDestroyCommandPool}, commandPool); - } - - VkResult createDescriptorPool(const Device& device, - const VkDescriptorPoolCreateInfo& createInfo, - DescriptorPool& descriptorPool) const noexcept - { - VkDescriptorPool h = {}; - const VkResult r = - vkCreateDescriptorPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, - h, - {device, vkDestroyDescriptorPool}, - descriptorPool); - } - - VkResult createDescriptorSetLayout( - const Device& device, - const VkDescriptorSetLayoutCreateInfo& createInfo, - DescriptorSetLayout& descriptorSetLayout) const noexcept - { - VkDescriptorSetLayout h = {}; - const VkResult r = - vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &h); - - return wrapResult(r, - h, - {device, vkDestroyDescriptorSetLayout}, - descriptorSetLayout); - } - - VkResult createDevice(const PhysicalDevice& physicalDevice, - const VkDeviceCreateInfo& createInfo, - Device& result) const noexcept - { - VkDevice h = {}; - const VkResult r = - vkCreateDevice(physicalDevice, &createInfo, nullptr, &h); - - return wrapResult(r, h, {vkDestroyDevice}, result); - } - - VkResult createEvent(const Device& device, - const VkEventCreateInfo& createInfo, - Event& event) const noexcept - { - VkEvent h = {}; - const VkResult r = vkCreateEvent(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyEvent}, event); - } - - VkResult createFence(const Device& device, - const VkFenceCreateInfo& createInfo, - Fence& fence) const noexcept - { - VkFence h = {}; - const VkResult r = vkCreateFence(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFence}, fence); - } - - VkResult createFramebuffer(const Device& device, - const VkFramebufferCreateInfo& createInfo, - Framebuffer& framebuffer) const noexcept - { - VkFramebuffer h = {}; - const VkResult r = - vkCreateFramebuffer(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyFramebuffer}, framebuffer); - } - - VkResult createImage(const Device& device, - const VkImageCreateInfo& createInfo, - Image& image) const noexcept - { - VkImage h = {}; - const VkResult r = vkCreateImage(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImage}, image); - } - - VkResult createImageView(const Device& device, - const VkImageViewCreateInfo& createInfo, - ImageView& imageView) const noexcept - { - VkImageView h = {}; - const VkResult r = vkCreateImageView(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyImageView}, imageView); - } - - template<size_t count> - VkResult createGraphicsPipelines( - const Device& device, - const OptionalParameter<PipelineCache>& pipelineCache, - const std::array<VkGraphicsPipelineCreateInfo, count>& createInfos, - std::array<Pipeline, count>& pipelines) const noexcept - { - std::array<VkPipeline, count> pipelineHandles{}; - - if (const VkResult r = vkCreateGraphicsPipelines( - device, - pipelineCache.get(), - static_cast<uint32_t>(createInfos.size()), - createInfos.data(), - nullptr, - pipelineHandles.data())) { - return r; - } - - pipelines = make_handle_array<Pipeline>(device.get(), - vkDestroyPipeline, - pipelineHandles); - return VK_SUCCESS; - } - - VkResult createPipelineCache(const Device& device, - const VkPipelineCacheCreateInfo& createInfo, - PipelineCache& pipelineCache) const noexcept - { - VkPipelineCache h = {}; - const VkResult r = - vkCreatePipelineCache(device, &createInfo, nullptr, &h); - - return wrapResult(r, - h, - {device, vkDestroyPipelineCache}, - pipelineCache); - } - - VkResult createPipelineLayout(const Device& device, - const VkPipelineLayoutCreateInfo& createInfo, - PipelineLayout& pipelineLayout) const noexcept - { - VkPipelineLayout h = {}; - const VkResult r = - vkCreatePipelineLayout(device, &createInfo, nullptr, &h); - - return wrapResult(r, - h, - {device, vkDestroyPipelineLayout}, - pipelineLayout); - } - - VkResult createQueryPool(const Device& device, - const VkQueryPoolCreateInfo& createInfo, - QueryPool& queryPool) const noexcept - { - VkQueryPool h = {}; - const VkResult r = vkCreateQueryPool(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyQueryPool}, queryPool); - } - - VkResult createRenderPass(const Device& device, - const VkRenderPassCreateInfo& createInfo, - RenderPass& renderPass) const noexcept - { - VkRenderPass h = {}; - const VkResult r = vkCreateRenderPass(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyRenderPass}, renderPass); - } - - VkResult createSampler(const Device& device, - const VkSamplerCreateInfo& createInfo, - Sampler& sampler) const noexcept - { - VkSampler h = {}; - const VkResult r = vkCreateSampler(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySampler}, sampler); - } - - VkResult createSemaphore(const Device& device, - const VkSemaphoreCreateInfo& createInfo, - Semaphore& semaphore) const noexcept - { - VkSemaphore h = {}; - const VkResult r = vkCreateSemaphore(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroySemaphore}, semaphore); - } - - VkResult createShaderModule(const Device& device, - const VkShaderModuleCreateInfo& createInfo, - ShaderModule& shaderModule) const noexcept - { - VkShaderModule h = {}; - const VkResult r = - vkCreateShaderModule(device, &createInfo, nullptr, &h); - - return wrapResult(r, h, {device, vkDestroyShaderModule}, shaderModule); - } - - VkResult deviceWaitIdle(const Device& device) const noexcept - { - return vkDeviceWaitIdle(device); - } - - template<class Vector> - VkResult - enumerateDeviceExtensionProperties(const PhysicalDevice& physicalDevice, - const char* const layerName, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor<VkExtensionProperties>( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - layerName); - } - - template<class Vector> - VkResult - enumerateDeviceExtensionProperties(const PhysicalDevice& physicalDevice, - Vector& properties) const noexcept - { - return detail::wrapVectorAccessor<VkExtensionProperties>( - properties, - vkEnumerateDeviceExtensionProperties, - physicalDevice, - nullptr); - } - - template<class Vector> - VkResult enumeratePhysicalDevices(const Instance& instance, - Vector& physicalDevices) const noexcept - { - uint32_t count = 0u; - VkResult r = vkEnumeratePhysicalDevices(instance, &count, nullptr); - if (r > VK_INCOMPLETE) { - return r; - } - - physicalDevices = Vector(count); - if ((r = vkEnumeratePhysicalDevices(instance, - &count, - physicalDevices.data()))) { - return r; - } - - return VK_SUCCESS; - } - - sk::Queue getDeviceQueue(const Device& device, - const uint32_t queueFamilyIndex, - const uint32_t queueIndex) const noexcept - { - VkQueue queue{}; - vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &queue); - return sk::Queue{queue}; - } - - VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( - VkPhysicalDevice physicalDevice) const noexcept - { - VkPhysicalDeviceMemoryProperties properties{}; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); - return properties; - } - - VkPhysicalDeviceProperties getPhysicalDeviceProperties( - const PhysicalDevice& physicalDevice) const noexcept - { - VkPhysicalDeviceProperties properties{}; - vkGetPhysicalDeviceProperties(physicalDevice, &properties); - return properties; - } - - template<class Vector> - VkResult getPhysicalDeviceQueueFamilyProperties( - const PhysicalDevice& physicalDevice, - Vector& queueFamilyProperties) const noexcept - { - uint32_t count = 0u; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, - &count, - nullptr); - - queueFamilyProperties = Vector(count); - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, - &count, - queueFamilyProperties.data()); - - return VK_SUCCESS; - } - - VkMemoryRequirements - getBufferMemoryRequirements(const Device& device, - const Buffer& buffer) const noexcept - { - VkMemoryRequirements requirements; - vkGetBufferMemoryRequirements(device, buffer, &requirements); - return requirements; - } - - VkResult allocateMemory(const Device& device, - const VkMemoryAllocateInfo& info, - DeviceMemory& memory) const noexcept - { - VkDeviceMemory h = {}; - if (const VkResult r = vkAllocateMemory(device, &info, nullptr, &h)) { - return r; - } else if (!h) { - return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - - memory = DeviceMemory{h, {device, vkFreeMemory}}; - return VK_SUCCESS; - } - - VkResult mapMemory(const Device& device, - const DeviceMemory& memory, - VkDeviceSize offset, - VkDeviceSize size, - VkMemoryMapFlags flags, - MappedMemory& mappedMemory) const noexcept - { - void* data = nullptr; - if (const VkResult r = - vkMapMemory(device, memory, offset, size, flags, &data)) { - return r; - } - - mappedMemory = MappedMemory{*this, device, memory, data}; - return VK_SUCCESS; - } - - VkResult queueSubmit(const Queue& queue, - uint32_t submitCount, - const VkSubmitInfo& submits, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, submitCount, &submits, fence); - } - - VkResult queueSubmit(const Queue& queue, - const VkSubmitInfo& submit, - const Fence& fence) const noexcept - { - return vkQueueSubmit(queue, 1u, &submit, fence); - } - - template<size_t descriptorWriteCount, size_t descriptorCopyCount> - void updateDescriptorSets( - const Device& device, - std::array<VkWriteDescriptorSet, descriptorWriteCount> descriptorWrites, - std::array<VkCopyDescriptorSet, descriptorCopyCount> descriptorCopies) - const noexcept - { - vkUpdateDescriptorSets(device, - static_cast<uint32_t>(descriptorWrites.size()), - descriptorWrites.data(), - static_cast<uint32_t>(descriptorCopies.size()), - descriptorCopies.data()); - } - - VkResult resetFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkResetFences(device, 1u, &h); - } - - VkResult waitForFence(const Device& device, - const Fence& fence, - uint64_t timeout) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, timeout); - } - - VkResult - waitForFence(const Device& device, const Fence& fence) const noexcept - { - VkFence h = fence; - return vkWaitForFences(device, 1u, &h, VK_TRUE, UINT64_MAX); - } - - // Scoped command buffer interface - SYBOK_NODISCARD - CommandScope - beginCommandBuffer(VkCommandBuffer commandBuffer, - VkCommandBufferBeginInfo beginInfo) const noexcept; - - // VK_EXT_debug_report - - VkResult createDebugReportCallbackEXT( - const Instance& instance, - const VkDebugReportCallbackCreateInfoEXT& createInfo, - DebugReportCallbackEXT& callback) const noexcept - { - VkDebugReportCallbackEXT h = {}; - - if (const VkResult r = vkCreateDebugReportCallbackEXT( - instance, &createInfo, nullptr, &h)) { - return r; - } else if (!h) { - return VK_ERROR_FEATURE_NOT_PRESENT; - } - - callback = {h, {instance, vkDestroyDebugReportCallbackEXT}}; - return VK_SUCCESS; - } - - // VK_KHR_surface - - VkResult getPhysicalDeviceSurfaceCapabilitiesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - VkSurfaceCapabilitiesKHR& capabilities) const noexcept - { - return vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, - surface, - &capabilities); - } - - template<typename Vector> - VkResult - getPhysicalDeviceSurfaceFormatsKHR(const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& surfaceFormats) const noexcept - { - return detail::wrapVectorAccessor<VkSurfaceFormatKHR>( - surfaceFormats, - vkGetPhysicalDeviceSurfaceFormatsKHR, - physicalDevice, - surface.get()); - } - - template<typename Vector> - VkResult getPhysicalDeviceSurfacePresentModesKHR( - const PhysicalDevice& physicalDevice, - const SurfaceKHR& surface, - Vector& presentModes) const noexcept - { - return detail::wrapVectorAccessor<VkPresentModeKHR>( - presentModes, - vkGetPhysicalDeviceSurfacePresentModesKHR, - physicalDevice, - surface.get()); - } - - VkResult - getPhysicalDeviceSurfaceSupportKHR(const PhysicalDevice& physicalDevice, - uint32_t queueFamilyIndex, - const SurfaceKHR& surface, - bool& supported) const noexcept - { - VkBool32 s = {}; - - if (VkResult r = vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, queueFamilyIndex, surface, &s)) { - return r; - } - - supported = s; - return VK_SUCCESS; - } - - // VK_KHR_swapchain - - VkResult acquireNextImageKHR(const Device& device, - const SwapchainKHR& swapchain, - uint64_t timeout, - const Semaphore& semaphore, - const OptionalParameter<Fence>& fence, - uint32_t* pImageIndex) const noexcept - { - return vkAcquireNextImageKHR( - device, swapchain, timeout, semaphore, fence.get(), pImageIndex); - } - - template<class Vector> - VkResult getSwapchainImagesKHR(const Device& device, - const SwapchainKHR& swapchain, - Vector& images) const noexcept - { - return detail::wrapVectorAccessor<VkImage>(images, - vkGetSwapchainImagesKHR, - device.get(), - swapchain.get()); - } - - VkResult createSwapchainKHR(const Device& device, - const VkSwapchainCreateInfoKHR& createInfo, - SwapchainKHR& swapchain) const noexcept - { - VkSwapchainKHR h = {}; - const VkResult r = - vkCreateSwapchainKHR(device, &createInfo, nullptr, &h); - - if (r) { - return r; - } else if (!h) { - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - - swapchain = {h, {device, vkDestroySwapchainKHR}}; - return VK_SUCCESS; - } - - VkResult queuePresentKHR(const Queue& queue, - const VkPresentInfoKHR& presentInfo) const noexcept - { - return vkQueuePresentKHR(queue, &presentInfo); - } + return r; + } + + VkResult init(const VulkanInitApi& initApi, const Instance& instance) noexcept + { + return init(initApi, instance, [](const char*) {}); + } + + template<class VkCommandBufferVector> + VkResult allocateCommandBuffers( + const Device& device, + const VkCommandBufferAllocateInfo& allocateInfo, + CommandBuffers<VkCommandBufferVector>& commandBuffers) const noexcept + { + VkCommandBufferVector rawCommandBuffers = + VkCommandBufferVector(allocateInfo.commandBufferCount); + + if (const VkResult r = vkAllocateCommandBuffers( + device, &allocateInfo, rawCommandBuffers.data())) { + return r; + } + + commandBuffers = CommandBuffers<VkCommandBufferVector>{ + allocateInfo.commandBufferCount, + std::move(rawCommandBuffers), + PoolDeleter<VkCommandBuffer, VkCommandPool, void>{ + device, + allocateInfo.commandPool, + allocateInfo.commandBufferCount, + vkFreeCommandBuffers}}; + return VK_SUCCESS; + } + + template<class VkDescriptorSetVector> + VkResult allocateDescriptorSets( + const Device& device, + const VkDescriptorSetAllocateInfo& allocateInfo, + DescriptorSets<VkDescriptorSetVector>& descriptorSets) const noexcept + { + auto descriptorSetVector = + VkDescriptorSetVector(allocateInfo.descriptorSetCount); + + if (const VkResult r = vkAllocateDescriptorSets( + device, &allocateInfo, descriptorSetVector.data())) { + return r; + } + + descriptorSets = DescriptorSets<VkDescriptorSetVector>{ + allocateInfo.descriptorSetCount, + std::move(descriptorSetVector), + PoolDeleter<VkDescriptorSet, VkDescriptorPool, VkResult>{ + device, + allocateInfo.descriptorPool, + allocateInfo.descriptorSetCount, + vkFreeDescriptorSets}}; + return VK_SUCCESS; + } + + VkResult bindBufferMemory(const Device& device, + const Buffer& buffer, + const DeviceMemory& memory, + VkDeviceSize memoryOffset) const noexcept + { + return vkBindBufferMemory + ? vkBindBufferMemory(device, buffer, memory, memoryOffset) + : VK_ERROR_FEATURE_NOT_PRESENT; + } + + VkResult createBuffer(const Device& device, + const VkBufferCreateInfo& createInfo, + Buffer& buffer) const noexcept + { + VkBuffer h = {}; + const VkResult r = vkCreateBuffer(device, &createInfo, nullptr, &h); + return wrapResult(r, h, {device, vkDestroyBuffer}, buffer); + } + + VkResult createBufferView(const Device& device, + const VkBufferViewCreateInfo& createInfo, + BufferView& bufferView) const noexcept + { + VkBufferView h = {}; + const VkResult r = vkCreateBufferView(device, &createInfo, nullptr, &h); + return wrapResult(r, h, {device, vkDestroyBufferView}, bufferView); + } + + VkResult createCommandPool(const Device& device, + const VkCommandPoolCreateInfo& createInfo, + CommandPool& commandPool) const noexcept + { + VkCommandPool h = {}; + const VkResult r = vkCreateCommandPool(device, &createInfo, nullptr, &h); + return wrapResult(r, h, {device, vkDestroyCommandPool}, commandPool); + } + + VkResult createDescriptorPool(const Device& device, + const VkDescriptorPoolCreateInfo& createInfo, + DescriptorPool& descriptorPool) const noexcept + { + VkDescriptorPool h = {}; + const VkResult r = vkCreateDescriptorPool(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyDescriptorPool}, descriptorPool); + } + + VkResult createDescriptorSetLayout( + const Device& device, + const VkDescriptorSetLayoutCreateInfo& createInfo, + DescriptorSetLayout& descriptorSetLayout) const noexcept + { + VkDescriptorSetLayout h = {}; + const VkResult r = + vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &h); + + return wrapResult( + r, h, {device, vkDestroyDescriptorSetLayout}, descriptorSetLayout); + } + + VkResult createDevice(const PhysicalDevice& physicalDevice, + const VkDeviceCreateInfo& createInfo, + Device& result) const noexcept + { + VkDevice h = {}; + const VkResult r = vkCreateDevice(physicalDevice, &createInfo, nullptr, &h); + + return wrapResult(r, h, {vkDestroyDevice}, result); + } + + VkResult createEvent(const Device& device, + const VkEventCreateInfo& createInfo, + Event& event) const noexcept + { + VkEvent h = {}; + const VkResult r = vkCreateEvent(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyEvent}, event); + } + + VkResult createFence(const Device& device, + const VkFenceCreateInfo& createInfo, + Fence& fence) const noexcept + { + VkFence h = {}; + const VkResult r = vkCreateFence(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyFence}, fence); + } + + VkResult createFramebuffer(const Device& device, + const VkFramebufferCreateInfo& createInfo, + Framebuffer& framebuffer) const noexcept + { + VkFramebuffer h = {}; + const VkResult r = vkCreateFramebuffer(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyFramebuffer}, framebuffer); + } + + VkResult createImage(const Device& device, + const VkImageCreateInfo& createInfo, + Image& image) const noexcept + { + VkImage h = {}; + const VkResult r = vkCreateImage(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyImage}, image); + } + + VkResult createImageView(const Device& device, + const VkImageViewCreateInfo& createInfo, + ImageView& imageView) const noexcept + { + VkImageView h = {}; + const VkResult r = vkCreateImageView(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyImageView}, imageView); + } + + template<size_t count> + VkResult createGraphicsPipelines( + const Device& device, + const OptionalParameter<PipelineCache>& pipelineCache, + const std::array<VkGraphicsPipelineCreateInfo, count>& createInfos, + std::array<Pipeline, count>& pipelines) const noexcept + { + std::array<VkPipeline, count> pipelineHandles{}; + + if (const VkResult r = + vkCreateGraphicsPipelines(device, + pipelineCache.get(), + static_cast<uint32_t>(createInfos.size()), + createInfos.data(), + nullptr, + pipelineHandles.data())) { + return r; + } + + pipelines = make_handle_array<Pipeline>( + device.get(), vkDestroyPipeline, pipelineHandles); + return VK_SUCCESS; + } + + VkResult createPipelineCache(const Device& device, + const VkPipelineCacheCreateInfo& createInfo, + PipelineCache& pipelineCache) const noexcept + { + VkPipelineCache h = {}; + const VkResult r = vkCreatePipelineCache(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyPipelineCache}, pipelineCache); + } + + VkResult createPipelineLayout(const Device& device, + const VkPipelineLayoutCreateInfo& createInfo, + PipelineLayout& pipelineLayout) const noexcept + { + VkPipelineLayout h = {}; + const VkResult r = vkCreatePipelineLayout(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyPipelineLayout}, pipelineLayout); + } + + VkResult createQueryPool(const Device& device, + const VkQueryPoolCreateInfo& createInfo, + QueryPool& queryPool) const noexcept + { + VkQueryPool h = {}; + const VkResult r = vkCreateQueryPool(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyQueryPool}, queryPool); + } + + VkResult createRenderPass(const Device& device, + const VkRenderPassCreateInfo& createInfo, + RenderPass& renderPass) const noexcept + { + VkRenderPass h = {}; + const VkResult r = vkCreateRenderPass(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyRenderPass}, renderPass); + } + + VkResult createSampler(const Device& device, + const VkSamplerCreateInfo& createInfo, + Sampler& sampler) const noexcept + { + VkSampler h = {}; + const VkResult r = vkCreateSampler(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroySampler}, sampler); + } + + VkResult createSemaphore(const Device& device, + const VkSemaphoreCreateInfo& createInfo, + Semaphore& semaphore) const noexcept + { + VkSemaphore h = {}; + const VkResult r = vkCreateSemaphore(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroySemaphore}, semaphore); + } + + VkResult createShaderModule(const Device& device, + const VkShaderModuleCreateInfo& createInfo, + ShaderModule& shaderModule) const noexcept + { + VkShaderModule h = {}; + const VkResult r = vkCreateShaderModule(device, &createInfo, nullptr, &h); + + return wrapResult(r, h, {device, vkDestroyShaderModule}, shaderModule); + } + + VkResult deviceWaitIdle(const Device& device) const noexcept + { + return vkDeviceWaitIdle(device); + } + + template<class Vector> + VkResult enumerateDeviceExtensionProperties( + const PhysicalDevice& physicalDevice, + const char* const layerName, + Vector& properties) const noexcept + { + return detail::wrapVectorAccessor<VkExtensionProperties>( + properties, + vkEnumerateDeviceExtensionProperties, + physicalDevice, + layerName); + } + + template<class Vector> + VkResult enumerateDeviceExtensionProperties( + const PhysicalDevice& physicalDevice, + Vector& properties) const noexcept + { + return detail::wrapVectorAccessor<VkExtensionProperties>( + properties, + vkEnumerateDeviceExtensionProperties, + physicalDevice, + nullptr); + } + + template<class Vector> + VkResult enumeratePhysicalDevices(const Instance& instance, + Vector& physicalDevices) const noexcept + { + uint32_t count = 0u; + VkResult r = vkEnumeratePhysicalDevices(instance, &count, nullptr); + if (r > VK_INCOMPLETE) { + return r; + } + + physicalDevices = Vector(count); + if ((r = vkEnumeratePhysicalDevices( + instance, &count, physicalDevices.data()))) { + return r; + } + + return VK_SUCCESS; + } + + sk::Queue getDeviceQueue(const Device& device, + const uint32_t queueFamilyIndex, + const uint32_t queueIndex) const noexcept + { + VkQueue queue{}; + vkGetDeviceQueue(device, queueFamilyIndex, queueIndex, &queue); + return sk::Queue{queue}; + } + + VkPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties( + VkPhysicalDevice physicalDevice) const noexcept + { + VkPhysicalDeviceMemoryProperties properties{}; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); + return properties; + } + + VkPhysicalDeviceProperties getPhysicalDeviceProperties( + const PhysicalDevice& physicalDevice) const noexcept + { + VkPhysicalDeviceProperties properties{}; + vkGetPhysicalDeviceProperties(physicalDevice, &properties); + return properties; + } + + template<class Vector> + VkResult getPhysicalDeviceQueueFamilyProperties( + const PhysicalDevice& physicalDevice, + Vector& queueFamilyProperties) const noexcept + { + uint32_t count = 0u; + vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &count, nullptr); + + queueFamilyProperties = Vector(count); + vkGetPhysicalDeviceQueueFamilyProperties( + physicalDevice, &count, queueFamilyProperties.data()); + + return VK_SUCCESS; + } + + VkMemoryRequirements getBufferMemoryRequirements( + const Device& device, + const Buffer& buffer) const noexcept + { + VkMemoryRequirements requirements; + vkGetBufferMemoryRequirements(device, buffer, &requirements); + return requirements; + } + + VkResult allocateMemory(const Device& device, + const VkMemoryAllocateInfo& info, + DeviceMemory& memory) const noexcept + { + VkDeviceMemory h = {}; + if (const VkResult r = vkAllocateMemory(device, &info, nullptr, &h)) { + return r; + } else if (!h) { + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + + memory = DeviceMemory{h, {device, vkFreeMemory}}; + return VK_SUCCESS; + } + + VkResult mapMemory(const Device& device, + const DeviceMemory& memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + MappedMemory& mappedMemory) const noexcept + { + void* data = nullptr; + if (const VkResult r = + vkMapMemory(device, memory, offset, size, flags, &data)) { + return r; + } + + mappedMemory = MappedMemory{*this, device, memory, data}; + return VK_SUCCESS; + } + + VkResult queueSubmit(const Queue& queue, + uint32_t submitCount, + const VkSubmitInfo& submits, + const Fence& fence) const noexcept + { + return vkQueueSubmit(queue, submitCount, &submits, fence); + } + + VkResult queueSubmit(const Queue& queue, + const VkSubmitInfo& submit, + const Fence& fence) const noexcept + { + return vkQueueSubmit(queue, 1u, &submit, fence); + } + + template<size_t descriptorWriteCount, size_t descriptorCopyCount> + void updateDescriptorSets( + const Device& device, + std::array<VkWriteDescriptorSet, descriptorWriteCount> descriptorWrites, + std::array<VkCopyDescriptorSet, descriptorCopyCount> descriptorCopies) + const noexcept + { + vkUpdateDescriptorSets(device, + static_cast<uint32_t>(descriptorWrites.size()), + descriptorWrites.data(), + static_cast<uint32_t>(descriptorCopies.size()), + descriptorCopies.data()); + } + + VkResult resetFence(const Device& device, const Fence& fence) const noexcept + { + VkFence h = fence; + return vkResetFences(device, 1u, &h); + } + + VkResult waitForFence(const Device& device, + const Fence& fence, + uint64_t timeout) const noexcept + { + VkFence h = fence; + return vkWaitForFences(device, 1u, &h, VK_TRUE, timeout); + } + + VkResult waitForFence(const Device& device, const Fence& fence) const noexcept + { + VkFence h = fence; + return vkWaitForFences(device, 1u, &h, VK_TRUE, UINT64_MAX); + } + + // Scoped command buffer interface + SYBOK_NODISCARD + CommandScope beginCommandBuffer( + VkCommandBuffer commandBuffer, + VkCommandBufferBeginInfo beginInfo) const noexcept; + + // VK_EXT_debug_report + + VkResult createDebugReportCallbackEXT( + const Instance& instance, + const VkDebugReportCallbackCreateInfoEXT& createInfo, + DebugReportCallbackEXT& callback) const noexcept + { + VkDebugReportCallbackEXT h = {}; + + if (const VkResult r = + vkCreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &h)) { + return r; + } else if (!h) { + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + callback = {h, {instance, vkDestroyDebugReportCallbackEXT}}; + return VK_SUCCESS; + } + + // VK_KHR_surface + + VkResult getPhysicalDeviceSurfaceCapabilitiesKHR( + const PhysicalDevice& physicalDevice, + const SurfaceKHR& surface, + VkSurfaceCapabilitiesKHR& capabilities) const noexcept + { + return vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + physicalDevice, surface, &capabilities); + } + + template<typename Vector> + VkResult getPhysicalDeviceSurfaceFormatsKHR( + const PhysicalDevice& physicalDevice, + const SurfaceKHR& surface, + Vector& surfaceFormats) const noexcept + { + return detail::wrapVectorAccessor<VkSurfaceFormatKHR>( + surfaceFormats, + vkGetPhysicalDeviceSurfaceFormatsKHR, + physicalDevice, + surface.get()); + } + + template<typename Vector> + VkResult getPhysicalDeviceSurfacePresentModesKHR( + const PhysicalDevice& physicalDevice, + const SurfaceKHR& surface, + Vector& presentModes) const noexcept + { + return detail::wrapVectorAccessor<VkPresentModeKHR>( + presentModes, + vkGetPhysicalDeviceSurfacePresentModesKHR, + physicalDevice, + surface.get()); + } + + VkResult getPhysicalDeviceSurfaceSupportKHR( + const PhysicalDevice& physicalDevice, + uint32_t queueFamilyIndex, + const SurfaceKHR& surface, + bool& supported) const noexcept + { + VkBool32 s = {}; + + if (VkResult r = vkGetPhysicalDeviceSurfaceSupportKHR( + physicalDevice, queueFamilyIndex, surface, &s)) { + return r; + } + + supported = s; + return VK_SUCCESS; + } + + // VK_KHR_swapchain + + VkResult acquireNextImageKHR(const Device& device, + const SwapchainKHR& swapchain, + uint64_t timeout, + const Semaphore& semaphore, + const OptionalParameter<Fence>& fence, + uint32_t* pImageIndex) const noexcept + { + return vkAcquireNextImageKHR( + device, swapchain, timeout, semaphore, fence.get(), pImageIndex); + } + + template<class Vector> + VkResult getSwapchainImagesKHR(const Device& device, + const SwapchainKHR& swapchain, + Vector& images) const noexcept + { + return detail::wrapVectorAccessor<VkImage>( + images, vkGetSwapchainImagesKHR, device.get(), swapchain.get()); + } + + VkResult createSwapchainKHR(const Device& device, + const VkSwapchainCreateInfoKHR& createInfo, + SwapchainKHR& swapchain) const noexcept + { + VkSwapchainKHR h = {}; + const VkResult r = vkCreateSwapchainKHR(device, &createInfo, nullptr, &h); + + if (r) { + return r; + } else if (!h) { + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + + swapchain = {h, {device, vkDestroySwapchainKHR}}; + return VK_SUCCESS; + } + + VkResult queuePresentKHR(const Queue& queue, + const VkPresentInfoKHR& presentInfo) const noexcept + { + return vkQueuePresentKHR(queue, &presentInfo); + } #define SK_FUNC(name) \ - PFN_##name name {} // NOLINT - - // Vulkan 1.0 Core - SK_FUNC(vkAllocateCommandBuffers); - SK_FUNC(vkAllocateDescriptorSets); - SK_FUNC(vkAllocateMemory); - SK_FUNC(vkBeginCommandBuffer); - SK_FUNC(vkBindBufferMemory); - SK_FUNC(vkBindImageMemory); - SK_FUNC(vkCmdBeginQuery); - SK_FUNC(vkCmdBeginRenderPass); - SK_FUNC(vkCmdBindDescriptorSets); - SK_FUNC(vkCmdBindIndexBuffer); - SK_FUNC(vkCmdBindPipeline); - SK_FUNC(vkCmdBindVertexBuffers); - SK_FUNC(vkCmdBlitImage); - SK_FUNC(vkCmdClearAttachments); - SK_FUNC(vkCmdClearColorImage); - SK_FUNC(vkCmdClearDepthStencilImage); - SK_FUNC(vkCmdCopyBuffer); - SK_FUNC(vkCmdCopyBufferToImage); - SK_FUNC(vkCmdCopyImage); - SK_FUNC(vkCmdCopyImageToBuffer); - SK_FUNC(vkCmdCopyQueryPoolResults); - SK_FUNC(vkCmdDispatch); - SK_FUNC(vkCmdDispatchIndirect); - SK_FUNC(vkCmdDraw); - SK_FUNC(vkCmdDrawIndexed); - SK_FUNC(vkCmdDrawIndexedIndirect); - SK_FUNC(vkCmdDrawIndirect); - SK_FUNC(vkCmdEndQuery); - SK_FUNC(vkCmdEndRenderPass); - SK_FUNC(vkCmdExecuteCommands); - SK_FUNC(vkCmdFillBuffer); - SK_FUNC(vkCmdNextSubpass); - SK_FUNC(vkCmdPipelineBarrier); - SK_FUNC(vkCmdPushConstants); - SK_FUNC(vkCmdResetEvent); - SK_FUNC(vkCmdResetQueryPool); - SK_FUNC(vkCmdResolveImage); - SK_FUNC(vkCmdSetBlendConstants); - SK_FUNC(vkCmdSetDepthBias); - SK_FUNC(vkCmdSetDepthBounds); - SK_FUNC(vkCmdSetEvent); - SK_FUNC(vkCmdSetLineWidth); - SK_FUNC(vkCmdSetScissor); - SK_FUNC(vkCmdSetStencilCompareMask); - SK_FUNC(vkCmdSetStencilReference); - SK_FUNC(vkCmdSetStencilWriteMask); - SK_FUNC(vkCmdSetViewport); - SK_FUNC(vkCmdUpdateBuffer); - SK_FUNC(vkCmdWaitEvents); - SK_FUNC(vkCmdWriteTimestamp); - SK_FUNC(vkCreateBuffer); - SK_FUNC(vkCreateBufferView); - SK_FUNC(vkCreateCommandPool); - SK_FUNC(vkCreateComputePipelines); - SK_FUNC(vkCreateDescriptorPool); - SK_FUNC(vkCreateDescriptorSetLayout); - SK_FUNC(vkCreateDevice); - SK_FUNC(vkCreateEvent); - SK_FUNC(vkCreateFence); - SK_FUNC(vkCreateFramebuffer); - SK_FUNC(vkCreateGraphicsPipelines); - SK_FUNC(vkCreateImage); - SK_FUNC(vkCreateImageView); - SK_FUNC(vkCreateInstance); - SK_FUNC(vkCreatePipelineCache); - SK_FUNC(vkCreatePipelineLayout); - SK_FUNC(vkCreateQueryPool); - SK_FUNC(vkCreateRenderPass); - SK_FUNC(vkCreateSampler); - SK_FUNC(vkCreateSemaphore); - SK_FUNC(vkCreateShaderModule); - SK_FUNC(vkDestroyBuffer); - SK_FUNC(vkDestroyBufferView); - SK_FUNC(vkDestroyCommandPool); - SK_FUNC(vkDestroyDescriptorPool); - SK_FUNC(vkDestroyDescriptorSetLayout); - SK_FUNC(vkDestroyDevice); - SK_FUNC(vkDestroyEvent); - SK_FUNC(vkDestroyFence); - SK_FUNC(vkDestroyFramebuffer); - SK_FUNC(vkDestroyImage); - SK_FUNC(vkDestroyImageView); - SK_FUNC(vkDestroyPipeline); - SK_FUNC(vkDestroyPipelineCache); - SK_FUNC(vkDestroyPipelineLayout); - SK_FUNC(vkDestroyQueryPool); - SK_FUNC(vkDestroyRenderPass); - SK_FUNC(vkDestroySampler); - SK_FUNC(vkDestroySemaphore); - SK_FUNC(vkDestroyShaderModule); - SK_FUNC(vkDeviceWaitIdle); - SK_FUNC(vkEndCommandBuffer); - SK_FUNC(vkEnumerateDeviceExtensionProperties); - SK_FUNC(vkEnumerateDeviceLayerProperties); - SK_FUNC(vkEnumeratePhysicalDevices); - SK_FUNC(vkFlushMappedMemoryRanges); - SK_FUNC(vkFreeCommandBuffers); - SK_FUNC(vkFreeDescriptorSets); - SK_FUNC(vkFreeMemory); - SK_FUNC(vkGetBufferMemoryRequirements); - SK_FUNC(vkGetDeviceMemoryCommitment); - SK_FUNC(vkGetDeviceProcAddr); - SK_FUNC(vkGetDeviceQueue); - SK_FUNC(vkGetEventStatus); - SK_FUNC(vkGetFenceStatus); - SK_FUNC(vkGetImageMemoryRequirements); - SK_FUNC(vkGetImageSparseMemoryRequirements); - SK_FUNC(vkGetImageSubresourceLayout); - SK_FUNC(vkGetInstanceProcAddr); - SK_FUNC(vkGetPhysicalDeviceFeatures); - SK_FUNC(vkGetPhysicalDeviceFormatProperties); - SK_FUNC(vkGetPhysicalDeviceImageFormatProperties); - SK_FUNC(vkGetPhysicalDeviceMemoryProperties); - SK_FUNC(vkGetPhysicalDeviceProperties); - SK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties); - SK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties); - SK_FUNC(vkGetPipelineCacheData); - SK_FUNC(vkGetQueryPoolResults); - SK_FUNC(vkGetRenderAreaGranularity); - SK_FUNC(vkInvalidateMappedMemoryRanges); - SK_FUNC(vkMapMemory); - SK_FUNC(vkMergePipelineCaches); - SK_FUNC(vkQueueBindSparse); - SK_FUNC(vkQueueSubmit); - SK_FUNC(vkQueueWaitIdle); - SK_FUNC(vkResetCommandBuffer); - SK_FUNC(vkResetCommandPool); - SK_FUNC(vkResetDescriptorPool); - SK_FUNC(vkResetEvent); - SK_FUNC(vkResetFences); - SK_FUNC(vkSetEvent); - SK_FUNC(vkUnmapMemory); - SK_FUNC(vkUpdateDescriptorSets); - SK_FUNC(vkWaitForFences); - - // VK_EXT_debug_report - SK_FUNC(vkCreateDebugReportCallbackEXT); - SK_FUNC(vkDebugReportMessageEXT); - SK_FUNC(vkDestroyDebugReportCallbackEXT); - - // VK_KHR_surface - SK_FUNC(vkDestroySurfaceKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR); - SK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR); - - // VK_KHR_swapchain - SK_FUNC(vkAcquireNextImageKHR); - SK_FUNC(vkCreateSwapchainKHR); - SK_FUNC(vkDestroySwapchainKHR); - SK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR); - SK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR); - SK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR); - SK_FUNC(vkGetSwapchainImagesKHR); - SK_FUNC(vkQueuePresentKHR); + PFN_##name name {} // NOLINT + + // Vulkan 1.0 Core + SK_FUNC(vkAllocateCommandBuffers); + SK_FUNC(vkAllocateDescriptorSets); + SK_FUNC(vkAllocateMemory); + SK_FUNC(vkBeginCommandBuffer); + SK_FUNC(vkBindBufferMemory); + SK_FUNC(vkBindImageMemory); + SK_FUNC(vkCmdBeginQuery); + SK_FUNC(vkCmdBeginRenderPass); + SK_FUNC(vkCmdBindDescriptorSets); + SK_FUNC(vkCmdBindIndexBuffer); + SK_FUNC(vkCmdBindPipeline); + SK_FUNC(vkCmdBindVertexBuffers); + SK_FUNC(vkCmdBlitImage); + SK_FUNC(vkCmdClearAttachments); + SK_FUNC(vkCmdClearColorImage); + SK_FUNC(vkCmdClearDepthStencilImage); + SK_FUNC(vkCmdCopyBuffer); + SK_FUNC(vkCmdCopyBufferToImage); + SK_FUNC(vkCmdCopyImage); + SK_FUNC(vkCmdCopyImageToBuffer); + SK_FUNC(vkCmdCopyQueryPoolResults); + SK_FUNC(vkCmdDispatch); + SK_FUNC(vkCmdDispatchIndirect); + SK_FUNC(vkCmdDraw); + SK_FUNC(vkCmdDrawIndexed); + SK_FUNC(vkCmdDrawIndexedIndirect); + SK_FUNC(vkCmdDrawIndirect); + SK_FUNC(vkCmdEndQuery); + SK_FUNC(vkCmdEndRenderPass); + SK_FUNC(vkCmdExecuteCommands); + SK_FUNC(vkCmdFillBuffer); + SK_FUNC(vkCmdNextSubpass); + SK_FUNC(vkCmdPipelineBarrier); + SK_FUNC(vkCmdPushConstants); + SK_FUNC(vkCmdResetEvent); + SK_FUNC(vkCmdResetQueryPool); + SK_FUNC(vkCmdResolveImage); + SK_FUNC(vkCmdSetBlendConstants); + SK_FUNC(vkCmdSetDepthBias); + SK_FUNC(vkCmdSetDepthBounds); + SK_FUNC(vkCmdSetEvent); + SK_FUNC(vkCmdSetLineWidth); + SK_FUNC(vkCmdSetScissor); + SK_FUNC(vkCmdSetStencilCompareMask); + SK_FUNC(vkCmdSetStencilReference); + SK_FUNC(vkCmdSetStencilWriteMask); + SK_FUNC(vkCmdSetViewport); + SK_FUNC(vkCmdUpdateBuffer); + SK_FUNC(vkCmdWaitEvents); + SK_FUNC(vkCmdWriteTimestamp); + SK_FUNC(vkCreateBuffer); + SK_FUNC(vkCreateBufferView); + SK_FUNC(vkCreateCommandPool); + SK_FUNC(vkCreateComputePipelines); + SK_FUNC(vkCreateDescriptorPool); + SK_FUNC(vkCreateDescriptorSetLayout); + SK_FUNC(vkCreateDevice); + SK_FUNC(vkCreateEvent); + SK_FUNC(vkCreateFence); + SK_FUNC(vkCreateFramebuffer); + SK_FUNC(vkCreateGraphicsPipelines); + SK_FUNC(vkCreateImage); + SK_FUNC(vkCreateImageView); + SK_FUNC(vkCreateInstance); + SK_FUNC(vkCreatePipelineCache); + SK_FUNC(vkCreatePipelineLayout); + SK_FUNC(vkCreateQueryPool); + SK_FUNC(vkCreateRenderPass); + SK_FUNC(vkCreateSampler); + SK_FUNC(vkCreateSemaphore); + SK_FUNC(vkCreateShaderModule); + SK_FUNC(vkDestroyBuffer); + SK_FUNC(vkDestroyBufferView); + SK_FUNC(vkDestroyCommandPool); + SK_FUNC(vkDestroyDescriptorPool); + SK_FUNC(vkDestroyDescriptorSetLayout); + SK_FUNC(vkDestroyDevice); + SK_FUNC(vkDestroyEvent); + SK_FUNC(vkDestroyFence); + SK_FUNC(vkDestroyFramebuffer); + SK_FUNC(vkDestroyImage); + SK_FUNC(vkDestroyImageView); + SK_FUNC(vkDestroyPipeline); + SK_FUNC(vkDestroyPipelineCache); + SK_FUNC(vkDestroyPipelineLayout); + SK_FUNC(vkDestroyQueryPool); + SK_FUNC(vkDestroyRenderPass); + SK_FUNC(vkDestroySampler); + SK_FUNC(vkDestroySemaphore); + SK_FUNC(vkDestroyShaderModule); + SK_FUNC(vkDeviceWaitIdle); + SK_FUNC(vkEndCommandBuffer); + SK_FUNC(vkEnumerateDeviceExtensionProperties); + SK_FUNC(vkEnumerateDeviceLayerProperties); + SK_FUNC(vkEnumeratePhysicalDevices); + SK_FUNC(vkFlushMappedMemoryRanges); + SK_FUNC(vkFreeCommandBuffers); + SK_FUNC(vkFreeDescriptorSets); + SK_FUNC(vkFreeMemory); + SK_FUNC(vkGetBufferMemoryRequirements); + SK_FUNC(vkGetDeviceMemoryCommitment); + SK_FUNC(vkGetDeviceProcAddr); + SK_FUNC(vkGetDeviceQueue); + SK_FUNC(vkGetEventStatus); + SK_FUNC(vkGetFenceStatus); + SK_FUNC(vkGetImageMemoryRequirements); + SK_FUNC(vkGetImageSparseMemoryRequirements); + SK_FUNC(vkGetImageSubresourceLayout); + SK_FUNC(vkGetInstanceProcAddr); + SK_FUNC(vkGetPhysicalDeviceFeatures); + SK_FUNC(vkGetPhysicalDeviceFormatProperties); + SK_FUNC(vkGetPhysicalDeviceImageFormatProperties); + SK_FUNC(vkGetPhysicalDeviceMemoryProperties); + SK_FUNC(vkGetPhysicalDeviceProperties); + SK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties); + SK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties); + SK_FUNC(vkGetPipelineCacheData); + SK_FUNC(vkGetQueryPoolResults); + SK_FUNC(vkGetRenderAreaGranularity); + SK_FUNC(vkInvalidateMappedMemoryRanges); + SK_FUNC(vkMapMemory); + SK_FUNC(vkMergePipelineCaches); + SK_FUNC(vkQueueBindSparse); + SK_FUNC(vkQueueSubmit); + SK_FUNC(vkQueueWaitIdle); + SK_FUNC(vkResetCommandBuffer); + SK_FUNC(vkResetCommandPool); + SK_FUNC(vkResetDescriptorPool); + SK_FUNC(vkResetEvent); + SK_FUNC(vkResetFences); + SK_FUNC(vkSetEvent); + SK_FUNC(vkUnmapMemory); + SK_FUNC(vkUpdateDescriptorSets); + SK_FUNC(vkWaitForFences); + + // VK_EXT_debug_report + SK_FUNC(vkCreateDebugReportCallbackEXT); + SK_FUNC(vkDebugReportMessageEXT); + SK_FUNC(vkDestroyDebugReportCallbackEXT); + + // VK_KHR_surface + SK_FUNC(vkDestroySurfaceKHR); + SK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + SK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR); + SK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR); + SK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR); + + // VK_KHR_swapchain + SK_FUNC(vkAcquireNextImageKHR); + SK_FUNC(vkCreateSwapchainKHR); + SK_FUNC(vkDestroySwapchainKHR); + SK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR); + SK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR); + SK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR); + SK_FUNC(vkGetSwapchainImagesKHR); + SK_FUNC(vkQueuePresentKHR); #undef SK_FUNC private: - template<class T> - static inline VkResult wrapResult(const VkResult r, - const typename T::Handle handle, - typename T::Deleter&& deleter, - T& result) noexcept - { - if (r) { - return r; - } else if (!handle) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - result = T{handle, std::move(deleter)}; - return VK_SUCCESS; - } + template<class T> + static inline VkResult wrapResult(const VkResult r, + const typename T::Handle handle, + typename T::Deleter&& deleter, + T& result) noexcept + { + if (r) { + return r; + } else if (!handle) { + return VK_ERROR_INITIALIZATION_FAILED; + } + + result = T{handle, std::move(deleter)}; + return VK_SUCCESS; + } }; /// Scope for commands that work both inside and outside a render pass class CommonCommandScope { public: - CommonCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : _api{api} - , _commandBuffer{commandBuffer} - , _result{result} - {} - - CommonCommandScope(const CommonCommandScope&) noexcept = delete; - CommonCommandScope& operator=(const CommonCommandScope&) noexcept = delete; - - CommonCommandScope(CommonCommandScope&& scope) noexcept - : _api{scope._api} - , _commandBuffer{scope._commandBuffer} - { - scope._commandBuffer = {}; - } - - CommonCommandScope& operator=(CommonCommandScope&&) = delete; - - ~CommonCommandScope() noexcept = default; - - explicit operator bool() const noexcept { return _result == VK_SUCCESS; } - - VkResult error() const noexcept { return _result; } - - void bindPipeline(VkPipelineBindPoint pipelineBindPoint, - VkPipeline pipeline) const noexcept - { - _api.vkCmdBindPipeline(_commandBuffer, pipelineBindPoint, pipeline); - } - - void setViewport(uint32_t firstViewport, - uint32_t viewportCount, - const VkViewport* pViewports) const noexcept - { - _api.vkCmdSetViewport(_commandBuffer, - firstViewport, - viewportCount, - pViewports); - } - - void setScissor(uint32_t firstScissor, - uint32_t scissorCount, - const VkRect2D* pScissors) const noexcept - { - _api.vkCmdSetScissor(_commandBuffer, - firstScissor, - scissorCount, - pScissors); - } - - void setLineWidth(float lineWidth) const noexcept - { - _api.vkCmdSetLineWidth(_commandBuffer, lineWidth); - } - - void setDepthBias(float depthBiasConstantFactor, - float depthBiasClamp, - float depthBiasSlopeFactor) const noexcept - { - _api.vkCmdSetDepthBias(_commandBuffer, - depthBiasConstantFactor, - depthBiasClamp, - depthBiasSlopeFactor); - } - - void setBlendConstants(const float blendConstants[4]) const noexcept - { - _api.vkCmdSetBlendConstants(_commandBuffer, blendConstants); - } - - void - setDepthBounds(float minDepthBounds, float maxDepthBounds) const noexcept - { - _api.vkCmdSetDepthBounds(_commandBuffer, - minDepthBounds, - maxDepthBounds); - } - - void setStencilCompareMask(VkStencilFaceFlags faceMask, - uint32_t compareMask) const noexcept - { - _api.vkCmdSetStencilCompareMask(_commandBuffer, faceMask, compareMask); - } - - void setStencilWriteMask(VkStencilFaceFlags faceMask, - uint32_t writeMask) const noexcept - { - _api.vkCmdSetStencilWriteMask(_commandBuffer, faceMask, writeMask); - } - - void setStencilReference(VkStencilFaceFlags faceMask, - uint32_t reference) const noexcept - { - _api.vkCmdSetStencilReference(_commandBuffer, faceMask, reference); - } - - void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, - VkPipelineLayout layout, - uint32_t firstSet, - uint32_t descriptorSetCount, - const VkDescriptorSet* pDescriptorSets, - uint32_t dynamicOffsetCount, - const uint32_t* pDynamicOffsets) const noexcept - { - _api.vkCmdBindDescriptorSets(_commandBuffer, - pipelineBindPoint, - layout, - firstSet, - descriptorSetCount, - pDescriptorSets, - dynamicOffsetCount, - pDynamicOffsets); - } - - void bindIndexBuffer(VkBuffer buffer, - VkDeviceSize offset, - VkIndexType indexType) const noexcept - { - _api.vkCmdBindIndexBuffer(_commandBuffer, buffer, offset, indexType); - } - - void bindVertexBuffers(uint32_t firstBinding, - uint32_t bindingCount, - const VkBuffer* pBuffers, - const VkDeviceSize* pOffsets) const noexcept - { - _api.vkCmdBindVertexBuffers( - _commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); - } - - void - waitEvents(uint32_t eventCount, - const VkEvent* pEvents, - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdWaitEvents(_commandBuffer, - eventCount, - pEvents, - srcStageMask, - dstStageMask, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void pipelineBarrier( - VkPipelineStageFlags srcStageMask, - VkPipelineStageFlags dstStageMask, - VkDependencyFlags dependencyFlags, - uint32_t memoryBarrierCount, - const VkMemoryBarrier* pMemoryBarriers, - uint32_t bufferMemoryBarrierCount, - const VkBufferMemoryBarrier* pBufferMemoryBarriers, - uint32_t imageMemoryBarrierCount, - const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept - { - _api.vkCmdPipelineBarrier(_commandBuffer, - srcStageMask, - dstStageMask, - dependencyFlags, - memoryBarrierCount, - pMemoryBarriers, - bufferMemoryBarrierCount, - pBufferMemoryBarriers, - imageMemoryBarrierCount, - pImageMemoryBarriers); - } - - void beginQuery(VkQueryPool queryPool, - uint32_t query, - VkQueryControlFlags flags) const noexcept - { - _api.vkCmdBeginQuery(_commandBuffer, queryPool, query, flags); - } - - void endQuery(VkQueryPool queryPool, uint32_t query) const noexcept - { - _api.vkCmdEndQuery(_commandBuffer, queryPool, query); - } - - void writeTimestamp(VkPipelineStageFlagBits pipelineStage, - VkQueryPool queryPool, - uint32_t query) const noexcept - { - _api.vkCmdWriteTimestamp(_commandBuffer, - pipelineStage, - queryPool, - query); - } - - void pushConstants(VkPipelineLayout layout, - VkShaderStageFlags stageFlags, - uint32_t offset, - uint32_t size, - const void* pValues) const noexcept - { - _api.vkCmdPushConstants( - _commandBuffer, layout, stageFlags, offset, size, pValues); - } - - void executeCommands(uint32_t commandBufferCount, - const VkCommandBuffer* pCommandBuffers) const noexcept - { - _api.vkCmdExecuteCommands(_commandBuffer, - commandBufferCount, - pCommandBuffers); - } + CommonCommandScope(const VulkanApi& api, + VkCommandBuffer commandBuffer, + VkResult result) noexcept + : _api{api} + , _commandBuffer{commandBuffer} + , _result{result} + {} + + CommonCommandScope(const CommonCommandScope&) noexcept = delete; + CommonCommandScope& operator=(const CommonCommandScope&) noexcept = delete; + + CommonCommandScope(CommonCommandScope&& scope) noexcept + : _api{scope._api} + , _commandBuffer{scope._commandBuffer} + { + scope._commandBuffer = {}; + } + + CommonCommandScope& operator=(CommonCommandScope&&) = delete; + + ~CommonCommandScope() noexcept = default; + + explicit operator bool() const noexcept { return _result == VK_SUCCESS; } + + VkResult error() const noexcept { return _result; } + + void bindPipeline(VkPipelineBindPoint pipelineBindPoint, + VkPipeline pipeline) const noexcept + { + _api.vkCmdBindPipeline(_commandBuffer, pipelineBindPoint, pipeline); + } + + void setViewport(uint32_t firstViewport, + uint32_t viewportCount, + const VkViewport* pViewports) const noexcept + { + _api.vkCmdSetViewport( + _commandBuffer, firstViewport, viewportCount, pViewports); + } + + void setScissor(uint32_t firstScissor, + uint32_t scissorCount, + const VkRect2D* pScissors) const noexcept + { + _api.vkCmdSetScissor(_commandBuffer, firstScissor, scissorCount, pScissors); + } + + void setLineWidth(float lineWidth) const noexcept + { + _api.vkCmdSetLineWidth(_commandBuffer, lineWidth); + } + + void setDepthBias(float depthBiasConstantFactor, + float depthBiasClamp, + float depthBiasSlopeFactor) const noexcept + { + _api.vkCmdSetDepthBias(_commandBuffer, + depthBiasConstantFactor, + depthBiasClamp, + depthBiasSlopeFactor); + } + + void setBlendConstants(const float blendConstants[4]) const noexcept + { + _api.vkCmdSetBlendConstants(_commandBuffer, blendConstants); + } + + void setDepthBounds(float minDepthBounds, float maxDepthBounds) const noexcept + { + _api.vkCmdSetDepthBounds(_commandBuffer, minDepthBounds, maxDepthBounds); + } + + void setStencilCompareMask(VkStencilFaceFlags faceMask, + uint32_t compareMask) const noexcept + { + _api.vkCmdSetStencilCompareMask(_commandBuffer, faceMask, compareMask); + } + + void setStencilWriteMask(VkStencilFaceFlags faceMask, + uint32_t writeMask) const noexcept + { + _api.vkCmdSetStencilWriteMask(_commandBuffer, faceMask, writeMask); + } + + void setStencilReference(VkStencilFaceFlags faceMask, + uint32_t reference) const noexcept + { + _api.vkCmdSetStencilReference(_commandBuffer, faceMask, reference); + } + + void bindDescriptorSets(VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t* pDynamicOffsets) const noexcept + { + _api.vkCmdBindDescriptorSets(_commandBuffer, + pipelineBindPoint, + layout, + firstSet, + descriptorSetCount, + pDescriptorSets, + dynamicOffsetCount, + pDynamicOffsets); + } + + void bindIndexBuffer(VkBuffer buffer, + VkDeviceSize offset, + VkIndexType indexType) const noexcept + { + _api.vkCmdBindIndexBuffer(_commandBuffer, buffer, offset, indexType); + } + + void bindVertexBuffers(uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets) const noexcept + { + _api.vkCmdBindVertexBuffers( + _commandBuffer, firstBinding, bindingCount, pBuffers, pOffsets); + } + + void waitEvents( + uint32_t eventCount, + const VkEvent* pEvents, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept + { + _api.vkCmdWaitEvents(_commandBuffer, + eventCount, + pEvents, + srcStageMask, + dstStageMask, + memoryBarrierCount, + pMemoryBarriers, + bufferMemoryBarrierCount, + pBufferMemoryBarriers, + imageMemoryBarrierCount, + pImageMemoryBarriers); + } + + void pipelineBarrier( + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) const noexcept + { + _api.vkCmdPipelineBarrier(_commandBuffer, + srcStageMask, + dstStageMask, + dependencyFlags, + memoryBarrierCount, + pMemoryBarriers, + bufferMemoryBarrierCount, + pBufferMemoryBarriers, + imageMemoryBarrierCount, + pImageMemoryBarriers); + } + + void beginQuery(VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags) const noexcept + { + _api.vkCmdBeginQuery(_commandBuffer, queryPool, query, flags); + } + + void endQuery(VkQueryPool queryPool, uint32_t query) const noexcept + { + _api.vkCmdEndQuery(_commandBuffer, queryPool, query); + } + + void writeTimestamp(VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, + uint32_t query) const noexcept + { + _api.vkCmdWriteTimestamp(_commandBuffer, pipelineStage, queryPool, query); + } + + void pushConstants(VkPipelineLayout layout, + VkShaderStageFlags stageFlags, + uint32_t offset, + uint32_t size, + const void* pValues) const noexcept + { + _api.vkCmdPushConstants( + _commandBuffer, layout, stageFlags, offset, size, pValues); + } + + void executeCommands(uint32_t commandBufferCount, + const VkCommandBuffer* pCommandBuffers) const noexcept + { + _api.vkCmdExecuteCommands( + _commandBuffer, commandBufferCount, pCommandBuffers); + } protected: - const VulkanApi& _api; - VkCommandBuffer _commandBuffer; - VkResult _result; + const VulkanApi& _api; + VkCommandBuffer _commandBuffer; + VkResult _result; }; // Top level command scope outside a render pass class CommandScope : public CommonCommandScope { public: - CommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer, - VkResult result) noexcept - : CommonCommandScope{api, commandBuffer, result} - {} - - CommandScope(const CommandScope&) = delete; - CommandScope& operator=(const CommandScope&) = delete; - - CommandScope(CommandScope&& scope) noexcept - : CommonCommandScope{std::forward<CommandScope>(scope)} - {} - - CommandScope& operator=(CommandScope&&) = delete; - - ~CommandScope() noexcept - { - assert(!_commandBuffer); // Buffer must be finished with end() - } - - VkResult end() noexcept - { - if (_commandBuffer) { - VkResult r = _api.vkEndCommandBuffer(_commandBuffer); - _commandBuffer = {}; - return r; - } - - return VK_NOT_READY; - } - - void dispatch(uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) const noexcept - { - _api.vkCmdDispatch(_commandBuffer, - groupCountX, - groupCountY, - groupCountZ); - } - - void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) const noexcept - { - _api.vkCmdDispatchIndirect(_commandBuffer, buffer, offset); - } - - void copyBuffer(VkBuffer srcBuffer, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferCopy* pRegions) const noexcept - { - _api.vkCmdCopyBuffer( - _commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); - } - - void copyImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void blitImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageBlit* pRegions, - VkFilter filter) const noexcept - { - _api.vkCmdBlitImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions, - filter); - } - - void copyBufferToImage(VkBuffer srcBuffer, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyBufferToImage(_commandBuffer, - srcBuffer, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void copyImageToBuffer(VkImage srcImage, - VkImageLayout srcImageLayout, - VkBuffer dstBuffer, - uint32_t regionCount, - const VkBufferImageCopy* pRegions) const noexcept - { - _api.vkCmdCopyImageToBuffer(_commandBuffer, - srcImage, - srcImageLayout, - dstBuffer, - regionCount, - pRegions); - } - - void updateBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize dataSize, - const void* pData) const noexcept - { - _api.vkCmdUpdateBuffer( - _commandBuffer, dstBuffer, dstOffset, dataSize, pData); - } - - void fillBuffer(VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize size, - uint32_t data) const noexcept - { - _api.vkCmdFillBuffer(_commandBuffer, dstBuffer, dstOffset, size, data); - } - - void clearColorImage(VkImage image, - VkImageLayout imageLayout, - const VkClearColorValue& color, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearColorImage( - _commandBuffer, image, imageLayout, &color, rangeCount, pRanges); - } - - void clearDepthStencilImage( - VkImage image, - VkImageLayout imageLayout, - const VkClearDepthStencilValue& depthStencil, - uint32_t rangeCount, - const VkImageSubresourceRange* pRanges) const noexcept - { - _api.vkCmdClearDepthStencilImage(_commandBuffer, - image, - imageLayout, - &depthStencil, - rangeCount, - pRanges); - } - - void resolveImage(VkImage srcImage, - VkImageLayout srcImageLayout, - VkImage dstImage, - VkImageLayout dstImageLayout, - uint32_t regionCount, - const VkImageResolve* pRegions) const noexcept - { - _api.vkCmdResolveImage(_commandBuffer, - srcImage, - srcImageLayout, - dstImage, - dstImageLayout, - regionCount, - pRegions); - } - - void setEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdSetEvent(_commandBuffer, event, stageMask); - } - - void - resetEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept - { - _api.vkCmdResetEvent(_commandBuffer, event, stageMask); - } - - void resetQueryPool(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount) const noexcept - { - _api.vkCmdResetQueryPool(_commandBuffer, - queryPool, - firstQuery, - queryCount); - } - - void copyQueryPoolResults(VkQueryPool queryPool, - uint32_t firstQuery, - uint32_t queryCount, - VkBuffer dstBuffer, - VkDeviceSize dstOffset, - VkDeviceSize stride, - VkQueryResultFlags flags) const noexcept - { - _api.vkCmdCopyQueryPoolResults(_commandBuffer, - queryPool, - firstQuery, - queryCount, - dstBuffer, - dstOffset, - stride, - flags); - } - - SYBOK_NODISCARD - RenderCommandScope - beginRenderPass(const VkRenderPassBeginInfo& renderPassBegin, - VkSubpassContents contents) const noexcept; + CommandScope(const VulkanApi& api, + VkCommandBuffer commandBuffer, + VkResult result) noexcept + : CommonCommandScope{api, commandBuffer, result} + {} + + CommandScope(const CommandScope&) = delete; + CommandScope& operator=(const CommandScope&) = delete; + + CommandScope(CommandScope&& scope) noexcept + : CommonCommandScope{std::forward<CommandScope>(scope)} + {} + + CommandScope& operator=(CommandScope&&) = delete; + + ~CommandScope() noexcept + { + assert(!_commandBuffer); // Buffer must be finished with end() + } + + VkResult end() noexcept + { + if (_commandBuffer) { + VkResult r = _api.vkEndCommandBuffer(_commandBuffer); + _commandBuffer = {}; + return r; + } + + return VK_NOT_READY; + } + + void dispatch(uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) const noexcept + { + _api.vkCmdDispatch(_commandBuffer, groupCountX, groupCountY, groupCountZ); + } + + void dispatchIndirect(VkBuffer buffer, VkDeviceSize offset) const noexcept + { + _api.vkCmdDispatchIndirect(_commandBuffer, buffer, offset); + } + + void copyBuffer(VkBuffer srcBuffer, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferCopy* pRegions) const noexcept + { + _api.vkCmdCopyBuffer( + _commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); + } + + void copyImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageCopy* pRegions) const noexcept + { + _api.vkCmdCopyImage(_commandBuffer, + srcImage, + srcImageLayout, + dstImage, + dstImageLayout, + regionCount, + pRegions); + } + + void blitImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageBlit* pRegions, + VkFilter filter) const noexcept + { + _api.vkCmdBlitImage(_commandBuffer, + srcImage, + srcImageLayout, + dstImage, + dstImageLayout, + regionCount, + pRegions, + filter); + } + + void copyBufferToImage(VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) const noexcept + { + _api.vkCmdCopyBufferToImage(_commandBuffer, + srcBuffer, + dstImage, + dstImageLayout, + regionCount, + pRegions); + } + + void copyImageToBuffer(VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) const noexcept + { + _api.vkCmdCopyImageToBuffer(_commandBuffer, + srcImage, + srcImageLayout, + dstBuffer, + regionCount, + pRegions); + } + + void updateBuffer(VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize dataSize, + const void* pData) const noexcept + { + _api.vkCmdUpdateBuffer( + _commandBuffer, dstBuffer, dstOffset, dataSize, pData); + } + + void fillBuffer(VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize size, + uint32_t data) const noexcept + { + _api.vkCmdFillBuffer(_commandBuffer, dstBuffer, dstOffset, size, data); + } + + void clearColorImage(VkImage image, + VkImageLayout imageLayout, + const VkClearColorValue& color, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges) const noexcept + { + _api.vkCmdClearColorImage( + _commandBuffer, image, imageLayout, &color, rangeCount, pRanges); + } + + void clearDepthStencilImage( + VkImage image, + VkImageLayout imageLayout, + const VkClearDepthStencilValue& depthStencil, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges) const noexcept + { + _api.vkCmdClearDepthStencilImage( + _commandBuffer, image, imageLayout, &depthStencil, rangeCount, pRanges); + } + + void resolveImage(VkImage srcImage, + VkImageLayout srcImageLayout, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkImageResolve* pRegions) const noexcept + { + _api.vkCmdResolveImage(_commandBuffer, + srcImage, + srcImageLayout, + dstImage, + dstImageLayout, + regionCount, + pRegions); + } + + void setEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept + { + _api.vkCmdSetEvent(_commandBuffer, event, stageMask); + } + + void resetEvent(VkEvent event, VkPipelineStageFlags stageMask) const noexcept + { + _api.vkCmdResetEvent(_commandBuffer, event, stageMask); + } + + void resetQueryPool(VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount) const noexcept + { + _api.vkCmdResetQueryPool(_commandBuffer, queryPool, firstQuery, queryCount); + } + + void copyQueryPoolResults(VkQueryPool queryPool, + uint32_t firstQuery, + uint32_t queryCount, + VkBuffer dstBuffer, + VkDeviceSize dstOffset, + VkDeviceSize stride, + VkQueryResultFlags flags) const noexcept + { + _api.vkCmdCopyQueryPoolResults(_commandBuffer, + queryPool, + firstQuery, + queryCount, + dstBuffer, + dstOffset, + stride, + flags); + } + + SYBOK_NODISCARD + RenderCommandScope beginRenderPass( + const VkRenderPassBeginInfo& renderPassBegin, + VkSubpassContents contents) const noexcept; }; class RenderCommandScope : public CommonCommandScope { public: - RenderCommandScope(const VulkanApi& api, - VkCommandBuffer commandBuffer) noexcept - : CommonCommandScope{api, commandBuffer, VK_SUCCESS} - {} - - RenderCommandScope(const RenderCommandScope&) = delete; - RenderCommandScope& operator=(const RenderCommandScope&) = delete; - - RenderCommandScope(RenderCommandScope&& scope) noexcept - : CommonCommandScope{std::forward<RenderCommandScope>(scope)} - {} - - RenderCommandScope& operator=(RenderCommandScope&&) = delete; - - ~RenderCommandScope() noexcept { _api.vkCmdEndRenderPass(_commandBuffer); } - - void draw(uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDraw(_commandBuffer, - vertexCount, - instanceCount, - firstVertex, - firstInstance); - } - - void drawIndexed(uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) const noexcept - { - _api.vkCmdDrawIndexed(_commandBuffer, - indexCount, - instanceCount, - firstIndex, - vertexOffset, - firstInstance); - } - - void drawIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndirect( - _commandBuffer, buffer, offset, drawCount, stride); - } - - void drawIndexedIndirect(VkBuffer buffer, - VkDeviceSize offset, - uint32_t drawCount, - uint32_t stride) const noexcept - { - _api.vkCmdDrawIndexedIndirect( - _commandBuffer, buffer, offset, drawCount, stride); - } - - void clearAttachments(uint32_t attachmentCount, - const VkClearAttachment& attachments, - uint32_t rectCount, - const VkClearRect* pRects) const noexcept - { - _api.vkCmdClearAttachments( - _commandBuffer, attachmentCount, &attachments, rectCount, pRects); - } - - void nextSubpass(VkSubpassContents contents) const noexcept - { - _api.vkCmdNextSubpass(_commandBuffer, contents); - } + RenderCommandScope(const VulkanApi& api, + VkCommandBuffer commandBuffer) noexcept + : CommonCommandScope{api, commandBuffer, VK_SUCCESS} + {} + + RenderCommandScope(const RenderCommandScope&) = delete; + RenderCommandScope& operator=(const RenderCommandScope&) = delete; + + RenderCommandScope(RenderCommandScope&& scope) noexcept + : CommonCommandScope{std::forward<RenderCommandScope>(scope)} + {} + + RenderCommandScope& operator=(RenderCommandScope&&) = delete; + + ~RenderCommandScope() noexcept { _api.vkCmdEndRenderPass(_commandBuffer); } + + void draw(uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) const noexcept + { + _api.vkCmdDraw( + _commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance); + } + + void drawIndexed(uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) const noexcept + { + _api.vkCmdDrawIndexed(_commandBuffer, + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); + } + + void drawIndirect(VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride) const noexcept + { + _api.vkCmdDrawIndirect(_commandBuffer, buffer, offset, drawCount, stride); + } + + void drawIndexedIndirect(VkBuffer buffer, + VkDeviceSize offset, + uint32_t drawCount, + uint32_t stride) const noexcept + { + _api.vkCmdDrawIndexedIndirect( + _commandBuffer, buffer, offset, drawCount, stride); + } + + void clearAttachments(uint32_t attachmentCount, + const VkClearAttachment& attachments, + uint32_t rectCount, + const VkClearRect* pRects) const noexcept + { + _api.vkCmdClearAttachments( + _commandBuffer, attachmentCount, &attachments, rectCount, pRects); + } + + void nextSubpass(VkSubpassContents contents) const noexcept + { + _api.vkCmdNextSubpass(_commandBuffer, contents); + } }; CommandScope VulkanApi::beginCommandBuffer( - VkCommandBuffer commandBuffer, - const VkCommandBufferBeginInfo beginInfo) const noexcept + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo beginInfo) const noexcept { - if (const VkResult r = vkBeginCommandBuffer(commandBuffer, &beginInfo)) { - return {*this, nullptr, r}; - } + if (const VkResult r = vkBeginCommandBuffer(commandBuffer, &beginInfo)) { + return {*this, nullptr, r}; + } - return {*this, commandBuffer, VK_SUCCESS}; + return {*this, commandBuffer, VK_SUCCESS}; } inline RenderCommandScope CommandScope::beginRenderPass(const VkRenderPassBeginInfo& renderPassBegin, VkSubpassContents contents) const noexcept { - _api.vkCmdBeginRenderPass(_commandBuffer, &renderPassBegin, contents); + _api.vkCmdBeginRenderPass(_commandBuffer, &renderPassBegin, contents); - return {_api, _commandBuffer}; + return {_api, _commandBuffer}; } inline MappedMemory::~MappedMemory() noexcept { - if (_api && _memory) { - _api->vkUnmapMemory(_device, _memory); - } + if (_api && _memory) { + _api->vkUnmapMemory(_device, _memory); + } } } // namespace sk diff --git a/include/pugl/cairo.h b/include/pugl/cairo.h index d72580d..9909682 100644 --- a/include/pugl/cairo.h +++ b/include/pugl/cairo.h @@ -33,7 +33,9 @@ PUGL_BEGIN_DECLS Pass the returned value to puglSetBackend() to draw to a view with Cairo. */ -PUGL_API PUGL_CONST_FUNC const PuglBackend* +PUGL_API +PUGL_CONST_FUNC +const PuglBackend* puglCairoBackend(void); /** diff --git a/include/pugl/gl.h b/include/pugl/gl.h index eb86c3d..a311416 100644 --- a/include/pugl/gl.h +++ b/include/pugl/gl.h @@ -25,25 +25,25 @@ enable pure portable programs. */ #ifndef PUGL_NO_INCLUDE_GL_H -# ifdef __APPLE__ -# include "OpenGL/gl.h" -# else -# ifdef _WIN32 -# include <windows.h> -# endif -# include "GL/gl.h" -# endif +# ifdef __APPLE__ +# include "OpenGL/gl.h" +# else +# ifdef _WIN32 +# include <windows.h> +# endif +# include "GL/gl.h" +# endif #endif #ifndef PUGL_NO_INCLUDE_GLU_H -# ifdef __APPLE__ -# include "OpenGL/glu.h" -# else -# ifdef _WIN32 -# include <windows.h> -# endif -# include "GL/glu.h" -# endif +# ifdef __APPLE__ +# include "OpenGL/glu.h" +# else +# ifdef _WIN32 +# include <windows.h> +# endif +# include "GL/glu.h" +# endif #endif // IWYU pragma: end_exports @@ -65,7 +65,8 @@ typedef void (*PuglGlFunc)(void); /** Return the address of an OpenGL extension function. */ -PUGL_API PuglGlFunc +PUGL_API +PuglGlFunc puglGetProcAddress(const char* name); /** @@ -75,7 +76,8 @@ puglGetProcAddress(const char* name); doing things like loading textures. Note that this must not be used for drawing, which may only be done while processing an expose event. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglEnterContext(PuglView* view); /** @@ -83,7 +85,8 @@ puglEnterContext(PuglView* view); This must only be called after puglEnterContext(). */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglLeaveContext(PuglView* view); /** @@ -91,7 +94,9 @@ puglLeaveContext(PuglView* view); Pass the returned value to puglSetBackend() to draw to a view with OpenGL. */ -PUGL_API PUGL_CONST_FUNC const PuglBackend* +PUGL_API +PUGL_CONST_FUNC +const PuglBackend* puglGlBackend(void); PUGL_END_DECLS diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h index 9ddc1ec..bb21a29 100644 --- a/include/pugl/pugl.h +++ b/include/pugl/pugl.h @@ -22,44 +22,44 @@ #include <stdint.h> #ifdef PUGL_SHARED -# ifdef _WIN32 -# define PUGL_LIB_IMPORT __declspec(dllimport) -# define PUGL_LIB_EXPORT __declspec(dllexport) -# else -# define PUGL_LIB_IMPORT __attribute__((visibility("default"))) -# define PUGL_LIB_EXPORT __attribute__((visibility("default"))) -# endif -# ifdef PUGL_INTERNAL -# define PUGL_API PUGL_LIB_EXPORT -# else -# define PUGL_API PUGL_LIB_IMPORT -# endif +# ifdef _WIN32 +# define PUGL_LIB_IMPORT __declspec(dllimport) +# define PUGL_LIB_EXPORT __declspec(dllexport) +# else +# define PUGL_LIB_IMPORT __attribute__((visibility("default"))) +# define PUGL_LIB_EXPORT __attribute__((visibility("default"))) +# endif +# ifdef PUGL_INTERNAL +# define PUGL_API PUGL_LIB_EXPORT +# else +# define PUGL_API PUGL_LIB_IMPORT +# endif #else -# define PUGL_API +# define PUGL_API #endif #ifndef PUGL_DISABLE_DEPRECATED -# if defined(__clang__) -# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep))) -# elif defined(__GNUC__) -# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep))) -# else -# define PUGL_DEPRECATED_BY(rep) -# endif +# if defined(__clang__) +# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("", rep))) +# elif defined(__GNUC__) +# define PUGL_DEPRECATED_BY(rep) __attribute__((deprecated("Use " rep))) +# else +# define PUGL_DEPRECATED_BY(rep) +# endif #endif #if defined(__GNUC__) -# define PUGL_CONST_FUNC __attribute__((const)) +# define PUGL_CONST_FUNC __attribute__((const)) #else -# define PUGL_CONST_FUNC +# define PUGL_CONST_FUNC #endif #ifdef __cplusplus -# define PUGL_BEGIN_DECLS extern "C" { -# define PUGL_END_DECLS } +# define PUGL_BEGIN_DECLS extern "C" { +# define PUGL_END_DECLS } #else -# define PUGL_BEGIN_DECLS -# define PUGL_END_DECLS +# define PUGL_BEGIN_DECLS +# define PUGL_END_DECLS #endif PUGL_BEGIN_DECLS @@ -77,10 +77,10 @@ PUGL_BEGIN_DECLS uses coordinates where the top left corner is 0,0. */ typedef struct { - double x; - double y; - double width; - double height; + double x; + double y; + double width; + double height; } PuglRect; /** @@ -96,10 +96,10 @@ typedef struct { /// Keyboard modifier flags typedef enum { - PUGL_MOD_SHIFT = 1u << 0u, ///< Shift key - PUGL_MOD_CTRL = 1u << 1u, ///< Control key - PUGL_MOD_ALT = 1u << 2u, ///< Alt/Option key - PUGL_MOD_SUPER = 1u << 3u ///< Mod4/Command/Windows key + PUGL_MOD_SHIFT = 1u << 0u, ///< Shift key + PUGL_MOD_CTRL = 1u << 1u, ///< Control key + PUGL_MOD_ALT = 1u << 2u, ///< Alt/Option key + PUGL_MOD_SUPER = 1u << 3u ///< Mod4/Command/Windows key } PuglMod; /// Bitwise OR of #PuglMod values @@ -120,92 +120,92 @@ typedef uint32_t PuglMods; mapping used here is arbitrary and specific to Pugl. */ typedef enum { - // ASCII control codes - PUGL_KEY_BACKSPACE = 0x08, - PUGL_KEY_ESCAPE = 0x1B, - PUGL_KEY_DELETE = 0x7F, - - // Unicode Private Use Area - PUGL_KEY_F1 = 0xE000, - PUGL_KEY_F2, - PUGL_KEY_F3, - PUGL_KEY_F4, - PUGL_KEY_F5, - PUGL_KEY_F6, - PUGL_KEY_F7, - PUGL_KEY_F8, - PUGL_KEY_F9, - PUGL_KEY_F10, - PUGL_KEY_F11, - PUGL_KEY_F12, - PUGL_KEY_LEFT, - PUGL_KEY_UP, - PUGL_KEY_RIGHT, - PUGL_KEY_DOWN, - PUGL_KEY_PAGE_UP, - PUGL_KEY_PAGE_DOWN, - PUGL_KEY_HOME, - PUGL_KEY_END, - PUGL_KEY_INSERT, - PUGL_KEY_SHIFT, - PUGL_KEY_SHIFT_L = PUGL_KEY_SHIFT, - PUGL_KEY_SHIFT_R, - PUGL_KEY_CTRL, - PUGL_KEY_CTRL_L = PUGL_KEY_CTRL, - PUGL_KEY_CTRL_R, - PUGL_KEY_ALT, - PUGL_KEY_ALT_L = PUGL_KEY_ALT, - PUGL_KEY_ALT_R, - PUGL_KEY_SUPER, - PUGL_KEY_SUPER_L = PUGL_KEY_SUPER, - PUGL_KEY_SUPER_R, - PUGL_KEY_MENU, - PUGL_KEY_CAPS_LOCK, - PUGL_KEY_SCROLL_LOCK, - PUGL_KEY_NUM_LOCK, - PUGL_KEY_PRINT_SCREEN, - PUGL_KEY_PAUSE + // ASCII control codes + PUGL_KEY_BACKSPACE = 0x08, + PUGL_KEY_ESCAPE = 0x1B, + PUGL_KEY_DELETE = 0x7F, + + // Unicode Private Use Area + PUGL_KEY_F1 = 0xE000, + PUGL_KEY_F2, + PUGL_KEY_F3, + PUGL_KEY_F4, + PUGL_KEY_F5, + PUGL_KEY_F6, + PUGL_KEY_F7, + PUGL_KEY_F8, + PUGL_KEY_F9, + PUGL_KEY_F10, + PUGL_KEY_F11, + PUGL_KEY_F12, + PUGL_KEY_LEFT, + PUGL_KEY_UP, + PUGL_KEY_RIGHT, + PUGL_KEY_DOWN, + PUGL_KEY_PAGE_UP, + PUGL_KEY_PAGE_DOWN, + PUGL_KEY_HOME, + PUGL_KEY_END, + PUGL_KEY_INSERT, + PUGL_KEY_SHIFT, + PUGL_KEY_SHIFT_L = PUGL_KEY_SHIFT, + PUGL_KEY_SHIFT_R, + PUGL_KEY_CTRL, + PUGL_KEY_CTRL_L = PUGL_KEY_CTRL, + PUGL_KEY_CTRL_R, + PUGL_KEY_ALT, + PUGL_KEY_ALT_L = PUGL_KEY_ALT, + PUGL_KEY_ALT_R, + PUGL_KEY_SUPER, + PUGL_KEY_SUPER_L = PUGL_KEY_SUPER, + PUGL_KEY_SUPER_R, + PUGL_KEY_MENU, + PUGL_KEY_CAPS_LOCK, + PUGL_KEY_SCROLL_LOCK, + PUGL_KEY_NUM_LOCK, + PUGL_KEY_PRINT_SCREEN, + PUGL_KEY_PAUSE } PuglKey; /// The type of a PuglEvent typedef enum { - PUGL_NOTHING, ///< No event - PUGL_CREATE, ///< View created, a #PuglEventCreate - PUGL_DESTROY, ///< View destroyed, a #PuglEventDestroy - PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure - PUGL_MAP, ///< View made visible, a #PuglEventMap - PUGL_UNMAP, ///< View made invisible, a #PuglEventUnmap - PUGL_UPDATE, ///< View ready to draw, a #PuglEventUpdate - PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose - PUGL_CLOSE, ///< View will be closed, a #PuglEventClose - PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus - PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus - PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey - PUGL_KEY_RELEASE, ///< Key released, a #PuglEventKey - PUGL_TEXT, ///< Character entered, a #PuglEventText - PUGL_POINTER_IN, ///< Pointer entered view, a #PuglEventCrossing - PUGL_POINTER_OUT, ///< Pointer left view, a #PuglEventCrossing - PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton - PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton - PUGL_MOTION, ///< Pointer moved, a #PuglEventMotion - PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll - PUGL_CLIENT, ///< Custom client message, a #PuglEventClient - PUGL_TIMER, ///< Timer triggered, a #PuglEventTimer - PUGL_LOOP_ENTER, ///< Recursive loop entered, a #PuglEventLoopEnter - PUGL_LOOP_LEAVE, ///< Recursive loop left, a #PuglEventLoopLeave + PUGL_NOTHING, ///< No event + PUGL_CREATE, ///< View created, a #PuglEventCreate + PUGL_DESTROY, ///< View destroyed, a #PuglEventDestroy + PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure + PUGL_MAP, ///< View made visible, a #PuglEventMap + PUGL_UNMAP, ///< View made invisible, a #PuglEventUnmap + PUGL_UPDATE, ///< View ready to draw, a #PuglEventUpdate + PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose + PUGL_CLOSE, ///< View will be closed, a #PuglEventClose + PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus + PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus + PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey + PUGL_KEY_RELEASE, ///< Key released, a #PuglEventKey + PUGL_TEXT, ///< Character entered, a #PuglEventText + PUGL_POINTER_IN, ///< Pointer entered view, a #PuglEventCrossing + PUGL_POINTER_OUT, ///< Pointer left view, a #PuglEventCrossing + PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton + PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton + PUGL_MOTION, ///< Pointer moved, a #PuglEventMotion + PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll + PUGL_CLIENT, ///< Custom client message, a #PuglEventClient + PUGL_TIMER, ///< Timer triggered, a #PuglEventTimer + PUGL_LOOP_ENTER, ///< Recursive loop entered, a #PuglEventLoopEnter + PUGL_LOOP_LEAVE, ///< Recursive loop left, a #PuglEventLoopLeave #ifndef PUGL_DISABLE_DEPRECATED - PUGL_ENTER_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_IN") = PUGL_POINTER_IN, - PUGL_LEAVE_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_OUT") = PUGL_POINTER_OUT, - PUGL_MOTION_NOTIFY PUGL_DEPRECATED_BY("PUGL_MOTION") = PUGL_MOTION, + PUGL_ENTER_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_IN") = PUGL_POINTER_IN, + PUGL_LEAVE_NOTIFY PUGL_DEPRECATED_BY("PUGL_POINTER_OUT") = PUGL_POINTER_OUT, + PUGL_MOTION_NOTIFY PUGL_DEPRECATED_BY("PUGL_MOTION") = PUGL_MOTION, #endif } PuglEventType; /// Common flags for all event types typedef enum { - PUGL_IS_SEND_EVENT = 1, ///< Event is synthetic - PUGL_IS_HINT = 2 ///< Event is a hint (not direct user input) + PUGL_IS_SEND_EVENT = 1, ///< Event is synthetic + PUGL_IS_HINT = 2 ///< Event is a hint (not direct user input) } PuglEventFlag; /// Bitwise OR of #PuglEventFlag values @@ -213,9 +213,9 @@ typedef uint32_t PuglEventFlags; /// Reason for a PuglEventCrossing typedef enum { - PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion - PUGL_CROSSING_GRAB, ///< Crossing due to a grab - PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release + PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion + PUGL_CROSSING_GRAB, ///< Crossing due to a grab + PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release } PuglCrossingMode; /** @@ -227,17 +227,17 @@ typedef enum { arbitrary scroll direction freedom, like some touchpads. */ typedef enum { - PUGL_SCROLL_UP, ///< Scroll up - PUGL_SCROLL_DOWN, ///< Scroll down - PUGL_SCROLL_LEFT, ///< Scroll left - PUGL_SCROLL_RIGHT, ///< Scroll right - PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction + PUGL_SCROLL_UP, ///< Scroll up + PUGL_SCROLL_DOWN, ///< Scroll down + PUGL_SCROLL_LEFT, ///< Scroll left + PUGL_SCROLL_RIGHT, ///< Scroll right + PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction } PuglScrollDirection; /// Common header for all event structs typedef struct { - PuglEventType type; ///< Event type - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + PuglEventType type; ///< Event type + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values } PuglEventAny; /** @@ -275,12 +275,12 @@ typedef PuglEventAny PuglEventDestroy; otherwise configure the context, but not to draw anything. */ typedef struct { - PuglEventType type; ///< #PUGL_CONFIGURE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< New parent-relative X coordinate - double y; ///< New parent-relative Y coordinate - double width; ///< New width - double height; ///< New height + PuglEventType type; ///< #PUGL_CONFIGURE + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double x; ///< New parent-relative X coordinate + double y; ///< New parent-relative Y coordinate + double width; ///< New width + double height; ///< New height } PuglEventConfigure; /** @@ -321,12 +321,12 @@ typedef PuglEventAny PuglEventUpdate; undefined, there is no preservation of anything drawn previously. */ typedef struct { - PuglEventType type; ///< #PUGL_EXPOSE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double width; ///< Width of exposed region - double height; ///< Height of exposed region + PuglEventType type; ///< #PUGL_EXPOSE + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double width; ///< Width of exposed region + double height; ///< Height of exposed region } PuglEventExpose; /** @@ -346,9 +346,9 @@ typedef PuglEventAny PuglEventClose; view with the keyboard focus will receive any key press or release events. */ typedef struct { - PuglEventType type; ///< #PUGL_FOCUS_IN or #PUGL_FOCUS_OUT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - PuglCrossingMode mode; ///< Reason for focus change + PuglEventType type; ///< #PUGL_FOCUS_IN or #PUGL_FOCUS_OUT + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + PuglCrossingMode mode; ///< Reason for focus change } PuglEventFocus; /** @@ -369,16 +369,16 @@ typedef struct { and hardware. */ typedef struct { - PuglEventType type; ///< #PUGL_KEY_PRESS or #PUGL_KEY_RELEASE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t keycode; ///< Raw key code - uint32_t key; ///< Unshifted Unicode character code, or 0 + PuglEventType type; ///< #PUGL_KEY_PRESS or #PUGL_KEY_RELEASE + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags + uint32_t keycode; ///< Raw key code + uint32_t key; ///< Unshifted Unicode character code, or 0 } PuglEventKey; /** @@ -393,17 +393,17 @@ typedef struct { presses will generate a single character. */ typedef struct { - PuglEventType type; ///< #PUGL_TEXT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t keycode; ///< Raw key code - uint32_t character; ///< Unicode character code - char string[8]; ///< UTF-8 string + PuglEventType type; ///< #PUGL_TEXT + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags + uint32_t keycode; ///< Raw key code + uint32_t character; ///< Unicode character code + char string[8]; ///< UTF-8 string } PuglEventText; /** @@ -414,44 +414,44 @@ typedef struct { window edge), as described by the `mode` field. */ typedef struct { - PuglEventType type; ///< #PUGL_POINTER_IN or #PUGL_POINTER_OUT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - PuglCrossingMode mode; ///< Reason for crossing + PuglEventType type; ///< #PUGL_POINTER_IN or #PUGL_POINTER_OUT + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags + PuglCrossingMode mode; ///< Reason for crossing } PuglEventCrossing; /** Button press or release event. */ typedef struct { - PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - uint32_t button; ///< Button number starting from 1 + PuglEventType type; ///< #PUGL_BUTTON_PRESS or #PUGL_BUTTON_RELEASE + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags + uint32_t button; ///< Button number starting from 1 } PuglEventButton; /** Pointer motion event. */ typedef struct { - PuglEventType type; ///< #PUGL_MOTION - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags + PuglEventType type; ///< #PUGL_MOTION + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags } PuglEventMotion; /** @@ -464,17 +464,17 @@ typedef struct { gracefully. */ typedef struct { - PuglEventType type; ///< #PUGL_SCROLL - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - double time; ///< Time in seconds - double x; ///< View-relative X coordinate - double y; ///< View-relative Y coordinate - double xRoot; ///< Root-relative X coordinate - double yRoot; ///< Root-relative Y coordinate - PuglMods state; ///< Bitwise OR of #PuglMod flags - PuglScrollDirection direction; ///< Scroll direction - double dx; ///< Scroll X distance in lines - double dy; ///< Scroll Y distance in lines + PuglEventType type; ///< #PUGL_SCROLL + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + double time; ///< Time in seconds + double x; ///< View-relative X coordinate + double y; ///< View-relative Y coordinate + double xRoot; ///< Root-relative X coordinate + double yRoot; ///< Root-relative Y coordinate + PuglMods state; ///< Bitwise OR of #PuglMod flags + PuglScrollDirection direction; ///< Scroll direction + double dx; ///< Scroll X distance in lines + double dy; ///< Scroll Y distance in lines } PuglEventScroll; /** @@ -485,10 +485,10 @@ typedef struct { things, this makes it possible to wake up the event loop for any reason. */ typedef struct { - PuglEventType type; ///< #PUGL_CLIENT - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - uintptr_t data1; ///< Client-specific data - uintptr_t data2; ///< Client-specific data + PuglEventType type; ///< #PUGL_CLIENT + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + uintptr_t data1; ///< Client-specific data + uintptr_t data2; ///< Client-specific data } PuglEventClient; /** @@ -502,9 +502,9 @@ typedef struct { event handler, even in applications that register only one timer. */ typedef struct { - PuglEventType type; ///< #PUGL_TIMER - PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values - uintptr_t id; ///< Timer ID + PuglEventType type; ///< #PUGL_TIMER + PuglEventFlags flags; ///< Bitwise OR of #PuglEventFlag values + uintptr_t id; ///< Timer ID } PuglEventTimer; /** @@ -551,19 +551,19 @@ typedef PuglEventAny PuglEventLoopLeave; and #PUGL_EXPOSE, but only enabled for drawing for #PUGL_EXPOSE. */ typedef union { - PuglEventAny any; ///< Valid for all event types - PuglEventType type; ///< Event type - PuglEventButton button; ///< #PUGL_BUTTON_PRESS, #PUGL_BUTTON_RELEASE - PuglEventConfigure configure; ///< #PUGL_CONFIGURE - PuglEventExpose expose; ///< #PUGL_EXPOSE - PuglEventKey key; ///< #PUGL_KEY_PRESS, #PUGL_KEY_RELEASE - PuglEventText text; ///< #PUGL_TEXT - PuglEventCrossing crossing; ///< #PUGL_POINTER_IN, #PUGL_POINTER_OUT - PuglEventMotion motion; ///< #PUGL_MOTION - PuglEventScroll scroll; ///< #PUGL_SCROLL - PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT - PuglEventClient client; ///< #PUGL_CLIENT - PuglEventTimer timer; ///< #PUGL_TIMER + PuglEventAny any; ///< Valid for all event types + PuglEventType type; ///< Event type + PuglEventButton button; ///< #PUGL_BUTTON_PRESS, #PUGL_BUTTON_RELEASE + PuglEventConfigure configure; ///< #PUGL_CONFIGURE + PuglEventExpose expose; ///< #PUGL_EXPOSE + PuglEventKey key; ///< #PUGL_KEY_PRESS, #PUGL_KEY_RELEASE + PuglEventText text; ///< #PUGL_TEXT + PuglEventCrossing crossing; ///< #PUGL_POINTER_IN, #PUGL_POINTER_OUT + PuglEventMotion motion; ///< #PUGL_MOTION + PuglEventScroll scroll; ///< #PUGL_SCROLL + PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT + PuglEventClient client; ///< #PUGL_CLIENT + PuglEventTimer timer; ///< #PUGL_TIMER } PuglEvent; /** @@ -577,22 +577,23 @@ typedef union { /// Return status code typedef enum { - PUGL_SUCCESS, ///< Success - PUGL_FAILURE, ///< Non-fatal failure - PUGL_UNKNOWN_ERROR, ///< Unknown system error - PUGL_BAD_BACKEND, ///< Invalid or missing backend - PUGL_BAD_CONFIGURATION, ///< Invalid view configuration - PUGL_BAD_PARAMETER, ///< Invalid parameter - PUGL_BACKEND_FAILED, ///< Backend initialization failed - PUGL_REGISTRATION_FAILED, ///< Class registration failed - PUGL_REALIZE_FAILED, ///< System view realization failed - PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format - PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context - PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type + PUGL_SUCCESS, ///< Success + PUGL_FAILURE, ///< Non-fatal failure + PUGL_UNKNOWN_ERROR, ///< Unknown system error + PUGL_BAD_BACKEND, ///< Invalid or missing backend + PUGL_BAD_CONFIGURATION, ///< Invalid view configuration + PUGL_BAD_PARAMETER, ///< Invalid parameter + PUGL_BACKEND_FAILED, ///< Backend initialization failed + PUGL_REGISTRATION_FAILED, ///< Class registration failed + PUGL_REALIZE_FAILED, ///< System view realization failed + PUGL_SET_FORMAT_FAILED, ///< Failed to set pixel format + PUGL_CREATE_CONTEXT_FAILED, ///< Failed to create drawing context + PUGL_UNSUPPORTED_TYPE, ///< Unsupported data type } PuglStatus; /// Return a string describing a status code -PUGL_API PUGL_CONST_FUNC +PUGL_API +PUGL_CONST_FUNC const char* puglStrerror(PuglStatus status); @@ -625,18 +626,18 @@ typedef void* PuglWorldHandle; /// The type of a World typedef enum { - PUGL_PROGRAM, ///< Top-level application - PUGL_MODULE ///< Plugin or module within a larger application + PUGL_PROGRAM, ///< Top-level application + PUGL_MODULE ///< Plugin or module within a larger application } PuglWorldType; /// World flags typedef enum { - /** - Set up support for threads if necessary. + /** + Set up support for threads if necessary. - - X11: Calls XInitThreads() which is required for some drivers. - */ - PUGL_WORLD_THREADS = 1u << 0u + - X11: Calls XInitThreads() which is required for some drivers. + */ + PUGL_WORLD_THREADS = 1u << 0u } PuglWorldFlag; /// Bitwise OR of #PuglWorldFlag values @@ -649,11 +650,13 @@ typedef uint32_t PuglWorldFlags; @param flags Flags to control world features. @return A new world, which must be later freed with puglFreeWorld(). */ -PUGL_API PuglWorld* +PUGL_API +PuglWorld* puglNewWorld(PuglWorldType type, PuglWorldFlags flags); /// Free a world allocated with puglNewWorld() -PUGL_API void +PUGL_API +void puglFreeWorld(PuglWorld* world); /** @@ -664,11 +667,13 @@ puglFreeWorld(PuglWorld* world); The handle is opaque to Pugl and is not interpreted in any way. */ -PUGL_API void +PUGL_API +void puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle); /// Get the user data for the world -PUGL_API PuglWorldHandle +PUGL_API +PuglWorldHandle puglGetWorldHandle(PuglWorld* world); /** @@ -680,7 +685,8 @@ puglGetWorldHandle(PuglWorld* world); Windows: Returns the `HMODULE` of the calling process. */ -PUGL_API void* +PUGL_API +void* puglGetNativeWorld(PuglWorld* world); /** @@ -692,7 +698,8 @@ puglGetNativeWorld(PuglWorld* world); for every instance of the application, but different from other applications. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetClassName(PuglWorld* world, const char* name); /** @@ -702,7 +709,8 @@ puglSetClassName(PuglWorld* world, const char* name); time is only useful to compare against other times returned by this function, its absolute value has no meaning. */ -PUGL_API double +PUGL_API +double puglGetTime(const PuglWorld* world); /** @@ -726,7 +734,8 @@ puglGetTime(const PuglWorld* world); @return #PUGL_SUCCESS if events are read, #PUGL_FAILURE if not, or an error. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglUpdate(PuglWorld* world, double timeout); /** @@ -775,31 +784,31 @@ typedef void* PuglHandle; /// A hint for configuring a view typedef enum { - PUGL_USE_COMPAT_PROFILE, ///< Use compatible (not core) OpenGL profile - PUGL_USE_DEBUG_CONTEXT, ///< True to use a debug OpenGL context - PUGL_CONTEXT_VERSION_MAJOR, ///< OpenGL context major version - PUGL_CONTEXT_VERSION_MINOR, ///< OpenGL context minor version - PUGL_RED_BITS, ///< Number of bits for red channel - PUGL_GREEN_BITS, ///< Number of bits for green channel - PUGL_BLUE_BITS, ///< Number of bits for blue channel - PUGL_ALPHA_BITS, ///< Number of bits for alpha channel - PUGL_DEPTH_BITS, ///< Number of bits for depth buffer - PUGL_STENCIL_BITS, ///< Number of bits for stencil buffer - PUGL_SAMPLES, ///< Number of samples per pixel (AA) - PUGL_DOUBLE_BUFFER, ///< True if double buffering should be used - PUGL_SWAP_INTERVAL, ///< Number of frames between buffer swaps - PUGL_RESIZABLE, ///< True if view should be resizable - PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored - PUGL_REFRESH_RATE, ///< Refresh rate in Hz - - PUGL_NUM_VIEW_HINTS + PUGL_USE_COMPAT_PROFILE, ///< Use compatible (not core) OpenGL profile + PUGL_USE_DEBUG_CONTEXT, ///< True to use a debug OpenGL context + PUGL_CONTEXT_VERSION_MAJOR, ///< OpenGL context major version + PUGL_CONTEXT_VERSION_MINOR, ///< OpenGL context minor version + PUGL_RED_BITS, ///< Number of bits for red channel + PUGL_GREEN_BITS, ///< Number of bits for green channel + PUGL_BLUE_BITS, ///< Number of bits for blue channel + PUGL_ALPHA_BITS, ///< Number of bits for alpha channel + PUGL_DEPTH_BITS, ///< Number of bits for depth buffer + PUGL_STENCIL_BITS, ///< Number of bits for stencil buffer + PUGL_SAMPLES, ///< Number of samples per pixel (AA) + PUGL_DOUBLE_BUFFER, ///< True if double buffering should be used + PUGL_SWAP_INTERVAL, ///< Number of frames between buffer swaps + PUGL_RESIZABLE, ///< True if view should be resizable + PUGL_IGNORE_KEY_REPEAT, ///< True if key repeat events are ignored + PUGL_REFRESH_RATE, ///< Refresh rate in Hz + + PUGL_NUM_VIEW_HINTS } PuglViewHint; /// A special view hint value typedef enum { - PUGL_DONT_CARE = -1, ///< Use best available value - PUGL_FALSE = 0, ///< Explicitly false - PUGL_TRUE = 1 ///< Explicitly true + PUGL_DONT_CARE = -1, ///< Use best available value + PUGL_FALSE = 0, ///< Explicitly false + PUGL_TRUE = 1 ///< Explicitly true } PuglViewHintValue; /// A function called when an event occurs @@ -818,15 +827,18 @@ typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event); It must first be configured, then the system view can be created with puglRealize(). */ -PUGL_API PuglView* +PUGL_API +PuglView* puglNewView(PuglWorld* world); /// Free a view created with puglNewView() -PUGL_API void +PUGL_API +void puglFreeView(PuglView* view); /// Return the world that `view` is a part of -PUGL_API PuglWorld* +PUGL_API +PuglWorld* puglGetWorld(PuglView* view); /** @@ -838,11 +850,13 @@ puglGetWorld(PuglView* view); The handle is opaque to Pugl and is not interpreted in any way. */ -PUGL_API void +PUGL_API +void puglSetHandle(PuglView* view, PuglHandle handle); /// Get the user data for a view -PUGL_API PuglHandle +PUGL_API +PuglHandle puglGetHandle(PuglView* view); /** @@ -862,11 +876,13 @@ puglGetHandle(PuglView* view); applications must link against the appropriate backend library, or be sure to compile in the appropriate code if using a local copy of Pugl. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetBackend(PuglView* view, const PuglBackend* backend); /// Set the function to call when an event occurs -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc); /** @@ -874,7 +890,8 @@ puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc); This only has an effect when called before puglRealize(). */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetViewHint(PuglView* view, PuglViewHint hint, int value); /** @@ -884,7 +901,8 @@ puglSetViewHint(PuglView* view, PuglViewHint hint, int value); hint which was initially set to PUGL_DONT_CARE, or has been adjusted from the suggested value. */ -PUGL_API int +PUGL_API +int puglGetViewHint(const PuglView* view, PuglViewHint hint); /** @@ -899,7 +917,8 @@ puglGetViewHint(const PuglView* view, PuglViewHint hint); The position is in screen coordinates with an upper left origin. */ -PUGL_API PuglRect +PUGL_API +PuglRect puglGetFrame(const PuglView* view); /** @@ -910,7 +929,8 @@ puglGetFrame(const PuglView* view); @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is unchanged. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetFrame(PuglView* view, PuglRect frame); /** @@ -923,7 +943,8 @@ puglSetFrame(PuglView* view, PuglRect frame); @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetDefaultSize(PuglView* view, int width, int height); /** @@ -935,7 +956,8 @@ puglSetDefaultSize(PuglView* view, int width, int height); @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetMinSize(PuglView* view, int width, int height); /** @@ -947,7 +969,8 @@ puglSetMinSize(PuglView* view, int width, int height); @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetMaxSize(PuglView* view, int width, int height); /** @@ -966,7 +989,8 @@ puglSetMaxSize(PuglView* view, int width, int height); @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY); /** @@ -983,7 +1007,8 @@ puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY); top-level window, and sets the title, typically displayed in the title bar or in window switchers. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetWindowTitle(PuglView* view, const char* title); /** @@ -991,7 +1016,8 @@ puglSetWindowTitle(PuglView* view, const char* title); This must be called before puglRealize(), reparenting is not supported. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetParentWindow(PuglView* view, PuglNativeView parent); /** @@ -1004,7 +1030,8 @@ puglSetParentWindow(PuglView* view, PuglNativeView parent); A view can either have a parent (for embedding) or a transient parent (for top-level windows like dialogs), but not both. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetTransientFor(PuglView* view, PuglNativeView parent); /** @@ -1018,7 +1045,8 @@ puglSetTransientFor(PuglView* view, PuglNativeView parent); The view should be fully configured using the above functions before this is called. This function may only be called once per view. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglRealize(PuglView* view); /** @@ -1030,19 +1058,23 @@ puglRealize(PuglView* view); If the view is currently hidden, it will be shown and possibly raised to the top depending on the platform. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglShow(PuglView* view); /// Hide the current window -PUGL_API PuglStatus +PUGL_API +PuglStatus puglHide(PuglView* view); /// Return true iff the view is currently visible -PUGL_API bool +PUGL_API +bool puglGetVisible(const PuglView* view); /// Return the native window handle -PUGL_API PuglNativeView +PUGL_API +PuglNativeView puglGetNativeWindow(PuglView* view); /** @@ -1063,7 +1095,8 @@ puglGetNativeWindow(PuglView* view); All other backends: returns null. */ -PUGL_API void* +PUGL_API +void* puglGetContext(PuglView* view); /** @@ -1075,7 +1108,8 @@ puglGetContext(PuglView* view); platforms. If called elsewhere, an expose will be enqueued to be processed in the next event loop iteration. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglPostRedisplay(PuglView* view); /** @@ -1084,7 +1118,8 @@ puglPostRedisplay(PuglView* view); This has the same semantics as puglPostRedisplay(), but allows giving a precise region for redrawing only a portion of the view. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglPostRedisplayRect(PuglView* view, PuglRect rect); /** @@ -1101,21 +1136,23 @@ puglPostRedisplayRect(PuglView* view, PuglRect rect); Windows. */ typedef enum { - PUGL_CURSOR_ARROW, ///< Default pointing arrow - PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry - PUGL_CURSOR_CROSSHAIR, ///< Cross-hair - PUGL_CURSOR_HAND, ///< Hand with a pointing finger - PUGL_CURSOR_NO, ///< Operation not allowed - PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize - PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize + PUGL_CURSOR_ARROW, ///< Default pointing arrow + PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry + PUGL_CURSOR_CROSSHAIR, ///< Cross-hair + PUGL_CURSOR_HAND, ///< Hand with a pointing finger + PUGL_CURSOR_NO, ///< Operation not allowed + PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize + PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize } PuglCursor; /// Grab the keyboard input focus -PUGL_API PuglStatus +PUGL_API +PuglStatus puglGrabFocus(PuglView* view); /// Return whether `view` has the keyboard input focus -PUGL_API bool +PUGL_API +bool puglHasFocus(const PuglView* view); /** @@ -1129,7 +1166,8 @@ puglHasFocus(const PuglView* view); @param data The data to copy to the clipboard. @param len The length of data in bytes (including terminator if necessary). */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetClipboard(PuglView* view, const char* type, const void* data, @@ -1146,7 +1184,8 @@ puglSetClipboard(PuglView* view, @param[out] len Set to the length of the data in bytes. @return The clipboard contents, or `NULL`. */ -PUGL_API const void* +PUGL_API +const void* puglGetClipboard(PuglView* view, const char** type, size_t* len); /** @@ -1160,7 +1199,8 @@ puglGetClipboard(PuglView* view, const char** type, size_t* len); - #PUGL_BAD_PARAMETER if the given cursor is invalid. - #PUGL_FAILURE if the cursor isknown but loading it from the system fails. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSetCursor(PuglView* view, PuglCursor cursor); /** @@ -1170,7 +1210,8 @@ puglSetCursor(PuglView* view, PuglCursor cursor); from the user. The exact effect depends on the platform, but is usually something like a flashing task bar entry or bouncing application icon. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglRequestAttention(PuglView* view); /** @@ -1200,7 +1241,8 @@ puglRequestAttention(PuglView* view); - #PUGL_FAILURE if timers are not supported by this system or build. - #PUGL_UNKNOWN_ERROR if setting the timer failed. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglStartTimer(PuglView* view, uintptr_t id, double timeout); /** @@ -1213,7 +1255,8 @@ puglStartTimer(PuglView* view, uintptr_t id, double timeout); - #PUGL_FAILURE if timers are not supported by this system or build. - #PUGL_UNKNOWN_ERROR if stopping the timer failed. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglStopTimer(PuglView* view, uintptr_t id); /** @@ -1233,7 +1276,8 @@ puglStopTimer(PuglView* view, uintptr_t id); - #PUGL_UNSUPPORTED_TYPE if sending events of this type is not supported. - #PUGL_UNKNOWN_ERROR if sending the event failed. */ -PUGL_API PuglStatus +PUGL_API +PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event); /** @@ -1271,13 +1315,14 @@ typedef uintptr_t PuglNativeWindow; @param argv Arguments (currently unused). @return A newly created view. */ -static inline PUGL_DEPRECATED_BY("puglNewView") PuglView* +static inline PUGL_DEPRECATED_BY("puglNewView") +PuglView* puglInit(const int* pargc, char** argv) { - (void)pargc; - (void)argv; + (void)pargc; + (void)argv; - return puglNewView(puglNewWorld(PUGL_MODULE, 0)); + return puglNewView(puglNewWorld(PUGL_MODULE, 0)); } /** @@ -1285,22 +1330,24 @@ puglInit(const int* pargc, char** argv) @deprecated Use puglFreeApp() and puglFreeView(). */ -static inline PUGL_DEPRECATED_BY("puglFreeView") void +static inline PUGL_DEPRECATED_BY("puglFreeView") +void puglDestroy(PuglView* view) { - PuglWorld* const world = puglGetWorld(view); + PuglWorld* const world = puglGetWorld(view); - puglFreeView(view); - puglFreeWorld(world); + puglFreeView(view); + puglFreeWorld(world); } /** Set the window class name before creating a window. */ -static inline PUGL_DEPRECATED_BY("puglSetClassName") void +static inline PUGL_DEPRECATED_BY("puglSetClassName") +void puglInitWindowClass(PuglView* view, const char* name) { - puglSetClassName(puglGetWorld(view), name); + puglSetClassName(puglGetWorld(view), name); } /** @@ -1308,24 +1355,26 @@ puglInitWindowClass(PuglView* view, const char* name) @deprecated Use puglSetFrame(). */ -static inline PUGL_DEPRECATED_BY("puglSetFrame") void +static inline PUGL_DEPRECATED_BY("puglSetFrame") +void puglInitWindowSize(PuglView* view, int width, int height) { - PuglRect frame = puglGetFrame(view); + PuglRect frame = puglGetFrame(view); - frame.width = width; - frame.height = height; + frame.width = width; + frame.height = height; - puglSetFrame(view, frame); + puglSetFrame(view, frame); } /** Set the minimum window size before creating a window. */ -static inline PUGL_DEPRECATED_BY("puglSetMinSize") void +static inline PUGL_DEPRECATED_BY("puglSetMinSize") +void puglInitWindowMinSize(PuglView* view, int width, int height) { - puglSetMinSize(view, width, height); + puglSetMinSize(view, width, height); } /** @@ -1338,14 +1387,15 @@ puglInitWindowMinSize(PuglView* view, int width, int height) currenty work on MacOS (the minimum is used), so only setting a fixed aspect ratio works properly across all platforms. */ -static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") void +static inline PUGL_DEPRECATED_BY("puglSetAspectRatio") +void puglInitWindowAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY) { - puglSetAspectRatio(view, minX, minY, maxX, maxY); + puglSetAspectRatio(view, minX, minY, maxX, maxY); } /** @@ -1354,10 +1404,11 @@ puglInitWindowAspectRatio(PuglView* view, On X11, parent must be a Window. On OSX, parent must be an NSView*. */ -static inline PUGL_DEPRECATED_BY("puglSetTransientFor") void +static inline PUGL_DEPRECATED_BY("puglSetTransientFor") +void puglInitTransientFor(PuglView* view, uintptr_t parent) { - puglSetTransientFor(view, (PuglNativeWindow)parent); + puglSetTransientFor(view, (PuglNativeWindow)parent); } /** @@ -1365,10 +1416,11 @@ puglInitTransientFor(PuglView* view, uintptr_t parent) @deprecated Use puglSetViewHint() with #PUGL_RESIZABLE. */ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") void +static inline PUGL_DEPRECATED_BY("puglSetViewHint") +void puglInitResizable(PuglView* view, bool resizable) { - puglSetViewHint(view, PUGL_RESIZABLE, resizable); + puglSetViewHint(view, PUGL_RESIZABLE, resizable); } /** @@ -1377,13 +1429,14 @@ puglInitResizable(PuglView* view, bool resizable) @deprecated Use puglGetFrame(). */ -static inline PUGL_DEPRECATED_BY("puglGetFrame") void +static inline PUGL_DEPRECATED_BY("puglGetFrame") +void puglGetSize(PuglView* view, int* width, int* height) { - const PuglRect frame = puglGetFrame(view); + const PuglRect frame = puglGetFrame(view); - *width = (int)frame.width; - *height = (int)frame.height; + *width = (int)frame.width; + *height = (int)frame.height; } /** @@ -1391,10 +1444,11 @@ puglGetSize(PuglView* view, int* width, int* height) @deprecated Use puglSetViewHint() with #PUGL_IGNORE_KEY_REPEAT. */ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") void +static inline PUGL_DEPRECATED_BY("puglSetViewHint") +void puglIgnoreKeyRepeat(PuglView* view, bool ignore) { - puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore); + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, ignore); } /** @@ -1402,10 +1456,11 @@ puglIgnoreKeyRepeat(PuglView* view, bool ignore) @deprecated Use puglSetWindowHint(). */ -static inline PUGL_DEPRECATED_BY("puglSetViewHint") void +static inline PUGL_DEPRECATED_BY("puglSetViewHint") +void puglInitWindowHint(PuglView* view, PuglViewHint hint, int value) { - puglSetViewHint(view, hint, value); + puglSetViewHint(view, hint, value); } /** @@ -1413,10 +1468,11 @@ puglInitWindowHint(PuglView* view, PuglViewHint hint, int value) @deprecated Use puglSetWindowParent(). */ -static inline PUGL_DEPRECATED_BY("puglSetParentWindow") void +static inline PUGL_DEPRECATED_BY("puglSetParentWindow") +void puglInitWindowParent(PuglView* view, PuglNativeWindow parent) { - puglSetParentWindow(view, parent); + puglSetParentWindow(view, parent); } /** @@ -1424,10 +1480,11 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) @deprecated Use puglSetBackend(). */ -static inline PUGL_DEPRECATED_BY("puglSetBackend") int +static inline PUGL_DEPRECATED_BY("puglSetBackend") +int puglInitBackend(PuglView* view, const PuglBackend* backend) { - return (int)puglSetBackend(view, backend); + return (int)puglSetBackend(view, backend); } /** @@ -1438,11 +1495,12 @@ puglInitBackend(PuglView* view, const PuglBackend* backend) @deprecated Use puglRealize(), or just show the view. */ -static inline PUGL_DEPRECATED_BY("puglRealize") PuglStatus +static inline PUGL_DEPRECATED_BY("puglRealize") +PuglStatus puglCreateWindow(PuglView* view, const char* title) { - puglSetWindowTitle(view, title); - return puglRealize(view); + puglSetWindowTitle(view, title); + return puglRealize(view); } /** @@ -1455,7 +1513,9 @@ puglCreateWindow(PuglView* view, const char* title) @deprecated Use puglPollEvents(). */ -PUGL_API PUGL_DEPRECATED_BY("puglPollEvents") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglPollEvents") +PuglStatus puglWaitForEvent(PuglView* view); /** @@ -1467,7 +1527,9 @@ puglWaitForEvent(PuglView* view); @deprecated Use puglDispatchEvents(). */ -PUGL_API PUGL_DEPRECATED_BY("puglDispatchEvents") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglDispatchEvents") +PuglStatus puglProcessEvents(PuglView* view); /** @@ -1485,7 +1547,9 @@ puglProcessEvents(PuglView* view); @deprecated Use puglUpdate(). */ -PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglUpdate") +PuglStatus puglPollEvents(PuglWorld* world, double timeout); /** @@ -1498,13 +1562,19 @@ puglPollEvents(PuglWorld* world, double timeout); @deprecated Use puglUpdate(). */ -PUGL_API PUGL_DEPRECATED_BY("puglUpdate") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglUpdate") +PuglStatus puglDispatchEvents(PuglWorld* world); -PUGL_API PUGL_DEPRECATED_BY("puglShow") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglShow") +PuglStatus puglShowWindow(PuglView* view); -PUGL_API PUGL_DEPRECATED_BY("puglHide") PuglStatus +PUGL_API +PUGL_DEPRECATED_BY("puglHide") +PuglStatus puglHideWindow(PuglView* view); #endif // PUGL_DISABLE_DEPRECATED diff --git a/include/pugl/stub.h b/include/pugl/stub.h index d2d1236..46e0e96 100644 --- a/include/pugl/stub.h +++ b/include/pugl/stub.h @@ -34,7 +34,8 @@ PUGL_BEGIN_DECLS This backend just creates a simple native window without setting up any portable graphics API. */ -PUGL_API PUGL_CONST_FUNC +PUGL_API +PUGL_CONST_FUNC const PuglBackend* puglStubBackend(void); diff --git a/include/pugl/vulkan.h b/include/pugl/vulkan.h index bd4ad8e..15f834c 100644 --- a/include/pugl/vulkan.h +++ b/include/pugl/vulkan.h @@ -66,11 +66,13 @@ typedef struct PuglVulkanLoaderImpl PuglVulkanLoader; /** Create a new dynamic loader for Vulkan functions. - This dynamically loads the Vulkan library and gets the load functions from it. + This dynamically loads the Vulkan library and gets the load functions from + it. @return A new Vulkan loader, or null on failure. */ -PUGL_API PuglVulkanLoader* +PUGL_API +PuglVulkanLoader* puglNewVulkanLoader(PuglWorld* world); /** @@ -79,7 +81,8 @@ puglNewVulkanLoader(PuglWorld* world); Note that this closes the Vulkan library, so no Vulkan objects or API may be used after this is called. */ -PUGL_API void +PUGL_API +void puglFreeVulkanLoader(PuglVulkanLoader* loader); /** @@ -88,7 +91,8 @@ puglFreeVulkanLoader(PuglVulkanLoader* loader); @return Null if the Vulkan library does not contain this function (which is unlikely and indicates a broken system). */ -PUGL_API PFN_vkGetInstanceProcAddr +PUGL_API +PFN_vkGetInstanceProcAddr puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader); /** @@ -97,7 +101,8 @@ puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader); @return Null if the Vulkan library does not contain this function (which is unlikely and indicates a broken system). */ -PUGL_API PFN_vkGetDeviceProcAddr +PUGL_API +PFN_vkGetDeviceProcAddr puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader); /** @@ -109,7 +114,8 @@ puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader); @param[out] count The number of extensions in the returned array. @return An array of extension name strings. */ -PUGL_API const char* const* +PUGL_API +const char* const* puglGetInstanceExtensions(uint32_t* count); /** @@ -122,7 +128,8 @@ puglGetInstanceExtensions(uint32_t* count); @param[out] surface Pointed to a newly created Vulkan surface. @return `VK_SUCCESS` on success, or a Vulkan error code. */ -PUGL_API VkResult +PUGL_API +VkResult puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, PuglView* view, VkInstance instance, @@ -134,7 +141,9 @@ puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, Pass the returned value to puglSetBackend() to draw to a view with Vulkan. */ -PUGL_API PUGL_CONST_FUNC const PuglBackend* +PUGL_API +PUGL_CONST_FUNC +const PuglBackend* puglVulkanBackend(void); /** diff --git a/src/implementation.c b/src/implementation.c index e842e13..a6d8393 100644 --- a/src/implementation.c +++ b/src/implementation.c @@ -26,248 +26,249 @@ const char* puglStrerror(const PuglStatus status) { - // clang-format off - switch (status) { - case PUGL_SUCCESS: return "Success"; - case PUGL_FAILURE: return "Non-fatal failure"; - case PUGL_UNKNOWN_ERROR: return "Unknown system error"; - case PUGL_BAD_BACKEND: return "Invalid or missing backend"; - case PUGL_BAD_CONFIGURATION: return "Invalid view configuration"; - case PUGL_BAD_PARAMETER: return "Invalid parameter"; - case PUGL_BACKEND_FAILED: return "Backend initialisation failed"; - case PUGL_REGISTRATION_FAILED: return "Class registration failed"; - case PUGL_REALIZE_FAILED: return "View creation failed"; - case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format"; - case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context"; - case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type"; - } - // clang-format on - - return "Unknown error"; + // clang-format off + switch (status) { + case PUGL_SUCCESS: return "Success"; + case PUGL_FAILURE: return "Non-fatal failure"; + case PUGL_UNKNOWN_ERROR: return "Unknown system error"; + case PUGL_BAD_BACKEND: return "Invalid or missing backend"; + case PUGL_BAD_CONFIGURATION: return "Invalid view configuration"; + case PUGL_BAD_PARAMETER: return "Invalid parameter"; + case PUGL_BACKEND_FAILED: return "Backend initialisation failed"; + case PUGL_REGISTRATION_FAILED: return "Class registration failed"; + case PUGL_REALIZE_FAILED: return "View creation failed"; + case PUGL_SET_FORMAT_FAILED: return "Failed to set pixel format"; + case PUGL_CREATE_CONTEXT_FAILED: return "Failed to create drawing context"; + case PUGL_UNSUPPORTED_TYPE: return "Unsupported data type"; + } + // clang-format on + + return "Unknown error"; } void puglSetString(char** dest, const char* string) { - if (*dest != string) { - const size_t len = strlen(string); + if (*dest != string) { + const size_t len = strlen(string); - *dest = (char*)realloc(*dest, len + 1); - strncpy(*dest, string, len + 1); - } + *dest = (char*)realloc(*dest, len + 1); + strncpy(*dest, string, len + 1); + } } void puglSetBlob(PuglBlob* const dest, const void* const data, const size_t len) { - if (data) { - dest->len = len; - dest->data = realloc(dest->data, len + 1); - memcpy(dest->data, data, len); - ((char*)dest->data)[len] = 0; - } else { - dest->len = 0; - dest->data = NULL; - } + if (data) { + dest->len = len; + dest->data = realloc(dest->data, len + 1); + memcpy(dest->data, data, len); + ((char*)dest->data)[len] = 0; + } else { + dest->len = 0; + dest->data = NULL; + } } static void puglSetDefaultHints(PuglHints hints) { - hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE; - hints[PUGL_CONTEXT_VERSION_MAJOR] = 2; - hints[PUGL_CONTEXT_VERSION_MINOR] = 0; - hints[PUGL_RED_BITS] = 8; - hints[PUGL_GREEN_BITS] = 8; - hints[PUGL_BLUE_BITS] = 8; - hints[PUGL_ALPHA_BITS] = 8; - hints[PUGL_DEPTH_BITS] = 0; - hints[PUGL_STENCIL_BITS] = 0; - hints[PUGL_SAMPLES] = 0; - hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE; - hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE; - hints[PUGL_RESIZABLE] = PUGL_FALSE; - hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE; - hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE; + hints[PUGL_USE_COMPAT_PROFILE] = PUGL_TRUE; + hints[PUGL_CONTEXT_VERSION_MAJOR] = 2; + hints[PUGL_CONTEXT_VERSION_MINOR] = 0; + hints[PUGL_RED_BITS] = 8; + hints[PUGL_GREEN_BITS] = 8; + hints[PUGL_BLUE_BITS] = 8; + hints[PUGL_ALPHA_BITS] = 8; + hints[PUGL_DEPTH_BITS] = 0; + hints[PUGL_STENCIL_BITS] = 0; + hints[PUGL_SAMPLES] = 0; + hints[PUGL_DOUBLE_BUFFER] = PUGL_TRUE; + hints[PUGL_SWAP_INTERVAL] = PUGL_DONT_CARE; + hints[PUGL_RESIZABLE] = PUGL_FALSE; + hints[PUGL_IGNORE_KEY_REPEAT] = PUGL_FALSE; + hints[PUGL_REFRESH_RATE] = PUGL_DONT_CARE; } PuglWorld* puglNewWorld(PuglWorldType type, PuglWorldFlags flags) { - PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); - if (!world || !(world->impl = puglInitWorldInternals(type, flags))) { - free(world); - return NULL; - } + PuglWorld* world = (PuglWorld*)calloc(1, sizeof(PuglWorld)); + if (!world || !(world->impl = puglInitWorldInternals(type, flags))) { + free(world); + return NULL; + } - world->startTime = puglGetTime(world); + world->startTime = puglGetTime(world); - puglSetString(&world->className, "Pugl"); + puglSetString(&world->className, "Pugl"); - return world; + return world; } void puglFreeWorld(PuglWorld* const world) { - puglFreeWorldInternals(world); - free(world->className); - free(world->views); - free(world); + puglFreeWorldInternals(world); + free(world->className); + free(world->views); + free(world); } void puglSetWorldHandle(PuglWorld* world, PuglWorldHandle handle) { - world->handle = handle; + world->handle = handle; } PuglWorldHandle puglGetWorldHandle(PuglWorld* world) { - return world->handle; + return world->handle; } PuglStatus puglSetClassName(PuglWorld* const world, const char* const name) { - puglSetString(&world->className, name); - return PUGL_SUCCESS; + puglSetString(&world->className, name); + return PUGL_SUCCESS; } PuglView* puglNewView(PuglWorld* const world) { - PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); - if (!view || !(view->impl = puglInitViewInternals())) { - free(view); - return NULL; - } + PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); + if (!view || !(view->impl = puglInitViewInternals())) { + free(view); + return NULL; + } - view->world = world; - view->minWidth = 1; - view->minHeight = 1; + view->world = world; + view->minWidth = 1; + view->minHeight = 1; - puglSetDefaultHints(view->hints); + puglSetDefaultHints(view->hints); - // Add to world view list - ++world->numViews; - world->views = (PuglView**)realloc(world->views, - world->numViews * sizeof(PuglView*)); + // Add to world view list + ++world->numViews; + world->views = + (PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*)); - world->views[world->numViews - 1] = view; + world->views[world->numViews - 1] = view; - return view; + return view; } void puglFreeView(PuglView* view) { - puglDispatchSimpleEvent(view, PUGL_DESTROY); - - // Remove from world view list - PuglWorld* world = view->world; - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i] == view) { - if (i == world->numViews - 1) { - world->views[i] = NULL; - } else { - memmove(world->views + i, world->views + i + 1, - sizeof(PuglView*) * (world->numViews - i - 1)); - world->views[world->numViews - 1] = NULL; - } - --world->numViews; - } - } - - free(view->title); - free(view->clipboard.data); - puglFreeViewInternals(view); - free(view); + puglDispatchSimpleEvent(view, PUGL_DESTROY); + + // Remove from world view list + PuglWorld* world = view->world; + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i] == view) { + if (i == world->numViews - 1) { + world->views[i] = NULL; + } else { + memmove(world->views + i, + world->views + i + 1, + sizeof(PuglView*) * (world->numViews - i - 1)); + world->views[world->numViews - 1] = NULL; + } + --world->numViews; + } + } + + free(view->title); + free(view->clipboard.data); + puglFreeViewInternals(view); + free(view); } PuglWorld* puglGetWorld(PuglView* view) { - return view->world; + return view->world; } PuglStatus puglSetViewHint(PuglView* view, PuglViewHint hint, int value) { - if (value == PUGL_DONT_CARE) { - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - case PUGL_USE_DEBUG_CONTEXT: - case PUGL_CONTEXT_VERSION_MAJOR: - case PUGL_CONTEXT_VERSION_MINOR: - case PUGL_SWAP_INTERVAL: - return PUGL_BAD_PARAMETER; - default: - break; - } - } + if (value == PUGL_DONT_CARE) { + switch (hint) { + case PUGL_USE_COMPAT_PROFILE: + case PUGL_USE_DEBUG_CONTEXT: + case PUGL_CONTEXT_VERSION_MAJOR: + case PUGL_CONTEXT_VERSION_MINOR: + case PUGL_SWAP_INTERVAL: + return PUGL_BAD_PARAMETER; + default: + break; + } + } - if (hint < PUGL_NUM_VIEW_HINTS) { - view->hints[hint] = value; - return PUGL_SUCCESS; - } + if (hint < PUGL_NUM_VIEW_HINTS) { + view->hints[hint] = value; + return PUGL_SUCCESS; + } - return PUGL_BAD_PARAMETER; + return PUGL_BAD_PARAMETER; } int puglGetViewHint(const PuglView* view, PuglViewHint hint) { - if (hint < PUGL_NUM_VIEW_HINTS) { - return view->hints[hint]; - } + if (hint < PUGL_NUM_VIEW_HINTS) { + return view->hints[hint]; + } - return PUGL_DONT_CARE; + return PUGL_DONT_CARE; } PuglStatus puglSetParentWindow(PuglView* view, PuglNativeView parent) { - view->parent = parent; - return PUGL_SUCCESS; + view->parent = parent; + return PUGL_SUCCESS; } PuglStatus puglSetBackend(PuglView* view, const PuglBackend* backend) { - view->backend = backend; - return PUGL_SUCCESS; + view->backend = backend; + return PUGL_SUCCESS; } void puglSetHandle(PuglView* view, PuglHandle handle) { - view->handle = handle; + view->handle = handle; } PuglHandle puglGetHandle(PuglView* view) { - return view->handle; + return view->handle; } bool puglGetVisible(const PuglView* view) { - return view->visible; + return view->visible; } PuglRect puglGetFrame(const PuglView* view) { - return view->frame; + return view->frame; } void* puglGetContext(PuglView* view) { - return view->backend->getContext(view); + return view->backend->getContext(view); } #ifndef PUGL_DISABLE_DEPRECATED @@ -275,25 +276,25 @@ puglGetContext(PuglView* view) PuglStatus puglPollEvents(PuglWorld* world, double timeout) { - return puglUpdate(world, timeout); + return puglUpdate(world, timeout); } PuglStatus puglDispatchEvents(PuglWorld* world) { - return puglUpdate(world, 0.0); + return puglUpdate(world, 0.0); } PuglStatus puglShowWindow(PuglView* view) { - return puglShow(view); + return puglShow(view); } PuglStatus puglHideWindow(PuglView* view) { - return puglHide(view); + return puglHide(view); } #endif @@ -301,112 +302,116 @@ puglHideWindow(PuglView* view) PuglStatus puglSetEventFunc(PuglView* view, PuglEventFunc eventFunc) { - view->eventFunc = eventFunc; - return PUGL_SUCCESS; + view->eventFunc = eventFunc; + return PUGL_SUCCESS; } /// Return the code point for buf, or the replacement character on error uint32_t puglDecodeUTF8(const uint8_t* buf) { -#define FAIL_IF(cond) do { if (cond) return 0xFFFD; } while (0) - - // http://en.wikipedia.org/wiki/UTF-8 - - if (buf[0] < 0x80) { - return buf[0]; - } else if (buf[0] < 0xC2) { - return 0xFFFD; - } else if (buf[0] < 0xE0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; - } else if (buf[0] < 0xF0) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); - FAIL_IF((buf[2] & 0xC0u) != 0x80); - return ((uint32_t)buf[0] << 12u) + // - ((uint32_t)buf[1] << 6u) + // - ((uint32_t)buf[2] - 0xE2080u); - } else if (buf[0] < 0xF5) { - FAIL_IF((buf[1] & 0xC0u) != 0x80); - FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); - FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); - FAIL_IF((buf[2] & 0xC0u) != 0x80u); - FAIL_IF((buf[3] & 0xC0u) != 0x80u); - return (((uint32_t)buf[0] << 18u) + // - ((uint32_t)buf[1] << 12u) + // - ((uint32_t)buf[2] << 6u) + // - ((uint32_t)buf[3] - 0x3C82080u)); - } - return 0xFFFD; +#define FAIL_IF(cond) \ + do { \ + if (cond) \ + return 0xFFFD; \ + } while (0) + + // http://en.wikipedia.org/wiki/UTF-8 + + if (buf[0] < 0x80) { + return buf[0]; + } else if (buf[0] < 0xC2) { + return 0xFFFD; + } else if (buf[0] < 0xE0) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + return ((uint32_t)buf[0] << 6u) + buf[1] - 0x3080u; + } else if (buf[0] < 0xF0) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); + FAIL_IF((buf[2] & 0xC0u) != 0x80); + return ((uint32_t)buf[0] << 12u) + // + ((uint32_t)buf[1] << 6u) + // + ((uint32_t)buf[2] - 0xE2080u); + } else if (buf[0] < 0xF5) { + FAIL_IF((buf[1] & 0xC0u) != 0x80); + FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); + FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); + FAIL_IF((buf[2] & 0xC0u) != 0x80u); + FAIL_IF((buf[3] & 0xC0u) != 0x80u); + return (((uint32_t)buf[0] << 18u) + // + ((uint32_t)buf[1] << 12u) + // + ((uint32_t)buf[2] << 6u) + // + ((uint32_t)buf[3] - 0x3C82080u)); + } + return 0xFFFD; } static inline bool puglMustConfigure(PuglView* view, const PuglEventConfigure* configure) { - return memcmp(configure, &view->lastConfigure, sizeof(PuglEventConfigure)); + return memcmp(configure, &view->lastConfigure, sizeof(PuglEventConfigure)); } void puglDispatchSimpleEvent(PuglView* view, const PuglEventType type) { - assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || - type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE || - type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); + assert(type == PUGL_CREATE || type == PUGL_DESTROY || type == PUGL_MAP || + type == PUGL_UNMAP || type == PUGL_UPDATE || type == PUGL_CLOSE || + type == PUGL_LOOP_ENTER || type == PUGL_LOOP_LEAVE); - const PuglEvent event = {{type, 0}}; - puglDispatchEvent(view, &event); + const PuglEvent event = {{type, 0}}; + puglDispatchEvent(view, &event); } void puglDispatchEventInContext(PuglView* view, const PuglEvent* event) { - if (event->type == PUGL_CONFIGURE) { - view->frame.x = event->configure.x; - view->frame.y = event->configure.y; - view->frame.width = event->configure.width; - view->frame.height = event->configure.height; - - if (puglMustConfigure(view, &event->configure)) { - view->eventFunc(view, event); - view->lastConfigure = event->configure; - } - } else if (event->type == PUGL_EXPOSE) { - if (event->expose.width > 0 && event->expose.height > 0) { - view->eventFunc(view, event); - } - } else { - view->eventFunc(view, event); - } + if (event->type == PUGL_CONFIGURE) { + view->frame.x = event->configure.x; + view->frame.y = event->configure.y; + view->frame.width = event->configure.width; + view->frame.height = event->configure.height; + + if (puglMustConfigure(view, &event->configure)) { + view->eventFunc(view, event); + view->lastConfigure = event->configure; + } + } else if (event->type == PUGL_EXPOSE) { + if (event->expose.width > 0 && event->expose.height > 0) { + view->eventFunc(view, event); + } + } else { + view->eventFunc(view, event); + } } void puglDispatchEvent(PuglView* view, const PuglEvent* event) { - switch (event->type) { - case PUGL_NOTHING: - break; - case PUGL_CREATE: - case PUGL_DESTROY: - view->backend->enter(view, NULL); - view->eventFunc(view, event); - view->backend->leave(view, NULL); - break; - case PUGL_CONFIGURE: - if (puglMustConfigure(view, &event->configure)) { - view->backend->enter(view, NULL); - puglDispatchEventInContext(view, event); - view->backend->leave(view, NULL); - } - break; - case PUGL_EXPOSE: - view->backend->enter(view, &event->expose); - puglDispatchEventInContext(view, event); - view->backend->leave(view, &event->expose); - break; - default: - view->eventFunc(view, event); - } + switch (event->type) { + case PUGL_NOTHING: + break; + case PUGL_CREATE: + case PUGL_DESTROY: + view->backend->enter(view, NULL); + view->eventFunc(view, event); + view->backend->leave(view, NULL); + break; + case PUGL_CONFIGURE: + if (puglMustConfigure(view, &event->configure)) { + view->backend->enter(view, NULL); + puglDispatchEventInContext(view, event); + view->backend->leave(view, NULL); + } + break; + case PUGL_EXPOSE: + view->backend->enter(view, &event->expose); + puglDispatchEventInContext(view, event); + view->backend->leave(view, &event->expose); + break; + default: + view->eventFunc(view, event); + } } const void* @@ -414,15 +419,15 @@ puglGetInternalClipboard(const PuglView* const view, const char** const type, size_t* const len) { - if (len) { - *len = view->clipboard.len; - } + if (len) { + *len = view->clipboard.len; + } - if (type) { - *type = "text/plain"; - } + if (type) { + *type = "text/plain"; + } - return view->clipboard.data; + return view->clipboard.data; } PuglStatus @@ -431,11 +436,10 @@ puglSetInternalClipboard(PuglView* const view, const void* const data, const size_t len) { - if (type && strcmp(type, "text/plain")) { - return PUGL_UNSUPPORTED_TYPE; - } + if (type && strcmp(type, "text/plain")) { + return PUGL_UNSUPPORTED_TYPE; + } - puglSetBlob(&view->clipboard, data, len); - return PUGL_SUCCESS; + puglSetBlob(&view->clipboard, data, len); + return PUGL_SUCCESS; } - @@ -38,18 +38,18 @@ @end struct PuglWorldInternalsImpl { - NSApplication* app; - NSAutoreleasePool* autoreleasePool; + NSApplication* app; + NSAutoreleasePool* autoreleasePool; }; struct PuglInternalsImpl { - NSApplication* app; - PuglWrapperView* wrapperView; - NSView* drawView; - NSCursor* cursor; - PuglWindow* window; - uint32_t mods; - bool mouseTracked; + NSApplication* app; + PuglWrapperView* wrapperView; + NSView* drawView; + NSCursor* cursor; + PuglWindow* window; + uint32_t mods; + bool mouseTracked; }; #endif // PUGL_DETAIL_MAC_H @@ -40,85 +40,85 @@ typedef NSUInteger NSWindowStyleMask; static NSRect rectToScreen(NSScreen* screen, NSRect rect) { - const double screenHeight = [screen frame].size.height; + const double screenHeight = [screen frame].size.height; - rect.origin.y = screenHeight - rect.origin.y - rect.size.height; - return rect; + rect.origin.y = screenHeight - rect.origin.y - rect.size.height; + return rect; } static NSScreen* viewScreen(PuglView* view) { - return view->impl->window ? [view->impl->window screen] : [NSScreen mainScreen]; + return view->impl->window ? [view->impl->window screen] + : [NSScreen mainScreen]; } static NSRect nsRectToPoints(PuglView* view, const NSRect rect) { - const double scaleFactor = [viewScreen(view) backingScaleFactor]; + const double scaleFactor = [viewScreen(view) backingScaleFactor]; - return NSMakeRect(rect.origin.x / scaleFactor, - rect.origin.y / scaleFactor, - rect.size.width / scaleFactor, - rect.size.height / scaleFactor); + return NSMakeRect(rect.origin.x / scaleFactor, + rect.origin.y / scaleFactor, + rect.size.width / scaleFactor, + rect.size.height / scaleFactor); } static NSRect nsRectFromPoints(PuglView* view, const NSRect rect) { - const double scaleFactor = [viewScreen(view) backingScaleFactor]; + const double scaleFactor = [viewScreen(view) backingScaleFactor]; - return NSMakeRect(rect.origin.x * scaleFactor, - rect.origin.y * scaleFactor, - rect.size.width * scaleFactor, - rect.size.height * scaleFactor); + return NSMakeRect(rect.origin.x * scaleFactor, + rect.origin.y * scaleFactor, + rect.size.width * scaleFactor, + rect.size.height * scaleFactor); } static NSPoint nsPointFromPoints(PuglView* view, const NSPoint point) { - const double scaleFactor = [viewScreen(view) backingScaleFactor]; + const double scaleFactor = [viewScreen(view) backingScaleFactor]; - return NSMakePoint(point.x * scaleFactor, point.y * scaleFactor); + return NSMakePoint(point.x * scaleFactor, point.y * scaleFactor); } static NSRect rectToNsRect(const PuglRect rect) { - return NSMakeRect(rect.x, rect.y, rect.width, rect.height); + return NSMakeRect(rect.x, rect.y, rect.width, rect.height); } static NSSize sizePoints(PuglView* view, const double width, const double height) { - const double scaleFactor = [viewScreen(view) backingScaleFactor]; + const double scaleFactor = [viewScreen(view) backingScaleFactor]; - return NSMakeSize(width / scaleFactor, height / scaleFactor); + return NSMakeSize(width / scaleFactor, height / scaleFactor); } static void updateViewRect(PuglView* view) { - NSWindow* const window = view->impl->window; - if (window) { - const NSRect screenFramePt = [[NSScreen mainScreen] frame]; - const NSRect screenFramePx = nsRectFromPoints(view, screenFramePt); - const NSRect framePt = [window frame]; - const NSRect contentPt = [window contentRectForFrameRect:framePt]; - const NSRect contentPx = nsRectFromPoints(view, contentPt); - const double screenHeight = screenFramePx.size.height; + NSWindow* const window = view->impl->window; + if (window) { + const NSRect screenFramePt = [[NSScreen mainScreen] frame]; + const NSRect screenFramePx = nsRectFromPoints(view, screenFramePt); + const NSRect framePt = [window frame]; + const NSRect contentPt = [window contentRectForFrameRect:framePt]; + const NSRect contentPx = nsRectFromPoints(view, contentPt); + const double screenHeight = screenFramePx.size.height; - view->frame.x = contentPx.origin.x; - view->frame.y = screenHeight - contentPx.origin.y - contentPx.size.height; - view->frame.width = contentPx.size.width; - view->frame.height = contentPx.size.height; - } + view->frame.x = contentPx.origin.x; + view->frame.y = screenHeight - contentPx.origin.y - contentPx.size.height; + view->frame.width = contentPx.size.width; + view->frame.height = contentPx.size.height; + } } -@implementation PuglWindow -{ +@implementation PuglWindow { @public - PuglView* puglview; + PuglView* puglview; } - (id)initWithContentRect:(NSRect)contentRect @@ -126,617 +126,638 @@ updateViewRect(PuglView* view) backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { - (void)flag; + (void)flag; - NSWindow* result = [super initWithContentRect:contentRect - styleMask:aStyle - backing:bufferingType - defer:NO]; + NSWindow* result = [super initWithContentRect:contentRect + styleMask:aStyle + backing:bufferingType + defer:NO]; - [result setAcceptsMouseMovedEvents:YES]; - return (PuglWindow*)result; + [result setAcceptsMouseMovedEvents:YES]; + return (PuglWindow*)result; } - (void)setPuglview:(PuglView*)view { - puglview = view; + puglview = view; - [self - setContentSize:sizePoints(view, view->frame.width, view->frame.height)]; + [self setContentSize:sizePoints(view, view->frame.width, view->frame.height)]; } - (BOOL)canBecomeKeyWindow { - return YES; + return YES; } - (BOOL)canBecomeMainWindow { - return YES; + return YES; } - (void)setIsVisible:(BOOL)flag { - if (flag && !puglview->visible) { - const PuglEventConfigure ev = { - PUGL_CONFIGURE, - 0, - puglview->frame.x, - puglview->frame.y, - puglview->frame.width, - puglview->frame.height, - }; + if (flag && !puglview->visible) { + const PuglEventConfigure ev = { + PUGL_CONFIGURE, + 0, + puglview->frame.x, + puglview->frame.y, + puglview->frame.width, + puglview->frame.height, + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - puglDispatchSimpleEvent(puglview, PUGL_MAP); - } else if (!flag && puglview->visible) { - puglDispatchSimpleEvent(puglview, PUGL_UNMAP); - } + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchSimpleEvent(puglview, PUGL_MAP); + } else if (!flag && puglview->visible) { + puglDispatchSimpleEvent(puglview, PUGL_UNMAP); + } - puglview->visible = flag; + puglview->visible = flag; - [super setIsVisible:flag]; + [super setIsVisible:flag]; } @end -@implementation PuglWrapperView -{ +@implementation PuglWrapperView { @public - PuglView* puglview; - NSTrackingArea* trackingArea; - NSMutableAttributedString* markedText; - NSMutableDictionary* userTimers; - bool reshaped; + PuglView* puglview; + NSTrackingArea* trackingArea; + NSMutableAttributedString* markedText; + NSMutableDictionary* userTimers; + bool reshaped; } - (void)dispatchExpose:(NSRect)rect { - const double scaleFactor = [[NSScreen mainScreen] backingScaleFactor]; + const double scaleFactor = [[NSScreen mainScreen] backingScaleFactor]; - if (reshaped) { - updateViewRect(puglview); + if (reshaped) { + updateViewRect(puglview); - const PuglEventConfigure ev = { - PUGL_CONFIGURE, - 0, - puglview->frame.x, - puglview->frame.y, - puglview->frame.width, - puglview->frame.height, - }; + const PuglEventConfigure ev = { + PUGL_CONFIGURE, + 0, + puglview->frame.x, + puglview->frame.y, + puglview->frame.width, + puglview->frame.height, + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - reshaped = false; - } + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + reshaped = false; + } - if (![[puglview->impl->drawView window] isVisible]) { - return; - } + if (![[puglview->impl->drawView window] isVisible]) { + return; + } - const PuglEventExpose ev = { - PUGL_EXPOSE, - 0, - rect.origin.x * scaleFactor, - rect.origin.y * scaleFactor, - rect.size.width * scaleFactor, - rect.size.height * scaleFactor, - }; + const PuglEventExpose ev = { + PUGL_EXPOSE, + 0, + rect.origin.x * scaleFactor, + rect.origin.y * scaleFactor, + rect.size.width * scaleFactor, + rect.size.height * scaleFactor, + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (NSSize)intrinsicContentSize { - if (puglview->defaultWidth || puglview->defaultHeight) { - return sizePoints(puglview, - puglview->defaultWidth, - puglview->defaultHeight); - } + if (puglview->defaultWidth || puglview->defaultHeight) { + return sizePoints( + puglview, puglview->defaultWidth, puglview->defaultHeight); + } - return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); + return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); } - (BOOL)isFlipped { - return YES; + return YES; } - (BOOL)acceptsFirstResponder { - return YES; + return YES; } - (void)setReshaped { - reshaped = true; + reshaped = true; } static uint32_t getModifiers(const NSEvent* const ev) { - const NSEventModifierFlags modifierFlags = [ev modifierFlags]; + const NSEventModifierFlags modifierFlags = [ev modifierFlags]; - return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) | - ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) | - ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) | - ((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0)); + return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) | + ((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) | + ((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) | + ((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0)); } static PuglKey keySymToSpecial(const NSEvent* const ev) { - NSString* chars = [ev charactersIgnoringModifiers]; - if ([chars length] == 1) { - switch ([chars characterAtIndex:0]) { - case NSF1FunctionKey: return PUGL_KEY_F1; - case NSF2FunctionKey: return PUGL_KEY_F2; - case NSF3FunctionKey: return PUGL_KEY_F3; - case NSF4FunctionKey: return PUGL_KEY_F4; - case NSF5FunctionKey: return PUGL_KEY_F5; - case NSF6FunctionKey: return PUGL_KEY_F6; - case NSF7FunctionKey: return PUGL_KEY_F7; - case NSF8FunctionKey: return PUGL_KEY_F8; - case NSF9FunctionKey: return PUGL_KEY_F9; - case NSF10FunctionKey: return PUGL_KEY_F10; - case NSF11FunctionKey: return PUGL_KEY_F11; - case NSF12FunctionKey: return PUGL_KEY_F12; - case NSDeleteCharacter: return PUGL_KEY_BACKSPACE; - case NSDeleteFunctionKey: return PUGL_KEY_DELETE; - case NSLeftArrowFunctionKey: return PUGL_KEY_LEFT; - case NSUpArrowFunctionKey: return PUGL_KEY_UP; - case NSRightArrowFunctionKey: return PUGL_KEY_RIGHT; - case NSDownArrowFunctionKey: return PUGL_KEY_DOWN; - case NSPageUpFunctionKey: return PUGL_KEY_PAGE_UP; - case NSPageDownFunctionKey: return PUGL_KEY_PAGE_DOWN; - case NSHomeFunctionKey: return PUGL_KEY_HOME; - case NSEndFunctionKey: return PUGL_KEY_END; - case NSInsertFunctionKey: return PUGL_KEY_INSERT; - case NSMenuFunctionKey: return PUGL_KEY_MENU; - case NSScrollLockFunctionKey: return PUGL_KEY_SCROLL_LOCK; - case NSClearLineFunctionKey: return PUGL_KEY_NUM_LOCK; - case NSPrintScreenFunctionKey: return PUGL_KEY_PRINT_SCREEN; - case NSPauseFunctionKey: return PUGL_KEY_PAUSE; - } - // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged] - } - return (PuglKey)0; + NSString* chars = [ev charactersIgnoringModifiers]; + if ([chars length] == 1) { + switch ([chars characterAtIndex:0]) { + case NSF1FunctionKey: + return PUGL_KEY_F1; + case NSF2FunctionKey: + return PUGL_KEY_F2; + case NSF3FunctionKey: + return PUGL_KEY_F3; + case NSF4FunctionKey: + return PUGL_KEY_F4; + case NSF5FunctionKey: + return PUGL_KEY_F5; + case NSF6FunctionKey: + return PUGL_KEY_F6; + case NSF7FunctionKey: + return PUGL_KEY_F7; + case NSF8FunctionKey: + return PUGL_KEY_F8; + case NSF9FunctionKey: + return PUGL_KEY_F9; + case NSF10FunctionKey: + return PUGL_KEY_F10; + case NSF11FunctionKey: + return PUGL_KEY_F11; + case NSF12FunctionKey: + return PUGL_KEY_F12; + case NSDeleteCharacter: + return PUGL_KEY_BACKSPACE; + case NSDeleteFunctionKey: + return PUGL_KEY_DELETE; + case NSLeftArrowFunctionKey: + return PUGL_KEY_LEFT; + case NSUpArrowFunctionKey: + return PUGL_KEY_UP; + case NSRightArrowFunctionKey: + return PUGL_KEY_RIGHT; + case NSDownArrowFunctionKey: + return PUGL_KEY_DOWN; + case NSPageUpFunctionKey: + return PUGL_KEY_PAGE_UP; + case NSPageDownFunctionKey: + return PUGL_KEY_PAGE_DOWN; + case NSHomeFunctionKey: + return PUGL_KEY_HOME; + case NSEndFunctionKey: + return PUGL_KEY_END; + case NSInsertFunctionKey: + return PUGL_KEY_INSERT; + case NSMenuFunctionKey: + return PUGL_KEY_MENU; + case NSScrollLockFunctionKey: + return PUGL_KEY_SCROLL_LOCK; + case NSClearLineFunctionKey: + return PUGL_KEY_NUM_LOCK; + case NSPrintScreenFunctionKey: + return PUGL_KEY_PRINT_SCREEN; + case NSPauseFunctionKey: + return PUGL_KEY_PAUSE; + } + // SHIFT, CTRL, ALT, and SUPER are handled in [flagsChanged] + } + return (PuglKey)0; } - (void)updateTrackingAreas { - if (trackingArea != nil) { - [self removeTrackingArea:trackingArea]; - [trackingArea release]; - } + if (trackingArea != nil) { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } - const int opts = (NSTrackingMouseEnteredAndExited | - NSTrackingMouseMoved | - NSTrackingActiveAlways); - trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] - options:opts - owner:self - userInfo:nil]; - [self addTrackingArea:trackingArea]; - [super updateTrackingAreas]; + const int opts = (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | + NSTrackingActiveAlways); + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:opts + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; } - (NSPoint)eventLocation:(NSEvent*)event { - return nsPointFromPoints(puglview, - [self convertPoint:[event locationInWindow] - fromView:nil]); + return nsPointFromPoints( + puglview, [self convertPoint:[event locationInWindow] fromView:nil]); } static void handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) { - const NSPoint wloc = [view eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventCrossing ev = { - type, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - PUGL_CROSSING_NORMAL, - }; + const NSPoint wloc = [view eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglEventCrossing ev = { + type, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + PUGL_CROSSING_NORMAL, + }; - puglDispatchEvent(view->puglview, (const PuglEvent*)&ev); + puglDispatchEvent(view->puglview, (const PuglEvent*)&ev); } - (void)mouseEntered:(NSEvent*)event { - handleCrossing(self, event, PUGL_POINTER_IN); - [puglview->impl->cursor set]; - puglview->impl->mouseTracked = true; + handleCrossing(self, event, PUGL_POINTER_IN); + [puglview->impl->cursor set]; + puglview->impl->mouseTracked = true; } - (void)mouseExited:(NSEvent*)event { - [[NSCursor arrowCursor] set]; - handleCrossing(self, event, PUGL_POINTER_OUT); - puglview->impl->mouseTracked = false; + [[NSCursor arrowCursor] set]; + handleCrossing(self, event, PUGL_POINTER_OUT); + puglview->impl->mouseTracked = false; } - (void)cursorUpdate:(NSEvent*)event { - (void)event; - [puglview->impl->cursor set]; + (void)event; + [puglview->impl->cursor set]; } - (void)mouseMoved:(NSEvent*)event { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventMotion ev = { - PUGL_MOTION, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - }; + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglEventMotion ev = { + PUGL_MOTION, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (void)mouseDragged:(NSEvent*)event { - [self mouseMoved: event]; + [self mouseMoved:event]; } - (void)rightMouseDragged:(NSEvent*)event { - [self mouseMoved: event]; + [self mouseMoved:event]; } - (void)otherMouseDragged:(NSEvent*)event { - [self mouseMoved: event]; + [self mouseMoved:event]; } - (void)mouseDown:(NSEvent*)event { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventButton ev = { - PUGL_BUTTON_PRESS, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - (uint32_t)[event buttonNumber] + 1, - }; + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglEventButton ev = { + PUGL_BUTTON_PRESS, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + (uint32_t)[event buttonNumber] + 1, + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (void)mouseUp:(NSEvent*)event { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglEventButton ev = { - PUGL_BUTTON_RELEASE, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - (uint32_t)[event buttonNumber] + 1, - }; + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglEventButton ev = { + PUGL_BUTTON_RELEASE, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + (uint32_t)[event buttonNumber] + 1, + }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (void)rightMouseDown:(NSEvent*)event { - [self mouseDown: event]; + [self mouseDown:event]; } - (void)rightMouseUp:(NSEvent*)event { - [self mouseUp: event]; + [self mouseUp:event]; } - (void)otherMouseDown:(NSEvent*)event { - [self mouseDown: event]; + [self mouseDown:event]; } - (void)otherMouseUp:(NSEvent*)event { - [self mouseUp: event]; + [self mouseUp:event]; } - (void)scrollWheel:(NSEvent*)event { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const double dx = [event scrollingDeltaX]; - const double dy = [event scrollingDeltaY]; - const PuglScrollDirection dir = - ((dx == 0.0 && dy > 0.0) - ? PUGL_SCROLL_UP - : ((dx == 0.0 && dy < 0.0) - ? PUGL_SCROLL_DOWN - : ((dy == 0.0 && dx > 0.0) - ? PUGL_SCROLL_RIGHT - : ((dy == 0.0 && dx < 0.0) ? PUGL_SCROLL_LEFT - : PUGL_SCROLL_SMOOTH)))); - - const PuglEventScroll ev = { - PUGL_SCROLL, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir, - dx, - dy, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const double dx = [event scrollingDeltaX]; + const double dy = [event scrollingDeltaY]; + const PuglScrollDirection dir = + ((dx == 0.0 && dy > 0.0) + ? PUGL_SCROLL_UP + : ((dx == 0.0 && dy < 0.0) + ? PUGL_SCROLL_DOWN + : ((dy == 0.0 && dx > 0.0) + ? PUGL_SCROLL_RIGHT + : ((dy == 0.0 && dx < 0.0) ? PUGL_SCROLL_LEFT + : PUGL_SCROLL_SMOOTH)))); + + const PuglEventScroll ev = { + PUGL_SCROLL, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + [event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir, + dx, + dy, + }; + + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (void)keyDown:(NSEvent*)event { - if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) { - return; - } - - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglKey spec = keySymToSpecial(event); - const NSString* chars = [event charactersIgnoringModifiers]; - const char* str = [[chars lowercaseString] UTF8String]; - const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); - - const PuglEventKey ev = { - PUGL_KEY_PRESS, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - (code != 0xFFFD) ? code : 0, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - - if (!spec) { - [self interpretKeyEvents:@[event]]; - } + if (puglview->hints[PUGL_IGNORE_KEY_REPEAT] && [event isARepeat]) { + return; + } + + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglKey spec = keySymToSpecial(event); + const NSString* chars = [event charactersIgnoringModifiers]; + const char* str = [[chars lowercaseString] UTF8String]; + const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); + + const PuglEventKey ev = { + PUGL_KEY_PRESS, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + [event keyCode], + (code != 0xFFFD) ? code : 0, + }; + + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + + if (!spec) { + [self interpretKeyEvents:@[event]]; + } } - (void)keyUp:(NSEvent*)event { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - const PuglKey spec = keySymToSpecial(event); - const NSString* chars = [event charactersIgnoringModifiers]; - const char* str = [[chars lowercaseString] UTF8String]; - const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); - - const PuglEventKey ev = { - PUGL_KEY_RELEASE, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - (code != 0xFFFD) ? code : 0, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + const PuglKey spec = keySymToSpecial(event); + const NSString* chars = [event charactersIgnoringModifiers]; + const char* str = [[chars lowercaseString] UTF8String]; + const uint32_t code = (spec ? spec : puglDecodeUTF8((const uint8_t*)str)); + + const PuglEventKey ev = { + PUGL_KEY_RELEASE, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + [event keyCode], + (code != 0xFFFD) ? code : 0, + }; + + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (BOOL)hasMarkedText { - return [markedText length] > 0; + return [markedText length] > 0; } - (NSRange)markedRange { - return (([markedText length] > 0) - ? NSMakeRange(0, [markedText length] - 1) - : NSMakeRange(NSNotFound, 0)); + return (([markedText length] > 0) ? NSMakeRange(0, [markedText length] - 1) + : NSMakeRange(NSNotFound, 0)); } - (NSRange)selectedRange { - return NSMakeRange(NSNotFound, 0); + return NSMakeRange(NSNotFound, 0); } - (void)setMarkedText:(id)string selectedRange:(NSRange)selected replacementRange:(NSRange)replacement { - (void)selected; - (void)replacement; - [markedText release]; - markedText = ( - [(NSObject*)string isKindOfClass:[NSAttributedString class]] - ? [[NSMutableAttributedString alloc] initWithAttributedString:string] - : [[NSMutableAttributedString alloc] initWithString:string]); + (void)selected; + (void)replacement; + [markedText release]; + markedText = + ([(NSObject*)string isKindOfClass:[NSAttributedString class]] + ? [[NSMutableAttributedString alloc] initWithAttributedString:string] + : [[NSMutableAttributedString alloc] initWithString:string]); } - (void)unmarkText { - [[markedText mutableString] setString:@""]; + [[markedText mutableString] setString:@""]; } - (NSArray*)validAttributesForMarkedText { - return @[]; + return @[]; } - (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange: - (NSRangePointer)actual + (NSRangePointer)actual { - (void)range; - (void)actual; - return nil; + (void)range; + (void)actual; + return nil; } - (NSUInteger)characterIndexForPoint:(NSPoint)point { - (void)point; - return 0; + (void)point; + return 0; } - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actual { - (void)range; - (void)actual; + (void)range; + (void)actual; - const NSRect frame = [self bounds]; - return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0); + const NSRect frame = [self bounds]; + return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0); } - (void)doCommandBySelector:(SEL)selector { - (void)selector; + (void)selector; } - (void)insertText:(id)string replacementRange:(NSRange)replacement { - (void)replacement; - - NSEvent* const event = [NSApp currentEvent]; - NSString* const characters = - ([(NSObject*)string isKindOfClass:[NSAttributedString class]] - ? [(NSAttributedString*)string string] - : (NSString*)string); - - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - for (size_t i = 0; i < [characters length]; ++i) { - const uint32_t code = [characters characterAtIndex:i]; - char utf8[8] = {0}; - NSUInteger len = 0; - - [characters getBytes:utf8 - maxLength:sizeof(utf8) - usedLength:&len - encoding:NSUTF8StringEncoding - options:0 - range:NSMakeRange(i, i + 1) - remainingRange:nil]; - - PuglEventText ev = { - PUGL_TEXT, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - getModifiers(event), - [event keyCode], - code, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - }; - - memcpy(ev.string, utf8, len); - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - } + (void)replacement; + + NSEvent* const event = [NSApp currentEvent]; + NSString* const characters = + ([(NSObject*)string isKindOfClass:[NSAttributedString class]] + ? [(NSAttributedString*)string string] + : (NSString*)string); + + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + for (size_t i = 0; i < [characters length]; ++i) { + const uint32_t code = [characters characterAtIndex:i]; + char utf8[8] = {0}; + NSUInteger len = 0; + + [characters getBytes:utf8 + maxLength:sizeof(utf8) + usedLength:&len + encoding:NSUTF8StringEncoding + options:0 + range:NSMakeRange(i, i + 1) + remainingRange:nil]; + + PuglEventText ev = { + PUGL_TEXT, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + getModifiers(event), + [event keyCode], + code, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + }; + + memcpy(ev.string, utf8, len); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + } } - (void)flagsChanged:(NSEvent*)event { - const uint32_t mods = getModifiers(event); - PuglEventType type = PUGL_NOTHING; - PuglKey special = (PuglKey)0; - - if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) { - type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_SHIFT; - } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) { - type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_CTRL; - } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) { - type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_ALT; - } else if ((mods & PUGL_MOD_SUPER) != (puglview->impl->mods & PUGL_MOD_SUPER)) { - type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - special = PUGL_KEY_SUPER; - } - - if (special != 0) { - const NSPoint wloc = [self eventLocation:event]; - const NSPoint rloc = [NSEvent mouseLocation]; - PuglEventKey ev = { - type, - 0, - [event timestamp], - wloc.x, - wloc.y, - rloc.x, - [[NSScreen mainScreen] frame].size.height - rloc.y, - mods, - [event keyCode], - special - }; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); - } - - puglview->impl->mods = mods; + const uint32_t mods = getModifiers(event); + PuglEventType type = PUGL_NOTHING; + PuglKey special = (PuglKey)0; + + if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) { + type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + special = PUGL_KEY_SHIFT; + } else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) { + type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + special = PUGL_KEY_CTRL; + } else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) { + type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + special = PUGL_KEY_ALT; + } else if ((mods & PUGL_MOD_SUPER) != + (puglview->impl->mods & PUGL_MOD_SUPER)) { + type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + special = PUGL_KEY_SUPER; + } + + if (special != 0) { + const NSPoint wloc = [self eventLocation:event]; + const NSPoint rloc = [NSEvent mouseLocation]; + PuglEventKey ev = {type, + 0, + [event timestamp], + wloc.x, + wloc.y, + rloc.x, + [[NSScreen mainScreen] frame].size.height - rloc.y, + mods, + [event keyCode], + special}; + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + } + + puglview->impl->mods = mods; } - (BOOL)preservesContentInLiveResize { - return NO; + return NO; } - (void)viewWillStartLiveResize { - puglDispatchSimpleEvent(puglview, PUGL_LOOP_ENTER); + puglDispatchSimpleEvent(puglview, PUGL_LOOP_ENTER); } - (void)viewWillDraw { - puglDispatchSimpleEvent(puglview, PUGL_UPDATE); - [super viewWillDraw]; + puglDispatchSimpleEvent(puglview, PUGL_UPDATE); + [super viewWillDraw]; } - (void)resizeTick { - puglPostRedisplay(puglview); + puglPostRedisplay(puglview); } - (void)timerTick:(NSTimer*)userTimer { - const NSNumber* userInfo = userTimer.userInfo; - const PuglEventTimer ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue}; + const NSNumber* userInfo = userTimer.userInfo; + const PuglEventTimer ev = {PUGL_TIMER, 0, userInfo.unsignedLongValue}; - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + puglDispatchEvent(puglview, (const PuglEvent*)&ev); } - (void)viewDidEndLiveResize { - puglDispatchSimpleEvent(puglview, PUGL_LOOP_LEAVE); + puglDispatchSimpleEvent(puglview, PUGL_LOOP_LEAVE); } @end @@ -747,51 +768,50 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) @end -@implementation PuglWindowDelegate -{ - PuglWindow* window; +@implementation PuglWindowDelegate { + PuglWindow* window; } - (instancetype)initWithPuglWindow:(PuglWindow*)puglWindow { - if ((self = [super init])) { - window = puglWindow; - } + if ((self = [super init])) { + window = puglWindow; + } - return self; + return self; } - (BOOL)windowShouldClose:(id)sender { - (void)sender; + (void)sender; - puglDispatchSimpleEvent(window->puglview, PUGL_CLOSE); - return YES; + puglDispatchSimpleEvent(window->puglview, PUGL_CLOSE); + return YES; } - (void)windowDidMove:(NSNotification*)notification { - (void)notification; + (void)notification; - updateViewRect(window->puglview); + updateViewRect(window->puglview); } - (void)windowDidBecomeKey:(NSNotification*)notification { - (void)notification; + (void)notification; - PuglEvent ev = {{PUGL_FOCUS_IN, 0}}; - ev.focus.mode = PUGL_CROSSING_NORMAL; - puglDispatchEvent(window->puglview, &ev); + PuglEvent ev = {{PUGL_FOCUS_IN, 0}}; + ev.focus.mode = PUGL_CROSSING_NORMAL; + puglDispatchEvent(window->puglview, &ev); } - (void)windowDidResignKey:(NSNotification*)notification { - (void)notification; + (void)notification; - PuglEvent ev = {{PUGL_FOCUS_OUT, 0}}; - ev.focus.mode = PUGL_CROSSING_NORMAL; - puglDispatchEvent(window->puglview, &ev); + PuglEvent ev = {{PUGL_FOCUS_OUT, 0}}; + ev.focus.mode = PUGL_CROSSING_NORMAL; + puglDispatchEvent(window->puglview, &ev); } @end @@ -799,532 +819,526 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) PuglWorldInternals* puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags)) { - PuglWorldInternals* impl = (PuglWorldInternals*)calloc( - 1, sizeof(PuglWorldInternals)); + PuglWorldInternals* impl = + (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); - impl->app = [NSApplication sharedApplication]; + impl->app = [NSApplication sharedApplication]; - if (type == PUGL_PROGRAM) { - impl->autoreleasePool = [NSAutoreleasePool new]; - } + if (type == PUGL_PROGRAM) { + impl->autoreleasePool = [NSAutoreleasePool new]; + } - return impl; + return impl; } void puglFreeWorldInternals(PuglWorld* world) { - if (world->impl->autoreleasePool) { - [world->impl->autoreleasePool drain]; - } + if (world->impl->autoreleasePool) { + [world->impl->autoreleasePool drain]; + } - free(world->impl); + free(world->impl); } void* puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world)) { - return NULL; + return NULL; } PuglInternals* puglInitViewInternals(void) { - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); - impl->cursor = [NSCursor arrowCursor]; + impl->cursor = [NSCursor arrowCursor]; - return impl; + return impl; } static NSLayoutConstraint* puglConstraint(id item, NSLayoutAttribute attribute, float constant) { - return [NSLayoutConstraint - constraintWithItem: item - attribute: attribute - relatedBy: NSLayoutRelationGreaterThanOrEqual - toItem: nil - attribute: NSLayoutAttributeNotAnAttribute - multiplier: 1.0 - constant: (CGFloat)constant]; + return + [NSLayoutConstraint constraintWithItem:item + attribute:attribute + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:(CGFloat)constant]; } PuglStatus puglRealize(PuglView* view) { - PuglInternals* impl = view->impl; - if (impl->wrapperView) { - return PUGL_FAILURE; - } - - const NSScreen* const screen = [NSScreen mainScreen]; - const double scaleFactor = [screen backingScaleFactor]; - - // Getting depth from the display mode seems tedious, just set usual values - if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_RED_BITS] = 8; - } - if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_BLUE_BITS] = 8; - } - if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_GREEN_BITS] = 8; - } - if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_ALPHA_BITS] = 8; - } - - CGDirectDisplayID displayId = CGMainDisplayID(); - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); - - // Try to get refresh rate from mode (usually fails) - view->hints[PUGL_REFRESH_RATE] = (int)CGDisplayModeGetRefreshRate(mode); - - CGDisplayModeRelease(mode); - if (view->hints[PUGL_REFRESH_RATE] == 0) { - // Get refresh rate from a display link - // TODO: Keep and actually use the display link for something? - CVDisplayLinkRef link; - CVDisplayLinkCreateWithCGDisplay(displayId, &link); - - const CVTime p = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - const double r = p.timeScale / (double)p.timeValue; - view->hints[PUGL_REFRESH_RATE] = (int)lrint(r); - - CVDisplayLinkRelease(link); - } - - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - const double screenWidthPx = [screen frame].size.width * scaleFactor; - const double screenHeightPx = [screen frame].size.height * scaleFactor; - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0; - } - - const NSRect framePx = rectToNsRect(view->frame); - const NSRect framePt = NSMakeRect(framePx.origin.x / scaleFactor, - framePx.origin.y / scaleFactor, - framePx.size.width / scaleFactor, - framePx.size.height / scaleFactor); - - // Create wrapper view to handle input - impl->wrapperView = [PuglWrapperView alloc]; - impl->wrapperView->puglview = view; - impl->wrapperView->userTimers = [[NSMutableDictionary alloc] init]; - impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init]; - [impl->wrapperView setAutoresizesSubviews:YES]; - [impl->wrapperView initWithFrame:framePt]; - [impl->wrapperView addConstraint: - puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->minWidth)]; - [impl->wrapperView addConstraint: - puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, view->minHeight)]; - - // Create draw view to be rendered to - PuglStatus st = PUGL_SUCCESS; - if ((st = view->backend->configure(view)) || - (st = view->backend->create(view))) { - return st; - } - - // Add draw view to wrapper view - [impl->wrapperView addSubview:impl->drawView]; - [impl->wrapperView setHidden:NO]; - [impl->drawView setHidden:NO]; - - if (view->parent) { - NSView* pview = (NSView*)view->parent; - [pview addSubview:impl->wrapperView]; - [impl->drawView setHidden:NO]; - [[impl->drawView window] makeFirstResponder:impl->wrapperView]; - } else { - unsigned style = (NSClosableWindowMask | - NSTitledWindowMask | - NSMiniaturizableWindowMask ); - if (view->hints[PUGL_RESIZABLE]) { - style |= NSResizableWindowMask; - } - - PuglWindow* window = [[[PuglWindow alloc] - initWithContentRect:rectToScreen([NSScreen mainScreen], framePt) - styleMask:style - backing:NSBackingStoreBuffered - defer:NO - ] retain]; - [window setPuglview:view]; - - if (view->title) { - NSString* titleString = [[NSString alloc] - initWithBytes:view->title - length:strlen(view->title) - encoding:NSUTF8StringEncoding]; - - [window setTitle:titleString]; - } - - if (view->minWidth || view->minHeight) { - [window setContentMinSize:sizePoints(view, - view->minWidth, - view->minHeight)]; - } - impl->window = window; - - ((NSWindow*)window).delegate = [[PuglWindowDelegate alloc] - initWithPuglWindow:window]; - - if (view->minAspectX && view->minAspectY) { - [window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } - - puglSetFrame(view, view->frame); - - [window setContentView:impl->wrapperView]; - [view->world->impl->app activateIgnoringOtherApps:YES]; - [window makeFirstResponder:impl->wrapperView]; - [window makeKeyAndOrderFront:window]; - [impl->window setIsVisible:NO]; - } - - [impl->wrapperView updateTrackingAreas]; - - puglDispatchSimpleEvent(view, PUGL_CREATE); - - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + if (impl->wrapperView) { + return PUGL_FAILURE; + } + + const NSScreen* const screen = [NSScreen mainScreen]; + const double scaleFactor = [screen backingScaleFactor]; + + // Getting depth from the display mode seems tedious, just set usual values + if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_RED_BITS] = 8; + } + if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_BLUE_BITS] = 8; + } + if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_GREEN_BITS] = 8; + } + if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_ALPHA_BITS] = 8; + } + + CGDirectDisplayID displayId = CGMainDisplayID(); + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + + // Try to get refresh rate from mode (usually fails) + view->hints[PUGL_REFRESH_RATE] = (int)CGDisplayModeGetRefreshRate(mode); + + CGDisplayModeRelease(mode); + if (view->hints[PUGL_REFRESH_RATE] == 0) { + // Get refresh rate from a display link + // TODO: Keep and actually use the display link for something? + CVDisplayLinkRef link; + CVDisplayLinkCreateWithCGDisplay(displayId, &link); + + const CVTime p = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); + const double r = p.timeScale / (double)p.timeValue; + view->hints[PUGL_REFRESH_RATE] = (int)lrint(r); + + CVDisplayLinkRelease(link); + } + + if (view->frame.width == 0.0 && view->frame.height == 0.0) { + if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { + return PUGL_BAD_CONFIGURATION; + } + + const double screenWidthPx = [screen frame].size.width * scaleFactor; + const double screenHeightPx = [screen frame].size.height * scaleFactor; + + view->frame.width = view->defaultWidth; + view->frame.height = view->defaultHeight; + view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0; + view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0; + } + + const NSRect framePx = rectToNsRect(view->frame); + const NSRect framePt = NSMakeRect(framePx.origin.x / scaleFactor, + framePx.origin.y / scaleFactor, + framePx.size.width / scaleFactor, + framePx.size.height / scaleFactor); + + // Create wrapper view to handle input + impl->wrapperView = [PuglWrapperView alloc]; + impl->wrapperView->puglview = view; + impl->wrapperView->userTimers = [[NSMutableDictionary alloc] init]; + impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init]; + [impl->wrapperView setAutoresizesSubviews:YES]; + [impl->wrapperView initWithFrame:framePt]; + [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeWidth, + view->minWidth)]; + [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, + NSLayoutAttributeHeight, + view->minHeight)]; + + // Create draw view to be rendered to + PuglStatus st = PUGL_SUCCESS; + if ((st = view->backend->configure(view)) || + (st = view->backend->create(view))) { + return st; + } + + // Add draw view to wrapper view + [impl->wrapperView addSubview:impl->drawView]; + [impl->wrapperView setHidden:NO]; + [impl->drawView setHidden:NO]; + + if (view->parent) { + NSView* pview = (NSView*)view->parent; + [pview addSubview:impl->wrapperView]; + [impl->drawView setHidden:NO]; + [[impl->drawView window] makeFirstResponder:impl->wrapperView]; + } else { + unsigned style = + (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask); + if (view->hints[PUGL_RESIZABLE]) { + style |= NSResizableWindowMask; + } + + PuglWindow* window = [[[PuglWindow alloc] + initWithContentRect:rectToScreen([NSScreen mainScreen], framePt) + styleMask:style + backing:NSBackingStoreBuffered + defer:NO] retain]; + [window setPuglview:view]; + + if (view->title) { + NSString* titleString = + [[NSString alloc] initWithBytes:view->title + length:strlen(view->title) + encoding:NSUTF8StringEncoding]; + + [window setTitle:titleString]; + } + + if (view->minWidth || view->minHeight) { + [window + setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; + } + impl->window = window; + + ((NSWindow*)window).delegate = + [[PuglWindowDelegate alloc] initWithPuglWindow:window]; + + if (view->minAspectX && view->minAspectY) { + [window setContentAspectRatio:sizePoints(view, + view->minAspectX, + view->minAspectY)]; + } + + puglSetFrame(view, view->frame); + + [window setContentView:impl->wrapperView]; + [view->world->impl->app activateIgnoringOtherApps:YES]; + [window makeFirstResponder:impl->wrapperView]; + [window makeKeyAndOrderFront:window]; + [impl->window setIsVisible:NO]; + } + + [impl->wrapperView updateTrackingAreas]; + + puglDispatchSimpleEvent(view, PUGL_CREATE); + + return PUGL_SUCCESS; } PuglStatus puglShow(PuglView* view) { - if (!view->impl->wrapperView) { - const PuglStatus st = puglRealize(view); - if (st) { - return st; - } - } + if (!view->impl->wrapperView) { + const PuglStatus st = puglRealize(view); + if (st) { + return st; + } + } - if (![view->impl->window isVisible]) { - [view->impl->window setIsVisible:YES]; - [view->impl->drawView setNeedsDisplay: YES]; - updateViewRect(view); - } + if (![view->impl->window isVisible]) { + [view->impl->window setIsVisible:YES]; + [view->impl->drawView setNeedsDisplay:YES]; + updateViewRect(view); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglHide(PuglView* view) { - [view->impl->window setIsVisible:NO]; - return PUGL_SUCCESS; + [view->impl->window setIsVisible:NO]; + return PUGL_SUCCESS; } void puglFreeViewInternals(PuglView* view) { - if (view) { - if (view->backend) { - view->backend->destroy(view); - } - - if (view->impl) { - [view->impl->wrapperView removeFromSuperview]; - view->impl->wrapperView->puglview = NULL; - if (view->impl->window) { - [view->impl->window close]; - } - [view->impl->wrapperView release]; - if (view->impl->window) { - [view->impl->window release]; - } - free(view->impl); - } - } + if (view) { + if (view->backend) { + view->backend->destroy(view); + } + + if (view->impl) { + [view->impl->wrapperView removeFromSuperview]; + view->impl->wrapperView->puglview = NULL; + if (view->impl->window) { + [view->impl->window close]; + } + [view->impl->wrapperView release]; + if (view->impl->window) { + [view->impl->window release]; + } + free(view->impl); + } + } } PuglStatus puglGrabFocus(PuglView* view) { - NSWindow* window = [view->impl->wrapperView window]; + NSWindow* window = [view->impl->wrapperView window]; - [window makeKeyWindow]; - [window makeFirstResponder:view->impl->wrapperView]; - return PUGL_SUCCESS; + [window makeKeyWindow]; + [window makeFirstResponder:view->impl->wrapperView]; + return PUGL_SUCCESS; } bool puglHasFocus(const PuglView* view) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; - return ([[impl->wrapperView window] isKeyWindow] && - [[impl->wrapperView window] firstResponder] == impl->wrapperView); + return ([[impl->wrapperView window] isKeyWindow] && + [[impl->wrapperView window] firstResponder] == impl->wrapperView); } PuglStatus puglRequestAttention(PuglView* view) { - if (![view->impl->window isKeyWindow]) { - [view->world->impl->app requestUserAttention:NSInformationalRequest]; - } + if (![view->impl->window isKeyWindow]) { + [view->world->impl->app requestUserAttention:NSInformationalRequest]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglStartTimer(PuglView* view, uintptr_t id, double timeout) { - puglStopTimer(view, id); + puglStopTimer(view, id); - NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; + NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; - NSTimer* timer = [NSTimer timerWithTimeInterval:timeout - target:view->impl->wrapperView - selector:@selector(timerTick:) - userInfo:idNumber - repeats:YES]; + NSTimer* timer = [NSTimer timerWithTimeInterval:timeout + target:view->impl->wrapperView + selector:@selector(timerTick:) + userInfo:idNumber + repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; - view->impl->wrapperView->userTimers[idNumber] = timer; + view->impl->wrapperView->userTimers[idNumber] = timer; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglStopTimer(PuglView* view, uintptr_t id) { - NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; - NSTimer* timer = view->impl->wrapperView->userTimers[idNumber]; + NSNumber* idNumber = [NSNumber numberWithUnsignedLong:id]; + NSTimer* timer = view->impl->wrapperView->userTimers[idNumber]; - if (timer) { - [view->impl->wrapperView->userTimers removeObjectForKey:timer]; - [timer invalidate]; - return PUGL_SUCCESS; - } + if (timer) { + [view->impl->wrapperView->userTimers removeObjectForKey:timer]; + [timer invalidate]; + return PUGL_SUCCESS; + } - return PUGL_UNKNOWN_ERROR; + return PUGL_UNKNOWN_ERROR; } PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) { - if (event->type == PUGL_CLIENT) { - PuglWrapperView* wrapper = view->impl->wrapperView; - const NSWindow* window = [wrapper window]; - const NSRect rect = [wrapper frame]; - const NSPoint center = {NSMidX(rect), NSMidY(rect)}; - - NSEvent* nsevent = [NSEvent - otherEventWithType:NSApplicationDefined - location:center - modifierFlags:0 - timestamp:[[NSProcessInfo processInfo] systemUptime] - windowNumber:window.windowNumber - context:nil - subtype:PUGL_CLIENT - data1:(NSInteger)event->client.data1 - data2:(NSInteger)event->client.data2]; - - [view->world->impl->app postEvent:nsevent atStart:false]; - return PUGL_SUCCESS; - } + if (event->type == PUGL_CLIENT) { + PuglWrapperView* wrapper = view->impl->wrapperView; + const NSWindow* window = [wrapper window]; + const NSRect rect = [wrapper frame]; + const NSPoint center = {NSMidX(rect), NSMidY(rect)}; + + NSEvent* nsevent = + [NSEvent otherEventWithType:NSApplicationDefined + location:center + modifierFlags:0 + timestamp:[[NSProcessInfo processInfo] systemUptime] + windowNumber:window.windowNumber + context:nil + subtype:PUGL_CLIENT + data1:(NSInteger)event->client.data1 + data2:(NSInteger)event->client.data2]; - return PUGL_UNSUPPORTED_TYPE; + [view->world->impl->app postEvent:nsevent atStart:false]; + return PUGL_SUCCESS; + } + + return PUGL_UNSUPPORTED_TYPE; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglWaitForEvent(PuglView* view) { - return puglPollEvents(view->world, -1.0); + return puglPollEvents(view->world, -1.0); } #endif static void dispatchClientEvent(PuglWorld* world, NSEvent* ev) { - NSWindow* win = [ev window]; - NSPoint loc = [ev locationInWindow]; - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* view = world->views[i]; - PuglWrapperView* wrapper = view->impl->wrapperView; - if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) { - const PuglEventClient event = {PUGL_CLIENT, - 0, - (uintptr_t)[ev data1], - (uintptr_t)[ev data2]}; + NSWindow* win = [ev window]; + NSPoint loc = [ev locationInWindow]; + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* view = world->views[i]; + PuglWrapperView* wrapper = view->impl->wrapperView; + if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) { + const PuglEventClient event = { + PUGL_CLIENT, 0, (uintptr_t)[ev data1], (uintptr_t)[ev data2]}; - puglDispatchEvent(view, (const PuglEvent*)&event); - } - } + puglDispatchEvent(view, (const PuglEvent*)&event); + } + } } PuglStatus puglUpdate(PuglWorld* world, const double timeout) { - NSDate* date = ((timeout < 0) - ? [NSDate distantFuture] - : [NSDate dateWithTimeIntervalSinceNow:timeout]); - - for (NSEvent* ev = NULL; - (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask - untilDate:date - inMode:NSDefaultRunLoopMode - dequeue:YES]);) { - - if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) { - dispatchClientEvent(world, ev); - } + NSDate* date = + ((timeout < 0) ? [NSDate distantFuture] + : [NSDate dateWithTimeIntervalSinceNow:timeout]); + + for (NSEvent* ev = NULL; + (ev = [world->impl->app nextEventMatchingMask:NSAnyEventMask + untilDate:date + inMode:NSDefaultRunLoopMode + dequeue:YES]);) { + if ([ev type] == NSApplicationDefined && [ev subtype] == PUGL_CLIENT) { + dispatchClientEvent(world, ev); + } - [world->impl->app sendEvent: ev]; + [world->impl->app sendEvent:ev]; - if (timeout < 0) { - // Now that we've waited and got an event, set the date to now to - // avoid looping forever - date = [NSDate date]; - } - } + if (timeout < 0) { + // Now that we've waited and got an event, set the date to now to + // avoid looping forever + date = [NSDate date]; + } + } - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* const view = world->views[i]; + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* const view = world->views[i]; - if ([[view->impl->drawView window] isVisible]) { - puglDispatchSimpleEvent(view, PUGL_UPDATE); - } + if ([[view->impl->drawView window] isVisible]) { + puglDispatchSimpleEvent(view, PUGL_UPDATE); + } - [view->impl->drawView displayIfNeeded]; - } + [view->impl->drawView displayIfNeeded]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglProcessEvents(PuglView* view) { - return puglDispatchEvents(view->world); + return puglDispatchEvents(view->world); } #endif double puglGetTime(const PuglWorld* world) { - return (mach_absolute_time() / 1e9) - world->startTime; + return (mach_absolute_time() / 1e9) - world->startTime; } PuglStatus puglPostRedisplay(PuglView* view) { - [view->impl->drawView setNeedsDisplay: YES]; - return PUGL_SUCCESS; + [view->impl->drawView setNeedsDisplay:YES]; + return PUGL_SUCCESS; } PuglStatus puglPostRedisplayRect(PuglView* view, const PuglRect rect) { - const NSRect rectPx = rectToNsRect(rect); + const NSRect rectPx = rectToNsRect(rect); - [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)]; + [view->impl->drawView setNeedsDisplayInRect:nsRectToPoints(view, rectPx)]; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglNativeView puglGetNativeWindow(PuglView* view) { - return (PuglNativeView)view->impl->wrapperView; + return (PuglNativeView)view->impl->wrapperView; } PuglStatus puglSetWindowTitle(PuglView* view, const char* title) { - puglSetString(&view->title, title); + puglSetString(&view->title, title); - if (view->impl->window) { - NSString* titleString = [[NSString alloc] - initWithBytes:title - length:strlen(title) - encoding:NSUTF8StringEncoding]; + if (view->impl->window) { + NSString* titleString = + [[NSString alloc] initWithBytes:title + length:strlen(title) + encoding:NSUTF8StringEncoding]; - [view->impl->window setTitle:titleString]; - } + [view->impl->window setTitle:titleString]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; - // Update view frame to exactly the requested frame in Pugl coordinates - view->frame = frame; + // Update view frame to exactly the requested frame in Pugl coordinates + view->frame = frame; - const NSRect framePx = rectToNsRect(frame); - const NSRect framePt = nsRectToPoints(view, framePx); - if (impl->window) { - // Resize window to fit new content rect - const NSRect screenPt = rectToScreen(viewScreen(view), framePt); - const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); + if (impl->window) { + // Resize window to fit new content rect + const NSRect screenPt = rectToScreen(viewScreen(view), framePt); + const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; - [impl->window setFrame:winFrame display:NO]; - } + [impl->window setFrame:winFrame display:NO]; + } - // Resize views - const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); - const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + // Resize views + const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; - [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)]; - [impl->drawView setFrame:sizePt]; + [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)]; + [impl->drawView setFrame:sizePt]; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglSetDefaultSize(PuglView* const view, const int width, const int height) { - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; + view->defaultWidth = width; + view->defaultHeight = height; + return PUGL_SUCCESS; } PuglStatus puglSetMinSize(PuglView* const view, const int width, const int height) { - view->minWidth = width; - view->minHeight = height; + view->minWidth = width; + view->minHeight = height; - if (view->impl->window && (view->minWidth || view->minHeight)) { - [view->impl->window setContentMinSize:sizePoints(view, - view->minWidth, - view->minHeight)]; - } + if (view->impl->window && (view->minWidth || view->minHeight)) { + [view->impl->window + setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglSetMaxSize(PuglView* const view, const int width, const int height) { - view->maxWidth = width; - view->maxHeight = height; + view->maxWidth = width; + view->maxHeight = height; - if (view->impl->window && (view->maxWidth || view->maxHeight)) { - [view->impl->window setContentMaxSize:sizePoints(view, - view->maxWidth, - view->maxHeight)]; - } + if (view->impl->window && (view->maxWidth || view->maxHeight)) { + [view->impl->window + setContentMaxSize:sizePoints(view, view->maxWidth, view->maxHeight)]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus @@ -1334,35 +1348,34 @@ puglSetAspectRatio(PuglView* const view, const int maxX, const int maxY) { - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + view->minAspectX = minX; + view->minAspectY = minY; + view->maxAspectX = maxX; + view->maxAspectY = maxY; - if (view->impl->window && view->minAspectX && view->minAspectY) { - [view->impl->window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } + if (view->impl->window && view->minAspectX && view->minAspectY) { + [view->impl->window setContentAspectRatio:sizePoints(view, + view->minAspectX, + view->minAspectY)]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglSetTransientFor(PuglView* view, PuglNativeView parent) { - view->transientParent = parent; + view->transientParent = parent; - if (view->impl->window) { - NSWindow* parentWindow = [(NSView*)parent window]; - if (parentWindow) { - [parentWindow addChildWindow:view->impl->window - ordered:NSWindowAbove]; - return PUGL_SUCCESS; - } - } + if (view->impl->window) { + NSWindow* parentWindow = [(NSView*)parent window]; + if (parentWindow) { + [parentWindow addChildWindow:view->impl->window ordered:NSWindowAbove]; + return PUGL_SUCCESS; + } + } - return PUGL_FAILURE; + return PUGL_FAILURE; } const void* @@ -1370,57 +1383,57 @@ puglGetClipboard(PuglView* const view, const char** const type, size_t* const len) { - NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; - if ([[pasteboard types] containsObject:NSStringPboardType]) { - const NSString* str = [pasteboard stringForType:NSStringPboardType]; - const char* utf8 = [str UTF8String]; + if ([[pasteboard types] containsObject:NSStringPboardType]) { + const NSString* str = [pasteboard stringForType:NSStringPboardType]; + const char* utf8 = [str UTF8String]; - puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1); - } + puglSetBlob(&view->clipboard, utf8, strlen(utf8) + 1); + } - return puglGetInternalClipboard(view, type, len); + return puglGetInternalClipboard(view, type, len); } static NSCursor* puglGetNsCursor(const PuglCursor cursor) { - switch (cursor) { - case PUGL_CURSOR_ARROW: - return [NSCursor arrowCursor]; - case PUGL_CURSOR_CARET: - return [NSCursor IBeamCursor]; - case PUGL_CURSOR_CROSSHAIR: - return [NSCursor crosshairCursor]; - case PUGL_CURSOR_HAND: - return [NSCursor pointingHandCursor]; - case PUGL_CURSOR_NO: - return [NSCursor operationNotAllowedCursor]; - case PUGL_CURSOR_LEFT_RIGHT: - return [NSCursor resizeLeftRightCursor]; - case PUGL_CURSOR_UP_DOWN: - return [NSCursor resizeUpDownCursor]; - } - - return NULL; + switch (cursor) { + case PUGL_CURSOR_ARROW: + return [NSCursor arrowCursor]; + case PUGL_CURSOR_CARET: + return [NSCursor IBeamCursor]; + case PUGL_CURSOR_CROSSHAIR: + return [NSCursor crosshairCursor]; + case PUGL_CURSOR_HAND: + return [NSCursor pointingHandCursor]; + case PUGL_CURSOR_NO: + return [NSCursor operationNotAllowedCursor]; + case PUGL_CURSOR_LEFT_RIGHT: + return [NSCursor resizeLeftRightCursor]; + case PUGL_CURSOR_UP_DOWN: + return [NSCursor resizeUpDownCursor]; + } + + return NULL; } PuglStatus puglSetCursor(PuglView* view, PuglCursor cursor) { - PuglInternals* const impl = view->impl; - NSCursor* const cur = puglGetNsCursor(cursor); - if (!cur) { - return PUGL_FAILURE; - } + PuglInternals* const impl = view->impl; + NSCursor* const cur = puglGetNsCursor(cursor); + if (!cur) { + return PUGL_FAILURE; + } - impl->cursor = cur; + impl->cursor = cur; - if (impl->mouseTracked) { - [cur set]; - } + if (impl->mouseTracked) { + [cur set]; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus @@ -1429,24 +1442,23 @@ puglSetClipboard(PuglView* const view, const void* const data, const size_t len) { - NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; - const char* const str = (const char*)data; + NSPasteboard* const pasteboard = [NSPasteboard generalPasteboard]; + const char* const str = (const char*)data; - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } + PuglStatus st = puglSetInternalClipboard(view, type, data, len); + if (st) { + return st; + } - NSString* nsString = [NSString stringWithUTF8String:str]; - if (nsString) { - [pasteboard - declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] - owner:nil]; + NSString* nsString = [NSString stringWithUTF8String:str]; + if (nsString) { + [pasteboard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] + owner:nil]; - [pasteboard setString:nsString forType:NSStringPboardType]; + [pasteboard setString:nsString forType:NSStringPboardType]; - return PUGL_SUCCESS; - } + return PUGL_SUCCESS; + } - return PUGL_UNKNOWN_ERROR; + return PUGL_UNKNOWN_ERROR; } diff --git a/src/mac_cairo.m b/src/mac_cairo.m index 9a46037..1c564a0 100644 --- a/src/mac_cairo.m +++ b/src/mac_cairo.m @@ -29,33 +29,32 @@ @interface PuglCairoView : NSView @end -@implementation PuglCairoView -{ +@implementation PuglCairoView { @public - PuglView* puglview; - cairo_surface_t* surface; - cairo_t* cr; + PuglView* puglview; + cairo_surface_t* surface; + cairo_t* cr; } - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; + self = [super initWithFrame:frame]; - return self; + return self; } - (void)resizeWithOldSuperviewSize:(NSSize)oldSize { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [super resizeWithOldSuperviewSize:oldSize]; - [wrapper setReshaped]; + [super resizeWithOldSuperviewSize:oldSize]; + [wrapper setReshaped]; } - (void)drawRect:(NSRect)rect { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:rect]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + [wrapper dispatchExpose:rect]; } @end @@ -63,99 +62,99 @@ static PuglStatus puglMacCairoCreate(PuglView* view) { - PuglInternals* impl = view->impl; - PuglCairoView* drawView = [PuglCairoView alloc]; - - drawView->puglview = view; - [drawView initWithFrame:[impl->wrapperView bounds]]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + PuglCairoView* drawView = [PuglCairoView alloc]; + + drawView->puglview = view; + [drawView initWithFrame:[impl->wrapperView bounds]]; + if (view->hints[PUGL_RESIZABLE]) { + [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + } else { + [drawView setAutoresizingMask:NSViewNotSizable]; + } + + impl->drawView = drawView; + return PUGL_SUCCESS; } static PuglStatus puglMacCairoDestroy(PuglView* view) { - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; + PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - [drawView removeFromSuperview]; - [drawView release]; + [drawView removeFromSuperview]; + [drawView release]; - view->impl->drawView = nil; - return PUGL_SUCCESS; + view->impl->drawView = nil; + return PUGL_SUCCESS; } static PuglStatus puglMacCairoEnter(PuglView* view, const PuglEventExpose* expose) { - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - if (!expose) { - return PUGL_SUCCESS; - } + PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; + if (!expose) { + return PUGL_SUCCESS; + } - assert(!drawView->surface); - assert(!drawView->cr); + assert(!drawView->surface); + assert(!drawView->cr); - const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor]; - CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; - const CGSize sizePx = {view->frame.width, view->frame.height}; - const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); + const double scale = 1.0 / [[NSScreen mainScreen] backingScaleFactor]; + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; + const CGSize sizePx = {view->frame.width, view->frame.height}; + const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx); - // Convert coordinates to standard Cairo space - CGContextTranslateCTM(context, 0.0, -sizePt.height); - CGContextScaleCTM(context, scale, -scale); + // Convert coordinates to standard Cairo space + CGContextTranslateCTM(context, 0.0, -sizePt.height); + CGContextScaleCTM(context, scale, -scale); - drawView->surface = cairo_quartz_surface_create_for_cg_context( - context, (unsigned)sizePx.width, (unsigned)sizePx.height); + drawView->surface = cairo_quartz_surface_create_for_cg_context( + context, (unsigned)sizePx.width, (unsigned)sizePx.height); - drawView->cr = cairo_create(drawView->surface); + drawView->cr = cairo_create(drawView->surface); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglMacCairoLeave(PuglView* view, const PuglEventExpose* expose) { - PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; - if (!expose) { - return PUGL_SUCCESS; - } + PuglCairoView* const drawView = (PuglCairoView*)view->impl->drawView; + if (!expose) { + return PUGL_SUCCESS; + } - assert(drawView->surface); - assert(drawView->cr); + assert(drawView->surface); + assert(drawView->cr); - CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface); + CGContextRef context = cairo_quartz_surface_get_cg_context(drawView->surface); - cairo_destroy(drawView->cr); - cairo_surface_destroy(drawView->surface); - drawView->cr = NULL; - drawView->surface = NULL; + cairo_destroy(drawView->cr); + cairo_surface_destroy(drawView->surface); + drawView->cr = NULL; + drawView->surface = NULL; - CGContextFlush(context); + CGContextFlush(context); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static void* puglMacCairoGetContext(PuglView* view) { - return ((PuglCairoView*)view->impl->drawView)->cr; + return ((PuglCairoView*)view->impl->drawView)->cr; } const PuglBackend* puglCairoBackend(void) { - static const PuglBackend backend = {puglStubConfigure, - puglMacCairoCreate, - puglMacCairoDestroy, - puglMacCairoEnter, - puglMacCairoLeave, - puglMacCairoGetContext}; - - return &backend; + static const PuglBackend backend = {puglStubConfigure, + puglMacCairoCreate, + puglMacCairoDestroy, + puglMacCairoEnter, + puglMacCairoLeave, + puglMacCairoGetContext}; + + return &backend; } diff --git a/src/mac_gl.m b/src/mac_gl.m index b29221f..dd06cc0 100644 --- a/src/mac_gl.m +++ b/src/mac_gl.m @@ -21,95 +21,95 @@ #include "pugl/gl.h" #ifndef __MAC_10_10 -# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core +# define NSOpenGLProfileVersion4_1Core NSOpenGLProfileVersion3_2Core #endif @interface PuglOpenGLView : NSOpenGLView @end -@implementation PuglOpenGLView -{ +@implementation PuglOpenGLView { @public - PuglView* puglview; + PuglView* puglview; } - (id)initWithFrame:(NSRect)frame { - const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE]; - const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES]; - const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR]; - const unsigned profile = ((compat || major < 3) - ? NSOpenGLProfileVersionLegacy - : (major >= 4 - ? NSOpenGLProfileVersion4_1Core - : NSOpenGLProfileVersion3_2Core)); - - // Set attributes to default if they are unset - // (There is no GLX_DONT_CARE equivalent on MacOS) - if (puglview->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { - puglview->hints[PUGL_DEPTH_BITS] = 0; - } - if (puglview->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { - puglview->hints[PUGL_STENCIL_BITS] = 0; - } - if (puglview->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { - puglview->hints[PUGL_SAMPLES] = 1; - } - if (puglview->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { - puglview->hints[PUGL_DOUBLE_BUFFER] = 1; - } - if (puglview->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { - puglview->hints[PUGL_SWAP_INTERVAL] = 1; - } - - const unsigned colorSize = (unsigned)(puglview->hints[PUGL_RED_BITS] + - puglview->hints[PUGL_BLUE_BITS] + - puglview->hints[PUGL_GREEN_BITS] + - puglview->hints[PUGL_ALPHA_BITS]); - - NSOpenGLPixelFormatAttribute pixelAttribs[17] = { - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAccelerated, - NSOpenGLPFAOpenGLProfile, profile, - NSOpenGLPFAColorSize, colorSize, - NSOpenGLPFADepthSize, (unsigned)puglview->hints[PUGL_DEPTH_BITS], - NSOpenGLPFAStencilSize, (unsigned)puglview->hints[PUGL_STENCIL_BITS], - NSOpenGLPFAMultisample, samples ? 1 : 0, - NSOpenGLPFASampleBuffers, samples ? 1 : 0, - NSOpenGLPFASamples, samples, - 0}; - - NSOpenGLPixelFormat* pixelFormat = [ - [NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs]; - - if (pixelFormat) { - self = [super initWithFrame:frame pixelFormat:pixelFormat]; - [pixelFormat release]; - } else { - self = [super initWithFrame:frame]; - } - - [self setWantsBestResolutionOpenGLSurface:YES]; - - if (self) { - [[self openGLContext] makeCurrentContext]; - [self reshape]; - } - return self; + const bool compat = puglview->hints[PUGL_USE_COMPAT_PROFILE]; + const unsigned samples = (unsigned)puglview->hints[PUGL_SAMPLES]; + const int major = puglview->hints[PUGL_CONTEXT_VERSION_MAJOR]; + const unsigned profile = + ((compat || major < 3) ? NSOpenGLProfileVersionLegacy + : (major >= 4 ? NSOpenGLProfileVersion4_1Core + : NSOpenGLProfileVersion3_2Core)); + + // Set attributes to default if they are unset + // (There is no GLX_DONT_CARE equivalent on MacOS) + if (puglview->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { + puglview->hints[PUGL_DEPTH_BITS] = 0; + } + if (puglview->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { + puglview->hints[PUGL_STENCIL_BITS] = 0; + } + if (puglview->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { + puglview->hints[PUGL_SAMPLES] = 1; + } + if (puglview->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { + puglview->hints[PUGL_DOUBLE_BUFFER] = 1; + } + if (puglview->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { + puglview->hints[PUGL_SWAP_INTERVAL] = 1; + } + + const unsigned colorSize = (unsigned)(puglview->hints[PUGL_RED_BITS] + + puglview->hints[PUGL_BLUE_BITS] + + puglview->hints[PUGL_GREEN_BITS] + + puglview->hints[PUGL_ALPHA_BITS]); + + // clang-format off + NSOpenGLPixelFormatAttribute pixelAttribs[17] = { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAccelerated, + NSOpenGLPFAOpenGLProfile, profile, + NSOpenGLPFAColorSize, colorSize, + NSOpenGLPFADepthSize, (unsigned)puglview->hints[PUGL_DEPTH_BITS], + NSOpenGLPFAStencilSize, (unsigned)puglview->hints[PUGL_STENCIL_BITS], + NSOpenGLPFAMultisample, samples ? 1 : 0, + NSOpenGLPFASampleBuffers, samples ? 1 : 0, + NSOpenGLPFASamples, samples, + 0}; + // clang-format on + + NSOpenGLPixelFormat* pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelAttribs]; + + if (pixelFormat) { + self = [super initWithFrame:frame pixelFormat:pixelFormat]; + [pixelFormat release]; + } else { + self = [super initWithFrame:frame]; + } + + [self setWantsBestResolutionOpenGLSurface:YES]; + + if (self) { + [[self openGLContext] makeCurrentContext]; + [self reshape]; + } + return self; } - (void)reshape { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [super reshape]; - [wrapper setReshaped]; + [super reshape]; + [wrapper setReshaped]; } - (void)drawRect:(NSRect)rect { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:rect]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + [wrapper dispatchExpose:rect]; } @end @@ -117,94 +117,94 @@ static PuglStatus puglMacGlCreate(PuglView* view) { - PuglInternals* impl = view->impl; - PuglOpenGLView* drawView = [PuglOpenGLView alloc]; - - drawView->puglview = view; - [drawView initWithFrame:[impl->wrapperView bounds]]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + PuglOpenGLView* drawView = [PuglOpenGLView alloc]; + + drawView->puglview = view; + [drawView initWithFrame:[impl->wrapperView bounds]]; + if (view->hints[PUGL_RESIZABLE]) { + [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + } else { + [drawView setAutoresizingMask:NSViewNotSizable]; + } + + impl->drawView = drawView; + return PUGL_SUCCESS; } static PuglStatus puglMacGlDestroy(PuglView* view) { - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; + PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - [drawView removeFromSuperview]; - [drawView release]; + [drawView removeFromSuperview]; + [drawView release]; - view->impl->drawView = nil; - return PUGL_SUCCESS; + view->impl->drawView = nil; + return PUGL_SUCCESS; } static PuglStatus puglMacGlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose)) { - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; + PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - [[drawView openGLContext] makeCurrentContext]; - return PUGL_SUCCESS; + [[drawView openGLContext] makeCurrentContext]; + return PUGL_SUCCESS; } static PuglStatus puglMacGlLeave(PuglView* view, const PuglEventExpose* expose) { - PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; + PuglOpenGLView* const drawView = (PuglOpenGLView*)view->impl->drawView; - if (expose) { - [[drawView openGLContext] flushBuffer]; - } + if (expose) { + [[drawView openGLContext] flushBuffer]; + } - [NSOpenGLContext clearCurrentContext]; + [NSOpenGLContext clearCurrentContext]; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglGlFunc -puglGetProcAddress(const char *name) +puglGetProcAddress(const char* name) { - CFBundleRef framework = - CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + CFBundleRef framework = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - CFStringRef symbol = CFStringCreateWithCString( - kCFAllocatorDefault, name, kCFStringEncodingASCII); + CFStringRef symbol = CFStringCreateWithCString( + kCFAllocatorDefault, name, kCFStringEncodingASCII); - PuglGlFunc func = (PuglGlFunc)CFBundleGetFunctionPointerForName( - framework, symbol); + PuglGlFunc func = + (PuglGlFunc)CFBundleGetFunctionPointerForName(framework, symbol); - CFRelease(symbol); + CFRelease(symbol); - return func; + return func; } PuglStatus puglEnterContext(PuglView* view) { - return view->backend->enter(view, NULL); + return view->backend->enter(view, NULL); } PuglStatus puglLeaveContext(PuglView* view) { - return view->backend->leave(view, NULL); + return view->backend->leave(view, NULL); } const PuglBackend* puglGlBackend(void) { - static const PuglBackend backend = {puglStubConfigure, - puglMacGlCreate, - puglMacGlDestroy, - puglMacGlEnter, - puglMacGlLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglStubConfigure, + puglMacGlCreate, + puglMacGlDestroy, + puglMacGlEnter, + puglMacGlLeave, + puglStubGetContext}; + + return &backend; } diff --git a/src/mac_stub.m b/src/mac_stub.m index 404d295..ac7bfcc 100644 --- a/src/mac_stub.m +++ b/src/mac_stub.m @@ -25,25 +25,24 @@ @interface PuglStubView : NSView @end -@implementation PuglStubView -{ +@implementation PuglStubView { @public - PuglView* puglview; + PuglView* puglview; } - (void)resizeWithOldSuperviewSize:(NSSize)oldSize { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [super resizeWithOldSuperviewSize:oldSize]; - [wrapper setReshaped]; + [super resizeWithOldSuperviewSize:oldSize]; + [wrapper setReshaped]; } - (void)drawRect:(NSRect)rect { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:rect]; + [wrapper dispatchExpose:rect]; } @end @@ -51,42 +50,43 @@ static PuglStatus puglMacStubCreate(PuglView* view) { - PuglInternals* impl = view->impl; - PuglStubView* drawView = [PuglStubView alloc]; - - drawView->puglview = view; - [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + PuglStubView* drawView = [PuglStubView alloc]; + + drawView->puglview = view; + [drawView + initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)]; + if (view->hints[PUGL_RESIZABLE]) { + [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + } else { + [drawView setAutoresizingMask:NSViewNotSizable]; + } + + impl->drawView = drawView; + return PUGL_SUCCESS; } static PuglStatus puglMacStubDestroy(PuglView* view) { - PuglStubView* const drawView = (PuglStubView*)view->impl->drawView; + PuglStubView* const drawView = (PuglStubView*)view->impl->drawView; - [drawView removeFromSuperview]; - [drawView release]; + [drawView removeFromSuperview]; + [drawView release]; - view->impl->drawView = nil; - return PUGL_SUCCESS; + view->impl->drawView = nil; + return PUGL_SUCCESS; } const PuglBackend* puglStubBackend(void) { - static const PuglBackend backend = {puglStubConfigure, - puglMacStubCreate, - puglMacStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglStubConfigure, + puglMacStubCreate, + puglMacStubDestroy, + puglStubEnter, + puglStubLeave, + puglStubGetContext}; + + return &backend; } diff --git a/src/mac_vulkan.m b/src/mac_vulkan.m index c56346c..6899483 100644 --- a/src/mac_vulkan.m +++ b/src/mac_vulkan.m @@ -40,47 +40,45 @@ @end -@implementation PuglVulkanView -{ +@implementation PuglVulkanView { @public - PuglView* puglview; + PuglView* puglview; } - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; + self = [super initWithFrame:frame]; - if (self) { - self.wantsLayer = YES; - self.layerContentsRedrawPolicy = - NSViewLayerContentsRedrawOnSetNeedsDisplay; - } + if (self) { + self.wantsLayer = YES; + self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; + } - return self; + return self; } - (CALayer*)makeBackingLayer { - CAMetalLayer* layer = [CAMetalLayer layer]; - [layer setDelegate:self]; - return layer; + CAMetalLayer* layer = [CAMetalLayer layer]; + [layer setDelegate:self]; + return layer; } - (void)setFrameSize:(NSSize)newSize { - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [super setFrameSize:newSize]; - [wrapper setReshaped]; + [super setFrameSize:newSize]; + [wrapper setReshaped]; - self.layer.frame = self.bounds; + self.layer.frame = self.bounds; } - (void)displayLayer:(CALayer*)layer { - (void)layer; - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - [wrapper dispatchExpose:[self bounds]]; + (void)layer; + PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; + [wrapper dispatchExpose:[self bounds]]; } @end @@ -88,105 +86,105 @@ static PuglStatus puglMacVulkanCreate(PuglView* view) { - PuglInternals* impl = view->impl; - PuglVulkanView* drawView = [PuglVulkanView alloc]; - const NSRect rect = NSMakeRect(0, 0, view->frame.width, view->frame.height); - - drawView->puglview = view; - [drawView initWithFrame:rect]; - if (view->hints[PUGL_RESIZABLE]) { - [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - } else { - [drawView setAutoresizingMask:NSViewNotSizable]; - } - - impl->drawView = drawView; - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + PuglVulkanView* drawView = [PuglVulkanView alloc]; + const NSRect rect = NSMakeRect(0, 0, view->frame.width, view->frame.height); + + drawView->puglview = view; + [drawView initWithFrame:rect]; + if (view->hints[PUGL_RESIZABLE]) { + [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + } else { + [drawView setAutoresizingMask:NSViewNotSizable]; + } + + impl->drawView = drawView; + return PUGL_SUCCESS; } static PuglStatus puglMacVulkanDestroy(PuglView* view) { - PuglVulkanView* const drawView = (PuglVulkanView*)view->impl->drawView; + PuglVulkanView* const drawView = (PuglVulkanView*)view->impl->drawView; - [drawView removeFromSuperview]; - [drawView release]; + [drawView removeFromSuperview]; + [drawView release]; - view->impl->drawView = nil; - return PUGL_SUCCESS; + view->impl->drawView = nil; + return PUGL_SUCCESS; } struct PuglVulkanLoaderImpl { - void* libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + void* libvulkan; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; }; PuglVulkanLoader* puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) { - PuglVulkanLoader* loader = (PuglVulkanLoader*) - calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } + PuglVulkanLoader* loader = + (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); + if (!loader) { + return NULL; + } - if (!(loader->libvulkan = dlopen("libvulkan.dylib", RTLD_LAZY))) { - free(loader); - return NULL; - } + if (!(loader->libvulkan = dlopen("libvulkan.dylib", RTLD_LAZY))) { + free(loader); + return NULL; + } - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) - dlsym(loader->libvulkan, "vkGetInstanceProcAddr"); + loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( + loader->libvulkan, "vkGetInstanceProcAddr"); - loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) - dlsym(loader->libvulkan, "vkGetDeviceProcAddr"); + loader->vkGetDeviceProcAddr = + (PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr"); - return loader; + return loader; } void puglFreeVulkanLoader(PuglVulkanLoader* loader) { - if (loader) { - dlclose(loader->libvulkan); - free(loader); - } + if (loader) { + dlclose(loader->libvulkan); + free(loader); + } } PFN_vkGetInstanceProcAddr puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetInstanceProcAddr; + return loader->vkGetInstanceProcAddr; } PFN_vkGetDeviceProcAddr puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetDeviceProcAddr; + return loader->vkGetDeviceProcAddr; } const PuglBackend* puglVulkanBackend(void) { - static const PuglBackend backend = {puglStubConfigure, - puglMacVulkanCreate, - puglMacVulkanDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglStubConfigure, + puglMacVulkanCreate, + puglMacVulkanDestroy, + puglStubEnter, + puglStubLeave, + puglStubGetContext}; + + return &backend; } const char* const* puglGetInstanceExtensions(uint32_t* const count) { - static const char* const extensions[] = {"VK_KHR_surface", - "VK_MVK_macos_surface"}; + static const char* const extensions[] = {"VK_KHR_surface", + "VK_MVK_macos_surface"}; - *count = 2; - return extensions; + *count = 2; + return extensions; } VkResult @@ -196,18 +194,18 @@ puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, const VkAllocationCallbacks* const allocator, VkSurfaceKHR* const surface) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; - PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = - (PFN_vkCreateMacOSSurfaceMVK) - vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK"); + PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK = + (PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr( + instance, "vkCreateMacOSSurfaceMVK"); - const VkMacOSSurfaceCreateInfoMVK info = { - VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, - NULL, - 0, - impl->drawView, - }; + const VkMacOSSurfaceCreateInfoMVK info = { + VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, + NULL, + 0, + impl->drawView, + }; - return vkCreateMacOSSurfaceMVK(instance, &info, allocator, surface); + return vkCreateMacOSSurfaceMVK(instance, &info, allocator, surface); } @@ -24,45 +24,45 @@ PUGL_BEGIN_DECLS static inline PuglStatus puglStubConfigure(PuglView* view) { - (void)view; - return PUGL_SUCCESS; + (void)view; + return PUGL_SUCCESS; } static inline PuglStatus puglStubCreate(PuglView* view) { - (void)view; - return PUGL_SUCCESS; + (void)view; + return PUGL_SUCCESS; } static inline PuglStatus puglStubDestroy(PuglView* view) { - (void)view; - return PUGL_SUCCESS; + (void)view; + return PUGL_SUCCESS; } static inline PuglStatus puglStubEnter(PuglView* view, const PuglEventExpose* expose) { - (void)view; - (void)expose; - return PUGL_SUCCESS; + (void)view; + (void)expose; + return PUGL_SUCCESS; } static inline PuglStatus puglStubLeave(PuglView* view, const PuglEventExpose* expose) { - (void)view; - (void)expose; - return PUGL_SUCCESS; + (void)view; + (void)expose; + return PUGL_SUCCESS; } static inline void* puglStubGetContext(PuglView* view) { - (void)view; - return NULL; + (void)view; + return NULL; } PUGL_END_DECLS diff --git a/src/types.h b/src/types.h index 4e63d43..a618e8c 100644 --- a/src/types.h +++ b/src/types.h @@ -25,11 +25,11 @@ // Unused parameter macro to suppresses warnings and make it impossible to use #if defined(__cplusplus) -# define PUGL_UNUSED(name) +# define PUGL_UNUSED(name) #elif defined(__GNUC__) || defined(__clang__) -# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__)) +# define PUGL_UNUSED(name) name##_unused __attribute__((__unused__)) #else -# define PUGL_UNUSED(name) name +# define PUGL_UNUSED(name) name #endif /// Platform-specific world internals @@ -43,45 +43,45 @@ typedef int PuglHints[PUGL_NUM_VIEW_HINTS]; /// Blob of arbitrary data typedef struct { - void* data; ///< Dynamically allocated data - size_t len; ///< Length of data in bytes + void* data; ///< Dynamically allocated data + size_t len; ///< Length of data in bytes } PuglBlob; /// Cross-platform view definition struct PuglViewImpl { - PuglWorld* world; - const PuglBackend* backend; - PuglInternals* impl; - PuglHandle handle; - PuglEventFunc eventFunc; - char* title; - PuglBlob clipboard; - PuglNativeView parent; - uintptr_t transientParent; - PuglRect frame; - PuglEventConfigure lastConfigure; - PuglHints hints; - int defaultWidth; - int defaultHeight; - int minWidth; - int minHeight; - int maxWidth; - int maxHeight; - int minAspectX; - int minAspectY; - int maxAspectX; - int maxAspectY; - bool visible; + PuglWorld* world; + const PuglBackend* backend; + PuglInternals* impl; + PuglHandle handle; + PuglEventFunc eventFunc; + char* title; + PuglBlob clipboard; + PuglNativeView parent; + uintptr_t transientParent; + PuglRect frame; + PuglEventConfigure lastConfigure; + PuglHints hints; + int defaultWidth; + int defaultHeight; + int minWidth; + int minHeight; + int maxWidth; + int maxHeight; + int minAspectX; + int minAspectY; + int maxAspectX; + int maxAspectY; + bool visible; }; /// Cross-platform world definition struct PuglWorldImpl { - PuglWorldInternals* impl; - PuglWorldHandle handle; - char* className; - double startTime; - size_t numViews; - PuglView** views; + PuglWorldInternals* impl; + PuglWorldHandle handle; + char* className; + double startTime; + size_t numViews; + PuglView** views; }; /// Opaque surface used by graphics backend @@ -89,23 +89,23 @@ typedef void PuglSurface; /// Graphics backend interface struct PuglBackendImpl { - /// Get visual information from display and setup view as necessary - PuglStatus (*configure)(PuglView*); + /// Get visual information from display and setup view as necessary + PuglStatus (*configure)(PuglView*); - /// Create surface and drawing context - PuglStatus (*create)(PuglView*); + /// Create surface and drawing context + PuglStatus (*create)(PuglView*); - /// Destroy surface and drawing context - PuglStatus (*destroy)(PuglView*); + /// Destroy surface and drawing context + PuglStatus (*destroy)(PuglView*); - /// Enter drawing context, for drawing if expose is non-null - PuglStatus (*enter)(PuglView*, const PuglEventExpose*); + /// Enter drawing context, for drawing if expose is non-null + PuglStatus (*enter)(PuglView*, const PuglEventExpose*); - /// Leave drawing context, after drawing if expose is non-null - PuglStatus (*leave)(PuglView*, const PuglEventExpose*); + /// Leave drawing context, after drawing if expose is non-null + PuglStatus (*leave)(PuglView*, const PuglEventExpose*); - /// Return the puglGetContext() handle for the application, if any - void* (*getContext)(PuglView*); + /// Return the puglGetContext() handle for the application, if any + void* (*getContext)(PuglView*); }; #endif // PUGL_DETAIL_TYPES_H @@ -32,24 +32,24 @@ #include <wctype.h> #ifndef WM_MOUSEWHEEL -# define WM_MOUSEWHEEL 0x020A +# define WM_MOUSEWHEEL 0x020A #endif #ifndef WM_MOUSEHWHEEL -# define WM_MOUSEHWHEEL 0x020E +# define WM_MOUSEHWHEEL 0x020E #endif #ifndef WHEEL_DELTA -# define WHEEL_DELTA 120 +# define WHEEL_DELTA 120 #endif #ifndef GWLP_USERDATA -# define GWLP_USERDATA (-21) +# define GWLP_USERDATA (-21) #endif -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) -#define PUGL_LOCAL_MARK_MSG (WM_USER + 51) +#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) +#define PUGL_LOCAL_MARK_MSG (WM_USER + 51) #define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52) -#define PUGL_USER_TIMER_MIN 9470 +#define PUGL_USER_TIMER_MIN 9470 -typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void); +typedef BOOL(WINAPI* PFN_SetProcessDPIAware)(void); LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -57,268 +57,267 @@ wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static wchar_t* puglUtf8ToWideChar(const char* const utf8) { - const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); - if (len > 0) { - wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len); - return result; - } - - return NULL; + const int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + if (len > 0) { + wchar_t* result = (wchar_t*)calloc((size_t)len, sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, result, len); + return result; + } + + return NULL; } static char* puglWideCharToUtf8(const wchar_t* const wstr, size_t* len) { - int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); - if (n > 0) { - char* result = (char*)calloc((size_t)n, sizeof(char)); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL); - *len = (size_t)n; - return result; - } - - return NULL; + int n = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + if (n > 0) { + char* result = (char*)calloc((size_t)n, sizeof(char)); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, result, n, NULL, NULL); + *len = (size_t)n; + return result; + } + + return NULL; } static bool puglRegisterWindowClass(const char* name) { - WNDCLASSEX wc = { 0 }; - if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) { - return true; // Already registered - } - - wc.cbSize = sizeof(wc); - wc.style = CS_OWNDC; - wc.lpfnWndProc = wndProc; - wc.hInstance = GetModuleHandle(NULL); - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = name; - - return RegisterClassEx(&wc); + WNDCLASSEX wc = {0}; + if (GetClassInfoEx(GetModuleHandle(NULL), name, &wc)) { + return true; // Already registered + } + + wc.cbSize = sizeof(wc); + wc.style = CS_OWNDC; + wc.lpfnWndProc = wndProc; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszClassName = name; + + return RegisterClassEx(&wc); } PuglWorldInternals* -puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type), +puglInitWorldInternals(PuglWorldType PUGL_UNUSED(type), PuglWorldFlags PUGL_UNUSED(flags)) { - PuglWorldInternals* impl = (PuglWorldInternals*)calloc( - 1, sizeof(PuglWorldInternals)); - if (!impl) { - return NULL; - } - - HMODULE user32 = LoadLibrary("user32.dll"); - if (user32) { - PFN_SetProcessDPIAware SetProcessDPIAware = - (PFN_SetProcessDPIAware)GetProcAddress( - user32, "SetProcessDPIAware"); - if (SetProcessDPIAware) { - SetProcessDPIAware(); - } - - FreeLibrary(user32); - } - - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - impl->timerFrequency = (double)frequency.QuadPart; - - return impl; + PuglWorldInternals* impl = + (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); + if (!impl) { + return NULL; + } + + HMODULE user32 = LoadLibrary("user32.dll"); + if (user32) { + PFN_SetProcessDPIAware SetProcessDPIAware = + (PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware"); + if (SetProcessDPIAware) { + SetProcessDPIAware(); + } + + FreeLibrary(user32); + } + + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + impl->timerFrequency = (double)frequency.QuadPart; + + return impl; } void* puglGetNativeWorld(PuglWorld* PUGL_UNUSED(world)) { - return GetModuleHandle(NULL); + return GetModuleHandle(NULL); } PuglInternals* puglInitViewInternals(void) { - return (PuglInternals*)calloc(1, sizeof(PuglInternals)); + return (PuglInternals*)calloc(1, sizeof(PuglInternals)); } static PuglStatus puglPollWinEvents(PuglWorld* world, const double timeout) { - (void)world; - - if (timeout < 0) { - WaitMessage(); - } else { - MsgWaitForMultipleObjects( - 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS); - } - return PUGL_SUCCESS; + (void)world; + + if (timeout < 0) { + WaitMessage(); + } else { + MsgWaitForMultipleObjects( + 0, NULL, FALSE, (DWORD)(timeout * 1e3), QS_ALLEVENTS); + } + return PUGL_SUCCESS; } PuglStatus puglRealize(PuglView* view) { - PuglInternals* impl = view->impl; - if (impl->hwnd) { - return PUGL_FAILURE; - } - - // Getting depth from the display mode seems tedious, just set usual values - if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_RED_BITS] = 8; - } - if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_BLUE_BITS] = 8; - } - if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_GREEN_BITS] = 8; - } - if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_ALPHA_BITS] = 8; - } - - // Get refresh rate for resize draw timer - DEVMODEA devMode = {0}; - EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode); - view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; - - // Register window class if necessary - if (!puglRegisterWindowClass(view->world->className)) { - return PUGL_REGISTRATION_FAILED; - } - - if (!view->backend || !view->backend->configure) { - return PUGL_BAD_BACKEND; - } - - PuglStatus st = PUGL_SUCCESS; - if ((st = view->backend->configure(view)) || - (st = view->backend->create(view))) { - return st; - } - - if (view->title) { - puglSetWindowTitle(view, view->title); - } - - view->impl->cursor = LoadCursor(NULL, IDC_ARROW); - - puglSetFrame(view, view->frame); - SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); - - puglDispatchSimpleEvent(view, PUGL_CREATE); - - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + if (impl->hwnd) { + return PUGL_FAILURE; + } + + // Getting depth from the display mode seems tedious, just set usual values + if (view->hints[PUGL_RED_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_RED_BITS] = 8; + } + if (view->hints[PUGL_BLUE_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_BLUE_BITS] = 8; + } + if (view->hints[PUGL_GREEN_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_GREEN_BITS] = 8; + } + if (view->hints[PUGL_ALPHA_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_ALPHA_BITS] = 8; + } + + // Get refresh rate for resize draw timer + DEVMODEA devMode = {0}; + EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &devMode); + view->hints[PUGL_REFRESH_RATE] = (int)devMode.dmDisplayFrequency; + + // Register window class if necessary + if (!puglRegisterWindowClass(view->world->className)) { + return PUGL_REGISTRATION_FAILED; + } + + if (!view->backend || !view->backend->configure) { + return PUGL_BAD_BACKEND; + } + + PuglStatus st = PUGL_SUCCESS; + if ((st = view->backend->configure(view)) || + (st = view->backend->create(view))) { + return st; + } + + if (view->title) { + puglSetWindowTitle(view, view->title); + } + + view->impl->cursor = LoadCursor(NULL, IDC_ARROW); + + puglSetFrame(view, view->frame); + SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); + + puglDispatchSimpleEvent(view, PUGL_CREATE); + + return PUGL_SUCCESS; } PuglStatus puglShow(PuglView* view) { - PuglInternals* impl = view->impl; - - if (!impl->hwnd) { - const PuglStatus st = puglRealize(view); - if (st) { - return st; - } - } - - ShowWindow(impl->hwnd, SW_SHOWNORMAL); - SetFocus(impl->hwnd); - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + + if (!impl->hwnd) { + const PuglStatus st = puglRealize(view); + if (st) { + return st; + } + } + + ShowWindow(impl->hwnd, SW_SHOWNORMAL); + SetFocus(impl->hwnd); + return PUGL_SUCCESS; } PuglStatus puglHide(PuglView* view) { - PuglInternals* impl = view->impl; + PuglInternals* impl = view->impl; - ShowWindow(impl->hwnd, SW_HIDE); - return PUGL_SUCCESS; + ShowWindow(impl->hwnd, SW_HIDE); + return PUGL_SUCCESS; } void puglFreeViewInternals(PuglView* view) { - if (view) { - if (view->backend) { - view->backend->destroy(view); - } - - ReleaseDC(view->impl->hwnd, view->impl->hdc); - DestroyWindow(view->impl->hwnd); - free(view->impl); - } + if (view) { + if (view->backend) { + view->backend->destroy(view); + } + + ReleaseDC(view->impl->hwnd, view->impl->hdc); + DestroyWindow(view->impl->hwnd); + free(view->impl); + } } void puglFreeWorldInternals(PuglWorld* world) { - UnregisterClass(world->className, NULL); - free(world->impl); + UnregisterClass(world->className, NULL); + free(world->impl); } static PuglKey keySymToSpecial(WPARAM sym) { - // clang-format off - switch (sym) { - case VK_F1: return PUGL_KEY_F1; - case VK_F2: return PUGL_KEY_F2; - case VK_F3: return PUGL_KEY_F3; - case VK_F4: return PUGL_KEY_F4; - case VK_F5: return PUGL_KEY_F5; - case VK_F6: return PUGL_KEY_F6; - case VK_F7: return PUGL_KEY_F7; - case VK_F8: return PUGL_KEY_F8; - case VK_F9: return PUGL_KEY_F9; - case VK_F10: return PUGL_KEY_F10; - case VK_F11: return PUGL_KEY_F11; - case VK_F12: return PUGL_KEY_F12; - case VK_BACK: return PUGL_KEY_BACKSPACE; - case VK_DELETE: return PUGL_KEY_DELETE; - case VK_LEFT: return PUGL_KEY_LEFT; - case VK_UP: return PUGL_KEY_UP; - case VK_RIGHT: return PUGL_KEY_RIGHT; - case VK_DOWN: return PUGL_KEY_DOWN; - case VK_PRIOR: return PUGL_KEY_PAGE_UP; - case VK_NEXT: return PUGL_KEY_PAGE_DOWN; - case VK_HOME: return PUGL_KEY_HOME; - case VK_END: return PUGL_KEY_END; - case VK_INSERT: return PUGL_KEY_INSERT; - case VK_SHIFT: - case VK_LSHIFT: return PUGL_KEY_SHIFT_L; - case VK_RSHIFT: return PUGL_KEY_SHIFT_R; - case VK_CONTROL: - case VK_LCONTROL: return PUGL_KEY_CTRL_L; - case VK_RCONTROL: return PUGL_KEY_CTRL_R; - case VK_MENU: - case VK_LMENU: return PUGL_KEY_ALT_L; - case VK_RMENU: return PUGL_KEY_ALT_R; - case VK_LWIN: return PUGL_KEY_SUPER_L; - case VK_RWIN: return PUGL_KEY_SUPER_R; - case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK; - case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK; - case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK; - case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN; - case VK_PAUSE: return PUGL_KEY_PAUSE; - } - // clang-format on - - return (PuglKey)0; + // clang-format off + switch (sym) { + case VK_F1: return PUGL_KEY_F1; + case VK_F2: return PUGL_KEY_F2; + case VK_F3: return PUGL_KEY_F3; + case VK_F4: return PUGL_KEY_F4; + case VK_F5: return PUGL_KEY_F5; + case VK_F6: return PUGL_KEY_F6; + case VK_F7: return PUGL_KEY_F7; + case VK_F8: return PUGL_KEY_F8; + case VK_F9: return PUGL_KEY_F9; + case VK_F10: return PUGL_KEY_F10; + case VK_F11: return PUGL_KEY_F11; + case VK_F12: return PUGL_KEY_F12; + case VK_BACK: return PUGL_KEY_BACKSPACE; + case VK_DELETE: return PUGL_KEY_DELETE; + case VK_LEFT: return PUGL_KEY_LEFT; + case VK_UP: return PUGL_KEY_UP; + case VK_RIGHT: return PUGL_KEY_RIGHT; + case VK_DOWN: return PUGL_KEY_DOWN; + case VK_PRIOR: return PUGL_KEY_PAGE_UP; + case VK_NEXT: return PUGL_KEY_PAGE_DOWN; + case VK_HOME: return PUGL_KEY_HOME; + case VK_END: return PUGL_KEY_END; + case VK_INSERT: return PUGL_KEY_INSERT; + case VK_SHIFT: + case VK_LSHIFT: return PUGL_KEY_SHIFT_L; + case VK_RSHIFT: return PUGL_KEY_SHIFT_R; + case VK_CONTROL: + case VK_LCONTROL: return PUGL_KEY_CTRL_L; + case VK_RCONTROL: return PUGL_KEY_CTRL_R; + case VK_MENU: + case VK_LMENU: return PUGL_KEY_ALT_L; + case VK_RMENU: return PUGL_KEY_ALT_R; + case VK_LWIN: return PUGL_KEY_SUPER_L; + case VK_RWIN: return PUGL_KEY_SUPER_R; + case VK_CAPITAL: return PUGL_KEY_CAPS_LOCK; + case VK_SCROLL: return PUGL_KEY_SCROLL_LOCK; + case VK_NUMLOCK: return PUGL_KEY_NUM_LOCK; + case VK_SNAPSHOT: return PUGL_KEY_PRINT_SCREEN; + case VK_PAUSE: return PUGL_KEY_PAUSE; + } + // clang-format on + + return (PuglKey)0; } static uint32_t getModifiers(void) { - // clang-format off - return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) | - ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) | - ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) | - ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) | - ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u)); - // clang-format on + // clang-format off + return (((GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0u) | + ((GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0u) | + ((GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0u) | + ((GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0u) | + ((GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0u)); + // clang-format on } static void @@ -328,59 +327,59 @@ initMouseEvent(PuglEvent* event, bool press, LPARAM lParam) { - POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; - ClientToScreen(view->impl->hwnd, &pt); - - if (press) { - SetCapture(view->impl->hwnd); - } else { - ReleaseCapture(); - } - - event->button.time = GetMessageTime() / 1e3; - event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE; - event->button.x = GET_X_LPARAM(lParam); - event->button.y = GET_Y_LPARAM(lParam); - event->button.xRoot = pt.x; - event->button.yRoot = pt.y; - event->button.state = getModifiers(); - event->button.button = (uint32_t)button; + POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + ClientToScreen(view->impl->hwnd, &pt); + + if (press) { + SetCapture(view->impl->hwnd); + } else { + ReleaseCapture(); + } + + event->button.time = GetMessageTime() / 1e3; + event->button.type = press ? PUGL_BUTTON_PRESS : PUGL_BUTTON_RELEASE; + event->button.x = GET_X_LPARAM(lParam); + event->button.y = GET_Y_LPARAM(lParam); + event->button.xRoot = pt.x; + event->button.yRoot = pt.y; + event->button.state = getModifiers(); + event->button.button = (uint32_t)button; } static void initScrollEvent(PuglEvent* event, PuglView* view, LPARAM lParam) { - POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; - ScreenToClient(view->impl->hwnd, &pt); - - event->scroll.time = GetMessageTime() / 1e3; - event->scroll.type = PUGL_SCROLL; - event->scroll.x = pt.x; - event->scroll.y = pt.y; - event->scroll.xRoot = GET_X_LPARAM(lParam); - event->scroll.yRoot = GET_Y_LPARAM(lParam); - event->scroll.state = getModifiers(); - event->scroll.dx = 0; - event->scroll.dy = 0; + POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + ScreenToClient(view->impl->hwnd, &pt); + + event->scroll.time = GetMessageTime() / 1e3; + event->scroll.type = PUGL_SCROLL; + event->scroll.x = pt.x; + event->scroll.y = pt.y; + event->scroll.xRoot = GET_X_LPARAM(lParam); + event->scroll.yRoot = GET_Y_LPARAM(lParam); + event->scroll.state = getModifiers(); + event->scroll.dx = 0; + event->scroll.dy = 0; } /// Return the code point for buf, or the replacement character on error static uint32_t puglDecodeUTF16(const wchar_t* buf, const int len) { - const uint32_t c0 = buf[0]; - const uint32_t c1 = buf[0]; - if (c0 >= 0xD800 && c0 < 0xDC00) { - if (len < 2) { - return 0xFFFD; // Surrogate, but length is only 1 - } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) { - return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000; - } - - return 0xFFFD; // Unpaired surrogates - } - - return c0; + const uint32_t c0 = buf[0]; + const uint32_t c1 = buf[0]; + if (c0 >= 0xD800 && c0 < 0xDC00) { + if (len < 2) { + return 0xFFFD; // Surrogate, but length is only 1 + } else if (c1 >= 0xDC00 && c1 <= 0xDFFF) { + return ((c0 & 0x03FF) << 10) + (c1 & 0x03FF) + 0x10000; + } + + return 0xFFFD; // Unpaired surrogates + } + + return c0; } static void @@ -390,120 +389,120 @@ initKeyEvent(PuglEventKey* event, WPARAM wParam, LPARAM lParam) { - POINT rpos = { 0, 0 }; - GetCursorPos(&rpos); - - POINT cpos = { rpos.x, rpos.y }; - ScreenToClient(view->impl->hwnd, &rpos); - - const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16); - const unsigned vkey = ((wParam == VK_SHIFT) - ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX) - : (unsigned)wParam); - - const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC); - const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR); - const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1; - const bool ext = lParam & 0x01000000; - - event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; - event->time = GetMessageTime() / 1e3; - event->state = getModifiers(); - event->xRoot = rpos.x; - event->yRoot = rpos.y; - event->x = cpos.x; - event->y = cpos.y; - event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16); - event->key = 0; - - const PuglKey special = keySymToSpecial(vkey); - if (special) { - if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) { - event->key = (uint32_t)special + 1u; // Right hand key - } else { - event->key = (uint32_t)special; - } - } else if (!dead) { - // Translate unshifted key - BYTE keyboardState[256] = {0}; - wchar_t buf[5] = {0}; - - event->key = puglDecodeUTF16( - buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2)); - } + POINT rpos = {0, 0}; + GetCursorPos(&rpos); + + POINT cpos = {rpos.x, rpos.y}; + ScreenToClient(view->impl->hwnd, &rpos); + + const unsigned scode = (uint32_t)((lParam & 0xFF0000) >> 16); + const unsigned vkey = + ((wParam == VK_SHIFT) ? MapVirtualKey(scode, MAPVK_VSC_TO_VK_EX) + : (unsigned)wParam); + + const unsigned vcode = MapVirtualKey(vkey, MAPVK_VK_TO_VSC); + const unsigned kchar = MapVirtualKey(vkey, MAPVK_VK_TO_CHAR); + const bool dead = kchar >> (sizeof(UINT) * 8 - 1) & 1; + const bool ext = lParam & 0x01000000; + + event->type = press ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE; + event->time = GetMessageTime() / 1e3; + event->state = getModifiers(); + event->xRoot = rpos.x; + event->yRoot = rpos.y; + event->x = cpos.x; + event->y = cpos.y; + event->keycode = (uint32_t)((lParam & 0xFF0000) >> 16); + event->key = 0; + + const PuglKey special = keySymToSpecial(vkey); + if (special) { + if (ext && (special == PUGL_KEY_CTRL || special == PUGL_KEY_ALT)) { + event->key = (uint32_t)special + 1u; // Right hand key + } else { + event->key = (uint32_t)special; + } + } else if (!dead) { + // Translate unshifted key + BYTE keyboardState[256] = {0}; + wchar_t buf[5] = {0}; + + event->key = puglDecodeUTF16( + buf, ToUnicode(vkey, vcode, keyboardState, buf, 4, 1 << 2)); + } } static void initCharEvent(PuglEvent* event, PuglView* view, WPARAM wParam, LPARAM lParam) { - const wchar_t utf16[2] = {wParam & 0xFFFF, - (wchar_t)((wParam >> 16) & 0xFFFF)}; + const wchar_t utf16[2] = {wParam & 0xFFFF, + (wchar_t)((wParam >> 16) & 0xFFFF)}; - initKeyEvent(&event->key, view, true, wParam, lParam); - event->type = PUGL_TEXT; - event->text.character = puglDecodeUTF16(utf16, 2); + initKeyEvent(&event->key, view, true, wParam, lParam); + event->type = PUGL_TEXT; + event->text.character = puglDecodeUTF16(utf16, 2); - if (!WideCharToMultiByte( - CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) { - memset(event->text.string, 0, 8); - } + if (!WideCharToMultiByte( + CP_UTF8, 0, utf16, 2, event->text.string, 8, NULL, NULL)) { + memset(event->text.string, 0, 8); + } } static bool ignoreKeyEvent(PuglView* view, LPARAM lParam) { - return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30)); + return view->hints[PUGL_IGNORE_KEY_REPEAT] && (lParam & (1 << 30)); } static RECT handleConfigure(PuglView* view, PuglEvent* event) { - RECT rect; - GetClientRect(view->impl->hwnd, &rect); - MapWindowPoints(view->impl->hwnd, - view->parent ? (HWND)view->parent : HWND_DESKTOP, - (LPPOINT)&rect, - 2); - - const LONG width = rect.right - rect.left; - const LONG height = rect.bottom - rect.top; - - view->frame.x = rect.left; - view->frame.y = rect.top; - - event->configure.type = PUGL_CONFIGURE; - event->configure.x = view->frame.x; - event->configure.y = view->frame.y; - event->configure.width = width; - event->configure.height = height; - - if (view->frame.width != width || view->frame.height != height) { - view->frame.width = width; - view->frame.height = height; - } - - return rect; + RECT rect; + GetClientRect(view->impl->hwnd, &rect); + MapWindowPoints(view->impl->hwnd, + view->parent ? (HWND)view->parent : HWND_DESKTOP, + (LPPOINT)&rect, + 2); + + const LONG width = rect.right - rect.left; + const LONG height = rect.bottom - rect.top; + + view->frame.x = rect.left; + view->frame.y = rect.top; + + event->configure.type = PUGL_CONFIGURE; + event->configure.x = view->frame.x; + event->configure.y = view->frame.y; + event->configure.width = width; + event->configure.height = height; + + if (view->frame.width != width || view->frame.height != height) { + view->frame.width = width; + view->frame.height = height; + } + + return rect; } static void handleCrossing(PuglView* view, const PuglEventType type, POINT pos) { - POINT root_pos = pos; - ClientToScreen(view->impl->hwnd, &root_pos); - - const PuglEventCrossing ev = { - type, - 0, - GetMessageTime() / 1e3, - (double)pos.x, - (double)pos.y, - (double)root_pos.x, - (double)root_pos.y, - getModifiers(), - PUGL_CROSSING_NORMAL, - }; - - puglDispatchEvent(view, (const PuglEvent*)&ev); + POINT root_pos = pos; + ClientToScreen(view->impl->hwnd, &root_pos); + + const PuglEventCrossing ev = { + type, + 0, + GetMessageTime() / 1e3, + (double)pos.x, + (double)pos.y, + (double)root_pos.x, + (double)root_pos.y, + getModifiers(), + PUGL_CROSSING_NORMAL, + }; + + puglDispatchEvent(view, (const PuglEvent*)&ev); } static void @@ -511,501 +510,497 @@ constrainAspect(const PuglView* const view, RECT* const size, const WPARAM wParam) { - const float minA = (float)view->minAspectX / (float)view->minAspectY; - const float maxA = (float)view->maxAspectX / (float)view->maxAspectY; - const float w = (float)(size->right - size->left); - const float h = (float)(size->bottom - size->top); - const float a = w / h; - - switch (wParam) { - case WMSZ_TOP: - size->top = (a < minA ? (LONG)((float)size->bottom - w * minA) : - a > maxA ? (LONG)((float)size->bottom - w * maxA) : - size->top); - break; - case WMSZ_TOPRIGHT: - case WMSZ_RIGHT: - case WMSZ_BOTTOMRIGHT: - size->right = (a < minA ? (LONG)((float)size->left + h * minA) : - a > maxA ? (LONG)((float)size->left + h * maxA) : - size->right); - break; - case WMSZ_BOTTOM: - size->bottom = (a < minA ? (LONG)((float)size->top + w * minA) : - a > maxA ? (LONG)((float)size->top + w * maxA) : - size->bottom); - break; - case WMSZ_BOTTOMLEFT: - case WMSZ_LEFT: - case WMSZ_TOPLEFT: - size->left = (a < minA ? (LONG)((float)size->right - h * minA) : - a > maxA ? (LONG)((float)size->right - h * maxA) : - size->left); - break; - } + const float minA = (float)view->minAspectX / (float)view->minAspectY; + const float maxA = (float)view->maxAspectX / (float)view->maxAspectY; + const float w = (float)(size->right - size->left); + const float h = (float)(size->bottom - size->top); + const float a = w / h; + + switch (wParam) { + case WMSZ_TOP: + size->top = (a < minA ? (LONG)((float)size->bottom - w * minA) + : a > maxA ? (LONG)((float)size->bottom - w * maxA) + : size->top); + break; + case WMSZ_TOPRIGHT: + case WMSZ_RIGHT: + case WMSZ_BOTTOMRIGHT: + size->right = (a < minA ? (LONG)((float)size->left + h * minA) + : a > maxA ? (LONG)((float)size->left + h * maxA) + : size->right); + break; + case WMSZ_BOTTOM: + size->bottom = (a < minA ? (LONG)((float)size->top + w * minA) + : a > maxA ? (LONG)((float)size->top + w * maxA) + : size->bottom); + break; + case WMSZ_BOTTOMLEFT: + case WMSZ_LEFT: + case WMSZ_TOPLEFT: + size->left = (a < minA ? (LONG)((float)size->right - h * minA) + : a > maxA ? (LONG)((float)size->right - h * maxA) + : size->left); + break; + } } static LRESULT handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) { - PuglEvent event = {{PUGL_NOTHING, 0}}; - RECT rect = {0, 0, 0, 0}; - POINT pt = {0, 0}; - MINMAXINFO* mmi = NULL; - void* dummy_ptr = NULL; - - if (InSendMessageEx(dummy_ptr)) { - event.any.flags |= PUGL_IS_SEND_EVENT; - } - - switch (message) { - case WM_SETCURSOR: - if (LOWORD(lParam) == HTCLIENT) { - SetCursor(view->impl->cursor); - } else { - return DefWindowProc(view->impl->hwnd, message, wParam, lParam); - } - break; - case WM_SHOWWINDOW: - if (wParam) { - handleConfigure(view, &event); - puglDispatchEvent(view, &event); - event.type = PUGL_NOTHING; - - RedrawWindow(view->impl->hwnd, NULL, NULL, - RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT); - } - - if ((bool)wParam != view->visible) { - view->visible = wParam; - event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP; - } - break; - case WM_SIZE: - handleConfigure(view, &event); - InvalidateRect(view->impl->hwnd, NULL, false); - break; - case WM_SIZING: - if (view->minAspectX) { - constrainAspect(view, (RECT*)lParam, wParam); - return TRUE; - } - break; - case WM_ENTERSIZEMOVE: - case WM_ENTERMENULOOP: - puglDispatchSimpleEvent(view, PUGL_LOOP_ENTER); - break; - case WM_TIMER: - if (wParam >= PUGL_USER_TIMER_MIN) { - PuglEvent ev = {{PUGL_TIMER, 0}}; - ev.timer.id = wParam - PUGL_USER_TIMER_MIN; - puglDispatchEvent(view, &ev); - } - break; - case WM_EXITSIZEMOVE: - case WM_EXITMENULOOP: - puglDispatchSimpleEvent(view, PUGL_LOOP_LEAVE); - break; - case WM_GETMINMAXINFO: - mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = view->minWidth; - mmi->ptMinTrackSize.y = view->minHeight; - if (view->maxWidth > 0 && view->maxHeight > 0) { - mmi->ptMaxTrackSize.x = view->maxWidth; - mmi->ptMaxTrackSize.y = view->maxHeight; - } - break; - case WM_PAINT: - GetUpdateRect(view->impl->hwnd, &rect, false); - event.expose.type = PUGL_EXPOSE; - event.expose.x = rect.left; - event.expose.y = rect.top; - event.expose.width = rect.right - rect.left; - event.expose.height = rect.bottom - rect.top; - break; - case WM_ERASEBKGND: - return true; - case WM_MOUSEMOVE: - pt.x = GET_X_LPARAM(lParam); - pt.y = GET_Y_LPARAM(lParam); - - if (!view->impl->mouseTracked) { - TRACKMOUSEEVENT tme = {0}; - - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = view->impl->hwnd; - TrackMouseEvent(&tme); - - handleCrossing(view, PUGL_POINTER_IN, pt); - view->impl->mouseTracked = true; - } - - ClientToScreen(view->impl->hwnd, &pt); - event.motion.type = PUGL_MOTION; - event.motion.time = GetMessageTime() / 1e3; - event.motion.x = GET_X_LPARAM(lParam); - event.motion.y = GET_Y_LPARAM(lParam); - event.motion.xRoot = pt.x; - event.motion.yRoot = pt.y; - event.motion.state = getModifiers(); - break; - case WM_MOUSELEAVE: - GetCursorPos(&pt); - ScreenToClient(view->impl->hwnd, &pt); - handleCrossing(view, PUGL_POINTER_OUT, pt); - view->impl->mouseTracked = false; - break; - case WM_LBUTTONDOWN: - initMouseEvent(&event, view, 1, true, lParam); - break; - case WM_MBUTTONDOWN: - initMouseEvent(&event, view, 2, true, lParam); - break; - case WM_RBUTTONDOWN: - initMouseEvent(&event, view, 3, true, lParam); - break; - case WM_LBUTTONUP: - initMouseEvent(&event, view, 1, false, lParam); - break; - case WM_MBUTTONUP: - initMouseEvent(&event, view, 2, false, lParam); - break; - case WM_RBUTTONUP: - initMouseEvent(&event, view, 3, false, lParam); - break; - case WM_MOUSEWHEEL: - initScrollEvent(&event, view, lParam); - event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; - event.scroll.direction = (event.scroll.dy > 0 - ? PUGL_SCROLL_UP - : PUGL_SCROLL_DOWN); - break; - case WM_MOUSEHWHEEL: - initScrollEvent(&event, view, lParam); - event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; - event.scroll.direction = (event.scroll.dx > 0 - ? PUGL_SCROLL_RIGHT - : PUGL_SCROLL_LEFT); - break; - case WM_KEYDOWN: - if (!ignoreKeyEvent(view, lParam)) { - initKeyEvent(&event.key, view, true, wParam, lParam); - } - break; - case WM_KEYUP: - initKeyEvent(&event.key, view, false, wParam, lParam); - break; - case WM_CHAR: - initCharEvent(&event, view, wParam, lParam); - break; - case WM_SETFOCUS: - event.type = PUGL_FOCUS_IN; - break; - case WM_KILLFOCUS: - event.type = PUGL_FOCUS_OUT; - break; - case WM_SYSKEYDOWN: - initKeyEvent(&event.key, view, true, wParam, lParam); - break; - case WM_SYSKEYUP: - initKeyEvent(&event.key, view, false, wParam, lParam); - break; - case WM_SYSCHAR: - return TRUE; - case PUGL_LOCAL_CLIENT_MSG: - event.client.type = PUGL_CLIENT; - event.client.data1 = (uintptr_t)wParam; - event.client.data2 = (uintptr_t)lParam; - break; - case WM_QUIT: - case PUGL_LOCAL_CLOSE_MSG: - event.any.type = PUGL_CLOSE; - break; - default: - return DefWindowProc(view->impl->hwnd, message, wParam, lParam); - } - - puglDispatchEvent(view, &event); - - return 0; + PuglEvent event = {{PUGL_NOTHING, 0}}; + RECT rect = {0, 0, 0, 0}; + POINT pt = {0, 0}; + MINMAXINFO* mmi = NULL; + void* dummy_ptr = NULL; + + if (InSendMessageEx(dummy_ptr)) { + event.any.flags |= PUGL_IS_SEND_EVENT; + } + + switch (message) { + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) { + SetCursor(view->impl->cursor); + } else { + return DefWindowProc(view->impl->hwnd, message, wParam, lParam); + } + break; + case WM_SHOWWINDOW: + if (wParam) { + handleConfigure(view, &event); + puglDispatchEvent(view, &event); + event.type = PUGL_NOTHING; + + RedrawWindow(view->impl->hwnd, + NULL, + NULL, + RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_INTERNALPAINT); + } + + if ((bool)wParam != view->visible) { + view->visible = wParam; + event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP; + } + break; + case WM_SIZE: + handleConfigure(view, &event); + InvalidateRect(view->impl->hwnd, NULL, false); + break; + case WM_SIZING: + if (view->minAspectX) { + constrainAspect(view, (RECT*)lParam, wParam); + return TRUE; + } + break; + case WM_ENTERSIZEMOVE: + case WM_ENTERMENULOOP: + puglDispatchSimpleEvent(view, PUGL_LOOP_ENTER); + break; + case WM_TIMER: + if (wParam >= PUGL_USER_TIMER_MIN) { + PuglEvent ev = {{PUGL_TIMER, 0}}; + ev.timer.id = wParam - PUGL_USER_TIMER_MIN; + puglDispatchEvent(view, &ev); + } + break; + case WM_EXITSIZEMOVE: + case WM_EXITMENULOOP: + puglDispatchSimpleEvent(view, PUGL_LOOP_LEAVE); + break; + case WM_GETMINMAXINFO: + mmi = (MINMAXINFO*)lParam; + mmi->ptMinTrackSize.x = view->minWidth; + mmi->ptMinTrackSize.y = view->minHeight; + if (view->maxWidth > 0 && view->maxHeight > 0) { + mmi->ptMaxTrackSize.x = view->maxWidth; + mmi->ptMaxTrackSize.y = view->maxHeight; + } + break; + case WM_PAINT: + GetUpdateRect(view->impl->hwnd, &rect, false); + event.expose.type = PUGL_EXPOSE; + event.expose.x = rect.left; + event.expose.y = rect.top; + event.expose.width = rect.right - rect.left; + event.expose.height = rect.bottom - rect.top; + break; + case WM_ERASEBKGND: + return true; + case WM_MOUSEMOVE: + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + + if (!view->impl->mouseTracked) { + TRACKMOUSEEVENT tme = {0}; + + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = view->impl->hwnd; + TrackMouseEvent(&tme); + + handleCrossing(view, PUGL_POINTER_IN, pt); + view->impl->mouseTracked = true; + } + + ClientToScreen(view->impl->hwnd, &pt); + event.motion.type = PUGL_MOTION; + event.motion.time = GetMessageTime() / 1e3; + event.motion.x = GET_X_LPARAM(lParam); + event.motion.y = GET_Y_LPARAM(lParam); + event.motion.xRoot = pt.x; + event.motion.yRoot = pt.y; + event.motion.state = getModifiers(); + break; + case WM_MOUSELEAVE: + GetCursorPos(&pt); + ScreenToClient(view->impl->hwnd, &pt); + handleCrossing(view, PUGL_POINTER_OUT, pt); + view->impl->mouseTracked = false; + break; + case WM_LBUTTONDOWN: + initMouseEvent(&event, view, 1, true, lParam); + break; + case WM_MBUTTONDOWN: + initMouseEvent(&event, view, 2, true, lParam); + break; + case WM_RBUTTONDOWN: + initMouseEvent(&event, view, 3, true, lParam); + break; + case WM_LBUTTONUP: + initMouseEvent(&event, view, 1, false, lParam); + break; + case WM_MBUTTONUP: + initMouseEvent(&event, view, 2, false, lParam); + break; + case WM_RBUTTONUP: + initMouseEvent(&event, view, 3, false, lParam); + break; + case WM_MOUSEWHEEL: + initScrollEvent(&event, view, lParam); + event.scroll.dy = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; + event.scroll.direction = + (event.scroll.dy > 0 ? PUGL_SCROLL_UP : PUGL_SCROLL_DOWN); + break; + case WM_MOUSEHWHEEL: + initScrollEvent(&event, view, lParam); + event.scroll.dx = GET_WHEEL_DELTA_WPARAM(wParam) / (double)WHEEL_DELTA; + event.scroll.direction = + (event.scroll.dx > 0 ? PUGL_SCROLL_RIGHT : PUGL_SCROLL_LEFT); + break; + case WM_KEYDOWN: + if (!ignoreKeyEvent(view, lParam)) { + initKeyEvent(&event.key, view, true, wParam, lParam); + } + break; + case WM_KEYUP: + initKeyEvent(&event.key, view, false, wParam, lParam); + break; + case WM_CHAR: + initCharEvent(&event, view, wParam, lParam); + break; + case WM_SETFOCUS: + event.type = PUGL_FOCUS_IN; + break; + case WM_KILLFOCUS: + event.type = PUGL_FOCUS_OUT; + break; + case WM_SYSKEYDOWN: + initKeyEvent(&event.key, view, true, wParam, lParam); + break; + case WM_SYSKEYUP: + initKeyEvent(&event.key, view, false, wParam, lParam); + break; + case WM_SYSCHAR: + return TRUE; + case PUGL_LOCAL_CLIENT_MSG: + event.client.type = PUGL_CLIENT; + event.client.data1 = (uintptr_t)wParam; + event.client.data2 = (uintptr_t)lParam; + break; + case WM_QUIT: + case PUGL_LOCAL_CLOSE_MSG: + event.any.type = PUGL_CLOSE; + break; + default: + return DefWindowProc(view->impl->hwnd, message, wParam, lParam); + } + + puglDispatchEvent(view, &event); + + return 0; } PuglStatus puglGrabFocus(PuglView* view) { - SetFocus(view->impl->hwnd); - return PUGL_SUCCESS; + SetFocus(view->impl->hwnd); + return PUGL_SUCCESS; } bool puglHasFocus(const PuglView* view) { - return GetFocus() == view->impl->hwnd; + return GetFocus() == view->impl->hwnd; } PuglStatus puglRequestAttention(PuglView* view) { - FLASHWINFO info = {sizeof(FLASHWINFO), - view->impl->hwnd, - FLASHW_ALL|FLASHW_TIMERNOFG, - 1, - 0}; + FLASHWINFO info = { + sizeof(FLASHWINFO), view->impl->hwnd, FLASHW_ALL | FLASHW_TIMERNOFG, 1, 0}; - FlashWindowEx(&info); + FlashWindowEx(&info); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglStartTimer(PuglView* view, uintptr_t id, double timeout) { - const UINT msec = (UINT)floor(timeout * 1000.0); + const UINT msec = (UINT)floor(timeout * 1000.0); - return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL) - ? PUGL_SUCCESS - : PUGL_UNKNOWN_ERROR); + return (SetTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id, msec, NULL) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR); } PuglStatus puglStopTimer(PuglView* view, uintptr_t id) { - return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id) - ? PUGL_SUCCESS - : PUGL_UNKNOWN_ERROR); + return (KillTimer(view->impl->hwnd, PUGL_USER_TIMER_MIN + id) + ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR); } PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) { - if (event->type == PUGL_CLIENT) { - PostMessage(view->impl->hwnd, - PUGL_LOCAL_CLIENT_MSG, - (WPARAM)event->client.data1, - (LPARAM)event->client.data2); + if (event->type == PUGL_CLIENT) { + PostMessage(view->impl->hwnd, + PUGL_LOCAL_CLIENT_MSG, + (WPARAM)event->client.data1, + (LPARAM)event->client.data2); - return PUGL_SUCCESS; - } + return PUGL_SUCCESS; + } - return PUGL_UNSUPPORTED_TYPE; + return PUGL_UNSUPPORTED_TYPE; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglWaitForEvent(PuglView* PUGL_UNUSED(view)) { - WaitMessage(); - return PUGL_SUCCESS; + WaitMessage(); + return PUGL_SUCCESS; } #endif static PuglStatus puglDispatchViewEvents(PuglView* view) { - /* Windows has no facility to process only currently queued messages, which - causes the event loop to run forever in cases like mouse movement where - the queue is constantly being filled with new messages. To work around - this, we post a message to ourselves before starting, record its time - when it is received, then break the loop on the first message that was - created afterwards. */ - - long markTime = 0; - MSG msg; - while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { - if (msg.message == PUGL_LOCAL_MARK_MSG) { - markTime = GetMessageTime(); - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - if (markTime != 0 && GetMessageTime() > markTime) { - break; - } - } - } - - return PUGL_SUCCESS; + /* Windows has no facility to process only currently queued messages, which + causes the event loop to run forever in cases like mouse movement where + the queue is constantly being filled with new messages. To work around + this, we post a message to ourselves before starting, record its time + when it is received, then break the loop on the first message that was + created afterwards. */ + + long markTime = 0; + MSG msg; + while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { + if (msg.message == PUGL_LOCAL_MARK_MSG) { + markTime = GetMessageTime(); + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (markTime != 0 && GetMessageTime() > markTime) { + break; + } + } + } + + return PUGL_SUCCESS; } static PuglStatus puglDispatchWinEvents(PuglWorld* world) { - for (size_t i = 0; i < world->numViews; ++i) { - PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0); - } + for (size_t i = 0; i < world->numViews; ++i) { + PostMessage(world->views[i]->impl->hwnd, PUGL_LOCAL_MARK_MSG, 0, 0); + } - for (size_t i = 0; i < world->numViews; ++i) { - puglDispatchViewEvents(world->views[i]); - } + for (size_t i = 0; i < world->numViews; ++i) { + puglDispatchViewEvents(world->views[i]); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglUpdate(PuglWorld* world, double timeout) { - const double startTime = puglGetTime(world); - PuglStatus st = PUGL_SUCCESS; - - if (timeout < 0.0) { - st = puglPollWinEvents(world, timeout); - st = st ? st : puglDispatchWinEvents(world); - } else if (timeout == 0.0) { - st = puglDispatchWinEvents(world); - } else { - const double endTime = startTime + timeout - 0.001; - for (double t = startTime; t < endTime; t = puglGetTime(world)) { - if ((st = puglPollWinEvents(world, endTime - t)) || - (st = puglDispatchWinEvents(world))) { - break; - } - } - } - - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i]->visible) { - puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE); - } - - UpdateWindow(world->views[i]->impl->hwnd); - } - - return st; + const double startTime = puglGetTime(world); + PuglStatus st = PUGL_SUCCESS; + + if (timeout < 0.0) { + st = puglPollWinEvents(world, timeout); + st = st ? st : puglDispatchWinEvents(world); + } else if (timeout == 0.0) { + st = puglDispatchWinEvents(world); + } else { + const double endTime = startTime + timeout - 0.001; + for (double t = startTime; t < endTime; t = puglGetTime(world)) { + if ((st = puglPollWinEvents(world, endTime - t)) || + (st = puglDispatchWinEvents(world))) { + break; + } + } + } + + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i]->visible) { + puglDispatchSimpleEvent(world->views[i], PUGL_UPDATE); + } + + UpdateWindow(world->views[i]->impl->hwnd); + } + + return st; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglProcessEvents(PuglView* view) { - return puglUpdate(view->world, 0.0); + return puglUpdate(view->world, 0.0); } #endif LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch (message) { - case WM_CREATE: - PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); - return 0; - case WM_CLOSE: - PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); - return 0; - case WM_DESTROY: - return 0; - default: - if (view && hwnd == view->impl->hwnd) { - return handleMessage(view, message, wParam, lParam); - } else { - return DefWindowProc(hwnd, message, wParam, lParam); - } - } + PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch (message) { + case WM_CREATE: + PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); + return 0; + case WM_CLOSE: + PostMessage(hwnd, PUGL_LOCAL_CLOSE_MSG, wParam, lParam); + return 0; + case WM_DESTROY: + return 0; + default: + if (view && hwnd == view->impl->hwnd) { + return handleMessage(view, message, wParam, lParam); + } else { + return DefWindowProc(hwnd, message, wParam, lParam); + } + } } double puglGetTime(const PuglWorld* world) { - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return ((double)count.QuadPart / world->impl->timerFrequency - - world->startTime); + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return ((double)count.QuadPart / world->impl->timerFrequency - + world->startTime); } PuglStatus puglPostRedisplay(PuglView* view) { - InvalidateRect(view->impl->hwnd, NULL, false); - return PUGL_SUCCESS; + InvalidateRect(view->impl->hwnd, NULL, false); + return PUGL_SUCCESS; } PuglStatus puglPostRedisplayRect(PuglView* view, const PuglRect rect) { - const RECT r = {(long)floor(rect.x), - (long)floor(rect.y), - (long)ceil(rect.x + rect.width), - (long)ceil(rect.y + rect.height)}; + const RECT r = {(long)floor(rect.x), + (long)floor(rect.y), + (long)ceil(rect.x + rect.width), + (long)ceil(rect.y + rect.height)}; - InvalidateRect(view->impl->hwnd, &r, false); + InvalidateRect(view->impl->hwnd, &r, false); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglNativeView puglGetNativeWindow(PuglView* view) { - return (PuglNativeView)view->impl->hwnd; + return (PuglNativeView)view->impl->hwnd; } PuglStatus puglSetWindowTitle(PuglView* view, const char* title) { - puglSetString(&view->title, title); + puglSetString(&view->title, title); - if (view->impl->hwnd) { - wchar_t* wtitle = puglUtf8ToWideChar(title); - if (wtitle) { - SetWindowTextW(view->impl->hwnd, wtitle); - free(wtitle); - } - } + if (view->impl->hwnd) { + wchar_t* wtitle = puglUtf8ToWideChar(title); + if (wtitle) { + SetWindowTextW(view->impl->hwnd, wtitle); + free(wtitle); + } + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { - view->frame = frame; - - if (view->impl->hwnd) { - RECT rect = { (long)frame.x, - (long)frame.y, - (long)frame.x + (long)frame.width, - (long)frame.y + (long)frame.height }; - - AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), - FALSE, - puglWinGetWindowExFlags(view)); - - if (!SetWindowPos(view->impl->hwnd, - HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) { - return PUGL_UNKNOWN_ERROR; - } - } - - return PUGL_SUCCESS; + view->frame = frame; + + if (view->impl->hwnd) { + RECT rect = {(long)frame.x, + (long)frame.y, + (long)frame.x + (long)frame.width, + (long)frame.y + (long)frame.height}; + + AdjustWindowRectEx( + &rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); + + if (!SetWindowPos(view->impl->hwnd, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER)) { + return PUGL_UNKNOWN_ERROR; + } + } + + return PUGL_SUCCESS; } PuglStatus puglSetDefaultSize(PuglView* const view, const int width, const int height) { - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; + view->defaultWidth = width; + view->defaultHeight = height; + return PUGL_SUCCESS; } PuglStatus puglSetMinSize(PuglView* const view, const int width, const int height) { - view->minWidth = width; - view->minHeight = height; - return PUGL_SUCCESS; + view->minWidth = width; + view->minHeight = height; + return PUGL_SUCCESS; } PuglStatus puglSetMaxSize(PuglView* const view, const int width, const int height) { - view->maxWidth = width; - view->maxHeight = height; - return PUGL_SUCCESS; + view->maxWidth = width; + view->maxHeight = height; + return PUGL_SUCCESS; } PuglStatus @@ -1015,28 +1010,28 @@ puglSetAspectRatio(PuglView* const view, const int maxX, const int maxY) { - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - return PUGL_SUCCESS; + view->minAspectX = minX; + view->minAspectY = minY; + view->maxAspectX = maxX; + view->maxAspectY = maxY; + return PUGL_SUCCESS; } PuglStatus puglSetTransientFor(PuglView* view, PuglNativeView parent) { - if (view->parent) { - return PUGL_FAILURE; - } + if (view->parent) { + return PUGL_FAILURE; + } - view->transientParent = parent; + view->transientParent = parent; - if (view->impl->hwnd) { - SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent); - return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE; - } + if (view->impl->hwnd) { + SetWindowLongPtr(view->impl->hwnd, GWLP_HWNDPARENT, (LONG_PTR)parent); + return GetLastError() == NO_ERROR ? PUGL_SUCCESS : PUGL_FAILURE; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } const void* @@ -1044,26 +1039,26 @@ puglGetClipboard(PuglView* const view, const char** const type, size_t* const len) { - PuglInternals* const impl = view->impl; - - if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || - !OpenClipboard(impl->hwnd)) { - return NULL; - } - - HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); - wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL; - if (!wstr) { - CloseClipboard(); - return NULL; - } - - free(view->clipboard.data); - view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len); - GlobalUnlock(mem); - CloseClipboard(); - - return puglGetInternalClipboard(view, type, len); + PuglInternals* const impl = view->impl; + + if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || + !OpenClipboard(impl->hwnd)) { + return NULL; + } + + HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); + wchar_t* wstr = mem ? (wchar_t*)GlobalLock(mem) : NULL; + if (!wstr) { + CloseClipboard(); + return NULL; + } + + free(view->clipboard.data); + view->clipboard.data = puglWideCharToUtf8(wstr, &view->clipboard.len); + GlobalUnlock(mem); + CloseClipboard(); + + return puglGetInternalClipboard(view, type, len); } PuglStatus @@ -1072,72 +1067,72 @@ puglSetClipboard(PuglView* const view, const void* const data, const size_t len) { - PuglInternals* const impl = view->impl; - - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } else if (!OpenClipboard(impl->hwnd)) { - return PUGL_UNKNOWN_ERROR; - } - - // Measure string and allocate global memory for clipboard - const char* str = (const char*)data; - const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, - (size_t)(wlen + 1) * sizeof(wchar_t)); - if (!mem) { - CloseClipboard(); - return PUGL_UNKNOWN_ERROR; - } - - // Lock global memory - wchar_t* wstr = (wchar_t*)GlobalLock(mem); - if (!wstr) { - GlobalFree(mem); - CloseClipboard(); - return PUGL_UNKNOWN_ERROR; - } - - // Convert string into global memory and set it as clipboard data - MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen); - wstr[wlen] = 0; - GlobalUnlock(mem); - SetClipboardData(CF_UNICODETEXT, mem); - CloseClipboard(); - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + + PuglStatus st = puglSetInternalClipboard(view, type, data, len); + if (st) { + return st; + } else if (!OpenClipboard(impl->hwnd)) { + return PUGL_UNKNOWN_ERROR; + } + + // Measure string and allocate global memory for clipboard + const char* str = (const char*)data; + const int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + HGLOBAL mem = + GlobalAlloc(GMEM_MOVEABLE, (size_t)(wlen + 1) * sizeof(wchar_t)); + if (!mem) { + CloseClipboard(); + return PUGL_UNKNOWN_ERROR; + } + + // Lock global memory + wchar_t* wstr = (wchar_t*)GlobalLock(mem); + if (!wstr) { + GlobalFree(mem); + CloseClipboard(); + return PUGL_UNKNOWN_ERROR; + } + + // Convert string into global memory and set it as clipboard data + MultiByteToWideChar(CP_UTF8, 0, str, (int)len, wstr, wlen); + wstr[wlen] = 0; + GlobalUnlock(mem); + SetClipboardData(CF_UNICODETEXT, mem); + CloseClipboard(); + return PUGL_SUCCESS; } static const char* const cursor_ids[] = { - IDC_ARROW, // ARROW - IDC_IBEAM, // CARET - IDC_CROSS, // CROSSHAIR - IDC_HAND, // HAND - IDC_NO, // NO - IDC_SIZEWE, // LEFT_RIGHT - IDC_SIZENS, // UP_DOWN + IDC_ARROW, // ARROW + IDC_IBEAM, // CARET + IDC_CROSS, // CROSSHAIR + IDC_HAND, // HAND + IDC_NO, // NO + IDC_SIZEWE, // LEFT_RIGHT + IDC_SIZENS, // UP_DOWN }; PuglStatus puglSetCursor(PuglView* view, PuglCursor cursor) { - PuglInternals* const impl = view->impl; - const unsigned index = (unsigned)cursor; - const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]); + PuglInternals* const impl = view->impl; + const unsigned index = (unsigned)cursor; + const unsigned count = sizeof(cursor_ids) / sizeof(cursor_ids[0]); - if (index >= count) { - return PUGL_BAD_PARAMETER; - } + if (index >= count) { + return PUGL_BAD_PARAMETER; + } - const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]); - if (!cur) { - return PUGL_FAILURE; - } + const HCURSOR cur = LoadCursor(NULL, cursor_ids[index]); + if (!cur) { + return PUGL_FAILURE; + } - impl->cursor = cur; - if (impl->mouseTracked) { - SetCursor(cur); - } + impl->cursor = cur; + if (impl->mouseTracked) { + SetCursor(cur); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } @@ -26,62 +26,62 @@ typedef PIXELFORMATDESCRIPTOR PuglWinPFD; struct PuglWorldInternalsImpl { - double timerFrequency; + double timerFrequency; }; struct PuglInternalsImpl { - PuglWinPFD pfd; - int pfId; - HWND hwnd; - HCURSOR cursor; - HDC hdc; - PuglSurface* surface; - bool flashing; - bool mouseTracked; + PuglWinPFD pfd; + int pfId; + HWND hwnd; + HCURSOR cursor; + HDC hdc; + PuglSurface* surface; + bool flashing; + bool mouseTracked; }; static inline PuglWinPFD puglWinGetPixelFormatDescriptor(const PuglHints hints) { - const int rgbBits = (hints[PUGL_RED_BITS] + // - hints[PUGL_GREEN_BITS] + // - hints[PUGL_BLUE_BITS]); - - const DWORD dwFlags = hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0u; - - PuglWinPFD pfd; - ZeroMemory(&pfd, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | dwFlags; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = (BYTE)rgbBits; - pfd.cRedBits = (BYTE)hints[PUGL_RED_BITS]; - pfd.cGreenBits = (BYTE)hints[PUGL_GREEN_BITS]; - pfd.cBlueBits = (BYTE)hints[PUGL_BLUE_BITS]; - pfd.cAlphaBits = (BYTE)hints[PUGL_ALPHA_BITS]; - pfd.cDepthBits = (BYTE)hints[PUGL_DEPTH_BITS]; - pfd.cStencilBits = (BYTE)hints[PUGL_STENCIL_BITS]; - pfd.iLayerType = PFD_MAIN_PLANE; - return pfd; + const int rgbBits = (hints[PUGL_RED_BITS] + // + hints[PUGL_GREEN_BITS] + // + hints[PUGL_BLUE_BITS]); + + const DWORD dwFlags = hints[PUGL_DOUBLE_BUFFER] ? PFD_DOUBLEBUFFER : 0u; + + PuglWinPFD pfd; + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | dwFlags; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = (BYTE)rgbBits; + pfd.cRedBits = (BYTE)hints[PUGL_RED_BITS]; + pfd.cGreenBits = (BYTE)hints[PUGL_GREEN_BITS]; + pfd.cBlueBits = (BYTE)hints[PUGL_BLUE_BITS]; + pfd.cAlphaBits = (BYTE)hints[PUGL_ALPHA_BITS]; + pfd.cDepthBits = (BYTE)hints[PUGL_DEPTH_BITS]; + pfd.cStencilBits = (BYTE)hints[PUGL_STENCIL_BITS]; + pfd.iLayerType = PFD_MAIN_PLANE; + return pfd; } static inline unsigned puglWinGetWindowFlags(const PuglView* const view) { - const bool resizable = view->hints[PUGL_RESIZABLE]; - const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u; + const bool resizable = view->hints[PUGL_RESIZABLE]; + const unsigned sizeFlags = resizable ? (WS_SIZEBOX | WS_MAXIMIZEBOX) : 0u; - return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | - (view->parent - ? WS_CHILD - : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | sizeFlags))); + return (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | + (view->parent + ? WS_CHILD + : (WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | sizeFlags))); } static inline unsigned puglWinGetWindowExFlags(const PuglView* const view) { - return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW); + return WS_EX_NOINHERITLAYOUT | (view->parent ? 0u : WS_EX_APPWINDOW); } static inline PuglStatus @@ -90,48 +90,58 @@ puglWinCreateWindow(PuglView* const view, HWND* const hwnd, HDC* const hdc) { - const char* className = (const char*)view->world->className; - const unsigned winFlags = puglWinGetWindowFlags(view); - const unsigned winExFlags = puglWinGetWindowExFlags(view); - - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - RECT desktopRect; - GetClientRect(GetDesktopWindow(), &desktopRect); - - const int screenWidth = desktopRect.right - desktopRect.left; - const int screenHeight = desktopRect.bottom - desktopRect.top; - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; - } - - // The meaning of "parent" depends on the window type (WS_CHILD) - PuglNativeView parent = view->parent ? view->parent : view->transientParent; - - // Calculate total window size to accommodate requested view size - RECT wr = { (long)view->frame.x, (long)view->frame.y, - (long)view->frame.width, (long)view->frame.height }; - AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); - - // Create window and get drawing context - if (!(*hwnd = CreateWindowEx(winExFlags, className, title, winFlags, - CW_USEDEFAULT, CW_USEDEFAULT, - wr.right-wr.left, wr.bottom-wr.top, - (HWND)parent, NULL, NULL, NULL))) { - return PUGL_REALIZE_FAILED; - } else if (!(*hdc = GetDC(*hwnd))) { - DestroyWindow(*hwnd); - *hwnd = NULL; - return PUGL_REALIZE_FAILED; - } - - return PUGL_SUCCESS; + const char* className = (const char*)view->world->className; + const unsigned winFlags = puglWinGetWindowFlags(view); + const unsigned winExFlags = puglWinGetWindowExFlags(view); + + if (view->frame.width == 0.0 && view->frame.height == 0.0) { + if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { + return PUGL_BAD_CONFIGURATION; + } + + RECT desktopRect; + GetClientRect(GetDesktopWindow(), &desktopRect); + + const int screenWidth = desktopRect.right - desktopRect.left; + const int screenHeight = desktopRect.bottom - desktopRect.top; + + view->frame.width = view->defaultWidth; + view->frame.height = view->defaultHeight; + view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; + view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; + } + + // The meaning of "parent" depends on the window type (WS_CHILD) + PuglNativeView parent = view->parent ? view->parent : view->transientParent; + + // Calculate total window size to accommodate requested view size + RECT wr = {(long)view->frame.x, + (long)view->frame.y, + (long)view->frame.width, + (long)view->frame.height}; + AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); + + // Create window and get drawing context + if (!(*hwnd = CreateWindowEx(winExFlags, + className, + title, + winFlags, + CW_USEDEFAULT, + CW_USEDEFAULT, + wr.right - wr.left, + wr.bottom - wr.top, + (HWND)parent, + NULL, + NULL, + NULL))) { + return PUGL_REALIZE_FAILED; + } else if (!(*hdc = GetDC(*hwnd))) { + DestroyWindow(*hwnd); + *hwnd = NULL; + return PUGL_REALIZE_FAILED; + } + + return PUGL_SUCCESS; } PuglStatus diff --git a/src/win_cairo.c b/src/win_cairo.c index bab8ea0..9dc5ce0 100644 --- a/src/win_cairo.c +++ b/src/win_cairo.c @@ -25,149 +25,154 @@ #include <stdlib.h> -typedef struct { - cairo_surface_t* surface; - cairo_t* cr; - HDC drawDc; - HBITMAP drawBitmap; +typedef struct { + cairo_surface_t* surface; + cairo_t* cr; + HDC drawDc; + HBITMAP drawBitmap; } PuglWinCairoSurface; static PuglStatus puglWinCairoCreateDrawContext(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - surface->drawDc = CreateCompatibleDC(impl->hdc); - surface->drawBitmap = CreateCompatibleBitmap( - impl->hdc, (int)view->frame.width, (int)view->frame.height); + surface->drawDc = CreateCompatibleDC(impl->hdc); + surface->drawBitmap = CreateCompatibleBitmap( + impl->hdc, (int)view->frame.width, (int)view->frame.height); - DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap)); + DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap)); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglWinCairoDestroyDrawContext(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - DeleteDC(surface->drawDc); - DeleteObject(surface->drawBitmap); + DeleteDC(surface->drawDc); + DeleteObject(surface->drawBitmap); - surface->drawDc = NULL; - surface->drawBitmap = NULL; + surface->drawDc = NULL; + surface->drawBitmap = NULL; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglWinCairoConfigure(PuglView* view) { - const PuglStatus st = puglWinStubConfigure(view); + const PuglStatus st = puglWinStubConfigure(view); - if (!st) { - view->impl->surface = (PuglWinCairoSurface*)calloc( - 1, sizeof(PuglWinCairoSurface)); - } + if (!st) { + view->impl->surface = + (PuglWinCairoSurface*)calloc(1, sizeof(PuglWinCairoSurface)); + } - return st; + return st; } static void puglWinCairoClose(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - cairo_surface_destroy(surface->surface); + cairo_surface_destroy(surface->surface); - surface->surface = NULL; + surface->surface = NULL; } static PuglStatus puglWinCairoOpen(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) || - cairo_surface_status(surface->surface) || - !(surface->cr = cairo_create(surface->surface)) || - cairo_status(surface->cr)) { - return PUGL_CREATE_CONTEXT_FAILED; - } + if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) || + cairo_surface_status(surface->surface) || + !(surface->cr = cairo_create(surface->surface)) || + cairo_status(surface->cr)) { + return PUGL_CREATE_CONTEXT_FAILED; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglWinCairoDestroy(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - puglWinCairoClose(view); - puglWinCairoDestroyDrawContext(view); - free(surface); - impl->surface = NULL; + puglWinCairoClose(view); + puglWinCairoDestroyDrawContext(view); + free(surface); + impl->surface = NULL; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglWinCairoEnter(PuglView* view, const PuglEventExpose* expose) { - PuglStatus st = PUGL_SUCCESS; + PuglStatus st = PUGL_SUCCESS; - if (expose && - !(st = puglWinCairoCreateDrawContext(view)) && - !(st = puglWinCairoOpen(view))) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } + if (expose && !(st = puglWinCairoCreateDrawContext(view)) && + !(st = puglWinCairoOpen(view))) { + PAINTSTRUCT ps; + BeginPaint(view->impl->hwnd, &ps); + } - return st; + return st; } static PuglStatus puglWinCairoLeave(PuglView* view, const PuglEventExpose* expose) { - PuglInternals* const impl = view->impl; - PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; - - if (expose) { - cairo_surface_flush(surface->surface); - BitBlt(impl->hdc, - 0, 0, (int)view->frame.width, (int)view->frame.height, - surface->drawDc, 0, 0, SRCCOPY); - - puglWinCairoClose(view); - puglWinCairoDestroyDrawContext(view); - - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - } - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + + if (expose) { + cairo_surface_flush(surface->surface); + BitBlt(impl->hdc, + 0, + 0, + (int)view->frame.width, + (int)view->frame.height, + surface->drawDc, + 0, + 0, + SRCCOPY); + + puglWinCairoClose(view); + puglWinCairoDestroyDrawContext(view); + + PAINTSTRUCT ps; + EndPaint(view->impl->hwnd, &ps); + } + + return PUGL_SUCCESS; } static void* puglWinCairoGetContext(PuglView* view) { - return ((PuglWinCairoSurface*)view->impl->surface)->cr; + return ((PuglWinCairoSurface*)view->impl->surface)->cr; } const PuglBackend* puglCairoBackend() { - static const PuglBackend backend = {puglWinCairoConfigure, - puglStubCreate, - puglWinCairoDestroy, - puglWinCairoEnter, - puglWinCairoLeave, - puglWinCairoGetContext}; - - return &backend; + static const PuglBackend backend = {puglWinCairoConfigure, + puglStubCreate, + puglWinCairoDestroy, + puglWinCairoEnter, + puglWinCairoLeave, + puglWinCairoGetContext}; + + return &backend; } diff --git a/src/win_gl.c b/src/win_gl.c index fcf511b..4abd5ab 100644 --- a/src/win_gl.c +++ b/src/win_gl.c @@ -27,305 +27,301 @@ #include <stdbool.h> #include <stdlib.h> -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_ALPHA_BITS_ARB 0x201b -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ALPHA_BITS_ARB 0x201b +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 #define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 typedef HGLRC (*WglCreateContextAttribs)(HDC, HGLRC, const int*); typedef BOOL (*WglSwapInterval)(int); -typedef BOOL (*WglChoosePixelFormat)( - HDC, const int*, const FLOAT*, UINT, int*, UINT*); +typedef BOOL ( + *WglChoosePixelFormat)(HDC, const int*, const FLOAT*, UINT, int*, UINT*); typedef struct { - WglChoosePixelFormat wglChoosePixelFormat; - WglCreateContextAttribs wglCreateContextAttribs; - WglSwapInterval wglSwapInterval; + WglChoosePixelFormat wglChoosePixelFormat; + WglCreateContextAttribs wglCreateContextAttribs; + WglSwapInterval wglSwapInterval; } PuglWinGlProcs; typedef struct { - PuglWinGlProcs procs; - HGLRC hglrc; + PuglWinGlProcs procs; + HGLRC hglrc; } PuglWinGlSurface; // Struct to manage the fake window used during configuration typedef struct { - HWND hwnd; - HDC hdc; + HWND hwnd; + HDC hdc; } PuglFakeWindow; static PuglStatus puglWinError(PuglFakeWindow* fakeWin, const PuglStatus status) { - if (fakeWin->hwnd) { - ReleaseDC(fakeWin->hwnd, fakeWin->hdc); - DestroyWindow(fakeWin->hwnd); - } + if (fakeWin->hwnd) { + ReleaseDC(fakeWin->hwnd, fakeWin->hdc); + DestroyWindow(fakeWin->hwnd); + } - return status; + return status; } -static PuglWinGlProcs puglWinGlGetProcs(void) +static PuglWinGlProcs +puglWinGlGetProcs(void) { - const PuglWinGlProcs procs = { - (WglChoosePixelFormat)( - wglGetProcAddress("wglChoosePixelFormatARB")), - (WglCreateContextAttribs)( - wglGetProcAddress("wglCreateContextAttribsARB")), - (WglSwapInterval)( - wglGetProcAddress("wglSwapIntervalEXT")) - }; - - return procs; + const PuglWinGlProcs procs = { + (WglChoosePixelFormat)(wglGetProcAddress("wglChoosePixelFormatARB")), + (WglCreateContextAttribs)(wglGetProcAddress("wglCreateContextAttribsARB")), + (WglSwapInterval)(wglGetProcAddress("wglSwapIntervalEXT"))}; + + return procs; } static PuglStatus puglWinGlConfigure(PuglView* view) { - PuglInternals* impl = view->impl; - - // Set attributes to default if they are unset - // (There is no GLX_DONT_CARE equivalent on Windows) - if (view->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_DEPTH_BITS] = 0; - } - if (view->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { - view->hints[PUGL_STENCIL_BITS] = 0; - } - if (view->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { - view->hints[PUGL_SAMPLES] = 1; - } - if (view->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { - view->hints[PUGL_DOUBLE_BUFFER] = 1; - } - if (view->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { - view->hints[PUGL_SWAP_INTERVAL] = 1; - } - - // clang-format off - const int pixelAttrs[] = { - WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_SUPPORT_OPENGL_ARB, GL_TRUE, - WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER], - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, - WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0, - WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES], - WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS], - WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS], - WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS], - WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS], - WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS], - WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS], - 0, - }; - // clang-format on - - PuglWinGlSurface* const surface = - (PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface)); - impl->surface = surface; - - // Create fake window for getting at GL context - PuglStatus st = PUGL_SUCCESS; - PuglFakeWindow fakeWin = {0, 0}; - static const char* title = "Pugl Configuration"; - if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) { - return puglWinError(&fakeWin, st); - } - - // Set pixel format for fake window - const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints); - const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd); - if (!fakePfId || !SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) { - return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); - } - - // Create fake GL context to get at the functions we need - HGLRC fakeRc = wglCreateContext(fakeWin.hdc); - if (!fakeRc) { - return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED); - } - - // Enter fake context and get extension functions - wglMakeCurrent(fakeWin.hdc, fakeRc); - surface->procs = puglWinGlGetProcs(); - - if (surface->procs.wglChoosePixelFormat) { - // Choose pixel format based on attributes - UINT numFormats = 0; - if (!surface->procs.wglChoosePixelFormat( - fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) { - return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); - } - - DescribePixelFormat( - impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd); - } else { - // Modern extensions not available, use basic pixel format - impl->pfd = fakePfd; - impl->pfId = fakePfId; - } - - // Dispose of fake window and context - wglMakeCurrent(NULL, NULL); - wglDeleteContext(fakeRc); - ReleaseDC(fakeWin.hwnd, fakeWin.hdc); - DestroyWindow(fakeWin.hwnd); - - return PUGL_SUCCESS; + PuglInternals* impl = view->impl; + + // Set attributes to default if they are unset + // (There is no GLX_DONT_CARE equivalent on Windows) + if (view->hints[PUGL_DEPTH_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_DEPTH_BITS] = 0; + } + if (view->hints[PUGL_STENCIL_BITS] == PUGL_DONT_CARE) { + view->hints[PUGL_STENCIL_BITS] = 0; + } + if (view->hints[PUGL_SAMPLES] == PUGL_DONT_CARE) { + view->hints[PUGL_SAMPLES] = 1; + } + if (view->hints[PUGL_DOUBLE_BUFFER] == PUGL_DONT_CARE) { + view->hints[PUGL_DOUBLE_BUFFER] = 1; + } + if (view->hints[PUGL_SWAP_INTERVAL] == PUGL_DONT_CARE) { + view->hints[PUGL_SWAP_INTERVAL] = 1; + } + + // clang-format off + const int pixelAttrs[] = { + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_DOUBLE_BUFFER_ARB, view->hints[PUGL_DOUBLE_BUFFER], + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_SAMPLE_BUFFERS_ARB, view->hints[PUGL_SAMPLES] ? 1 : 0, + WGL_SAMPLES_ARB, view->hints[PUGL_SAMPLES], + WGL_RED_BITS_ARB, view->hints[PUGL_RED_BITS], + WGL_GREEN_BITS_ARB, view->hints[PUGL_GREEN_BITS], + WGL_BLUE_BITS_ARB, view->hints[PUGL_BLUE_BITS], + WGL_ALPHA_BITS_ARB, view->hints[PUGL_ALPHA_BITS], + WGL_DEPTH_BITS_ARB, view->hints[PUGL_DEPTH_BITS], + WGL_STENCIL_BITS_ARB, view->hints[PUGL_STENCIL_BITS], + 0, + }; + // clang-format on + + PuglWinGlSurface* const surface = + (PuglWinGlSurface*)calloc(1, sizeof(PuglWinGlSurface)); + impl->surface = surface; + + // Create fake window for getting at GL context + PuglStatus st = PUGL_SUCCESS; + PuglFakeWindow fakeWin = {0, 0}; + static const char* title = "Pugl Configuration"; + if ((st = puglWinCreateWindow(view, title, &fakeWin.hwnd, &fakeWin.hdc))) { + return puglWinError(&fakeWin, st); + } + + // Set pixel format for fake window + const PuglWinPFD fakePfd = puglWinGetPixelFormatDescriptor(view->hints); + const int fakePfId = ChoosePixelFormat(fakeWin.hdc, &fakePfd); + if (!fakePfId || !SetPixelFormat(fakeWin.hdc, fakePfId, &fakePfd)) { + return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); + } + + // Create fake GL context to get at the functions we need + HGLRC fakeRc = wglCreateContext(fakeWin.hdc); + if (!fakeRc) { + return puglWinError(&fakeWin, PUGL_CREATE_CONTEXT_FAILED); + } + + // Enter fake context and get extension functions + wglMakeCurrent(fakeWin.hdc, fakeRc); + surface->procs = puglWinGlGetProcs(); + + if (surface->procs.wglChoosePixelFormat) { + // Choose pixel format based on attributes + UINT numFormats = 0; + if (!surface->procs.wglChoosePixelFormat( + fakeWin.hdc, pixelAttrs, NULL, 1u, &impl->pfId, &numFormats)) { + return puglWinError(&fakeWin, PUGL_SET_FORMAT_FAILED); + } + + DescribePixelFormat(impl->hdc, impl->pfId, sizeof(impl->pfd), &impl->pfd); + } else { + // Modern extensions not available, use basic pixel format + impl->pfd = fakePfd; + impl->pfId = fakePfId; + } + + // Dispose of fake window and context + wglMakeCurrent(NULL, NULL); + wglDeleteContext(fakeRc); + ReleaseDC(fakeWin.hwnd, fakeWin.hdc); + DestroyWindow(fakeWin.hwnd); + + return PUGL_SUCCESS; } static PuglStatus puglWinGlCreate(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface; - PuglStatus st = PUGL_SUCCESS; - - const int contextAttribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MAJOR], - - WGL_CONTEXT_MINOR_VERSION_ARB, - view->hints[PUGL_CONTEXT_VERSION_MINOR], - - WGL_CONTEXT_FLAGS_ARB, - (view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), - - WGL_CONTEXT_PROFILE_MASK_ARB, - (view->hints[PUGL_USE_COMPAT_PROFILE] - ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB - : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB), - - 0}; - - // Create real window with desired pixel format - if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { - return st; - } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { - ReleaseDC(impl->hwnd, impl->hdc); - DestroyWindow(impl->hwnd); - impl->hwnd = NULL; - impl->hdc = NULL; - return PUGL_SET_FORMAT_FAILED; - } - - // Create GL context - if (surface->procs.wglCreateContextAttribs && - !(surface->hglrc = surface->procs.wglCreateContextAttribs( - impl->hdc, 0, contextAttribs))) { - return PUGL_CREATE_CONTEXT_FAILED; - } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - // Enter context and set swap interval - wglMakeCurrent(impl->hdc, surface->hglrc); - const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; - if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) { - surface->procs.wglSwapInterval(swapInterval); - } - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglWinGlSurface* const surface = (PuglWinGlSurface*)impl->surface; + PuglStatus st = PUGL_SUCCESS; + + const int contextAttribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + WGL_CONTEXT_MINOR_VERSION_ARB, + view->hints[PUGL_CONTEXT_VERSION_MINOR], + + WGL_CONTEXT_FLAGS_ARB, + (view->hints[PUGL_USE_DEBUG_CONTEXT] ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), + + WGL_CONTEXT_PROFILE_MASK_ARB, + (view->hints[PUGL_USE_COMPAT_PROFILE] + ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB + : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB), + + 0}; + + // Create real window with desired pixel format + if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { + return st; + } else if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { + ReleaseDC(impl->hwnd, impl->hdc); + DestroyWindow(impl->hwnd); + impl->hwnd = NULL; + impl->hdc = NULL; + return PUGL_SET_FORMAT_FAILED; + } + + // Create GL context + if (surface->procs.wglCreateContextAttribs && + !(surface->hglrc = surface->procs.wglCreateContextAttribs( + impl->hdc, 0, contextAttribs))) { + return PUGL_CREATE_CONTEXT_FAILED; + } else if (!(surface->hglrc = wglCreateContext(impl->hdc))) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + // Enter context and set swap interval + wglMakeCurrent(impl->hdc, surface->hglrc); + const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; + if (surface->procs.wglSwapInterval && swapInterval != PUGL_DONT_CARE) { + surface->procs.wglSwapInterval(swapInterval); + } + + return PUGL_SUCCESS; } static PuglStatus puglWinGlDestroy(PuglView* view) { - PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; - if (surface) { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(surface->hglrc); - free(surface); - view->impl->surface = NULL; - } - - return PUGL_SUCCESS; + PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; + if (surface) { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(surface->hglrc); + free(surface); + view->impl->surface = NULL; + } + + return PUGL_SUCCESS; } static PuglStatus puglWinGlEnter(PuglView* view, const PuglEventExpose* expose) { - PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; + PuglWinGlSurface* surface = (PuglWinGlSurface*)view->impl->surface; - wglMakeCurrent(view->impl->hdc, surface->hglrc); + wglMakeCurrent(view->impl->hdc, surface->hglrc); - if (expose) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } + if (expose) { + PAINTSTRUCT ps; + BeginPaint(view->impl->hwnd, &ps); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglWinGlLeave(PuglView* view, const PuglEventExpose* expose) { - if (expose) { - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - SwapBuffers(view->impl->hdc); - } - - wglMakeCurrent(NULL, NULL); - return PUGL_SUCCESS; + if (expose) { + PAINTSTRUCT ps; + EndPaint(view->impl->hwnd, &ps); + SwapBuffers(view->impl->hdc); + } + + wglMakeCurrent(NULL, NULL); + return PUGL_SUCCESS; } PuglGlFunc puglGetProcAddress(const char* name) { - const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name); + const PuglGlFunc func = (PuglGlFunc)wglGetProcAddress(name); - /* Windows has the annoying property that wglGetProcAddress returns NULL - for functions from OpenGL 1.1, so we fall back to pulling them directly - from opengl32.dll */ + /* Windows has the annoying property that wglGetProcAddress returns NULL + for functions from OpenGL 1.1, so we fall back to pulling them directly + from opengl32.dll */ - return func - ? func - : (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name); + return func + ? func + : (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name); } PuglStatus puglEnterContext(PuglView* view) { - return view->backend->enter(view, NULL); + return view->backend->enter(view, NULL); } PuglStatus puglLeaveContext(PuglView* view) { - return view->backend->leave(view, NULL); + return view->backend->leave(view, NULL); } const PuglBackend* puglGlBackend(void) { - static const PuglBackend backend = {puglWinGlConfigure, - puglWinGlCreate, - puglWinGlDestroy, - puglWinGlEnter, - puglWinGlLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglWinGlConfigure, + puglWinGlCreate, + puglWinGlDestroy, + puglWinGlEnter, + puglWinGlLeave, + puglStubGetContext}; + + return &backend; } diff --git a/src/win_stub.c b/src/win_stub.c index 2027836..cf86390 100644 --- a/src/win_stub.c +++ b/src/win_stub.c @@ -23,58 +23,58 @@ PuglStatus puglWinStubConfigure(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglStatus st = PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglStatus st = PUGL_SUCCESS; - if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { - return st; - } + if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { + return st; + } - impl->pfd = puglWinGetPixelFormatDescriptor(view->hints); - impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd); + impl->pfd = puglWinGetPixelFormatDescriptor(view->hints); + impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd); - if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { - ReleaseDC(impl->hwnd, impl->hdc); - DestroyWindow(impl->hwnd); - impl->hwnd = NULL; - impl->hdc = NULL; - return PUGL_SET_FORMAT_FAILED; - } + if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { + ReleaseDC(impl->hwnd, impl->hdc); + DestroyWindow(impl->hwnd); + impl->hwnd = NULL; + impl->hdc = NULL; + return PUGL_SET_FORMAT_FAILED; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglWinStubEnter(PuglView* view, const PuglEventExpose* expose) { - if (expose) { - PAINTSTRUCT ps; - BeginPaint(view->impl->hwnd, &ps); - } + if (expose) { + PAINTSTRUCT ps; + BeginPaint(view->impl->hwnd, &ps); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglWinStubLeave(PuglView* view, const PuglEventExpose* expose) { - if (expose) { - PAINTSTRUCT ps; - EndPaint(view->impl->hwnd, &ps); - } + if (expose) { + PAINTSTRUCT ps; + EndPaint(view->impl->hwnd, &ps); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } const PuglBackend* puglStubBackend(void) { - static const PuglBackend backend = {puglWinStubConfigure, - puglStubCreate, - puglStubDestroy, - puglWinStubEnter, - puglWinStubLeave, - puglStubGetContext}; + static const PuglBackend backend = {puglWinStubConfigure, + puglStubCreate, + puglStubDestroy, + puglWinStubEnter, + puglWinStubLeave, + puglStubGetContext}; - return &backend; + return &backend; } diff --git a/src/win_vulkan.c b/src/win_vulkan.c index f862716..d35d204 100644 --- a/src/win_vulkan.c +++ b/src/win_vulkan.c @@ -28,78 +28,77 @@ #include <stdlib.h> -struct PuglVulkanLoaderImpl -{ - HMODULE libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +struct PuglVulkanLoaderImpl { + HMODULE libvulkan; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; }; PuglVulkanLoader* puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) { - PuglVulkanLoader* loader = - (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } + PuglVulkanLoader* loader = + (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); + if (!loader) { + return NULL; + } - if (!(loader->libvulkan = LoadLibrary("vulkan-1.dll"))) { - free(loader); - return NULL; - } + if (!(loader->libvulkan = LoadLibrary("vulkan-1.dll"))) { + free(loader); + return NULL; + } - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress( - loader->libvulkan, "vkGetInstanceProcAddr"); + loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress( + loader->libvulkan, "vkGetInstanceProcAddr"); - loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)GetProcAddress( - loader->libvulkan, "vkGetDeviceProcAddr"); + loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)GetProcAddress( + loader->libvulkan, "vkGetDeviceProcAddr"); - return loader; + return loader; } void puglFreeVulkanLoader(PuglVulkanLoader* loader) { - if (loader) { - FreeLibrary(loader->libvulkan); - free(loader); - } + if (loader) { + FreeLibrary(loader->libvulkan); + free(loader); + } } PFN_vkGetInstanceProcAddr puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetInstanceProcAddr; + return loader->vkGetInstanceProcAddr; } PFN_vkGetDeviceProcAddr puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetDeviceProcAddr; + return loader->vkGetDeviceProcAddr; } const PuglBackend* puglVulkanBackend() { - static const PuglBackend backend = {puglWinStubConfigure, - puglStubCreate, - puglStubDestroy, - puglWinStubEnter, - puglWinStubLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglWinStubConfigure, + puglStubCreate, + puglStubDestroy, + puglWinStubEnter, + puglWinStubLeave, + puglStubGetContext}; + + return &backend; } const char* const* puglGetInstanceExtensions(uint32_t* const count) { - static const char* const extensions[] = {"VK_KHR_surface", - "VK_KHR_win32_surface"}; + static const char* const extensions[] = {"VK_KHR_surface", + "VK_KHR_win32_surface"}; - *count = 2; - return extensions; + *count = 2; + return extensions; } VkResult @@ -109,19 +108,19 @@ puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, const VkAllocationCallbacks* const pAllocator, VkSurfaceKHR* const pSurface) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; - PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = - (PFN_vkCreateWin32SurfaceKHR) - vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); + PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = + (PFN_vkCreateWin32SurfaceKHR)vkGetInstanceProcAddr( + instance, "vkCreateWin32SurfaceKHR"); - const VkWin32SurfaceCreateInfoKHR createInfo = { - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - NULL, - 0, - GetModuleHandle(NULL), - impl->hwnd, - }; + const VkWin32SurfaceCreateInfoKHR createInfo = { + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + NULL, + 0, + GetModuleHandle(NULL), + impl->hwnd, + }; - return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface); + return vkCreateWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface); } @@ -32,17 +32,17 @@ #include <X11/keysym.h> #ifdef HAVE_XRANDR -# include <X11/extensions/Xrandr.h> +# include <X11/extensions/Xrandr.h> #endif #ifdef HAVE_XSYNC -# include <X11/extensions/sync.h> -# include <X11/extensions/syncconst.h> +# include <X11/extensions/sync.h> +# include <X11/extensions/syncconst.h> #endif #ifdef HAVE_XCURSOR -# include <X11/Xcursor/Xcursor.h> -# include <X11/cursorfont.h> +# include <X11/Xcursor/Xcursor.h> +# include <X11/cursorfont.h> #endif #include <sys/select.h> @@ -56,881 +56,913 @@ #include <time.h> #ifndef MIN -# define MIN(a, b) (((a) < (b)) ? (a) : (b)) +# define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -# define MAX(a, b) (((a) > (b)) ? (a) : (b)) +# define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif enum WmClientStateMessageAction { - WM_STATE_REMOVE, - WM_STATE_ADD, - WM_STATE_TOGGLE + WM_STATE_REMOVE, + WM_STATE_ADD, + WM_STATE_TOGGLE }; static bool puglInitXSync(PuglWorldInternals* impl) { #ifdef HAVE_XSYNC - int syncMajor = 0; - int syncMinor = 0; - int errorBase = 0; - XSyncSystemCounter* counters = NULL; - int numCounters = 0; - - if (XSyncQueryExtension(impl->display, &impl->syncEventBase, &errorBase) && - XSyncInitialize(impl->display, &syncMajor, &syncMinor) && - (counters = XSyncListSystemCounters(impl->display, &numCounters))) { - - for (int n = 0; n < numCounters; ++n) { - if (!strcmp(counters[n].name, "SERVERTIME")) { - impl->serverTimeCounter = counters[n].counter; - impl->syncSupported = true; - break; - } - } - - XSyncFreeSystemCounterList(counters); - } + int syncMajor = 0; + int syncMinor = 0; + int errorBase = 0; + XSyncSystemCounter* counters = NULL; + int numCounters = 0; + + if (XSyncQueryExtension(impl->display, &impl->syncEventBase, &errorBase) && + XSyncInitialize(impl->display, &syncMajor, &syncMinor) && + (counters = XSyncListSystemCounters(impl->display, &numCounters))) { + for (int n = 0; n < numCounters; ++n) { + if (!strcmp(counters[n].name, "SERVERTIME")) { + impl->serverTimeCounter = counters[n].counter; + impl->syncSupported = true; + break; + } + } + + XSyncFreeSystemCounterList(counters); + } #else - (void)impl; + (void)impl; #endif - return false; + return false; } PuglWorldInternals* puglInitWorldInternals(PuglWorldType type, PuglWorldFlags flags) { - if (type == PUGL_PROGRAM && (flags & PUGL_WORLD_THREADS)) { - XInitThreads(); - } - - Display* display = XOpenDisplay(NULL); - if (!display) { - return NULL; - } - - PuglWorldInternals* impl = (PuglWorldInternals*)calloc( - 1, sizeof(PuglWorldInternals)); - - impl->display = display; - - // Intern the various atoms we will need - impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); - impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); - impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); - impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); - impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); - impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); - impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); - impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION = - XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 0); - - // Open input method - XSetLocaleModifiers(""); - if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) { - XSetLocaleModifiers("@im="); - impl->xim = XOpenIM(display, NULL, NULL, NULL); - } - - puglInitXSync(impl); - XFlush(display); - - return impl; + if (type == PUGL_PROGRAM && (flags & PUGL_WORLD_THREADS)) { + XInitThreads(); + } + + Display* display = XOpenDisplay(NULL); + if (!display) { + return NULL; + } + + PuglWorldInternals* impl = + (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); + + impl->display = display; + + // Intern the various atoms we will need + impl->atoms.CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0); + impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); + impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); + impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); + impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); + impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); + impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); + impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION = + XInternAtom(display, "_NET_WM_STATE_DEMANDS_ATTENTION", 0); + + // Open input method + XSetLocaleModifiers(""); + if (!(impl->xim = XOpenIM(display, NULL, NULL, NULL))) { + XSetLocaleModifiers("@im="); + impl->xim = XOpenIM(display, NULL, NULL, NULL); + } + + puglInitXSync(impl); + XFlush(display); + + return impl; } void* puglGetNativeWorld(PuglWorld* world) { - return world->impl->display; + return world->impl->display; } PuglInternals* puglInitViewInternals(void) { - PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); + PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); #ifdef HAVE_XCURSOR - impl->cursorShape = XC_arrow; + impl->cursorShape = XC_arrow; #endif - return impl; + return impl; } static PuglStatus puglPollX11Socket(PuglWorld* world, const double timeout) { - if (XPending(world->impl->display) > 0) { - return PUGL_SUCCESS; - } - - const int fd = ConnectionNumber(world->impl->display); - const int nfds = fd + 1; - int ret = 0; - fd_set fds; - FD_ZERO(&fds); // NOLINT - FD_SET(fd, &fds); - - if (timeout < 0.0) { - ret = select(nfds, &fds, NULL, NULL, NULL); - } else { - const long sec = (long)timeout; - const long usec = (long)((timeout - (double)sec) * 1e6); - struct timeval tv = {sec, usec}; - ret = select(nfds, &fds, NULL, NULL, &tv); - } - - return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS; + if (XPending(world->impl->display) > 0) { + return PUGL_SUCCESS; + } + + const int fd = ConnectionNumber(world->impl->display); + const int nfds = fd + 1; + int ret = 0; + fd_set fds; + FD_ZERO(&fds); // NOLINT + FD_SET(fd, &fds); + + if (timeout < 0.0) { + ret = select(nfds, &fds, NULL, NULL, NULL); + } else { + const long sec = (long)timeout; + const long usec = (long)((timeout - (double)sec) * 1e6); + struct timeval tv = {sec, usec}; + ret = select(nfds, &fds, NULL, NULL, &tv); + } + + return ret < 0 ? PUGL_UNKNOWN_ERROR : PUGL_SUCCESS; } static PuglView* puglFindView(PuglWorld* world, const Window window) { - for (size_t i = 0; i < world->numViews; ++i) { - if (world->views[i]->impl->win == window) { - return world->views[i]; - } - } + for (size_t i = 0; i < world->numViews; ++i) { + if (world->views[i]->impl->win == window) { + return world->views[i]; + } + } - return NULL; + return NULL; } static PuglStatus updateSizeHints(const PuglView* view) { - if (!view->impl->win) { - return PUGL_SUCCESS; - } - - Display* display = view->world->impl->display; - XSizeHints sizeHints = {0}; - - if (!view->hints[PUGL_RESIZABLE]) { - sizeHints.flags = PBaseSize | PMinSize | PMaxSize; - sizeHints.base_width = (int)view->frame.width; - sizeHints.base_height = (int)view->frame.height; - sizeHints.min_width = (int)view->frame.width; - sizeHints.min_height = (int)view->frame.height; - sizeHints.max_width = (int)view->frame.width; - sizeHints.max_height = (int)view->frame.height; - } else { - if (view->defaultWidth || view->defaultHeight) { - sizeHints.flags = PBaseSize; - sizeHints.base_width = view->defaultWidth; - sizeHints.base_height = view->defaultHeight; - } - if (view->minWidth || view->minHeight) { - sizeHints.flags = PMinSize; - sizeHints.min_width = view->minWidth; - sizeHints.min_height = view->minHeight; - } - if (view->maxWidth || view->maxHeight) { - sizeHints.flags = PMaxSize; - sizeHints.max_width = view->maxWidth; - sizeHints.max_height = view->maxHeight; - } - if (view->minAspectX) { - sizeHints.flags |= PAspect; - sizeHints.min_aspect.x = view->minAspectX; - sizeHints.min_aspect.y = view->minAspectY; - sizeHints.max_aspect.x = view->maxAspectX; - sizeHints.max_aspect.y = view->maxAspectY; - } - } - - XSetNormalHints(display, view->impl->win, &sizeHints); - return PUGL_SUCCESS; + if (!view->impl->win) { + return PUGL_SUCCESS; + } + + Display* display = view->world->impl->display; + XSizeHints sizeHints = {0}; + + if (!view->hints[PUGL_RESIZABLE]) { + sizeHints.flags = PBaseSize | PMinSize | PMaxSize; + sizeHints.base_width = (int)view->frame.width; + sizeHints.base_height = (int)view->frame.height; + sizeHints.min_width = (int)view->frame.width; + sizeHints.min_height = (int)view->frame.height; + sizeHints.max_width = (int)view->frame.width; + sizeHints.max_height = (int)view->frame.height; + } else { + if (view->defaultWidth || view->defaultHeight) { + sizeHints.flags = PBaseSize; + sizeHints.base_width = view->defaultWidth; + sizeHints.base_height = view->defaultHeight; + } + if (view->minWidth || view->minHeight) { + sizeHints.flags = PMinSize; + sizeHints.min_width = view->minWidth; + sizeHints.min_height = view->minHeight; + } + if (view->maxWidth || view->maxHeight) { + sizeHints.flags = PMaxSize; + sizeHints.max_width = view->maxWidth; + sizeHints.max_height = view->maxHeight; + } + if (view->minAspectX) { + sizeHints.flags |= PAspect; + sizeHints.min_aspect.x = view->minAspectX; + sizeHints.min_aspect.y = view->minAspectY; + sizeHints.max_aspect.x = view->maxAspectX; + sizeHints.max_aspect.y = view->maxAspectY; + } + } + + XSetNormalHints(display, view->impl->win, &sizeHints); + return PUGL_SUCCESS; } #ifdef HAVE_XCURSOR static PuglStatus puglDefineCursorShape(PuglView* view, unsigned shape) { - PuglInternals* const impl = view->impl; - PuglWorld* const world = view->world; - Display* const display = world->impl->display; - const Cursor cur = XcursorShapeLoadCursor(display, shape); - - if (cur) { - XDefineCursor(display, impl->win, cur); - XFreeCursor(display, cur); - return PUGL_SUCCESS; - } - - return PUGL_FAILURE; + PuglInternals* const impl = view->impl; + PuglWorld* const world = view->world; + Display* const display = world->impl->display; + const Cursor cur = XcursorShapeLoadCursor(display, shape); + + if (cur) { + XDefineCursor(display, impl->win, cur); + XFreeCursor(display, cur); + return PUGL_SUCCESS; + } + + return PUGL_FAILURE; } #endif PuglStatus puglRealize(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglWorld* const world = view->world; - PuglX11Atoms* const atoms = &view->world->impl->atoms; - Display* const display = world->impl->display; - const int screen = DefaultScreen(display); - const Window root = RootWindow(display, screen); - const Window parent = view->parent ? (Window)view->parent : root; - XSetWindowAttributes attr = {0}; - PuglStatus st = PUGL_SUCCESS; - - // Ensure that we're unrealized and that a reasonable backend has been set - if (impl->win) { - return PUGL_FAILURE; - } else if (!view->backend || !view->backend->configure) { - return PUGL_BAD_BACKEND; - } - - // Set the size to the default if it has not already been set - if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 || view->defaultHeight == 0.0) { - return PUGL_BAD_CONFIGURATION; - } - - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - } - - // Center top-level windows if a position has not been set - if (!view->parent && view->frame.x == 0.0 && view->frame.y == 0.0) { - const int screenWidth = DisplayWidth(display, screen); - const int screenHeight = DisplayHeight(display, screen); - - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; - } - - // Configure the backend to get the visual info - impl->display = display; - impl->screen = screen; - if ((st = view->backend->configure(view)) || !impl->vi) { - view->backend->destroy(view); - return st ? st : PUGL_BACKEND_FAILED; - } - - // Create a colormap based on the visual info from the backend - attr.colormap = - XCreateColormap(display, parent, impl->vi->visual, AllocNone); - - // Set the event mask to request all of the event types we react to - attr.event_mask |= ButtonPressMask; - attr.event_mask |= ButtonReleaseMask; - attr.event_mask |= EnterWindowMask; - attr.event_mask |= ExposureMask; - attr.event_mask |= FocusChangeMask; - attr.event_mask |= KeyPressMask; - attr.event_mask |= KeyReleaseMask; - attr.event_mask |= LeaveWindowMask; - attr.event_mask |= PointerMotionMask; - attr.event_mask |= StructureNotifyMask; - attr.event_mask |= VisibilityChangeMask; - - // Create the window - impl->win = XCreateWindow(display, - parent, - (int)view->frame.x, - (int)view->frame.y, - (unsigned)view->frame.width, - (unsigned)view->frame.height, - 0, - impl->vi->depth, - InputOutput, - impl->vi->visual, - CWColormap | CWEventMask, - &attr); - - // Create the backend drawing context/surface - if ((st = view->backend->create(view))) { - return st; - } + PuglInternals* const impl = view->impl; + PuglWorld* const world = view->world; + PuglX11Atoms* const atoms = &view->world->impl->atoms; + Display* const display = world->impl->display; + const int screen = DefaultScreen(display); + const Window root = RootWindow(display, screen); + const Window parent = view->parent ? (Window)view->parent : root; + XSetWindowAttributes attr = {0}; + PuglStatus st = PUGL_SUCCESS; + + // Ensure that we're unrealized and that a reasonable backend has been set + if (impl->win) { + return PUGL_FAILURE; + } else if (!view->backend || !view->backend->configure) { + return PUGL_BAD_BACKEND; + } + + // Set the size to the default if it has not already been set + if (view->frame.width == 0.0 && view->frame.height == 0.0) { + if (view->defaultWidth == 0.0 || view->defaultHeight == 0.0) { + return PUGL_BAD_CONFIGURATION; + } + + view->frame.width = view->defaultWidth; + view->frame.height = view->defaultHeight; + } + + // Center top-level windows if a position has not been set + if (!view->parent && view->frame.x == 0.0 && view->frame.y == 0.0) { + const int screenWidth = DisplayWidth(display, screen); + const int screenHeight = DisplayHeight(display, screen); + + view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; + view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; + } + + // Configure the backend to get the visual info + impl->display = display; + impl->screen = screen; + if ((st = view->backend->configure(view)) || !impl->vi) { + view->backend->destroy(view); + return st ? st : PUGL_BACKEND_FAILED; + } + + // Create a colormap based on the visual info from the backend + attr.colormap = XCreateColormap(display, parent, impl->vi->visual, AllocNone); + + // Set the event mask to request all of the event types we react to + attr.event_mask |= ButtonPressMask; + attr.event_mask |= ButtonReleaseMask; + attr.event_mask |= EnterWindowMask; + attr.event_mask |= ExposureMask; + attr.event_mask |= FocusChangeMask; + attr.event_mask |= KeyPressMask; + attr.event_mask |= KeyReleaseMask; + attr.event_mask |= LeaveWindowMask; + attr.event_mask |= PointerMotionMask; + attr.event_mask |= StructureNotifyMask; + attr.event_mask |= VisibilityChangeMask; + + // Create the window + impl->win = XCreateWindow(display, + parent, + (int)view->frame.x, + (int)view->frame.y, + (unsigned)view->frame.width, + (unsigned)view->frame.height, + 0, + impl->vi->depth, + InputOutput, + impl->vi->visual, + CWColormap | CWEventMask, + &attr); + + // Create the backend drawing context/surface + if ((st = view->backend->create(view))) { + return st; + } #ifdef HAVE_XRANDR - // Set refresh rate hint to the real refresh rate - XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); - short current_rate = XRRConfigCurrentRate(conf); + // Set refresh rate hint to the real refresh rate + XRRScreenConfiguration* conf = XRRGetScreenInfo(display, parent); + short current_rate = XRRConfigCurrentRate(conf); - view->hints[PUGL_REFRESH_RATE] = current_rate; - XRRFreeScreenConfigInfo(conf); + view->hints[PUGL_REFRESH_RATE] = current_rate; + XRRFreeScreenConfigInfo(conf); #endif - updateSizeHints(view); + updateSizeHints(view); - XClassHint classHint = { world->className, world->className }; - XSetClassHint(display, impl->win, &classHint); + XClassHint classHint = {world->className, world->className}; + XSetClassHint(display, impl->win, &classHint); - if (view->title) { - puglSetWindowTitle(view, view->title); - } + if (view->title) { + puglSetWindowTitle(view, view->title); + } - if (parent == root) { - XSetWMProtocols(display, impl->win, &atoms->WM_DELETE_WINDOW, 1); - } + if (parent == root) { + XSetWMProtocols(display, impl->win, &atoms->WM_DELETE_WINDOW, 1); + } - if (view->transientParent) { - XSetTransientForHint(display, impl->win, (Window)view->transientParent); - } + if (view->transientParent) { + XSetTransientForHint(display, impl->win, (Window)view->transientParent); + } - // Create input context - impl->xic = XCreateIC(world->impl->xim, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, impl->win, - XNFocusWindow, impl->win, - NULL); + // Create input context + impl->xic = XCreateIC(world->impl->xim, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + impl->win, + XNFocusWindow, + impl->win, + NULL); #ifdef HAVE_XCURSOR - puglDefineCursorShape(view, impl->cursorShape); + puglDefineCursorShape(view, impl->cursorShape); #endif - puglDispatchSimpleEvent(view, PUGL_CREATE); + puglDispatchSimpleEvent(view, PUGL_CREATE); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } PuglStatus puglShow(PuglView* view) { - PuglStatus st = PUGL_SUCCESS; + PuglStatus st = PUGL_SUCCESS; - if (!view->impl->win) { - if ((st = puglRealize(view))) { - return st; - } - } + if (!view->impl->win) { + if ((st = puglRealize(view))) { + return st; + } + } - XMapRaised(view->impl->display, view->impl->win); - puglPostRedisplay(view); + XMapRaised(view->impl->display, view->impl->win); + puglPostRedisplay(view); - return st; + return st; } PuglStatus puglHide(PuglView* view) { - XUnmapWindow(view->impl->display, view->impl->win); - return PUGL_SUCCESS; + XUnmapWindow(view->impl->display, view->impl->win); + return PUGL_SUCCESS; } void puglFreeViewInternals(PuglView* view) { - if (view && view->impl) { - if (view->impl->xic) { - XDestroyIC(view->impl->xic); - } - if (view->backend) { - view->backend->destroy(view); - } - if (view->impl->display) { - XDestroyWindow(view->impl->display, view->impl->win); - } - XFree(view->impl->vi); - free(view->impl); - } + if (view && view->impl) { + if (view->impl->xic) { + XDestroyIC(view->impl->xic); + } + if (view->backend) { + view->backend->destroy(view); + } + if (view->impl->display) { + XDestroyWindow(view->impl->display, view->impl->win); + } + XFree(view->impl->vi); + free(view->impl); + } } void puglFreeWorldInternals(PuglWorld* world) { - if (world->impl->xim) { - XCloseIM(world->impl->xim); - } - XCloseDisplay(world->impl->display); - free(world->impl->timers); - free(world->impl); + if (world->impl->xim) { + XCloseIM(world->impl->xim); + } + XCloseDisplay(world->impl->display); + free(world->impl->timers); + free(world->impl); } static PuglKey keySymToSpecial(KeySym sym) { - switch (sym) { - case XK_F1: return PUGL_KEY_F1; - case XK_F2: return PUGL_KEY_F2; - case XK_F3: return PUGL_KEY_F3; - case XK_F4: return PUGL_KEY_F4; - case XK_F5: return PUGL_KEY_F5; - case XK_F6: return PUGL_KEY_F6; - case XK_F7: return PUGL_KEY_F7; - case XK_F8: return PUGL_KEY_F8; - case XK_F9: return PUGL_KEY_F9; - case XK_F10: return PUGL_KEY_F10; - case XK_F11: return PUGL_KEY_F11; - case XK_F12: return PUGL_KEY_F12; - case XK_Left: return PUGL_KEY_LEFT; - case XK_Up: return PUGL_KEY_UP; - case XK_Right: return PUGL_KEY_RIGHT; - case XK_Down: return PUGL_KEY_DOWN; - case XK_Page_Up: return PUGL_KEY_PAGE_UP; - case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; - case XK_Home: return PUGL_KEY_HOME; - case XK_End: return PUGL_KEY_END; - case XK_Insert: return PUGL_KEY_INSERT; - case XK_Shift_L: return PUGL_KEY_SHIFT_L; - case XK_Shift_R: return PUGL_KEY_SHIFT_R; - case XK_Control_L: return PUGL_KEY_CTRL_L; - case XK_Control_R: return PUGL_KEY_CTRL_R; - case XK_Alt_L: return PUGL_KEY_ALT_L; - case XK_ISO_Level3_Shift: - case XK_Alt_R: return PUGL_KEY_ALT_R; - case XK_Super_L: return PUGL_KEY_SUPER_L; - case XK_Super_R: return PUGL_KEY_SUPER_R; - case XK_Menu: return PUGL_KEY_MENU; - case XK_Caps_Lock: return PUGL_KEY_CAPS_LOCK; - case XK_Scroll_Lock: return PUGL_KEY_SCROLL_LOCK; - case XK_Num_Lock: return PUGL_KEY_NUM_LOCK; - case XK_Print: return PUGL_KEY_PRINT_SCREEN; - case XK_Pause: return PUGL_KEY_PAUSE; - default: break; - } - return (PuglKey)0; + switch (sym) { + case XK_F1: + return PUGL_KEY_F1; + case XK_F2: + return PUGL_KEY_F2; + case XK_F3: + return PUGL_KEY_F3; + case XK_F4: + return PUGL_KEY_F4; + case XK_F5: + return PUGL_KEY_F5; + case XK_F6: + return PUGL_KEY_F6; + case XK_F7: + return PUGL_KEY_F7; + case XK_F8: + return PUGL_KEY_F8; + case XK_F9: + return PUGL_KEY_F9; + case XK_F10: + return PUGL_KEY_F10; + case XK_F11: + return PUGL_KEY_F11; + case XK_F12: + return PUGL_KEY_F12; + case XK_Left: + return PUGL_KEY_LEFT; + case XK_Up: + return PUGL_KEY_UP; + case XK_Right: + return PUGL_KEY_RIGHT; + case XK_Down: + return PUGL_KEY_DOWN; + case XK_Page_Up: + return PUGL_KEY_PAGE_UP; + case XK_Page_Down: + return PUGL_KEY_PAGE_DOWN; + case XK_Home: + return PUGL_KEY_HOME; + case XK_End: + return PUGL_KEY_END; + case XK_Insert: + return PUGL_KEY_INSERT; + case XK_Shift_L: + return PUGL_KEY_SHIFT_L; + case XK_Shift_R: + return PUGL_KEY_SHIFT_R; + case XK_Control_L: + return PUGL_KEY_CTRL_L; + case XK_Control_R: + return PUGL_KEY_CTRL_R; + case XK_Alt_L: + return PUGL_KEY_ALT_L; + case XK_ISO_Level3_Shift: + case XK_Alt_R: + return PUGL_KEY_ALT_R; + case XK_Super_L: + return PUGL_KEY_SUPER_L; + case XK_Super_R: + return PUGL_KEY_SUPER_R; + case XK_Menu: + return PUGL_KEY_MENU; + case XK_Caps_Lock: + return PUGL_KEY_CAPS_LOCK; + case XK_Scroll_Lock: + return PUGL_KEY_SCROLL_LOCK; + case XK_Num_Lock: + return PUGL_KEY_NUM_LOCK; + case XK_Print: + return PUGL_KEY_PRINT_SCREEN; + case XK_Pause: + return PUGL_KEY_PAUSE; + default: + break; + } + return (PuglKey)0; } static int lookupString(XIC xic, XEvent* xevent, char* str, KeySym* sym) { - Status status = 0; + Status status = 0; #ifdef X_HAVE_UTF8_STRING - const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status); + const int n = Xutf8LookupString(xic, &xevent->xkey, str, 7, sym, &status); #else - const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status); + const int n = XmbLookupString(xic, &xevent->xkey, str, 7, sym, &status); #endif - return status == XBufferOverflow ? 0 : n; + return status == XBufferOverflow ? 0 : n; } static void translateKey(PuglView* view, XEvent* xevent, PuglEvent* event) { - const unsigned state = xevent->xkey.state; - const bool filter = XFilterEvent(xevent, None); - - event->key.keycode = xevent->xkey.keycode; - xevent->xkey.state = 0; - - // Lookup unshifted key - char ustr[8] = {0}; - KeySym sym = 0; - const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL); - const PuglKey special = keySymToSpecial(sym); - - event->key.key = ((special || ufound <= 0) - ? special - : puglDecodeUTF8((const uint8_t*)ustr)); - - if (xevent->type == KeyPress && !filter && !special) { - // Lookup shifted key for possible text event - xevent->xkey.state = state; - - char sstr[8] = {0}; - const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym); - if (sfound > 0) { - // Dispatch key event now - puglDispatchEvent(view, event); - - // "Return" a text event in its place - event->text.type = PUGL_TEXT; - event->text.character = puglDecodeUTF8((const uint8_t*)sstr); - memcpy(event->text.string, sstr, sizeof(sstr)); - } - } + const unsigned state = xevent->xkey.state; + const bool filter = XFilterEvent(xevent, None); + + event->key.keycode = xevent->xkey.keycode; + xevent->xkey.state = 0; + + // Lookup unshifted key + char ustr[8] = {0}; + KeySym sym = 0; + const int ufound = XLookupString(&xevent->xkey, ustr, 8, &sym, NULL); + const PuglKey special = keySymToSpecial(sym); + + event->key.key = + ((special || ufound <= 0) ? special : puglDecodeUTF8((const uint8_t*)ustr)); + + if (xevent->type == KeyPress && !filter && !special) { + // Lookup shifted key for possible text event + xevent->xkey.state = state; + + char sstr[8] = {0}; + const int sfound = lookupString(view->impl->xic, xevent, sstr, &sym); + if (sfound > 0) { + // Dispatch key event now + puglDispatchEvent(view, event); + + // "Return" a text event in its place + event->text.type = PUGL_TEXT; + event->text.character = puglDecodeUTF8((const uint8_t*)sstr); + memcpy(event->text.string, sstr, sizeof(sstr)); + } + } } static uint32_t translateModifiers(const unsigned xstate) { - return (((xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0u) | - ((xstate & ControlMask) ? PUGL_MOD_CTRL : 0u) | - ((xstate & Mod1Mask) ? PUGL_MOD_ALT : 0u) | - ((xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0u)); + return (((xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0u) | + ((xstate & ControlMask) ? PUGL_MOD_CTRL : 0u) | + ((xstate & Mod1Mask) ? PUGL_MOD_ALT : 0u) | + ((xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0u)); } static PuglEvent translateEvent(PuglView* view, XEvent xevent) { - const PuglX11Atoms* atoms = &view->world->impl->atoms; - - PuglEvent event = {{PUGL_NOTHING, 0}}; - event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0; - - switch (xevent.type) { - case ClientMessage: - if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) { - const Atom protocol = (Atom)xevent.xclient.data.l[0]; - if (protocol == atoms->WM_DELETE_WINDOW) { - event.type = PUGL_CLOSE; - } - } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) { - event.type = PUGL_CLIENT; - event.client.data1 = (uintptr_t)xevent.xclient.data.l[0]; - event.client.data2 = (uintptr_t)xevent.xclient.data.l[1]; - } - break; - case VisibilityNotify: - view->visible = xevent.xvisibility.state != VisibilityFullyObscured; - break; - case MapNotify: - event.type = PUGL_MAP; - break; - case UnmapNotify: - event.type = PUGL_UNMAP; - view->visible = false; - break; - case ConfigureNotify: - event.type = PUGL_CONFIGURE; - event.configure.x = xevent.xconfigure.x; - event.configure.y = xevent.xconfigure.y; - event.configure.width = xevent.xconfigure.width; - event.configure.height = xevent.xconfigure.height; - break; - case Expose: - event.type = PUGL_EXPOSE; - event.expose.x = xevent.xexpose.x; - event.expose.y = xevent.xexpose.y; - event.expose.width = xevent.xexpose.width; - event.expose.height = xevent.xexpose.height; - break; - case MotionNotify: - event.type = PUGL_MOTION; - event.motion.time = (double)xevent.xmotion.time / 1e3; - event.motion.x = xevent.xmotion.x; - event.motion.y = xevent.xmotion.y; - event.motion.xRoot = xevent.xmotion.x_root; - event.motion.yRoot = xevent.xmotion.y_root; - event.motion.state = translateModifiers(xevent.xmotion.state); - if (xevent.xmotion.is_hint == NotifyHint) { - event.motion.flags |= PUGL_IS_HINT; - } - break; - case ButtonPress: - if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) { - event.type = PUGL_SCROLL; - event.scroll.time = (double)xevent.xbutton.time / 1e3; - event.scroll.x = xevent.xbutton.x; - event.scroll.y = xevent.xbutton.y; - event.scroll.xRoot = xevent.xbutton.x_root; - event.scroll.yRoot = xevent.xbutton.y_root; - event.scroll.state = translateModifiers(xevent.xbutton.state); - event.scroll.dx = 0.0; - event.scroll.dy = 0.0; - switch (xevent.xbutton.button) { - case 4: - event.scroll.dy = 1.0; - event.scroll.direction = PUGL_SCROLL_UP; - break; - case 5: - event.scroll.dy = -1.0; - event.scroll.direction = PUGL_SCROLL_DOWN; - break; - case 6: - event.scroll.dx = -1.0; - event.scroll.direction = PUGL_SCROLL_LEFT; - break; - case 7: - event.scroll.dx = 1.0; - event.scroll.direction = PUGL_SCROLL_RIGHT; - break; - } - // fallthru - } - // fallthru - case ButtonRelease: - if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) { - event.button.type = ((xevent.type == ButtonPress) - ? PUGL_BUTTON_PRESS - : PUGL_BUTTON_RELEASE); - event.button.time = (double)xevent.xbutton.time / 1e3; - event.button.x = xevent.xbutton.x; - event.button.y = xevent.xbutton.y; - event.button.xRoot = xevent.xbutton.x_root; - event.button.yRoot = xevent.xbutton.y_root; - event.button.state = translateModifiers(xevent.xbutton.state); - event.button.button = xevent.xbutton.button; - } - break; - case KeyPress: - case KeyRelease: - event.type = ((xevent.type == KeyPress) - ? PUGL_KEY_PRESS - : PUGL_KEY_RELEASE); - event.key.time = (double)xevent.xkey.time / 1e3; - event.key.x = xevent.xkey.x; - event.key.y = xevent.xkey.y; - event.key.xRoot = xevent.xkey.x_root; - event.key.yRoot = xevent.xkey.y_root; - event.key.state = translateModifiers(xevent.xkey.state); - translateKey(view, &xevent, &event); - break; - case EnterNotify: - case LeaveNotify: - event.type = ((xevent.type == EnterNotify) - ? PUGL_POINTER_IN - : PUGL_POINTER_OUT); - event.crossing.time = (double)xevent.xcrossing.time / 1e3; - event.crossing.x = xevent.xcrossing.x; - event.crossing.y = xevent.xcrossing.y; - event.crossing.xRoot = xevent.xcrossing.x_root; - event.crossing.yRoot = xevent.xcrossing.y_root; - event.crossing.state = translateModifiers(xevent.xcrossing.state); - event.crossing.mode = PUGL_CROSSING_NORMAL; - if (xevent.xcrossing.mode == NotifyGrab) { - event.crossing.mode = PUGL_CROSSING_GRAB; - } else if (xevent.xcrossing.mode == NotifyUngrab) { - event.crossing.mode = PUGL_CROSSING_UNGRAB; - } - break; - - case FocusIn: - case FocusOut: - event.type = (xevent.type == FocusIn) ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT; - event.focus.mode = PUGL_CROSSING_NORMAL; - if (xevent.xfocus.mode == NotifyGrab) { - event.focus.mode = PUGL_CROSSING_GRAB; - } else if (xevent.xfocus.mode == NotifyUngrab) { - event.focus.mode = PUGL_CROSSING_UNGRAB; - } - break; - - default: - break; - } - - return event; + const PuglX11Atoms* atoms = &view->world->impl->atoms; + + PuglEvent event = {{PUGL_NOTHING, 0}}; + event.any.flags = xevent.xany.send_event ? PUGL_IS_SEND_EVENT : 0; + + switch (xevent.type) { + case ClientMessage: + if (xevent.xclient.message_type == atoms->WM_PROTOCOLS) { + const Atom protocol = (Atom)xevent.xclient.data.l[0]; + if (protocol == atoms->WM_DELETE_WINDOW) { + event.type = PUGL_CLOSE; + } + } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) { + event.type = PUGL_CLIENT; + event.client.data1 = (uintptr_t)xevent.xclient.data.l[0]; + event.client.data2 = (uintptr_t)xevent.xclient.data.l[1]; + } + break; + case VisibilityNotify: + view->visible = xevent.xvisibility.state != VisibilityFullyObscured; + break; + case MapNotify: + event.type = PUGL_MAP; + break; + case UnmapNotify: + event.type = PUGL_UNMAP; + view->visible = false; + break; + case ConfigureNotify: + event.type = PUGL_CONFIGURE; + event.configure.x = xevent.xconfigure.x; + event.configure.y = xevent.xconfigure.y; + event.configure.width = xevent.xconfigure.width; + event.configure.height = xevent.xconfigure.height; + break; + case Expose: + event.type = PUGL_EXPOSE; + event.expose.x = xevent.xexpose.x; + event.expose.y = xevent.xexpose.y; + event.expose.width = xevent.xexpose.width; + event.expose.height = xevent.xexpose.height; + break; + case MotionNotify: + event.type = PUGL_MOTION; + event.motion.time = (double)xevent.xmotion.time / 1e3; + event.motion.x = xevent.xmotion.x; + event.motion.y = xevent.xmotion.y; + event.motion.xRoot = xevent.xmotion.x_root; + event.motion.yRoot = xevent.xmotion.y_root; + event.motion.state = translateModifiers(xevent.xmotion.state); + if (xevent.xmotion.is_hint == NotifyHint) { + event.motion.flags |= PUGL_IS_HINT; + } + break; + case ButtonPress: + if (xevent.xbutton.button >= 4 && xevent.xbutton.button <= 7) { + event.type = PUGL_SCROLL; + event.scroll.time = (double)xevent.xbutton.time / 1e3; + event.scroll.x = xevent.xbutton.x; + event.scroll.y = xevent.xbutton.y; + event.scroll.xRoot = xevent.xbutton.x_root; + event.scroll.yRoot = xevent.xbutton.y_root; + event.scroll.state = translateModifiers(xevent.xbutton.state); + event.scroll.dx = 0.0; + event.scroll.dy = 0.0; + switch (xevent.xbutton.button) { + case 4: + event.scroll.dy = 1.0; + event.scroll.direction = PUGL_SCROLL_UP; + break; + case 5: + event.scroll.dy = -1.0; + event.scroll.direction = PUGL_SCROLL_DOWN; + break; + case 6: + event.scroll.dx = -1.0; + event.scroll.direction = PUGL_SCROLL_LEFT; + break; + case 7: + event.scroll.dx = 1.0; + event.scroll.direction = PUGL_SCROLL_RIGHT; + break; + } + // fallthru + } + // fallthru + case ButtonRelease: + if (xevent.xbutton.button < 4 || xevent.xbutton.button > 7) { + event.button.type = ((xevent.type == ButtonPress) ? PUGL_BUTTON_PRESS + : PUGL_BUTTON_RELEASE); + event.button.time = (double)xevent.xbutton.time / 1e3; + event.button.x = xevent.xbutton.x; + event.button.y = xevent.xbutton.y; + event.button.xRoot = xevent.xbutton.x_root; + event.button.yRoot = xevent.xbutton.y_root; + event.button.state = translateModifiers(xevent.xbutton.state); + event.button.button = xevent.xbutton.button; + } + break; + case KeyPress: + case KeyRelease: + event.type = + ((xevent.type == KeyPress) ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE); + event.key.time = (double)xevent.xkey.time / 1e3; + event.key.x = xevent.xkey.x; + event.key.y = xevent.xkey.y; + event.key.xRoot = xevent.xkey.x_root; + event.key.yRoot = xevent.xkey.y_root; + event.key.state = translateModifiers(xevent.xkey.state); + translateKey(view, &xevent, &event); + break; + case EnterNotify: + case LeaveNotify: + event.type = + ((xevent.type == EnterNotify) ? PUGL_POINTER_IN : PUGL_POINTER_OUT); + event.crossing.time = (double)xevent.xcrossing.time / 1e3; + event.crossing.x = xevent.xcrossing.x; + event.crossing.y = xevent.xcrossing.y; + event.crossing.xRoot = xevent.xcrossing.x_root; + event.crossing.yRoot = xevent.xcrossing.y_root; + event.crossing.state = translateModifiers(xevent.xcrossing.state); + event.crossing.mode = PUGL_CROSSING_NORMAL; + if (xevent.xcrossing.mode == NotifyGrab) { + event.crossing.mode = PUGL_CROSSING_GRAB; + } else if (xevent.xcrossing.mode == NotifyUngrab) { + event.crossing.mode = PUGL_CROSSING_UNGRAB; + } + break; + + case FocusIn: + case FocusOut: + event.type = (xevent.type == FocusIn) ? PUGL_FOCUS_IN : PUGL_FOCUS_OUT; + event.focus.mode = PUGL_CROSSING_NORMAL; + if (xevent.xfocus.mode == NotifyGrab) { + event.focus.mode = PUGL_CROSSING_GRAB; + } else if (xevent.xfocus.mode == NotifyUngrab) { + event.focus.mode = PUGL_CROSSING_UNGRAB; + } + break; + + default: + break; + } + + return event; } PuglStatus puglGrabFocus(PuglView* view) { - XSetInputFocus( - view->impl->display, view->impl->win, RevertToNone, CurrentTime); - return PUGL_SUCCESS; + XSetInputFocus( + view->impl->display, view->impl->win, RevertToNone, CurrentTime); + return PUGL_SUCCESS; } bool puglHasFocus(const PuglView* view) { - int revertTo = 0; - Window focusedWindow = 0; - XGetInputFocus(view->impl->display, &focusedWindow, &revertTo); - return focusedWindow == view->impl->win; + int revertTo = 0; + Window focusedWindow = 0; + XGetInputFocus(view->impl->display, &focusedWindow, &revertTo); + return focusedWindow == view->impl->win; } PuglStatus puglRequestAttention(PuglView* view) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - XEvent event = {0}; - - event.type = ClientMessage; - event.xclient.window = impl->win; - event.xclient.format = 32; - event.xclient.message_type = atoms->NET_WM_STATE; - event.xclient.data.l[0] = WM_STATE_ADD; - event.xclient.data.l[1] = (long)atoms->NET_WM_STATE_DEMANDS_ATTENTION; - event.xclient.data.l[2] = 0; - event.xclient.data.l[3] = 1; - event.xclient.data.l[4] = 0; - - const Window root = RootWindow(impl->display, impl->screen); - XSendEvent(impl->display, - root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; + XEvent event = {0}; + + event.type = ClientMessage; + event.xclient.window = impl->win; + event.xclient.format = 32; + event.xclient.message_type = atoms->NET_WM_STATE; + event.xclient.data.l[0] = WM_STATE_ADD; + event.xclient.data.l[1] = (long)atoms->NET_WM_STATE_DEMANDS_ATTENTION; + event.xclient.data.l[2] = 0; + event.xclient.data.l[3] = 1; + event.xclient.data.l[4] = 0; + + const Window root = RootWindow(impl->display, impl->screen); + XSendEvent(impl->display, + root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + + return PUGL_SUCCESS; } PuglStatus puglStartTimer(PuglView* view, uintptr_t id, double timeout) { #ifdef HAVE_XSYNC - if (view->world->impl->syncSupported) { - XSyncValue value; - XSyncIntToValue(&value, (int)floor(timeout * 1000.0)); - - PuglWorldInternals* w = view->world->impl; - Display* const display = w->display; - const XSyncCounter counter = w->serverTimeCounter; - const XSyncTestType type = XSyncPositiveTransition; - const XSyncTrigger trigger = {counter, XSyncRelative, value, type}; - XSyncAlarmAttributes attr = {trigger, value, True, XSyncAlarmActive}; - const XSyncAlarm alarm = XSyncCreateAlarm(display, 0x17, &attr); - const PuglTimer timer = {alarm, view, id}; - - if (alarm != None) { - for (size_t i = 0; i < w->numTimers; ++i) { - if (w->timers[i].view == view && w->timers[i].id == id) { - // Replace existing timer - XSyncDestroyAlarm(w->display, w->timers[i].alarm); - w->timers[i] = timer; - return PUGL_SUCCESS; - } - } - - // Add new timer - const size_t size = ++w->numTimers * sizeof(timer); - w->timers = (PuglTimer*)realloc(w->timers, size); - w->timers[w->numTimers - 1] = timer; - return PUGL_SUCCESS; - } - } + if (view->world->impl->syncSupported) { + XSyncValue value; + XSyncIntToValue(&value, (int)floor(timeout * 1000.0)); + + PuglWorldInternals* w = view->world->impl; + Display* const display = w->display; + const XSyncCounter counter = w->serverTimeCounter; + const XSyncTestType type = XSyncPositiveTransition; + const XSyncTrigger trigger = {counter, XSyncRelative, value, type}; + XSyncAlarmAttributes attr = {trigger, value, True, XSyncAlarmActive}; + const XSyncAlarm alarm = XSyncCreateAlarm(display, 0x17, &attr); + const PuglTimer timer = {alarm, view, id}; + + if (alarm != None) { + for (size_t i = 0; i < w->numTimers; ++i) { + if (w->timers[i].view == view && w->timers[i].id == id) { + // Replace existing timer + XSyncDestroyAlarm(w->display, w->timers[i].alarm); + w->timers[i] = timer; + return PUGL_SUCCESS; + } + } + + // Add new timer + const size_t size = ++w->numTimers * sizeof(timer); + w->timers = (PuglTimer*)realloc(w->timers, size); + w->timers[w->numTimers - 1] = timer; + return PUGL_SUCCESS; + } + } #else - (void)view; - (void)id; - (void)timeout; + (void)view; + (void)id; + (void)timeout; #endif - return PUGL_FAILURE; + return PUGL_FAILURE; } PuglStatus puglStopTimer(PuglView* view, uintptr_t id) { #ifdef HAVE_XSYNC - PuglWorldInternals* w = view->world->impl; - - for (size_t i = 0; i < w->numTimers; ++i) { - if (w->timers[i].view == view && w->timers[i].id == id) { - XSyncDestroyAlarm(w->display, w->timers[i].alarm); - - if (i == w->numTimers - 1) { - memset(&w->timers[i], 0, sizeof(PuglTimer)); - } else { - memmove(w->timers + i, - w->timers + i + 1, - sizeof(PuglTimer) * (w->numTimers - i - 1)); - - memset(&w->timers[i], 0, sizeof(PuglTimer)); - } - - --w->numTimers; - return PUGL_SUCCESS; - } - } + PuglWorldInternals* w = view->world->impl; + + for (size_t i = 0; i < w->numTimers; ++i) { + if (w->timers[i].view == view && w->timers[i].id == id) { + XSyncDestroyAlarm(w->display, w->timers[i].alarm); + + if (i == w->numTimers - 1) { + memset(&w->timers[i], 0, sizeof(PuglTimer)); + } else { + memmove(w->timers + i, + w->timers + i + 1, + sizeof(PuglTimer) * (w->numTimers - i - 1)); + + memset(&w->timers[i], 0, sizeof(PuglTimer)); + } + + --w->numTimers; + return PUGL_SUCCESS; + } + } #else - (void)view; - (void)id; + (void)view; + (void)id; #endif - return PUGL_FAILURE; + return PUGL_FAILURE; } static XEvent puglEventToX(PuglView* view, const PuglEvent* event) { - XEvent xev = {0}; - xev.xany.send_event = True; - - switch (event->type) { - case PUGL_EXPOSE: { - const double x = floor(event->expose.x); - const double y = floor(event->expose.y); - const double w = ceil(event->expose.x + event->expose.width) - x; - const double h = ceil(event->expose.y + event->expose.height) - y; - - xev.xexpose.type = Expose; - xev.xexpose.serial = 0; - xev.xexpose.display = view->impl->display; - xev.xexpose.window = view->impl->win; - xev.xexpose.x = (int)x; - xev.xexpose.y = (int)y; - xev.xexpose.width = (int)w; - xev.xexpose.height = (int)h; - break; - } - - case PUGL_CLIENT: - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.display = view->impl->display; - xev.xclient.window = view->impl->win; - xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG; - xev.xclient.format = 32; - xev.xclient.data.l[0] = (long)event->client.data1; - xev.xclient.data.l[1] = (long)event->client.data2; - break; - - default: - break; - } - - return xev; + XEvent xev = {0}; + xev.xany.send_event = True; + + switch (event->type) { + case PUGL_EXPOSE: { + const double x = floor(event->expose.x); + const double y = floor(event->expose.y); + const double w = ceil(event->expose.x + event->expose.width) - x; + const double h = ceil(event->expose.y + event->expose.height) - y; + + xev.xexpose.type = Expose; + xev.xexpose.serial = 0; + xev.xexpose.display = view->impl->display; + xev.xexpose.window = view->impl->win; + xev.xexpose.x = (int)x; + xev.xexpose.y = (int)y; + xev.xexpose.width = (int)w; + xev.xexpose.height = (int)h; + break; + } + + case PUGL_CLIENT: + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = view->impl->display; + xev.xclient.window = view->impl->win; + xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG; + xev.xclient.format = 32; + xev.xclient.data.l[0] = (long)event->client.data1; + xev.xclient.data.l[1] = (long)event->client.data2; + break; + + default: + break; + } + + return xev; } PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) { - XEvent xev = puglEventToX(view, event); + XEvent xev = puglEventToX(view, event); - if (xev.type) { - if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) { - return PUGL_SUCCESS; - } else { - return PUGL_UNKNOWN_ERROR; - } - } + if (xev.type) { + if (XSendEvent(view->impl->display, view->impl->win, False, 0, &xev)) { + return PUGL_SUCCESS; + } else { + return PUGL_UNKNOWN_ERROR; + } + } - return PUGL_UNSUPPORTED_TYPE; + return PUGL_UNSUPPORTED_TYPE; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglWaitForEvent(PuglView* view) { - XEvent xevent; - XPeekEvent(view->impl->display, &xevent); - return PUGL_SUCCESS; + XEvent xevent; + XPeekEvent(view->impl->display, &xevent); + return PUGL_SUCCESS; } #endif static void mergeExposeEvents(PuglEventExpose* dst, const PuglEventExpose* src) { - if (!dst->type) { - *dst = *src; - } else { - const double max_x = MAX(dst->x + dst->width, src->x + src->width); - const double max_y = MAX(dst->y + dst->height, src->y + src->height); - - dst->x = MIN(dst->x, src->x); - dst->y = MIN(dst->y, src->y); - dst->width = max_x - dst->x; - dst->height = max_y - dst->y; - } + if (!dst->type) { + *dst = *src; + } else { + const double max_x = MAX(dst->x + dst->width, src->x + src->width); + const double max_y = MAX(dst->y + dst->height, src->y + src->height); + + dst->x = MIN(dst->x, src->x); + dst->y = MIN(dst->y, src->y); + dst->width = max_x - dst->x; + dst->height = max_y - dst->y; + } } static void handleSelectionNotify(const PuglWorld* world, PuglView* view) { - uint8_t* str = NULL; - Atom type = 0; - int fmt = 0; - unsigned long len = 0; - unsigned long left = 0; - - XGetWindowProperty(world->impl->display, - view->impl->win, - XA_PRIMARY, - 0, - 0x1FFFFFFF, - False, - AnyPropertyType, - &type, - &fmt, - &len, - &left, - &str); - - if (str && fmt == 8 && type == world->impl->atoms.UTF8_STRING && - left == 0) { - puglSetBlob(&view->clipboard, str, len); - } - - XFree(str); + uint8_t* str = NULL; + Atom type = 0; + int fmt = 0; + unsigned long len = 0; + unsigned long left = 0; + + XGetWindowProperty(world->impl->display, + view->impl->win, + XA_PRIMARY, + 0, + 0x1FFFFFFF, + False, + AnyPropertyType, + &type, + &fmt, + &len, + &left, + &str); + + if (str && fmt == 8 && type == world->impl->atoms.UTF8_STRING && left == 0) { + puglSetBlob(&view->clipboard, str, len); + } + + XFree(str); } static void @@ -938,305 +970,308 @@ handleSelectionRequest(const PuglWorld* world, PuglView* view, const XSelectionRequestEvent* request) { - XSelectionEvent note = {SelectionNotify, - request->serial, - False, - world->impl->display, - request->requestor, - request->selection, - request->target, - None, - request->time}; - - const char* type = NULL; - size_t len = 0; - const void* data = puglGetInternalClipboard(view, &type, &len); - if (data && request->selection == world->impl->atoms.CLIPBOARD && - request->target == world->impl->atoms.UTF8_STRING) { - note.property = request->property; - XChangeProperty(world->impl->display, - note.requestor, - note.property, - note.target, - 8, - PropModeReplace, - (const uint8_t*)data, - (int)len); - } else { - note.property = None; - } - - XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)¬e); + XSelectionEvent note = {SelectionNotify, + request->serial, + False, + world->impl->display, + request->requestor, + request->selection, + request->target, + None, + request->time}; + + const char* type = NULL; + size_t len = 0; + const void* data = puglGetInternalClipboard(view, &type, &len); + if (data && request->selection == world->impl->atoms.CLIPBOARD && + request->target == world->impl->atoms.UTF8_STRING) { + note.property = request->property; + XChangeProperty(world->impl->display, + note.requestor, + note.property, + note.target, + 8, + PropModeReplace, + (const uint8_t*)data, + (int)len); + } else { + note.property = None; + } + + XSendEvent(world->impl->display, note.requestor, True, 0, (XEvent*)¬e); } /// Flush pending configure and expose events for all views static void flushExposures(PuglWorld* world) { - for (size_t i = 0; i < world->numViews; ++i) { - PuglView* const view = world->views[i]; - - if (view->visible) { - puglDispatchSimpleEvent(view, PUGL_UPDATE); - } - - const PuglEvent configure = view->impl->pendingConfigure; - const PuglEvent expose = view->impl->pendingExpose; - - view->impl->pendingConfigure.type = PUGL_NOTHING; - view->impl->pendingExpose.type = PUGL_NOTHING; - - if (configure.type || expose.type) { - view->backend->enter(view, expose.type ? &expose.expose : NULL); - puglDispatchEventInContext(view, &configure); - puglDispatchEventInContext(view, &expose); - view->backend->leave(view, expose.type ? &expose.expose : NULL); - } - } + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* const view = world->views[i]; + + if (view->visible) { + puglDispatchSimpleEvent(view, PUGL_UPDATE); + } + + const PuglEvent configure = view->impl->pendingConfigure; + const PuglEvent expose = view->impl->pendingExpose; + + view->impl->pendingConfigure.type = PUGL_NOTHING; + view->impl->pendingExpose.type = PUGL_NOTHING; + + if (configure.type || expose.type) { + view->backend->enter(view, expose.type ? &expose.expose : NULL); + puglDispatchEventInContext(view, &configure); + puglDispatchEventInContext(view, &expose); + view->backend->leave(view, expose.type ? &expose.expose : NULL); + } + } } static bool handleTimerEvent(PuglWorld* world, XEvent xevent) { #ifdef HAVE_XSYNC - if (xevent.type == world->impl->syncEventBase + XSyncAlarmNotify) { - XSyncAlarmNotifyEvent* notify = ((XSyncAlarmNotifyEvent*)&xevent); - - for (size_t i = 0; i < world->impl->numTimers; ++i) { - if (world->impl->timers[i].alarm == notify->alarm) { - PuglEvent event = {{PUGL_TIMER, 0}}; - event.timer.id = world->impl->timers[i].id; - puglDispatchEvent(world->impl->timers[i].view, - (const PuglEvent*)&event); - } - } - - return true; - } + if (xevent.type == world->impl->syncEventBase + XSyncAlarmNotify) { + XSyncAlarmNotifyEvent* notify = ((XSyncAlarmNotifyEvent*)&xevent); + + for (size_t i = 0; i < world->impl->numTimers; ++i) { + if (world->impl->timers[i].alarm == notify->alarm) { + PuglEvent event = {{PUGL_TIMER, 0}}; + event.timer.id = world->impl->timers[i].id; + puglDispatchEvent(world->impl->timers[i].view, + (const PuglEvent*)&event); + } + } + + return true; + } #else - (void)world; - (void)xevent; + (void)world; + (void)xevent; #endif - return false; + return false; } static PuglStatus puglDispatchX11Events(PuglWorld* world) { - const PuglX11Atoms* const atoms = &world->impl->atoms; - - // Flush output to the server once at the start - Display* display = world->impl->display; - XFlush(display); - - // Process all queued events (without further flushing) - while (XEventsQueued(display, QueuedAfterReading) > 0) { - XEvent xevent; - XNextEvent(display, &xevent); - - if (handleTimerEvent(world, xevent)) { - continue; - } - - PuglView* view = puglFindView(world, xevent.xany.window); - if (!view) { - continue; - } - - // Handle special events - PuglInternals* const impl = view->impl; - if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) { - XEvent next; - if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) && - next.type == KeyPress && - next.xkey.time == xevent.xkey.time && - next.xkey.keycode == xevent.xkey.keycode) { - continue; - } - } else if (xevent.type == FocusIn) { - XSetICFocus(impl->xic); - } else if (xevent.type == FocusOut) { - XUnsetICFocus(impl->xic); - } else if (xevent.type == SelectionClear) { - puglSetBlob(&view->clipboard, NULL, 0); - } else if (xevent.type == SelectionNotify && - xevent.xselection.selection == atoms->CLIPBOARD && - xevent.xselection.target == atoms->UTF8_STRING && - xevent.xselection.property == XA_PRIMARY) { - handleSelectionNotify(world, view); - } else if (xevent.type == SelectionRequest) { - handleSelectionRequest(world, view, &xevent.xselectionrequest); - } - - // Translate X11 event to Pugl event - const PuglEvent event = translateEvent(view, xevent); - - if (event.type == PUGL_EXPOSE) { - // Expand expose event to be dispatched after loop - mergeExposeEvents(&view->impl->pendingExpose.expose, &event.expose); - } else if (event.type == PUGL_CONFIGURE) { - // Expand configure event to be dispatched after loop - view->impl->pendingConfigure = event; - view->frame.x = event.configure.x; - view->frame.y = event.configure.y; - view->frame.width = event.configure.width; - view->frame.height = event.configure.height; - } else if (event.type == PUGL_MAP && view->parent) { - XWindowAttributes attrs; - XGetWindowAttributes(view->impl->display, view->impl->win, &attrs); - - const PuglEventConfigure configure = { - PUGL_CONFIGURE, 0, attrs.x, attrs.y, attrs.width, attrs.height}; - - puglDispatchEvent(view, (const PuglEvent*)&configure); - puglDispatchEvent(view, &event); - } else { - // Dispatch event to application immediately - puglDispatchEvent(view, &event); - } - } - - return PUGL_SUCCESS; + const PuglX11Atoms* const atoms = &world->impl->atoms; + + // Flush output to the server once at the start + Display* display = world->impl->display; + XFlush(display); + + // Process all queued events (without further flushing) + while (XEventsQueued(display, QueuedAfterReading) > 0) { + XEvent xevent; + XNextEvent(display, &xevent); + + if (handleTimerEvent(world, xevent)) { + continue; + } + + PuglView* view = puglFindView(world, xevent.xany.window); + if (!view) { + continue; + } + + // Handle special events + PuglInternals* const impl = view->impl; + if (xevent.type == KeyRelease && view->hints[PUGL_IGNORE_KEY_REPEAT]) { + XEvent next; + if (XCheckTypedWindowEvent(display, impl->win, KeyPress, &next) && + next.type == KeyPress && next.xkey.time == xevent.xkey.time && + next.xkey.keycode == xevent.xkey.keycode) { + continue; + } + } else if (xevent.type == FocusIn) { + XSetICFocus(impl->xic); + } else if (xevent.type == FocusOut) { + XUnsetICFocus(impl->xic); + } else if (xevent.type == SelectionClear) { + puglSetBlob(&view->clipboard, NULL, 0); + } else if (xevent.type == SelectionNotify && + xevent.xselection.selection == atoms->CLIPBOARD && + xevent.xselection.target == atoms->UTF8_STRING && + xevent.xselection.property == XA_PRIMARY) { + handleSelectionNotify(world, view); + } else if (xevent.type == SelectionRequest) { + handleSelectionRequest(world, view, &xevent.xselectionrequest); + } + + // Translate X11 event to Pugl event + const PuglEvent event = translateEvent(view, xevent); + + if (event.type == PUGL_EXPOSE) { + // Expand expose event to be dispatched after loop + mergeExposeEvents(&view->impl->pendingExpose.expose, &event.expose); + } else if (event.type == PUGL_CONFIGURE) { + // Expand configure event to be dispatched after loop + view->impl->pendingConfigure = event; + view->frame.x = event.configure.x; + view->frame.y = event.configure.y; + view->frame.width = event.configure.width; + view->frame.height = event.configure.height; + } else if (event.type == PUGL_MAP && view->parent) { + XWindowAttributes attrs; + XGetWindowAttributes(view->impl->display, view->impl->win, &attrs); + + const PuglEventConfigure configure = { + PUGL_CONFIGURE, 0, attrs.x, attrs.y, attrs.width, attrs.height}; + + puglDispatchEvent(view, (const PuglEvent*)&configure); + puglDispatchEvent(view, &event); + } else { + // Dispatch event to application immediately + puglDispatchEvent(view, &event); + } + } + + return PUGL_SUCCESS; } #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglProcessEvents(PuglView* view) { - return puglUpdate(view->world, 0.0); + return puglUpdate(view->world, 0.0); } #endif PuglStatus puglUpdate(PuglWorld* world, double timeout) { - const double startTime = puglGetTime(world); - PuglStatus st = PUGL_SUCCESS; - - world->impl->dispatchingEvents = true; - - if (timeout < 0.0) { - st = puglPollX11Socket(world, timeout); - st = st ? st : puglDispatchX11Events(world); - } else if (timeout <= 0.001) { - st = puglDispatchX11Events(world); - } else { - const double endTime = startTime + timeout - 0.001; - for (double t = startTime; t < endTime; t = puglGetTime(world)) { - if ((st = puglPollX11Socket(world, endTime - t)) || - (st = puglDispatchX11Events(world))) { - break; - } - } - } - - flushExposures(world); - - world->impl->dispatchingEvents = false; - - return st; + const double startTime = puglGetTime(world); + PuglStatus st = PUGL_SUCCESS; + + world->impl->dispatchingEvents = true; + + if (timeout < 0.0) { + st = puglPollX11Socket(world, timeout); + st = st ? st : puglDispatchX11Events(world); + } else if (timeout <= 0.001) { + st = puglDispatchX11Events(world); + } else { + const double endTime = startTime + timeout - 0.001; + for (double t = startTime; t < endTime; t = puglGetTime(world)) { + if ((st = puglPollX11Socket(world, endTime - t)) || + (st = puglDispatchX11Events(world))) { + break; + } + } + } + + flushExposures(world); + + world->impl->dispatchingEvents = false; + + return st; } double puglGetTime(const PuglWorld* world) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) - - world->startTime; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) - + world->startTime; } PuglStatus puglPostRedisplay(PuglView* view) { - const PuglRect rect = { 0, 0, view->frame.width, view->frame.height }; + const PuglRect rect = {0, 0, view->frame.width, view->frame.height}; - return puglPostRedisplayRect(view, rect); + return puglPostRedisplayRect(view, rect); } PuglStatus puglPostRedisplayRect(PuglView* view, PuglRect rect) { - const PuglEventExpose event = { - PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height - }; - - if (view->world->impl->dispatchingEvents) { - // Currently dispatching events, add/expand expose for the loop end - mergeExposeEvents(&view->impl->pendingExpose.expose, &event); - } else if (view->visible) { - // Not dispatching events, send an X expose so we wake up next time - return puglSendEvent(view, (const PuglEvent*)&event); - } - - return PUGL_SUCCESS; + const PuglEventExpose event = { + PUGL_EXPOSE, 0, rect.x, rect.y, rect.width, rect.height}; + + if (view->world->impl->dispatchingEvents) { + // Currently dispatching events, add/expand expose for the loop end + mergeExposeEvents(&view->impl->pendingExpose.expose, &event); + } else if (view->visible) { + // Not dispatching events, send an X expose so we wake up next time + return puglSendEvent(view, (const PuglEvent*)&event); + } + + return PUGL_SUCCESS; } PuglNativeView puglGetNativeWindow(PuglView* view) { - return (PuglNativeView)view->impl->win; + return (PuglNativeView)view->impl->win; } PuglStatus puglSetWindowTitle(PuglView* view, const char* title) { - Display* display = view->world->impl->display; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - - puglSetString(&view->title, title); - - if (view->impl->win) { - XStoreName(display, view->impl->win, title); - XChangeProperty(display, view->impl->win, atoms->NET_WM_NAME, - atoms->UTF8_STRING, 8, PropModeReplace, - (const uint8_t*)title, (int)strlen(title)); - } - - return PUGL_SUCCESS; + Display* display = view->world->impl->display; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; + + puglSetString(&view->title, title); + + if (view->impl->win) { + XStoreName(display, view->impl->win, title); + XChangeProperty(display, + view->impl->win, + atoms->NET_WM_NAME, + atoms->UTF8_STRING, + 8, + PropModeReplace, + (const uint8_t*)title, + (int)strlen(title)); + } + + return PUGL_SUCCESS; } PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { - if (view->impl->win) { - if (!XMoveResizeWindow(view->world->impl->display, - view->impl->win, - (int)frame.x, - (int)frame.y, - (unsigned)frame.width, - (unsigned)frame.height)) { - return PUGL_UNKNOWN_ERROR; - } - } - - view->frame = frame; - return PUGL_SUCCESS; + if (view->impl->win) { + if (!XMoveResizeWindow(view->world->impl->display, + view->impl->win, + (int)frame.x, + (int)frame.y, + (unsigned)frame.width, + (unsigned)frame.height)) { + return PUGL_UNKNOWN_ERROR; + } + } + + view->frame = frame; + return PUGL_SUCCESS; } PuglStatus puglSetDefaultSize(PuglView* const view, const int width, const int height) { - view->defaultWidth = width; - view->defaultHeight = height; - return updateSizeHints(view); + view->defaultWidth = width; + view->defaultHeight = height; + return updateSizeHints(view); } PuglStatus puglSetMinSize(PuglView* const view, const int width, const int height) { - view->minWidth = width; - view->minHeight = height; - return updateSizeHints(view); + view->minWidth = width; + view->minHeight = height; + return updateSizeHints(view); } PuglStatus puglSetMaxSize(PuglView* const view, const int width, const int height) { - view->minWidth = width; - view->minHeight = height; - return updateSizeHints(view); + view->minWidth = width; + view->minHeight = height; + return updateSizeHints(view); } PuglStatus @@ -1246,27 +1281,27 @@ puglSetAspectRatio(PuglView* const view, const int maxX, const int maxY) { - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + view->minAspectX = minX; + view->minAspectY = minY; + view->maxAspectX = maxX; + view->maxAspectY = maxY; - return updateSizeHints(view); + return updateSizeHints(view); } PuglStatus puglSetTransientFor(PuglView* view, PuglNativeView parent) { - Display* display = view->world->impl->display; + Display* display = view->world->impl->display; - view->transientParent = parent; + view->transientParent = parent; - if (view->impl->win) { - XSetTransientForHint(display, view->impl->win, - (Window)view->transientParent); - } + if (view->impl->win) { + XSetTransientForHint( + display, view->impl->win, (Window)view->transientParent); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } const void* @@ -1274,29 +1309,29 @@ puglGetClipboard(PuglView* const view, const char** const type, size_t* const len) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; - - const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD); - if (owner != None && owner != impl->win) { - // Clear internal selection - puglSetBlob(&view->clipboard, NULL, 0); - - // Request selection from the owner - XConvertSelection(impl->display, - atoms->CLIPBOARD, - atoms->UTF8_STRING, - XA_PRIMARY, - impl->win, - CurrentTime); - - // Run event loop until data is received - while (!view->clipboard.data) { - puglUpdate(view->world, -1.0); - } - } - - return puglGetInternalClipboard(view, type, len); + PuglInternals* const impl = view->impl; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; + + const Window owner = XGetSelectionOwner(impl->display, atoms->CLIPBOARD); + if (owner != None && owner != impl->win) { + // Clear internal selection + puglSetBlob(&view->clipboard, NULL, 0); + + // Request selection from the owner + XConvertSelection(impl->display, + atoms->CLIPBOARD, + atoms->UTF8_STRING, + XA_PRIMARY, + impl->win, + CurrentTime); + + // Run event loop until data is received + while (!view->clipboard.data) { + puglUpdate(view->world, -1.0); + } + } + + return puglGetInternalClipboard(view, type, len); } PuglStatus @@ -1305,27 +1340,27 @@ puglSetClipboard(PuglView* const view, const void* const data, const size_t len) { - PuglInternals* const impl = view->impl; - const PuglX11Atoms* const atoms = &view->world->impl->atoms; + PuglInternals* const impl = view->impl; + const PuglX11Atoms* const atoms = &view->world->impl->atoms; - PuglStatus st = puglSetInternalClipboard(view, type, data, len); - if (st) { - return st; - } + PuglStatus st = puglSetInternalClipboard(view, type, data, len); + if (st) { + return st; + } - XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime); - return PUGL_SUCCESS; + XSetSelectionOwner(impl->display, atoms->CLIPBOARD, impl->win, CurrentTime); + return PUGL_SUCCESS; } #ifdef HAVE_XCURSOR static const unsigned cursor_nums[] = { - XC_arrow, // ARROW - XC_xterm, // CARET - XC_crosshair, // CROSSHAIR - XC_hand2, // HAND - XC_pirate, // NO - XC_sb_h_double_arrow, // LEFT_RIGHT - XC_sb_v_double_arrow, // UP_DOWN + XC_arrow, // ARROW + XC_xterm, // CARET + XC_crosshair, // CROSSHAIR + XC_hand2, // HAND + XC_pirate, // NO + XC_sb_h_double_arrow, // LEFT_RIGHT + XC_sb_v_double_arrow, // UP_DOWN }; #endif @@ -1333,24 +1368,24 @@ PuglStatus puglSetCursor(PuglView* view, PuglCursor cursor) { #ifdef HAVE_XCURSOR - PuglInternals* const impl = view->impl; - const unsigned index = (unsigned)cursor; - const unsigned count = sizeof(cursor_nums) / sizeof(cursor_nums[0]); - if (index >= count) { - return PUGL_BAD_PARAMETER; - } + PuglInternals* const impl = view->impl; + const unsigned index = (unsigned)cursor; + const unsigned count = sizeof(cursor_nums) / sizeof(cursor_nums[0]); + if (index >= count) { + return PUGL_BAD_PARAMETER; + } - const unsigned shape = cursor_nums[index]; - if (!impl->win || impl->cursorShape == shape) { - return PUGL_SUCCESS; - } + const unsigned shape = cursor_nums[index]; + if (!impl->win || impl->cursorShape == shape) { + return PUGL_SUCCESS; + } - impl->cursorShape = cursor_nums[index]; + impl->cursorShape = cursor_nums[index]; - return puglDefineCursorShape(view, impl->cursorShape); + return puglDefineCursorShape(view, impl->cursorShape); #else - (void)view; - (void)cursor; - return PUGL_FAILURE; + (void)view; + (void)cursor; + return PUGL_FAILURE; #endif } @@ -30,48 +30,49 @@ #include <stdint.h> typedef struct { - Atom CLIPBOARD; - Atom UTF8_STRING; - Atom WM_PROTOCOLS; - Atom WM_DELETE_WINDOW; - Atom PUGL_CLIENT_MSG; - Atom NET_WM_NAME; - Atom NET_WM_STATE; - Atom NET_WM_STATE_DEMANDS_ATTENTION; + Atom CLIPBOARD; + Atom UTF8_STRING; + Atom WM_PROTOCOLS; + Atom WM_DELETE_WINDOW; + Atom PUGL_CLIENT_MSG; + Atom NET_WM_NAME; + Atom NET_WM_STATE; + Atom NET_WM_STATE_DEMANDS_ATTENTION; } PuglX11Atoms; typedef struct { - XID alarm; - PuglView* view; - uintptr_t id; + XID alarm; + PuglView* view; + uintptr_t id; } PuglTimer; struct PuglWorldInternalsImpl { - Display* display; - PuglX11Atoms atoms; - XIM xim; - PuglTimer* timers; - size_t numTimers; - XID serverTimeCounter; - int syncEventBase; - bool syncSupported; - bool dispatchingEvents; + Display* display; + PuglX11Atoms atoms; + XIM xim; + PuglTimer* timers; + size_t numTimers; + XID serverTimeCounter; + int syncEventBase; + bool syncSupported; + bool dispatchingEvents; }; struct PuglInternalsImpl { - Display* display; - XVisualInfo* vi; - Window win; - XIC xic; - PuglSurface* surface; - PuglEvent pendingConfigure; - PuglEvent pendingExpose; - int screen; + Display* display; + XVisualInfo* vi; + Window win; + XIC xic; + PuglSurface* surface; + PuglEvent pendingConfigure; + PuglEvent pendingExpose; + int screen; #ifdef HAVE_XCURSOR - unsigned cursorShape; + unsigned cursorShape; #endif }; -PuglStatus puglX11StubConfigure(PuglView* view); +PuglStatus +puglX11StubConfigure(PuglView* view); #endif // PUGL_DETAIL_X11_H diff --git a/src/x11_cairo.c b/src/x11_cairo.c index 3147266..a0e7d08 100644 --- a/src/x11_cairo.c +++ b/src/x11_cairo.c @@ -27,140 +27,137 @@ #include <stdlib.h> typedef struct { - cairo_surface_t* back; - cairo_surface_t* front; - cairo_t* cr; + cairo_surface_t* back; + cairo_surface_t* front; + cairo_t* cr; } PuglX11CairoSurface; static void puglX11CairoClose(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - cairo_surface_destroy(surface->front); - cairo_surface_destroy(surface->back); - surface->front = surface->back = NULL; + cairo_surface_destroy(surface->front); + cairo_surface_destroy(surface->back); + surface->front = surface->back = NULL; } static PuglStatus puglX11CairoOpen(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - surface->back = cairo_xlib_surface_create(impl->display, - impl->win, - impl->vi->visual, - (int)view->frame.width, - (int)view->frame.height); - - surface->front = cairo_surface_create_similar( - surface->back, - cairo_surface_get_content(surface->back), - (int)view->frame.width, - (int)view->frame.height); - - if (cairo_surface_status(surface->back) || - cairo_surface_status(surface->front)) { - puglX11CairoClose(view); - return PUGL_CREATE_CONTEXT_FAILED; - } - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + + surface->back = cairo_xlib_surface_create(impl->display, + impl->win, + impl->vi->visual, + (int)view->frame.width, + (int)view->frame.height); + + surface->front = + cairo_surface_create_similar(surface->back, + cairo_surface_get_content(surface->back), + (int)view->frame.width, + (int)view->frame.height); + + if (cairo_surface_status(surface->back) || + cairo_surface_status(surface->front)) { + puglX11CairoClose(view); + return PUGL_CREATE_CONTEXT_FAILED; + } + + return PUGL_SUCCESS; } static PuglStatus puglX11CairoCreate(PuglView* view) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; - impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface)); + impl->surface = (cairo_surface_t*)calloc(1, sizeof(PuglX11CairoSurface)); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglX11CairoDestroy(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - puglX11CairoClose(view); - free(surface); + puglX11CairoClose(view); + free(surface); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglX11CairoEnter(PuglView* view, const PuglEventExpose* expose) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - PuglStatus st = PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + PuglStatus st = PUGL_SUCCESS; - if (expose && !(st = puglX11CairoOpen(view))) { - surface->cr = cairo_create(surface->front); + if (expose && !(st = puglX11CairoOpen(view))) { + surface->cr = cairo_create(surface->front); - if (cairo_status(surface->cr)) { - st = PUGL_CREATE_CONTEXT_FAILED; - } - } + if (cairo_status(surface->cr)) { + st = PUGL_CREATE_CONTEXT_FAILED; + } + } - return st; + return st; } static PuglStatus puglX11CairoLeave(PuglView* view, const PuglEventExpose* expose) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - - if (expose) { - // Destroy front context and create a new one for drawing to the back - cairo_destroy(surface->cr); - surface->cr = cairo_create(surface->back); - - // Clip to expose region - cairo_rectangle(surface->cr, - expose->x, - expose->y, - expose->width, - expose->height); - cairo_clip(surface->cr); - - // Paint front onto back - cairo_set_source_surface(surface->cr, surface->front, 0, 0); - cairo_paint(surface->cr); - - // Flush to X and close everything - cairo_destroy(surface->cr); - cairo_surface_flush(surface->back); - puglX11CairoClose(view); - surface->cr = NULL; - } - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + + if (expose) { + // Destroy front context and create a new one for drawing to the back + cairo_destroy(surface->cr); + surface->cr = cairo_create(surface->back); + + // Clip to expose region + cairo_rectangle( + surface->cr, expose->x, expose->y, expose->width, expose->height); + cairo_clip(surface->cr); + + // Paint front onto back + cairo_set_source_surface(surface->cr, surface->front, 0, 0); + cairo_paint(surface->cr); + + // Flush to X and close everything + cairo_destroy(surface->cr); + cairo_surface_flush(surface->back); + puglX11CairoClose(view); + surface->cr = NULL; + } + + return PUGL_SUCCESS; } static void* puglX11CairoGetContext(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; + PuglInternals* const impl = view->impl; + PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface; - return surface->cr; + return surface->cr; } const PuglBackend* puglCairoBackend(void) { - static const PuglBackend backend = {puglX11StubConfigure, - puglX11CairoCreate, - puglX11CairoDestroy, - puglX11CairoEnter, - puglX11CairoLeave, - puglX11CairoGetContext}; - - return &backend; + static const PuglBackend backend = {puglX11StubConfigure, + puglX11CairoCreate, + puglX11CairoDestroy, + puglX11CairoEnter, + puglX11CairoLeave, + puglX11CairoGetContext}; + + return &backend; } diff --git a/src/x11_gl.c b/src/x11_gl.c index 50b37b8..d0330b0 100644 --- a/src/x11_gl.c +++ b/src/x11_gl.c @@ -31,14 +31,14 @@ #include <stdlib.h> typedef struct { - GLXFBConfig fb_config; - GLXContext ctx; + GLXFBConfig fb_config; + GLXContext ctx; } PuglX11GlSurface; static int puglX11GlHintValue(const int value) { - return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value; + return value == PUGL_DONT_CARE ? (int)GLX_DONT_CARE : value; } static int @@ -46,185 +46,191 @@ puglX11GlGetAttrib(Display* const display, GLXFBConfig fb_config, const int attrib) { - int value = 0; - glXGetFBConfigAttrib(display, fb_config, attrib, &value); - return value; + int value = 0; + glXGetFBConfigAttrib(display, fb_config, attrib, &value); + return value; } static PuglStatus puglX11GlConfigure(PuglView* view) { - PuglInternals* const impl = view->impl; - const int screen = impl->screen; - Display* const display = impl->display; - - PuglX11GlSurface* const surface = - (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); - impl->surface = surface; - - const int attrs[] = { - GLX_X_RENDERABLE, True, - GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_SAMPLES, puglX11GlHintValue(view->hints[PUGL_SAMPLES]), - GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]), - GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]), - GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]), - GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]), - GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]), - GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]), - GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]), - None - }; - - int n_fbc = 0; - GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); - if (n_fbc <= 0) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - surface->fb_config = fbc[0]; - impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]); - - view->hints[PUGL_RED_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_RED_SIZE); - view->hints[PUGL_GREEN_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_GREEN_SIZE); - view->hints[PUGL_BLUE_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_BLUE_SIZE); - view->hints[PUGL_ALPHA_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_ALPHA_SIZE); - view->hints[PUGL_DEPTH_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_DEPTH_SIZE); - view->hints[PUGL_STENCIL_BITS] = puglX11GlGetAttrib( - display, fbc[0], GLX_STENCIL_SIZE); - view->hints[PUGL_SAMPLES] = puglX11GlGetAttrib( - display, fbc[0], GLX_SAMPLES); - view->hints[PUGL_DOUBLE_BUFFER] = puglX11GlGetAttrib( - display, fbc[0], GLX_DOUBLEBUFFER); - - XFree(fbc); - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + const int screen = impl->screen; + Display* const display = impl->display; + + PuglX11GlSurface* const surface = + (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface)); + impl->surface = surface; + + // clang-format off + const int attrs[] = { + GLX_X_RENDERABLE, True, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_SAMPLES, puglX11GlHintValue(view->hints[PUGL_SAMPLES]), + GLX_RED_SIZE, puglX11GlHintValue(view->hints[PUGL_RED_BITS]), + GLX_GREEN_SIZE, puglX11GlHintValue(view->hints[PUGL_GREEN_BITS]), + GLX_BLUE_SIZE, puglX11GlHintValue(view->hints[PUGL_BLUE_BITS]), + GLX_ALPHA_SIZE, puglX11GlHintValue(view->hints[PUGL_ALPHA_BITS]), + GLX_DEPTH_SIZE, puglX11GlHintValue(view->hints[PUGL_DEPTH_BITS]), + GLX_STENCIL_SIZE, puglX11GlHintValue(view->hints[PUGL_STENCIL_BITS]), + GLX_DOUBLEBUFFER, puglX11GlHintValue(view->hints[PUGL_DOUBLE_BUFFER]), + None + }; + // clang-format on + + int n_fbc = 0; + GLXFBConfig* fbc = glXChooseFBConfig(display, screen, attrs, &n_fbc); + if (n_fbc <= 0) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + surface->fb_config = fbc[0]; + impl->vi = glXGetVisualFromFBConfig(impl->display, fbc[0]); + + view->hints[PUGL_RED_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_RED_SIZE); + view->hints[PUGL_GREEN_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_GREEN_SIZE); + view->hints[PUGL_BLUE_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_BLUE_SIZE); + view->hints[PUGL_ALPHA_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_ALPHA_SIZE); + view->hints[PUGL_DEPTH_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_DEPTH_SIZE); + view->hints[PUGL_STENCIL_BITS] = + puglX11GlGetAttrib(display, fbc[0], GLX_STENCIL_SIZE); + view->hints[PUGL_SAMPLES] = puglX11GlGetAttrib(display, fbc[0], GLX_SAMPLES); + view->hints[PUGL_DOUBLE_BUFFER] = + puglX11GlGetAttrib(display, fbc[0], GLX_DOUBLEBUFFER); + + XFree(fbc); + + return PUGL_SUCCESS; } static PuglStatus puglX11GlEnter(PuglView* view, const PuglEventExpose* PUGL_UNUSED(expose)) { - PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx); - return PUGL_SUCCESS; + PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; + glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx); + return PUGL_SUCCESS; } static PuglStatus puglX11GlLeave(PuglView* view, const PuglEventExpose* expose) { - if (expose && view->hints[PUGL_DOUBLE_BUFFER]) { - glXSwapBuffers(view->impl->display, view->impl->win); - } + if (expose && view->hints[PUGL_DOUBLE_BUFFER]) { + glXSwapBuffers(view->impl->display, view->impl->win); + } - glXMakeCurrent(view->impl->display, None, NULL); + glXMakeCurrent(view->impl->display, None, NULL); - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static PuglStatus puglX11GlCreate(PuglView* view) { - PuglInternals* const impl = view->impl; - PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface; - Display* const display = impl->display; - GLXFBConfig fb_config = surface->fb_config; - - const int ctx_attrs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MAJOR], - GLX_CONTEXT_MINOR_VERSION_ARB, view->hints[PUGL_CONTEXT_VERSION_MINOR], - GLX_CONTEXT_FLAGS_ARB, (view->hints[PUGL_USE_DEBUG_CONTEXT] - ? GLX_CONTEXT_DEBUG_BIT_ARB - : 0), - GLX_CONTEXT_PROFILE_MASK_ARB, (view->hints[PUGL_USE_COMPAT_PROFILE] - ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB - : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), - 0}; - - PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = - (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( - (const uint8_t*)"glXCreateContextAttribsARB"); - - PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = - (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress( - (const uint8_t*)"glXSwapIntervalEXT"); - - surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs); - if (!surface->ctx) { - surface->ctx = - glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); - } - - if (!surface->ctx) { - return PUGL_CREATE_CONTEXT_FAILED; - } - - const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; - if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) { - puglX11GlEnter(view, NULL); - glXSwapIntervalEXT(display, impl->win, swapInterval); - puglX11GlLeave(view, NULL); - } - - glXGetConfig(impl->display, - impl->vi, - GLX_DOUBLEBUFFER, - &view->hints[PUGL_DOUBLE_BUFFER]); - - glXQueryDrawable(display, - impl->win, - GLX_SWAP_INTERVAL_EXT, - (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]); - - return PUGL_SUCCESS; + PuglInternals* const impl = view->impl; + PuglX11GlSurface* const surface = (PuglX11GlSurface*)impl->surface; + Display* const display = impl->display; + GLXFBConfig fb_config = surface->fb_config; + + const int ctx_attrs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + view->hints[PUGL_CONTEXT_VERSION_MAJOR], + + GLX_CONTEXT_MINOR_VERSION_ARB, + view->hints[PUGL_CONTEXT_VERSION_MINOR], + + GLX_CONTEXT_FLAGS_ARB, + (view->hints[PUGL_USE_DEBUG_CONTEXT] ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + + GLX_CONTEXT_PROFILE_MASK_ARB, + (view->hints[PUGL_USE_COMPAT_PROFILE] + ? GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB + : GLX_CONTEXT_CORE_PROFILE_BIT_ARB), + 0}; + + PFNGLXCREATECONTEXTATTRIBSARBPROC create_context = + (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress( + (const uint8_t*)"glXCreateContextAttribsARB"); + + PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = + (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( + (const uint8_t*)"glXSwapIntervalEXT"); + + surface->ctx = create_context(display, fb_config, 0, True, ctx_attrs); + if (!surface->ctx) { + surface->ctx = + glXCreateNewContext(display, fb_config, GLX_RGBA_TYPE, 0, True); + } + + if (!surface->ctx) { + return PUGL_CREATE_CONTEXT_FAILED; + } + + const int swapInterval = view->hints[PUGL_SWAP_INTERVAL]; + if (glXSwapIntervalEXT && swapInterval != PUGL_DONT_CARE) { + puglX11GlEnter(view, NULL); + glXSwapIntervalEXT(display, impl->win, swapInterval); + puglX11GlLeave(view, NULL); + } + + glXGetConfig(impl->display, + impl->vi, + GLX_DOUBLEBUFFER, + &view->hints[PUGL_DOUBLE_BUFFER]); + + glXQueryDrawable(display, + impl->win, + GLX_SWAP_INTERVAL_EXT, + (unsigned int*)&view->hints[PUGL_SWAP_INTERVAL]); + + return PUGL_SUCCESS; } static PuglStatus puglX11GlDestroy(PuglView* view) { - PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; - if (surface) { - glXDestroyContext(view->impl->display, surface->ctx); - free(surface); - view->impl->surface = NULL; - } - return PUGL_SUCCESS; + PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface; + if (surface) { + glXDestroyContext(view->impl->display, surface->ctx); + free(surface); + view->impl->surface = NULL; + } + return PUGL_SUCCESS; } PuglGlFunc puglGetProcAddress(const char* name) { - return glXGetProcAddress((const uint8_t*)name); + return glXGetProcAddress((const uint8_t*)name); } PuglStatus puglEnterContext(PuglView* view) { - return view->backend->enter(view, NULL); + return view->backend->enter(view, NULL); } PuglStatus puglLeaveContext(PuglView* view) { - return view->backend->leave(view, NULL); + return view->backend->leave(view, NULL); } const PuglBackend* puglGlBackend(void) { - static const PuglBackend backend = {puglX11GlConfigure, - puglX11GlCreate, - puglX11GlDestroy, - puglX11GlEnter, - puglX11GlLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglX11GlConfigure, + puglX11GlCreate, + puglX11GlDestroy, + puglX11GlEnter, + puglX11GlLeave, + puglStubGetContext}; + + return &backend; } diff --git a/src/x11_stub.c b/src/x11_stub.c index be66a88..de89a86 100644 --- a/src/x11_stub.c +++ b/src/x11_stub.c @@ -27,32 +27,32 @@ PuglStatus puglX11StubConfigure(PuglView* view) { - PuglInternals* const impl = view->impl; - XVisualInfo pat = {0}; - int n = 0; + PuglInternals* const impl = view->impl; + XVisualInfo pat = {0}; + int n = 0; - pat.screen = impl->screen; - impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); + pat.screen = impl->screen; + impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); - view->hints[PUGL_RED_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_GREEN_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_BLUE_BITS] = impl->vi->bits_per_rgb; - view->hints[PUGL_ALPHA_BITS] = 0; + view->hints[PUGL_RED_BITS] = impl->vi->bits_per_rgb; + view->hints[PUGL_GREEN_BITS] = impl->vi->bits_per_rgb; + view->hints[PUGL_BLUE_BITS] = impl->vi->bits_per_rgb; + view->hints[PUGL_ALPHA_BITS] = 0; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } const PuglBackend* puglStubBackend(void) { - static const PuglBackend backend = { - puglX11StubConfigure, - puglStubCreate, - puglStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext, - }; - - return &backend; + static const PuglBackend backend = { + puglX11StubConfigure, + puglStubCreate, + puglStubDestroy, + puglStubEnter, + puglStubLeave, + puglStubGetContext, + }; + + return &backend; } diff --git a/src/x11_vulkan.c b/src/x11_vulkan.c index b32111c..77bdd59 100644 --- a/src/x11_vulkan.c +++ b/src/x11_vulkan.c @@ -31,78 +31,77 @@ #include <stdint.h> #include <stdlib.h> -struct PuglVulkanLoaderImpl -{ - void* libvulkan; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; +struct PuglVulkanLoaderImpl { + void* libvulkan; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; }; PuglVulkanLoader* puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world)) { - PuglVulkanLoader* loader = - (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); - if (!loader) { - return NULL; - } + PuglVulkanLoader* loader = + (PuglVulkanLoader*)calloc(1, sizeof(PuglVulkanLoader)); + if (!loader) { + return NULL; + } - if (!(loader->libvulkan = dlopen("libvulkan.so", RTLD_LAZY))) { - free(loader); - return NULL; - } + if (!(loader->libvulkan = dlopen("libvulkan.so", RTLD_LAZY))) { + free(loader); + return NULL; + } - loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( - loader->libvulkan, "vkGetInstanceProcAddr"); + loader->vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( + loader->libvulkan, "vkGetInstanceProcAddr"); - loader->vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( - loader->libvulkan, "vkGetDeviceProcAddr"); + loader->vkGetDeviceProcAddr = + (PFN_vkGetDeviceProcAddr)dlsym(loader->libvulkan, "vkGetDeviceProcAddr"); - return loader; + return loader; } void puglFreeVulkanLoader(PuglVulkanLoader* loader) { - if (loader) { - dlclose(loader->libvulkan); - free(loader); - } + if (loader) { + dlclose(loader->libvulkan); + free(loader); + } } PFN_vkGetInstanceProcAddr puglGetInstanceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetInstanceProcAddr; + return loader->vkGetInstanceProcAddr; } PFN_vkGetDeviceProcAddr puglGetDeviceProcAddrFunc(const PuglVulkanLoader* loader) { - return loader->vkGetDeviceProcAddr; + return loader->vkGetDeviceProcAddr; } const PuglBackend* puglVulkanBackend(void) { - static const PuglBackend backend = {puglX11StubConfigure, - puglStubCreate, - puglStubDestroy, - puglStubEnter, - puglStubLeave, - puglStubGetContext}; - - return &backend; + static const PuglBackend backend = {puglX11StubConfigure, + puglStubCreate, + puglStubDestroy, + puglStubEnter, + puglStubLeave, + puglStubGetContext}; + + return &backend; } const char* const* puglGetInstanceExtensions(uint32_t* const count) { - static const char* const extensions[] = {"VK_KHR_surface", - "VK_KHR_xlib_surface"}; + static const char* const extensions[] = {"VK_KHR_surface", + "VK_KHR_xlib_surface"}; - *count = 2; - return extensions; + *count = 2; + return extensions; } VkResult @@ -112,20 +111,20 @@ puglCreateSurface(PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr, const VkAllocationCallbacks* const allocator, VkSurfaceKHR* const surface) { - PuglInternals* const impl = view->impl; - PuglWorldInternals* world_impl = view->world->impl; - - PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = - (PFN_vkCreateXlibSurfaceKHR) - vkGetInstanceProcAddr(instance, "vkCreateXlibSurfaceKHR"); - - const VkXlibSurfaceCreateInfoKHR info = { - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - NULL, - 0, - world_impl->display, - impl->win, - }; - - return vkCreateXlibSurfaceKHR(instance, &info, allocator, surface); + PuglInternals* const impl = view->impl; + PuglWorldInternals* world_impl = view->world->impl; + + PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR = + (PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr(instance, + "vkCreateXlibSurfaceKHR"); + + const VkXlibSurfaceCreateInfoKHR info = { + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + NULL, + 0, + world_impl->display, + impl->win, + }; + + return vkCreateXlibSurfaceKHR(instance, &info, allocator, surface); } diff --git a/test/test_build.c b/test/test_build.c index 5259c7c..957e0bd 100644 --- a/test/test_build.c +++ b/test/test_build.c @@ -28,5 +28,5 @@ int main(void) { - return 0; + return 0; } diff --git a/test/test_build.cpp b/test/test_build.cpp index 5beb4c3..20235e8 100644 --- a/test/test_build.cpp +++ b/test/test_build.cpp @@ -29,5 +29,5 @@ int main() { - return 0; + return 0; } diff --git a/test/test_clipboard.c b/test/test_clipboard.c index c1180b0..5749b65 100644 --- a/test/test_clipboard.c +++ b/test/test_clipboard.c @@ -30,75 +30,75 @@ #include <stddef.h> typedef struct { - PuglWorld* world; - PuglView* views[2]; - PuglTestOptions opts; - bool exposed; + PuglWorld* world; + PuglView* views[2]; + PuglTestOptions opts; + bool exposed; } PuglTest; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); + PuglTest* test = (PuglTest*)puglGetHandle(view); - if (event->type == PUGL_EXPOSE) { - test->exposed = true; - } + if (event->type == PUGL_EXPOSE) { + test->exposed = true; + } - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - {NULL, NULL}, - puglParseTestOptions(&argc, &argv), - false}; - - puglSetClassName(test.world, "Pugl Test"); - - // Set up views - for (unsigned i = 0u; i < 2; ++i) { - test.views[i] = puglNewView(test.world); - puglSetBackend(test.views[i], puglStubBackend()); - puglSetHandle(test.views[i], &test); - puglSetEventFunc(test.views[i], onEvent); - puglSetDefaultSize(test.views[i], 512, 512); - - assert(!puglShow(test.views[i])); - } - - // Update until view is exposed - while (!test.exposed) { - assert(!puglUpdate(test.world, 0.0)); - } - - // Set clipboard text via the first view - puglSetClipboard(test.views[0], NULL, "Text", 5); - - // Get clipboard contents via the second view - const char* type = NULL; - size_t len = 0; - const void* const contents = puglGetClipboard(test.views[1], &type, &len); - - // Check that the data made it over - assert(!strcmp(type, "text/plain")); - assert(len == 5); - assert(contents); - assert(!strcmp((const char*)contents, "Text")); - - // Try setting the clipboard to an unsupported type - assert(puglSetClipboard(test.views[0], "text/csv", "a,b,c", 6)); - - // Tear down - puglFreeView(test.views[0]); - puglFreeView(test.views[1]); - puglFreeWorld(test.world); - - return 0; + PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), + {NULL, NULL}, + puglParseTestOptions(&argc, &argv), + false}; + + puglSetClassName(test.world, "Pugl Test"); + + // Set up views + for (unsigned i = 0u; i < 2; ++i) { + test.views[i] = puglNewView(test.world); + puglSetBackend(test.views[i], puglStubBackend()); + puglSetHandle(test.views[i], &test); + puglSetEventFunc(test.views[i], onEvent); + puglSetDefaultSize(test.views[i], 512, 512); + + assert(!puglShow(test.views[i])); + } + + // Update until view is exposed + while (!test.exposed) { + assert(!puglUpdate(test.world, 0.0)); + } + + // Set clipboard text via the first view + puglSetClipboard(test.views[0], NULL, "Text", 5); + + // Get clipboard contents via the second view + const char* type = NULL; + size_t len = 0; + const void* const contents = puglGetClipboard(test.views[1], &type, &len); + + // Check that the data made it over + assert(!strcmp(type, "text/plain")); + assert(len == 5); + assert(contents); + assert(!strcmp((const char*)contents, "Text")); + + // Try setting the clipboard to an unsupported type + assert(puglSetClipboard(test.views[0], "text/csv", "a,b,c", 6)); + + // Tear down + puglFreeView(test.views[0]); + puglFreeView(test.views[1]); + puglFreeWorld(test.world); + + return 0; } diff --git a/test/test_gl_hints.c b/test/test_gl_hints.c index c30d0ed..3be3651 100644 --- a/test/test_gl_hints.c +++ b/test/test_gl_hints.c @@ -30,60 +30,60 @@ static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - (void)view; - (void)event; + (void)view; + (void)event; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } int main(void) { - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetBackend(view, puglGlBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Set all hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DEPTH_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_STENCIL_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_SAMPLES, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_DOUBLE_BUFFER, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DEPTH_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_STENCIL_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SAMPLES) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_DOUBLE_BUFFER) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_SWAP_INTERVAL) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; + PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); + PuglView* const view = puglNewView(world); + + // Set up view + puglSetClassName(world, "Pugl Test"); + puglSetBackend(view, puglGlBackend()); + puglSetEventFunc(view, onEvent); + puglSetDefaultSize(view, 512, 512); + + // Set all hints that support it to PUGL_DONT_CARE + assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_DEPTH_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_STENCIL_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_SAMPLES, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_DOUBLE_BUFFER, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); + + // Realize view and print all hints for debugging convenience + assert(!puglRealize(view)); + printViewHints(view); + + // Check that no hints are set to PUGL_DONT_CARE + assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_DEPTH_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_STENCIL_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_SAMPLES) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_DOUBLE_BUFFER) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_SWAP_INTERVAL) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); + + // Tear down + puglFreeView(view); + puglFreeWorld(world); + + return 0; } diff --git a/test/test_realize.c b/test/test_realize.c index bb0b327..3c4e09a 100644 --- a/test/test_realize.c +++ b/test/test_realize.c @@ -34,67 +34,67 @@ #include <stddef.h> typedef enum { - START, - CREATED, + START, + CREATED, } State; typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + State state; } PuglTest; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglTest* test = (PuglTest*)puglGetHandle(view); + + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } + + switch (event->type) { + case PUGL_CREATE: + assert(test->state == START); + test->state = CREATED; + break; + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - assert(!puglUpdate(test.world, -1.0)); - } - - // Check that calling realize() again is okay - assert(puglRealize(test.view) == PUGL_FAILURE); - - // Tear down - puglFreeView(test.view); - puglFreeWorld(test.world); - - return 0; + PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), + NULL, + puglParseTestOptions(&argc, &argv), + START}; + + // Set up view + test.view = puglNewView(test.world); + puglSetClassName(test.world, "Pugl Test"); + puglSetBackend(test.view, puglStubBackend()); + puglSetHandle(test.view, &test); + puglSetEventFunc(test.view, onEvent); + puglSetDefaultSize(test.view, 512, 512); + + // Create initially invisible window + assert(!puglRealize(test.view)); + assert(!puglGetVisible(test.view)); + while (test.state < CREATED) { + assert(!puglUpdate(test.world, -1.0)); + } + + // Check that calling realize() again is okay + assert(puglRealize(test.view) == PUGL_FAILURE); + + // Tear down + puglFreeView(test.view); + puglFreeWorld(test.world); + + return 0; } diff --git a/test/test_redisplay.c b/test/test_redisplay.c index 1d5b084..c5b9887 100644 --- a/test/test_redisplay.c +++ b/test/test_redisplay.c @@ -38,19 +38,18 @@ static const double timeout = -1.0; #endif typedef enum { - START, - EXPOSED, - SHOULD_REDISPLAY, - POSTED_REDISPLAY, - REDISPLAYED, + START, + EXPOSED, + SHOULD_REDISPLAY, + POSTED_REDISPLAY, + REDISPLAYED, } State; -typedef struct -{ - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; +typedef struct { + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + State state; } PuglTest; static const PuglRect redisplayRect = {2, 4, 8, 16}; @@ -59,83 +58,84 @@ static const uintptr_t postRedisplayId = 42; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_UPDATE: - if (test->state == SHOULD_REDISPLAY) { - puglPostRedisplayRect(view, redisplayRect); - test->state = POSTED_REDISPLAY; - } - break; - - case PUGL_EXPOSE: - if (test->state == START) { - test->state = EXPOSED; - } else if (test->state == POSTED_REDISPLAY && - event->expose.x == redisplayRect.x && - event->expose.y == redisplayRect.y && - event->expose.width == redisplayRect.width && - event->expose.height == redisplayRect.height) { - test->state = REDISPLAYED; - } - break; - - case PUGL_CLIENT: - if (event->client.data1 == postRedisplayId) { - test->state = SHOULD_REDISPLAY; - } - break; - - default: break; - } - - return PUGL_SUCCESS; + PuglTest* test = (PuglTest*)puglGetHandle(view); + + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } + + switch (event->type) { + case PUGL_UPDATE: + if (test->state == SHOULD_REDISPLAY) { + puglPostRedisplayRect(view, redisplayRect); + test->state = POSTED_REDISPLAY; + } + break; + + case PUGL_EXPOSE: + if (test->state == START) { + test->state = EXPOSED; + } else if (test->state == POSTED_REDISPLAY && + event->expose.x == redisplayRect.x && + event->expose.y == redisplayRect.y && + event->expose.width == redisplayRect.width && + event->expose.height == redisplayRect.height) { + test->state = REDISPLAYED; + } + break; + + case PUGL_CLIENT: + if (event->client.data1 == postRedisplayId) { + test->state = SHOULD_REDISPLAY; + } + break; + + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - while (app.state != EXPOSED) { - assert(!puglUpdate(app.world, timeout)); - } - - // Send a custom event to trigger a redisplay in the event loop - PuglEvent client_event = {{PUGL_CLIENT, 0}}; - client_event.client.data1 = postRedisplayId; - client_event.client.data2 = 0; - assert(!puglSendEvent(app.view, &client_event)); - - // Loop until an expose happens in the same iteration as the redisplay - app.state = SHOULD_REDISPLAY; - while (app.state != REDISPLAYED) { - assert(!puglUpdate(app.world, timeout)); - assert(app.state != POSTED_REDISPLAY); - } - - // Tear down - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; + PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), + NULL, + puglParseTestOptions(&argc, &argv), + START}; + + // Set up view + app.view = puglNewView(app.world); + puglSetClassName(app.world, "Pugl Test"); + puglSetBackend(app.view, puglStubBackend()); + puglSetHandle(app.view, &app); + puglSetEventFunc(app.view, onEvent); + puglSetDefaultSize(app.view, 512, 512); + + // Create and show window + assert(!puglRealize(app.view)); + assert(!puglShow(app.view)); + while (app.state != EXPOSED) { + assert(!puglUpdate(app.world, timeout)); + } + + // Send a custom event to trigger a redisplay in the event loop + PuglEvent client_event = {{PUGL_CLIENT, 0}}; + client_event.client.data1 = postRedisplayId; + client_event.client.data2 = 0; + assert(!puglSendEvent(app.view, &client_event)); + + // Loop until an expose happens in the same iteration as the redisplay + app.state = SHOULD_REDISPLAY; + while (app.state != REDISPLAYED) { + assert(!puglUpdate(app.world, timeout)); + assert(app.state != POSTED_REDISPLAY); + } + + // Tear down + puglFreeView(app.view); + puglFreeWorld(app.world); + + return 0; } diff --git a/test/test_show_hide.c b/test/test_show_hide.c index 4280408..584448c 100644 --- a/test/test_show_hide.c +++ b/test/test_show_hide.c @@ -31,118 +31,118 @@ #include <stddef.h> typedef enum { - START, - CREATED, - CONFIGURED, - MAPPED, - EXPOSED, - UNMAPPED, - DESTROYED, + START, + CREATED, + CONFIGURED, + MAPPED, + EXPOSED, + UNMAPPED, + DESTROYED, } State; typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + State state; } PuglTest; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_CREATE: - assert(test->state == START); - test->state = CREATED; - break; - case PUGL_CONFIGURE: - if (test->state == CREATED) { - test->state = CONFIGURED; - } - break; - case PUGL_MAP: - assert(test->state == CONFIGURED || test->state == UNMAPPED); - test->state = MAPPED; - break; - case PUGL_EXPOSE: - assert(test->state == MAPPED || test->state == EXPOSED); - test->state = EXPOSED; - break; - case PUGL_UNMAP: - assert(test->state == EXPOSED); - test->state = UNMAPPED; - break; - case PUGL_DESTROY: - assert(test->state == UNMAPPED); - test->state = DESTROYED; - break; - default: - break; - } - - return PUGL_SUCCESS; + PuglTest* test = (PuglTest*)puglGetHandle(view); + + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } + + switch (event->type) { + case PUGL_CREATE: + assert(test->state == START); + test->state = CREATED; + break; + case PUGL_CONFIGURE: + if (test->state == CREATED) { + test->state = CONFIGURED; + } + break; + case PUGL_MAP: + assert(test->state == CONFIGURED || test->state == UNMAPPED); + test->state = MAPPED; + break; + case PUGL_EXPOSE: + assert(test->state == MAPPED || test->state == EXPOSED); + test->state = EXPOSED; + break; + case PUGL_UNMAP: + assert(test->state == EXPOSED); + test->state = UNMAPPED; + break; + case PUGL_DESTROY: + assert(test->state == UNMAPPED); + test->state = DESTROYED; + break; + default: + break; + } + + return PUGL_SUCCESS; } static void tick(PuglWorld* world) { #ifdef __APPLE__ - // FIXME: Expose events are not events on MacOS, so we can't block - // indefinitely here since it will block forever - assert(!puglUpdate(world, 1 / 30.0)); + // FIXME: Expose events are not events on MacOS, so we can't block + // indefinitely here since it will block forever + assert(!puglUpdate(world, 1 / 30.0)); #else - assert(!puglUpdate(world, -1)); + assert(!puglUpdate(world, -1)); #endif } int main(int argc, char** argv) { - PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - test.view = puglNewView(test.world); - puglSetClassName(test.world, "Pugl Test"); - puglSetBackend(test.view, puglStubBackend()); - puglSetHandle(test.view, &test); - puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); - - // Create initially invisible window - assert(!puglRealize(test.view)); - assert(!puglGetVisible(test.view)); - while (test.state < CREATED) { - tick(test.world); - } - - // Show and hide window a couple of times - for (unsigned i = 0u; i < 2u; ++i) { - assert(!puglShow(test.view)); - while (test.state != EXPOSED) { - tick(test.world); - } - - assert(puglGetVisible(test.view)); - assert(!puglHide(test.view)); - while (test.state != UNMAPPED) { - tick(test.world); - } - } - - // Tear down - assert(!puglGetVisible(test.view)); - puglFreeView(test.view); - assert(test.state == DESTROYED); - puglFreeWorld(test.world); - - return 0; + PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), + NULL, + puglParseTestOptions(&argc, &argv), + START}; + + // Set up view + test.view = puglNewView(test.world); + puglSetClassName(test.world, "Pugl Test"); + puglSetBackend(test.view, puglStubBackend()); + puglSetHandle(test.view, &test); + puglSetEventFunc(test.view, onEvent); + puglSetDefaultSize(test.view, 512, 512); + + // Create initially invisible window + assert(!puglRealize(test.view)); + assert(!puglGetVisible(test.view)); + while (test.state < CREATED) { + tick(test.world); + } + + // Show and hide window a couple of times + for (unsigned i = 0u; i < 2u; ++i) { + assert(!puglShow(test.view)); + while (test.state != EXPOSED) { + tick(test.world); + } + + assert(puglGetVisible(test.view)); + assert(!puglHide(test.view)); + while (test.state != UNMAPPED) { + tick(test.world); + } + } + + // Tear down + assert(!puglGetVisible(test.view)); + puglFreeView(test.view); + assert(test.state == DESTROYED); + puglFreeWorld(test.world); + + return 0; } diff --git a/test/test_stub_hints.c b/test/test_stub_hints.c index 2bfc86c..1cc1180 100644 --- a/test/test_stub_hints.c +++ b/test/test_stub_hints.c @@ -30,51 +30,51 @@ static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - (void)view; - (void)event; + (void)view; + (void)event; - return PUGL_SUCCESS; + return PUGL_SUCCESS; } int main(void) { - PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); - PuglView* const view = puglNewView(world); - - // Set up view - puglSetClassName(world, "Pugl Test"); - puglSetBackend(view, puglStubBackend()); - puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); - - // Set all relevant hints that support it to PUGL_DONT_CARE - assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); - assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); - - // Realize view and print all hints for debugging convenience - assert(!puglRealize(view)); - printViewHints(view); - - // Check that no relevant hints are set to PUGL_DONT_CARE - assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); - assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); - - // Tear down - puglFreeView(view); - puglFreeWorld(world); - - return 0; + PuglWorld* const world = puglNewWorld(PUGL_PROGRAM, 0); + PuglView* const view = puglNewView(world); + + // Set up view + puglSetClassName(world, "Pugl Test"); + puglSetBackend(view, puglStubBackend()); + puglSetEventFunc(view, onEvent); + puglSetDefaultSize(view, 512, 512); + + // Set all relevant hints that support it to PUGL_DONT_CARE + assert(!puglSetViewHint(view, PUGL_RED_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_GREEN_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_BLUE_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_ALPHA_BITS, PUGL_DONT_CARE)); + assert(!puglSetViewHint(view, PUGL_REFRESH_RATE, PUGL_DONT_CARE)); + + // Realize view and print all hints for debugging convenience + assert(!puglRealize(view)); + printViewHints(view); + + // Check that no relevant hints are set to PUGL_DONT_CARE + assert(puglGetViewHint(view, PUGL_USE_COMPAT_PROFILE) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_USE_DEBUG_CONTEXT) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_CONTEXT_VERSION_MINOR) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_RED_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_GREEN_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_BLUE_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_ALPHA_BITS) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_RESIZABLE) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_IGNORE_KEY_REPEAT) != PUGL_DONT_CARE); + assert(puglGetViewHint(view, PUGL_REFRESH_RATE) != PUGL_DONT_CARE); + + // Tear down + puglFreeView(view); + puglFreeWorld(world); + + return 0; } diff --git a/test/test_timer.c b/test/test_timer.c index 0b77396..18518ec 100644 --- a/test/test_timer.c +++ b/test/test_timer.c @@ -50,112 +50,110 @@ static const uintptr_t timerId = 1u; static const double timerPeriod = 1 / 60.0; typedef enum { - START, - EXPOSED, + START, + EXPOSED, } State; typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - size_t numAlarms; - State state; + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + size_t numAlarms; + State state; } PuglTest; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); + PuglTest* test = (PuglTest*)puglGetHandle(view); - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } - switch (event->type) { - case PUGL_EXPOSE: - test->state = EXPOSED; - break; + switch (event->type) { + case PUGL_EXPOSE: + test->state = EXPOSED; + break; - case PUGL_TIMER: - assert(event->timer.id == timerId); - ++test->numAlarms; - break; + case PUGL_TIMER: + assert(event->timer.id == timerId); + ++test->numAlarms; + break; - default: - break; - } + default: + break; + } - return PUGL_SUCCESS; + return PUGL_SUCCESS; } static double roundPeriod(const double period) { - return floor(period * 1000.0) / 1000.0; // Round down to milliseconds + return floor(period * 1000.0) / 1000.0; // Round down to milliseconds } int main(int argc, char** argv) { - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - 0, - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - while (app.state != EXPOSED) { - assert(!puglUpdate(app.world, timeout)); - } - - // Register a timer with a longer period first - assert(!puglStartTimer(app.view, timerId, timerPeriod * 2.0)); - - // Replace it with the one we want (to ensure timers are replaced) - assert(!puglStartTimer(app.view, timerId, timerPeriod)); - - const double startTime = puglGetTime(app.world); - - puglUpdate(app.world, 1.0); - - // Calculate the actual period of the timer - const double endTime = puglGetTime(app.world); - const double duration = endTime - startTime; - const double expectedPeriod = roundPeriod(timerPeriod); - const double actualPeriod = roundPeriod(duration / (double)app.numAlarms); - const double difference = fabs(actualPeriod - expectedPeriod); - - if (difference > tolerance) { - fprintf(stderr, - "error: Period not within %f of %f\n", - tolerance, - expectedPeriod); - fprintf(stderr, "note: Actual period %f\n", actualPeriod); - } - - assert(difference <= tolerance); - - // Deregister timer and tick once to synchronize - assert(!puglStopTimer(app.view, timerId)); - puglUpdate(app.world, 0.0); - - // Update for a half second and check that we receive no more alarms - app.numAlarms = 0; - puglUpdate(app.world, 0.5); - assert(app.numAlarms == 0); - - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; + PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), + NULL, + puglParseTestOptions(&argc, &argv), + 0, + START}; + + // Set up view + app.view = puglNewView(app.world); + puglSetClassName(app.world, "Pugl Test"); + puglSetBackend(app.view, puglStubBackend()); + puglSetHandle(app.view, &app); + puglSetEventFunc(app.view, onEvent); + puglSetDefaultSize(app.view, 512, 512); + + // Create and show window + assert(!puglRealize(app.view)); + assert(!puglShow(app.view)); + while (app.state != EXPOSED) { + assert(!puglUpdate(app.world, timeout)); + } + + // Register a timer with a longer period first + assert(!puglStartTimer(app.view, timerId, timerPeriod * 2.0)); + + // Replace it with the one we want (to ensure timers are replaced) + assert(!puglStartTimer(app.view, timerId, timerPeriod)); + + const double startTime = puglGetTime(app.world); + + puglUpdate(app.world, 1.0); + + // Calculate the actual period of the timer + const double endTime = puglGetTime(app.world); + const double duration = endTime - startTime; + const double expectedPeriod = roundPeriod(timerPeriod); + const double actualPeriod = roundPeriod(duration / (double)app.numAlarms); + const double difference = fabs(actualPeriod - expectedPeriod); + + if (difference > tolerance) { + fprintf( + stderr, "error: Period not within %f of %f\n", tolerance, expectedPeriod); + fprintf(stderr, "note: Actual period %f\n", actualPeriod); + } + + assert(difference <= tolerance); + + // Deregister timer and tick once to synchronize + assert(!puglStopTimer(app.view, timerId)); + puglUpdate(app.world, 0.0); + + // Update for a half second and check that we receive no more alarms + app.numAlarms = 0; + puglUpdate(app.world, 0.5); + assert(app.numAlarms == 0); + + puglFreeView(app.view); + puglFreeWorld(app.world); + + return 0; } diff --git a/test/test_update.c b/test/test_update.c index b35e96e..89de0b6 100644 --- a/test/test_update.c +++ b/test/test_update.c @@ -37,89 +37,89 @@ static const double timeout = -1.0; #endif typedef enum { - START, - EXPOSED1, - UPDATED, - EXPOSED2, + START, + EXPOSED1, + UPDATED, + EXPOSED2, } State; typedef struct { - PuglWorld* world; - PuglView* view; - PuglTestOptions opts; - State state; + PuglWorld* world; + PuglView* view; + PuglTestOptions opts; + State state; } PuglTest; static PuglStatus onEvent(PuglView* view, const PuglEvent* event) { - PuglTest* test = (PuglTest*)puglGetHandle(view); - - if (test->opts.verbose) { - printEvent(event, "Event: ", true); - } - - switch (event->type) { - case PUGL_EXPOSE: - switch (test->state) { - case START: - test->state = EXPOSED1; - break; - case UPDATED: - test->state = EXPOSED2; - break; - default: - break; - } - break; - - case PUGL_UPDATE: - if (test->state == EXPOSED1) { - puglPostRedisplay(view); - test->state = UPDATED; - } - break; - - default: - break; - } - - return PUGL_SUCCESS; + PuglTest* test = (PuglTest*)puglGetHandle(view); + + if (test->opts.verbose) { + printEvent(event, "Event: ", true); + } + + switch (event->type) { + case PUGL_EXPOSE: + switch (test->state) { + case START: + test->state = EXPOSED1; + break; + case UPDATED: + test->state = EXPOSED2; + break; + default: + break; + } + break; + + case PUGL_UPDATE: + if (test->state == EXPOSED1) { + puglPostRedisplay(view); + test->state = UPDATED; + } + break; + + default: + break; + } + + return PUGL_SUCCESS; } int main(int argc, char** argv) { - PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), - NULL, - puglParseTestOptions(&argc, &argv), - START}; - - // Set up view - app.view = puglNewView(app.world); - puglSetClassName(app.world, "Pugl Test"); - puglSetBackend(app.view, puglStubBackend()); - puglSetHandle(app.view, &app); - puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); - - // Create and show window - assert(!puglRealize(app.view)); - assert(!puglShow(app.view)); - - // Tick until an expose happens - while (app.state < EXPOSED1) { - assert(!puglUpdate(app.world, timeout)); - assert(app.state != UPDATED); - } - - // Tick once and ensure the update and the expose it posted both happened - assert(!puglUpdate(app.world, 0.0)); - assert(app.state == EXPOSED2); - - // Tear down - puglFreeView(app.view); - puglFreeWorld(app.world); - - return 0; + PuglTest app = {puglNewWorld(PUGL_PROGRAM, 0), + NULL, + puglParseTestOptions(&argc, &argv), + START}; + + // Set up view + app.view = puglNewView(app.world); + puglSetClassName(app.world, "Pugl Test"); + puglSetBackend(app.view, puglStubBackend()); + puglSetHandle(app.view, &app); + puglSetEventFunc(app.view, onEvent); + puglSetDefaultSize(app.view, 512, 512); + + // Create and show window + assert(!puglRealize(app.view)); + assert(!puglShow(app.view)); + + // Tick until an expose happens + while (app.state < EXPOSED1) { + assert(!puglUpdate(app.world, timeout)); + assert(app.state != UPDATED); + } + + // Tick once and ensure the update and the expose it posted both happened + assert(!puglUpdate(app.world, 0.0)); + assert(app.state == EXPOSED2); + + // Tear down + puglFreeView(app.view); + puglFreeWorld(app.world); + + return 0; } diff --git a/test/test_utils.h b/test/test_utils.h index 7a91535..2464737 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -29,328 +29,328 @@ #include <string.h> #ifdef __GNUC__ -# define PUGL_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) +# define PUGL_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #else -# define PUGL_LOG_FUNC(fmt, arg1) +# define PUGL_LOG_FUNC(fmt, arg1) #endif typedef struct { - int samples; - int doubleBuffer; - int sync; - bool continuous; - bool help; - bool ignoreKeyRepeat; - bool resizable; - bool verbose; - bool errorChecking; + int samples; + int doubleBuffer; + int sync; + bool continuous; + bool help; + bool ignoreKeyRepeat; + bool resizable; + bool verbose; + bool errorChecking; } PuglTestOptions; PUGL_LOG_FUNC(1, 2) static int logError(const char* fmt, ...) { - fprintf(stderr, "error: "); + fprintf(stderr, "error: "); - va_list args; // NOLINT - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); + va_list args; // NOLINT + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); - return 1; + return 1; } static inline int printModifiers(const uint32_t mods) { - return fprintf(stderr, "Modifiers:%s%s%s%s\n", - (mods & PUGL_MOD_SHIFT) ? " Shift" : "", - (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", - (mods & PUGL_MOD_ALT) ? " Alt" : "", - (mods & PUGL_MOD_SUPER) ? " Super" : ""); + return fprintf(stderr, + "Modifiers:%s%s%s%s\n", + (mods & PUGL_MOD_SHIFT) ? " Shift" : "", + (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", + (mods & PUGL_MOD_ALT) ? " Alt" : "", + (mods & PUGL_MOD_SUPER) ? " Super" : ""); } static inline const char* crossingModeString(const PuglCrossingMode mode) { - switch (mode) { - case PUGL_CROSSING_NORMAL: - return "normal"; - case PUGL_CROSSING_GRAB: - return "grab"; - case PUGL_CROSSING_UNGRAB: - return "ungrab"; - } + switch (mode) { + case PUGL_CROSSING_NORMAL: + return "normal"; + case PUGL_CROSSING_GRAB: + return "grab"; + case PUGL_CROSSING_UNGRAB: + return "ungrab"; + } - return "unknown"; + return "unknown"; } static inline const char* scrollDirectionString(const PuglScrollDirection direction) { - switch (direction) { - case PUGL_SCROLL_UP: - return "up"; - case PUGL_SCROLL_DOWN: - return "down"; - case PUGL_SCROLL_LEFT: - return "left"; - case PUGL_SCROLL_RIGHT: - return "right"; - case PUGL_SCROLL_SMOOTH: - return "smooth"; - } + switch (direction) { + case PUGL_SCROLL_UP: + return "up"; + case PUGL_SCROLL_DOWN: + return "down"; + case PUGL_SCROLL_LEFT: + return "left"; + case PUGL_SCROLL_RIGHT: + return "right"; + case PUGL_SCROLL_SMOOTH: + return "smooth"; + } - return "unknown"; + return "unknown"; } static inline int printEvent(const PuglEvent* event, const char* prefix, const bool verbose) { -#define FFMT "%6.1f" -#define PFMT FFMT " " FFMT +#define FFMT "%6.1f" +#define PFMT FFMT " " FFMT #define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) - switch (event->type) { - case PUGL_NOTHING: - return 0; - case PUGL_KEY_PRESS: - return PRINT("%sKey press code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_KEY_RELEASE: - return PRINT("%sKey release code %3u key U+%04X\n", - prefix, - event->key.keycode, - event->key.key); - case PUGL_TEXT: - return PRINT("%sText entry code %3u char U+%04X (%s)\n", - prefix, - event->text.keycode, - event->text.character, - event->text.string); - case PUGL_BUTTON_PRESS: - case PUGL_BUTTON_RELEASE: - return (PRINT("%sMouse %u %s at " PFMT " ", - prefix, - event->button.button, - (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ", - event->button.x, - event->button.y) + - printModifiers(event->scroll.state)); - case PUGL_SCROLL: - return (PRINT("%sScroll %5.1f %5.1f (%s) at " PFMT " ", - prefix, - event->scroll.dx, - event->scroll.dy, - scrollDirectionString(event->scroll.direction), - event->scroll.x, - event->scroll.y) + - printModifiers(event->scroll.state)); - case PUGL_POINTER_IN: - return PRINT("%sMouse enter at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_POINTER_OUT: - return PRINT("%sMouse leave at " PFMT " (%s)\n", - prefix, - event->crossing.x, - event->crossing.y, - crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_IN: - return PRINT("%sFocus in (%s)\n", - prefix, - crossingModeString(event->crossing.mode)); - case PUGL_FOCUS_OUT: - return PRINT("%sFocus out (%s)\n", - prefix, - crossingModeString(event->crossing.mode)); - case PUGL_CLIENT: - return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", - prefix, - event->client.data1, - event->client.data2); - case PUGL_LOOP_ENTER: - return PRINT("%sLoop enter\n", prefix); - case PUGL_LOOP_LEAVE: - return PRINT("%sLoop leave\n", prefix); - default: - break; - } + switch (event->type) { + case PUGL_NOTHING: + return 0; + case PUGL_KEY_PRESS: + return PRINT("%sKey press code %3u key U+%04X\n", + prefix, + event->key.keycode, + event->key.key); + case PUGL_KEY_RELEASE: + return PRINT("%sKey release code %3u key U+%04X\n", + prefix, + event->key.keycode, + event->key.key); + case PUGL_TEXT: + return PRINT("%sText entry code %3u char U+%04X (%s)\n", + prefix, + event->text.keycode, + event->text.character, + event->text.string); + case PUGL_BUTTON_PRESS: + case PUGL_BUTTON_RELEASE: + return (PRINT("%sMouse %u %s at " PFMT " ", + prefix, + event->button.button, + (event->type == PUGL_BUTTON_PRESS) ? "down" : "up ", + event->button.x, + event->button.y) + + printModifiers(event->scroll.state)); + case PUGL_SCROLL: + return (PRINT("%sScroll %5.1f %5.1f (%s) at " PFMT " ", + prefix, + event->scroll.dx, + event->scroll.dy, + scrollDirectionString(event->scroll.direction), + event->scroll.x, + event->scroll.y) + + printModifiers(event->scroll.state)); + case PUGL_POINTER_IN: + return PRINT("%sMouse enter at " PFMT " (%s)\n", + prefix, + event->crossing.x, + event->crossing.y, + crossingModeString(event->crossing.mode)); + case PUGL_POINTER_OUT: + return PRINT("%sMouse leave at " PFMT " (%s)\n", + prefix, + event->crossing.x, + event->crossing.y, + crossingModeString(event->crossing.mode)); + case PUGL_FOCUS_IN: + return PRINT( + "%sFocus in (%s)\n", prefix, crossingModeString(event->crossing.mode)); + case PUGL_FOCUS_OUT: + return PRINT( + "%sFocus out (%s)\n", prefix, crossingModeString(event->crossing.mode)); + case PUGL_CLIENT: + return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", + prefix, + event->client.data1, + event->client.data2); + case PUGL_LOOP_ENTER: + return PRINT("%sLoop enter\n", prefix); + case PUGL_LOOP_LEAVE: + return PRINT("%sLoop leave\n", prefix); + default: + break; + } - if (verbose) { - switch (event->type) { - case PUGL_CREATE: - return fprintf(stderr, "%sCreate\n", prefix); - case PUGL_DESTROY: - return fprintf(stderr, "%sDestroy\n", prefix); - case PUGL_MAP: - return fprintf(stderr, "%sMap\n", prefix); - case PUGL_UNMAP: - return fprintf(stderr, "%sUnmap\n", prefix); - case PUGL_UPDATE: - return fprintf(stderr, "%sUpdate\n", prefix); - case PUGL_CONFIGURE: - return PRINT("%sConfigure " PFMT " " PFMT "\n", - prefix, - event->configure.x, - event->configure.y, - event->configure.width, - event->configure.height); - case PUGL_EXPOSE: - return PRINT("%sExpose " PFMT " " PFMT "\n", - prefix, - event->expose.x, - event->expose.y, - event->expose.width, - event->expose.height); - case PUGL_CLOSE: - return PRINT("%sClose\n", prefix); - case PUGL_MOTION: - return PRINT("%sMouse motion at " PFMT "\n", - prefix, - event->motion.x, - event->motion.y); - case PUGL_TIMER: - return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id); - default: - return PRINT("%sUnknown event type %d\n", prefix, (int)event->type); - } - } + if (verbose) { + switch (event->type) { + case PUGL_CREATE: + return fprintf(stderr, "%sCreate\n", prefix); + case PUGL_DESTROY: + return fprintf(stderr, "%sDestroy\n", prefix); + case PUGL_MAP: + return fprintf(stderr, "%sMap\n", prefix); + case PUGL_UNMAP: + return fprintf(stderr, "%sUnmap\n", prefix); + case PUGL_UPDATE: + return fprintf(stderr, "%sUpdate\n", prefix); + case PUGL_CONFIGURE: + return PRINT("%sConfigure " PFMT " " PFMT "\n", + prefix, + event->configure.x, + event->configure.y, + event->configure.width, + event->configure.height); + case PUGL_EXPOSE: + return PRINT("%sExpose " PFMT " " PFMT "\n", + prefix, + event->expose.x, + event->expose.y, + event->expose.width, + event->expose.height); + case PUGL_CLOSE: + return PRINT("%sClose\n", prefix); + case PUGL_MOTION: + return PRINT("%sMouse motion at " PFMT "\n", + prefix, + event->motion.x, + event->motion.y); + case PUGL_TIMER: + return PRINT("%sTimer %" PRIuPTR "\n", prefix, event->timer.id); + default: + return PRINT("%sUnknown event type %d\n", prefix, (int)event->type); + } + } #undef PRINT #undef PFMT #undef FFMT - return 0; + return 0; } static inline const char* puglViewHintString(const PuglViewHint hint) { - switch (hint) { - case PUGL_USE_COMPAT_PROFILE: - return "Use compatible profile"; - case PUGL_USE_DEBUG_CONTEXT: - return "Use debug context"; - case PUGL_CONTEXT_VERSION_MAJOR: - return "Context major version"; - case PUGL_CONTEXT_VERSION_MINOR: - return "Context minor version"; - case PUGL_RED_BITS: - return "Red bits"; - case PUGL_GREEN_BITS: - return "Green bits"; - case PUGL_BLUE_BITS: - return "Blue bits"; - case PUGL_ALPHA_BITS: - return "Alpha bits"; - case PUGL_DEPTH_BITS: - return "Depth bits"; - case PUGL_STENCIL_BITS: - return "Stencil bits"; - case PUGL_SAMPLES: - return "Samples"; - case PUGL_DOUBLE_BUFFER: - return "Double buffer"; - case PUGL_SWAP_INTERVAL: - return "Swap interval"; - case PUGL_RESIZABLE: - return "Resizable"; - case PUGL_IGNORE_KEY_REPEAT: - return "Ignore key repeat"; - case PUGL_REFRESH_RATE: - return "Refresh rate"; - case PUGL_NUM_VIEW_HINTS: - return "Unknown"; - } + switch (hint) { + case PUGL_USE_COMPAT_PROFILE: + return "Use compatible profile"; + case PUGL_USE_DEBUG_CONTEXT: + return "Use debug context"; + case PUGL_CONTEXT_VERSION_MAJOR: + return "Context major version"; + case PUGL_CONTEXT_VERSION_MINOR: + return "Context minor version"; + case PUGL_RED_BITS: + return "Red bits"; + case PUGL_GREEN_BITS: + return "Green bits"; + case PUGL_BLUE_BITS: + return "Blue bits"; + case PUGL_ALPHA_BITS: + return "Alpha bits"; + case PUGL_DEPTH_BITS: + return "Depth bits"; + case PUGL_STENCIL_BITS: + return "Stencil bits"; + case PUGL_SAMPLES: + return "Samples"; + case PUGL_DOUBLE_BUFFER: + return "Double buffer"; + case PUGL_SWAP_INTERVAL: + return "Swap interval"; + case PUGL_RESIZABLE: + return "Resizable"; + case PUGL_IGNORE_KEY_REPEAT: + return "Ignore key repeat"; + case PUGL_REFRESH_RATE: + return "Refresh rate"; + case PUGL_NUM_VIEW_HINTS: + return "Unknown"; + } - return "Unknown"; + return "Unknown"; } static inline void printViewHints(const PuglView* view) { - for (int i = 0; i < PUGL_NUM_VIEW_HINTS; ++i) { - const PuglViewHint hint = (PuglViewHint)i; - fprintf(stderr, - "%s: %d\n", - puglViewHintString(hint), - puglGetViewHint(view, hint)); - } + for (int i = 0; i < PUGL_NUM_VIEW_HINTS; ++i) { + const PuglViewHint hint = (PuglViewHint)i; + fprintf(stderr, + "%s: %d\n", + puglViewHintString(hint), + puglGetViewHint(view, hint)); + } } static inline void puglPrintTestUsage(const char* prog, const char* posHelp) { - printf("Usage: %s [OPTION]... %s\n\n" - " -a Enable anti-aliasing\n" - " -c Continuously animate and draw\n" - " -d Directly draw to window (no double-buffering)\n" - " -e Enable platform error-checking\n" - " -f Fast drawing, explicitly disable vertical sync\n" - " -h Display this help\n" - " -i Ignore key repeat\n" - " -v Print verbose output\n" - " -r Resizable window\n" - " -s Explicitly enable vertical sync\n", - prog, posHelp); + printf("Usage: %s [OPTION]... %s\n\n" + " -a Enable anti-aliasing\n" + " -c Continuously animate and draw\n" + " -d Directly draw to window (no double-buffering)\n" + " -e Enable platform error-checking\n" + " -f Fast drawing, explicitly disable vertical sync\n" + " -h Display this help\n" + " -i Ignore key repeat\n" + " -v Print verbose output\n" + " -r Resizable window\n" + " -s Explicitly enable vertical sync\n", + prog, + posHelp); } static inline PuglTestOptions puglParseTestOptions(int* pargc, char*** pargv) { - PuglTestOptions opts = { - 0, - PUGL_TRUE, - PUGL_DONT_CARE, - false, - false, - false, - false, - false, - false, - }; + PuglTestOptions opts = { + 0, + PUGL_TRUE, + PUGL_DONT_CARE, + false, + false, + false, + false, + false, + false, + }; - char** const argv = *pargv; - int i = 1; - for (; i < *pargc; ++i) { - if (!strcmp(argv[i], "-a")) { - opts.samples = 4; - } else if (!strcmp(argv[i], "-c")) { - opts.continuous = true; - } else if (!strcmp(argv[i], "-d")) { - opts.doubleBuffer = PUGL_FALSE; - } else if (!strcmp(argv[i], "-e")) { - opts.errorChecking = PUGL_TRUE; - } else if (!strcmp(argv[i], "-f")) { - opts.sync = PUGL_FALSE; - } else if (!strcmp(argv[i], "-h")) { - opts.help = true; - return opts; - } else if (!strcmp(argv[i], "-i")) { - opts.ignoreKeyRepeat = true; - } else if (!strcmp(argv[i], "-r")) { - opts.resizable = true; - } else if (!strcmp(argv[i], "-s")) { - opts.sync = PUGL_TRUE; - } else if (!strcmp(argv[i], "-v")) { - opts.verbose = true; - } else if (argv[i][0] != '-') { - break; - } else { - opts.help = true; - logError("Unknown option: %s\n", argv[i]); - } - } + char** const argv = *pargv; + int i = 1; + for (; i < *pargc; ++i) { + if (!strcmp(argv[i], "-a")) { + opts.samples = 4; + } else if (!strcmp(argv[i], "-c")) { + opts.continuous = true; + } else if (!strcmp(argv[i], "-d")) { + opts.doubleBuffer = PUGL_FALSE; + } else if (!strcmp(argv[i], "-e")) { + opts.errorChecking = PUGL_TRUE; + } else if (!strcmp(argv[i], "-f")) { + opts.sync = PUGL_FALSE; + } else if (!strcmp(argv[i], "-h")) { + opts.help = true; + return opts; + } else if (!strcmp(argv[i], "-i")) { + opts.ignoreKeyRepeat = true; + } else if (!strcmp(argv[i], "-r")) { + opts.resizable = true; + } else if (!strcmp(argv[i], "-s")) { + opts.sync = PUGL_TRUE; + } else if (!strcmp(argv[i], "-v")) { + opts.verbose = true; + } else if (argv[i][0] != '-') { + break; + } else { + opts.help = true; + logError("Unknown option: %s\n", argv[i]); + } + } - *pargc -= i; - *pargv += i; + *pargc -= i; + *pargv += i; - return opts; + return opts; } #endif // TEST_TEST_UTILS_H |