Advertisement
Guest User

Untitled

a guest
Mar 21st, 2018
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 427.65 KB | None | 0 0
  1. #define FPL_IMPLEMENTATION
  2.  
  3. /*
  4. final_platform_layer.hpp
  5.  
  6. -------------------------------------------------------------------------------
  7.     About
  8. -------------------------------------------------------------------------------
  9.  
  10. A Open source C++ single file header platform abstraction layer library.
  11.  
  12. Final Platform Layer is a cross-platform single-header-file development library designed to abstract the underlying platform to a very simple and easy to use low-level api for accessing input devices (keyboard, mouse, gamepad), audio playback, window handling, IO handling (files, directories, paths), multithreading (threads, mutex, signals) and graphics software or hardware rendering initialization.
  13. The main focus is game/simulation development, so the default settings will create a window, setup a opengl rendering context and initialize audio playback on any platform.
  14. The only dependencies are built-in operating system libraries, a C++/11 compiler and the C runtime library.
  15.  
  16. -------------------------------------------------------------------------------
  17.     Getting started
  18. -------------------------------------------------------------------------------
  19.  
  20. - Drop this file into any C++ projects you want and include it in any place you want.
  21. - In your main translation unit provide the typical main() entry point.
  22. - Define FPL_IMPLEMENTATION before including this header file in at least one translation unit.
  23. - Init the platform.
  24. - Use the features you want.
  25. - Release the platform when you are done.
  26.  
  27. -------------------------------------------------------------------------------
  28.     Usage: Hello world console application
  29. -------------------------------------------------------------------------------
  30.  
  31. #define FPL_IMPLEMENTATION
  32. #include <final_platform_layer.hpp>
  33.  
  34. int main(int argc, char **args){
  35.     if (fpl::InitPlatform(fpl::InitFlags::None)) {
  36.         fpl::console::ConsoleOut("Hello World!");
  37.         fpl::ReleasePlatform();
  38.         return 0;
  39.     } else {
  40.         return -1;
  41.     }
  42. }
  43.  
  44. -------------------------------------------------------------------------------
  45.     Usage: OpenGL legacy or modern application
  46. -------------------------------------------------------------------------------
  47.  
  48. #define FPL_IMPLEMENTATION
  49. #include <final_platform_layer.hpp>
  50.  
  51. int main(int argc, char **args){
  52.     fpl::Settings settings = DefaultSettings();
  53.     fpl::VideoSettings &videoSettings = settings.video;
  54.  
  55.     videoSettings.driver = fpl::VideoDriverType::OpenGL;
  56.  
  57.     // Legacy OpenGL
  58.     videoSettings.opengl.compabilityFlags = fpl::OpenGLCompabilityFlags::Legacy;
  59.  
  60.     // or
  61.  
  62.     // Modern OpenGL
  63.     videoSettings.opengl.compabilityFlags = fpl::OpenGLCompabilityFlags::Core;
  64.     videoSettings.opengl.majorVersion = 3;
  65.     videoSettings.opengl.minorVersion = 3;
  66. FPL_LOG_FUNCTION
  67.     if (fpl::InitPlatform(fpl::InitFlags::Video, settings)) {
  68.         // Event/Main loop
  69.         while (fpl::window::WindowUpdate()) {
  70.             // Handle actual window events
  71.             fpl::window::Event ev;
  72.             while (fpl::window::PollWindowEvent(ev)) {
  73.                 /// ...
  74.             }
  75.  
  76.             // your code goes here
  77.  
  78.             fpl::video::VideoFlip();
  79.         }
  80.         fpl::ReleasePlatform();
  81.         return 0;
  82.     } else {
  83.         return -1;
  84.     }
  85.  
  86. }
  87.  
  88. -------------------------------------------------------------------------------
  89.     License
  90. -------------------------------------------------------------------------------
  91.  
  92. Final Platform Layer is released under the following license:
  93.  
  94. MIT License
  95.  
  96. Copyright (c) 2017-2018 Torsten Spaete
  97.  
  98. Permission is hereby granted, free of charge, to any person obtaining a copy
  99. of this software and associated documentation files (the "Software"), to deal
  100. in the Software without restriction, including without limitation the rights
  101. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  102. copies of the Software, and to permit persons to whom the Software is
  103. furnished to do so, subject to the following conditions:
  104.  
  105. The above copyright notice and this permission notice shall be included in all
  106. copies or substantial portions of the Software.
  107.  
  108. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  109. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  110. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  111. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  112. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  113. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  114. SOFTWARE.
  115. */
  116.  
  117. /*!
  118.     \file final_platform_layer.hpp
  119.     \version v0.7.0.0 beta
  120.     \author Torsten Spaete
  121.     \brief Final Platform Layer (FPL) - A Open source C++ single file header platform abstraction layer library.
  122. */
  123.  
  124. /*!
  125.     \page page_changelog Changelog
  126.     \tableofcontents
  127.  
  128.     ## v0.7.0.0 beta:
  129.     - Changed: Changed Init/app state structs a lot
  130.     - Changed: Removed most anonymous unions and structs
  131.     - Changed: Renamed a lot of the internal handles
  132.     - Changed: Renamed threading::ThreadContext to threading::ThreadHandle
  133.     - Changed: Renamed threading::ThreadSignal to threading::SignalHandle
  134.     - Changed: Renamed threading::ThreadMutex to threading::MutexHandle
  135.     - Changed: All structs, functions with name *API renamed to *Api
  136.     - Changed: Moved internal functions around and restructured things
  137.     - Changed: Moved platforms and subplatforms into its own namespace
  138.     - Changed: Updated documentation a bit
  139.     - Changed: Introduced common::Argument*Error functions
  140.     - Changed: Removed memory::MemoryStackAllocate()
  141.     - Changed: App state memory size is aligned by 16-bytes as well
  142.     - Changed: Video/Audio state memory block is included in app state memory as well
  143.     - Fixed: Get rid of const char* to char* warnings for Get*DriverString() functions
  144.     - Fixed: [Win32] Icon was not default application icon
  145.     - Fixed: paths::ExtractFileName and paths::ExtractFileExtension was not returning const char*
  146.     - New: [X11][Window] Experimental X11 window creation and handling
  147.     - New: [X11][OpenGL] Experimental X11/GLX video driver
  148.     - New: [POSIX] Implemented all remaining posix functions
  149.     - New: Introduced debug logging
  150.     - New: Added FPL_ALIGNMENT_OFFSET macro
  151.     - New: Added FPL_ALIGNED_SIZE macro
  152.  
  153.     ## v0.6.0.0 beta:
  154.     - Changed: Documentation changed a bit
  155.     - Changed: Renamed SignalWakeUp() to SignalSet()
  156.     - Changed: [Win32] Start thread always immediatly
  157.     - Changed: Included "Windows" prefix for output path in visual studio projects
  158.     - Changed: Moved opengl settings into graphics union
  159.     - Changed: All global functions use :: as a prefix
  160.     - Deleted: Removed ThreadSuspend() -> Not complaint with pthread
  161.     - Deleted: Removed ThreadResume() -> Not complaint with pthread
  162.     - Deleted: Removed SignalReset() -> Not complaint with pthread
  163.     - Fixed: Resize video backbuffer was not working anymore
  164.     - Fixed: [Win32] Some _Interlocked* functions was not existing on x86
  165.     - New: Introduced PrepareWindowForVideoAfter() so we can setup a video context after the window has been created
  166.     - New: Introduced PrepareWindowForVideoBefore() so we can setup any window before initializing the video context
  167.     - New: Added timings::GetTimeInMilliseconds() with [Win32] and [POSIX] implementation
  168.     - New: [POSIX] Implemented all threading functions
  169.     - New: [Linux] Added a makefile for each demo project
  170.     - New: Added files::FileMove
  171.  
  172.     ## v0.5.9.1 beta:
  173.     - Changed: MemoryInfos uses uint64_t instead of size_t
  174.     - Changed: Added BSD to platform detecton
  175.     - Changed: Architecture detection does not use _WIN64 or _WIN32 anymore
  176.     - Changed: fpl_api is now either fpl_platform_api or fpl_common_api
  177.     - Changed: Internal code refactoring
  178.     - Changed: Renamed VideoSettings driverType to driver
  179.     - Changed: Video initialization is now platform independent
  180.     - Changed: Window initialization is now platform independent
  181.     - Changed: Moved window::WindowFlip to video::VideoFlip
  182.     - Changed: [POSIX] Replaced file-io with POSIX open, read, write
  183.     - Changed: [Win32] Removed fpl_api from main entry point forward declararation
  184.     - Changed: [Win32] Moved main entry point inside the implementation block
  185.     - Fixed: Arm64 was misdetected as X64, this is now its own arch
  186.     - Fixed: GNUC and ICC are pure C-compilers, it makes no sense to detect such in a C++ library
  187.     - Fixed: [Linux][POSIX] Refactor init and release to match PlatformInitState and PlatformAppState
  188.     - Updated: Documentations updated
  189.     - New: [POSIX][X11][Linux] Added missing functions as not-implemented
  190.  
  191.     ## v0.5.9.0 beta:
  192.     - Changed: Moved documentation inside its own file "final_platform_layer.documentation"
  193.     - Changed: [Win32] Window creation uses CS_OWNDC always
  194.     - Changed: Refactoring of platform and non-platform code
  195.     - Changed: InitPlatform() and ReleasePlatform() is now platform independent
  196.  
  197.     ## v0.5.8.1 beta:
  198.     - Changed: KeyboardEventType::Char renamed to KeyboardEventType::CharInput
  199.     - Changed: Completed basic documentation
  200.     - Changed: Renamed VideoBackBuffer.stride to VideoBackBuffer.lineWidth
  201.     - Changed: Moved a few internal inline audio functions to the global audio namespace
  202.     - Fixed: [Win32] WM_CHAR was allowing unicode characters as well, which is wrong because it must be properly converted first.
  203.     - Fixed: Audio driver selection was buggy
  204.     - Added: pixelStride to fpl::video::VideoBackBuffer
  205.     - Added: fpl::window::ClearWindowEvents()
  206.     - Added: fpl::window::PushWindowEvent()
  207.     - Added: fpl::window::UpdateGameControllers()
  208.     - Added: fpl::audio::GetAudioBufferSizeInFrames()
  209.     - Added: fpl::audio::GetAudioDriverString()
  210.     - Added: fpl::audio::GetAudioFormatString()
  211.     - Added: fpl::audio::GetAudioSampleSizeInBytes()
  212.     - Added: fpl::audio::GetAudioFrameSizeInBytes()
  213.     - Added: fpl::audio::GetAudioBufferSizeInBytes()
  214.  
  215.     ## v0.5.8.0 beta:
  216.     - Changed: SignalWaitFor* requires additional parameter for passing in the ThreadMutex reference (pthread compability)
  217.     - Changed: Signal* does not use const reference anymore (pthread compability)
  218.     - Changed: Updated documentation a ton
  219.     - Changed: Decreased MAX_ERRORSTATE_COUNT from 1024 to 256
  220.     - Changed: global__LastErrorState is a non-pointer global now
  221.     - Changed: Renamed GetPlatformLastError() to GetPlatformError()
  222.     - Changed: All array of objects parameters uses C++ array style -> int *arr[] instead of int **arr
  223.     - Fixed: MemoryAlignedFree() had wrong signature (void **) instead of (void *)
  224.     - Fixed: GetPlatformErrorCount() was not increasing when an empty error was pushed on for single error states
  225.     - Fixed: [Win32] InitPlatform() was not cleaning up the Win32State when the initialization failed
  226.     - Replaced: VideoCompabilityProfile is replaced by OpenGLCompabilityFlags (Only available with OpenGL)
  227.     - New: Added ClearPlatformErrors()
  228.  
  229.     ## v0.5.7.4 beta:
  230.     - Changed: Updated code documentation for all functions and types to doxygen/javadoc style
  231.     - Changed: SetFilePosition32 position is now int32_t instead of uint32_t to support negative positions as well
  232.     - Changed: Renamed desiredFormat to deviceFormat in AudioSettings
  233.     - Changed: [DirectSound] Use deviceID as GUID for the audio device
  234.     - New: Introduced AudioDeviceID
  235.     - New: Added deviceID field in AudioSettings
  236.     - New: Added audio::GetAudioDevices()
  237.     - New: Added strings::FormatString()
  238.  
  239.     ## v0.5.7.3 beta:
  240.     - Fixed: [Win32] Fixed SetWindowFullscreen was not working properly
  241.     - New: Introduced outputRect in VideoBackBuffer + Win32 implementation
  242.     - Changed: SetWindowFullscreen returns bool
  243.  
  244.     ## v0.5.7.2 beta:
  245.     - Added: Added new audio formats (AudioFormatType::F64, AudioFormatType::S64)
  246.  
  247.     ## v0.5.7.1 beta:
  248.     - Fixed: xInputSetState renamed to xInputGetState internally
  249.     - Added: Introduced InputSettings
  250.     - Added: [Win32] XInput controller detection is now limited to a fixed frequency, for improving performance (InputSettings.controllerDetectionFrequency)
  251.  
  252.     ## v0.5.7.0 beta:
  253.     - Changed: Total change of documentation style
  254.     - Changed: [Win32] ThreadMutex uses a critical section instead of a event
  255.     - Changed: [Win32] Include windows.h in the header, so we can define HANDLE, CRITICAL_SECTION in the api
  256.     - Changed: [Win32] Changed lots of functions to use conditions instead of asserts
  257.     - Changed: [Win32] Changed format specifiers to use either %d or %zu for integer types
  258.     - Changed: All Thread*Wait functions returns if the wait was successful or not in the same way Signal*Wait
  259.     - Changed: All ListFiles* functions uses reference instead of pointer
  260.  
  261.     ## v0.5.6.0 beta:
  262.     - Changed: We are back to C++/11 and we will never going back to C++/98
  263.  
  264.     ## v0.5.5.1 beta:
  265.     - New[POSIX]: Implemented fpl::timings
  266.     - New[POSIX]: Implemented fpl::library
  267.     - New[POSIX]: Implemented fpl::threading::ThreadSleep
  268.     - Changed[POSIX]: Moved Linux fpl::console functions to Posix
  269.  
  270.     ## v0.5.5.0 beta:
  271.     - Changed: All internal handles are now unions now, so can have different sizes of handles
  272.     - Changed: Introduced POSIX platform and moved linux atomics into it
  273.  
  274.     ## v0.5.4.0 beta:
  275.     - Fixed: Some enum types was not using the namespace version
  276.  
  277.     ## v0.5.3.0 beta:
  278.     - Changed: Use custom int types because C++/98 has no default types unfortunatly
  279.     - Fixed: Changed compiler detection order, because some non-MSVC compilers define _MSVC
  280.     - Changed: Better C++/11 feature detection for optional nullptr and constexpr
  281.  
  282.     ## v0.5.2.1 beta:
  283.     - Fixed: Corrected all doxygen statements to match new enum style or added missing exlamation marks.
  284.  
  285.     ## v0.5.2 beta:
  286.     - Changed: Library is now C++/98 complaint
  287.     - Changed: The actual enum type for "flags" has no "s" at the end anymore.
  288.     - Opimization: Changed some internal functions to "static inline"
  289.     - Changed: Renamed audio::GetAudioNativeFormat to audio::GetAudioHardwareFormat
  290.     - New: Added "periods", "bufferSizeInBytes", "bufferSizeInFrames" to AudioDeviceFormat
  291.  
  292.     ## v0.5.1 beta:
  293.     - New: audio::GetAudioNativeFormat()
  294.     - New: audio::SetAudioClientReadCallback()
  295.     - Fixed: InitFlags::Audio was never tested before InitAudio() was being called.
  296.     - Changed: Renamed ThreadStop to ThreadDestroy
  297.  
  298.     ## v0.5.0 beta:
  299.     - Added: [Win32] DirectSound playback support
  300.     - Added: Asyncronous audio playback
  301.  
  302.     ## v0.4.11 alpha:
  303.     - Fixed: [Win32] For now, load all user32 functions always, even when window is not used (This is to prepare for audio playback)
  304.     - Fixed: [Win32] ThreadStop was not releasing the thread handle
  305.     - Added: [Win32] ThreadWaitForAny
  306.     - Added: [Win32] SignalWaitForAll
  307.     - Added: [Win32] SignalWaitForAny
  308.     - Added: [Win32] SignalReset
  309.     - Added: FPL_NO_VIDEO
  310.     - Changed: ThreadWaitForSingle renamed to ThreadWaitForOne
  311.     - Changed: ThreadWaitForMultiple renamed to ThreadWaitForAll
  312.     - Changed: SignalWait renamed to SignalWaitForOne
  313.  
  314.     ## v0.4.10 alpha:
  315.     - Removed: Removed all _internal _INTERNAL postfixes from types, functions and macros
  316.     - Changed: Proper identitation for compiler directives based on context
  317.     - Added: [Win32] Dynamically loading ole32 functions (CoCreateInstance, CoInitializeEx, etc.)
  318.     - Fixed: [Win32] GetCursor was not using the dynamic loaded function
  319.     - Fixed: [Win32] Missing *Clipboard* dynamic functions
  320.  
  321.     ## v0.4.9 alpha:
  322.     - Removed: Removed all audio code for now
  323.     - Changed: A total cleanup of all internal stuff, so its much easier to add in new features
  324.  
  325.     ## v0.4.8 alpha:
  326.     - New: AtomicLoadU32, AtomicLoadU64, AtomicLoadS32, AtomicLoadS64, AtomicLoadPtr
  327.     - New: AtomicStoreU32, AtomicStoreU64, AtomicStoreS32, AtomicStoreS64, AtomicStorePtr
  328.     - New: AtomicExchangePtr, AtomicCompareAndExchangePtr, IsAtomicCompareAndExchangePtr
  329.     - New: [Win32] Implementation for AtomicLoadU32, AtomicLoadU64, AtomicLoadS32, AtomicLoadS64, AtomicLoadPtr
  330.     - New: [Win32] Implementation for AtomicStoreU32, AtomicStoreU64, AtomicStoreS32, AtomicStoreS64, AtomicStorePtr
  331.     - New: [Linux] Implementation for AtomicLoadU32, AtomicLoadU64, AtomicLoadS32, AtomicLoadS64, AtomicLoadPtr
  332.     - New: [Linux] Implementation for AtomicStoreU32, AtomicStoreU64, AtomicStoreS32, AtomicStoreS64, AtomicStorePtr
  333.     - New: [Win32] Loading of DirectSound (Prepare for audio output support)
  334.     - Draft: Added first audio output api
  335.     - Fixed: Threading context determination
  336.     - Fixed: [Win32] Fixed all thread implementations
  337.     - Fixed: [Win32] SetWindowLongPtrA does not exists on X86
  338.     - Fixed: [Win32] Missing call convention in SHGetFolderPathA and SHGetFolderPathW
  339.     - Changed: Improved header documentation (More examples, better descriptions, proper markdown syntax, etc.)
  340.     - Changed: All threading functions uses pointer instead of reference
  341.     - Changed: [Linux] Atomic* uses __sync instead of __atomic
  342.     - Changed: A bit of internal cleanup
  343.  
  344.     ## v0.4.7 alpha:
  345.     - Changed: [Win32] Load all user32 and shell32 functions dynamically
  346.     - Changed: FPL_ENUM_AS_FLAGS_OPERATORS_INTERNAL requires a int type as well
  347.     - Fixed: MemoryAlignedAllocate and MemoryAlignedFree was broken
  348.     - Added: FPL_IS_ALIGNED macro
  349.  
  350.     ## v0.4.6 alpha:
  351.     - Fixed: [Win32] Crash when window is not set in the InitFlags but FPL_USE_WINDOW is set.
  352.  
  353.     ## v0.4.5 alpha:
  354.     - Changed: [Win32] Use CommandLineToArgvW for command line parsing
  355.  
  356.     ## v0.4.4 alpha:
  357.     - New: [Win32] Implemented argument parsing for WinMain and wWinMain
  358.     - Fixed: Corrected small things for doxygen
  359.     - Changed: Renamed CopyAFile to FileCopy
  360.     - Changed: Renamed DeleteAFile to FileDelete
  361.  
  362.     ## v0.4.3 alpha:
  363.     - New: Introduced IsAtomicCompareAndExchange
  364.     - Added: [Linux] Implemented IsAtomicCompareAndExchange for all 32 and 64 bit integer types
  365.     - Added: [Win32] Implemented IsAtomicCompareAndExchange for all 32 and 64 bit integer types
  366.     - Added: [Win32] Loading gdi32.dll dynamically for ChoosePixelFormat, etc.
  367.     - Added: [Win32] Loading opengl32.dll dynamically for wglGetProcAddress, wglMakeCurrent, etc.
  368.     - Fixed: [Win32] Adding memory fence for AtomicReadWriteFence on non-x64 architectures
  369.     - Fixed: [Win32] Adding memory fence for AtomicReadFence on non-x64 architectures
  370.     - Fixed: [Win32] Adding memory fence for AtomicWriteFence on non-x64 architectures
  371.     - Fixed: Solidified descriptions for all Atomic*Fence
  372.     - Changed: Enabled FPL_FORCE_ASSERTIONS will ensure that C asserts are never used, because it may be compiled out.
  373.     - Changed: Removed all FPL_WIN32_ kernel32 macros and replaced it with normal calls.
  374.     - Changed: [Win32] Changed a lof ot the internals
  375.  
  376.     ## v0.4.2 alpha:
  377.     - Added: [Linux] Started linux implementation
  378.     - Added: [Linux] Memory allocations
  379.     - Added: [Linux] Atomic operations
  380.     - Added: Check for C++/11 compiler and fail if not supported
  381.     - Added: Nasty vstudio 2015+ workaround to detect C++/11
  382.     - Added: &= operator overloading for enums
  383.     - Changed: AtomicCompareAndExchange argument "comparand" and "exchange" flipped.
  384.     - Changed: constexpr is now fpl_constant to make clear what is a constant
  385.     - Removed: [Win32] CreateDIBSection is not needed for a software backbuffer
  386.     - Fixed: [Win32] Software rendering was not working properly.
  387.     - Fixed: Some AtomicCompareAndExchange signatures was still AtomicAndCompareExchange
  388.  
  389.     ## v0.4.1 alpha:
  390.     - Cleanup: Internal cleanup
  391.     - Changed: All the settings constructors removed and replaced by a simple inline function.
  392.     - Added: Added native C++ unit test project to demos solution
  393.     - Fixed: FPL_OFFSETOF was not working
  394.     - Fixed: All file size macros like FPL_MEGABYTES was returning invalid results.
  395.     - Removed: FPL_PETABYTES and higher are removed, just because its useless.
  396.  
  397.     ## v0.4.0 alpha:
  398.     - Changed: All FPL_ENABLE_ defines are internal now, the caller must use FPL_NO_ or FPL_YES_ respectivily.
  399.     - Changed: AtomicCompareExchange* is now AtomicCompareAndExchange*
  400.     - Changed: InitFlags::VideoOpenGL is now InitFlags::Video
  401.     - Added: Software rendering support
  402.     - Added: VideoDriverType enumeration for selecting the active video driver
  403.     - Added: video::GetVideoBackBuffer with [Win32] implementation
  404.     - Added: video::ResizeVideoBackBuffer with [Win32] implementation
  405.     - Added: FPL_PETABYTES macro
  406.     - Added: FPL_EXABYTES macro
  407.     - Added: FPL_ZETTABYTES macro
  408.     - Added: FPL_YOTTABYTES macro
  409.     - Added: FPL_MIN macro
  410.     - Added: FPL_MAX macro
  411.     - Added: MutexCreate with [Win32] implementation
  412.     - Added: MutexDestroy with [Win32] implementation
  413.     - Added: MutexLock with [Win32] implementation
  414.     - Added: MutexUnlock with [Win32] implementation
  415.     - Added: SignalCreate with [Win32] implementation
  416.     - Added: SignalDestroy with [Win32] implementation
  417.     - Added: SignalWait with [Win32] implementation
  418.     - Added: SignalWakeUp with [Win32] implementation
  419.     - Added: GetClipboardAnsiText with [Win32] implementation
  420.     - Added: GetClipboardWideText with [Win32] implementation
  421.     - Added: SetClipboardText with [Win32] implementation for ansi and wide strings
  422.     - Added [MSVC]: AtomicExchangeS32 (Signed integer)
  423.     - Added [MSVC]: AtomicExchangeS64 (Signed integer)
  424.     - Added [MSVC]: AtomicAddS32 (Signed integer)
  425.     - Added [MSVC]: AtomicAddS64 (Signed integer)
  426.     - Added [MSVC]: AtomicCompareExchangeS32 (Signed integer)
  427.     - Added [MSVC]: AtomicCompareExchangeS64 (Signed integer)
  428.     - Fixed [MSVC]: AtomicExchangeU32 was not using unsigned intrinsic
  429.     - Fixed [MSVC]: AtomicExchangeU64 was not using unsigned intrinsic
  430.     - Fixed [MSVC]: AtomicAddU32 was not using unsigned intrinsic
  431.     - Fixed [MSVC]: AtomicAddU64 was not using unsigned intrinsic
  432.     - Fixed [MSVC]: AtomicCompareExchangeU32 was not using unsigned intrinsic
  433.     - Fixed [MSVC]: AtomicCompareExchangeU64 was not using unsigned intrinsic
  434.     - Implemented [Win32]: GetProcessorCoreCount
  435.     - Implemented [Win32]: Main thread infos
  436.     - Performance [Win32]: GetProcessorName (3 loop iterations at max)
  437.  
  438.     ## v0.3.6 alpha:
  439.     - Cleanup: All win32 functions are macro calls now (prepare for dynamic function loading)
  440.     - Fixed: FPL_ENABLE_WINDOW was enabling window features even when it was deactivated by the caller
  441.  
  442.     ## v0.3.5 alpha:
  443.     - Renamed: All memory/library/threading functions
  444.     - Removed: FPL_ENABLE_PUSHMEMORY removed entirely
  445.  
  446.     ## v0.3.4 alpha:
  447.     - Renamed: CopyFile/DeleteFile/All memory functions renamed (Stupid win32!)
  448.     - Renamed: All internal opengl defines renamed, so that it wont conflict with other libraries
  449.     - Fixed: [Win32] strings::All Wide conversions was not working properly
  450.     - Removed: [Win32] Undefs for CopyFile
  451.     - Changed: [Win32/OpenGL] Test for already included gl.h
  452.  
  453.     ## v0.3.3 alpha:
  454.     - Basic threading creation and handling
  455.     - Fixed strings::All Wide convertions was not working properly
  456.  
  457.     ## v0.3.2 alpha:
  458.     - Introduced: Automatic namespace inclusion (FPL_AUTO_NAMESPACE)
  459.     - Introduced: Push memory (FPL_ENABLE_PUSHMEMORY)
  460.     - Signature changed for: ExtractFilePath/ChangeFileExtension (source first, destination second)
  461.     - Window features not not compiled out anymore when FPL_ENABLE_WINDOW is 0
  462.     - New overloaded CombinePath without any destination arguments
  463.     - New: AllocateStackMemory function
  464.     - Optional destination arguments for: GetExecutableFilePath/GetHomePath/ChangeFileExtension/CombinePath
  465.     - Fixed strings::CopyAnsiString/CopyWideString was not returning the correct value
  466.  
  467.     ## v0.3.1 alpha:
  468.     - All types/structs/fields/functions documented
  469.     - [Win32] Fixed legacy opengl (GL_INVALID_OPERATION)
  470.  
  471.     ## v0.3.0 alpha:
  472.     - Updated documentation a lot
  473.     - [Win32] Support for WGL opengl profile selection
  474.  
  475.     ## v0.2.6 alpha:
  476.     - Added memory::CopyMemory
  477.     - Added fpl::GetLastError and fpl::GetLastErrorCount for proper error handling
  478.     - Added files::CreateBinaryFile and files::OpenBinaryFile for wide file paths
  479.     - Added basic support for creating a modern opengl rendering context, see VideoCompabilityProfile in VideoSettings
  480.     - Added support for enabling opengl vsync through WGL
  481.     - Returns char * for all paths:: get like functions
  482.     - Returns char/wchar_t * for all strings:: functions
  483.     - Fixed files::CreateBinaryFile was never able to overwrite the file.
  484.     - Fixed include was in some namespaces defined
  485.     - Fixed files::ClearMemory was wrong
  486.     - Replaced all const constants with fpl_constant
  487.     - Removed template code / Replaced it with macros
  488.  
  489.     ## v0.2.5 alpha:
  490.     - Added CreateDirectories
  491.     - Returns char * for all path get like functions
  492.     - Fixed CreateBinaryFile was never able to overwrite the file.
  493.  
  494.     ## v.2.4 alpha:
  495.     - Changed to a doxygen + vc complaint documentation style
  496.     - CopyFile2, DeleteFile2 and CloseFile2 are now CopyFile, DeleteFile, CloseFile
  497.  
  498.     ## v0.2.3 alpha:
  499.     - Support for doxygen in documentations
  500.  
  501.     ## v0.2.2 alpha:
  502.     - Added XInput support
  503.  
  504.     ## v0.2.1 alpha:
  505.     - Changed a lot of pointer arguments to reference
  506.     - Added gamepad event structures
  507.  
  508.     ## v0.2 alpha:
  509.     - Dropped C support and moved to a more C++ ish api
  510.     - Dropped no C-Runtime support
  511.  
  512.     ## v0.1 alpha:
  513.     - Initial version
  514. */
  515.  
  516. /*!
  517.     \page page_todo ToDo / Planned (Random order)
  518.     \tableofcontents
  519.  
  520.     \section section_todo_required In process
  521.  
  522.     - Linux Platform:
  523.         - Files & Path (Copy, File/Dir iteration)
  524.         - Window (X11)
  525.         - Video opengl (GLX)
  526.         - Video software (X11)
  527.  
  528.     \section section_todo_planned Planned
  529.  
  530.     - BSD Platform (POSIX, X11)
  531.  
  532.     - Mac OSX Platform
  533.  
  534.     - Audio:
  535.         - Support for channel mapping
  536.         - ALSA audio driver
  537.         - WASAPI audio driver
  538.  
  539.     - Video:
  540.         - Direct2D
  541.         - Direct3D 9/10/11
  542.         - Vulkan
  543.  
  544.     - Networking (UDP, TCP)
  545.         - [Win32] WinSock
  546.         - [POSIX] Socket
  547.  
  548.     - Documentation
  549.         - Audio deviceID
  550.         - Audio introduction (What is a frame, a sample, a buffer, how data is layed out, etc.)
  551.         - Memory
  552.         - Atomics
  553.         - Multi-Threading
  554.         - File-IO
  555.         - Paths
  556.         - Strings
  557.  
  558.     - DLL-Export support
  559.  
  560.     - Multimonitor-Support
  561.  
  562.     - Unicode-Support for commandline arguments (Win32)
  563.  
  564.     - Window
  565.         - Custom icon
  566.         - Custom window style (Border, Resizeable, etc.)
  567.         - Unicode/UTF-8 Support for character input
  568.  
  569.     \section section_todo_optional Optional
  570.  
  571.     - Make VideoBackBuffer be readonly and separate functions for getting the data pointer and setting the output rectangle.
  572.  
  573.     - Additional parameters for passing pointers instead of returning structs (Method overloading)
  574.  
  575.     - Pack/Unpack functions (Handle endianess)
  576.  
  577.     - Open/Save file/folder dialog
  578. */
  579.  
  580. // ****************************************************************************
  581. //
  582. // > HEADER
  583. //
  584. // ****************************************************************************
  585. #ifndef FPL_INCLUDE_HPP
  586. #define FPL_INCLUDE_HPP
  587.  
  588. // C++/11 detection
  589. #if !((defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSC_VER) && _MSC_VER >= 1900))
  590. #   error "You need a C++/11 compatible compiler for this library!"
  591. #endif
  592.  
  593. //
  594. // Platform detection
  595. //
  596. // https://sourceforge.net/p/predef/wiki/OperatingSystems/
  597. #if defined(_WIN32) || defined(_WIN64)
  598. #   define FPL_PLATFORM_WIN32
  599. #   define FPL_PLATFORM_NAME "Windows"
  600. #   define FPL_SUBPLATFORM_STD_CONSOLE
  601. #elif defined(__linux__) || defined(__gnu_linux__)
  602. #   define FPL_PLATFORM_LINUX
  603. #   define FPL_PLATFORM_NAME "Linux"
  604. #   define FPL_SUBPLATFORM_POSIX
  605. #   define FPL_SUBPLATFORM_X11
  606. #   define FPL_SUBPLATFORM_STD_STRINGS
  607. #   define FPL_SUBPLATFORM_STD_CONSOLE
  608. #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__bsdi__)
  609. #   define FPL_PLATFORM_BSD
  610. #   define FPL_PLATFORM_NAME "BSD"
  611. #   define FPL_SUBPLATFORM_POSIX
  612. #   define FPL_SUBPLATFORM_X11
  613. #   define FPL_SUBPLATFORM_STD_STRINGS
  614. #   define FPL_SUBPLATFORM_STD_CONSOLE
  615. #   error "Not implemented yet!"
  616. #elif defined(unix) || defined(__unix) || defined(__unix__)
  617. #   define FPL_PLATFORM_UNIX
  618. #   define FPL_PLATFORM_NAME "Unix"
  619. #   define FPL_SUBPLATFORM_POSIX
  620. #   define FPL_SUBPLATFORM_X11
  621. #   define FPL_SUBPLATFORM_STD_STRINGS
  622. #   define FPL_SUBPLATFORM_STD_CONSOLE
  623. #   error "Not implemented yet!"
  624. #else
  625. #   error "This platform is not supported!"
  626. #endif // FPL_PLATFORM
  627.  
  628. //
  629. // Architecture detection (x86, x64)
  630. // See: https://sourceforge.net/p/predef/wiki/Architectures/
  631. //
  632. #if defined(_M_X64) || defined(__x86_64__) || defined(__amd64__)
  633. #   define FPL_ARCH_X64
  634. #elif defined(_M_IX86) || defined(__i386__) || defined(__X86__) || defined(_X86_)
  635. #   define FPL_ARCH_X86
  636. #elif defined(__arm__) || defined(_M_ARM)
  637. #   if defined(__aarch64__)
  638. #       define FPL_ARCH_ARM64
  639. #   else   
  640. #       define FPL_ARCH_ARM32
  641. #   endif
  642. #else
  643. #   error "This architecture is not supported!"
  644. #endif // FPL_ARCH
  645.  
  646. //
  647. // Build configuration and compilers
  648. // See: http://beefchunk.com/documentation/lang/c/pre-defined-c/precomp.html
  649. // See: http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros
  650. //
  651. #if defined(__clang__)
  652.     //! CLANG compiler detected
  653. #   define FPL_COMPILER_CLANG
  654. #elif defined(__llvm__)
  655.     //! LLVM compiler detected
  656. #   define FPL_COMPILER_LLVM
  657. #elif defined(__INTEL_COMPILER)
  658.     //! Intel compiler detected
  659. #   define FPL_COMPILER_INTEL
  660. #elif defined(__MINGW32__)
  661.     //! MingW compiler detected
  662. #   define FPL_COMPILER_MINGW
  663. #elif defined(__GNUG__) && !defined(__clang__)
  664.     //! GCC compiler detected
  665. #   define FPL_COMPILER_GCC
  666. #elif defined(_MSC_VER)
  667.     //! Visual studio compiler detected
  668. #   define FPL_COMPILER_MSVC
  669. #else
  670.     //! No compiler detected
  671. #   define FPL_COMPILER_UNKNOWN
  672. #endif // FPL_COMPILER
  673.  
  674. //
  675. // Compiler depended settings and detections
  676. //
  677. #if defined(FPL_COMPILER_MSVC)
  678.     //! Disable noexcept compiler warning for C++
  679. #   pragma warning( disable : 4577 )
  680.     //! Disable "switch statement contains 'default' but no 'case' labels" compiler warning for C++
  681. #   pragma warning( disable : 4065 )
  682.  
  683. #   if defined(_DEBUG) || (!defined(NDEBUG))
  684.         //! Debug mode detected
  685. #       define FPL_ENABLE_DEBUG
  686. #   else
  687.         //! Non-debug (Release) mode detected
  688. #       define FPL_ENABLE_RELEASE
  689. #   endif
  690.  
  691.     //! Function name macro (Win32)
  692. #   define FPL_FUNCTION_NAME __FUNCTION__
  693. #else
  694.     // @NOTE(final): Expect all other compilers to pass in FPL_DEBUG manually
  695. #   if defined(FPL_DEBUG)
  696.         //! Debug mode detected
  697. #       define FPL_ENABLE_DEBUG
  698. #   else
  699.         //! Non-debug (Release) mode detected
  700. #       define FPL_ENABLE_RELEASE
  701. #   endif
  702.  
  703.     //! Function name macro (Other compilers)
  704. #   define FPL_FUNCTION_NAME __FUNCTION__
  705. #endif // FPL_COMPILER
  706.  
  707. //
  708. // Options & Feature detection
  709. //
  710.  
  711. // Assertions
  712. #if !defined(FPL_NO_ASSERTIONS)
  713. #   if !defined(FPL_FORCE_ASSERTIONS)
  714. #       if defined(FPL_ENABLE_DEBUG)
  715.             //! Enable Assertions in Debug Mode by default
  716. #           define FPL_ENABLE_ASSERTIONS
  717. #       endif
  718. #   else
  719.         //! Enable Assertions always
  720. #       define FPL_ENABLE_ASSERTIONS
  721. #   endif
  722. #endif // !FPL_NO_ASSERTIONS
  723. #if defined(FPL_ENABLE_ASSERTIONS)
  724. #   if !defined(FPL_NO_C_ASSERT)
  725.         //! Enable C-Runtime Assertions by default
  726. #       define FPL_ENABLE_C_ASSERT
  727. #   endif
  728. #endif // FPL_ENABLE_ASSERTIONS
  729.  
  730. // Window
  731. #if !defined(FPL_NO_WINDOW)
  732.     //! Window support enabled by default
  733. #   define FPL_SUPPORT_WINDOW
  734. #endif
  735.  
  736. // Video
  737. #if !defined(FPL_NO_VIDEO)
  738.     //! Video support
  739. #   define FPL_SUPPORT_VIDEO
  740. #endif
  741. #if defined(FPL_SUPPORT_VIDEO)
  742. #   if !defined(FPL_NO_VIDEO_OPENGL)
  743.         //! OpenGL support enabled by default
  744. #       define FPL_SUPPORT_VIDEO_OPENGL
  745. #   endif
  746. #   if !defined(FPL_NO_VIDEO_SOFTWARE)
  747.         //! Software rendering support enabled by default
  748. #       define FPL_SUPPORT_VIDEO_SOFTWARE
  749. #   endif
  750. #endif // FPL_SUPPORT_VIDEO
  751.  
  752. // Audio
  753. #if !defined(FPL_NO_AUDIO)
  754.     //! Audio support
  755. #   define FPL_SUPPORT_AUDIO
  756. #endif
  757. #if defined(FPL_SUPPORT_AUDIO)
  758. #   if !defined(FPL_NO_AUDIO_DIRECTSOUND) && defined(FPL_PLATFORM_WIN32)
  759.         //! DirectSound support is only available on Win32
  760. #       define FPL_SUPPORT_AUDIO_DIRECTSOUND
  761. #   endif
  762. #endif // FPL_SUPPORT_AUDIO
  763.  
  764. // Remove video support when window is disabled
  765. #if !defined(FPL_SUPPORT_WINDOW)
  766. #   if defined(FPL_SUBPLATFORM_X11)
  767. #       undef FPL_SUBPLATFORM_X11
  768. #   endif
  769.  
  770. #   if defined(FPL_SUPPORT_VIDEO)
  771. #       undef FPL_SUPPORT_VIDEO
  772. #   endif
  773. #   if defined(FPL_SUPPORT_VIDEO_OPENGL)
  774. #       undef FPL_SUPPORT_VIDEO_OPENGL
  775. #   endif
  776. #   if defined(FPL_SUPPORT_VIDEO_SOFTWARE)
  777. #       undef FPL_SUPPORT_VIDEO_SOFTWARE
  778. #   endif
  779. #endif // !FPL_SUPPORT_WINDOW
  780.  
  781. //
  782. // Enable supports (FPL uses _ENABLE_ internally only)
  783. //
  784. #if defined(FPL_SUPPORT_WINDOW)
  785.     //! Enable Window
  786. #   define FPL_ENABLE_WINDOW
  787. #endif
  788. #if defined(FPL_SUPPORT_VIDEO)
  789.     //! Enable Video
  790. #   define FPL_ENABLE_VIDEO
  791. #   if defined(FPL_SUPPORT_VIDEO_OPENGL)
  792.         //! Enable OpenGL Video
  793. #       define FPL_ENABLE_VIDEO_OPENGL
  794. #   endif
  795. #   if defined(FPL_SUPPORT_VIDEO_SOFTWARE)
  796.         //! Enable Software Rendering Video
  797. #       define FPL_ENABLE_VIDEO_SOFTWARE
  798. #   endif
  799. #endif // FPL_SUPPORT_VIDEO
  800. #if defined(FPL_SUPPORT_AUDIO)
  801.     //! Enable Audio
  802. #   define FPL_ENABLE_AUDIO
  803. #   if defined(FPL_SUPPORT_AUDIO_DIRECTSOUND)
  804.         //! Enable DirectSound Audio
  805. #       define FPL_ENABLE_AUDIO_DIRECTSOUND
  806. #   endif
  807. #endif // FPL_SUPPORT_AUDIO
  808.  
  809. #if !defined(FPL_NO_ERROR_IN_CONSOLE)
  810.     //! Write errors in console
  811. #   define FPL_ENABLE_ERROR_IN_CONSOLE
  812. #endif
  813. #if !defined(FPL_NO_MULTIPLE_ERRORSTATES)
  814.     //! Allow multiple error states
  815. #   define FPL_ENABLE_MULTIPLE_ERRORSTATES
  816. #endif
  817. #if defined(FPL_AUTO_NAMESPACE)
  818.     //! Expand namespaces at the header end always
  819. #   define FPL_ENABLE_AUTO_NAMESPACE
  820. #endif
  821.  
  822. //
  823. // Static/Inline/Extern/Internal
  824. //
  825. //! Global persistent variable
  826. #define fpl_globalvar static
  827. //! Local persistent variable
  828. #define fpl_localvar static
  829. //! Private/Internal function
  830. #define fpl_internal static
  831. //! Inline function
  832. #define fpl_inline inline
  833. //! Internal inlined function
  834. #define fpl_internal_inline fpl_internal fpl_inline
  835. //! Constant
  836. #define fpl_constant constexpr
  837.  
  838. #if defined(FPL_API_AS_PRIVATE)
  839.     //! Private api call
  840. #   define fpl_api static
  841. #else
  842.     //! Public api call
  843. #   define fpl_api extern
  844. #endif // FPL_API_AS_PRIVATE
  845.  
  846. //! Platform api definition
  847. #define fpl_platform_api fpl_api
  848. //! Common api definition
  849. #define fpl_common_api fpl_api
  850. //! Main entry point api definition
  851. #define fpl_main
  852.  
  853. //
  854. // Assertions
  855. //
  856. #if defined(FPL_ENABLE_ASSERTIONS)
  857. #   if defined(FPL_ENABLE_C_ASSERT) && !defined(FPL_FORCE_ASSERTIONS)
  858. #       include <assert.h>
  859.         //! Runtime assert (C Runtime)
  860. #       define FPL_ASSERT(exp) assert(exp)
  861.         //! Compile error assert (C Runtime)
  862. #       define FPL_STATICASSERT(exp) static_assert(exp, "static_assert")
  863. #   else
  864.         //! Runtime assert
  865. #       define FPL_ASSERT(exp) if(!(exp)) {*(int *)0 = 0;}
  866.         //! Compile error assert
  867. #       define FPL_STATICASSERT_(exp, line) \
  868.             int fpl_static_assert_##line(int static_assert_failed[(exp)?1:-1])
  869. #       define FPL_STATICASSERT(exp) \
  870.             FPL_STATICASSERT_(exp, __LINE__)
  871. #   endif // FPL_ENABLE_C_ASSERT
  872. #else
  873.     //! Runtime assertions disabled
  874. #   define FPL_ASSERT(exp)
  875.     //! Compile time assertions disabled
  876. #   define FPL_STATICASSERT(exp)
  877. #endif // FPL_ENABLE_ASSERTIONS
  878.  
  879. //! This will full-on crash when something is not implemented always.
  880. #define FPL_NOT_IMPLEMENTED {*(int *)0 = 0xBAD;}
  881.  
  882. //
  883. // Logging
  884. //
  885. #if defined(FPL_LOGGING)
  886.     //! Enable logging
  887. #   define FPL_ENABLE_LOGGING
  888. #endif
  889.  
  890. //
  891. // Types & Limits
  892. //
  893. #include <stdint.h> // uint32_t, ...
  894. #include <stddef.h> // size_t
  895. #include <stdlib.h> // UINT32_MAX, ...
  896.  
  897. //
  898. // Macro functions
  899. //
  900. //! Returns the element count from a static array,
  901. #define FPL_ARRAYCOUNT(arr) (sizeof(arr) / sizeof((arr)[0]))
  902.  
  903. //! Returns the offset in bytes to a field in a structure
  904. #define FPL_OFFSETOF(type, field) ((size_t)(&(((type*)(0))->field)))
  905.  
  906. //! Returns the offset for the value to satisfy the given alignment boundary
  907. #define FPL_ALIGNMENT_OFFSET(value, alignment) ( (((alignment) > 1) && (((value) & ((alignment) - 1)) != 0)) ? ((alignment) - ((value) & (alignment - 1))) : 0)          
  908. //! Returns the given size extended o to satisfy the given alignment boundary
  909. #define FPL_ALIGNED_SIZE(size, alignment) (((size) > 0 && (alignment) > 0) ? ((size) + FPL_ALIGNMENT_OFFSET(size, alignment)) : (size))
  910. //! Returns true when the given pointer address is aligned to the given alignment
  911. #define FPL_IS_ALIGNED(ptr, alignment) (((uintptr_t)(const void *)(ptr)) % (alignment) == 0)
  912.  
  913. //! Returns the smallest value
  914. #define FPL_MIN(a, b) ((a) < (b)) ? (a) : (b)
  915. //! Returns the biggest value
  916. #define FPL_MAX(a, b) ((a) > (b)) ? (a) : (b)
  917.  
  918. //! Returns the number of bytes for the given kilobytes
  919. #define FPL_KILOBYTES(value) (((value) * 1024ull))
  920. //! Returns the number of bytes for the given megabytes
  921. #define FPL_MEGABYTES(value) ((FPL_KILOBYTES(value) * 1024ull))
  922. //! Returns the number of bytes for the given gigabytes
  923. #define FPL_GIGABYTES(value) ((FPL_MEGABYTES(value) * 1024ull))
  924. //! Returns the number of bytes for the given terabytes
  925. #define FPL_TERABYTES(value) ((FPL_GIGABYTES(value) * 1024ull))
  926.  
  927. //! Manually allocate memory on the stack (Use this with care!)
  928. #define FPL_STACKALLOCATE(size) _alloca(size)
  929.  
  930. //! Defines the operator overloads for a enum used as flags
  931. #define FPL_ENUM_AS_FLAGS_OPERATORS(etype) \
  932.         inline etype operator | (etype lhs, etype rhs) { \
  933.             return (etype)(static_cast<int>(lhs) | static_cast<int>(rhs)); \
  934.         } \
  935.         inline bool operator & (const etype lhs, const etype rhs) { \
  936.             return (static_cast<int>(lhs) & static_cast<int>(rhs)) == static_cast<int>(rhs); \
  937.         } \
  938.         inline etype& operator |= (etype &lhs, etype rhs) { \
  939.             lhs = (etype)(static_cast<int>(lhs) | static_cast<int>(rhs)); \
  940.             return lhs; \
  941.         } \
  942.         inline etype& operator &= (etype &lhs, etype rhs) { \
  943.             lhs = (etype)(static_cast<int>(lhs) & static_cast<int>(rhs)); \
  944.             return lhs; \
  945.         }
  946.  
  947. // ****************************************************************************
  948. // ****************************************************************************
  949. //
  950. // Platform includes
  951. //
  952. // ****************************************************************************
  953. // ****************************************************************************
  954. #if defined(FPL_PLATFORM_WIN32)
  955. // @NOTE(final): windef.h defines min/max macros defined in lowerspace, this will break for example std::min/max so we have to tell the header we dont want this!
  956. #   if !defined(NOMINMAX)
  957. #       define NOMINMAX
  958. #   endif
  959. // @NOTE(final): For now we dont want any network, com or gdi stuff at all, maybe later who knows.
  960. #   if !defined(WIN32_LEAN_AND_MEAN)
  961. #       define WIN32_LEAN_AND_MEAN 1
  962. #   endif
  963. #   include <windows.h>     // Win32 api, its unfortunate we have to include this in the header as well, but there are structures
  964. #endif // FPL_PLATFORM_WIN32
  965.  
  966. #if defined(FPL_SUBPLATFORM_POSIX)
  967. #   include <pthread.h> // pthread_t, pthread_mutex_, pthread_cond_, pthread_barrier_
  968. #endif // FPL_SUBPLATFORM_POSIX
  969.  
  970. #if defined(FPL_SUBPLATFORM_X11)
  971. #   include <X11/X.h> // Window
  972. #   include <X11/Xlib.h> // Display
  973. #   undef None
  974. #   undef Success
  975. #endif // FPL_SUBPLATFORM_X11
  976.  
  977. // ****************************************************************************
  978. // ****************************************************************************
  979. //
  980. // API Declaration
  981. //
  982. // ****************************************************************************
  983. // ****************************************************************************
  984.  
  985. //! Core
  986. namespace fpl {
  987.     //! Atomic functions
  988.     namespace atomics {
  989.         /**
  990.           * \defgroup Atomics Atomic functions
  991.           * \brief Atomic functions, like AtomicCompareAndExchange, AtomicReadFence, etc.
  992.           * \{
  993.           */
  994.  
  995.         /**
  996.           * \brief Insert a memory read fence/barrier.
  997.           *
  998.           * This will complete previous reads before future reads and prevents the compiler from reordering memory reads across this fence.
  999.           */
  1000.         fpl_platform_api void AtomicReadFence();
  1001.         /**
  1002.           * \brief Insert a memory write fence/barrier.
  1003.           * This will complete previous writes before future writes and prevents the compiler from reordering memory writes across this fence.
  1004.           */
  1005.         fpl_platform_api void AtomicWriteFence();
  1006.         /**
  1007.           * \brief Insert a memory read/write fence/barrier.
  1008.           * This will complete previous reads/writes before future reads/writes and prevents the compiler from reordering memory access across this fence.
  1009.           */
  1010.         fpl_platform_api void AtomicReadWriteFence();
  1011.  
  1012.         /**
  1013.           * \brief Replace a 32-bit unsigned integer with the given value atomically.
  1014.           * Ensures that memory operations are completed in order.
  1015.           * \param target The target value to write into.
  1016.           * \param value The source value used for exchange.
  1017.           * \return Returns the initial value before the replacement.
  1018.           */
  1019.         fpl_platform_api uint32_t AtomicExchangeU32(volatile uint32_t *target, const uint32_t value);
  1020.         /**
  1021.           * \brief Replace a 64-bit unsigned integer with the given value atomically.
  1022.           * Ensures that memory operations are completed in order.
  1023.           * \param target The target value to write into.
  1024.           * \param value The source value used for exchange.
  1025.           * \return Returns the initial value before the replacement.
  1026.           */
  1027.         fpl_platform_api uint64_t AtomicExchangeU64(volatile uint64_t *target, const uint64_t value);
  1028.         /**
  1029.           * \brief Replace a 32-bit signed integer with the given value atomically.
  1030.           * Ensures that memory operations are completed in order.
  1031.           * \param target The target value to write into.
  1032.           * \param value The source value used for exchange.
  1033.           * \return Returns the initial value before the replacement.
  1034.           */
  1035.         fpl_platform_api int32_t AtomicExchangeS32(volatile int32_t *target, const int32_t value);
  1036.         /**
  1037.           * \brief Replace a 64-bit signed integer with the given value atomically.
  1038.           * Ensures that memory operations are completed in order.
  1039.           * \param target The target value to write into.
  1040.           * \param value The source value used for exchange.
  1041.           * \return Returns the initial value before the replacement.
  1042.           */
  1043.         fpl_platform_api int64_t AtomicExchangeS64(volatile int64_t *target, const int64_t value);
  1044.         /**
  1045.           * \brief Replace a pointer with the given value atomically.
  1046.           * Ensures that memory operations are completed in order.
  1047.           * \param target The target value to write into.
  1048.           * \param value The source value used for exchange.
  1049.           * \return Returns the initial value before the replacement.
  1050.           */
  1051.         fpl_common_api void *AtomicExchangePtr(volatile void **target, const void *value);
  1052.  
  1053.         /**
  1054.           * \brief Adds a 32-bit unsigned integer to the value by the given addend atomically.
  1055.           * Ensures that memory operations are completed in order.
  1056.           * \param value The target value to append to.
  1057.           * \param addend The value used for adding.
  1058.           * \return Returns the initial value before the append.
  1059.           */
  1060.         fpl_platform_api uint32_t AtomicAddU32(volatile uint32_t *value, const uint32_t addend);
  1061.         /**
  1062.           * \brief Adds a 64-bit unsigned integer to the value by the given addend atomically.
  1063.           * Ensures that memory operations are completed in order.
  1064.           * \param value The target value to append to.
  1065.           * \param addend The value used for adding.
  1066.           * \return Returns the initial value before the append.
  1067.           */
  1068.         fpl_platform_api uint64_t AtomicAddU64(volatile uint64_t *value, const uint64_t addend);
  1069.         /**
  1070.           * \brief Adds a 32-bit signed integer to the value by the given addend atomically.
  1071.           * Ensures that memory operations are completed in order.
  1072.           * \param value The target value to append to.
  1073.           * \param addend The value used for adding.
  1074.           * \return Returns the initial value before the append.
  1075.           */
  1076.         fpl_platform_api int32_t AtomicAddS32(volatile int32_t *value, const int32_t addend);
  1077.         /**
  1078.           * \brief Adds a 64-bit signed integer to the value by the given addend atomically.
  1079.           * Ensures that memory operations are completed in order.
  1080.           * \param value The target value to append to.
  1081.           * \param addend The value used for adding.
  1082.           * \return Returns the initial value before the append.
  1083.           */
  1084.         fpl_platform_api int64_t AtomicAddS64(volatile int64_t *value, const int64_t addend);
  1085.  
  1086.         /**
  1087.           * \brief Compares a 32-bit unsigned integer with a comparand and exchange it when comparand matches destination.
  1088.           * Ensures that memory operations are completed in order.
  1089.           * \param dest The target value to write into.
  1090.           * \param comparand The value to compare with.
  1091.           * \param exchange The value to exchange with.
  1092.           * \note Use \ref IsAtomicCompareAndExchangeU32() when you want to check if the exchange has happened or not.
  1093.           * \return Returns the dest before the exchange, regardless of the result.
  1094.           */
  1095.         fpl_platform_api uint32_t AtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange);
  1096.         /**
  1097.           * \brief Compares a 64-bit unsigned integer with a comparand and exchange it when comparand matches destination.
  1098.           * Ensures that memory operations are completed in order.
  1099.           * \param dest The target value to write into.
  1100.           * \param comparand The value to compare with.
  1101.           * \param exchange The value to exchange with.
  1102.           * \note Use \ref IsAtomicCompareAndExchangeU64() when you want to check if the exchange has happened or not.
  1103.           * \return Returns the value of the destination before the exchange, regardless of the result.
  1104.           */
  1105.         fpl_platform_api uint64_t AtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange);
  1106.         /**
  1107.           * \brief Compares a 32-bit signed integer with a comparand and exchange it when comparand matches destination.
  1108.           * Ensures that memory operations are completed in order.
  1109.           * \param dest The target value to write into.
  1110.           * \param comparand The value to compare with.
  1111.           * \param exchange The value to exchange with.
  1112.           * \note Use \ref IsAtomicCompareAndExchangeS32() when you want to check if the exchange has happened or not.
  1113.           * \return Returns the value of the destination before the exchange, regardless of the result.
  1114.           */
  1115.         fpl_platform_api int32_t AtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange);
  1116.         /**
  1117.           * \brief Compares a 64-bit signed integer with a comparand and exchange it when comparand matches destination.
  1118.           * Ensures that memory operations are completed in order.
  1119.           * \param dest The target value to write into.
  1120.           * \param comparand The value to compare with.
  1121.           * \param exchange The value to exchange with.
  1122.           * \note Use \ref IsAtomicCompareAndExchangeS64() when you want to check if the exchange has happened or not.
  1123.           * \return Returns the value of the destination before the exchange, regardless of the result.
  1124.           */
  1125.         fpl_platform_api int64_t AtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange);
  1126.         /**
  1127.           * \brief Compares a pointer with a comparand and exchange it when comparand matches destination.
  1128.           * Ensures that memory operations are completed in order.
  1129.           * \param dest The target value to write into.
  1130.           * \param comparand The value to compare with.
  1131.           * \param exchange The value to exchange with.
  1132.           * \note Use \ref IsAtomicCompareAndExchangePtr() when you want to check if the exchange has happened or not.
  1133.           * \return Returns the value of the destination before the exchange, regardless of the result.
  1134.           */
  1135.         fpl_common_api void *AtomicCompareAndExchangePtr(volatile void **dest, const void *comparand, const void *exchange);
  1136.  
  1137.         /**
  1138.           * \brief Compares a 32-bit unsigned integer with a comparand and exchange it when comparand matches destination and returns a bool indicating the result.
  1139.           * Ensures that memory operations are completed in order.
  1140.           * \param dest The target value to write into.
  1141.           * \param comparand The value to compare with.
  1142.           * \param exchange The value to exchange with.
  1143.           * \return Returns true when the exchange happened, otherwise false.
  1144.           */
  1145.         fpl_platform_api bool IsAtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange);
  1146.         /**
  1147.           * \brief Compares a 64-bit unsigned integer with a comparand and exchange it when comparand matches destination and returns a bool indicating the result.
  1148.           * Ensures that memory operations are completed in order.
  1149.           * \param dest The target value to write into.
  1150.           * \param comparand The value to compare with.
  1151.           * \param exchange The value to exchange with.
  1152.           * \return Returns true when the exchange happened, otherwise false.
  1153.           */
  1154.         fpl_platform_api bool IsAtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange);
  1155.         /**
  1156.           * \brief Compares a 32-bit signed integer with a comparand and exchange it when comparand matches destination and returns a bool indicating the result.
  1157.           * Ensures that memory operations are completed in order.
  1158.           * \param dest The target value to write into.
  1159.           * \param comparand The value to compare with.
  1160.           * \param exchange The value to exchange with.
  1161.           * \return Returns true when the exchange happened, otherwise false.
  1162.           */
  1163.         fpl_platform_api bool IsAtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange);
  1164.         /**
  1165.           * \brief Compares a 64-bit signed integer with a comparand and exchange it when comparand matches destination and returns a bool indicating the result.
  1166.           * Ensures that memory operations are completed in order.
  1167.           * \param dest The target value to write into.
  1168.           * \param comparand The value to compare with.
  1169.           * \param exchange The value to exchange with.
  1170.           * \return Returns true when the exchange happened, otherwise false.
  1171.           */
  1172.         fpl_platform_api bool IsAtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange);
  1173.         /**
  1174.           * \brief Compares a pointer with a comparand and exchange it when comparand matches destination and returns a bool indicating the result.
  1175.           * Ensures that memory operations are completed in order.
  1176.           * \param dest The target value to write into.
  1177.           * \param comparand The value to compare with.
  1178.           * \param exchange The value to exchange with.
  1179.           * \return Returns true when the exchange happened, otherwise false.
  1180.           */
  1181.         fpl_common_api bool IsAtomicCompareAndExchangePtr(volatile void **dest, const void *comparand, const void *exchange);
  1182.  
  1183.         /**
  1184.           * \brief Loads the 32-bit unsigned value atomically and returns the value.
  1185.           * Ensures that memory operations are completed before the read.
  1186.           * \param source The source value to read from.
  1187.           * \note This may use a CAS instruction when there is no suitable compiler intrinsics found.
  1188.           * \return Returns the source value.
  1189.           */
  1190.         fpl_platform_api uint32_t AtomicLoadU32(volatile uint32_t *source);
  1191.         /**
  1192.           * \brief Loads the 64-bit unsigned value atomically and returns the value.
  1193.           * Ensures that memory operations are completed before the read.
  1194.           * \param source The source value to read from.
  1195.           * \note This may use a CAS instruction when there is no suitable compiler intrinsics found.
  1196.           * \return Returns the source value.
  1197.           */
  1198.         fpl_platform_api uint64_t AtomicLoadU64(volatile uint64_t *source);
  1199.         /**
  1200.           * \brief Loads the 32-bit signed value atomically and returns the value.
  1201.           * Ensures that memory operations are completed before the read.
  1202.           * \param source The source value to read from.
  1203.           * \note This may use a CAS instruction when there is no suitable compiler intrinsics found.
  1204.           * \return Returns the source value.
  1205.           */
  1206.         fpl_platform_api int32_t AtomicLoadS32(volatile int32_t *source);
  1207.         /**
  1208.           * \brief Loads the 64-bit signed value atomically and returns the value.
  1209.           * Ensures that memory operations are completed before the read.
  1210.           * \param source The source value to read from.
  1211.           * \note This may use a CAS instruction when there is no suitable compiler intrinsics found.
  1212.           * \return Returns the source value.
  1213.           */
  1214.         fpl_platform_api int64_t AtomicLoadS64(volatile int64_t *source);
  1215.         /**
  1216.           * \brief Loads the pointer value atomically and returns the value.
  1217.           * Ensures that memory operations are completed before the read.
  1218.           * \param source The source value to read from.
  1219.           * \note This may use a CAS instruction when there is no suitable compiler intrinsics found.
  1220.           * \return Returns the source value.
  1221.           */
  1222.         fpl_common_api void *AtomicLoadPtr(volatile void **source);
  1223.  
  1224.         /**
  1225.           * \brief Overwrites the 32-bit unsigned value atomically.
  1226.           * Ensures that memory operations are completed before the write.
  1227.           * \param dest The destination to write to.
  1228.           * \param value The value to exchange with.
  1229.           * \return Returns the source value.
  1230.           */
  1231.         fpl_platform_api void AtomicStoreU32(volatile uint32_t *dest, const uint32_t value);
  1232.         /**
  1233.           * \brief Overwrites the 64-bit unsigned value atomically.
  1234.           * Ensures that memory operations are completed before the write.
  1235.           * \param dest The destination to write to.
  1236.           * \param value The value to exchange with.
  1237.           * \return Returns the source value.
  1238.           */
  1239.         fpl_platform_api void AtomicStoreU64(volatile uint64_t *dest, const uint64_t value);
  1240.         /**
  1241.           * \brief Overwrites the 32-bit signed value atomically.
  1242.           * Ensures that memory operations are completed before the write.
  1243.           * \param dest The destination to write to.
  1244.           * \param value The value to exchange with.
  1245.           * \return Returns the source value.
  1246.           */
  1247.         fpl_platform_api void AtomicStoreS32(volatile int32_t *dest, const int32_t value);
  1248.         /**
  1249.           * \brief Overwrites the 64-bit signed value atomically.
  1250.           * Ensures that memory operations are completed before the write.
  1251.           * \param dest The destination to write to.
  1252.           * \param value The value to exchange with.
  1253.           * \return Returns the source value.
  1254.           */
  1255.         fpl_platform_api void AtomicStoreS64(volatile int64_t *dest, const int64_t value);
  1256.         /**
  1257.           * \brief Overwrites the pointer value atomically.
  1258.           * Ensures that memory operations are completed before the write.
  1259.           * \param dest The destination to write to.
  1260.           * \param value The value to exchange with.
  1261.           * \return Returns the source value.
  1262.           */
  1263.         fpl_common_api void AtomicStorePtr(volatile void **dest, const void *value);
  1264.  
  1265.         /** \}*/
  1266.     }
  1267.  
  1268.     //! Hardware functions
  1269.     namespace hardware {
  1270.         /**
  1271.           * \defgroup Hardware Hardware functions
  1272.           * \brief Hardware functions, like GetProcessorCoreCount, GetProcessorName, etc.
  1273.           * \{
  1274.           */
  1275.  
  1276.           //! Memory informations
  1277.         struct MemoryInfos {
  1278.             //! Total size of physical memory in bytes (Amount of RAM installed)
  1279.             uint64_t totalPhysicalSize;
  1280.             //! Available size of physical memory in bytes (May be less than the amount of RAM installed)
  1281.             uint64_t availablePhysicalSize;
  1282.             //! Free size of physical memory in bytes
  1283.             uint64_t usedPhysicalSize;
  1284.             //! Total size of virtual memory in bytes
  1285.             uint64_t totalVirtualSize;
  1286.             //! Used size of virtual memory in bytes
  1287.             uint64_t usedVirtualSize;
  1288.             //! Total page size in bytes
  1289.             uint64_t totalPageSize;
  1290.             //! Used page size in bytes
  1291.             uint64_t usedPageSize;
  1292.         };
  1293.  
  1294.         /**
  1295.           * \brief Returns the total number of processor cores.
  1296.           * \return Number of processor cores.
  1297.           */
  1298.         fpl_platform_api uint32_t GetProcessorCoreCount();
  1299.         /**
  1300.           * \brief Returns the name of the processor.
  1301.           * The processor name is written in the destination buffer.
  1302.           * \param destBuffer The character buffer to write the processor name into.
  1303.           * \param maxDestBufferLen The total number of characters available in the destination character buffer.
  1304.           * \return Name of the processor.
  1305.           */
  1306.         fpl_platform_api char *GetProcessorName(char *destBuffer, const uint32_t maxDestBufferLen);
  1307.         /**
  1308.           * \brief Returns the current system memory informations.
  1309.           * \return Current system memory informations.
  1310.           */
  1311.         fpl_platform_api MemoryInfos GetSystemMemoryInfos();
  1312.  
  1313.         /** \}*/
  1314.     }
  1315.  
  1316.     /**
  1317.       * \defgroup Settings Settings and configurations
  1318.       * \brief Video/audio/window settings
  1319.       * \{
  1320.       */
  1321.  
  1322.     //! Initialization flags (Window, Video, etc.)
  1323.     enum class InitFlags : int {
  1324.         //! No init flags
  1325.         None = 0,
  1326.         //! Create a single window
  1327.         Window = 1 << 0,
  1328.         //! Use a video backbuffer (This flag ensures that \ref InitFlags::Window is included always)
  1329.         Video = 1 << 1,
  1330.         //! Use asyncronous audio playback
  1331.         Audio = 1 << 2,
  1332.         //! Default init flags for initializing everything
  1333.         All = Window | Video | Audio
  1334.     };
  1335.     //! Operator support for InitFlags
  1336.     FPL_ENUM_AS_FLAGS_OPERATORS(InitFlags);
  1337.  
  1338.     //! Video driver type
  1339.     enum class VideoDriverType {
  1340.         //! No video driver
  1341.         None,
  1342.         //! OpenGL
  1343.         OpenGL,
  1344.         //! Software
  1345.         Software
  1346.     };
  1347.  
  1348. #if defined(FPL_ENABLE_VIDEO_OPENGL)
  1349.     //! OpenGL compability flags
  1350.     enum class OpenGLCompabilityFlags : uint32_t {
  1351.         //! Use legacy context
  1352.         Legacy = 0,
  1353.         //! Use core profile
  1354.         Core = 1 << 1,
  1355.         //! Use compability profile
  1356.         Compability = 1 << 2,
  1357.         //! Remove features marked as deprecated
  1358.         Forward = 1 << 3,
  1359.     };
  1360.     //! Defines the operator overloads for a enum used as flags
  1361.     FPL_ENUM_AS_FLAGS_OPERATORS(OpenGLCompabilityFlags);
  1362.  
  1363.     //! OpenGL video settings container
  1364.     struct OpenGLVideoSettings {
  1365.         //! Compability flags
  1366.         OpenGLCompabilityFlags compabilityFlags;
  1367.         //! Desired major version
  1368.         uint32_t majorVersion;
  1369.         //! Desired minor version
  1370.         uint32_t minorVersion;
  1371.     };
  1372. #endif // FPL_ENABLE_VIDEO_OPENGL
  1373.  
  1374.     //! Graphics API settings union
  1375.     union GraphicsAPISettings {
  1376. #   if defined(FPL_ENABLE_VIDEO_OPENGL)
  1377.         //! OpenGL settings
  1378.         OpenGLVideoSettings opengl;
  1379. #   endif
  1380.     };
  1381.  
  1382.     //! Video settings container (Driver, Flags, Version, VSync, etc.)
  1383.     struct VideoSettings {
  1384.         //! Video driver type
  1385.         VideoDriverType driver;
  1386.         //! Vertical syncronisation enabled/disabled
  1387.         bool isVSync;
  1388.         //! Backbuffer size is automatically resized. Useable only for software rendering!
  1389.         bool isAutoSize;
  1390.         //! Graphics API settings
  1391.         GraphicsAPISettings graphics;
  1392.     };
  1393.  
  1394.     /**
  1395.       * \brief Make default video settings
  1396.       * \note This will not change any video settings! To change the actual settings you have to pass the entire \ref Settings container to a argument in \ref InitPlatform().
  1397.       */
  1398.     fpl_inline VideoSettings DefaultVideoSettings() {
  1399.         VideoSettings result = {};
  1400.  
  1401.         result.isVSync = false;
  1402.         result.isAutoSize = true;
  1403.  
  1404.         // @NOTE(final): Auto detect video driver
  1405. #   if defined(FPL_ENABLE_VIDEO_OPENGL)
  1406.         result.driver = VideoDriverType::OpenGL;
  1407.         result.graphics.opengl.compabilityFlags = OpenGLCompabilityFlags::Legacy;
  1408. #   elif defined(FPL_ENABLE_VIDEO_SOFTWARE)
  1409.         result.driver = VideoDriverType::Software;
  1410. #   else
  1411.         result.driver = VideoDriverType::None;
  1412. #   endif
  1413.  
  1414.         return(result);
  1415.     }
  1416.  
  1417.     //! Audio driver type
  1418.     enum class AudioDriverType {
  1419.         //! No audio driver
  1420.         None,
  1421.         //! Auto detection
  1422.         Auto,
  1423.         //! DirectSound
  1424.         DirectSound,
  1425.     };
  1426.  
  1427.     //! Audio format type
  1428.     enum class AudioFormatType : uint32_t {
  1429.         // No audio format
  1430.         None,
  1431.         // Unsigned 8-bit integer PCM
  1432.         U8,
  1433.         // Signed 16-bit integer PCM
  1434.         S16,
  1435.         // Signed 24-bit integer PCM
  1436.         S24,
  1437.         // Signed 32-bit integer PCM
  1438.         S32,
  1439.         // Signed 64-bit integer PCM
  1440.         S64,
  1441.         // 32-bit IEEE_FLOAT
  1442.         F32,
  1443.         // 64-bit IEEE_FLOAT
  1444.         F64,
  1445.     };
  1446.  
  1447.     //! Audio device format
  1448.     struct AudioDeviceFormat {
  1449.         //! Audio format
  1450.         AudioFormatType type;
  1451.         //! Samples per seconds
  1452.         uint32_t sampleRate;
  1453.         //! Number of channels
  1454.         uint32_t channels;
  1455.         //! Number of periods
  1456.         uint32_t periods;
  1457.         //! Buffer size for the device
  1458.         uint32_t bufferSizeInBytes;
  1459.         //! Buffer size in frames
  1460.         uint32_t bufferSizeInFrames;
  1461.     };
  1462.  
  1463.     //! Audio device id union
  1464.     union AudioDeviceID {
  1465. #   if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  1466.         //! DirectShow Device GUID
  1467.         GUID dshow;
  1468. #   endif
  1469.     };
  1470.  
  1471.     //! Audio device info
  1472.     struct AudioDeviceInfo {
  1473.         //! Device name
  1474.         char name[256];
  1475.         //! Device id
  1476.         AudioDeviceID id;
  1477.     };
  1478.  
  1479.     //! Audio Client Read Callback Function
  1480.     typedef uint32_t(AudioClientReadFunction)(const AudioDeviceFormat &deviceFormat, const uint32_t frameCount, void *outputSamples, void *userData);
  1481.  
  1482.     //! Audio settings
  1483.     struct AudioSettings {
  1484.         //! The device format
  1485.         AudioDeviceFormat deviceFormat;
  1486.         //! The device info
  1487.         AudioDeviceInfo deviceInfo;
  1488.         //! The callback for retrieving audio data from the client
  1489.         AudioClientReadFunction *clientReadCallback;
  1490.         //! The targeted driver
  1491.         AudioDriverType driver;
  1492.         //! Audio buffer in milliseconds
  1493.         uint32_t bufferSizeInMilliSeconds;
  1494.         //! Is exclude mode prefered
  1495.         bool preferExclusiveMode;
  1496.         //! User data pointer for client read callback
  1497.         void *userData;
  1498.     };
  1499.  
  1500.     /**
  1501.       * \brief Make default audio settings (S16 PCM, 48 KHz, 2 Channels)
  1502.       * \note This will not change any audio settings! To change the actual settings you have to pass the entire \ref Settings container to a argument in \ref InitPlatform().
  1503.       */
  1504.     fpl_inline AudioSettings DefaultAudioSettings() {
  1505.         AudioSettings result = {};
  1506.         result.bufferSizeInMilliSeconds = 25;
  1507.         result.preferExclusiveMode = false;
  1508.         result.deviceFormat.channels = 2;
  1509.         result.deviceFormat.sampleRate = 48000;
  1510.         result.deviceFormat.type = AudioFormatType::S16;
  1511.  
  1512.         result.driver = AudioDriverType::None;
  1513. #   if defined(FPL_PLATFORM_WIN32)
  1514. #       if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  1515.         result.driver = AudioDriverType::DirectSound;
  1516. #       endif
  1517. #   endif
  1518.         return(result);
  1519.     }
  1520.  
  1521.     //! Window settings (Size, Title etc.)
  1522.     struct WindowSettings {
  1523.         //! Window title
  1524.         char windowTitle[256];
  1525.         //! Window width in screen coordinates
  1526.         uint32_t windowWidth;
  1527.         //! Window height in screen coordinates
  1528.         uint32_t windowHeight;
  1529.         //! Fullscreen width in screen coordinates
  1530.         uint32_t fullscreenWidth;
  1531.         //! Fullscreen height in screen coordinates
  1532.         uint32_t fullscreenHeight;
  1533.         //! Is window resizable
  1534.         bool isResizable;
  1535.         //! Is window in fullscreen mode
  1536.         bool isFullscreen;
  1537.     };
  1538.  
  1539.     /**
  1540.       * \brief Make default settings for the window
  1541.       * \note This will not change any window settings! To change the actual settings you have to pass the entire \ref Settings container to a argument in \ref InitPlatform().
  1542.       */
  1543.     fpl_inline WindowSettings DefaultWindowSettings() {
  1544.         WindowSettings result = {};
  1545.         result.windowTitle[0] = 0;
  1546.         result.windowWidth = 800;
  1547.         result.windowHeight = 600;
  1548.         result.fullscreenWidth = 0;
  1549.         result.fullscreenHeight = 0;
  1550.         result.isResizable = true;
  1551.         result.isFullscreen = false;
  1552.         return(result);
  1553.     }
  1554.  
  1555.     //! Input settings
  1556.     struct InputSettings {
  1557.         //! Frequency in ms for detecting new or removed controllers (Default: 100 ms)
  1558.         uint32_t controllerDetectionFrequency;
  1559.     };
  1560.  
  1561.     /**
  1562.       * \brief Make default settings for input devices.
  1563.       * \note This will not change any input settings! To change the actual settings you have to pass the entire \ref Settings container to a argument in \ref InitPlatform().
  1564.       */
  1565.     fpl_inline InputSettings DefaultInputSettings() {
  1566.         InputSettings result = {};
  1567.         result.controllerDetectionFrequency = 100;
  1568.         return(result);
  1569.     }
  1570.  
  1571.     //! Settings container (Window, Video, etc)
  1572.     struct Settings {
  1573.         //! Window settings
  1574.         WindowSettings window;
  1575.         //! Video settings
  1576.         VideoSettings video;
  1577.         //! Audio settings
  1578.         AudioSettings audio;
  1579.         //! Input settings
  1580.         InputSettings input;
  1581.     };
  1582.  
  1583.     /**
  1584.       * \brief Make default settings for window, video, audio, etc.
  1585.       * \note This will not change any settings! To change the actual settings you have to pass this settings container to a argument in \ref InitPlatform().
  1586.       */
  1587.     fpl_inline Settings DefaultSettings() {
  1588.         Settings result = {};
  1589.         result.window = DefaultWindowSettings();
  1590.         result.video = DefaultVideoSettings();
  1591.         result.audio = DefaultAudioSettings();
  1592.         result.input = DefaultInputSettings();
  1593.         return(result);
  1594.     }
  1595.  
  1596.     /**
  1597.       * \brief Returns the current settings
  1598.       */
  1599.     fpl_common_api const Settings &GetCurrentSettings();
  1600.  
  1601.     /** \}*/
  1602.  
  1603.     /**
  1604.       * \defgroup Initialization Initialization functions
  1605.       * \brief Initialization and release functions
  1606.       * \{
  1607.       */
  1608.  
  1609.     /**
  1610.       * \brief Initializes the platform layer.
  1611.       * \param initFlags Optional init flags used for enable certain features, like video/audio etc. (Default: \ref InitFlags::All)
  1612.       * \param initSettings Optional initialization settings which can be passed to control the platform layer behavior or systems. (Default: \ref Settings provided by \ref DefaultSettings())
  1613.       * \note \ref ReleasePlatform() must be called when you are done! After \ref ReleasePlatform() has been called you can call this function again if needed.
  1614.       * \return Returns true when the initialzation was successful, otherwise false. Will return false when the platform layers is already initialized successfully.
  1615.       */
  1616.     fpl_common_api bool InitPlatform(const InitFlags initFlags = InitFlags::All, const Settings &initSettings = DefaultSettings());
  1617.     /**
  1618.       * \brief Releases the resources allocated by the platform layer.
  1619.       * \note Can only be called when \ref InitPlatform() was successful.
  1620.       */
  1621.     fpl_common_api void ReleasePlatform();
  1622.  
  1623.     /** \}*/
  1624.  
  1625.     /**
  1626.       * \defgroup ErrorHandling Error Handling
  1627.       * \brief Functions for error handling
  1628.       * \{
  1629.       */
  1630.  
  1631.       /**
  1632.         * \brief Returns the last internal error string
  1633.         * \note This function can be called regardless of the initialization state!
  1634.         * \return Last error string or empty string when there was no error.
  1635.         */
  1636.     fpl_common_api const char *GetPlatformError();
  1637.     /**
  1638.       * \brief Returns the last error string from the given index
  1639.       * \param index The index
  1640.       * \note This function can be called regardless of the initialization state!
  1641.       * \return Last error string from the given index or empty when there was no error.
  1642.       */
  1643.     fpl_common_api const char *GetPlatformError(const size_t index);
  1644.     /**
  1645.       * \brief Returns the count of total last errors
  1646.       * \note This function can be called regardless of the initialization state!
  1647.       * \return Number of last errors or zero when there was no error.
  1648.       */
  1649.     fpl_common_api size_t GetPlatformErrorCount();
  1650.     /**
  1651.       * \brief Clears all the current errors in the platform
  1652.       * \note This function can be called regardless of the initialization state!
  1653.       */
  1654.     fpl_common_api void ClearPlatformErrors();
  1655.  
  1656.     /** \}*/
  1657.  
  1658.     //! Dynamic library functions and types
  1659.     namespace library {
  1660.         /**
  1661.           * \defgroup DynamicLibrary Dynamic library loading
  1662.           * \brief Loading dynamic libraries and retrieving the procedure addresses.
  1663.           * \{
  1664.           */
  1665.  
  1666.         //! Internal library handle union
  1667.         union InternalDynamicLibraryHandle {
  1668. #       if defined(FPL_PLATFORM_WIN32)
  1669.             //! Win32 library handle
  1670.             HMODULE win32LibraryHandle;
  1671. #       elif defined(FPL_SUBPLATFORM_POSIX)
  1672.             //! Posix library handle
  1673.             void *posixLibraryHandle;
  1674. #       endif
  1675.         };
  1676.  
  1677.           //! Handle to a loaded dynamic library
  1678.         struct DynamicLibraryHandle {
  1679.             //! Internal library handle
  1680.             InternalDynamicLibraryHandle internalHandle;
  1681.             //! Library opened successfully
  1682.             bool isValid;
  1683.         };
  1684.  
  1685.         /**
  1686.           * \brief Loads a dynamic library and returns the loaded handle for it.
  1687.           * \param libraryFilePath The path to the library with included file extension (.dll / .so)
  1688.           * \note To check for success, just check the DynamicLibraryHandle.isValid field from the result.
  1689.           * \return Handle container of the loaded library.
  1690.           */
  1691.         fpl_platform_api DynamicLibraryHandle DynamicLibraryLoad(const char *libraryFilePath);
  1692.         /**
  1693.           * \brief Returns the dynamic library procedure address for the given procedure name.
  1694.           * \param handle Handle to the loaded library
  1695.           * \param name Name of the procedure
  1696.           * \return Procedure address for the given procedure name or nullptr when procedure not found or library is not loaded.
  1697.           */
  1698.         fpl_platform_api void *GetDynamicLibraryProc(const DynamicLibraryHandle &handle, const char *name);
  1699.         /**
  1700.           * \brief Unloads the loaded library and resets the handle to zero.
  1701.           * \param handle Loaded dynamic library handle
  1702.           */
  1703.         fpl_platform_api void DynamicLibraryUnload(DynamicLibraryHandle &handle);
  1704.  
  1705.         /** \}*/
  1706.     }
  1707.  
  1708.     //! Console functions
  1709.     namespace console {
  1710.         /**
  1711.           * \defgroup Console Console functions
  1712.           * \brief Console out/in functions
  1713.           * \{
  1714.           */
  1715.  
  1716.           /**
  1717.             * \brief Writes the given text to the standard output console buffer.
  1718.             * \param text The text to write into standard output console.
  1719.             * \note This is most likely just a wrapper call to fprintf(stdout)
  1720.             */
  1721.         fpl_platform_api void ConsoleOut(const char *text);
  1722.         /**
  1723.           * \brief Writes the given formatted text to the standard output console buffer.
  1724.           * \param format The format used for writing into the standard output console.
  1725.           * \param ... The dynamic arguments used for formatting the text.
  1726.           * \note This is most likely just a wrapper call to vfprintf(stdout)
  1727.           */
  1728.         fpl_platform_api void ConsoleFormatOut(const char *format, ...);
  1729.         /**
  1730.           * \brief Writes the given text to the standard error console buffer.
  1731.           * \param text The text to write into standard error console.
  1732.           * \note This is most likely just a wrapper call to fprintf(stderr)
  1733.           */
  1734.         fpl_platform_api void ConsoleError(const char *text);
  1735.         /**
  1736.           * \brief Writes the given formatted text to the standard error console buffer.
  1737.           * \param format The format used for writing into the standard error console.
  1738.           * \param ... The dynamic arguments used for formatting the text.
  1739.           * \note This is most likely just a wrapper call to vfprintf(stderr)
  1740.           */
  1741.         fpl_platform_api void ConsoleFormatError(const char *format, ...);
  1742.         /**
  1743.           * \brief Wait for a character to be typed in the console input and return it
  1744.           * \note This is most likely just a wrapper call to getchar()
  1745.           * \return Character typed in in the console input
  1746.           */
  1747.         fpl_platform_api const char ConsoleWaitForCharInput();
  1748.  
  1749.         /** \}*/
  1750.     }
  1751.  
  1752.     //! Threading functions
  1753.     namespace threading {
  1754.         /**
  1755.           * \defgroup Threading Threading routines
  1756.           * \brief Tons of functions for multithreading, mutex and signal creation and handling
  1757.           * \{
  1758.           */
  1759.  
  1760.           //! Thread state
  1761.         enum class ThreadState : uint32_t {
  1762.             //! Thread is stopped
  1763.             Stopped,
  1764.             //! Thread is being started
  1765.             Starting,
  1766.             //! Thread is still running
  1767.             Running,
  1768.             //! Thread is being stopped
  1769.             Stopping,
  1770.         };
  1771.  
  1772.         struct ThreadHandle;
  1773.         //! Run function type definition for CreateThread
  1774.         typedef void (run_thread_function)(const ThreadHandle &thread, void *data);
  1775.  
  1776. #   if defined(FPL_SUBPLATFORM_POSIX)
  1777.         //! Posix internal thread handle
  1778.         struct PosixInternalThreadHandle {
  1779.             //! Thread
  1780.             pthread_t thread;
  1781.             //! Mutex
  1782.             pthread_mutex_t mutex;
  1783.             //! Stop condition
  1784.             pthread_cond_t stopCondition;
  1785.         };
  1786. #   endif
  1787.  
  1788.         //! Internal thread handle union
  1789.         union InternalThreadHandle {
  1790. #       if defined(FPL_PLATFORM_WIN32)
  1791.             //! Win32 thread handle
  1792.             HANDLE win32ThreadHandle;
  1793. #       elif defined(FPL_SUBPLATFORM_POSIX)
  1794.             //! Posix thread handle
  1795.             PosixInternalThreadHandle posix;
  1796. #       endif
  1797.         };
  1798.  
  1799.         //! Thread handle
  1800.         struct ThreadHandle {
  1801.             //! The internal thread handle
  1802.             InternalThreadHandle internalHandle;
  1803.             //! The identifier of the thread
  1804.             uint64_t id;
  1805.             //! The stored run function
  1806.             run_thread_function *runFunc;
  1807.             //! The user data passed to the run function
  1808.             void *data;
  1809.             //! Thread state
  1810.             volatile ThreadState currentState;
  1811.             //! Is this thread valid
  1812.             volatile bool isValid;
  1813.             //! Is this thread stopping
  1814.             volatile bool isStopping;
  1815.         };
  1816.  
  1817.         //! Internal mutex handle union
  1818.         union InternalMutexHandle {
  1819. #       if defined(FPL_PLATFORM_WIN32)
  1820.             //! Win32 mutex handle
  1821.             CRITICAL_SECTION win32CriticalSection;
  1822. #       elif defined(FPL_SUBPLATFORM_POSIX)
  1823.             //! Posix mutex handle
  1824.             pthread_mutex_t posixMutex;
  1825. #       endif
  1826.         };
  1827.  
  1828.         //! Mutex handle
  1829.         struct MutexHandle {
  1830.             //! The internal mutex handle
  1831.             InternalMutexHandle internalHandle;
  1832.             //! Is it valid
  1833.             bool isValid;
  1834.         };
  1835.  
  1836.         //! Internal signal handle union
  1837.         union InternalSignalHandle {
  1838. #       if defined(FPL_PLATFORM_WIN32)
  1839.             //! Win32 event handle
  1840.             HANDLE win32EventHandle;
  1841. #       elif defined(FPL_SUBPLATFORM_POSIX)
  1842.             //! Posix condition
  1843.             pthread_cond_t posixCondition;
  1844. #       endif
  1845.         };
  1846.  
  1847.         //! Signal handle
  1848.         struct SignalHandle {
  1849.             //! The internal signal handle
  1850.             InternalSignalHandle internalHandle;
  1851.             //! Is it valid
  1852.             bool isValid;
  1853.         };
  1854.  
  1855.         //! Returns the current thread state from the given thread
  1856.         fpl_inline ThreadState GetThreadState(ThreadHandle *thread) {
  1857.             if(thread == nullptr) {
  1858.                 return ThreadState::Stopped;
  1859.             }
  1860.             ThreadState result = (ThreadState)atomics::AtomicLoadU32((volatile uint32_t *)&thread->currentState);
  1861.             return(result);
  1862.         }
  1863.  
  1864.         /**
  1865.           * \brief Creates a thread and return a handle to it.
  1866.           * \param runFunc Function prototype called when this thread starts.
  1867.           * \param data User data passed to the run function.
  1868.           * \note Use \ref ThreadDestroy() with this thread context when you dont need this thread anymore. You can only have 64 threads suspended/running at the same time!
  1869.           * \warning Do not free this thread context directly! Use \ref ThreadDestroy() instead.
  1870.           * \return Pointer to a internal stored thread-context or return nullptr when the limit of current threads has been reached.
  1871.           */
  1872.         fpl_platform_api ThreadHandle *ThreadCreate(run_thread_function *runFunc, void *data);
  1873.         /**
  1874.           * \brief Let the current thread sleep for the given amount of milliseconds.
  1875.           * \param milliseconds Number of milliseconds to sleep
  1876.           * \note There is no guarantee that the OS sleeps for the exact amount of milliseconds! This can vary based on the OS scheduler granularity.
  1877.           */
  1878.         fpl_platform_api void ThreadSleep(const uint32_t milliseconds);
  1879.         /**
  1880.           * \brief Stop the given thread and release all underlying resources.
  1881.           * \param thread Thread
  1882.           * \note This thread context may get re-used for another thread in the future!
  1883.           * \warning Do not free the given thread context manually!
  1884.           */
  1885.         fpl_platform_api void ThreadDestroy(ThreadHandle *thread);
  1886.         /**
  1887.           * \brief Wait until the given thread is done running or the given timeout has been reached.
  1888.           * \param thread Thread
  1889.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1890.           * \return Returns true when the thread completes or when the timeout has been reached.
  1891.           */
  1892.         fpl_platform_api bool ThreadWaitForOne(ThreadHandle *thread, const uint32_t maxMilliseconds = UINT32_MAX);
  1893.         /**
  1894.           * \brief Wait until all given threads are done running or the given timeout has been reached.
  1895.           * \param threads Array of threads
  1896.           * \param count Number of threads in the array
  1897.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1898.           * \return Returns true when all threads completes or when the timeout has been reached.
  1899.           */
  1900.         fpl_platform_api bool ThreadWaitForAll(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds = UINT32_MAX);
  1901.         /**
  1902.           * \brief Wait until one of given threads is done running or the given timeout has been reached.
  1903.           * \param threads Array of threads
  1904.           * \param count Number of threads in the array
  1905.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1906.           * \return Returns true when one thread completes or when the timeout has been reached.
  1907.           */
  1908.         fpl_platform_api bool ThreadWaitForAny(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds = UINT32_MAX);
  1909.  
  1910.         /**
  1911.           * \brief Creates a mutex and returns a copy of the handle to it.
  1912.           * \note Use \ref MutexDestroy() when you are done with this mutex.
  1913.           * \return Copy of the handle to the mutex.
  1914.           */
  1915.         fpl_platform_api MutexHandle MutexCreate();
  1916.         /**
  1917.           * \brief Releases the given mutex and clears the structure to zero.
  1918.           * \param mutex The mutex reference to destroy.
  1919.           */
  1920.         fpl_platform_api void MutexDestroy(MutexHandle &mutex);
  1921.         /**
  1922.           * \brief Locks the given mutex and ensures that other threads will wait until it gets unlocked or the timeout has been reached.
  1923.           * \param mutex The mutex reference to lock
  1924.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1925.           * \returns True when mutex was locked or false otherwise.
  1926.           */
  1927.         fpl_platform_api bool MutexLock(MutexHandle &mutex, const uint32_t maxMilliseconds = UINT32_MAX);
  1928.         /**
  1929.          * \brief Unlocks the given mutex
  1930.          * \param mutex The mutex reference to unlock
  1931.          * \returns True when mutex was unlocked or false otherwise.
  1932.          */
  1933.         fpl_platform_api bool MutexUnlock(MutexHandle &mutex);
  1934.  
  1935.         /**
  1936.           * \brief Creates a signal and returns a copy of the handle to it.
  1937.           * \note Use \ref SignalDestroy() when you are done with this signal.
  1938.           * \return Copy of the handle to the signal.
  1939.           */
  1940.         fpl_platform_api SignalHandle SignalCreate();
  1941.         /**
  1942.           * \brief Releases the given signal and clears the structure to zero.
  1943.           * \param signal The signal reference to destroy.
  1944.           */
  1945.         fpl_platform_api void SignalDestroy(SignalHandle &signal);
  1946.         /**
  1947.           * \brief Waits until the given signal are waked up.
  1948.           * \param mutex The mutex reference
  1949.           * \param signal The signal reference to signal.
  1950.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1951.           * \return Returns true when the signal woke up or the timeout has been reached, otherwise false.
  1952.           */
  1953.         fpl_platform_api bool SignalWaitForOne(MutexHandle &mutex, SignalHandle &signal, const uint32_t maxMilliseconds = UINT32_MAX);
  1954.         /**
  1955.           * \brief Waits until all the given signal are waked up.
  1956.           * \param mutex The mutex reference
  1957.           * \param signals Array of signals
  1958.           * \param count Number of signals
  1959.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1960.           * \return Returns true when all signals woke up or the timeout has been reached, otherwise false.
  1961.           */
  1962.         fpl_platform_api bool SignalWaitForAll(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds = UINT32_MAX);
  1963.         /**
  1964.           * \brief Waits until any of the given signals wakes up or the timeout has been reached.
  1965.           * \param mutex The mutex reference
  1966.           * \param signals Array of signals
  1967.           * \param count Number of signals
  1968.           * \param maxMilliseconds Optional number of milliseconds to wait. When this is set to UINT32_MAX it may wait infinitly. (Default: UINT32_MAX)
  1969.           * \return Returns true when any of the signals woke up or the timeout has been reached, otherwise false.
  1970.           */
  1971.         fpl_platform_api bool SignalWaitForAny(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds = UINT32_MAX);
  1972.         /**
  1973.           * \brief Sets the signal and wakes up the given signal.
  1974.           * \param signal The reference to the signal
  1975.           * \return Returns true when the signal was set and woke up, otherwise false.
  1976.           */
  1977.         fpl_platform_api bool SignalSet(SignalHandle &signal);
  1978.  
  1979.         /** \}*/
  1980.     }
  1981.  
  1982.     //! Memory allocation, clearing and copy functions
  1983.     namespace memory {
  1984.         /**
  1985.           * \defgroup Memory Memory functions
  1986.           * \brief Memory allocation, clearing and copy functions
  1987.           * \{
  1988.           */
  1989.  
  1990.           /**
  1991.             * \brief Clears the given memory by the given size to zero.
  1992.             * \param mem Pointer to the memory.
  1993.             * \param size Size in bytes to be cleared to zero.
  1994.             */
  1995.         fpl_common_api void MemoryClear(void *mem, const size_t size);
  1996.         /**
  1997.           * \brief Copies the given source memory with its length to the target memory.
  1998.           * \param sourceMem Pointer to the source memory to copy from.
  1999.           * \param sourceSize Size in bytes to be copied.
  2000.           * \param targetMem Pointer to the target memory to copy to.
  2001.           */
  2002.         fpl_common_api void MemoryCopy(void *sourceMem, const size_t sourceSize, void *targetMem);
  2003.         /**
  2004.           * \brief Allocates memory from the operating system by the given size.
  2005.           * \param size Size to by allocated in bytes.
  2006.           * \note The memory is guaranteed to be initialized by zero.
  2007.           * \warning Alignment is not ensured here, the OS decides how to handle this. If you want to force a specific alignment use \ref MemoryAlignedAllocate() instead.
  2008.           * \return Pointer to the new allocated memory.
  2009.           */
  2010.         fpl_platform_api void *MemoryAllocate(const size_t size);
  2011.         /**
  2012.           * \brief Releases the memory allocated from the operating system.
  2013.           * \param ptr Pointer to the allocated memory.
  2014.           * \warning This should never be called with a aligned memory pointer! For freeing aligned memory, use \ref MemoryAlignedFree() instead.
  2015.           * \return Pointer to the new allocated memory.
  2016.           */
  2017.         fpl_platform_api void MemoryFree(void *ptr);
  2018.         /**
  2019.           * \brief Allocates aligned memory from the operating system by the given alignment.
  2020.           * \param size Size amount in bytes
  2021.           * \param alignment Alignment in bytes (Needs to be a power-of-two!)
  2022.           * \note The memory is guaranteed to be initialized by zero.
  2023.           * \return Pointer to the new allocated aligned memory.
  2024.           */
  2025.         fpl_common_api void *MemoryAlignedAllocate(const size_t size, const size_t alignment);
  2026.         /**
  2027.           * \brief Releases the aligned memory allocated from the operating system.
  2028.           * \param ptr Pointer to the aligned allocated memory.
  2029.           * \warning This should never be called with a not-aligned memory pointer! For freeing not-aligned memory, use \ref MemoryFree() instead.
  2030.           * \return Pointer to the new allocated memory.
  2031.           */
  2032.         fpl_common_api void MemoryAlignedFree(void *ptr);
  2033.  
  2034.         /** \}*/
  2035.     }
  2036.  
  2037.     //! Timing and measurement functions
  2038.     namespace timings {
  2039.         /**
  2040.           * \defgroup Timings Timing functions
  2041.           * \brief Functions for retrieving timebased informations
  2042.           * \{
  2043.           */
  2044.  
  2045.         /**
  2046.           * \brief Returns the current system clock in seconds with the highest precision possible.
  2047.           * \return Returns number of second since some fixed starting point (OS start, System start, etc).
  2048.           * \note Can only be used to calculate a difference in time!
  2049.           */
  2050.         fpl_platform_api double GetHighResolutionTimeInSeconds();
  2051.  
  2052.         /**
  2053.           * \brief Returns the current system in milliseconds without deeper precision.
  2054.           * \return Returns number of milliseconds since some fixed starting point (OS start, System start, etc).
  2055.           * \note Can only be used to calculate a difference in time!
  2056.           */
  2057.         fpl_platform_api uint64_t GetTimeInMilliseconds();
  2058.  
  2059.         /** \}*/
  2060.     }
  2061.  
  2062.     //! String functions
  2063.     namespace strings {
  2064.         /**
  2065.           * \defgroup Strings String manipulation functions
  2066.           * \brief Functions for converting/manipulating strings
  2067.           * \{
  2068.           */
  2069.  
  2070.           /**
  2071.             * \brief Returns true when both ansi strings are equal with enforcing the given length.
  2072.             * \param a First string
  2073.             * \param aLen Number of characters for the first string
  2074.             * \param b Second string
  2075.             * \param bLen Number of characters for the second string
  2076.             * \note Len parameters does not include the null-terminator!
  2077.             * \return True when strings matches, otherwise false.
  2078.             */
  2079.         fpl_common_api bool IsStringEqual(const char *a, const uint32_t aLen, const char *b, const uint32_t bLen);
  2080.         /**
  2081.           * \brief Returns true when both ansi strings are equal.
  2082.           * \param a First string
  2083.           * \param b Second string
  2084.           * \return True when strings matches, otherwise false.
  2085.           */
  2086.         fpl_common_api bool IsStringEqual(const char *a, const char *b);
  2087.         /**
  2088.           * \brief Returns the number of characters of the given 8-bit Ansi string.
  2089.           * \param str The 8-bit ansi string
  2090.           * \note Null terminator is not included!
  2091.           * \return Returns the character length or zero when the input string is nullptr.
  2092.           */
  2093.         fpl_common_api uint32_t GetAnsiStringLength(const char *str);
  2094.         /**
  2095.           * \brief Returns the number of characters of the given 16-bit wide string.
  2096.           * \param str The 16-bit wide string
  2097.           * \note Null terminator is not included!
  2098.           * \return Returns the character length or zero when the input string is nullptr.
  2099.           */
  2100.         fpl_common_api uint32_t GetWideStringLength(const wchar_t *str);
  2101.         /**
  2102.           * \brief Copies the given 8-bit source ansi string with a fixed length into a destination ansi string.
  2103.           * \param source The 8-bit source ansi string.
  2104.           * \param sourceLen The number of characters to copy.
  2105.           * \param dest The 8-bit destination ansi string buffer.
  2106.           * \param maxDestLen The total number of characters available in the destination buffer.
  2107.           * \note Null terminator is included always. Does not allocate any memory.
  2108.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2109.           */
  2110.         fpl_common_api char *CopyAnsiString(const char *source, const uint32_t sourceLen, char *dest, const uint32_t maxDestLen);
  2111.         /**
  2112.           * \brief Copies the given 8-bit source ansi string into a destination ansi string.
  2113.           * \param source The 8-bit source ansi string.
  2114.           * \param dest The 8-bit destination ansi string buffer.
  2115.           * \param maxDestLen The total number of characters available in the destination buffer.
  2116.           * \note Null terminator is included always. Does not allocate any memory.
  2117.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2118.           */
  2119.         fpl_common_api char *CopyAnsiString(const char *source, char *dest, const uint32_t maxDestLen);
  2120.         /**
  2121.           * \brief Copies the given 16-bit source wide string with a fixed length into a destination wide string.
  2122.           * \param source The 16-bit source wide string.
  2123.           * \param sourceLen The number of characters to copy.
  2124.           * \param dest The 16-bit destination wide string buffer.
  2125.           * \param maxDestLen The total number of characters available in the destination buffer.
  2126.           * \note Null terminator is included always. Does not allocate any memory.
  2127.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2128.           */
  2129.         fpl_common_api wchar_t *CopyWideString(const wchar_t *source, const uint32_t sourceLen, wchar_t *dest, const uint32_t maxDestLen);
  2130.         /**
  2131.           * \brief Copies the given 16-bit source wide string into a destination wide string.
  2132.           * \param source The 16-bit source wide string.
  2133.           * \param dest The 16-bit destination wide string buffer.
  2134.           * \param maxDestLen The total number of characters available in the destination buffer.
  2135.           * \note Null terminator is included always. Does not allocate any memory.
  2136.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2137.           */
  2138.         fpl_common_api wchar_t *CopyWideString(const wchar_t *source, wchar_t *dest, const uint32_t maxDestLen);
  2139.         /**
  2140.           * \brief Converts the given 16-bit source wide string with length in a 8-bit ansi string.
  2141.           * \param wideSource The 16-bit source wide string.
  2142.           * \param maxWideSourceLen The number of characters of the source wide string.
  2143.           * \param ansiDest The 8-bit destination ansi string buffer.
  2144.           * \param maxAnsiDestLen The total number of characters available in the destination buffer.
  2145.           * \note Null terminator is included always. Does not allocate any memory.
  2146.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2147.           */
  2148.         fpl_platform_api char *WideStringToAnsiString(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *ansiDest, const uint32_t maxAnsiDestLen);
  2149.         /**
  2150.           * \brief Converts the given 16-bit source wide string with length in a 8-bit UTF-8 ansi string.
  2151.           * \param wideSource The 16-bit source wide string.
  2152.           * \param maxWideSourceLen The number of characters of the source wide string.
  2153.           * \param utf8Dest The 8-bit destination ansi string buffer.
  2154.           * \param maxUtf8DestLen The total number of characters available in the destination buffer.
  2155.           * \note Null terminator is included always. Does not allocate any memory.
  2156.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2157.           */
  2158.         fpl_platform_api char *WideStringToUTF8String(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *utf8Dest, const uint32_t maxUtf8DestLen);
  2159.         /**
  2160.           * \brief Converts the given 8-bit source ansi string with length in a 16-bit wide string.
  2161.           * \param ansiSource The 8-bit source ansi string.
  2162.           * \param ansiSourceLen The number of characters of the source wide string.
  2163.           * \param wideDest The 16-bit destination wide string buffer.
  2164.           * \param maxWideDestLen The total number of characters available in the destination buffer.
  2165.           * \note Null terminator is included always. Does not allocate any memory.
  2166.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2167.           */
  2168.         fpl_platform_api wchar_t *AnsiStringToWideString(const char *ansiSource, const uint32_t ansiSourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen);
  2169.         /**
  2170.           * \brief Converts the given 8-bit UTF-8 source ansi string with length in a 16-bit wide string.
  2171.           * \param utf8Source The 8-bit source ansi string.
  2172.           * \param utf8SourceLen The number of characters of the source wide string.
  2173.           * \param wideDest The 16-bit destination wide string buffer.
  2174.           * \param maxWideDestLen The total number of characters available in the destination buffer.
  2175.           * \note Null terminator is included always. Does not allocate any memory.
  2176.           * \return Returns the pointer to the first character in the destination buffer or nullptr when either the dest buffer is too small or the source string is invalid.
  2177.           */
  2178.         fpl_platform_api wchar_t *UTF8StringToWideString(const char *utf8Source, const uint32_t utf8SourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen);
  2179.         /**
  2180.           * \brief Fills out the given destination ansi string buffer with a formatted string, using the format specifier and variable arguments.
  2181.           * \param ansiDestBuffer The 8-bit destination ansi string buffer.
  2182.           * \param maxAnsiDestBufferLen The total number of characters available in the destination buffer.
  2183.           * \param format The string format.
  2184.           * \param ... Variable arguments.
  2185.           * \note This is most likely just a wrapper call to vsnprintf()
  2186.           * \return Pointer to the first character in the destination buffer or nullptr.
  2187.           */
  2188.         fpl_platform_api char *FormatAnsiString(char *ansiDestBuffer, const uint32_t maxAnsiDestBufferLen, const char *format, ...);
  2189.  
  2190.         /** \}*/
  2191.     }
  2192.  
  2193.     //! Files & directory functions and types
  2194.     namespace files {
  2195.         /**
  2196.           * \defgroup Files Files/IO functions
  2197.           * \brief Tons of file and directory IO functions
  2198.           * \{
  2199.           */
  2200.  
  2201.         //! Internal file handle union
  2202.         union InternalFileHandle {
  2203. #       if defined(FPL_PLATFORM_WIN32)
  2204.             //! Win32 file handle
  2205.             HANDLE win32FileHandle;
  2206. #       elif defined(FPL_SUBPLATFORM_POSIX)
  2207.             //! Posix file handle
  2208.             int posixFileHandle;
  2209. #       endif
  2210.         };
  2211.  
  2212.         //! Handle to a loaded/created file
  2213.         struct FileHandle {
  2214.             //! Internal file handle
  2215.             InternalFileHandle internalHandle;
  2216.             //! File opened successfully
  2217.             bool isValid;
  2218.         };
  2219.  
  2220.         //! File position mode (Beginning, Current, End)
  2221.         enum class FilePositionMode {
  2222.             //! Starts from the beginning
  2223.             Beginning,
  2224.             //! Starts from the current position
  2225.             Current,
  2226.             //! Starts from the end
  2227.             End
  2228.         };
  2229.  
  2230.         //! File entry type (File, Directory, etc.)
  2231.         enum class FileEntryType {
  2232.             //! Unknown entry type
  2233.             Unknown,
  2234.             //! Entry is a file
  2235.             File,
  2236.             //! Entry is a directory
  2237.             Directory
  2238.         };
  2239.  
  2240.         //! File attribute flags (Normal, Readonly, Hidden, etc.)
  2241.         enum class FileAttributeFlags : int {
  2242.             //! No attributes
  2243.             None = 0,
  2244.             //! Normal
  2245.             Normal = 1 << 0,
  2246.             //! Readonly
  2247.             ReadOnly = 1 << 1,
  2248.             //! Hidden
  2249.             Hidden = 1 << 2,
  2250.             //! Archive
  2251.             Archive = 1 << 3,
  2252.             //! System
  2253.             System = 1 << 4
  2254.         };
  2255.         //! Operator support for FileAttributeFlags
  2256.         FPL_ENUM_AS_FLAGS_OPERATORS(FileAttributeFlags);
  2257.  
  2258.         //! Maximum length of a file entry path
  2259.         fpl_constant uint32_t MAX_FILEENTRY_PATH_LENGTH = 1024;
  2260.  
  2261.         //! Internal file entry handle
  2262.         struct InternalFileEntryHandle {
  2263. #       if defined(FPL_PLATFORM_WIN32)
  2264.             //! Win32 file handle
  2265.             HANDLE win32FileHandle;
  2266. #       elif defined(FPL_SUBPLATFORM_POSIX)
  2267.             //! Posix file handle
  2268.             int posixFileHandle;
  2269. #       endif
  2270.         };
  2271.  
  2272.         //! Entry for storing current file informations (path, type, attributes, etc.)
  2273.         struct FileEntry {
  2274.             //! File path
  2275.             char path[MAX_FILEENTRY_PATH_LENGTH];
  2276.             //! Internal file handle
  2277.             InternalFileEntryHandle internalHandle;
  2278.             //! Entry type
  2279.             FileEntryType type;
  2280.             //! File attributes
  2281.             FileAttributeFlags attributes;
  2282.         };
  2283.  
  2284.         /**
  2285.           * \brief Opens a binary file for reading from a ansi string path and returns the handle of it.
  2286.           * \param filePath Ansi file path.
  2287.           * \note To check for success just test the \ref FileHandle.isValid field from the result.
  2288.           * \return Copy of the handle to the open file.
  2289.           */
  2290.         fpl_platform_api FileHandle OpenBinaryFile(const char *filePath);
  2291.         /**
  2292.           * \brief Opens a binary file for reading from a wide string path and returns the handle of it.
  2293.           * \param filePath Wide file path.
  2294.           * \note To check for success just test the \ref FileHandle.isValid field from the result.
  2295.           * \return Copy of the handle to the open file.
  2296.           */
  2297.         fpl_platform_api FileHandle OpenBinaryFile(const wchar_t *filePath);
  2298.         /**
  2299.           * \brief Create a binary file for writing to the given ansi string path and returns the handle of it.
  2300.           * \param filePath Ansi file path.
  2301.           * \note To check for success just test the \ref FileHandle.isValid field from the result. The file is ensured to be overriden always.
  2302.           * \return Copy of the handle to the created file.
  2303.           */
  2304.         fpl_platform_api FileHandle CreateBinaryFile(const char *filePath);
  2305.         /**
  2306.           * \brief Create a binary file for writing to the given wide string path and returns the handle of it.
  2307.           * \param filePath Wide file path.
  2308.           * \note To check for success just test the \ref FileHandle.isValid field from the result. The file is ensured to be overriden always.
  2309.           * \return Copy of the handle to the created file.
  2310.           */
  2311.         fpl_platform_api FileHandle CreateBinaryFile(const wchar_t *filePath);
  2312.         /**
  2313.           * \brief Reads a block from the given file handle and returns the number of bytes read.
  2314.           * \param fileHandle Reference to the file handle.
  2315.           * \param sizeToRead Number of bytes to read.
  2316.           * \param targetBuffer Target memory to write into.
  2317.           * \param maxTargetBufferSize Total number of bytes available in the target buffer.
  2318.           * \note Its limited to files < 2 GB.
  2319.           * \return Number of bytes read or zero.
  2320.           */
  2321.         fpl_platform_api uint32_t ReadFileBlock32(const FileHandle &fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize);
  2322.         /**
  2323.           * \brief Writes a block to the given file handle and returns the number of bytes written.
  2324.           * \param fileHandle Reference to the file handle.
  2325.           * \param sourceBuffer Source memory to read from.
  2326.           * \param sourceSize Number of bytes to write.
  2327.           * \note Its limited to files < 2 GB.
  2328.           * \return Number of bytes written or zero.
  2329.           */
  2330.         fpl_platform_api uint32_t WriteFileBlock32(const FileHandle &fileHandle, void *sourceBuffer, const uint32_t sourceSize);
  2331.         /**
  2332.           * \brief Sets the current file position by the given position, depending on the mode its absolute or relative.
  2333.           * \param fileHandle Reference to the file handle.
  2334.           * \param position Position in bytes
  2335.           * \param mode Position mode
  2336.           * \note Its limited to files < 2 GB.
  2337.           */
  2338.         fpl_platform_api void SetFilePosition32(const FileHandle &fileHandle, const int32_t position, const FilePositionMode mode);
  2339.         /**
  2340.           * \brief Returns the current file position in bytes.
  2341.           * \param fileHandle Reference to the file handle.
  2342.           * \note Its limited to files < 2 GB.
  2343.           * \return Current file position in bytes.
  2344.           */
  2345.         fpl_platform_api uint32_t GetFilePosition32(const FileHandle &fileHandle);
  2346.         /**
  2347.           * \brief Closes the given file and releases the underlying resources and clears the handle to zero.
  2348.           * \param fileHandle Reference to the file handle.
  2349.           */
  2350.         fpl_platform_api void CloseFile(FileHandle &fileHandle);
  2351.  
  2352.         // @TODO(final): Add 64-bit file operations
  2353.         // @TODO(final): Add wide file operations
  2354.  
  2355.         /**
  2356.           * \brief Returns the 32-bit file size in bytes for the given file.
  2357.           * \param filePath Ansi path to the file.
  2358.           * \note Its limited to files < 2 GB.
  2359.           * \return File size in bytes or zero.
  2360.           */
  2361.         fpl_platform_api uint32_t GetFileSize32(const char *filePath);
  2362.         /**
  2363.           * \brief Returns the 32-bit file size in bytes for a opened file.
  2364.           * \param fileHandle Reference to the file handle.
  2365.           * \note Its limited to files < 2 GB.
  2366.           * \return File size in bytes or zero.
  2367.           */
  2368.         fpl_platform_api uint32_t GetFileSize32(const FileHandle &fileHandle);
  2369.         /**
  2370.           * \brief Returns true when the given file physically exists.
  2371.           * \param filePath Ansi path to the file.
  2372.           * \return True when the file exists, otherwise false.
  2373.           */
  2374.         fpl_platform_api bool FileExists(const char *filePath);
  2375.         /**
  2376.           * \brief Copies the given source file to the target path and returns true when copy was successful.
  2377.           * \param sourceFilePath Ansi source file path.
  2378.           * \param targetFilePath Ansi target file path.
  2379.           * \param overwrite When true the target file always be overwritten, otherwise it will return false when file already exists.
  2380.           * \return True when the file was copied, otherwise false.
  2381.           */
  2382.         fpl_platform_api bool FileCopy(const char *sourceFilePath, const char *targetFilePath, const bool overwrite);
  2383.         /**
  2384.           * \brief Movies the given source file to the target file and returns true when the move was successful.
  2385.           * \param sourceFilePath Ansi source file path.
  2386.           * \param targetFilePath Ansi target file path.
  2387.           * \return True when the file was moved, otherwise false.
  2388.           */
  2389.         fpl_platform_api bool FileMove(const char *sourceFilePath, const char *targetFilePath);
  2390.         /**
  2391.           * \brief Deletes the given file without confirmation and returns true when the deletion was successful.
  2392.           * \param filePath Ansi path to the file.
  2393.           * \return True when the file was deleted, otherwise false.
  2394.           */
  2395.         fpl_platform_api bool FileDelete(const char *filePath);
  2396.  
  2397.         /**
  2398.           * \brief Creates all the directories in the given path.
  2399.           * \param path Ansi path to the directory.
  2400.           * \return True when at least one directory was created, otherwise false.
  2401.           */
  2402.         fpl_platform_api bool CreateDirectories(const char *path);
  2403.         /**
  2404.           * \brief Returns true when the given directory physically exists.
  2405.           * \param path Ansi path to the directory.
  2406.           * \return True when the directory exists, otherwise false.
  2407.           */
  2408.         fpl_platform_api bool DirectoryExists(const char *path);
  2409.         /**
  2410.           * \brief Deletes the given empty directory without confirmation and returns true when the deletion was successful.
  2411.           * \param path Ansi path to the directory.
  2412.           * \return True when the empty directory was deleted, otherwise false.
  2413.           */
  2414.         fpl_platform_api bool RemoveEmptyDirectory(const char *path);
  2415.         /**
  2416.           * \brief Iterates through files / directories in the given directory.
  2417.           * \param pathAndFilter The path with its included after the path separator.
  2418.           * \param firstEntry The reference to a file entry.
  2419.           * \note The path must contain the filter as well.
  2420.           * \return Returns true when there was a first entry found otherwise false.
  2421.           */
  2422.         fpl_platform_api bool ListFilesBegin(const char *pathAndFilter, FileEntry &firstEntry);
  2423.         /**
  2424.           * \brief Gets the next file entry from iterating through files / directories.
  2425.           * \param nextEntry The reference to the current file entry.
  2426.           * \return Returns true when there was a next file otherwise false if not.
  2427.           */
  2428.         fpl_platform_api bool ListFilesNext(FileEntry &nextEntry);
  2429.         /**
  2430.           * \brief Releases opened resources from iterating through files / directories.
  2431.           * \param lastEntry The reference to the last file entry.
  2432.           */
  2433.         fpl_platform_api void ListFilesEnd(FileEntry &lastEntry);
  2434.  
  2435.         /** \}*/
  2436.     }
  2437.  
  2438.     //! Directory and paths functions
  2439.     namespace paths {
  2440.         /**
  2441.           * \defgroup Paths Path functions
  2442.           * \brief Functions for retrieving paths like HomePath, ExecutablePath, etc.
  2443.           * \{
  2444.           */
  2445.  
  2446.           // @TODO(final): Support wide paths as well
  2447.  
  2448.           /**
  2449.             * \brief Returns the full path to this executable, including the executable file name.
  2450.             * \param destPath Destination buffer
  2451.             * \param maxDestLen Total number of characters available in the destination buffer.
  2452.             * \note Result is written in the destination buffer.
  2453.             * \return Returns the pointer to the first character in the destination buffer or nullptr.
  2454.             */
  2455.         fpl_platform_api char *GetExecutableFilePath(char *destPath, const uint32_t maxDestLen);
  2456.         /**
  2457.           * \brief Returns the full path to your home directory.
  2458.           * \param destPath Destination buffer
  2459.           * \param maxDestLen Total number of characters available in the destination buffer.
  2460.           * \note Result is written in the destination buffer.
  2461.           * \return Returns the pointer to the first character in the destination buffer or nullptr.
  2462.           */
  2463.         fpl_platform_api char *GetHomePath(char *destPath, const uint32_t maxDestLen);
  2464.         /**
  2465.           * \brief Returns the path from the given source path.
  2466.           * \param sourcePath Source path to extract from.
  2467.           * \param destPath Destination buffer
  2468.           * \param maxDestLen Total number of characters available in the destination buffer.
  2469.           * \note Result is written in the destination buffer.
  2470.           * \return Returns the pointer to the first character in the destination buffer or nullptr.
  2471.           */
  2472.         fpl_common_api char *ExtractFilePath(const char *sourcePath, char *destPath, const uint32_t maxDestLen);
  2473.         /**
  2474.           * \brief Returns the file extension from the given source path.
  2475.           * \param sourcePath Source path to extract from.
  2476.           * \return Returns the pointer to the first character of the extension.
  2477.           */
  2478.         fpl_common_api const char *ExtractFileExtension(const char *sourcePath);
  2479.         /**
  2480.           * \brief Returns the file name including the file extension from the given source path.
  2481.           * \param sourcePath Source path to extract from.
  2482.           * \return Returns the pointer to the first character of the filename.
  2483.           */
  2484.         fpl_common_api const char *ExtractFileName(const char *sourcePath);
  2485.         /**
  2486.           * \brief Changes the file extension on the given source path and writes the result into the destination path.
  2487.           * \param filePath File path to search for the extension.
  2488.           * \param newFileExtension New file extension.
  2489.           * \param destPath Destination buffer
  2490.           * \param maxDestLen Total number of characters available in the destination buffer.
  2491.           * \note Result is written in the destination buffer.
  2492.           * \return Returns the pointer to the first character in the destination buffer or nullptr.
  2493.           */
  2494.         fpl_common_api char *ChangeFileExtension(const char *filePath, const char *newFileExtension, char *destPath, const uint32_t maxDestLen);
  2495.         /**
  2496.           * \brief Combines all included path by the systems path separator.
  2497.           * \param destPath Destination buffer
  2498.           * \param maxDestPathLen Total number of characters available in the destination buffer.
  2499.           * \param pathCount Number of dynamic path arguments.
  2500.           * \param ... Dynamic path arguments.
  2501.           * \note Result is written in the destination buffer.
  2502.           * \return Returns the pointer to the first character in the destination buffer or nullptr.
  2503.           */
  2504.         fpl_common_api char *CombinePath(char *destPath, const uint32_t maxDestPathLen, const uint32_t pathCount, ...);
  2505.  
  2506.         /** \}*/
  2507.     }
  2508.  
  2509. #if defined(FPL_ENABLE_WINDOW)
  2510.     //! Window based functions and types
  2511.     namespace window {
  2512.         /**
  2513.         * \defgroup WindowEvents Window events
  2514.         * \brief Window event structures
  2515.         * \{
  2516.         */
  2517.  
  2518.         //! Mapped keys (Based on MS Virtual-Key-Codes, mostly directly mapped from ASCII)
  2519.         enum class Key {
  2520.             Key_None = 0,
  2521.  
  2522.             // 0x07: Undefined
  2523.  
  2524.             Key_Backspace = 0x08,
  2525.             Key_Tab = 0x09,
  2526.  
  2527.             // 0x0A-0x0B: Reserved
  2528.  
  2529.             Key_Clear = 0x0C,
  2530.             Key_Enter = 0x0D,
  2531.  
  2532.             // 0x0E-0x0F: Undefined
  2533.  
  2534.             Key_Shift = 0x10,
  2535.             Key_Control = 0x11,
  2536.             Key_Alt = 0x12,
  2537.             Key_Pause = 0x13,
  2538.             Key_CapsLock = 0x14,
  2539.  
  2540.             // 0x15: IME-Keys
  2541.             // 0x16: Undefined
  2542.             // 0x17-0x19 IME-Keys
  2543.             // 0x1A: Undefined
  2544.  
  2545.             Key_Escape = 0x1B,
  2546.  
  2547.             // 0x1C - 0x1F: IME-Keys
  2548.  
  2549.             Key_Space = 0x20,
  2550.             Key_PageUp = 0x21,
  2551.             Key_PageDown = 0x22,
  2552.             Key_End = 0x23,
  2553.             Key_Home = 0x24,
  2554.             Key_Left = 0x25,
  2555.             Key_Up = 0x26,
  2556.             Key_Right = 0x27,
  2557.             Key_Down = 0x28,
  2558.             Key_Select = 0x29,
  2559.             Key_Print = 0x2A,
  2560.             Key_Execute = 0x2B,
  2561.             Key_Snapshot = 0x2C,
  2562.             Key_Insert = 0x2D,
  2563.             Key_Delete = 0x2E,
  2564.             Key_Help = 0x2F,
  2565.  
  2566.             Key_0 = 0x30,
  2567.             Key_1 = 0x31,
  2568.             Key_2 = 0x32,
  2569.             Key_3 = 0x33,
  2570.             Key_4 = 0x34,
  2571.             Key_5 = 0x35,
  2572.             Key_6 = 0x36,
  2573.             Key_7 = 0x37,
  2574.             Key_8 = 0x38,
  2575.             Key_9 = 0x39,
  2576.  
  2577.             // 0x3A-0x40: Undefined
  2578.  
  2579.             Key_A = 0x41,
  2580.             Key_B = 0x42,
  2581.             Key_C = 0x43,
  2582.             Key_D = 0x44,
  2583.             Key_E = 0x45,
  2584.             Key_F = 0x46,
  2585.             Key_G = 0x47,
  2586.             Key_H = 0x48,
  2587.             Key_I = 0x49,
  2588.             Key_J = 0x4A,
  2589.             Key_K = 0x4B,
  2590.             Key_L = 0x4C,
  2591.             Key_M = 0x4D,
  2592.             Key_N = 0x4E,
  2593.             Key_O = 0x4F,
  2594.             Key_P = 0x50,
  2595.             Key_Q = 0x51,
  2596.             Key_R = 0x52,
  2597.             Key_S = 0x53,
  2598.             Key_T = 0x54,
  2599.             Key_U = 0x55,
  2600.             Key_V = 0x56,
  2601.             Key_W = 0x57,
  2602.             Key_X = 0x58,
  2603.             Key_Y = 0x59,
  2604.             Key_Z = 0x5A,
  2605.  
  2606.             Key_LeftWin = 0x5B,
  2607.             Key_RightWin = 0x5C,
  2608.             Key_Apps = 0x5D,
  2609.  
  2610.             // 0x5E: Reserved
  2611.  
  2612.             Key_Sleep = 0x5F,
  2613.             Key_NumPad0 = 0x60,
  2614.             Key_NumPad1 = 0x61,
  2615.             Key_NumPad2 = 0x62,
  2616.             Key_NumPad3 = 0x63,
  2617.             Key_NumPad4 = 0x64,
  2618.             Key_NumPad5 = 0x65,
  2619.             Key_NumPad6 = 0x66,
  2620.             Key_NumPad7 = 0x67,
  2621.             Key_NumPad8 = 0x68,
  2622.             Key_NumPad9 = 0x69,
  2623.             Key_Multiply = 0x6A,
  2624.             Key_Add = 0x6B,
  2625.             Key_Separator = 0x6C,
  2626.             Key_Substract = 0x6D,
  2627.             Key_Decimal = 0x6E,
  2628.             Key_Divide = 0x6F,
  2629.             Key_F1 = 0x70,
  2630.             Key_F2 = 0x71,
  2631.             Key_F3 = 0x72,
  2632.             Key_F4 = 0x73,
  2633.             Key_F5 = 0x74,
  2634.             Key_F6 = 0x75,
  2635.             Key_F7 = 0x76,
  2636.             Key_F8 = 0x77,
  2637.             Key_F9 = 0x78,
  2638.             Key_F10 = 0x79,
  2639.             Key_F11 = 0x7A,
  2640.             Key_F12 = 0x7B,
  2641.             Key_F13 = 0x7C,
  2642.             Key_F14 = 0x7D,
  2643.             Key_F15 = 0x7E,
  2644.             Key_F16 = 0x7F,
  2645.             Key_F17 = 0x80,
  2646.             Key_F18 = 0x81,
  2647.             Key_F19 = 0x82,
  2648.             Key_F20 = 0x83,
  2649.             Key_F21 = 0x84,
  2650.             Key_F22 = 0x85,
  2651.             Key_F23 = 0x86,
  2652.             Key_F24 = 0x87,
  2653.  
  2654.             // 0x88-8F: Unassigned
  2655.  
  2656.             Key_NumLock = 0x90,
  2657.             Key_Scroll = 0x91,
  2658.  
  2659.             // 0x92-9x96: OEM specific
  2660.             // 0x97-0x9F: Unassigned
  2661.  
  2662.             Key_LeftShift = 0xA0,
  2663.             Key_RightShift = 0xA1,
  2664.             Key_LeftControl = 0xA2,
  2665.             Key_RightControl = 0xA3,
  2666.             Key_LeftAlt = 0xA4,
  2667.             Key_RightAlt = 0xA5,
  2668.  
  2669.             // 0xA6-0xFE: Dont care
  2670.         };
  2671.  
  2672.         //! Window event type (Resized, PositionChanged, etc.)
  2673.         enum class WindowEventType {
  2674.             //! Window has been resized
  2675.             Resized,
  2676.             //! Window got focus
  2677.             GotFocus,
  2678.             //! Window lost focus
  2679.             LostFocus,
  2680.         };
  2681.  
  2682.         //! Window event data (Size, Position, etc.)
  2683.         struct WindowEvent {
  2684.             //! Window event type
  2685.             WindowEventType type;
  2686.             //! Window width in screen coordinates
  2687.             uint32_t width;
  2688.             //! Window height in screen coordinates
  2689.             uint32_t height;
  2690.         };
  2691.  
  2692.         //! Keyboard event type (KeyDown, KeyUp, Char, ...)
  2693.         enum class KeyboardEventType {
  2694.             //! Key is down
  2695.             KeyDown,
  2696.             //! Key was released
  2697.             KeyUp,
  2698.             //! Character was entered
  2699.             CharInput,
  2700.         };
  2701.  
  2702.         //! Keyboard modifier flags (Alt, Ctrl, ...)
  2703.         enum class KeyboardModifierFlags : int {
  2704.             //! No modifiers
  2705.             None = 0,
  2706.             //! Alt key is down
  2707.             Alt = 1 << 0,
  2708.             //! Ctrl key is down
  2709.             Ctrl = 1 << 1,
  2710.             //! Shift key is down
  2711.             Shift = 1 << 2,
  2712.             //! Super key is down
  2713.             Super = 1 << 3,
  2714.         };
  2715.         //! Operator support for KeyboardModifierFlags
  2716.         FPL_ENUM_AS_FLAGS_OPERATORS(KeyboardModifierFlags);
  2717.  
  2718.         //! Keyboard event data (Type, Keycode, Mapped key, etc.)
  2719.         struct KeyboardEvent {
  2720.             //! Keyboard event type
  2721.             KeyboardEventType type;
  2722.             //! Raw key code
  2723.             uint64_t keyCode;
  2724.             //! Mapped key
  2725.             Key mappedKey;
  2726.             //! Keyboard modifiers
  2727.             KeyboardModifierFlags modifiers;
  2728.         };
  2729.  
  2730.         //! Mouse event type (Move, ButtonDown, ...)
  2731.         enum class MouseEventType {
  2732.             //! Mouse position has been changed
  2733.             Move,
  2734.             //! Mouse button is down
  2735.             ButtonDown,
  2736.             //! Mouse button was released
  2737.             ButtonUp,
  2738.             //! Mouse wheel up/down
  2739.             Wheel,
  2740.         };
  2741.  
  2742.         //! Mouse button type (Left, Right, ...)
  2743.         enum class MouseButtonType : int {
  2744.             //! No mouse button
  2745.             None = -1,
  2746.             //! Left mouse button
  2747.             Left = 0,
  2748.             //! Right mouse button
  2749.             Right = 1,
  2750.             //! Middle mouse button
  2751.             Middle = 2,
  2752.         };
  2753.  
  2754.         //! Mouse event data (Type, Button, Position, etc.)
  2755.         struct MouseEvent {
  2756.             //! Mouse event type
  2757.             MouseEventType type;
  2758.             //! Mouse button
  2759.             MouseButtonType mouseButton;
  2760.             //! Mouse X-Position
  2761.             int32_t mouseX;
  2762.             //! Mouse Y-Position
  2763.             int32_t mouseY;
  2764.             //! Mouse wheel delta
  2765.             float wheelDelta;
  2766.         };
  2767.  
  2768.         //! Gamepad event type (Connected, Disconnected, StateChanged, etc.)
  2769.         enum class GamepadEventType {
  2770.             //! No gamepad event
  2771.             None,
  2772.             //! Gamepad connected
  2773.             Connected,
  2774.             //! Gamepad disconnected
  2775.             Disconnected,
  2776.             //! Gamepad state updated
  2777.             StateChanged,
  2778.         };
  2779.  
  2780.         //! Gamepad button (IsDown, etc.)
  2781.         struct GamepadButton {
  2782.             //! Is button down
  2783.             bool isDown;
  2784.         };
  2785.  
  2786.         //! Gamepad state data
  2787.         struct GamepadState {
  2788.             union {
  2789.                 struct {
  2790.                     //! Digital button up
  2791.                     GamepadButton dpadUp;
  2792.                     //! Digital button right
  2793.                     GamepadButton dpadRight;
  2794.                     //! Digital button down
  2795.                     GamepadButton dpadDown;
  2796.                     //! Digital button left
  2797.                     GamepadButton dpadLeft;
  2798.  
  2799.                     //! Action button A
  2800.                     GamepadButton actionA;
  2801.                     //! Action button B
  2802.                     GamepadButton actionB;
  2803.                     //! Action button X
  2804.                     GamepadButton actionX;
  2805.                     //! Action button Y
  2806.                     GamepadButton actionY;
  2807.  
  2808.                     //! Start button
  2809.                     GamepadButton start;
  2810.                     //! Back button
  2811.                     GamepadButton back;
  2812.  
  2813.                     //! Analog left thumb button
  2814.                     GamepadButton leftThumb;
  2815.                     //! Analog right thumb button
  2816.                     GamepadButton rightThumb;
  2817.  
  2818.                     //! Left shoulder button
  2819.                     GamepadButton leftShoulder;
  2820.                     //! Right shoulder button
  2821.                     GamepadButton rightShoulder;
  2822.                 };
  2823.                 //! All gamepad buttons
  2824.                 GamepadButton buttons[14];
  2825.             };
  2826.  
  2827.             //! Analog left thumb X in range (-1.0 to 1.0f)
  2828.             float leftStickX;
  2829.             //! Analog left thumb Y in range (-1.0 to 1.0f)
  2830.             float leftStickY;
  2831.             //! Analog right thumb X in range (-1.0 to 1.0f)
  2832.             float rightStickX;
  2833.             //! Analog right thumb Y in range (-1.0 to 1.0f)
  2834.             float rightStickY;
  2835.  
  2836.             //! Analog left trigger in range (-1.0 to 1.0f)
  2837.             float leftTrigger;
  2838.             //! Analog right trigger in range (-1.0 to 1.0f)
  2839.             float rightTrigger;
  2840.         };
  2841.  
  2842.         //! Gamepad event data (Type, Device, State, etc.)
  2843.         struct GamepadEvent {
  2844.             //! Gamepad event type
  2845.             GamepadEventType type;
  2846.             //! Gamepad device index
  2847.             uint32_t deviceIndex;
  2848.             //! Full gamepad state
  2849.             GamepadState state;
  2850.         };
  2851.  
  2852.         //! Event type (Window, Keyboard, Mouse, ...)
  2853.         enum class EventType {
  2854.             //! Window event
  2855.             Window,
  2856.             //! Keyboard event
  2857.             Keyboard,
  2858.             //! Mouse event
  2859.             Mouse,
  2860.             //! Gamepad event
  2861.             Gamepad,
  2862.         };
  2863.  
  2864.         //! Event data (Type, Window, Keyboard, Mouse, etc.)
  2865.         struct Event {
  2866.             //! Event type
  2867.             EventType type;
  2868.             union {
  2869.                 //! Window event data
  2870.                 WindowEvent window;
  2871.                 //! Keyboard event data
  2872.                 KeyboardEvent keyboard;
  2873.                 //! Mouse event data
  2874.                 MouseEvent mouse;
  2875.                 //! Gamepad event data
  2876.                 GamepadEvent gamepad;
  2877.             };
  2878.         };
  2879.  
  2880.         /**
  2881.           * \brief Gets the top event from the internal event queue and removes it.
  2882.           * \param ev Reference to an event
  2883.           * \return Returns false when there are no events left, otherwise true.
  2884.           */
  2885.         fpl_common_api bool PollWindowEvent(Event &ev);
  2886.         /**
  2887.           * \brief Removes all the events from the internal event queue.
  2888.           * \note Dont call when you care about any event!
  2889.           */
  2890.         fpl_common_api void ClearWindowEvents();
  2891.         /**
  2892.           * \brief Reads the next window event from the OS and pushes it into the internal queue.
  2893.           * \return Returns true when there was a event from the OS, otherwise true.
  2894.           * \note Use this only if dont use \ref WindowUpdate() and want to handle the events more granular!
  2895.           */
  2896.         fpl_platform_api bool PushWindowEvent();
  2897.         /**
  2898.           * \brief Updates the game controller states and detects new and disconnected devices.
  2899.           * \note Use this only if dont use \ref WindowUpdate() and want to handle the events more granular!
  2900.           */
  2901.         fpl_platform_api void UpdateGameControllers();
  2902.  
  2903.         /*\}*/
  2904.  
  2905.         /**
  2906.           * \defgroup WindowBase Window functions
  2907.           * \brief Functions for reading/setting/handling the window
  2908.           * \{
  2909.           */
  2910.  
  2911.           //! Window size in screen coordinates
  2912.         struct WindowSize {
  2913.             //! Width in screen coordinates
  2914.             uint32_t width;
  2915.             //! Height in screen coordinates
  2916.             uint32_t height;
  2917.         };
  2918.  
  2919.         //! Window position in screen coordinates
  2920.         struct WindowPosition {
  2921.             //! Left position in screen coordinates
  2922.             int32_t left;
  2923.             //! Top position in screen coordinates
  2924.             int32_t top;
  2925.         };
  2926.  
  2927.         /**
  2928.           * \brief Returns true when the window is active.
  2929.           * \return True when the window is active, otherwise false.
  2930.           */
  2931.         fpl_platform_api bool IsWindowRunning();
  2932.         /**
  2933.           * \brief Processes the message queue of the window.
  2934.           * \note This will update the game controller states as well.
  2935.           * \return True when the window is still active, otherwise false.
  2936.           */
  2937.         fpl_platform_api bool WindowUpdate();
  2938.         /**
  2939.           * \brief Enables or disables the window cursor.
  2940.           * \param value Set this to true for enabling the cursor or false for disabling the cursor.
  2941.           */
  2942.         fpl_platform_api void SetWindowCursorEnabled(const bool value);
  2943.         /**
  2944.           * \brief Returns the inner window area.
  2945.           * \return Window area size
  2946.           */
  2947.         fpl_platform_api WindowSize GetWindowArea();
  2948.         /**
  2949.           * \brief Resizes the window to fit the inner area to the given size.
  2950.           * \param width Width in screen units
  2951.           * \param height Height in screen units
  2952.           */
  2953.         fpl_platform_api void SetWindowArea(const uint32_t width, const uint32_t height);
  2954.         /**
  2955.           * \brief Returns true when the window is resizable.
  2956.           * \return True when the window resizable, otherwise false.
  2957.           */
  2958.         fpl_platform_api bool IsWindowResizable();
  2959.         /**
  2960.           * \brief Enables or disables the ability to resize the window.
  2961.           * \param value Set this to true for making the window resizable or false for making it static
  2962.           */
  2963.         fpl_platform_api void SetWindowResizeable(const bool value);
  2964.         /**
  2965.           * \brief Enables or disables fullscreen mode.
  2966.           * \param value Set this to true for changing the window to fullscreen or false for switching it back to window mode.
  2967.           * \param fullscreenWidth Optional fullscreen width in screen units. When set to zero the desktop default is being used. (Default: 0)
  2968.           * \param fullscreenHeight Optional fullscreen height in screen units. When set to zero the desktop default is being used. (Default: 0)
  2969.           * \param refreshRate Optional refresh rate in screen units. When set to zero the desktop default is being used. (Default: 0)
  2970.           * \return True when the window was changed to the desire fullscreen mode, false when otherwise.
  2971.           */
  2972.         fpl_platform_api bool SetWindowFullscreen(const bool value, const uint32_t fullscreenWidth = 0, const uint32_t fullscreenHeight = 0, const uint32_t refreshRate = 0);
  2973.         /**
  2974.           * \brief Returns true when the window is in fullscreen mode
  2975.           * \return True when the window is in fullscreen mode, otherwise false.
  2976.           */
  2977.         fpl_platform_api bool IsWindowFullscreen();
  2978.         /**
  2979.           * \brief Returns the absolute window position.
  2980.           * \return Window position in screen units
  2981.           */
  2982.         fpl_platform_api WindowPosition GetWindowPosition();
  2983.         /**
  2984.           * \brief Sets the window absolut position to the given coordinates.
  2985.           * \param left Left position in screen units.
  2986.           * \param top Top position in screen units.
  2987.           */
  2988.         fpl_platform_api void SetWindowPosition(const int32_t left, const int32_t top);
  2989.         /**
  2990.           * \brief Sets the window title.
  2991.           * \param title New title ansi string
  2992.           */
  2993.         fpl_platform_api void SetWindowTitle(const char *title);
  2994.  
  2995.         /*\}*/
  2996.  
  2997.         /**
  2998.           * \defgroup WindowClipboard Clipboard functions
  2999.           * \brief Functions for reading/writing clipboard data
  3000.           * \{
  3001.           */
  3002.  
  3003.           /**
  3004.             * \brief Returns the current clipboard ansi text.
  3005.             * \param dest The destination ansi string buffer to write the clipboard text into.
  3006.             * \param maxDestLen The total number of characters available in the destination buffer.
  3007.             * \return Pointer to the first character in the clipboard text or nullptr otherwise.
  3008.             */
  3009.         fpl_platform_api char *GetClipboardAnsiText(char *dest, const uint32_t maxDestLen);
  3010.         /**
  3011.           * \brief Returns the current clipboard wide text.
  3012.           * \param dest The destination wide string buffer to write the clipboard text into.
  3013.           * \param maxDestLen The total number of characters available in the destination buffer.
  3014.           * \return Pointer to the first character in the clipboard text or nullptr otherwise.
  3015.           */
  3016.         fpl_platform_api wchar_t *GetClipboardWideText(wchar_t *dest, const uint32_t maxDestLen);
  3017.         /**
  3018.           * \brief Overwrites the current clipboard ansi text with the given one.
  3019.           * \param ansiSource The new clipboard ansi string.
  3020.           * \return Returns true when the text in the clipboard was changed, otherwise false.
  3021.           */
  3022.         fpl_platform_api bool SetClipboardText(const char *ansiSource);
  3023.         /**
  3024.           * \brief Overwrites the current clipboard wide text with the given one.
  3025.           * \param wideSource The new clipboard wide string.
  3026.           * \return Returns true when the text in the clipboard was changed, otherwise false.
  3027.           */
  3028.         fpl_platform_api bool SetClipboardText(const wchar_t *wideSource);
  3029.  
  3030.         /** \}*/
  3031.     };
  3032. #endif // FPL_ENABLE_WINDOW
  3033.  
  3034. #if defined(FPL_ENABLE_VIDEO)
  3035.     //! Video context access
  3036.     namespace video {
  3037.         /**
  3038.           * \defgroup Video Video functions
  3039.           * \brief Functions for retrieving or resizing the video buffer
  3040.           * \{
  3041.           */
  3042.  
  3043.         //! Video rectangle
  3044.         struct VideoRect {
  3045.             //! Left position in pixels
  3046.             int32_t x;
  3047.             //! Top position in pixels
  3048.             int32_t y;
  3049.             //! Width in pixels
  3050.             int32_t width;
  3051.             //! Height in pixels
  3052.             int32_t height;
  3053.         };
  3054.  
  3055.         /**
  3056.           * \brief Makes a video rectangle from a LT-RB rectangle
  3057.           * \param left Left position in screen units.
  3058.           * \param top Top position in screen units.
  3059.           * \param right Right position in screen units.
  3060.           * \param bottom Bottom position in screen units.
  3061.           * \return Computed video rectangle
  3062.           */
  3063.         fpl_inline VideoRect CreateVideoRectFromLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
  3064.             VideoRect result = { left, top, (right - left) + 1, (bottom - top) + 1 };
  3065.             return(result);
  3066.         }
  3067.  
  3068.         /**
  3069.           * \brief Returns the string for the given video driver
  3070.           * \param driver The audio driver
  3071.           * \return String for the given audio driver
  3072.           */
  3073.         fpl_inline const char *GetVideoDriverString(VideoDriverType driver) {
  3074.             const char *VIDEO_DRIVER_TYPE_STRINGS[] = {
  3075.                 "None",
  3076.                 "OpenGL",
  3077.                 "Software",
  3078.             };
  3079.             uint32_t index = (uint32_t)driver;
  3080.             FPL_ASSERT(index < FPL_ARRAYCOUNT(VIDEO_DRIVER_TYPE_STRINGS));
  3081.             const char *result = VIDEO_DRIVER_TYPE_STRINGS[index];
  3082.             return(result);
  3083.         }
  3084.  
  3085.  
  3086.         //! Video backbuffer container. Use this for accessing the pixels directly. Use with care!
  3087.         struct VideoBackBuffer {
  3088.             //! The 32-bit pixel top-down array, format: 0xAABBGGRR. Do not modify before WindowUpdate
  3089.             uint32_t *pixels;
  3090.             //! The width of the backbuffer in pixels. Do not modify, it will be set automatically.
  3091.             uint32_t width;
  3092.             //! The height of the backbuffer in pixels. Do not modify, it will be set automatically.
  3093.             uint32_t height;
  3094.             //! The size of one entire pixel with all 4 components in bytes. Do not modify, it will be set automatically.
  3095.             size_t pixelStride;
  3096.             //! The width of one line in bytes. Do not modify, it will be set automatically.
  3097.             size_t lineWidth;
  3098.             //! The output rectangle for displaying the backbuffer (Size may not match backbuffer size!)
  3099.             VideoRect outputRect;
  3100.             //! Set this to true to actually use the output rectangle
  3101.             bool useOutputRect;
  3102.         };
  3103.  
  3104.         /**
  3105.           * \brief Returns the pointer to the video software context.
  3106.           * \warning Do not release this memory by any means, otherwise you will corrupt heap memory!
  3107.           * \return Pointer to the video backbuffer.
  3108.           */
  3109.         fpl_common_api VideoBackBuffer *GetVideoBackBuffer();
  3110.         /**
  3111.           * \brief Resizes the current video backbuffer.
  3112.           * \param width Width in pixels.
  3113.           * \param height Height in pixels.
  3114.           * \return Returns true when video back buffer could be resized or false otherwise.
  3115.           */
  3116.         fpl_common_api bool ResizeVideoBackBuffer(const uint32_t width, const uint32_t height);
  3117.         /**
  3118.           * \brief Returns the current video driver type used.
  3119.           * \return The current video driver type used.
  3120.           */
  3121.         fpl_common_api VideoDriverType GetVideoDriver();
  3122.  
  3123.         /**
  3124.           * \brief Forces the window to redraw or to swap the back/front buffer.
  3125.           */
  3126.         fpl_common_api void VideoFlip();
  3127.  
  3128.         /** \}*/
  3129.     };
  3130. #endif // FPL_ENABLE_VIDEO
  3131.  
  3132. #if defined(FPL_ENABLE_AUDIO)
  3133.     //! Audio functions
  3134.     namespace audio {
  3135.         /**
  3136.           * \defgroup Audio Audio functions
  3137.           * \brief Functions for start/stop playing audio and retrieving/changing some audio related settings.
  3138.           * \{
  3139.           */
  3140.  
  3141.           //! Audio result
  3142.         enum class AudioResult {
  3143.             Success,
  3144.             DeviceNotInitialized,
  3145.             DeviceAlreadyStopped,
  3146.             DeviceAlreadyStarted,
  3147.             DeviceBusy,
  3148.             Failed,
  3149.         };
  3150.  
  3151.         /**
  3152.           * \brief Start playing asyncronous audio.
  3153.           * \return Audio result code.
  3154.           */
  3155.         fpl_common_api AudioResult PlayAudio();
  3156.         /**
  3157.           * \brief Stop playing asyncronous audio.
  3158.           * \return Audio result code.
  3159.           */
  3160.         fpl_common_api AudioResult StopAudio();
  3161.         /**
  3162.           * \brief Returns the native format for the current audio device.
  3163.           * \return Copy fo the audio device format.
  3164.           */
  3165.         fpl_common_api AudioDeviceFormat GetAudioHardwareFormat();
  3166.         /**
  3167.           * \brief Overwrites the audio client read callback.
  3168.           * \param newCallback Pointer to the client read callback.
  3169.           * \param userData Pointer to the client/user data.
  3170.           * \note This has no effect when audio is already playing, you have to call it when audio is in a stopped state!
  3171.           */
  3172.         fpl_common_api void SetAudioClientReadCallback(AudioClientReadFunction *newCallback, void *userData);
  3173.         /**
  3174.           * \brief Gets all playback audio devices.
  3175.           * \param devices Target device id array.
  3176.           * \param maxDeviceCount Total number of devices available in the devices array.
  3177.           * \return Number of devices found.
  3178.           */
  3179.         fpl_common_api uint32_t GetAudioDevices(AudioDeviceInfo *devices, uint32_t maxDeviceCount);
  3180.  
  3181.         /**
  3182.           * \brief Returns the number of bytes required to write one sample with one channel
  3183.           * \param format The audio format
  3184.           * \return Number of bytes for one sample with one channel
  3185.           */
  3186.         fpl_inline uint32_t GetAudioSampleSizeInBytes(const AudioFormatType format) {
  3187.             switch(format) {
  3188.                 case AudioFormatType::U8:
  3189.                     return 1;
  3190.                 case AudioFormatType::S16:
  3191.                     return 2;
  3192.                 case AudioFormatType::S24:
  3193.                     return 3;
  3194.                 case AudioFormatType::S32:
  3195.                 case AudioFormatType::F32:
  3196.                     return 4;
  3197.                 case AudioFormatType::S64:
  3198.                 case AudioFormatType::F64:
  3199.                     return 8;
  3200.                 default:
  3201.                     return 0;
  3202.             }
  3203.         }
  3204.  
  3205.         /**
  3206.           * \brief Returns the string for the given format type
  3207.           * \param format The audio format
  3208.           * \return String for the given format type
  3209.           */
  3210.         fpl_inline const char *GetAudioFormatString(const AudioFormatType format) {
  3211.             // @NOTE(final): Order must be equal to the AudioFormatType enum!
  3212.             const char *AUDIO_FORMAT_TYPE_STRINGS[] = {
  3213.                 "None",
  3214.                 "U8",
  3215.                 "S16",
  3216.                 "S24",
  3217.                 "S32",
  3218.                 "S64",
  3219.                 "F32",
  3220.                 "F64",
  3221.             };
  3222.             uint32_t index = (uint32_t)format;
  3223.             FPL_ASSERT(index < FPL_ARRAYCOUNT(AUDIO_FORMAT_TYPE_STRINGS));
  3224.             const char *result = AUDIO_FORMAT_TYPE_STRINGS[index];
  3225.             return(result);
  3226.         }
  3227.  
  3228.         /**
  3229.           * \brief Returns the string for the given audio driver
  3230.           * \param driver The audio driver
  3231.           * \return String for the given audio driver
  3232.           */
  3233.         fpl_inline const char *GetAudioDriverString(AudioDriverType driver) {
  3234.             const char *AUDIO_DRIVER_TYPE_STRINGS[] = {
  3235.                 "None",
  3236.                 "Auto",
  3237.                 "DirectSound",
  3238.             };
  3239.             uint32_t index = (uint32_t)driver;
  3240.             FPL_ASSERT(index < FPL_ARRAYCOUNT(AUDIO_DRIVER_TYPE_STRINGS));
  3241.             const char *result = AUDIO_DRIVER_TYPE_STRINGS[index];
  3242.             return(result);
  3243.         }
  3244.  
  3245.         /**
  3246.           * \brief Returns the total frame count for given sample rate and buffer size in milliseconds
  3247.           * \param sampleRate The sample rate in Hz
  3248.           * \param bufferSizeInMilliSeconds The buffer size in number of milliseconds
  3249.           * \return Number of frames
  3250.           */
  3251.         fpl_inline uint32_t GetAudioBufferSizeInFrames(uint32_t sampleRate, uint32_t bufferSizeInMilliSeconds) {
  3252.             uint32_t result = (sampleRate / 1000) * bufferSizeInMilliSeconds;
  3253.             return(result);
  3254.         }
  3255.  
  3256.         /**
  3257.           * \brief Returns the number of bytes required for one interleaved audio frame - containing all the channels
  3258.           * \param format The audio format
  3259.           * \param channelCount The number of channels
  3260.           * \return Number of bytes for one frame in bytes
  3261.           */
  3262.         fpl_inline uint32_t GetAudioFrameSizeInBytes(const AudioFormatType format, const uint32_t channelCount) {
  3263.             uint32_t result = GetAudioSampleSizeInBytes(format) * channelCount;
  3264.             return(result);
  3265.         }
  3266.  
  3267.         /**
  3268.           * \brief Returns the total number of bytes for the buffer and the given parameters
  3269.           * \param format The audio format
  3270.           * \param channelCount The number of channels
  3271.           * \param frameCount The number of frames
  3272.           * \return Total number of bytes for the buffer
  3273.           */
  3274.         fpl_inline uint32_t GetAudioBufferSizeInBytes(const AudioFormatType format, const uint32_t channelCount, const uint32_t frameCount) {
  3275.             uint32_t frameSize = GetAudioFrameSizeInBytes(format, channelCount);
  3276.             uint32_t result = frameSize * frameCount;
  3277.             return(result);
  3278.         }
  3279.  
  3280.         /** \}*/
  3281.     };
  3282. #endif // FPL_ENABLE_AUDIO
  3283. }
  3284.  
  3285. //
  3286. // Expand all namespaces if the callers wants this
  3287. //
  3288. #if defined(FPL_ENABLE_AUTO_NAMESPACE)
  3289. using namespace fpl;
  3290. #   if defined(FPL_ENABLE_WINDOW)
  3291. using namespace fpl::window;
  3292. using namespace fpl::video;
  3293. #   endif
  3294. #   if defined(FPL_ENABLE_AUDIO)
  3295. using namespace fpl::audio;
  3296. #   endif
  3297. using namespace fpl::atomics;
  3298. using namespace fpl::hardware;
  3299. using namespace fpl::memory;
  3300. using namespace fpl::timings;
  3301. using namespace fpl::paths;
  3302. using namespace fpl::files;
  3303. using namespace fpl::library;
  3304. using namespace fpl::strings;
  3305. using namespace fpl::console;
  3306. using namespace fpl::threading;
  3307. #endif // FPL_ENABLE_AUTO_NAMESPACE
  3308.  
  3309. #endif // FPL_INCLUDE_HPP
  3310.  
  3311. // ****************************************************************************
  3312. //
  3313. // > IMPLEMENTATION
  3314. //
  3315. // FPL uses several implementation blocks to structure things in categories.
  3316. // Each block has its own ifdef definition to collapse it down if needed.
  3317. // But the baseline structure is the follow:
  3318. //
  3319. // - Platform Constants & Types (All required structs, Constants, Global variables, etc.)
  3320. // - Common implementations
  3321. // - Actual platform implementations (Win32, Linux)
  3322. // - Sub platform implementations (X11, POSIX, STD)
  3323. // - Driver implementations (Video: OpenGL/Software, Audio: DirectSound/Alsa)
  3324. // - Systems (Audio, Video, Window systems)
  3325. // - Core (Init & Release of the specific platform by selection)
  3326. //
  3327. // You can use the following strings to search for implementation blocks - including the > prefix:
  3328. //
  3329. // > PLATFORM_CONSTANTS
  3330. //
  3331. // > TYPES
  3332. // > TYPES_WIN32
  3333. // > TYPES_POSIX
  3334. // > TYPES_LINUX
  3335. // > TYPES_X11
  3336. //
  3337. // > PLATFORM_STATES
  3338. //
  3339. // > COMMON
  3340. //
  3341. // > WIN32_PLATFORM
  3342. // > LINUX_PLATFORM
  3343. //
  3344. // > POSIX_SUBPLATFORM
  3345. // > X11_SUBPLATFORM
  3346. //
  3347. // > STD_STRINGS_SUBPLATFORM
  3348. // > STD_CONSOLE_SUBPLATFORM
  3349. //
  3350. // > VIDEO_DRIVERS
  3351. // > VIDEO_DRIVER_OPENGL_WIN32
  3352. // > VIDEO_DRIVER_OPENGL_X11
  3353. // > VIDEO_DRIVER_SOFTWARE_WIN32
  3354. //
  3355. // > AUDIO_DRIVERS
  3356. // > AUDIO_DRIVER_DIRECTSOUND
  3357. //
  3358. // > SYSTEM_AUDIO_L1
  3359. // > SYSTEM_VIDEO_L1
  3360. // > SYSTEM_WINDOW
  3361. // > SYSTEM_AUDIO_L2
  3362. // > SYSTEM_VIDEO_L2 (Video backbuffer access and present of the frame)
  3363. // > SYSTEM_INIT (Init & Release of the Platform)
  3364. //
  3365. // ****************************************************************************
  3366. #if defined(FPL_IMPLEMENTATION) && !defined(FPL_IMPLEMENTED)
  3367. #define FPL_IMPLEMENTED
  3368.  
  3369. //
  3370. // Very simple logging system
  3371. //
  3372. #if defined(FPL_ENABLE_LOGGING)
  3373. #   include <stdio.h> // fprintf
  3374. #   define FPL_LOG_FORMAT(what, format) "[" what "] " format "\n"
  3375. #   define FPL_LOG(what, format, ...) do { \
  3376.         ::fprintf(stdout, FPL_LOG_FORMAT(what, format), ## __VA_ARGS__); \
  3377.     } while (0)
  3378. #   define FPL_LOG_FUNCTION_N(what, name) ::fprintf(stdout, "> %s %s\n", what, name)
  3379. #   define FPL_LOG_FUNCTION(what) FPL_LOG_FUNCTION_N(what, FPL_FUNCTION_NAME)
  3380. #   define FPL_LOG_BLOCK_NAME flb__COUNTER__
  3381.  
  3382. struct fplLogBlock {
  3383.     const char *funcName;
  3384.     fplLogBlock(const char *funcName) {
  3385.         this->funcName = funcName;
  3386.         FPL_LOG_FUNCTION_N("Enter", funcName);
  3387.     }
  3388.     ~fplLogBlock() {
  3389.         FPL_LOG_FUNCTION_N("Leave", this->funcName);
  3390.     }
  3391. };
  3392.  
  3393. #   define FPL_LOG_BLOCK_N(name) fplLogBlock FPL_LOG_BLOCK_NAME(name)
  3394. #   define FPL_LOG_BLOCK FPL_LOG_BLOCK_N(FPL_FUNCTION_NAME)
  3395. #else
  3396. #   define FPL_LOG(what, format, ...)
  3397. #   define FPL_LOG_FUNCTION(what)
  3398. #   define FPL_LOG_BLOCK
  3399. #endif
  3400.  
  3401. // ############################################################################
  3402. //
  3403. // > PLATFORM_CONSTANTS
  3404. //
  3405. // ############################################################################
  3406. #if !defined(FPL_PLATFORM_CONSTANTS_DEFINED)
  3407. #define FPL_PLATFORM_CONSTANTS_DEFINED
  3408.  
  3409. #if defined(FPL_PLATFORM_WIN32)
  3410. // @NOTE(final): Required for access "main" from the actual win32 entry point
  3411. fpl_main int main(int argc, char *args[]);
  3412. #endif // FPL_PLATFORM_WIN32
  3413.  
  3414. namespace fpl {
  3415.     namespace platform {
  3416. #   if defined(FPL_PLATFORM_WIN32)
  3417.         fpl_constant char PATH_SEPARATOR = '\\';
  3418.         fpl_constant char FILE_EXT_SEPARATOR = '.';
  3419. #   else
  3420.         fpl_constant char PATH_SEPARATOR = '/';
  3421.         fpl_constant char FILE_EXT_SEPARATOR = '.';
  3422. #   endif
  3423.  
  3424.         // One cacheline worth of padding
  3425.         fpl_constant size_t SIZE_PADDING = 64;
  3426.  
  3427.         struct PlatformAppState;
  3428.         fpl_globalvar PlatformAppState* global__AppState = nullptr;
  3429.     }
  3430.  
  3431.     namespace common {
  3432.         fpl_internal void PushError(const char *format, ...);
  3433.     }
  3434. }
  3435. #endif // FPL_PLATFORM_CONSTANTS_DEFINED
  3436.  
  3437. // ****************************************************************************
  3438. //
  3439. // > TYPES
  3440. //
  3441. // This implementation block includes all the required platform-specific
  3442. // header files and defines all the constants, structures and types.
  3443. //
  3444. // ****************************************************************************
  3445.  
  3446. // ############################################################################
  3447. //
  3448. // > TYPES_WIN32
  3449. //
  3450. // ############################################################################
  3451. #if defined(FPL_PLATFORM_WIN32)
  3452. #   include <windowsx.h>    // Macros for window messages
  3453. #   include <shlobj.h>      // SHGetFolderPath
  3454. #   include <intrin.h>      // Interlock*
  3455. #   include <xinput.h>      // XInputGetState
  3456.  
  3457. // Little macro to not write 5 lines of code all the time
  3458. #define FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(libHandle, libName, target, type, name) \
  3459.     target = (type *)GetProcAddress(libHandle, name); \
  3460.     if (target == nullptr) { \
  3461.         fpl::common::PushError("Failed getting procedure address '%s' from library '%s'", name, libName); \
  3462.         return false; \
  3463.     }
  3464. #define FPL_WIN32_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, target, type, name) \
  3465.     target = (type *)GetProcAddress(libHandle, name); \
  3466.     if (target == nullptr) { \
  3467.         fpl::common::PushError("Failed getting procedure address '%s' from library '%s'", name, libName); \
  3468.         break; \
  3469.     }
  3470.  
  3471. namespace fpl {
  3472.     namespace platform_win32 {
  3473.         //
  3474.         // XInput
  3475.         //
  3476. #       define FPL_XINPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
  3477.         typedef FPL_XINPUT_GET_STATE(win32_func_XInputGetState);
  3478.         FPL_XINPUT_GET_STATE(Win32XInputGetStateStub) {
  3479.             return(ERROR_DEVICE_NOT_CONNECTED);
  3480.         }
  3481. #       define FPL_XINPUT_GET_CAPABILITIES(name) DWORD WINAPI name(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
  3482.         typedef FPL_XINPUT_GET_CAPABILITIES(win32_func_XInputGetCapabilities);
  3483.         FPL_XINPUT_GET_CAPABILITIES(Win32XInputGetCapabilitiesStub) {
  3484.             return(ERROR_DEVICE_NOT_CONNECTED);
  3485.         }
  3486.         struct Win32XInputApi {
  3487.             HMODULE xinputLibrary;
  3488.             win32_func_XInputGetState *xInputGetState = Win32XInputGetStateStub;
  3489.             win32_func_XInputGetCapabilities *xInputGetCapabilities = Win32XInputGetCapabilitiesStub;
  3490.         };
  3491.  
  3492.         fpl_internal void Win32UnloadXInputApi(Win32XInputApi &xinputApi) {
  3493.             if(xinputApi.xinputLibrary) {
  3494.                 ::FreeLibrary(xinputApi.xinputLibrary);
  3495.                 xinputApi.xinputLibrary = nullptr;
  3496.                 xinputApi.xInputGetState = Win32XInputGetStateStub;
  3497.             }
  3498.         }
  3499.  
  3500.         fpl_internal void Win32LoadXInputApi(Win32XInputApi &xinputApi) {
  3501.             FPL_LOG("XInput", "Load XInput Library");
  3502.  
  3503.             // Windows 8
  3504.             HMODULE xinputLibrary = ::LoadLibraryA("xinput1_4.dll");
  3505.             if(!xinputLibrary) {
  3506.                 // Windows 7
  3507.                 xinputLibrary = ::LoadLibraryA("xinput1_3.dll");
  3508.             }
  3509.             if(!xinputLibrary) {
  3510.                 // Windows Generic
  3511.                 xinputLibrary = ::LoadLibraryA("xinput9_1_0.dll");
  3512.             }
  3513.             if(xinputLibrary) {
  3514.                 xinputApi.xinputLibrary = xinputLibrary;
  3515.                 xinputApi.xInputGetState = (win32_func_XInputGetState *)::GetProcAddress(xinputLibrary, "XInputGetState");
  3516.                 xinputApi.xInputGetCapabilities = (win32_func_XInputGetCapabilities *)::GetProcAddress(xinputLibrary, "XInputGetCapabilities");
  3517.             }
  3518.             if(xinputApi.xInputGetState == nullptr) {
  3519.                 xinputApi.xInputGetState = Win32XInputGetStateStub;
  3520.             }
  3521.             if(xinputApi.xInputGetCapabilities == nullptr) {
  3522.                 xinputApi.xInputGetCapabilities = Win32XInputGetCapabilitiesStub;
  3523.             }
  3524.         }
  3525.  
  3526.         //
  3527.         // WINAPI functions
  3528.         //
  3529.  
  3530.         // GDI32
  3531. #       define FPL_FUNC_CHOOSE_PIXEL_FORMAT(name) int WINAPI name(HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd)
  3532.         typedef FPL_FUNC_CHOOSE_PIXEL_FORMAT(win32_func_ChoosePixelFormat);
  3533. #       define FPL_FUNC_SET_PIXEL_FORMAT(name) BOOL WINAPI name(HDC hdc, int format, CONST PIXELFORMATDESCRIPTOR *ppfd)
  3534.         typedef FPL_FUNC_SET_PIXEL_FORMAT(win32_func_SetPixelFormat);
  3535. #       define FPL_FUNC_DESCRIPE_PIXEL_FORMAT(name) int WINAPI name(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd)
  3536.         typedef FPL_FUNC_DESCRIPE_PIXEL_FORMAT(win32_func_DescribePixelFormat);
  3537. #       define FPL_FUNC_GET_DEVICE_CAPS(name) int WINAPI name(HDC hdc, int index)
  3538.         typedef FPL_FUNC_GET_DEVICE_CAPS(win32_func_GetDeviceCaps);
  3539. #       define FPL_FUNC_STRETCH_DIBITS(name) int WINAPI name(HDC hdc, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, int SrcHeight, CONST VOID *lpBits, CONST BITMAPINFO *lpbmi, UINT iUsage, DWORD rop)
  3540.         typedef FPL_FUNC_STRETCH_DIBITS(win32_func_StretchDIBits);
  3541. #       define FPL_FUNC_DELETE_OBJECT(name) BOOL WINAPI name( _In_ HGDIOBJ ho)
  3542.         typedef FPL_FUNC_DELETE_OBJECT(win32_func_DeleteObject);
  3543. #       define FPL_FUNC_SWAP_BUFFERS(name) BOOL WINAPI name(HDC)
  3544.         typedef FPL_FUNC_SWAP_BUFFERS(win32_func_SwapBuffers);
  3545.  
  3546.         // ShellAPI
  3547. #       define FPL_FUNC_COMMAND_LINE_TO_ARGV_W(name) LPWSTR* WINAPI name(LPCWSTR lpCmdLine, int *pNumArgs)
  3548.         typedef FPL_FUNC_COMMAND_LINE_TO_ARGV_W(win32_func_CommandLineToArgvW);
  3549. #       define FPL_FUNC_SH_GET_FOLDER_PATH_A(name) HRESULT WINAPI name(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPSTR pszPath)
  3550.         typedef FPL_FUNC_SH_GET_FOLDER_PATH_A(win32_func_SHGetFolderPathA);
  3551. #       define FPL_FUNC_SH_GET_FOLDER_PATH_W(name) HRESULT WINAPI name(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath)
  3552.         typedef FPL_FUNC_SH_GET_FOLDER_PATH_W(win32_func_SHGetFolderPathW);
  3553.  
  3554.         // User32
  3555. #       define FPL_FUNC_REGISTER_CLASS_EX_A(name) ATOM WINAPI name(CONST WNDCLASSEXA *)
  3556.         typedef FPL_FUNC_REGISTER_CLASS_EX_A(win32_func_RegisterClassExA);
  3557. #       define FPL_FUNC_REGISTER_CLASS_EX_W(name) ATOM WINAPI name(CONST WNDCLASSEXW *)
  3558.         typedef FPL_FUNC_REGISTER_CLASS_EX_W(win32_func_RegisterClassExW);
  3559. #       define FPL_FUNC_UNREGISTER_CLASS_EX_A(name) BOOL WINAPI name(LPCSTR lpClassName, HINSTANCE hInstance)
  3560.         typedef FPL_FUNC_UNREGISTER_CLASS_EX_A(win32_func_UnregisterClassA);
  3561. #       define FPL_FUNC_UNREGISTER_CLASS_EX_W(name) BOOL WINAPI name(LPCWSTR lpClassName, HINSTANCE hInstance)
  3562.         typedef FPL_FUNC_UNREGISTER_CLASS_EX_W(win32_func_UnregisterClassW);
  3563. #       define FPL_FUNC_SHOW_WINDOW(name) BOOL WINAPI name(HWND hWnd, int nCmdShow)
  3564.         typedef FPL_FUNC_SHOW_WINDOW(win32_func_ShowWindow);
  3565. #       define FPL_FUNC_DESTROY_WINDOW(name) BOOL WINAPI name(HWND hWnd)
  3566.         typedef FPL_FUNC_DESTROY_WINDOW(win32_func_DestroyWindow);
  3567. #       define FPL_FUNC_UPDATE_WINDOW(name) BOOL WINAPI name(HWND hWnd)
  3568.         typedef FPL_FUNC_UPDATE_WINDOW(win32_func_UpdateWindow);
  3569. #       define FPL_FUNC_TRANSLATE_MESSAGE(name) BOOL WINAPI name(CONST MSG *lpMsg)
  3570.         typedef FPL_FUNC_TRANSLATE_MESSAGE(win32_func_TranslateMessage);
  3571. #       define FPL_FUNC_DISPATCH_MESSAGE_A(name) LRESULT WINAPI name(CONST MSG *lpMsg)
  3572.         typedef FPL_FUNC_DISPATCH_MESSAGE_A(win32_func_DispatchMessageA);
  3573. #       define FPL_FUNC_DISPATCH_MESSAGE_W(name) LRESULT WINAPI name(CONST MSG *lpMsg)
  3574.         typedef FPL_FUNC_DISPATCH_MESSAGE_W(win32_func_DispatchMessageW);
  3575. #       define FPL_FUNC_PEEK_MESSAGE_A(name) BOOL WINAPI name(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
  3576.         typedef FPL_FUNC_PEEK_MESSAGE_A(win32_func_PeekMessageA);
  3577. #       define FPL_FUNC_PEEK_MESSAGE_W(name) BOOL WINAPI name(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
  3578.         typedef FPL_FUNC_PEEK_MESSAGE_W(win32_func_PeekMessageW);
  3579. #       define FPL_FUNC_DEF_WINDOW_PROC_A(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  3580.         typedef FPL_FUNC_DEF_WINDOW_PROC_A(win32_func_DefWindowProcA);
  3581. #       define FPL_FUNC_DEF_WINDOW_PROC_W(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  3582.         typedef FPL_FUNC_DEF_WINDOW_PROC_W(win32_func_DefWindowProcW);
  3583. #       define FPL_FUNC_CREATE_WINDOW_EX_W(name) HWND WINAPI name(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
  3584.         typedef FPL_FUNC_CREATE_WINDOW_EX_W(win32_func_CreateWindowExW);
  3585. #       define FPL_FUNC_CREATE_WINDOW_EX_A(name) HWND WINAPI name(DWORD dwExStyle, LPCSTR lpClassName, PCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
  3586.         typedef FPL_FUNC_CREATE_WINDOW_EX_A(win32_func_CreateWindowExA);
  3587. #       define FPL_FUNC_SET_WINDOW_POS(name) BOOL WINAPI name(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags)
  3588.         typedef FPL_FUNC_SET_WINDOW_POS(win32_func_SetWindowPos);
  3589. #       define FPL_FUNC_GET_WINDOW_PLACEMENT(name) BOOL WINAPI name(HWND hWnd, WINDOWPLACEMENT *lpwndpl)
  3590.         typedef FPL_FUNC_GET_WINDOW_PLACEMENT(win32_func_GetWindowPlacement);
  3591. #       define FPL_FUNC_SET_WINDOW_PLACEMENT(name) BOOL WINAPI name(HWND hWnd, CONST WINDOWPLACEMENT *lpwndpl)
  3592.         typedef FPL_FUNC_SET_WINDOW_PLACEMENT(win32_func_SetWindowPlacement);
  3593. #       define FPL_FUNC_GET_CLIENT_RECT(name) BOOL WINAPI name(HWND hWnd, LPRECT lpRect)
  3594.         typedef FPL_FUNC_GET_CLIENT_RECT(win32_func_GetClientRect);
  3595. #       define FPL_FUNC_GET_WINDOW_RECT(name) BOOL WINAPI name(HWND hWnd, LPRECT lpRect)
  3596.         typedef FPL_FUNC_GET_WINDOW_RECT(win32_func_GetWindowRect);
  3597. #       define FPL_FUNC_ADJUST_WINDOW_RECT(name) BOOL WINAPI name(LPRECT lpRect, DWORD dwStyle, BOOL bMenu)
  3598.         typedef FPL_FUNC_ADJUST_WINDOW_RECT(win32_func_AdjustWindowRect);
  3599. #       define FPL_FUNC_GET_ASYNC_KEY_STATE(name) SHORT WINAPI name(int vKey)
  3600.         typedef FPL_FUNC_GET_ASYNC_KEY_STATE(win32_func_GetAsyncKeyState);
  3601. #       define FPL_FUNC_MAP_VIRTUAL_KEY_A(name) UINT WINAPI name(UINT uCode, UINT uMapType)
  3602.         typedef FPL_FUNC_MAP_VIRTUAL_KEY_A(win32_func_MapVirtualKeyA);
  3603. #       define FPL_FUNC_MAP_VIRTUAL_KEY_W(name) UINT WINAPI name(UINT uCode, UINT uMapType)
  3604.         typedef FPL_FUNC_MAP_VIRTUAL_KEY_W(win32_func_MapVirtualKeyW);
  3605. #       define FPL_FUNC_SET_CURSOR(name) HCURSOR WINAPI name(HCURSOR hCursor)
  3606.         typedef FPL_FUNC_SET_CURSOR(win32_func_SetCursor);
  3607. #       define FPL_FUNC_GET_CURSOR(name) HCURSOR WINAPI name(VOID)
  3608.         typedef FPL_FUNC_GET_CURSOR(win32_func_GetCursor);
  3609. #       define FPL_FUNC_LOAD_CURSOR_A(name) HCURSOR WINAPI name(HINSTANCE hInstance, LPCSTR lpCursorName)
  3610.         typedef FPL_FUNC_LOAD_CURSOR_A(win32_func_LoadCursorA);
  3611. #       define FPL_FUNC_LOAD_CURSOR_W(name) HCURSOR WINAPI name(HINSTANCE hInstance, LPCWSTR lpCursorName)
  3612.         typedef FPL_FUNC_LOAD_CURSOR_W(win32_func_LoadCursorW);
  3613. #       define FPL_FUNC_LOAD_ICON_A(name) HICON WINAPI name(HINSTANCE hInstance, LPCSTR lpIconName)
  3614.         typedef FPL_FUNC_LOAD_ICON_A(win32_func_LoadIconA);
  3615. #       define FPL_FUNC_LOAD_ICON_W(name) HICON WINAPI name(HINSTANCE hInstance, LPCWSTR lpIconName)
  3616.         typedef FPL_FUNC_LOAD_ICON_W(win32_func_LoadIconW);
  3617. #       define FPL_FUNC_SET_WINDOW_TEXT_A(name) BOOL WINAPI name(HWND hWnd, LPCSTR lpString)
  3618.         typedef FPL_FUNC_SET_WINDOW_TEXT_A(win32_func_SetWindowTextA);
  3619. #       define FPL_FUNC_SET_WINDOW_TEXT_W(name) BOOL WINAPI name(HWND hWnd, LPCWSTR lpString)
  3620.         typedef FPL_FUNC_SET_WINDOW_TEXT_W(win32_func_SetWindowTextW);
  3621. #       define FPL_FUNC_SET_WINDOW_LONG_A(name) LONG WINAPI name(HWND hWnd, int nIndex, LONG dwNewLong)
  3622.         typedef FPL_FUNC_SET_WINDOW_LONG_A(win32_func_SetWindowLongA);
  3623. #       define FPL_FUNC_SET_WINDOW_LONG_W(name) LONG WINAPI name(HWND hWnd, int nIndex, LONG dwNewLong)
  3624.         typedef FPL_FUNC_SET_WINDOW_LONG_W(win32_func_SetWindowLongW);
  3625. #       define FPL_FUNC_GET_WINDOW_LONG_A(name) LONG WINAPI name(HWND hWnd, int nIndex)
  3626.         typedef FPL_FUNC_GET_WINDOW_LONG_A(win32_func_GetWindowLongA);
  3627. #       define FPL_FUNC_GET_WINDOW_LONG_W(name) LONG WINAPI name(HWND hWnd, int nIndex)
  3628.         typedef FPL_FUNC_GET_WINDOW_LONG_W(win32_func_GetWindowLongW);
  3629.  
  3630. #   if defined(FPL_ARCH_X64)
  3631. #       define FPL_FUNC_SET_WINDOW_LONG_PTR_A(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
  3632.         typedef FPL_FUNC_SET_WINDOW_LONG_PTR_A(win32_func_SetWindowLongPtrA);
  3633. #       define FPL_FUNC_SET_WINDOW_LONG_PTR_W(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
  3634.         typedef FPL_FUNC_SET_WINDOW_LONG_PTR_W(win32_func_SetWindowLongPtrW);
  3635. #       define FPL_FUNC_GET_WINDOW_LONG_PTR_A(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex)
  3636.         typedef FPL_FUNC_GET_WINDOW_LONG_PTR_A(win32_func_GetWindowLongPtrA);
  3637. #       define FPL_FUNC_GET_WINDOW_LONG_PTR_W(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex)
  3638.         typedef FPL_FUNC_GET_WINDOW_LONG_PTR_W(win32_func_GetWindowLongPtrW);
  3639. #   endif
  3640.  
  3641. #       define FPL_FUNC_RELEASE_DC(name) int WINAPI name(HWND hWnd, HDC hDC)
  3642.         typedef FPL_FUNC_RELEASE_DC(win32_func_ReleaseDC);
  3643. #       define FPL_FUNC_GET_DC(name) HDC WINAPI name(HWND hWnd)
  3644.         typedef FPL_FUNC_GET_DC(win32_func_GetDC);
  3645. #       define FPL_FUNC_CHANGE_DISPLAY_SETTINGS_A(name) LONG WINAPI name(DEVMODEA* lpDevMode, DWORD dwFlags)
  3646.         typedef FPL_FUNC_CHANGE_DISPLAY_SETTINGS_A(win32_func_ChangeDisplaySettingsA);
  3647. #       define FPL_FUNC_CHANGE_DISPLAY_SETTINGS_W(name) LONG WINAPI name(DEVMODEW* lpDevMode, DWORD dwFlags)
  3648.         typedef FPL_FUNC_CHANGE_DISPLAY_SETTINGS_W(win32_func_ChangeDisplaySettingsW);
  3649. #       define FPL_FUNC_ENUM_DISPLAY_SETTINGS_A(name) BOOL WINAPI name(LPCSTR lpszDeviceName, DWORD iModeNum, DEVMODEA* lpDevMode)
  3650.         typedef FPL_FUNC_ENUM_DISPLAY_SETTINGS_A(win32_func_EnumDisplaySettingsA);
  3651. #       define FPL_FUNC_ENUM_DISPLAY_SETTINGS_W(name) BOOL WINAPI name(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode)
  3652.         typedef FPL_FUNC_ENUM_DISPLAY_SETTINGS_W(win32_func_EnumDisplaySettingsW);
  3653.  
  3654. #       define FPL_FUNC_OPEN_CLIPBOARD(name) BOOL WINAPI name(HWND hWndNewOwner)
  3655.         typedef FPL_FUNC_OPEN_CLIPBOARD(win32_func_OpenClipboard);
  3656. #       define FPL_FUNC_CLOSE_CLIPBOARD(name) BOOL WINAPI name(VOID)
  3657.         typedef FPL_FUNC_CLOSE_CLIPBOARD(win32_func_CloseClipboard);
  3658. #       define FPL_FUNC_EMPTY_CLIPBOARD(name) BOOL WINAPI name(VOID)
  3659.         typedef FPL_FUNC_EMPTY_CLIPBOARD(win32_func_EmptyClipboard);
  3660. #       define FPL_FUNC_IS_CLIPBOARD_FORMAT_AVAILABLE(name) BOOL WINAPI name(UINT format)
  3661.         typedef FPL_FUNC_IS_CLIPBOARD_FORMAT_AVAILABLE(win32_func_IsClipboardFormatAvailable);
  3662. #       define FPL_FUNC_SET_CLIPBOARD_DATA(name) HANDLE WINAPI name(UINT uFormat, HANDLE hMem)
  3663.         typedef FPL_FUNC_SET_CLIPBOARD_DATA(win32_func_SetClipboardData);
  3664. #       define FPL_FUNC_GET_CLIPBOARD_DATA(name) HANDLE WINAPI name(UINT uFormat)
  3665.         typedef FPL_FUNC_GET_CLIPBOARD_DATA(win32_func_GetClipboardData);
  3666.  
  3667. #       define FPL_FUNC_GET_DESKTOP_WINDOW(name) HWND WINAPI name(VOID)
  3668.         typedef FPL_FUNC_GET_DESKTOP_WINDOW(win32_func_GetDesktopWindow);
  3669. #       define FPL_FUNC_GET_FOREGROUND_WINDOW(name) HWND WINAPI name(VOID)
  3670.         typedef FPL_FUNC_GET_FOREGROUND_WINDOW(win32_func_GetForegroundWindow);
  3671.  
  3672. #       define FPL_FUNC_IS_ZOOMED(name) BOOL WINAPI name(HWND hWnd)
  3673.         typedef FPL_FUNC_IS_ZOOMED(win32_func_IsZoomed);
  3674. #       define FPL_FUNC_SEND_MESSAGE_A(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  3675.         typedef FPL_FUNC_SEND_MESSAGE_A(win32_func_SendMessageA);
  3676. #       define FPL_FUNC_SEND_MESSAGE_W(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  3677.         typedef FPL_FUNC_SEND_MESSAGE_W(win32_func_SendMessageW);
  3678. #       define FPL_FUNC_GET_MONITOR_INFO_A(name) BOOL WINAPI name(HMONITOR hMonitor, LPMONITORINFO lpmi)
  3679.         typedef FPL_FUNC_GET_MONITOR_INFO_A(win32_func_GetMonitorInfoA);
  3680. #       define FPL_FUNC_GET_MONITOR_INFO_W(name) BOOL WINAPI name(HMONITOR hMonitor, LPMONITORINFO lpmi)
  3681.         typedef FPL_FUNC_GET_MONITOR_INFO_W(win32_func_GetMonitorInfoW);
  3682. #       define FPL_FUNC_MONITOR_FROM_RECT(name) HMONITOR WINAPI name(LPCRECT lprc, DWORD dwFlags)
  3683.         typedef FPL_FUNC_MONITOR_FROM_RECT(win32_func_MonitorFromRect);
  3684. #       define FPL_FUNC_MONITOR_FROM_WINDOW(name) HMONITOR WINAPI name(HWND hwnd, DWORD dwFlags)
  3685.         typedef FPL_FUNC_MONITOR_FROM_WINDOW(win32_func_MonitorFromWindow);
  3686.  
  3687.         // OLE32
  3688. #       define FPL_FUNC_WIN32_CO_INITIALIZE_EX(name) HRESULT WINAPI name(LPVOID pvReserved, DWORD  dwCoInit)
  3689.         typedef FPL_FUNC_WIN32_CO_INITIALIZE_EX(win32_func_CoInitializeEx);
  3690. #       define FPL_FUNC_WIN32_CO_UNINITIALIZE(name) void WINAPI name(void)
  3691.         typedef FPL_FUNC_WIN32_CO_UNINITIALIZE(win32_func_CoUninitialize);
  3692. #       define FPL_FUNC_WIN32_CO_CREATE_INSTANCE(name) HRESULT WINAPI name(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
  3693.         typedef FPL_FUNC_WIN32_CO_CREATE_INSTANCE(win32_func_CoCreateInstance);
  3694. #       define FPL_FUNC_WIN32_CO_TASK_MEM_FREE(name) void WINAPI name(LPVOID pv)
  3695.         typedef FPL_FUNC_WIN32_CO_TASK_MEM_FREE(win32_func_CoTaskMemFree);
  3696. #       define FPL_FUNC_WIN32_PROP_VARIANT_CLEAR(name) HRESULT WINAPI name(PROPVARIANT *pvar)
  3697.         typedef FPL_FUNC_WIN32_PROP_VARIANT_CLEAR(win32_func_PropVariantClear);
  3698.  
  3699.         struct Win32GdiApi {
  3700.             HMODULE gdiLibrary;
  3701.             win32_func_ChoosePixelFormat *choosePixelFormat;
  3702.             win32_func_SetPixelFormat *setPixelFormat;
  3703.             win32_func_DescribePixelFormat *describePixelFormat;
  3704.             win32_func_GetDeviceCaps *getDeviceCaps;
  3705.             win32_func_StretchDIBits *stretchDIBits;
  3706.             win32_func_DeleteObject *deleteObject;
  3707.             win32_func_SwapBuffers *swapBuffers;
  3708.         };
  3709.  
  3710.         struct Win32ShellApi {
  3711.             HMODULE shellLibrary;
  3712.             win32_func_CommandLineToArgvW *commandLineToArgvW;
  3713.             win32_func_SHGetFolderPathA *shGetFolderPathA;
  3714.             win32_func_SHGetFolderPathW *shGetFolderPathW;
  3715.         };
  3716.  
  3717.         struct Win32UserApi {
  3718.             HMODULE userLibrary;
  3719.             win32_func_RegisterClassExA *registerClassExA;
  3720.             win32_func_RegisterClassExW *registerClassExW;
  3721.             win32_func_UnregisterClassA *unregisterClassA;
  3722.             win32_func_UnregisterClassW *unregisterClassW;
  3723.             win32_func_ShowWindow *showWindow;
  3724.             win32_func_DestroyWindow *destroyWindow;
  3725.             win32_func_UpdateWindow *updateWindow;
  3726.             win32_func_TranslateMessage *translateMessage;
  3727.             win32_func_DispatchMessageA *dispatchMessageA;
  3728.             win32_func_DispatchMessageW *dispatchMessageW;
  3729.             win32_func_PeekMessageA *peekMessageA;
  3730.             win32_func_PeekMessageW *peekMessageW;
  3731.             win32_func_DefWindowProcA *defWindowProcA;
  3732.             win32_func_DefWindowProcW *defWindowProcW;
  3733.             win32_func_CreateWindowExA *createWindowExA;
  3734.             win32_func_CreateWindowExW *createWindowExW;
  3735.             win32_func_SetWindowPos *setWindowPos;
  3736.             win32_func_GetWindowPlacement *getWindowPlacement;
  3737.             win32_func_SetWindowPlacement *setWindowPlacement;
  3738.             win32_func_GetClientRect *getClientRect;
  3739.             win32_func_GetWindowRect *getWindowRect;
  3740.             win32_func_AdjustWindowRect *adjustWindowRect;
  3741.             win32_func_GetAsyncKeyState *getAsyncKeyState;
  3742.             win32_func_MapVirtualKeyA *mapVirtualKeyA;
  3743.             win32_func_MapVirtualKeyW *mapVirtualKeyW;
  3744.             win32_func_SetCursor *setCursor;
  3745.             win32_func_GetCursor *getCursor;
  3746.             win32_func_LoadCursorA *loadCursorA;
  3747.             win32_func_LoadCursorW *loadCursorW;
  3748.             win32_func_LoadIconA *loadIconA;
  3749.             win32_func_LoadIconW *loadIconW;
  3750.             win32_func_SetWindowTextA *setWindowTextA;
  3751.             win32_func_SetWindowTextW *setWindowTextW;
  3752.             win32_func_SetWindowLongA *setWindowLongA;
  3753.             win32_func_SetWindowLongW *setWindowLongW;
  3754.             win32_func_GetWindowLongA *getWindowLongA;
  3755.             win32_func_GetWindowLongW *getWindowLongW;
  3756. #       if defined(FPL_ARCH_X64)
  3757.             win32_func_SetWindowLongPtrA *setWindowLongPtrA;
  3758.             win32_func_SetWindowLongPtrW *setWindowLongPtrW;
  3759.             win32_func_GetWindowLongPtrA *getWindowLongPtrA;
  3760.             win32_func_GetWindowLongPtrW *getWindowLongPtrW;
  3761. #       endif
  3762.             win32_func_ReleaseDC *releaseDC;
  3763.             win32_func_GetDC *getDC;
  3764.             win32_func_ChangeDisplaySettingsA *changeDisplaySettingsA;
  3765.             win32_func_ChangeDisplaySettingsW *changeDisplaySettingsW;
  3766.             win32_func_EnumDisplaySettingsA *enumDisplaySettingsA;
  3767.             win32_func_EnumDisplaySettingsW *enumDisplaySettingsW;
  3768.  
  3769.             win32_func_OpenClipboard *openClipboard;
  3770.             win32_func_CloseClipboard *closeClipboard;
  3771.             win32_func_EmptyClipboard *emptyClipboard;
  3772.             win32_func_IsClipboardFormatAvailable *isClipboardFormatAvailable;
  3773.             win32_func_SetClipboardData *setClipboardData;
  3774.             win32_func_GetClipboardData *getClipboardData;
  3775.  
  3776.             win32_func_GetDesktopWindow *getDesktopWindow;
  3777.             win32_func_GetForegroundWindow *getForegroundWindow;
  3778.             win32_func_IsZoomed *isZoomed;
  3779.             win32_func_SendMessageA *sendMessageA;
  3780.             win32_func_SendMessageW *sendMessageW;
  3781.             win32_func_GetMonitorInfoA *getMonitorInfoA;
  3782.             win32_func_GetMonitorInfoW *getMonitorInfoW;
  3783.             win32_func_MonitorFromRect *monitorFromRect;
  3784.             win32_func_MonitorFromWindow *monitorFromWindow;
  3785.         };
  3786.  
  3787.         struct Win32OleApi {
  3788.             HMODULE oleLibrary;
  3789.             win32_func_CoInitializeEx *coInitializeEx;
  3790.             win32_func_CoUninitialize *coUninitialize;
  3791.             win32_func_CoCreateInstance *coCreateInstance;
  3792.             win32_func_CoTaskMemFree *coTaskMemFree;
  3793.             win32_func_PropVariantClear *propVariantClear;
  3794.         };
  3795.  
  3796.         struct Win32Api {
  3797.             Win32GdiApi gdi;
  3798.             Win32ShellApi shell;
  3799.             Win32UserApi user;
  3800.             Win32OleApi ole;
  3801.         };
  3802.  
  3803.         fpl_internal void Win32UnloadApi(Win32Api &wapi) {
  3804.             if(wapi.ole.oleLibrary != nullptr) {
  3805.                 ::FreeLibrary(wapi.ole.oleLibrary);
  3806.                 wapi.ole = {};
  3807.             }
  3808.             if(wapi.gdi.gdiLibrary != nullptr) {
  3809.                 ::FreeLibrary(wapi.gdi.gdiLibrary);
  3810.                 wapi.gdi = {};
  3811.             }
  3812.             if(wapi.user.userLibrary != nullptr) {
  3813.                 ::FreeLibrary(wapi.user.userLibrary);
  3814.                 wapi.user = {};
  3815.             }
  3816.             if(wapi.shell.shellLibrary != nullptr) {
  3817.                 ::FreeLibrary(wapi.shell.shellLibrary);
  3818.                 wapi.shell = {};
  3819.             }
  3820.         }
  3821.  
  3822.         fpl_internal bool Win32LoadApi(Win32Api &wapi) {
  3823.             // Shell32
  3824.             {
  3825.                 const char *shellLibraryName = "shell32.dll";
  3826.                 HMODULE library = wapi.shell.shellLibrary = ::LoadLibraryA(shellLibraryName);
  3827.                 if(library == nullptr) {
  3828.                     common::PushError("Failed loading library '%s'", shellLibraryName);
  3829.                     return false;
  3830.                 }
  3831.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, shellLibraryName, wapi.shell.commandLineToArgvW, win32_func_CommandLineToArgvW, "CommandLineToArgvW");
  3832.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, shellLibraryName, wapi.shell.shGetFolderPathA, win32_func_SHGetFolderPathA, "SHGetFolderPathA");
  3833.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, shellLibraryName, wapi.shell.shGetFolderPathW, win32_func_SHGetFolderPathW, "SHGetFolderPathW");
  3834.             }
  3835.  
  3836.             // User32
  3837.             {
  3838.                 const char *userLibraryName = "user32.dll";
  3839.                 HMODULE library = wapi.user.userLibrary = ::LoadLibraryA(userLibraryName);
  3840.                 if(library == nullptr) {
  3841.                     common::PushError("Failed loading library '%s'", userLibraryName);
  3842.                     return false;
  3843.                 }
  3844.  
  3845.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.registerClassExA, win32_func_RegisterClassExA, "RegisterClassExA");
  3846.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.registerClassExW, win32_func_RegisterClassExW, "RegisterClassExW");
  3847.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.unregisterClassA, win32_func_UnregisterClassA, "UnregisterClassA");
  3848.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.unregisterClassW, win32_func_UnregisterClassW, "UnregisterClassW");
  3849.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.showWindow, win32_func_ShowWindow, "ShowWindow");
  3850.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.destroyWindow, win32_func_DestroyWindow, "DestroyWindow");
  3851.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.updateWindow, win32_func_UpdateWindow, "UpdateWindow");
  3852.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.translateMessage, win32_func_TranslateMessage, "TranslateMessage");
  3853.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.dispatchMessageA, win32_func_DispatchMessageA, "DispatchMessageA");
  3854.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.dispatchMessageW, win32_func_DispatchMessageW, "DispatchMessageW");
  3855.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.peekMessageA, win32_func_PeekMessageA, "PeekMessageA");
  3856.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.peekMessageW, win32_func_PeekMessageW, "PeekMessageW");
  3857.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.defWindowProcA, win32_func_DefWindowProcA, "DefWindowProcA");
  3858.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.defWindowProcW, win32_func_DefWindowProcW, "DefWindowProcW");
  3859.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.createWindowExA, win32_func_CreateWindowExA, "CreateWindowExA");
  3860.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.createWindowExW, win32_func_CreateWindowExW, "CreateWindowExW");
  3861.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowPos, win32_func_SetWindowPos, "SetWindowPos");
  3862.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowPlacement, win32_func_GetWindowPlacement, "GetWindowPlacement");
  3863.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowPlacement, win32_func_SetWindowPlacement, "SetWindowPlacement");
  3864.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getClientRect, win32_func_GetClientRect, "GetClientRect");
  3865.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowRect, win32_func_GetWindowRect, "GetWindowRect");
  3866.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.adjustWindowRect, win32_func_AdjustWindowRect, "AdjustWindowRect");
  3867.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getAsyncKeyState, win32_func_GetAsyncKeyState, "GetAsyncKeyState");
  3868.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.mapVirtualKeyA, win32_func_MapVirtualKeyA, "MapVirtualKeyA");
  3869.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.mapVirtualKeyW, win32_func_MapVirtualKeyW, "MapVirtualKeyW");
  3870.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setCursor, win32_func_SetCursor, "SetCursor");
  3871.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getCursor, win32_func_GetCursor, "GetCursor");
  3872.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.loadCursorA, win32_func_LoadCursorA, "LoadCursorA");
  3873.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.loadCursorW, win32_func_LoadCursorW, "LoadCursorW");
  3874.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.loadIconA, win32_func_LoadIconA, "LoadCursorA");
  3875.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.loadIconW, win32_func_LoadIconW, "LoadIconW");
  3876.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowTextA, win32_func_SetWindowTextA, "SetWindowTextA");
  3877.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowTextW, win32_func_SetWindowTextW, "SetWindowTextW");
  3878.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowLongA, win32_func_SetWindowLongA, "SetWindowLongA");
  3879.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowLongW, win32_func_SetWindowLongW, "SetWindowLongW");
  3880.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowLongA, win32_func_GetWindowLongA, "GetWindowLongA");
  3881.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowLongW, win32_func_GetWindowLongW, "GetWindowLongW");
  3882.  
  3883. #               if defined(FPL_ARCH_X64)
  3884.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowLongPtrA, win32_func_SetWindowLongPtrA, "SetWindowLongPtrA");
  3885.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setWindowLongPtrW, win32_func_SetWindowLongPtrW, "SetWindowLongPtrW");
  3886.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowLongPtrA, win32_func_GetWindowLongPtrA, "GetWindowLongPtrA");
  3887.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getWindowLongPtrW, win32_func_GetWindowLongPtrW, "GetWindowLongPtrW");
  3888. #               endif
  3889.  
  3890.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.releaseDC, win32_func_ReleaseDC, "ReleaseDC");
  3891.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getDC, win32_func_GetDC, "GetDC");
  3892.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.changeDisplaySettingsA, win32_func_ChangeDisplaySettingsA, "ChangeDisplaySettingsA");
  3893.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.changeDisplaySettingsW, win32_func_ChangeDisplaySettingsW, "ChangeDisplaySettingsW");
  3894.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.enumDisplaySettingsA, win32_func_EnumDisplaySettingsA, "EnumDisplaySettingsA");
  3895.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.enumDisplaySettingsW, win32_func_EnumDisplaySettingsW, "EnumDisplaySettingsW");
  3896.  
  3897.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.openClipboard, win32_func_OpenClipboard, "OpenClipboard");
  3898.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.closeClipboard, win32_func_CloseClipboard, "CloseClipboard");
  3899.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.emptyClipboard, win32_func_EmptyClipboard, "EmptyClipboard");
  3900.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.setClipboardData, win32_func_SetClipboardData, "SetClipboardData");
  3901.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getClipboardData, win32_func_GetClipboardData, "GetClipboardData");
  3902.  
  3903.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getDesktopWindow, win32_func_GetDesktopWindow, "GetDesktopWindow");
  3904.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getForegroundWindow, win32_func_GetForegroundWindow, "GetForegroundWindow");
  3905.  
  3906.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.isZoomed, win32_func_IsZoomed, "IsZoomed");
  3907.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.sendMessageA, win32_func_SendMessageA, "SendMessageA");
  3908.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.sendMessageW, win32_func_SendMessageW, "SendMessageW");
  3909.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getMonitorInfoA, win32_func_GetMonitorInfoA, "GetMonitorInfoA");
  3910.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.getMonitorInfoW, win32_func_GetMonitorInfoW, "GetMonitorInfoW");
  3911.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.monitorFromRect, win32_func_MonitorFromRect, "MonitorFromRect");
  3912.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, userLibraryName, wapi.user.monitorFromWindow, win32_func_MonitorFromWindow, "MonitorFromWindow");
  3913.             }
  3914.  
  3915.             // GDI32
  3916.             {
  3917.                 const char *gdiLibraryName = "gdi32.dll";
  3918.                 HMODULE library = wapi.gdi.gdiLibrary = ::LoadLibraryA(gdiLibraryName);
  3919.                 if(library == nullptr) {
  3920.                     common::PushError("Failed loading library '%s'", gdiLibraryName);
  3921.                     return false;
  3922.                 }
  3923.  
  3924.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.choosePixelFormat, win32_func_ChoosePixelFormat, "ChoosePixelFormat");
  3925.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.setPixelFormat, win32_func_SetPixelFormat, "SetPixelFormat");
  3926.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.describePixelFormat, win32_func_DescribePixelFormat, "DescribePixelFormat");
  3927.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.stretchDIBits, win32_func_StretchDIBits, "StretchDIBits");
  3928.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.deleteObject, win32_func_DeleteObject, "DeleteObject");
  3929.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.swapBuffers, win32_func_SwapBuffers, "SwapBuffers");
  3930.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, gdiLibraryName, wapi.gdi.getDeviceCaps, win32_func_GetDeviceCaps, "GetDeviceCaps");
  3931.             }
  3932.  
  3933.             // OLE32
  3934.             {
  3935.                 const char *oleLibraryName = "ole32.dll";
  3936.                 HMODULE library = wapi.ole.oleLibrary = ::LoadLibraryA(oleLibraryName);
  3937.                 if(library == nullptr) {
  3938.                     common::PushError("Failed loading library '%s'", oleLibraryName);
  3939.                     return false;
  3940.                 }
  3941.  
  3942.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, oleLibraryName, wapi.ole.coInitializeEx, win32_func_CoInitializeEx, "CoInitializeEx");
  3943.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, oleLibraryName, wapi.ole.coUninitialize, win32_func_CoUninitialize, "CoUninitialize");
  3944.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, oleLibraryName, wapi.ole.coCreateInstance, win32_func_CoCreateInstance, "CoCreateInstance");
  3945.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, oleLibraryName, wapi.ole.coTaskMemFree, win32_func_CoTaskMemFree, "CoTaskMemFree");
  3946.                 FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(library, oleLibraryName, wapi.ole.propVariantClear, win32_func_PropVariantClear, "PropVariantClear");
  3947.             }
  3948.  
  3949.             return true;
  3950.         }
  3951.  
  3952.         // Unicode dependent function calls and types
  3953. #   if !defined(UNICODE)
  3954. #       define FPL_WIN32_CLASSNAME "FPLWindowClassA"
  3955. #       define FPL_WIN32_UNNAMED_WINDOW "Unnamed FPL Ansi Window"
  3956.         typedef char win32_char;
  3957. #       define win32_copyString strings::CopyAnsiString
  3958. #       define win32_getStringLength strings::GetAnsiStringLength
  3959. #       define win32_ansiToString strings::CopyAnsiString
  3960. #       define win32_wndclassex WNDCLASSEXA
  3961. #       if defined(FPL_ARCH_X64)
  3962. #           define win32_setWindowLongPtr platform::global__AppState->win32.winApi.user.setWindowLongPtrA
  3963. #       else
  3964. #           define win32_setWindowLongPtr platform::global__AppState->win32.winApi.user.setWindowLongA
  3965. #       endif
  3966. #       define win32_setWindowLong platform::global__AppState->win32.winApi.user.setWindowLongA
  3967. #       define win32_getWindowLong platform::global__AppState->win32.winApi.user.getWindowLongA
  3968. #       define win32_peekMessage platform::global__AppState->win32.winApi.user.peekMessageA
  3969. #       define win32_dispatchMessage platform::global__AppState->win32.winApi.user.dispatchMessageA
  3970. #       define win32_defWindowProc platform::global__AppState->win32.winApi.user.defWindowProcA
  3971. #       define win32_registerClassEx platform::global__AppState->win32.winApi.user.registerClassExA
  3972. #       define win32_unregisterClass platform::global__AppState->win32.winApi.user.unregisterClassA
  3973. #       define win32_createWindowEx platform::global__AppState->win32.winApi.user.createWindowExA
  3974. #       define win32_loadIcon platform::global__AppState->win32.winApi.user.loadIconA
  3975. #       define win32_loadCursor platform::global__AppState->win32.winApi.user.loadCursorA
  3976. #       define win32_sendMessage platform::global__AppState->win32.winApi.user.sendMessageA
  3977. #       define win32_getMonitorInfo platform::global__AppState->win32.winApi.user.getMonitorInfoA
  3978. #   else
  3979. #       define FPL_WIN32_CLASSNAME L"FPLWindowClassW"
  3980. #       define FPL_WIN32_UNNAMED_WINDOW L"Unnamed FPL Unicode Window"
  3981.         typedef wchar_t win32_char;
  3982. #       define win32_copyString strings::CopyWideString
  3983. #       define win32_getStringLength strings::GetWideStringLength
  3984. #       define win32_ansiToString strings::AnsiStringToWideString
  3985. #       define win32_wndclassex WNDCLASSEXW
  3986. #       if defined(FPL_ARCH_X64)
  3987. #           define win32_setWindowLongPtr platform::global__AppState->win32.winApi.user.setWindowLongPtrW
  3988. #       else
  3989. #           define win32_setWindowLongPtr platform::global__AppState->win32.winApi.user.setWindowLongW
  3990. #       endif
  3991. #       define win32_setWindowLong platform::global__AppState->win32.winApi.user.setWindowLongW
  3992. #       define win32_getWindowLong platform::global__AppState->win32.winApi.user.getWindowLongW
  3993. #       define win32_peekMessage platform::global__AppState->win32.winApi.user.peekMessageW
  3994. #       define win32_dispatchMessage platform::global__AppState->win32.winApi.user.dispatchMessageW
  3995. #       define win32_defWindowProc platform::global__AppState->win32.winApi.user.defWindowProcW
  3996. #       define win32_registerClassEx platform::global__AppState->win32.winApi.user.registerClassExW
  3997. #       define win32_unregisterClass platform::global__AppState->win32.winApi.user.unregisterClassW
  3998. #       define win32_createWindowEx platform::global__AppState->win32.winApi.user.createWindowExW
  3999. #       define win32_loadIcon platform::global__AppState->win32.winApi.user.loadIconW
  4000. #       define win32_loadCursor platform::global__AppState->win32.winApi.user.loadCursorW
  4001. #       define win32_sendMessage platform::global__AppState->win32.winApi.user.sendMessageW
  4002. #       define win32_getMonitorInfo platform::global__AppState->win32.winApi.user.getMonitorInfoW
  4003. #   endif // UNICODE
  4004.  
  4005.         struct Win32XInputState {
  4006.             bool isConnected[XUSER_MAX_COUNT];
  4007.             LARGE_INTEGER lastDeviceSearchTime;
  4008.             Win32XInputApi xinputApi;
  4009.         };
  4010.  
  4011.         struct Win32InitState {
  4012.             HINSTANCE appInstance;
  4013.             LARGE_INTEGER performanceFrequency;
  4014.         };
  4015.  
  4016.         struct Win32AppState {
  4017.             Win32XInputState xinput;
  4018.             Win32Api winApi;
  4019.         };
  4020.  
  4021. #   if defined(FPL_ENABLE_WINDOW)
  4022.         struct Win32LastWindowInfo {
  4023.             WINDOWPLACEMENT placement;
  4024.             DWORD style;
  4025.             DWORD exStyle;
  4026.             bool isMaximized;
  4027.             bool wasResolutionChanged;
  4028.         };
  4029.  
  4030.         struct Win32WindowState {
  4031.             win32_char windowClass[256];
  4032.             HWND windowHandle;
  4033.             HDC deviceContext;
  4034.             HCURSOR defaultCursor;
  4035.             Win32LastWindowInfo lastFullscreenInfo;
  4036.             bool isRunning;
  4037.             bool isCursorActive;
  4038.         };
  4039. #   endif // FPL_ENABLE_WINDOW
  4040.  
  4041.     } // platform_win32
  4042. } // fpl
  4043. #endif // FPL_PLATFORM_WIN32
  4044.  
  4045. // ############################################################################
  4046. //
  4047. // > TYPES_POSIX
  4048. //
  4049. // ############################################################################
  4050. #if defined(FPL_SUBPLATFORM_POSIX)
  4051. #   include <sys/mman.h> // mmap, munmap
  4052. #   include <sys/types.h> // data types
  4053. #   include <sys/stat.h> // mkdir
  4054. #   include <sys/errno.h> // errno
  4055. #   include <signal.h> // pthread_kill
  4056. #   include <time.h> // clock_gettime, nanosleep
  4057. #   include <dlfcn.h> // dlopen, dlclose
  4058. #   include <fcntl.h> // open
  4059. #   include <unistd.h> // read, write, close, access, rmdir
  4060.  
  4061. // Little macro to not write 5 lines of code all the time
  4062. #   define FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, target, type, name) \
  4063.         target = (type *)::dlsym(libHandle, name); \
  4064.         if (target == nullptr) { \
  4065.             fpl::common::PushError("Failed getting '%s' from library '%s'", name, libName); \
  4066.             break; \
  4067.         }
  4068.  
  4069. namespace fpl {
  4070.     namespace subplatform_posix {
  4071. #       define FPL_FUNC_PTHREAD_CREATE(name) int name(pthread_t *, const pthread_attr_t *, void *(*__start_routine) (void *), void *)
  4072.         typedef FPL_FUNC_PTHREAD_CREATE(pthread_func_pthread_create);
  4073. #       define FPL_FUNC_PTHREAD_KILL(name) int name(pthread_t thread, int sig)
  4074.         typedef FPL_FUNC_PTHREAD_KILL(pthread_func_pthread_kill);
  4075. #       define FPL_FUNC_PTHREAD_JOIN(name) int name(pthread_t __th, void **__thread_return)
  4076.         typedef FPL_FUNC_PTHREAD_JOIN(pthread_func_pthread_join);
  4077. #       define FPL_FUNC_PTHREAD_EXIT(name) void name(void *__retval)
  4078.         typedef FPL_FUNC_PTHREAD_EXIT(pthread_func_pthread_exit);
  4079. #       define FPL_FUNC_PTHREAD_YIELD(name) int name(void)
  4080.         typedef FPL_FUNC_PTHREAD_YIELD(pthread_func_pthread_yield);
  4081.  
  4082. #       define FPL_FUNC_PTHREAD_MUTEX_INIT(name) int name(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
  4083.         typedef FPL_FUNC_PTHREAD_MUTEX_INIT(pthread_func_pthread_mutex_init);
  4084. #       define FPL_FUNC_PTHREAD_MUTEX_DESTROY(name) int name(pthread_mutex_t *mutex)
  4085.         typedef FPL_FUNC_PTHREAD_MUTEX_DESTROY(pthread_func_pthread_mutex_destroy);
  4086. #       define FPL_FUNC_PTHREAD_MUTEX_LOCK(name) int name(pthread_mutex_t *mutex)
  4087.         typedef FPL_FUNC_PTHREAD_MUTEX_LOCK(pthread_func_pthread_mutex_lock);
  4088. #       define FPL_FUNC_PTHREAD_MUTEX_TRYLOCK(name) int name(pthread_mutex_t *mutex)
  4089.         typedef FPL_FUNC_PTHREAD_MUTEX_TRYLOCK(pthread_func_pthread_mutex_trylock);
  4090. #       define FPL_FUNC_PTHREAD_MUTEX_UNLOCK(name) int name(pthread_mutex_t *mutex)
  4091.         typedef FPL_FUNC_PTHREAD_MUTEX_UNLOCK(pthread_func_pthread_mutex_unlock);
  4092.  
  4093. #       define FPL_FUNC_PTHREAD_COND_INIT(name) int name(pthread_cond_t *cond, const pthread_condattr_t *attr)
  4094.         typedef FPL_FUNC_PTHREAD_COND_INIT(pthread_func_pthread_cond_init);
  4095. #       define FPL_FUNC_PTHREAD_COND_DESTROY(name) int name(pthread_cond_t *cond)
  4096.         typedef FPL_FUNC_PTHREAD_COND_DESTROY(pthread_func_pthread_cond_destroy);
  4097. #       define FPL_FUNC_PTHREAD_COND_TIMEDWAIT(name) int name(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
  4098.         typedef FPL_FUNC_PTHREAD_COND_TIMEDWAIT(pthread_func_pthread_cond_timedwait);
  4099. #       define FPL_FUNC_PTHREAD_COND_WAIT(name) int name(pthread_cond_t *cond, pthread_mutex_t *mutex)
  4100.         typedef FPL_FUNC_PTHREAD_COND_WAIT(pthread_func_pthread_cond_wait);
  4101. #       define FPL_FUNC_PTHREAD_COND_BROADCAST(name) int name(pthread_cond_t *cond)
  4102.         typedef FPL_FUNC_PTHREAD_COND_BROADCAST(pthread_func_pthread_cond_broadcast);
  4103. #       define FPL_FUNC_PTHREAD_COND_SIGNAL(name) int name(pthread_cond_t *cond)
  4104.         typedef FPL_FUNC_PTHREAD_COND_SIGNAL(pthread_func_pthread_cond_signal);
  4105.  
  4106.  
  4107.         struct PThreadApi {
  4108.             void *libHandle;
  4109.             pthread_func_pthread_create *pthread_create;
  4110.             pthread_func_pthread_kill *pthread_kill;
  4111.             pthread_func_pthread_join *pthread_join;
  4112.             pthread_func_pthread_exit *pthread_exit;
  4113.             pthread_func_pthread_yield *pthread_yield;
  4114.  
  4115.             pthread_func_pthread_mutex_init *pthread_mutex_init;
  4116.             pthread_func_pthread_mutex_destroy *pthread_mutex_destroy;
  4117.             pthread_func_pthread_mutex_lock *pthread_mutex_lock;
  4118.             pthread_func_pthread_mutex_trylock *pthread_mutex_trylock;
  4119.             pthread_func_pthread_mutex_unlock *pthread_mutex_unlock;
  4120.  
  4121.             pthread_func_pthread_cond_init *pthread_cond_init;
  4122.             pthread_func_pthread_cond_destroy *pthread_cond_destroy;
  4123.             pthread_func_pthread_cond_timedwait *pthread_cond_timedwait;
  4124.             pthread_func_pthread_cond_wait *pthread_cond_wait;
  4125.             pthread_func_pthread_cond_broadcast *pthread_cond_broadcast;
  4126.             pthread_func_pthread_cond_signal *pthread_cond_signal;
  4127.         };
  4128.  
  4129.         fpl_constant int DL_LOADTYPE = RTLD_NOW;
  4130.  
  4131.         fpl_internal void UnloadPThreadApi(PThreadApi &pthreadApi) {
  4132.             if(pthreadApi.libHandle != nullptr) {
  4133.                 dlclose(pthreadApi.libHandle);
  4134.             }
  4135.             pthreadApi = {};
  4136.         }
  4137.  
  4138.         fpl_internal bool LoadPThreadApi(PThreadApi &pthreadApi) {
  4139.             const char* libpthreadFileNames[] = {
  4140.                 "libpthread.so",
  4141.                 "libpthread.so.0",
  4142.             };
  4143.             bool result = false;
  4144.             for(uint32_t index = 0; index < FPL_ARRAYCOUNT(libpthreadFileNames); ++index) {
  4145.                 const char * libName = libpthreadFileNames[index];
  4146.                 void *libHandle = pthreadApi.libHandle = ::dlopen(libName, DL_LOADTYPE);
  4147.                 if(libHandle != nullptr) {
  4148.                     // pthread_t
  4149.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_create, pthread_func_pthread_create, "pthread_create");
  4150.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_kill, pthread_func_pthread_kill, "pthread_kill");
  4151.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_join, pthread_func_pthread_join, "pthread_join");
  4152.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_exit, pthread_func_pthread_exit, "pthread_exit");
  4153.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_yield, pthread_func_pthread_yield, "pthread_yield");
  4154.  
  4155.                     // pthread_mutex_t
  4156.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_mutex_init, pthread_func_pthread_mutex_init, "pthread_mutex_init");
  4157.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_mutex_destroy, pthread_func_pthread_mutex_destroy, "pthread_mutex_destroy");
  4158.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_mutex_lock, pthread_func_pthread_mutex_lock, "pthread_mutex_lock");
  4159.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_mutex_trylock, pthread_func_pthread_mutex_trylock, "pthread_mutex_trylock");
  4160.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_mutex_unlock, pthread_func_pthread_mutex_unlock, "pthread_mutex_unlock");
  4161.  
  4162.                     // pthread_cond_t
  4163.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_init, pthread_func_pthread_cond_init, "pthread_cond_init");
  4164.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_destroy, pthread_func_pthread_cond_destroy, "pthread_cond_destroy");
  4165.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_timedwait, pthread_func_pthread_cond_timedwait, "pthread_cond_timedwait");
  4166.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_wait, pthread_func_pthread_cond_wait, "pthread_cond_wait");
  4167.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_broadcast, pthread_func_pthread_cond_broadcast, "pthread_cond_broadcast");
  4168.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, pthreadApi.pthread_cond_signal, pthread_func_pthread_cond_signal, "pthread_cond_signal");
  4169.                     result = true;
  4170.                     break;
  4171.                 }
  4172.                 UnloadPThreadApi(pthreadApi);
  4173.             }
  4174.             return(result);
  4175.         }
  4176.  
  4177.         struct PosixInitState {
  4178.         };
  4179.  
  4180.         struct PosixAppState {
  4181.             PThreadApi pthreadApi;
  4182.         };
  4183.  
  4184.  
  4185.     } // subplatform_posix
  4186. } // fpl
  4187. #endif // FPL_SUBPLATFORM_POSIX
  4188.  
  4189. // ############################################################################
  4190. //
  4191. // > TYPES_LINUX
  4192. //
  4193. // ############################################################################
  4194. #if defined(FPL_PLATFORM_LINUX)
  4195. namespace fpl {
  4196.     namespace platform_linux {
  4197.         struct LinuxInitState {
  4198.         };
  4199.  
  4200.         struct LinuxAppState {
  4201.         };
  4202.     } // platform_linux
  4203. } // fpl
  4204. #endif // FPL_PLATFORM_LINUX
  4205.  
  4206. // ############################################################################
  4207. //
  4208. // > TYPES_X11
  4209. //
  4210. // ############################################################################
  4211. #if defined(FPL_SUBPLATFORM_X11)
  4212. namespace fpl {
  4213.     namespace subplatform_x11 {
  4214.         //
  4215.         // X11 Api
  4216.         //
  4217. #       define FPL_FUNC_X11_X_FREE(name) int name(void *data)
  4218.         typedef FPL_FUNC_X11_X_FREE(fpl_func_x11_XFree);
  4219. #       define FPL_FUNC_X11_X_FLUSH(name) void name(Display *display)
  4220.         typedef FPL_FUNC_X11_X_FLUSH(fpl_func_x11_XFlush);
  4221. #       define FPL_FUNC_X11_X_OPEN_DISPLAY(name) Display *name(char *display_name)
  4222.         typedef FPL_FUNC_X11_X_OPEN_DISPLAY(fpl_func_x11_XOpenDisplay);
  4223. #       define FPL_FUNC_X11_X_CLOSE_DISPLAY(name) int name(Display *display)
  4224.         typedef FPL_FUNC_X11_X_CLOSE_DISPLAY(fpl_func_x11_XCloseDisplay);
  4225. #       define FPL_FUNC_X11_X_DEFAULT_SCREEN(name) int name(Display *display)
  4226.         typedef FPL_FUNC_X11_X_DEFAULT_SCREEN(fpl_func_x11_XDefaultScreen);
  4227. #       define FPL_FUNC_X11_X_ROOT_WINDOW(name) Window name(Display *display, int screen_number)
  4228.         typedef FPL_FUNC_X11_X_ROOT_WINDOW(fpl_func_x11_XRootWindow);
  4229. #       define FPL_FUNC_X11_X_CREATE_WINDOW(name) Window name(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int clazz, Visual *visual, unsigned long valuemask, XSetWindowAttributes *attributes)
  4230.         typedef FPL_FUNC_X11_X_CREATE_WINDOW(fpl_func_x11_XCreateWindow);
  4231. #       define FPL_FUNC_X11_X_DESTROY_WINDOW(name) int name(Display *display, Window w)
  4232.         typedef FPL_FUNC_X11_X_DESTROY_WINDOW(fpl_func_x11_XDestroyWindow);
  4233. #       define FPL_FUNC_X11_X_CREATE_COLORMAP(name) Colormap name(Display *display, Window w, Visual *visual, int alloc)
  4234.         typedef FPL_FUNC_X11_X_CREATE_COLORMAP(fpl_func_x11_XCreateColormap);
  4235. #       define FPL_FUNC_X11_X_DEFAULT_COLORMAP(name) Colormap name(Display *display, int screen_number)
  4236.         typedef FPL_FUNC_X11_X_DEFAULT_COLORMAP(fpl_func_x11_XDefaultColormap);
  4237. #       define FPL_FUNC_X11_X_FREE_COLORMAP(name) void name(Display *display, Colormap colormap)
  4238.         typedef FPL_FUNC_X11_X_FREE_COLORMAP(fpl_func_x11_XFreeColormap);
  4239. #       define FPL_FUNC_X11_X_MAP_WINDOW(name) void name(Display *display, Window w)
  4240.         typedef FPL_FUNC_X11_X_MAP_WINDOW(fpl_func_x11_XMapWindow);
  4241. #       define FPL_FUNC_X11_X_UNMAP_WINDOW(name) void name(Display *display, Window w)
  4242.         typedef FPL_FUNC_X11_X_UNMAP_WINDOW(fpl_func_x11_XUnmapWindow);
  4243. #       define FPL_FUNC_X11_X_STORE_NAME(name) void name(Display *display, Window w, char *windowName)
  4244.         typedef FPL_FUNC_X11_X_STORE_NAME(fpl_func_x11_XStoreName);
  4245. #       define FPL_FUNC_X11_X_DEFAULT_VISUAL(name) Visual *name(Display *display, int screen_number)
  4246.         typedef FPL_FUNC_X11_X_DEFAULT_VISUAL(fpl_func_x11_XDefaultVisual);
  4247. #       define FPL_FUNC_X11_X_DEFAULT_DEPTH(name) int name(Display *display, int screen_number)
  4248.         typedef FPL_FUNC_X11_X_DEFAULT_DEPTH(fpl_func_x11_XDefaultDepth);
  4249. #       define FPL_FUNC_X11_X_SET_ERROR_HANDLER(name) XErrorHandler name(XErrorHandler handler)
  4250.         typedef FPL_FUNC_X11_X_SET_ERROR_HANDLER(fpl_func_x11_XSetErrorHandler);
  4251.  
  4252.         struct X11Api {
  4253.             void *libHandle;
  4254.             fpl_func_x11_XFlush *XFlush;
  4255.             fpl_func_x11_XFree *XFree;
  4256.             fpl_func_x11_XOpenDisplay *XOpenDisplay;
  4257.             fpl_func_x11_XCloseDisplay *XCloseDisplay;
  4258.             fpl_func_x11_XDefaultScreen *XDefaultScreen;
  4259.             fpl_func_x11_XRootWindow *XRootWindow;
  4260.             fpl_func_x11_XCreateWindow *XCreateWindow;
  4261.             fpl_func_x11_XDestroyWindow *XDestroyWindow;
  4262.             fpl_func_x11_XCreateColormap *XCreateColormap;
  4263.             fpl_func_x11_XFreeColormap *XFreeColormap;
  4264.             fpl_func_x11_XDefaultColormap *XDefaultColormap;
  4265.             fpl_func_x11_XMapWindow *XMapWindow;
  4266.             fpl_func_x11_XUnmapWindow *XUnmapWindow;
  4267.             fpl_func_x11_XStoreName *XStoreName;
  4268.             fpl_func_x11_XDefaultVisual *XDefaultVisual;
  4269.             fpl_func_x11_XDefaultDepth *XDefaultDepth;
  4270.             fpl_func_x11_XSetErrorHandler *XSetErrorHandler;
  4271.         };
  4272.  
  4273.         fpl_internal void UnloadX11Api(X11Api &x11Api) {
  4274.             if(x11Api.libHandle != nullptr) {
  4275.                 ::dlclose(x11Api.libHandle);
  4276.             }
  4277.             x11Api = {};
  4278.         }
  4279.  
  4280.         fpl_internal bool LoadX11Api(X11Api &x11Api) {
  4281.             const char* libFileNames[] = {
  4282.                 "libX11.so",
  4283.                 "libX11.so.7",
  4284.                 "libX11.so.6",
  4285.                 "libX11.so.5",
  4286.             };
  4287.             bool result = false;
  4288.             for(uint32_t index = 0; index < FPL_ARRAYCOUNT(libFileNames); ++index) {
  4289.                 const char *libName = libFileNames[index];
  4290.                 void *libHandle = x11Api.libHandle = ::dlopen(libName, subplatform_posix::DL_LOADTYPE);
  4291.                 if(libHandle != nullptr) {
  4292.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFlush, fpl_func_x11_XFlush, "XFlush");
  4293.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFree, fpl_func_x11_XFree, "XFree");
  4294.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XOpenDisplay, fpl_func_x11_XOpenDisplay, "XOpenDisplay");
  4295.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCloseDisplay, fpl_func_x11_XCloseDisplay, "XCloseDisplay");
  4296.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultScreen, fpl_func_x11_XDefaultScreen, "XDefaultScreen");
  4297.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XRootWindow, fpl_func_x11_XRootWindow, "XRootWindow");
  4298.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCreateWindow, fpl_func_x11_XCreateWindow, "XCreateWindow");
  4299.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDestroyWindow, fpl_func_x11_XDestroyWindow, "XDestroyWindow");
  4300.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XCreateColormap, fpl_func_x11_XCreateColormap, "XCreateColormap");
  4301.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XFreeColormap, fpl_func_x11_XFreeColormap, "XFreeColormap");
  4302.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultColormap, fpl_func_x11_XDefaultColormap, "XDefaultColormap");
  4303.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XMapWindow, fpl_func_x11_XMapWindow, "XMapWindow");
  4304.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XUnmapWindow, fpl_func_x11_XUnmapWindow, "XUnmapWindow");
  4305.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XStoreName, fpl_func_x11_XStoreName, "XStoreName");
  4306.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultVisual, fpl_func_x11_XDefaultVisual, "XDefaultVisual");
  4307.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XDefaultDepth, fpl_func_x11_XDefaultDepth, "XDefaultDepth");
  4308.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, x11Api.XSetErrorHandler, fpl_func_x11_XSetErrorHandler, "XSetErrorHandler");
  4309.                     result = true;
  4310.                     break;
  4311.                 }
  4312.                 UnloadX11Api(x11Api);
  4313.             }
  4314.             return(result);
  4315.         }
  4316.  
  4317.         struct X11SubplatformState {
  4318.             X11Api api;
  4319.         };
  4320.  
  4321.         struct X11WindowState {
  4322.             Display* display;
  4323.             int screen;
  4324.             Window root;
  4325.             Colormap colorMap;
  4326.             Window window;
  4327.         };
  4328.  
  4329.         struct X11PreWindowSetupResult {
  4330.             Visual *visual;
  4331.             int colorDepth;
  4332.         };
  4333.  
  4334.     } // subplatform_x11
  4335. } // fpl
  4336. #endif // FPL_SUBPLATFORM_X11
  4337.  
  4338. // ****************************************************************************
  4339. //
  4340. // > PLATFORM_STATES
  4341. //
  4342. // - Defines the final PlatformInitState and PlatformAppState
  4343. // - Declares all required global variables
  4344. //
  4345. // ****************************************************************************
  4346. #if !defined(FPL_PLATFORM_STATES_DEFINED)
  4347. #define FPL_PLATFORM_STATES_DEFINED
  4348. namespace fpl {
  4349.     namespace platform {
  4350.         //
  4351.         // Platform initialization state
  4352.         //
  4353.         struct PlatformInitState {
  4354. #       if defined(FPL_SUBPLATFORM_POSIX)
  4355.             subplatform_posix::PosixInitState posix;
  4356. #       endif
  4357.             bool isInitialized;
  4358.  
  4359.             union {
  4360. #       if defined(FPL_PLATFORM_WIN32)
  4361.                 platform_win32::Win32InitState win32;
  4362. #       elif defined(FPL_PLATFORM_LINUX)
  4363.                 platform_linux::LinuxInitState linux;
  4364. #       endif              
  4365.             };
  4366.         };
  4367.         fpl_globalvar PlatformInitState global__InitState = {};
  4368.  
  4369. #   if defined(FPL_ENABLE_WINDOW)
  4370.         fpl_constant uint32_t MAX_EVENT_COUNT = 32768;
  4371.         struct EventQueue {
  4372.             window::Event events[MAX_EVENT_COUNT];
  4373.             volatile uint32_t pollIndex;
  4374.             volatile uint32_t pushCount;
  4375.         };
  4376.  
  4377.         struct PlatformWindowState {
  4378.             EventQueue eventQueue;
  4379.             union {
  4380. #       if defined(FPL_PLATFORM_WIN32)
  4381.                 platform_win32::Win32WindowState win32;
  4382. #       elif defined(FPL_SUBPLATFORM_X11)
  4383.                 subplatform_x11::X11WindowState x11;
  4384. #       endif
  4385.             };
  4386.         };
  4387. #   endif
  4388.  
  4389. #   if defined(FPL_ENABLE_VIDEO)
  4390.         struct PlatformVideoState {
  4391.             void *mem; // Points to common::VideoState
  4392.             size_t memSize;
  4393.         };
  4394. #   endif // FPL_ENABLE_VIDEO
  4395.  
  4396. #   if defined(FPL_ENABLE_AUDIO)
  4397.         struct PlatformAudioState {
  4398.             void *mem; // Points to common::AudioState
  4399.             size_t memSize;
  4400.         };
  4401. #   endif
  4402.  
  4403.         //
  4404.         // Platform application state
  4405.         //
  4406.         struct PlatformAppState {
  4407.  
  4408. #       if defined(FPL_SUBPLATFORM_POSIX)
  4409.             subplatform_posix::PosixAppState posix;
  4410. #       endif
  4411. #       if defined(FPL_SUBPLATFORM_X11)
  4412.             subplatform_x11::X11SubplatformState x11;
  4413. #       endif
  4414.  
  4415. #       if defined(FPL_ENABLE_WINDOW)
  4416.             PlatformWindowState window;
  4417. #       endif
  4418.  
  4419. #       if defined(FPL_ENABLE_VIDEO)
  4420.             PlatformVideoState video;
  4421. #       endif
  4422.  
  4423. #       if defined(FPL_ENABLE_AUDIO)
  4424.             PlatformAudioState audio;
  4425. #       endif
  4426.  
  4427.             Settings initSettings;
  4428.             Settings currentSettings;
  4429.             InitFlags initFlags;
  4430.  
  4431.             union {
  4432. #           if defined(FPL_PLATFORM_WIN32)
  4433.                 platform_win32::Win32AppState win32;
  4434. #           elif defined(FPL_PLATFORM_LINUX)
  4435.                 platform_linux::LinuxAppState linux;
  4436. #           endif
  4437.             };
  4438.         };
  4439.  
  4440. #   if defined(FPL_ENABLE_WINDOW)
  4441.         fpl_internal_inline void PushEvent(const window::Event &event) {
  4442.             PlatformAppState *appState = global__AppState;
  4443.             FPL_ASSERT(appState != nullptr);
  4444.             EventQueue &eventQueue = appState->window.eventQueue;
  4445.             if(eventQueue.pushCount < MAX_EVENT_COUNT) {
  4446.                 uint32_t eventIndex = atomics::AtomicAddU32(&eventQueue.pushCount, 1);
  4447.                 FPL_ASSERT(eventIndex < MAX_EVENT_COUNT);
  4448.                 eventQueue.events[eventIndex] = event;
  4449.             }
  4450.         }
  4451.  
  4452.         union PreSetupWindowResult {
  4453. #       if defined(FPL_SUBPLATFORM_X11)
  4454.             subplatform_x11::X11PreWindowSetupResult x11;
  4455. #       endif
  4456.         };
  4457.  
  4458.         // @NOTE(final): Callback used for setup a window before it is created
  4459. #       define FPL_FUNC_PRE_SETUP_WINDOW(name) bool name(platform::PlatformAppState *appState, const InitFlags initFlags, const Settings &initSettings, platform::PreSetupWindowResult &outResult)
  4460.         typedef FPL_FUNC_PRE_SETUP_WINDOW(callback_PreSetupWindow);
  4461.  
  4462.         // @NOTE(final): Callback used for setup a window after it was created
  4463. #       define FPL_FUNC_POST_SETUP_WINDOW(name) bool name(platform::PlatformAppState *appState, const InitFlags initFlags, const Settings &initSettings)
  4464.         typedef FPL_FUNC_POST_SETUP_WINDOW(callback_PostSetupWindow);
  4465.  
  4466.         struct SetupWindowCallbacks {
  4467.             callback_PreSetupWindow *preSetup;
  4468.             callback_PostSetupWindow *postSetup;
  4469.         };
  4470. #endif // FPL_ENABLE_WINDOW
  4471.  
  4472.     } // platform
  4473. } // fpl
  4474. #endif // FPL_PLATFORM_STATES_DEFINED
  4475.  
  4476. // ****************************************************************************
  4477. //
  4478. // > COMMON (Common Implementations)
  4479. //
  4480. // - Standard C library includes
  4481. // - Internal macros
  4482. // - Error state handling
  4483. // - Threading state handling
  4484. // - CommonAudioState
  4485. // - Common Implementations (Strings, Memory, Atomics, Path, etc.)
  4486. //
  4487. // ****************************************************************************
  4488. #if !defined(FPL_COMMON_DEFINED)
  4489. #define FPL_COMMON_DEFINED
  4490.  
  4491. // Standard includes
  4492. #include <stdarg.h> // va_start, va_end, va_list, va_arg
  4493. #include <stdio.h> // fprintf, vfprintf, vsnprintf, getchar
  4494. #include <stdlib.h> // wcstombs, mbstowcs, getenv
  4495.  
  4496. //
  4497. // Macros
  4498. //
  4499.  
  4500. // Clearing memory in chunks
  4501. #define FPL_CLEARMEM(T, memory, size, shift, mask) \
  4502.     do { \
  4503.         size_t clearedBytes = 0; \
  4504.         if (sizeof(T) > sizeof(uint8_t)) { \
  4505.             T *dataBlock = static_cast<T *>(memory); \
  4506.             T *dataBlockEnd = static_cast<T *>(memory) + (size >> shift); \
  4507.             while (dataBlock != dataBlockEnd) { \
  4508.                 *dataBlock++ = 0; \
  4509.                 clearedBytes += sizeof(T); \
  4510.             } \
  4511.         } \
  4512.         uint8_t *data8 = (uint8_t *)memory + clearedBytes; \
  4513.         uint8_t *data8End = (uint8_t *)memory + size; \
  4514.         while (data8 != data8End) { \
  4515.             *data8++ = 0; \
  4516.         } \
  4517.     } while (0);
  4518.  
  4519. #define FPL_COPYMEM(T, source, sourceSize, dest, shift, mask) \
  4520.     do { \
  4521.         size_t copiedBytes = 0; \
  4522.         if (sizeof(T) > sizeof(uint8_t)) { \
  4523.             T *sourceDataBlock = static_cast<T *>(source); \
  4524.             T *sourceDataBlockEnd = static_cast<T *>(source) + (sourceSize >> shift); \
  4525.             T *destDataBlock = static_cast<T *>(dest); \
  4526.             while (sourceDataBlock != sourceDataBlockEnd) { \
  4527.                 *destDataBlock++ = *sourceDataBlock++; \
  4528.                 copiedBytes += sizeof(T); \
  4529.             } \
  4530.         } \
  4531.         uint8_t *sourceData8 = (uint8_t *)source + copiedBytes; \
  4532.         uint8_t *sourceData8End = (uint8_t *)source + sourceSize; \
  4533.         uint8_t *destData8 = (uint8_t *)dest + copiedBytes; \
  4534.         while (sourceData8 != sourceData8End) { \
  4535.             *destData8++ = *sourceData8++; \
  4536.         } \
  4537.     } while (0);
  4538.  
  4539. namespace fpl {
  4540.     namespace common {
  4541.         //
  4542.         // Internal types and functions
  4543.         //
  4544.         fpl_constant uint32_t MAX_LAST_ERROR_STRING_LENGTH = 1024;
  4545. #   if defined(FPL_ENABLE_MULTIPLE_ERRORSTATES)
  4546.         fpl_constant uint32_t MAX_ERRORSTATE_COUNT = 256;
  4547. #   else
  4548.         fpl_constant uint32_t MAX_ERRORSTATE_COUNT = 1;
  4549. #   endif
  4550.  
  4551.         struct ErrorState {
  4552.             char errors[MAX_ERRORSTATE_COUNT][MAX_LAST_ERROR_STRING_LENGTH];
  4553.             uint32_t count;
  4554.         };
  4555.  
  4556.         fpl_globalvar ErrorState global__LastErrorState;
  4557.  
  4558. #   if defined(FPL_ENABLE_MULTIPLE_ERRORSTATES)
  4559.         fpl_internal_inline void PushError_Formatted(const char *format, va_list &argList) {
  4560.             ErrorState &state = global__LastErrorState;
  4561.             FPL_ASSERT(format != nullptr);
  4562.             char buffer[MAX_LAST_ERROR_STRING_LENGTH];
  4563.             ::vsnprintf(buffer, FPL_ARRAYCOUNT(buffer), format, argList);
  4564.             uint32_t messageLen = strings::GetAnsiStringLength(buffer);
  4565.             FPL_ASSERT(state.count < MAX_ERRORSTATE_COUNT);
  4566.             size_t errorIndex = state.count;
  4567.             state.count = (state.count + 1) % MAX_ERRORSTATE_COUNT;
  4568.             strings::CopyAnsiString(buffer, messageLen, state.errors[errorIndex], MAX_LAST_ERROR_STRING_LENGTH);
  4569. #       if defined(FPL_ENABLE_ERROR_IN_CONSOLE)
  4570.             console::ConsoleFormatError("FPL Error[%s]: %s\n", FPL_PLATFORM_NAME, buffer);
  4571. #       endif
  4572.         }
  4573. #   else
  4574.         fpl_internal_inline void PushError_Formatted(const char *format, va_list &argList) {
  4575.             ErrorState &state = global__LastErrorState;
  4576.             FPL_ASSERT(format != nullptr);
  4577.             char buffer[MAX_LAST_ERROR_STRING_LENGTH];
  4578.             ::vsnprintf(buffer, FPL_ARRAYCOUNT(buffer), format, argList);
  4579.             uint32_t messageLen = strings::GetAnsiStringLength(buffer);
  4580.             state.count = 1;
  4581.             strings::CopyAnsiString(buffer, messageLen, state.errors[0], MAX_LAST_ERROR_STRING_LENGTH);
  4582. #       if defined(FPL_ENABLE_ERROR_IN_CONSOLE)
  4583.             console::ConsoleFormatError("FPL Error[%s]: %s\h", FPL_PLATFORM_NAME, buffer);
  4584. #       endif
  4585.         }
  4586. #   endif // FPL_ENABLE_MULTIPLE_ERRORSTATES
  4587.  
  4588. #if defined(FPL_ENABLE_AUDIO)
  4589.         // @TODO(final): Why is CommonAudioState here???
  4590.         struct CommonAudioState {
  4591.             AudioDeviceFormat internalFormat;
  4592.             AudioClientReadFunction *clientReadCallback;
  4593.             void *clientUserData;
  4594.         };
  4595.         fpl_internal_inline uint32_t ReadAudioFramesFromClient(const CommonAudioState &commonAudio, uint32_t frameCount, void *pSamples) {
  4596.             uint32_t outputSamplesWritten = 0;
  4597.             if(commonAudio.clientReadCallback != nullptr) {
  4598.                 outputSamplesWritten = commonAudio.clientReadCallback(commonAudio.internalFormat, frameCount, pSamples, commonAudio.clientUserData);
  4599.             }
  4600.             return outputSamplesWritten;
  4601.         }
  4602. #endif // FPL_ENABLE_AUDIO
  4603.  
  4604.         fpl_internal_inline void PushError(const char *format, ...) {
  4605.             va_list valist;
  4606.             va_start(valist, format);
  4607.             PushError_Formatted(format, valist);
  4608.             va_end(valist);
  4609.         }
  4610.  
  4611.         fpl_internal_inline void ArgumentNullError(const char *paramName) {
  4612.             PushError("%s parameter are not allowed to be null", paramName);
  4613.         }
  4614.         fpl_internal_inline void ArgumentZeroError(const char *paramName) {
  4615.             PushError("%s parameter must be greater than zero", paramName);
  4616.         }
  4617.         fpl_internal_inline void ArgumentSizeTooSmallError(const char *paramName, const size_t value, const size_t minValue) {
  4618.             PushError("%s parameter '%zu' must be greater or equal than '%zu'", paramName, value, minValue);
  4619.         }
  4620.         fpl_internal_inline void ArgumentSizeTooBigError(const char *paramName, const size_t value, const size_t maxValue) {
  4621.             PushError("%s parameter '%zu' must be less or equal than '%zu'", paramName, value, maxValue);
  4622.         }
  4623.  
  4624.         // Maximum number of active threads you can have in your process
  4625.         fpl_constant uint32_t MAX_THREAD_COUNT = 64;
  4626.  
  4627.         // Maximum number of active signals you can wait for
  4628.         fpl_constant uint32_t MAX_SIGNAL_COUNT = 256;
  4629.  
  4630.         struct ThreadState {
  4631.             threading::ThreadHandle mainThread;
  4632.             threading::ThreadHandle threads[MAX_THREAD_COUNT];
  4633.         };
  4634.  
  4635.         fpl_globalvar ThreadState global__ThreadState = {};
  4636.  
  4637.         fpl_internal_inline threading::ThreadHandle *GetFreeThread() {
  4638.             threading::ThreadHandle *result = nullptr;
  4639.             for(uint32_t index = 0; index < MAX_THREAD_COUNT; ++index) {
  4640.                 threading::ThreadHandle *thread = global__ThreadState.threads + index;
  4641.                 threading::ThreadState state = threading::GetThreadState(thread);
  4642.                 if(state == threading::ThreadState::Stopped) {
  4643.                     result = thread;
  4644.                     break;
  4645.                 }
  4646.             }
  4647.             return(result);
  4648.         }
  4649.     } // common
  4650.  
  4651.     //
  4652.     // Common Strings
  4653.     //
  4654.     namespace strings {
  4655.         fpl_common_api bool IsStringEqual(const char *a, const uint32_t aLen, const char *b, const uint32_t bLen) {
  4656.             if((a == nullptr) || (b == nullptr)) {
  4657.                 return (a == b);
  4658.             }
  4659.             if(aLen != bLen) {
  4660.                 return false;
  4661.             }
  4662.             FPL_ASSERT(aLen == bLen);
  4663.             bool result = true;
  4664.             for(uint32_t index = 0; index < aLen; ++index) {
  4665.                 char aChar = a[index];
  4666.                 char bChar = b[index];
  4667.                 if(aChar != bChar) {
  4668.                     result = false;
  4669.                     break;
  4670.                 }
  4671.             }
  4672.             return(result);
  4673.         }
  4674.  
  4675.         fpl_common_api bool IsStringEqual(const char *a, const char *b) {
  4676.             if((a == nullptr) || (b == nullptr)) {
  4677.                 return (a == b);
  4678.             }
  4679.             bool result = true;
  4680.             for(;;) {
  4681.                 const char aChar = *(a++);
  4682.                 const char bChar = *(b++);
  4683.                 if(aChar == 0 || bChar == 0) {
  4684.                     result = (aChar == bChar);
  4685.                     break;
  4686.                 }
  4687.                 if(aChar != bChar) {
  4688.                     result = false;
  4689.                     break;
  4690.                 }
  4691.             }
  4692.             return(result);
  4693.         }
  4694.  
  4695.         fpl_common_api uint32_t GetAnsiStringLength(const char *str) {
  4696.             uint32_t result = 0;
  4697.             if(str != nullptr) {
  4698.                 while(*str++) {
  4699.                     result++;
  4700.                 }
  4701.             }
  4702.             return(result);
  4703.         }
  4704.  
  4705.         fpl_common_api uint32_t GetWideStringLength(const wchar_t *str) {
  4706.             uint32_t result = 0;
  4707.             if(str != nullptr) {
  4708.                 while(*str++) {
  4709.                     result++;
  4710.                 }
  4711.             }
  4712.             return(result);
  4713.         }
  4714.  
  4715.         fpl_common_api char *CopyAnsiString(const char *source, const uint32_t sourceLen, char *dest, const uint32_t maxDestLen) {
  4716.             char *result = nullptr;
  4717.             if((source != nullptr && dest != nullptr) && ((sourceLen + 1) <= maxDestLen)) {
  4718.                 result = dest;
  4719.                 uint32_t index = 0;
  4720.                 while(index++ < sourceLen) {
  4721.                     *dest++ = *source++;
  4722.                 }
  4723.                 *dest = 0;
  4724.             } else {
  4725.                 // @TODO(final): Do we want to push a error here?
  4726.             }
  4727.             return(result);
  4728.         }
  4729.  
  4730.         fpl_common_api char *CopyAnsiString(const char *source, char *dest, const uint32_t maxDestLen) {
  4731.             char *result = nullptr;
  4732.             if(source != nullptr) {
  4733.                 uint32_t sourceLen = GetAnsiStringLength(source);
  4734.                 result = CopyAnsiString(source, sourceLen, dest, maxDestLen);
  4735.             } else {
  4736.                 // @TODO(final): Do we want to push a error here?
  4737.             }
  4738.             return(result);
  4739.         }
  4740.  
  4741.         fpl_common_api wchar_t *CopyWideString(const wchar_t *source, const uint32_t sourceLen, wchar_t *dest, const uint32_t maxDestLen) {
  4742.             wchar_t *result = nullptr;
  4743.             if((source != nullptr && dest != nullptr) && ((sourceLen + 1) <= maxDestLen)) {
  4744.                 result = dest;
  4745.                 uint32_t index = 0;
  4746.                 while(index++ < sourceLen) {
  4747.                     *dest++ = *source++;
  4748.                 }
  4749.                 *dest = 0;
  4750.             } else {
  4751.                 // @TODO(final): Do we want to push a error here?
  4752.             }
  4753.             return(result);
  4754.         }
  4755.  
  4756.         fpl_common_api wchar_t *CopyWideString(const wchar_t *source, wchar_t *dest, const uint32_t maxDestLen) {
  4757.             wchar_t *result = nullptr;
  4758.             if(source != nullptr) {
  4759.                 uint32_t sourceLen = GetWideStringLength(source);
  4760.                 result = CopyWideString(source, sourceLen, dest, maxDestLen);
  4761.             } else {
  4762.                 // @TODO(final): Do we want to push a error here?
  4763.             }
  4764.             return(result);
  4765.         }
  4766.     } // strings
  4767.  
  4768.     //
  4769.     // Common Memory
  4770.     //
  4771.     namespace memory {
  4772.         fpl_common_api void *MemoryAlignedAllocate(const size_t size, const size_t alignment) {
  4773.             if(!size) {
  4774.                 common::ArgumentZeroError("Size");
  4775.                 return nullptr;
  4776.             }
  4777.             if(!alignment) {
  4778.                 common::ArgumentZeroError("Alignment");
  4779.                 return nullptr;
  4780.             }
  4781.             if(alignment & (alignment - 1)) {
  4782.                 common::PushError("Alignment parameter '%zu' must be a power of two", alignment);
  4783.                 return nullptr;
  4784.             }
  4785.  
  4786.             // Allocate empty memory to hold a size of a pointer + the actual size + alignment padding
  4787.             size_t newSize = sizeof(void *) + size + (alignment << 1);
  4788.             void *basePtr = fpl::memory::MemoryAllocate(newSize);
  4789.  
  4790.             // The resulting address starts after the stored base pointer
  4791.             void *alignedPtr = (void *)((uint8_t *)basePtr + sizeof(void *));
  4792.  
  4793.             // Move the resulting address to a aligned one when not aligned
  4794.             uintptr_t mask = alignment - 1;
  4795.             if((alignment > 1) && (((uintptr_t)alignedPtr & mask) != 0)) {
  4796.                 uintptr_t offset = ((uintptr_t)alignment - ((uintptr_t)alignedPtr & mask));
  4797.                 alignedPtr = (uint8_t *)alignedPtr + offset;
  4798.             }
  4799.  
  4800.             // Write the base pointer before the alignment pointer
  4801.             *(void **)((void *)((uint8_t *)alignedPtr - sizeof(void *))) = basePtr;
  4802.  
  4803.             // Ensure alignment
  4804.             FPL_ASSERT(FPL_IS_ALIGNED(alignedPtr, alignment));
  4805.  
  4806.             return(alignedPtr);
  4807.         }
  4808.  
  4809.         fpl_common_api void MemoryAlignedFree(void *ptr) {
  4810.             if(ptr == nullptr) {
  4811.                 common::ArgumentNullError("Pointer");
  4812.                 return;
  4813.             }
  4814.  
  4815.             // Free the base pointer which is stored to the left from the given pointer
  4816.             void *basePtr = *(void **)((void *)((uint8_t *)ptr - sizeof(void *)));
  4817.             FPL_ASSERT(basePtr != nullptr);
  4818.             MemoryFree(basePtr);
  4819.         }
  4820.  
  4821.         fpl_constant size_t MEM_SHIFT_64 = 3;
  4822.         fpl_constant size_t MEM_MASK_64 = 0x00000007;
  4823.         fpl_constant size_t MEM_SHIFT_32 = 2;
  4824.         fpl_constant size_t MEM_MASK_32 = 0x00000003;
  4825.         fpl_constant size_t MEM_SHIFT_16 = 1;
  4826.         fpl_constant size_t MEM_MASK_16 = 0x00000001;
  4827.  
  4828.         fpl_common_api void MemoryClear(void *mem, const size_t size) {
  4829.             if(mem == nullptr) {
  4830.                 common::ArgumentNullError("Memory");
  4831.                 return;
  4832.             }
  4833.             if(size == 0) {
  4834.                 common::ArgumentSizeTooSmallError("Size", size, 1);
  4835.                 return;
  4836.             }
  4837.             // @SPEED(final): Try faster memory copy using SIMD
  4838.             if(size % 8 == 0) {
  4839.                 FPL_CLEARMEM(uint64_t, mem, size, MEM_SHIFT_64, MEM_MASK_64);
  4840.             } else if(size % 4 == 0) {
  4841.                 FPL_CLEARMEM(uint32_t, mem, size, MEM_SHIFT_32, MEM_MASK_32);
  4842.             } else if(size % 2 == 0) {
  4843.                 FPL_CLEARMEM(uint16_t, mem, size, MEM_SHIFT_16, MEM_MASK_16);
  4844.             } else {
  4845.                 FPL_CLEARMEM(uint8_t, mem, size, 0, 0);
  4846.             }
  4847.         }
  4848.  
  4849.         fpl_common_api void MemoryCopy(void *sourceMem, const size_t sourceSize, void *targetMem) {
  4850.             if(sourceMem == nullptr) {
  4851.                 common::ArgumentNullError("Source memory");
  4852.                 return;
  4853.             }
  4854.             if(!sourceSize) {
  4855.                 common::ArgumentZeroError("Source size");
  4856.                 return;
  4857.             }
  4858.             if(targetMem == nullptr) {
  4859.                 common::ArgumentNullError("Target memory");
  4860.                 return;
  4861.             }
  4862.             if(sourceSize % 8 == 0) {
  4863.                 FPL_COPYMEM(uint64_t, sourceMem, sourceSize, targetMem, MEM_SHIFT_64, MEM_MASK_64);
  4864.             } else if(sourceSize % 4 == 0) {
  4865.                 FPL_COPYMEM(uint32_t, sourceMem, sourceSize, targetMem, MEM_SHIFT_32, MEM_MASK_32);
  4866.             } else if(sourceSize % 2 == 0) {
  4867.                 FPL_COPYMEM(uint16_t, sourceMem, sourceSize, targetMem, MEM_SHIFT_32, MEM_MASK_32);
  4868.             } else {
  4869.                 FPL_COPYMEM(uint8_t, sourceMem, sourceSize, targetMem, 0, 0);
  4870.             }
  4871.         }
  4872.     } // memory
  4873.  
  4874.     //
  4875.     // Common Atomics
  4876.     //
  4877.     namespace atomics {
  4878.         fpl_common_api void *AtomicExchangePtr(volatile void **target, const void *value) {
  4879.             FPL_ASSERT(target != nullptr);
  4880. #       if defined(FPL_ARCH_X64)
  4881.             void *result = (void *)AtomicExchangeU64((volatile uint64_t *)target, (uint64_t)value);
  4882. #       elif defined(FPL_ARCH_X86)
  4883.             void *result = (void *)AtomicExchangeU32((volatile uint32_t *)target, (uint32_t)value);
  4884. #       else
  4885. #           error "Unsupported architecture/platform!"
  4886. #       endif
  4887.             return (result);
  4888.         }
  4889.  
  4890.         fpl_common_api void *AtomicCompareAndExchangePtr(volatile void **dest, const void *comparand, const void *exchange) {
  4891.             FPL_ASSERT(dest != nullptr);
  4892. #       if defined(FPL_ARCH_X64)
  4893.             void *result = (void *)AtomicCompareAndExchangeU64((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
  4894. #       elif defined(FPL_ARCH_X86)
  4895.             void *result = (void *)AtomicCompareAndExchangeU32((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
  4896. #       else
  4897. #           error "Unsupported architecture/platform!"
  4898. #       endif
  4899.             return (result);
  4900.         }
  4901.  
  4902.         fpl_common_api bool IsAtomicCompareAndExchangePtr(volatile void **dest, const void *comparand, const void *exchange) {
  4903.             FPL_ASSERT(dest != nullptr);
  4904. #       if defined(FPL_ARCH_X64)
  4905.             bool result = IsAtomicCompareAndExchangeU64((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
  4906. #       elif defined(FPL_ARCH_X86)
  4907.             bool result = IsAtomicCompareAndExchangeU32((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
  4908. #       else
  4909. #           error "Unsupported architecture/platform!"
  4910. #       endif // FPL_ARCH
  4911.             return (result);
  4912.         }
  4913.  
  4914.         fpl_common_api void *AtomicLoadPtr(volatile void **source) {
  4915. #       if defined(FPL_ARCH_X64)
  4916.             void *result = (void *)AtomicLoadU64((volatile uint64_t *)source);
  4917. #       elif defined(FPL_ARCH_X86)
  4918.             void *result = (void *)AtomicLoadU32((volatile uint32_t *)source);
  4919. #       else
  4920. #           error "Unsupported architecture/platform!"
  4921. #       endif
  4922.             return(result);
  4923.         }
  4924.  
  4925.         fpl_common_api void AtomicStorePtr(volatile void **dest, const void *value) {
  4926. #       if defined(FPL_ARCH_X64)
  4927.             AtomicStoreU64((volatile uint64_t *)dest, (uint64_t)value);
  4928. #       elif defined(FPL_ARCH_X86)
  4929.             AtomicStoreU32((volatile uint32_t *)dest, (uint32_t)value);
  4930. #       else
  4931. #           error "Unsupported architecture/platform!"
  4932. #       endif
  4933.         }
  4934.     } // atomics
  4935.  
  4936.     //
  4937.     // Common Paths
  4938.     //
  4939.     namespace paths {
  4940.         fpl_common_api char *ExtractFilePath(const char *sourcePath, char *destPath, const uint32_t maxDestLen) {
  4941.             if(sourcePath == nullptr) {
  4942.                 common::ArgumentNullError("Source path");
  4943.                 return nullptr;
  4944.             }
  4945.             uint32_t sourceLen = strings::GetAnsiStringLength(sourcePath);
  4946.             if(sourceLen == 0) {
  4947.                 common::ArgumentZeroError("Source len");
  4948.                 return nullptr;
  4949.             }
  4950.             if(destPath == nullptr) {
  4951.                 common::ArgumentNullError("Dest path");
  4952.                 return nullptr;
  4953.             }
  4954.             size_t requiredDestLen = sourceLen + 1;
  4955.             if(maxDestLen < requiredDestLen) {
  4956.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredDestLen);
  4957.                 return nullptr;
  4958.             }
  4959.  
  4960.             char *result = nullptr;
  4961.             if(sourcePath) {
  4962.                 int copyLen = 0;
  4963.                 char *chPtr = (char *)sourcePath;
  4964.                 while(*chPtr) {
  4965.                     if(*chPtr == platform::PATH_SEPARATOR) {
  4966.                         copyLen = (int)(chPtr - sourcePath);
  4967.                     }
  4968.                     ++chPtr;
  4969.                 }
  4970.                 if(copyLen) {
  4971.                     result = strings::CopyAnsiString(sourcePath, copyLen, destPath, maxDestLen);
  4972.                 }
  4973.             }
  4974.             return(result);
  4975.         }
  4976.  
  4977.         fpl_common_api const char *ExtractFileExtension(const char *sourcePath) {
  4978.             const char *result = nullptr;
  4979.             if(sourcePath != nullptr) {
  4980.                 const char *filename = ExtractFileName(sourcePath);
  4981.                 if(filename) {
  4982.                     const char *chPtr = filename;
  4983.                     while(*chPtr) {
  4984.                         if(*chPtr == platform::FILE_EXT_SEPARATOR) {
  4985.                             result = chPtr;
  4986.                             break;
  4987.                         }
  4988.                         ++chPtr;
  4989.                     }
  4990.                 }
  4991.             }
  4992.             return(result);
  4993.         }
  4994.  
  4995.         fpl_common_api const char *ExtractFileName(const char *sourcePath) {
  4996.             const char *result = nullptr;
  4997.             if(sourcePath) {
  4998.                 result = sourcePath;
  4999.                 const char *chPtr = sourcePath;
  5000.                 while(*chPtr) {
  5001.                     if(*chPtr == platform::PATH_SEPARATOR) {
  5002.                         result = chPtr + 1;
  5003.                     }
  5004.                     ++chPtr;
  5005.                 }
  5006.             }
  5007.             return(result);
  5008.         }
  5009.  
  5010.         fpl_common_api char *ChangeFileExtension(const char *filePath, const char *newFileExtension, char *destPath, const uint32_t maxDestLen) {
  5011.             if(filePath == nullptr) {
  5012.                 common::ArgumentNullError("File path");
  5013.                 return nullptr;
  5014.             }
  5015.             if(newFileExtension == nullptr) {
  5016.                 common::ArgumentNullError("New file extension");
  5017.                 return nullptr;
  5018.             }
  5019.             uint32_t pathLen = strings::GetAnsiStringLength(filePath);
  5020.             if(pathLen == 0) {
  5021.                 common::ArgumentZeroError("Path len");
  5022.                 return nullptr;
  5023.             }
  5024.             uint32_t extLen = strings::GetAnsiStringLength(newFileExtension);
  5025.  
  5026.             if(destPath == nullptr) {
  5027.                 common::ArgumentNullError("Dest path");
  5028.                 return nullptr;
  5029.             }
  5030.             size_t requiredDestLen = pathLen + extLen + 1;
  5031.             if(maxDestLen < requiredDestLen) {
  5032.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredDestLen);
  5033.                 return nullptr;
  5034.             }
  5035.  
  5036.             char *result = nullptr;
  5037.             if(filePath != nullptr) {
  5038.                 // Find last path
  5039.                 char *chPtr = (char *)filePath;
  5040.                 char *lastPathSeparatorPtr = nullptr;
  5041.                 while(*chPtr) {
  5042.                     if(*chPtr == platform::PATH_SEPARATOR) {
  5043.                         lastPathSeparatorPtr = chPtr;
  5044.                     }
  5045.                     ++chPtr;
  5046.                 }
  5047.  
  5048.                 // Find last ext separator
  5049.                 if(lastPathSeparatorPtr != nullptr) {
  5050.                     chPtr = lastPathSeparatorPtr + 1;
  5051.                 } else {
  5052.                     chPtr = (char *)filePath;
  5053.                 }
  5054.                 char *lastExtSeparatorPtr = nullptr;
  5055.                 while(*chPtr) {
  5056.                     if(*chPtr == platform::FILE_EXT_SEPARATOR) {
  5057.                         lastExtSeparatorPtr = chPtr;
  5058.                     }
  5059.                     ++chPtr;
  5060.                 }
  5061.  
  5062.                 uint32_t copyLen;
  5063.                 if(lastExtSeparatorPtr != nullptr) {
  5064.                     copyLen = (uint32_t)((uintptr_t)lastExtSeparatorPtr - (uintptr_t)filePath);
  5065.                 } else {
  5066.                     copyLen = pathLen;
  5067.                 }
  5068.  
  5069.                 // Copy parts
  5070.                 strings::CopyAnsiString(filePath, copyLen, destPath, maxDestLen);
  5071.                 char *destExtPtr = destPath + copyLen;
  5072.                 strings::CopyAnsiString(newFileExtension, extLen, destExtPtr, maxDestLen - copyLen);
  5073.                 result = destPath;
  5074.             }
  5075.             return(result);
  5076.         }
  5077.  
  5078.         fpl_common_api char *CombinePath(char *destPath, const uint32_t maxDestPathLen, const uint32_t pathCount, ...) {
  5079.             if(pathCount == 0) {
  5080.                 common::ArgumentZeroError("Path count");
  5081.                 return nullptr;
  5082.             }
  5083.             if(destPath == nullptr) {
  5084.                 common::ArgumentNullError("Dest path");
  5085.                 return nullptr;
  5086.             }
  5087.             if(maxDestPathLen == 0) {
  5088.                 common::ArgumentZeroError("Max dest path len");
  5089.                 return nullptr;
  5090.             }
  5091.  
  5092.             uint32_t curDestPosition = 0;
  5093.             char *currentDestPtr = destPath;
  5094.             va_list vargs;
  5095.             va_start(vargs, pathCount);
  5096.             for(uint32_t pathIndex = 0; pathIndex < pathCount; ++pathIndex) {
  5097.                 char *path = va_arg(vargs, char *);
  5098.                 uint32_t pathLen = strings::GetAnsiStringLength(path);
  5099.                 bool requireSeparator = pathIndex < (pathCount - 1);
  5100.                 uint32_t requiredPathLen = requireSeparator ? pathLen + 1 : pathLen;
  5101.                 FPL_ASSERT(curDestPosition + requiredPathLen <= maxDestPathLen);
  5102.                 strings::CopyAnsiString(path, pathLen, currentDestPtr, maxDestPathLen - curDestPosition);
  5103.                 currentDestPtr += pathLen;
  5104.                 if(requireSeparator) {
  5105.                     *currentDestPtr++ = platform::PATH_SEPARATOR;
  5106.                 }
  5107.                 curDestPosition += requiredPathLen;
  5108.             }
  5109.             *currentDestPtr = 0;
  5110.             va_end(vargs);
  5111.             return destPath;
  5112.         }
  5113.  
  5114.     } // paths
  5115.  
  5116. #if defined(FPL_ENABLE_WINDOW)
  5117.     namespace window {
  5118.         fpl_common_api bool PollWindowEvent(Event &ev) {
  5119.             platform::PlatformAppState *appState = platform::global__AppState;
  5120.             FPL_ASSERT(appState != nullptr);
  5121.             platform::EventQueue &eventQueue = appState->window.eventQueue;
  5122.             bool result = false;
  5123.             if(eventQueue.pushCount > 0 && (eventQueue.pollIndex < eventQueue.pushCount)) {
  5124.                 uint32_t eventIndex = atomics::AtomicAddU32(&eventQueue.pollIndex, 1);
  5125.                 ev = eventQueue.events[eventIndex];
  5126.                 result = true;
  5127.             } else if(eventQueue.pushCount > 0) {
  5128.                 atomics::AtomicExchangeU32(&eventQueue.pollIndex, 0);
  5129.                 atomics::AtomicExchangeU32(&eventQueue.pushCount, 0);
  5130.             }
  5131.             return result;
  5132.         }
  5133.  
  5134.         fpl_common_api void ClearWindowEvents() {
  5135.             platform::PlatformAppState *appState = platform::global__AppState;
  5136.             FPL_ASSERT(appState != nullptr);
  5137.             platform::EventQueue &eventQueue = appState->window.eventQueue;
  5138.             atomics::AtomicExchangeU32(&eventQueue.pollIndex, 0);
  5139.             atomics::AtomicExchangeU32(&eventQueue.pushCount, 0);
  5140.         }
  5141.     } // window
  5142. #endif // FPL_ENABLE_WINDOW
  5143.  
  5144.     fpl_common_api const char *GetPlatformError() {
  5145.         const char *result = "";
  5146.         const common::ErrorState &errorState = common::global__LastErrorState;
  5147. #   if defined(FPL_ENABLE_MULTIPLE_ERRORSTATES)
  5148.         if(errorState.count > 0) {
  5149.             size_t index = errorState.count - 1;
  5150.             result = GetPlatformError(index);
  5151.         }
  5152. #   else
  5153.         result = errorState.errors[0];
  5154. #   endif // FPL_ENABLE_MULTIPLE_ERRORSTATES
  5155.         return (result);
  5156.     }
  5157.  
  5158.     fpl_common_api const char *GetPlatformError(const size_t index) {
  5159.         const char *result = "";
  5160.         const common::ErrorState &errorState = common::global__LastErrorState;
  5161. #   if defined(FPL_ENABLE_MULTIPLE_ERRORSTATES)
  5162.         if(index < errorState.count) {
  5163.             result = errorState.errors[index];
  5164.         } else {
  5165.             result = errorState.errors[errorState.count - 1];
  5166.         }
  5167. #   else
  5168.         result = errorState.errors[0];
  5169. #   endif // FPL_ENABLE_MULTIPLE_ERRORSTATES
  5170.         return (result);
  5171.     }
  5172.  
  5173.     fpl_common_api size_t GetPlatformErrorCount() {
  5174.         size_t result = 0;
  5175.         const common::ErrorState &errorState = common::global__LastErrorState;
  5176.         result = errorState.count;
  5177.         return (result);
  5178.     }
  5179.  
  5180.     fpl_common_api void ClearPlatformErrors() {
  5181.         common::ErrorState &errorState = common::global__LastErrorState;
  5182.         memory::MemoryClear(&errorState, sizeof(errorState));
  5183.     }
  5184.  
  5185.     fpl_common_api const Settings &GetCurrentSettings() {
  5186.         FPL_ASSERT(platform::global__AppState != nullptr);
  5187.         const platform::PlatformAppState *appState = platform::global__AppState;
  5188.         return (appState->currentSettings);
  5189.     }
  5190.  
  5191. } // fpl
  5192. #endif // FPL_COMMON_DEFINED
  5193.  
  5194. // ############################################################################
  5195. //
  5196. // > WIN32_PLATFORM (Win32, Win64)
  5197. //
  5198. // ############################################################################
  5199. #if defined(FPL_PLATFORM_WIN32)
  5200.  
  5201. #   if defined(FPL_ARCH_X86)
  5202. #       define FPL_MEMORY_BARRIER() \
  5203.             LONG barrier; \
  5204.             ::_InterlockedOr(&barrier, 0);
  5205. #   elif defined(FPL_ARCH_X64)
  5206.         // @NOTE(final): No need for hardware memory fence on X64 because the hardware guarantees memory order always.
  5207. #       define FPL_MEMORY_BARRIER()
  5208. #   endif
  5209.  
  5210. namespace fpl {
  5211.     namespace platform_win32 {
  5212. #   if defined(FPL_ENABLE_WINDOW)
  5213.         struct Win32WindowStyle {
  5214.             DWORD style;
  5215.             DWORD exStyle;
  5216.         };
  5217.  
  5218.         fpl_constant DWORD Win32ResizeableWindowStyle = WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
  5219.         fpl_constant DWORD Win32ResizeableWindowExtendedStyle = WS_EX_LEFT;
  5220.  
  5221.         fpl_constant DWORD Win32NonResizableWindowStyle = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;
  5222.         fpl_constant DWORD Win32NonResizableWindowExtendedStyle = WS_EX_LEFT;
  5223.  
  5224.         fpl_constant DWORD Win32FullscreenWindowStyle = WS_POPUP | WS_VISIBLE;
  5225.         fpl_constant DWORD Win32FullscreenWindowExtendedStyle = WS_EX_APPWINDOW | WS_EX_TOPMOST;
  5226.  
  5227.         fpl_internal bool Win32LeaveFullscreen() {
  5228.             // @TODO(final): The old window rect may be wrong when the display was changed (Turn off, Orientation, Grid Position, Screen res).
  5229.             FPL_ASSERT(platform::global__AppState != nullptr);
  5230.             const platform::PlatformAppState *platState = platform::global__AppState;
  5231.             const Win32AppState &win32State = platState->win32;
  5232.             const Win32Api &wapi = win32State.winApi;
  5233.             const WindowSettings &settings = platState->currentSettings.window;
  5234.             const Win32WindowState &win32Window = platState->window.win32;
  5235.             const Win32LastWindowInfo &fullscreenInfo = win32Window.lastFullscreenInfo;
  5236.  
  5237.             HWND windowHandle = win32Window.windowHandle;
  5238.  
  5239.             FPL_ASSERT(fullscreenInfo.style > 0 && fullscreenInfo.exStyle > 0);
  5240.             win32_setWindowLong(windowHandle, GWL_STYLE, fullscreenInfo.style);
  5241.             win32_setWindowLong(windowHandle, GWL_EXSTYLE, fullscreenInfo.exStyle);
  5242.             wapi.user.setWindowPlacement(windowHandle, &fullscreenInfo.placement);
  5243.             wapi.user.setWindowPos(windowHandle, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  5244.  
  5245.             if(fullscreenInfo.isMaximized) {
  5246.                 win32_sendMessage(windowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
  5247.             }
  5248.  
  5249.             bool result;
  5250.             if(fullscreenInfo.wasResolutionChanged) {
  5251.                 result = (wapi.user.changeDisplaySettingsA(nullptr, CDS_RESET) == DISP_CHANGE_SUCCESSFUL);
  5252.             } else {
  5253.                 result = true;
  5254.             }
  5255.  
  5256.             return(result);
  5257.         }
  5258.  
  5259.         fpl_internal bool Win32EnterFullscreen(const uint32_t fullscreenWidth, const uint32_t fullscreenHeight, const uint32_t refreshRate, const uint32_t colorBits) {
  5260.             FPL_ASSERT(platform::global__AppState != nullptr);
  5261.             platform::PlatformAppState *platState = platform::global__AppState;
  5262.             Win32AppState &win32State = platState->win32;
  5263.             const Win32Api &wapi = win32State.winApi;
  5264.             const WindowSettings &settings = platState->currentSettings.window;
  5265.             Win32WindowState &win32Window = platState->window.win32;
  5266.             Win32LastWindowInfo &fullscreenInfo = win32Window.lastFullscreenInfo;
  5267.  
  5268.             HWND windowHandle = win32Window.windowHandle;
  5269.             HDC deviceContext = win32Window.deviceContext;
  5270.  
  5271.             FPL_ASSERT(fullscreenInfo.style > 0 && fullscreenInfo.exStyle > 0);
  5272.             win32_setWindowLong(windowHandle, GWL_STYLE, fullscreenInfo.style & ~(WS_CAPTION | WS_THICKFRAME));
  5273.             win32_setWindowLong(windowHandle, GWL_EXSTYLE, fullscreenInfo.exStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
  5274.  
  5275.             MONITORINFO monitor = {};
  5276.             monitor.cbSize = sizeof(monitor);
  5277.             win32_getMonitorInfo(wapi.user.monitorFromWindow(windowHandle, MONITOR_DEFAULTTONEAREST), &monitor);
  5278.  
  5279.             bool result;
  5280.             if(fullscreenWidth > 0 && fullscreenHeight > 0) {
  5281.                 DWORD useFullscreenWidth = fullscreenWidth;
  5282.                 DWORD useFullscreenHeight = fullscreenHeight;
  5283.  
  5284.                 DWORD useRefreshRate = refreshRate;
  5285.                 if(!useRefreshRate) {
  5286.                     useRefreshRate = wapi.gdi.getDeviceCaps(deviceContext, VREFRESH);
  5287.                 }
  5288.  
  5289.                 DWORD useColourBits = colorBits;
  5290.                 if(!useColourBits) {
  5291.                     useColourBits = wapi.gdi.getDeviceCaps(deviceContext, BITSPIXEL);
  5292.                 }
  5293.  
  5294.                 // @TODO(final): Is this correct to assume the fullscreen rect is at (0, 0, w - 1, h - 1)?
  5295.                 RECT windowRect;
  5296.                 windowRect.left = 0;
  5297.                 windowRect.top = 0;
  5298.                 windowRect.right = windowRect.left + (useFullscreenWidth - 1);
  5299.                 windowRect.bottom = windowRect.left + (useFullscreenHeight - 1);
  5300.  
  5301.                 WINDOWPLACEMENT placement = {};
  5302.                 placement.length = sizeof(placement);
  5303.                 placement.rcNormalPosition = windowRect;
  5304.                 placement.showCmd = SW_SHOW;
  5305.                 wapi.user.setWindowPlacement(windowHandle, &placement);
  5306.                 wapi.user.setWindowPos(windowHandle, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  5307.  
  5308.                 DEVMODEA fullscreenSettings = {};
  5309.                 wapi.user.enumDisplaySettingsA(nullptr, 0, &fullscreenSettings);
  5310.                 fullscreenSettings.dmPelsWidth = useFullscreenWidth;
  5311.                 fullscreenSettings.dmPelsHeight = useFullscreenHeight;
  5312.                 fullscreenSettings.dmBitsPerPel = useColourBits;
  5313.                 fullscreenSettings.dmDisplayFrequency = useRefreshRate;
  5314.                 fullscreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
  5315.                 result = (wapi.user.changeDisplaySettingsA(&fullscreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
  5316.                 fullscreenInfo.wasResolutionChanged = true;
  5317.             } else {
  5318.                 RECT windowRect = monitor.rcMonitor;
  5319.  
  5320.                 WINDOWPLACEMENT placement = {};
  5321.                 placement.length = sizeof(placement);
  5322.                 placement.rcNormalPosition = windowRect;
  5323.                 placement.showCmd = SW_SHOW;
  5324.                 wapi.user.setWindowPlacement(windowHandle, &placement);
  5325.                 wapi.user.setWindowPos(windowHandle, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  5326.  
  5327.                 result = true;
  5328.                 fullscreenInfo.wasResolutionChanged = false;
  5329.             }
  5330.  
  5331.             return(result);
  5332.         }
  5333.  
  5334.         fpl_internal_inline float Win32XInputProcessStickValue(const SHORT value, const SHORT deadZoneThreshold) {
  5335.             float result = 0;
  5336.             if(value < -deadZoneThreshold) {
  5337.                 result = (float)((value + deadZoneThreshold) / (32768.0f - deadZoneThreshold));
  5338.             } else if(value > deadZoneThreshold) {
  5339.                 result = (float)((value - deadZoneThreshold) / (32767.0f - deadZoneThreshold));
  5340.             }
  5341.             return(result);
  5342.         }
  5343.  
  5344.         fpl_internal void Win32PollControllers(const Settings &settings, const Win32InitState &initState, Win32XInputState &xinputState) {
  5345.             using namespace window;
  5346.             if(xinputState.xinputApi.xInputGetState != nullptr) {
  5347.                 //
  5348.                 // Detect new controller (Only on a fixed frequency)
  5349.                 //
  5350.                 if(xinputState.lastDeviceSearchTime.QuadPart == 0) {
  5351.                     ::QueryPerformanceCounter(&xinputState.lastDeviceSearchTime);
  5352.                 }
  5353.                 LARGE_INTEGER currentDeviceSearchTime;
  5354.                 ::QueryPerformanceCounter(&currentDeviceSearchTime);
  5355.                 uint64_t deviceSearchDifferenceTimeInMs = ((currentDeviceSearchTime.QuadPart - xinputState.lastDeviceSearchTime.QuadPart) / (initState.performanceFrequency.QuadPart / 1000));
  5356.                 if((settings.input.controllerDetectionFrequency == 0) || (deviceSearchDifferenceTimeInMs > settings.input.controllerDetectionFrequency)) {
  5357.                     xinputState.lastDeviceSearchTime = currentDeviceSearchTime;
  5358.                     for(DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; ++controllerIndex) {
  5359.                         XINPUT_STATE controllerState = {};
  5360.                         if(xinputState.xinputApi.xInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
  5361.                             if(!xinputState.isConnected[controllerIndex]) {
  5362.                                 // Connected
  5363.                                 xinputState.isConnected[controllerIndex] = true;
  5364.                                 Event ev = {};
  5365.                                 ev.type = EventType::Gamepad;
  5366.                                 ev.gamepad.type = GamepadEventType::Connected;
  5367.                                 ev.gamepad.deviceIndex = controllerIndex;
  5368.                                 platform::PushEvent(ev);
  5369.                             }
  5370.                         } else {
  5371.                             if(xinputState.isConnected[controllerIndex]) {
  5372.                                 // Disonnected
  5373.                                 xinputState.isConnected[controllerIndex] = false;
  5374.                                 Event ev = {};
  5375.                                 ev.type = EventType::Gamepad;
  5376.                                 ev.gamepad.type = GamepadEventType::Disconnected;
  5377.                                 ev.gamepad.deviceIndex = controllerIndex;
  5378.                                 platform::PushEvent(ev);
  5379.                             }
  5380.                         }
  5381.                     }
  5382.                 }
  5383.  
  5384.                 //
  5385.                 // Update controller state when connected only
  5386.                 //
  5387.                 for(DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; ++controllerIndex) {
  5388.                     if(xinputState.isConnected[controllerIndex]) {
  5389.                         XINPUT_STATE controllerState = {};
  5390.                         if(xinputState.xinputApi.xInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
  5391.                             // State changed
  5392.                             Event ev = {};
  5393.                             ev.type = EventType::Gamepad;
  5394.                             ev.gamepad.type = GamepadEventType::StateChanged;
  5395.                             ev.gamepad.deviceIndex = controllerIndex;
  5396.  
  5397.                             XINPUT_GAMEPAD *pad = &controllerState.Gamepad;
  5398.  
  5399.                             // Analog sticks
  5400.                             ev.gamepad.state.leftStickX = Win32XInputProcessStickValue(pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  5401.                             ev.gamepad.state.leftStickY = Win32XInputProcessStickValue(pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
  5402.                             ev.gamepad.state.rightStickX = Win32XInputProcessStickValue(pad->sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
  5403.                             ev.gamepad.state.rightStickY = Win32XInputProcessStickValue(pad->sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
  5404.  
  5405.                             // Triggers
  5406.                             ev.gamepad.state.leftTrigger = (float)pad->bLeftTrigger / 255.0f;
  5407.                             ev.gamepad.state.rightTrigger = (float)pad->bRightTrigger / 255.0f;
  5408.  
  5409.                             // Digital pad buttons
  5410.                             if(pad->wButtons & XINPUT_GAMEPAD_DPAD_UP)
  5411.                                 ev.gamepad.state.dpadUp = { true };
  5412.                             if(pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
  5413.                                 ev.gamepad.state.dpadDown = { true };
  5414.                             if(pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
  5415.                                 ev.gamepad.state.dpadLeft = { true };
  5416.                             if(pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
  5417.                                 ev.gamepad.state.dpadRight = { true };
  5418.  
  5419.                             // Action buttons
  5420.                             if(pad->wButtons & XINPUT_GAMEPAD_A)
  5421.                                 ev.gamepad.state.actionA = { true };
  5422.                             if(pad->wButtons & XINPUT_GAMEPAD_B)
  5423.                                 ev.gamepad.state.actionB = { true };
  5424.                             if(pad->wButtons & XINPUT_GAMEPAD_X)
  5425.                                 ev.gamepad.state.actionX = { true };
  5426.                             if(pad->wButtons & XINPUT_GAMEPAD_Y)
  5427.                                 ev.gamepad.state.actionY = { true };
  5428.  
  5429.                             // Center buttons
  5430.                             if(pad->wButtons & XINPUT_GAMEPAD_START)
  5431.                                 ev.gamepad.state.start = { true };
  5432.                             if(pad->wButtons & XINPUT_GAMEPAD_BACK)
  5433.                                 ev.gamepad.state.back = { true };
  5434.  
  5435.                             // Shoulder buttons
  5436.                             if(pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)
  5437.                                 ev.gamepad.state.leftShoulder = { true };
  5438.                             if(pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)
  5439.                                 ev.gamepad.state.rightShoulder = { true };
  5440.  
  5441.                             platform::PushEvent(ev);
  5442.                         }
  5443.                     }
  5444.                 }
  5445.             }
  5446.         }
  5447.  
  5448.         fpl_internal_inline void Win32PushMouseEvent(const window::MouseEventType &mouseEventType, const window::MouseButtonType mouseButton, const LPARAM lParam, const WPARAM wParam) {
  5449.             using namespace window;
  5450.             Event newEvent = {};
  5451.             newEvent.type = EventType::Mouse;
  5452.             newEvent.mouse.type = mouseEventType;
  5453.             newEvent.mouse.mouseX = GET_X_LPARAM(lParam);
  5454.             newEvent.mouse.mouseY = GET_Y_LPARAM(lParam);
  5455.             newEvent.mouse.mouseButton = mouseButton;
  5456.             if(mouseEventType == MouseEventType::Wheel) {
  5457.                 short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
  5458.                 newEvent.mouse.wheelDelta = (zDelta / (float)WHEEL_DELTA);
  5459.             }
  5460.             platform::PushEvent(newEvent);
  5461.         }
  5462.  
  5463.         fpl_internal window::Key Win32MapVirtualKey(const uint64_t keyCode) {
  5464.             using namespace window;
  5465.             switch(keyCode) {
  5466.                 case VK_BACK:
  5467.                     return Key::Key_Backspace;
  5468.                 case VK_TAB:
  5469.                     return Key::Key_Tab;
  5470.  
  5471.                 case VK_CLEAR:
  5472.                     return Key::Key_Clear;
  5473.                 case VK_RETURN:
  5474.                     return Key::Key_Enter;
  5475.  
  5476.                 case VK_SHIFT:
  5477.                     return Key::Key_Shift;
  5478.                 case VK_CONTROL:
  5479.                     return Key::Key_Control;
  5480.                 case VK_MENU:
  5481.                     return Key::Key_Alt;
  5482.                 case VK_PAUSE:
  5483.                     return Key::Key_Pause;
  5484.                 case VK_CAPITAL:
  5485.                     return Key::Key_CapsLock;
  5486.  
  5487.                 case VK_ESCAPE:
  5488.                     return Key::Key_Escape;
  5489.                 case VK_SPACE:
  5490.                     return Key::Key_Space;
  5491.                 case VK_PRIOR:
  5492.                     return Key::Key_PageUp;
  5493.                 case VK_NEXT:
  5494.                     return Key::Key_PageDown;
  5495.                 case VK_END:
  5496.                     return Key::Key_End;
  5497.                 case VK_HOME:
  5498.                     return Key::Key_Home;
  5499.                 case VK_LEFT:
  5500.                     return Key::Key_Left;
  5501.                 case VK_UP:
  5502.                     return Key::Key_Up;
  5503.                 case VK_RIGHT:
  5504.                     return Key::Key_Right;
  5505.                 case VK_DOWN:
  5506.                     return Key::Key_Down;
  5507.                 case VK_SELECT:
  5508.                     return Key::Key_Select;
  5509.                 case VK_PRINT:
  5510.                     return Key::Key_Print;
  5511.                 case VK_EXECUTE:
  5512.                     return Key::Key_Execute;
  5513.                 case VK_SNAPSHOT:
  5514.                     return Key::Key_Snapshot;
  5515.                 case VK_INSERT:
  5516.                     return Key::Key_Insert;
  5517.                 case VK_DELETE:
  5518.                     return Key::Key_Delete;
  5519.                 case VK_HELP:
  5520.                     return Key::Key_Help;
  5521.  
  5522.                 case 0x30:
  5523.                     return Key::Key_0;
  5524.                 case 0x31:
  5525.                     return Key::Key_1;
  5526.                 case 0x32:
  5527.                     return Key::Key_2;
  5528.                 case 0x33:
  5529.                     return Key::Key_3;
  5530.                 case 0x34:
  5531.                     return Key::Key_4;
  5532.                 case 0x35:
  5533.                     return Key::Key_5;
  5534.                 case 0x36:
  5535.                     return Key::Key_6;
  5536.                 case 0x37:
  5537.                     return Key::Key_7;
  5538.                 case 0x38:
  5539.                     return Key::Key_8;
  5540.                 case 0x39:
  5541.                     return Key::Key_9;
  5542.  
  5543.                 case 0x41:
  5544.                     return Key::Key_A;
  5545.                 case 0x42:
  5546.                     return Key::Key_B;
  5547.                 case 0x43:
  5548.                     return Key::Key_C;
  5549.                 case 0x44:
  5550.                     return Key::Key_D;
  5551.                 case 0x45:
  5552.                     return Key::Key_E;
  5553.                 case 0x46:
  5554.                     return Key::Key_F;
  5555.                 case 0x47:
  5556.                     return Key::Key_G;
  5557.                 case 0x48:
  5558.                     return Key::Key_H;
  5559.                 case 0x49:
  5560.                     return Key::Key_I;
  5561.                 case 0x4A:
  5562.                     return Key::Key_J;
  5563.                 case 0x4B:
  5564.                     return Key::Key_K;
  5565.                 case 0x4C:
  5566.                     return Key::Key_L;
  5567.                 case 0x4D:
  5568.                     return Key::Key_M;
  5569.                 case 0x4E:
  5570.                     return Key::Key_N;
  5571.                 case 0x4F:
  5572.                     return Key::Key_O;
  5573.                 case 0x50:
  5574.                     return Key::Key_P;
  5575.                 case 0x51:
  5576.                     return Key::Key_Q;
  5577.                 case 0x52:
  5578.                     return Key::Key_R;
  5579.                 case 0x53:
  5580.                     return Key::Key_S;
  5581.                 case 0x54:
  5582.                     return Key::Key_T;
  5583.                 case 0x55:
  5584.                     return Key::Key_U;
  5585.                 case 0x56:
  5586.                     return Key::Key_V;
  5587.                 case 0x57:
  5588.                     return Key::Key_W;
  5589.                 case 0x58:
  5590.                     return Key::Key_X;
  5591.                 case 0x59:
  5592.                     return Key::Key_Y;
  5593.                 case 0x5A:
  5594.                     return Key::Key_Z;
  5595.  
  5596.                 case VK_LWIN:
  5597.                     return Key::Key_LeftWin;
  5598.                 case VK_RWIN:
  5599.                     return Key::Key_RightWin;
  5600.                 case VK_APPS:
  5601.                     return Key::Key_Apps;
  5602.  
  5603.                 case VK_SLEEP:
  5604.                     return Key::Key_Sleep;
  5605.                 case VK_NUMPAD0:
  5606.                     return Key::Key_NumPad0;
  5607.                 case VK_NUMPAD1:
  5608.                     return Key::Key_NumPad1;
  5609.                 case VK_NUMPAD2:
  5610.                     return Key::Key_NumPad2;
  5611.                 case VK_NUMPAD3:
  5612.                     return Key::Key_NumPad3;
  5613.                 case VK_NUMPAD4:
  5614.                     return Key::Key_NumPad4;
  5615.                 case VK_NUMPAD5:
  5616.                     return Key::Key_NumPad5;
  5617.                 case VK_NUMPAD6:
  5618.                     return Key::Key_NumPad6;
  5619.                 case VK_NUMPAD7:
  5620.                     return Key::Key_NumPad7;
  5621.                 case VK_NUMPAD8:
  5622.                     return Key::Key_NumPad8;
  5623.                 case VK_NUMPAD9:
  5624.                     return Key::Key_NumPad9;
  5625.                 case VK_MULTIPLY:
  5626.                     return Key::Key_Multiply;
  5627.                 case VK_ADD:
  5628.                     return Key::Key_Add;
  5629.                 case VK_SEPARATOR:
  5630.                     return Key::Key_Separator;
  5631.                 case VK_SUBTRACT:
  5632.                     return Key::Key_Substract;
  5633.                 case VK_DECIMAL:
  5634.                     return Key::Key_Decimal;
  5635.                 case VK_DIVIDE:
  5636.                     return Key::Key_Divide;
  5637.                 case VK_F1:
  5638.                     return Key::Key_F1;
  5639.                 case VK_F2:
  5640.                     return Key::Key_F2;
  5641.                 case VK_F3:
  5642.                     return Key::Key_F3;
  5643.                 case VK_F4:
  5644.                     return Key::Key_F4;
  5645.                 case VK_F5:
  5646.                     return Key::Key_F5;
  5647.                 case VK_F6:
  5648.                     return Key::Key_F6;
  5649.                 case VK_F7:
  5650.                     return Key::Key_F7;
  5651.                 case VK_F8:
  5652.                     return Key::Key_F8;
  5653.                 case VK_F9:
  5654.                     return Key::Key_F9;
  5655.                 case VK_F10:
  5656.                     return Key::Key_F10;
  5657.                 case VK_F11:
  5658.                     return Key::Key_F11;
  5659.                 case VK_F12:
  5660.                     return Key::Key_F12;
  5661.                 case VK_F13:
  5662.                     return Key::Key_F13;
  5663.                 case VK_F14:
  5664.                     return Key::Key_F14;
  5665.                 case VK_F15:
  5666.                     return Key::Key_F15;
  5667.                 case VK_F16:
  5668.                     return Key::Key_F16;
  5669.                 case VK_F17:
  5670.                     return Key::Key_F17;
  5671.                 case VK_F18:
  5672.                     return Key::Key_F18;
  5673.                 case VK_F19:
  5674.                     return Key::Key_F19;
  5675.                 case VK_F20:
  5676.                     return Key::Key_F20;
  5677.                 case VK_F21:
  5678.                     return Key::Key_F21;
  5679.                 case VK_F22:
  5680.                     return Key::Key_F22;
  5681.                 case VK_F23:
  5682.                     return Key::Key_F23;
  5683.                 case VK_F24:
  5684.                     return Key::Key_F24;
  5685.  
  5686.                 case VK_LSHIFT:
  5687.                     return Key::Key_LeftShift;
  5688.                 case VK_RSHIFT:
  5689.                     return Key::Key_RightShift;
  5690.                 case VK_LCONTROL:
  5691.                     return Key::Key_LeftControl;
  5692.                 case VK_RCONTROL:
  5693.                     return Key::Key_RightControl;
  5694.                 case VK_LMENU:
  5695.                     return Key::Key_LeftAlt;
  5696.                 case VK_RMENU:
  5697.                     return Key::Key_RightAlt;
  5698.  
  5699.                 default:
  5700.                     return Key::Key_None;
  5701.             }
  5702.         }
  5703.  
  5704.         fpl_internal_inline void Win32PushKeyboardEvent(const window::KeyboardEventType keyboardEventType, const uint64_t keyCode, const window::KeyboardModifierFlags modifiers, const bool isDown) {
  5705.             using namespace window;
  5706.             Event newEvent = {};
  5707.             newEvent.type = EventType::Keyboard;
  5708.             newEvent.keyboard.keyCode = keyCode;
  5709.             newEvent.keyboard.mappedKey = Win32MapVirtualKey(keyCode);
  5710.             newEvent.keyboard.type = keyboardEventType;
  5711.             newEvent.keyboard.modifiers = modifiers;
  5712.             platform::PushEvent(newEvent);
  5713.         }
  5714.  
  5715.         fpl_internal_inline bool Win32IsKeyDown(const Win32Api &wapi, const uint64_t keyCode) {
  5716.             bool result = (wapi.user.getAsyncKeyState((int)keyCode) & 0x8000) > 0;
  5717.             return(result);
  5718.         }
  5719.  
  5720.         LRESULT CALLBACK Win32MessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  5721.             using namespace window;
  5722.  
  5723.             FPL_ASSERT(platform::global__AppState != nullptr);
  5724.             platform::PlatformAppState *appState = platform::global__AppState;
  5725.  
  5726.             Win32AppState &win32State = appState->win32;
  5727.             Win32WindowState &win32Window = appState->window.win32;
  5728.             const Win32Api &wapi = win32State.winApi;
  5729.  
  5730.             if(!win32Window.windowHandle) {
  5731.                 return win32_defWindowProc(hwnd, msg, wParam, lParam);
  5732.             }
  5733.  
  5734.             LRESULT result = 0;
  5735.             switch(msg) {
  5736.                 case WM_DESTROY:
  5737.                 case WM_CLOSE:
  5738.                 {
  5739.                     win32Window.isRunning = false;
  5740.                 } break;
  5741.  
  5742.                 case WM_SIZE:
  5743.                 {
  5744. #               if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  5745.                     if(appState->currentSettings.video.driver == VideoDriverType::Software) {
  5746.                         if(appState->initSettings.video.isAutoSize) {
  5747.                             uint32_t w = LOWORD(lParam);
  5748.                             uint32_t h = HIWORD(lParam);
  5749.                             video::ResizeVideoBackBuffer(w, h);
  5750.                         }
  5751.                     }
  5752. #               endif
  5753.  
  5754.                     Event newEvent = {};
  5755.                     newEvent.type = EventType::Window;
  5756.                     newEvent.window.type = WindowEventType::Resized;
  5757.                     newEvent.window.width = LOWORD(lParam);
  5758.                     newEvent.window.height = HIWORD(lParam);
  5759.                     platform::PushEvent(newEvent);
  5760.                 } break;
  5761.  
  5762.                 case WM_SYSKEYDOWN:
  5763.                 case WM_SYSKEYUP:
  5764.                 case WM_KEYDOWN:
  5765.                 case WM_KEYUP:
  5766.                 {
  5767.                     uint64_t keyCode = wParam;
  5768.                     bool wasDown = ((int)(lParam & (1 << 30)) != 0);
  5769.                     bool isDown = ((int)(lParam & (1 << 31)) == 0);
  5770.  
  5771.                     bool altKeyWasDown = Win32IsKeyDown(wapi, VK_MENU);
  5772.                     bool shiftKeyWasDown = Win32IsKeyDown(wapi, VK_LSHIFT);
  5773.                     bool ctrlKeyWasDown = Win32IsKeyDown(wapi, VK_LCONTROL);
  5774.                     bool superKeyWasDown = Win32IsKeyDown(wapi, VK_LMENU);
  5775.  
  5776.                     KeyboardEventType keyEventType = isDown ? KeyboardEventType::KeyDown : KeyboardEventType::KeyUp;
  5777.                     KeyboardModifierFlags modifiers = KeyboardModifierFlags::None;
  5778.                     if(altKeyWasDown) {
  5779.                         modifiers |= KeyboardModifierFlags::Alt;
  5780.                     }
  5781.                     if(shiftKeyWasDown) {
  5782.                         modifiers |= KeyboardModifierFlags::Shift;
  5783.                     }
  5784.                     if(ctrlKeyWasDown) {
  5785.                         modifiers |= KeyboardModifierFlags::Ctrl;
  5786.                     }
  5787.                     if(superKeyWasDown) {
  5788.                         modifiers |= KeyboardModifierFlags::Super;
  5789.                     }
  5790.                     Win32PushKeyboardEvent(keyEventType, keyCode, modifiers, isDown);
  5791.  
  5792.                     if(wasDown != isDown) {
  5793.                         if(isDown) {
  5794.                             if(keyCode == VK_F4 && altKeyWasDown) {
  5795.                                 win32Window.isRunning = 0;
  5796.                             }
  5797.                         }
  5798.                     }
  5799.                 } break;
  5800.  
  5801.                 case WM_CHAR:
  5802.                 {
  5803.                     // @TODO(final): Add unicode support (WM_UNICHAR)!
  5804.                     if(wParam >= 0 && wParam < 256) {
  5805.                         uint64_t keyCode = wParam;
  5806.                         KeyboardModifierFlags modifiers = KeyboardModifierFlags::None;
  5807.                         Win32PushKeyboardEvent(KeyboardEventType::CharInput, keyCode, modifiers, 0);
  5808.                     }
  5809.                 } break;
  5810.  
  5811.                 case WM_ACTIVATE:
  5812.                 {
  5813.                     Event newEvent = {};
  5814.                     newEvent.type = EventType::Window;
  5815.                     if(wParam == WA_INACTIVE) {
  5816.                         newEvent.window.type = WindowEventType::LostFocus;
  5817.                     } else {
  5818.                         newEvent.window.type = WindowEventType::GotFocus;
  5819.                     }
  5820.                     platform::PushEvent(newEvent);
  5821.                 } break;
  5822.  
  5823.                 case WM_LBUTTONDOWN:
  5824.                 case WM_LBUTTONUP:
  5825.                 {
  5826.                     MouseEventType mouseEventType;
  5827.                     if(msg == WM_LBUTTONDOWN) {
  5828.                         mouseEventType = MouseEventType::ButtonDown;
  5829.                     } else {
  5830.                         mouseEventType = MouseEventType::ButtonUp;
  5831.                     }
  5832.                     Win32PushMouseEvent(mouseEventType, MouseButtonType::Left, lParam, wParam);
  5833.                 } break;
  5834.                 case WM_RBUTTONDOWN:
  5835.                 case WM_RBUTTONUP:
  5836.                 {
  5837.                     MouseEventType mouseEventType;
  5838.                     if(msg == WM_RBUTTONDOWN) {
  5839.                         mouseEventType = MouseEventType::ButtonDown;
  5840.                     } else {
  5841.                         mouseEventType = MouseEventType::ButtonUp;
  5842.                     }
  5843.                     Win32PushMouseEvent(mouseEventType, MouseButtonType::Right, lParam, wParam);
  5844.                 } break;
  5845.                 case WM_MBUTTONDOWN:
  5846.                 case WM_MBUTTONUP:
  5847.                 {
  5848.                     MouseEventType mouseEventType;
  5849.                     if(msg == WM_MBUTTONDOWN) {
  5850.                         mouseEventType = MouseEventType::ButtonDown;
  5851.                     } else {
  5852.                         mouseEventType = MouseEventType::ButtonUp;
  5853.                     }
  5854.                     Win32PushMouseEvent(mouseEventType, MouseButtonType::Middle, lParam, wParam);
  5855.                 } break;
  5856.                 case WM_MOUSEMOVE:
  5857.                 {
  5858.                     Win32PushMouseEvent(MouseEventType::Move, MouseButtonType::None, lParam, wParam);
  5859.                 } break;
  5860.                 case WM_MOUSEWHEEL:
  5861.                 {
  5862.                     Win32PushMouseEvent(MouseEventType::Wheel, MouseButtonType::None, lParam, wParam);
  5863.                 } break;
  5864.  
  5865.                 case WM_SETCURSOR:
  5866.                 {
  5867.                     // @TODO(final): This is not right to assume default cursor always, because the size cursor does not work this way!
  5868.                     if(win32Window.isCursorActive) {
  5869.                         HCURSOR cursor = wapi.user.getCursor();
  5870.                         wapi.user.setCursor(cursor);
  5871.                     } else {
  5872.                         wapi.user.setCursor(nullptr);
  5873.                         return 1;
  5874.                     }
  5875.                 } break;
  5876.  
  5877.                 case WM_ERASEBKGND:
  5878.                 {
  5879.                     // Prevent erase background always
  5880.                     return 1;
  5881.                 } break;
  5882.  
  5883.                 default:
  5884.                     break;
  5885.             }
  5886.             result = win32_defWindowProc(hwnd, msg, wParam, lParam);
  5887.             return (result);
  5888.         }
  5889.  
  5890.         fpl_internal bool Win32InitWindow(const Settings &initSettings, WindowSettings &currentWindowSettings, platform::PlatformAppState *platAppState, Win32AppState &appState, Win32WindowState &windowState, const platform::SetupWindowCallbacks &setupCallbacks) {
  5891.             const Win32Api &wapi = appState.winApi;
  5892.             const WindowSettings &initWindowSettings = initSettings.window;
  5893.  
  5894.             // Register window class
  5895.             win32_wndclassex windowClass = {};
  5896.             windowClass.cbSize = sizeof(win32_wndclassex);
  5897.             windowClass.hInstance = GetModuleHandleA(nullptr);
  5898.             windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  5899.             windowClass.cbSize = sizeof(windowClass);
  5900.             windowClass.style = CS_HREDRAW | CS_VREDRAW;
  5901.             windowClass.hCursor = win32_loadCursor(windowClass.hInstance, IDC_ARROW);
  5902.             windowClass.hIcon = win32_loadIcon(windowClass.hInstance, IDI_APPLICATION);
  5903.             windowClass.hIconSm = win32_loadIcon(windowClass.hInstance, IDI_APPLICATION);
  5904.             windowClass.lpszClassName = FPL_WIN32_CLASSNAME;
  5905.             windowClass.lpfnWndProc = Win32MessageProc;
  5906.             windowClass.style |= CS_OWNDC;
  5907.             win32_copyString(windowClass.lpszClassName, win32_getStringLength(windowClass.lpszClassName), windowState.windowClass, FPL_ARRAYCOUNT(windowState.windowClass));
  5908.             if(win32_registerClassEx(&windowClass) == 0) {
  5909.                 common::PushError("Failed registering window class '%s'", windowState.windowClass);
  5910.                 return false;
  5911.             }
  5912.  
  5913.             // Create window
  5914.             win32_char windowTitleBuffer[1024];
  5915.             win32_char *windowTitle = FPL_WIN32_UNNAMED_WINDOW;
  5916.             currentWindowSettings.isFullscreen = false;
  5917.             if(strings::GetAnsiStringLength(initWindowSettings.windowTitle) > 0) {
  5918.                 win32_ansiToString(initWindowSettings.windowTitle, strings::GetAnsiStringLength(initWindowSettings.windowTitle), windowTitleBuffer, FPL_ARRAYCOUNT(windowTitleBuffer));
  5919.                 windowTitle = windowTitleBuffer;
  5920.                 strings::CopyAnsiString(initWindowSettings.windowTitle, strings::GetAnsiStringLength(initWindowSettings.windowTitle), currentWindowSettings.windowTitle, FPL_ARRAYCOUNT(currentWindowSettings.windowTitle));
  5921.             }
  5922.  
  5923.             DWORD style;
  5924.             DWORD exStyle;
  5925.             if(initWindowSettings.isResizable) {
  5926.                 style = Win32ResizeableWindowStyle;
  5927.                 exStyle = Win32ResizeableWindowExtendedStyle;
  5928.                 currentWindowSettings.isResizable = true;
  5929.             } else {
  5930.                 style = Win32NonResizableWindowStyle;
  5931.                 exStyle = Win32NonResizableWindowExtendedStyle;
  5932.                 currentWindowSettings.isResizable = false;
  5933.             }
  5934.  
  5935.             int windowX = CW_USEDEFAULT;
  5936.             int windowY = CW_USEDEFAULT;
  5937.             int windowWidth;
  5938.             int windowHeight;
  5939.             if((initWindowSettings.windowWidth > 0) &&
  5940.                 (initWindowSettings.windowHeight > 0)) {
  5941.                 RECT windowRect;
  5942.                 windowRect.left = 0;
  5943.                 windowRect.top = 0;
  5944.                 windowRect.right = initWindowSettings.windowWidth;
  5945.                 windowRect.bottom = initWindowSettings.windowHeight;
  5946.                 wapi.user.adjustWindowRect(&windowRect, style, false);
  5947.                 windowWidth = windowRect.right - windowRect.left;
  5948.                 windowHeight = windowRect.bottom - windowRect.top;
  5949.             } else {
  5950.                 // @NOTE(final): Operating system decide how big the window should be.
  5951.                 windowWidth = CW_USEDEFAULT;
  5952.                 windowHeight = CW_USEDEFAULT;
  5953.             }
  5954.  
  5955.  
  5956.             // Create window
  5957.             windowState.windowHandle = win32_createWindowEx(exStyle, windowClass.lpszClassName, windowTitle, style, windowX, windowY, windowWidth, windowHeight, nullptr, nullptr, windowClass.hInstance, nullptr);
  5958.             if(windowState.windowHandle == nullptr) {
  5959.                 common::PushError("Failed creating window for class '%s' and position (%d x %d) with size (%d x %d)", windowState.windowClass, windowX, windowY, windowWidth, windowHeight);
  5960.                 return false;
  5961.             }
  5962.  
  5963.             // Get actual window size and store results
  5964.             currentWindowSettings.windowWidth = windowWidth;
  5965.             currentWindowSettings.windowHeight = windowHeight;
  5966.             RECT clientRect;
  5967.             if(wapi.user.getClientRect(windowState.windowHandle, &clientRect)) {
  5968.                 currentWindowSettings.windowWidth = clientRect.right - clientRect.left;
  5969.                 currentWindowSettings.windowHeight = clientRect.bottom - clientRect.top;
  5970.             }
  5971.  
  5972.             // Get device context so we can swap the back and front buffer
  5973.             windowState.deviceContext = wapi.user.getDC(windowState.windowHandle);
  5974.             if(windowState.deviceContext == nullptr) {
  5975.                 common::PushError("Failed aquiring device context from window '%d'", windowState.windowHandle);
  5976.                 return false;
  5977.             }
  5978.  
  5979.             // Call post window setup callback
  5980.             if(setupCallbacks.postSetup != nullptr) {
  5981.                 setupCallbacks.postSetup(platAppState, platAppState->initFlags, initSettings);
  5982.             }
  5983.  
  5984.             // Enter fullscreen if needed
  5985.             if(initWindowSettings.isFullscreen) {
  5986.                 window::SetWindowFullscreen(true, initWindowSettings.fullscreenWidth, initWindowSettings.fullscreenHeight);
  5987.             }
  5988.  
  5989.             // Show window
  5990.             wapi.user.showWindow(windowState.windowHandle, SW_SHOW);
  5991.             wapi.user.updateWindow(windowState.windowHandle);
  5992.  
  5993.             // Cursor is visible at start
  5994.             windowState.defaultCursor = windowClass.hCursor;
  5995.             windowState.isCursorActive = true;
  5996.             windowState.isRunning = true;
  5997.  
  5998.             return true;
  5999.         }
  6000.  
  6001.         fpl_internal void Win32ReleaseWindow(const Win32InitState &initState, const Win32AppState &appState, Win32WindowState &windowState) {
  6002.             const Win32Api &wapi = appState.winApi;
  6003.  
  6004.             if(windowState.deviceContext != nullptr) {
  6005.                 wapi.user.releaseDC(windowState.windowHandle, windowState.deviceContext);
  6006.                 windowState.deviceContext = nullptr;
  6007.             }
  6008.  
  6009.             if(windowState.windowHandle != nullptr) {
  6010.                 wapi.user.destroyWindow(windowState.windowHandle);
  6011.                 windowState.windowHandle = nullptr;
  6012.                 win32_unregisterClass(windowState.windowClass, initState.appInstance);
  6013.             }
  6014.         }
  6015.  
  6016.         struct Win32CommandLineUTF8Arguments {
  6017.             void *mem;
  6018.             char **args;
  6019.             uint32_t count;
  6020.         };
  6021.         fpl_internal Win32CommandLineUTF8Arguments Win32ParseWideArguments(LPWSTR cmdLine) {
  6022.             Win32CommandLineUTF8Arguments args = {};
  6023.  
  6024.             // @NOTE(final): Temporary load and unload shell32 for parsing the arguments
  6025.             HMODULE shellapiLibrary = ::LoadLibraryA("shell32.dll");
  6026.             if(shellapiLibrary != nullptr) {
  6027.                 win32_func_CommandLineToArgvW *commandLineToArgvW = (win32_func_CommandLineToArgvW *)::GetProcAddress(shellapiLibrary, "CommandLineToArgvW");
  6028.                 if(commandLineToArgvW != nullptr) {
  6029.                     // Parse arguments and compute total UTF8 string length
  6030.                     int executableFilePathArgumentCount = 0;
  6031.                     wchar_t **executableFilePathArgs = commandLineToArgvW(L"", &executableFilePathArgumentCount);
  6032.                     uint32_t executableFilePathLen = 0;
  6033.                     for(int i = 0; i < executableFilePathArgumentCount; ++i) {
  6034.                         if(i > 0) {
  6035.                             // Include whitespace
  6036.                             executableFilePathLen++;
  6037.                         }
  6038.                         uint32_t sourceLen = strings::GetWideStringLength(executableFilePathArgs[i]);
  6039.                         uint32_t destLen = ::WideCharToMultiByte(CP_UTF8, 0, executableFilePathArgs[i], sourceLen, nullptr, 0, 0, 0);
  6040.                         executableFilePathLen += destLen;
  6041.                     }
  6042.  
  6043.                     // @NOTE(final): Do not parse the arguments when there are no actual arguments, otherwise we will get back the executable arguments again.
  6044.                     int actualArgumentCount = 0;
  6045.                     wchar_t **actualArgs = nullptr;
  6046.                     uint32_t actualArgumentsLen = 0;
  6047.                     if(cmdLine != nullptr && strings::GetWideStringLength(cmdLine) > 0) {
  6048.                         actualArgs = commandLineToArgvW(cmdLine, &actualArgumentCount);
  6049.                         for(int i = 0; i < actualArgumentCount; ++i) {
  6050.                             uint32_t sourceLen = strings::GetWideStringLength(actualArgs[i]);
  6051.                             uint32_t destLen = ::WideCharToMultiByte(CP_UTF8, 0, actualArgs[i], sourceLen, nullptr, 0, 0, 0);
  6052.                             actualArgumentsLen += destLen;
  6053.                         }
  6054.                     }
  6055.  
  6056.                     // Calculate argument
  6057.                     args.count = 1 + actualArgumentCount;
  6058.                     uint32_t totalStringLen = executableFilePathLen + actualArgumentsLen + args.count;
  6059.                     size_t singleArgStringSize = sizeof(char) * (totalStringLen);
  6060.                     size_t arbitaryPadding = platform::SIZE_PADDING;
  6061.                     size_t argArraySize = sizeof(char **) * args.count;
  6062.                     size_t totalArgSize = singleArgStringSize + arbitaryPadding + argArraySize;
  6063.  
  6064.                     args.mem = (uint8_t *)memory::MemoryAllocate(totalArgSize);
  6065.                     char *argsString = (char *)args.mem;
  6066.                     args.args = (char **)((uint8_t *)args.mem + singleArgStringSize + arbitaryPadding);
  6067.  
  6068.                     // Convert executable path to UTF8
  6069.                     char *destArg = argsString;
  6070.                     {
  6071.                         args.args[0] = argsString;
  6072.                         for(int i = 0; i < executableFilePathArgumentCount; ++i) {
  6073.                             if(i > 0) {
  6074.                                 *destArg++ = ' ';
  6075.                             }
  6076.                             wchar_t *sourceArg = executableFilePathArgs[i];
  6077.                             uint32_t sourceArgLen = strings::GetWideStringLength(sourceArg);
  6078.                             uint32_t destArgLen = ::WideCharToMultiByte(CP_UTF8, 0, sourceArg, sourceArgLen, nullptr, 0, 0, 0);
  6079.                             ::WideCharToMultiByte(CP_UTF8, 0, sourceArg, sourceArgLen, destArg, destArgLen, 0, 0);
  6080.                             destArg += destArgLen;
  6081.                         }
  6082.                         *destArg++ = 0;
  6083.                         ::LocalFree(executableFilePathArgs);
  6084.                     }
  6085.  
  6086.                     // Convert actual arguments to UTF8
  6087.                     if(actualArgumentCount > 0) {
  6088.                         FPL_ASSERT(actualArgs != nullptr);
  6089.                         for(int i = 0; i < actualArgumentCount; ++i) {
  6090.                             args.args[1 + i] = destArg;
  6091.                             wchar_t *sourceArg = actualArgs[i];
  6092.                             uint32_t sourceArgLen = strings::GetWideStringLength(sourceArg);
  6093.                             uint32_t destArgLen = ::WideCharToMultiByte(CP_UTF8, 0, sourceArg, sourceArgLen, nullptr, 0, 0, 0);
  6094.                             ::WideCharToMultiByte(CP_UTF8, 0, sourceArg, sourceArgLen, destArg, destArgLen, 0, 0);
  6095.                             destArg += destArgLen;
  6096.                             *destArg++ = 0;
  6097.                         }
  6098.                         LocalFree(actualArgs);
  6099.                     }
  6100.                 }
  6101.                 ::FreeLibrary(shellapiLibrary);
  6102.                 shellapiLibrary = nullptr;
  6103.             }
  6104.             return(args);
  6105.         }
  6106.  
  6107.         fpl_internal Win32CommandLineUTF8Arguments Win32ParseAnsiArguments(LPSTR cmdLine) {
  6108.             Win32CommandLineUTF8Arguments result;
  6109.             if(cmdLine != nullptr) {
  6110.                 uint32_t ansiSourceLen = strings::GetAnsiStringLength(cmdLine);
  6111.                 uint32_t wideDestLen = ::MultiByteToWideChar(CP_ACP, 0, cmdLine, ansiSourceLen, nullptr, 0);
  6112.                 // @TODO(final): Can we use a stack allocation here?
  6113.                 wchar_t *wideCmdLine = (wchar_t *)memory::MemoryAllocate(sizeof(wchar_t) * (wideDestLen + 1));
  6114.                 ::MultiByteToWideChar(CP_ACP, 0, cmdLine, ansiSourceLen, wideCmdLine, wideDestLen);
  6115.                 wideCmdLine[wideDestLen] = 0;
  6116.                 result = Win32ParseWideArguments(wideCmdLine);
  6117.                 memory::MemoryFree(wideCmdLine);
  6118.             } else {
  6119.                 result = Win32ParseWideArguments(L"");
  6120.             }
  6121.             return(result);
  6122.         }
  6123.  
  6124. #   endif // FPL_ENABLE_WINDOW
  6125.  
  6126.         fpl_internal bool Win32ThreadWaitForMultiple(threading::ThreadHandle *threads[], const uint32_t count, const bool waitForAll, const uint32_t maxMilliseconds) {
  6127.             if(threads == nullptr) {
  6128.                 common::ArgumentNullError("Threads");
  6129.                 return false;
  6130.             }
  6131.             if(count > common::MAX_THREAD_COUNT) {
  6132.                 common::ArgumentSizeTooBigError("Count", count, common::MAX_THREAD_COUNT);
  6133.                 return false;
  6134.             }
  6135.             HANDLE threadHandles[common::MAX_THREAD_COUNT];
  6136.             for(uint32_t index = 0; index < count; ++index) {
  6137.                 threading::ThreadHandle *thread = threads[index];
  6138.                 if(thread == nullptr) {
  6139.                     common::PushError("Thread for index '%d' are not allowed to be null", index);
  6140.                     return false;
  6141.                 }
  6142.                 if(thread->internalHandle.win32ThreadHandle == nullptr) {
  6143.                     common::PushError("Thread handle for index '%d' are not allowed to be null", index);
  6144.                     return false;
  6145.                 }
  6146.                 HANDLE handle = thread->internalHandle.win32ThreadHandle;
  6147.                 threadHandles[index] = handle;
  6148.             }
  6149.             DWORD code = ::WaitForMultipleObjects(count, threadHandles, waitForAll ? TRUE : FALSE, maxMilliseconds < UINT32_MAX ? maxMilliseconds : INFINITE);
  6150.             bool result = (code != WAIT_TIMEOUT) && (code != WAIT_FAILED);
  6151.             return(result);
  6152.         }
  6153.  
  6154.         fpl_internal bool Win32SignalWaitForMultiple(threading::SignalHandle *signals[], const uint32_t count, const bool waitForAll, const uint32_t maxMilliseconds) {
  6155.             if(signals == nullptr) {
  6156.                 common::ArgumentNullError("Signals");
  6157.                 return false;
  6158.             }
  6159.             if(count > common::MAX_SIGNAL_COUNT) {
  6160.                 common::ArgumentSizeTooBigError("Count", count, common::MAX_SIGNAL_COUNT);
  6161.                 return false;
  6162.             }
  6163.             HANDLE signalHandles[common::MAX_SIGNAL_COUNT];
  6164.             for(uint32_t index = 0; index < count; ++index) {
  6165.                 threading::SignalHandle *availableSignal = signals[index];
  6166.                 if(availableSignal == nullptr) {
  6167.                     common::PushError("Signal for index '%d' are not allowed to be null", index);
  6168.                     return false;
  6169.                 }
  6170.                 if(availableSignal->internalHandle.win32EventHandle == nullptr) {
  6171.                     common::PushError("Signal handle for index '%d' are not allowed to be null", index);
  6172.                     return false;
  6173.                 }
  6174.                 HANDLE handle = availableSignal->internalHandle.win32EventHandle;
  6175.                 signalHandles[index] = handle;
  6176.             }
  6177.             DWORD code = ::WaitForMultipleObjects(count, signalHandles, waitForAll ? TRUE : FALSE, maxMilliseconds < UINT32_MAX ? maxMilliseconds : INFINITE);
  6178.             bool result = (code != WAIT_TIMEOUT) && (code != WAIT_FAILED);
  6179.             return(result);
  6180.         }
  6181.  
  6182.         fpl_internal void Win32ReleasePlatform(platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  6183.             FPL_ASSERT(appState != nullptr);
  6184.             Win32AppState &win32AppState = appState->win32;
  6185.             Settings &currentSettings = appState->currentSettings;
  6186.             Win32InitState &win32InitState = initState.win32;
  6187.  
  6188.             Win32UnloadXInputApi(win32AppState.xinput.xinputApi);
  6189.  
  6190.             Win32UnloadApi(win32AppState.winApi);
  6191.         }
  6192.  
  6193.         fpl_internal bool Win32InitPlatform(const InitFlags initFlags, const Settings &initSettings, platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  6194.             Win32InitState &win32InitState = initState.win32;
  6195.             win32InitState.appInstance = ::GetModuleHandleA(nullptr);
  6196.  
  6197.             FPL_ASSERT(appState != nullptr);
  6198.             Win32AppState &win32AppState = appState->win32;
  6199.  
  6200.             // @NOTE(final): Expect kernel32.lib to be linked always, so VirtualAlloc and LoadLibrary will always work.
  6201.  
  6202.             // Timing
  6203.             ::QueryPerformanceFrequency(&win32InitState.performanceFrequency);
  6204.  
  6205.             // Get main thread infos
  6206.             HANDLE mainThreadHandle = ::GetCurrentThread();
  6207.             DWORD mainThreadHandleId = ::GetCurrentThreadId();
  6208.             threading::ThreadHandle *mainThread = &common::global__ThreadState.mainThread;
  6209.             *mainThread = {};
  6210.             mainThread->id = mainThreadHandleId;
  6211.             mainThread->internalHandle.win32ThreadHandle = mainThreadHandle;
  6212.             mainThread->currentState = threading::ThreadState::Running;
  6213.  
  6214.             // Load windows api library
  6215.             if(!Win32LoadApi(win32AppState.winApi)) {
  6216.                 // @NOTE(final): Assume that errors are pushed on already.
  6217.                 Win32ReleasePlatform(initState, appState);
  6218.                 return false;
  6219.             }
  6220.  
  6221.             // Load XInput
  6222.             Win32LoadXInputApi(win32AppState.xinput.xinputApi);
  6223.  
  6224.             return (true);
  6225.         }
  6226.  
  6227.     } // platform
  6228.  
  6229.     //
  6230.     // Win32 Atomics
  6231.     //
  6232.     namespace atomics {
  6233.         fpl_platform_api void AtomicReadFence() {
  6234.             FPL_MEMORY_BARRIER();
  6235.             ::_ReadBarrier();
  6236.         }
  6237.         fpl_platform_api void AtomicWriteFence() {
  6238.             FPL_MEMORY_BARRIER();
  6239.             ::_WriteBarrier();
  6240.         }
  6241.         fpl_platform_api void AtomicReadWriteFence() {
  6242.             FPL_MEMORY_BARRIER();
  6243.             ::_ReadWriteBarrier();
  6244.         }
  6245.  
  6246.         fpl_platform_api uint32_t AtomicExchangeU32(volatile uint32_t *target, const uint32_t value) {
  6247.             FPL_ASSERT(target != nullptr);
  6248.             uint32_t result = ::_InterlockedExchange((volatile unsigned long *)target, value);
  6249.             return (result);
  6250.         }
  6251.         fpl_platform_api int32_t AtomicExchangeS32(volatile int32_t *target, const int32_t value) {
  6252.             FPL_ASSERT(target != nullptr);
  6253.             int32_t result = ::_InterlockedExchange((volatile long *)target, value);
  6254.             return (result);
  6255.         }
  6256.         fpl_platform_api uint64_t AtomicExchangeU64(volatile uint64_t *target, const uint64_t value) {
  6257.             FPL_ASSERT(target != nullptr);
  6258.             uint64_t result = ::_InterlockedExchange((volatile unsigned __int64 *)target, value);
  6259.             return (result);
  6260.         }
  6261.         fpl_platform_api int64_t AtomicExchangeS64(volatile int64_t *target, const int64_t value) {
  6262.             FPL_ASSERT(target != nullptr);
  6263. #       if defined(FPL_ARCH_X64)
  6264.             int64_t result = ::_InterlockedExchange64((volatile long long *)target, value);
  6265. #       else
  6266.             // @NOTE(final): Why does MSVC have no _InterlockedExchange64 on x86???
  6267.             int64_t result = ::_InterlockedCompareExchange64((volatile long long *)target, value, value);
  6268. #       endif
  6269.             return (result);
  6270.         }
  6271.  
  6272.         fpl_platform_api uint32_t AtomicAddU32(volatile uint32_t *value, const uint32_t addend) {
  6273.             FPL_ASSERT(value != nullptr);
  6274.             uint32_t result = ::_InterlockedExchangeAdd((volatile unsigned long *)value, addend);
  6275.             return (result);
  6276.         }
  6277.         fpl_platform_api int32_t AtomicAddS32(volatile int32_t *value, const int32_t addend) {
  6278.             FPL_ASSERT(value != nullptr);
  6279.             int32_t result = ::_InterlockedExchangeAdd((volatile long *)value, addend);
  6280.             return (result);
  6281.         }
  6282.         fpl_platform_api uint64_t AtomicAddU64(volatile uint64_t *value, const uint64_t addend) {
  6283.             FPL_ASSERT(value != nullptr);
  6284.             uint64_t result = ::_InterlockedExchangeAdd((volatile unsigned __int64 *)value, addend);
  6285.             return (result);
  6286.         }
  6287.         fpl_platform_api int64_t AtomicAddS64(volatile int64_t *value, const int64_t addend) {
  6288.             FPL_ASSERT(value != nullptr);
  6289. #       if defined(FPL_ARCH_X64)
  6290.             int64_t result = ::_InterlockedExchangeAdd64((volatile long long *)value, addend);
  6291. #       else
  6292.             // @NOTE(final): Why does MSVC have no _InterlockedExchangeAdd64 on x86???
  6293.             int64_t oldValue = AtomicLoadS64(value);
  6294.             int64_t newValue = oldValue + addend;
  6295.             int64_t result = oldValue;
  6296.             AtomicStoreS64(value, newValue);
  6297. #       endif
  6298.             return (result);
  6299.         }
  6300.  
  6301.         fpl_platform_api uint32_t AtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
  6302.             FPL_ASSERT(dest != nullptr);
  6303.             uint32_t result = ::_InterlockedCompareExchange((volatile unsigned long *)dest, exchange, comparand);
  6304.             return (result);
  6305.         }
  6306.         fpl_platform_api int32_t AtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
  6307.             FPL_ASSERT(dest != nullptr);
  6308.             int32_t result = ::_InterlockedCompareExchange((volatile long *)dest, exchange, comparand);
  6309.             return (result);
  6310.         }
  6311.         fpl_platform_api uint64_t AtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
  6312.             FPL_ASSERT(dest != nullptr);
  6313.             uint64_t result = ::_InterlockedCompareExchange((volatile unsigned __int64 *)dest, exchange, comparand);
  6314.             return (result);
  6315.         }
  6316.         fpl_platform_api int64_t AtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
  6317.             FPL_ASSERT(dest != nullptr);
  6318.             int64_t result = ::_InterlockedCompareExchange64((volatile long long *)dest, exchange, comparand);
  6319.             return (result);
  6320.         }
  6321.  
  6322.         fpl_platform_api bool IsAtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
  6323.             FPL_ASSERT(dest != nullptr);
  6324.             uint32_t value = ::_InterlockedCompareExchange((volatile unsigned long *)dest, exchange, comparand);
  6325.             bool result = (value == comparand);
  6326.             return (result);
  6327.         }
  6328.         fpl_platform_api bool IsAtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
  6329.             FPL_ASSERT(dest != nullptr);
  6330.             int32_t value = ::_InterlockedCompareExchange((volatile long *)dest, exchange, comparand);
  6331.             bool result = (value == comparand);
  6332.             return (result);
  6333.         }
  6334.         fpl_platform_api bool IsAtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
  6335.             FPL_ASSERT(dest != nullptr);
  6336.             uint64_t value = ::_InterlockedCompareExchange((volatile unsigned __int64 *)dest, exchange, comparand);
  6337.             bool result = (value == comparand);
  6338.             return (result);
  6339.         }
  6340.         fpl_platform_api bool IsAtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
  6341.             FPL_ASSERT(dest != nullptr);
  6342.             int64_t value = ::_InterlockedCompareExchange64((volatile long long *)dest, exchange, comparand);
  6343.             bool result = (value == comparand);
  6344.             return (result);
  6345.         }
  6346.  
  6347.         fpl_platform_api uint32_t AtomicLoadU32(volatile uint32_t *source) {
  6348.             uint32_t result = ::_InterlockedCompareExchange((volatile unsigned long *)source, 0, 0);
  6349.             return(result);
  6350.         }
  6351.         fpl_platform_api uint64_t AtomicLoadU64(volatile uint64_t *source) {
  6352.             uint64_t result = ::_InterlockedCompareExchange((volatile unsigned __int64 *)source, 0, 0);
  6353.             return(result);
  6354.         }
  6355.         fpl_platform_api int32_t AtomicLoadS32(volatile int32_t *source) {
  6356.             int32_t result = ::_InterlockedCompareExchange((volatile long *)source, 0, 0);
  6357.             return(result);
  6358.         }
  6359.         fpl_platform_api int64_t AtomicLoadS64(volatile int64_t *source) {
  6360.             int64_t result = ::_InterlockedCompareExchange64((volatile __int64 *)source, 0, 0);
  6361.             return(result);
  6362.         }
  6363.  
  6364.         fpl_platform_api void AtomicStoreU32(volatile uint32_t *dest, const uint32_t value) {
  6365.             ::_InterlockedExchange((volatile unsigned long *)dest, value);
  6366.         }
  6367.         fpl_platform_api void AtomicStoreU64(volatile uint64_t *dest, const uint64_t value) {
  6368.             ::_InterlockedExchange((volatile unsigned __int64 *)dest, value);
  6369.         }
  6370.         fpl_platform_api void AtomicStoreS32(volatile int32_t *dest, const int32_t value) {
  6371.             ::_InterlockedExchange((volatile long *)dest, value);
  6372.         }
  6373.         fpl_platform_api void AtomicStoreS64(volatile int64_t *dest, const int64_t value) {
  6374. #       if defined(FPL_ARCH_X64)
  6375.             ::_InterlockedExchange64((volatile __int64 *)dest, value);
  6376. #       else
  6377.             // @NOTE(final): Why does MSVC have no _InterlockedExchange64 on x86???
  6378.             int64_t oldValue = AtomicLoadS64(dest);
  6379.             ::_InterlockedCompareExchange64((volatile __int64 *)dest, value, oldValue);
  6380. #       endif
  6381.         }
  6382.     } // atomics
  6383.  
  6384.     //
  6385.     // Win32 Hardware
  6386.     //
  6387.     namespace hardware {
  6388.         fpl_platform_api uint32_t GetProcessorCoreCount() {
  6389.             SYSTEM_INFO sysInfo = {};
  6390.             ::GetSystemInfo(&sysInfo);
  6391.             // @NOTE(final): For now this returns the number of logical processors, which is the actual core count in most cases.
  6392.             uint32_t result = sysInfo.dwNumberOfProcessors;
  6393.             return(result);
  6394.         }
  6395.  
  6396.         fpl_platform_api MemoryInfos GetSystemMemoryInfos() {
  6397.             MemoryInfos result = {};
  6398.             MEMORYSTATUSEX statex = {};
  6399.             statex.dwLength = sizeof(statex);
  6400.             ULONGLONG totalMemorySize;
  6401.             if(::GetPhysicallyInstalledSystemMemory(&totalMemorySize) && ::GlobalMemoryStatusEx(&statex)) {
  6402.                 result.totalPhysicalSize = totalMemorySize * 1024ull;
  6403.                 result.availablePhysicalSize = statex.ullTotalPhys;
  6404.                 result.usedPhysicalSize = result.availablePhysicalSize - statex.ullAvailPhys;
  6405.                 result.totalVirtualSize = statex.ullTotalVirtual;
  6406.                 result.usedVirtualSize = result.totalVirtualSize - statex.ullAvailVirtual;
  6407.                 result.totalPageSize = statex.ullTotalPageFile;
  6408.                 result.usedPageSize = result.totalPageSize - statex.ullAvailPageFile;
  6409.             }
  6410.             return(result);
  6411.         }
  6412.  
  6413.         fpl_platform_api char *GetProcessorName(char *destBuffer, const uint32_t maxDestBufferLen) {
  6414.             fpl_constant uint32_t CPU_BRAND_BUFFER_SIZE = 0x40;
  6415.  
  6416.             if(destBuffer == nullptr) {
  6417.                 common::ArgumentNullError("Dest buffer");
  6418.                 return nullptr;
  6419.             }
  6420.  
  6421.             size_t requiredDestBufferLen = CPU_BRAND_BUFFER_SIZE + 1;
  6422.             if(maxDestBufferLen < requiredDestBufferLen) {
  6423.                 common::ArgumentSizeTooSmallError("Max dest buffer len", maxDestBufferLen, requiredDestBufferLen);
  6424.                 return nullptr;
  6425.             }
  6426.  
  6427.             // @TODO(final): __cpuid may not be available on other Win32 Compilers!
  6428.  
  6429.             int cpuInfo[4] = { -1 };
  6430.             char cpuBrandBuffer[CPU_BRAND_BUFFER_SIZE] = {};
  6431.             ::__cpuid(cpuInfo, 0x80000000);
  6432.             uint32_t extendedIds = cpuInfo[0];
  6433.  
  6434.             // Get the information associated with each extended ID. Interpret CPU brand string.
  6435.             uint32_t max = FPL_MIN(extendedIds, 0x80000004);
  6436.             for(uint32_t i = 0x80000002; i <= max; ++i) {
  6437.                 ::__cpuid(cpuInfo, i);
  6438.                 uint32_t offset = (i - 0x80000002) << 4;
  6439.                 memory::MemoryCopy(cpuInfo, sizeof(cpuInfo), cpuBrandBuffer + offset);
  6440.             }
  6441.  
  6442.             // Copy result back to the dest buffer
  6443.             uint32_t sourceLen = strings::GetAnsiStringLength(cpuBrandBuffer);
  6444.             strings::CopyAnsiString(cpuBrandBuffer, sourceLen, destBuffer, maxDestBufferLen);
  6445.  
  6446.             return(destBuffer);
  6447.         }
  6448.     } // hardware
  6449.  
  6450.     //
  6451.     // Win32 Threading
  6452.     //
  6453.     namespace threading {
  6454.         fpl_internal DWORD WINAPI Win32ThreadProc(void *data) {
  6455.             ThreadHandle *thread = (ThreadHandle *)data;
  6456.             FPL_ASSERT(thread != nullptr);
  6457.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)ThreadState::Running);
  6458.             DWORD result = 0;
  6459.             if(thread->runFunc != nullptr) {
  6460.                 thread->runFunc(*thread, thread->data);
  6461.             }
  6462.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)ThreadState::Stopped);
  6463.             return(result);
  6464.         }
  6465.  
  6466.         fpl_platform_api ThreadHandle *ThreadCreate(run_thread_function *runFunc, void *data) {
  6467.             ThreadHandle *result = nullptr;
  6468.             ThreadHandle *thread = common::GetFreeThread();
  6469.             if(thread != nullptr) {
  6470.                 DWORD creationFlags = 0;
  6471.                 DWORD threadId = 0;
  6472.                 thread->data = data;
  6473.                 thread->runFunc = runFunc;
  6474.                 thread->currentState = ThreadState::Starting;
  6475.                 HANDLE handle = ::CreateThread(nullptr, 0, Win32ThreadProc, thread, creationFlags, &threadId);
  6476.                 if(handle != nullptr) {
  6477.                     thread->isValid = true;
  6478.                     thread->id = threadId;
  6479.                     thread->internalHandle.win32ThreadHandle = handle;
  6480.                     result = thread;
  6481.                 } else {
  6482.                     common::PushError("Failed creating thread, error code: %d", GetLastError());
  6483.                 }
  6484.             } else {
  6485.                 common::PushError("All %d threads are in use, you cannot create until you free one", common::MAX_THREAD_COUNT);
  6486.             }
  6487.             return(result);
  6488.         }
  6489.  
  6490.         fpl_platform_api void ThreadSleep(const uint32_t milliseconds) {
  6491.             ::Sleep((DWORD)milliseconds);
  6492.         }
  6493.  
  6494.         fpl_platform_api void ThreadDestroy(ThreadHandle *thread) {
  6495.             if(thread == nullptr) {
  6496.                 common::ArgumentNullError("Thread");
  6497.                 return;
  6498.             }
  6499.             if(thread->internalHandle.win32ThreadHandle == nullptr) {
  6500.                 common::PushError("Win32 thread handle are not allowed to be null");
  6501.                 return;
  6502.             }
  6503.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)ThreadState::Stopping);
  6504.             HANDLE handle = thread->internalHandle.win32ThreadHandle;
  6505.             ::TerminateThread(handle, 0);
  6506.             ::CloseHandle(handle);
  6507.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)ThreadState::Stopped);
  6508.             *thread = {};
  6509.         }
  6510.  
  6511.         fpl_platform_api bool ThreadWaitForOne(ThreadHandle *thread, const uint32_t maxMilliseconds) {
  6512.             if(thread == nullptr) {
  6513.                 common::ArgumentNullError("Thread");
  6514.                 return false;
  6515.             }
  6516.             if(thread->internalHandle.win32ThreadHandle == nullptr) {
  6517.                 common::PushError("Win32 thread handle are not allowed to be null");
  6518.                 return false;
  6519.             }
  6520.             HANDLE handle = thread->internalHandle.win32ThreadHandle;
  6521.             bool result = (::WaitForSingleObject(handle, maxMilliseconds < UINT32_MAX ? maxMilliseconds : INFINITE) == WAIT_OBJECT_0);
  6522.             return(result);
  6523.         }
  6524.  
  6525.         fpl_platform_api bool ThreadWaitForAll(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds) {
  6526.             bool result = platform_win32::Win32ThreadWaitForMultiple(threads, count, true, maxMilliseconds);
  6527.             return(result);
  6528.         }
  6529.  
  6530.         fpl_platform_api bool ThreadWaitForAny(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds) {
  6531.             bool result = platform_win32::Win32ThreadWaitForMultiple(threads, count, false, maxMilliseconds);
  6532.             return(result);
  6533.         }
  6534.  
  6535.         fpl_platform_api MutexHandle MutexCreate() {
  6536.             MutexHandle result = {};
  6537.             ::InitializeCriticalSection(&result.internalHandle.win32CriticalSection);
  6538.             result.isValid = true;
  6539.             return(result);
  6540.         }
  6541.  
  6542.         fpl_platform_api void MutexDestroy(MutexHandle &mutex) {
  6543.             if(mutex.isValid) {
  6544.                 ::DeleteCriticalSection(&mutex.internalHandle.win32CriticalSection);
  6545.             }
  6546.             mutex = {};
  6547.         }
  6548.  
  6549.         fpl_platform_api bool MutexLock(MutexHandle &mutex, const uint32_t maxMilliseconds) {
  6550.             if(!mutex.isValid) {
  6551.                 common::PushError("Mutex parameter must be valid");
  6552.                 return false;
  6553.             }
  6554.             ::EnterCriticalSection(&mutex.internalHandle.win32CriticalSection);
  6555.             return true;
  6556.         }
  6557.  
  6558.         fpl_platform_api bool MutexUnlock(MutexHandle &mutex) {
  6559.             if(!mutex.isValid) {
  6560.                 common::PushError("Mutex parameter must be valid");
  6561.                 return false;
  6562.             }
  6563.             ::LeaveCriticalSection(&mutex.internalHandle.win32CriticalSection);
  6564.             return true;
  6565.         }
  6566.  
  6567.         fpl_platform_api SignalHandle SignalCreate() {
  6568.             SignalHandle result = {};
  6569.             HANDLE handle = ::CreateEventA(nullptr, FALSE, FALSE, nullptr);
  6570.             if(handle != nullptr) {
  6571.                 result.isValid = true;
  6572.                 result.internalHandle.win32EventHandle = handle;
  6573.             } else {
  6574.                 common::PushError("Failed creating signal (Win32 event): %d", GetLastError());
  6575.             }
  6576.             return(result);
  6577.         }
  6578.  
  6579.         fpl_platform_api void SignalDestroy(SignalHandle &signal) {
  6580.             if(signal.internalHandle.win32EventHandle == nullptr) {
  6581.                 common::PushError("Signal handle are not allowed to be null");
  6582.                 return;
  6583.             }
  6584.             HANDLE handle = signal.internalHandle.win32EventHandle;
  6585.             ::CloseHandle(handle);
  6586.             signal = {};
  6587.         }
  6588.  
  6589.         fpl_platform_api bool SignalWaitForOne(MutexHandle &mutex, SignalHandle &signal, const uint32_t maxMilliseconds) {
  6590.             if(signal.internalHandle.win32EventHandle == nullptr) {
  6591.                 common::PushError("Signal handle are not allowed to be null");
  6592.                 return false;
  6593.             }
  6594.             HANDLE handle = signal.internalHandle.win32EventHandle;
  6595.             bool result = (::WaitForSingleObject(handle, maxMilliseconds < UINT32_MAX ? maxMilliseconds : INFINITE) == WAIT_OBJECT_0);
  6596.             return(result);
  6597.         }
  6598.  
  6599.         fpl_platform_api bool SignalWaitForAll(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds) {
  6600.             bool result = platform_win32::Win32SignalWaitForMultiple((SignalHandle **)signals, count, true, maxMilliseconds);
  6601.             return(result);
  6602.         }
  6603.  
  6604.         fpl_platform_api bool SignalWaitForAny(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds) {
  6605.             bool result = platform_win32::Win32SignalWaitForMultiple((SignalHandle **)signals, count, false, maxMilliseconds);
  6606.             return(result);
  6607.         }
  6608.  
  6609.         fpl_platform_api bool SignalSet(SignalHandle &signal) {
  6610.             if(signal.internalHandle.win32EventHandle == nullptr) {
  6611.                 common::PushError("Signal handle are not allowed to be null");
  6612.                 return false;
  6613.             }
  6614.             HANDLE handle = signal.internalHandle.win32EventHandle;
  6615.             bool result = ::SetEvent(handle) == TRUE;
  6616.             return(result);
  6617.         }
  6618.  
  6619.     } // threading
  6620.  
  6621.     //
  6622.     // Win32 Memory
  6623.     //
  6624.     namespace memory {
  6625.         fpl_platform_api void *MemoryAllocate(const size_t size) {
  6626.             if(size == 0) {
  6627.                 common::ArgumentZeroError("Size");
  6628.                 return nullptr;
  6629.             }
  6630.             void *result = ::VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  6631.             if(result == nullptr) {
  6632.                 common::PushError("Failed allocating memory of %xu bytes", size);
  6633.             }
  6634.             return(result);
  6635.         }
  6636.  
  6637.         fpl_platform_api void MemoryFree(void *ptr) {
  6638.             if(ptr == nullptr) {
  6639.                 common::ArgumentNullError("Pointer");
  6640.                 return;
  6641.             }
  6642.             ::VirtualFree(ptr, 0, MEM_FREE);
  6643.         }
  6644.     } // memory
  6645.  
  6646.     //
  6647.     // Win32 Files
  6648.     //
  6649.     namespace files {
  6650.         fpl_platform_api FileHandle OpenBinaryFile(const char *filePath) {
  6651.             FileHandle result = {};
  6652.             if(filePath != nullptr) {
  6653.                 HANDLE win32FileHandle = ::CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  6654.                 if(win32FileHandle != INVALID_HANDLE_VALUE) {
  6655.                     result.isValid = true;
  6656.                     result.internalHandle.win32FileHandle = (void *)win32FileHandle;
  6657.                 }
  6658.             }
  6659.             return(result);
  6660.         }
  6661.         fpl_platform_api FileHandle OpenBinaryFile(const wchar_t *filePath) {
  6662.             FileHandle result = {};
  6663.             if(filePath != nullptr) {
  6664.                 HANDLE win32FileHandle = ::CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  6665.                 if(win32FileHandle != INVALID_HANDLE_VALUE) {
  6666.                     result.isValid = true;
  6667.                     result.internalHandle.win32FileHandle = (void *)win32FileHandle;
  6668.                 }
  6669.             }
  6670.             return(result);
  6671.         }
  6672.  
  6673.         fpl_platform_api FileHandle CreateBinaryFile(const char *filePath) {
  6674.             FileHandle result = {};
  6675.             if(filePath != nullptr) {
  6676.                 HANDLE win32FileHandle = ::CreateFileA(filePath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  6677.                 if(win32FileHandle != INVALID_HANDLE_VALUE) {
  6678.                     result.isValid = true;
  6679.                     result.internalHandle.win32FileHandle = (void *)win32FileHandle;
  6680.                 }
  6681.             }
  6682.             return(result);
  6683.         }
  6684.         fpl_platform_api FileHandle CreateBinaryFile(const wchar_t *filePath) {
  6685.             FileHandle result = {};
  6686.             if(filePath != nullptr) {
  6687.                 HANDLE win32FileHandle = ::CreateFileW(filePath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  6688.                 if(win32FileHandle != INVALID_HANDLE_VALUE) {
  6689.                     result.isValid = true;
  6690.                     result.internalHandle.win32FileHandle = (void *)win32FileHandle;
  6691.                 }
  6692.             }
  6693.             return(result);
  6694.         }
  6695.  
  6696.         fpl_platform_api uint32_t ReadFileBlock32(const FileHandle &fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize) {
  6697.             if(sizeToRead == 0) {
  6698.                 return 0;
  6699.             }
  6700.             if(targetBuffer == nullptr) {
  6701.                 common::ArgumentNullError("Target buffer");
  6702.                 return 0;
  6703.             }
  6704.             if(fileHandle.internalHandle.win32FileHandle == nullptr) {
  6705.                 common::PushError("File handle is not opened for reading");
  6706.                 return 0;
  6707.             }
  6708.             uint32_t result = 0;
  6709.             HANDLE win32FileHandle = (HANDLE)fileHandle.internalHandle.win32FileHandle;
  6710.             DWORD bytesRead = 0;
  6711.             if(::ReadFile(win32FileHandle, targetBuffer, (DWORD)sizeToRead, &bytesRead, nullptr) == TRUE) {
  6712.                 result = bytesRead;
  6713.             }
  6714.             return(result);
  6715.         }
  6716.  
  6717.         fpl_platform_api uint32_t WriteFileBlock32(const FileHandle &fileHandle, void *sourceBuffer, const uint32_t sourceSize) {
  6718.             if(sourceSize == 0) {
  6719.                 common::ArgumentZeroError("Source size");
  6720.                 return 0;
  6721.             }
  6722.             if(sourceBuffer == nullptr) {
  6723.                 common::ArgumentNullError("Source buffer");
  6724.                 return 0;
  6725.             }
  6726.             if(fileHandle.internalHandle.win32FileHandle == nullptr) {
  6727.                 common::PushError("File handle is not opened for writing");
  6728.                 return 0;
  6729.             }
  6730.             uint32_t result = 0;
  6731.             HANDLE win32FileHandle = (HANDLE)fileHandle.internalHandle.win32FileHandle;
  6732.             DWORD bytesWritten = 0;
  6733.             if(::WriteFile(win32FileHandle, sourceBuffer, (DWORD)sourceSize, &bytesWritten, nullptr) == TRUE) {
  6734.                 result = bytesWritten;
  6735.             }
  6736.             return(result);
  6737.         }
  6738.  
  6739.         fpl_platform_api void SetFilePosition32(const FileHandle &fileHandle, const int32_t position, const FilePositionMode mode) {
  6740.             if(fileHandle.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6741.                 HANDLE win32FileHandle = (void *)fileHandle.internalHandle.win32FileHandle;
  6742.                 DWORD moveMethod = FILE_BEGIN;
  6743.                 if(mode == FilePositionMode::Current) {
  6744.                     moveMethod = FILE_CURRENT;
  6745.                 } else if(mode == FilePositionMode::End) {
  6746.                     moveMethod = FILE_END;
  6747.                 }
  6748.                 ::SetFilePointer(win32FileHandle, (LONG)position, nullptr, moveMethod);
  6749.             }
  6750.         }
  6751.  
  6752.         fpl_platform_api uint32_t GetFilePosition32(const FileHandle &fileHandle) {
  6753.             uint32_t result = 0;
  6754.             if(fileHandle.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6755.                 HANDLE win32FileHandle = (void *)fileHandle.internalHandle.win32FileHandle;
  6756.                 DWORD filePosition = ::SetFilePointer(win32FileHandle, 0L, nullptr, FILE_CURRENT);
  6757.                 if(filePosition != INVALID_SET_FILE_POINTER) {
  6758.                     result = filePosition;
  6759.                 }
  6760.             }
  6761.             return(result);
  6762.         }
  6763.  
  6764.         fpl_platform_api void CloseFile(FileHandle &fileHandle) {
  6765.             if(fileHandle.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6766.                 HANDLE win32FileHandle = (void *)fileHandle.internalHandle.win32FileHandle;
  6767.                 ::CloseHandle(win32FileHandle);
  6768.                 fileHandle = {};
  6769.             }
  6770.         }
  6771.  
  6772.         fpl_platform_api uint32_t GetFileSize32(const char *filePath) {
  6773.             uint32_t result = 0;
  6774.             if(filePath != nullptr) {
  6775.                 HANDLE win32FileHandle = ::CreateFileA(filePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  6776.                 if(win32FileHandle != INVALID_HANDLE_VALUE) {
  6777.                     DWORD fileSize = ::GetFileSize(win32FileHandle, nullptr);
  6778.                     result = fileSize;
  6779.                     ::CloseHandle(win32FileHandle);
  6780.                 }
  6781.             }
  6782.             return(result);
  6783.         }
  6784.  
  6785.         fpl_platform_api uint32_t GetFileSize32(const FileHandle &fileHandle) {
  6786.             uint32_t result = 0;
  6787.             if(fileHandle.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6788.                 HANDLE win32FileHandle = (void *)fileHandle.internalHandle.win32FileHandle;
  6789.                 DWORD fileSize = ::GetFileSize(win32FileHandle, nullptr);
  6790.                 result = fileSize;
  6791.             }
  6792.             return(result);
  6793.         }
  6794.  
  6795.         fpl_platform_api bool FileExists(const char *filePath) {
  6796.             bool result = false;
  6797.             if(filePath != nullptr) {
  6798.                 WIN32_FIND_DATAA findData;
  6799.                 HANDLE searchHandle = ::FindFirstFileA(filePath, &findData);
  6800.                 if(searchHandle != INVALID_HANDLE_VALUE) {
  6801.                     result = !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  6802.                     ::FindClose(searchHandle);
  6803.                 }
  6804.             }
  6805.             return(result);
  6806.         }
  6807.  
  6808.         fpl_platform_api bool FileCopy(const char *sourceFilePath, const char *targetFilePath, const bool overwrite) {
  6809.             if(sourceFilePath == nullptr) {
  6810.                 common::ArgumentNullError("Source file path");
  6811.                 return false;
  6812.             }
  6813.             if(targetFilePath == nullptr) {
  6814.                 common::ArgumentNullError("Target file path");
  6815.                 return false;
  6816.             }
  6817.             bool result = (::CopyFileA(sourceFilePath, targetFilePath, !overwrite) == TRUE);
  6818.             return(result);
  6819.         }
  6820.  
  6821.         fpl_platform_api bool FileMove(const char *sourceFilePath, const char *targetFilePath) {
  6822.             if(sourceFilePath == nullptr) {
  6823.                 common::ArgumentNullError("Source file path");
  6824.                 return false;
  6825.             }
  6826.             if(targetFilePath == nullptr) {
  6827.                 common::ArgumentNullError("Target file path");
  6828.                 return false;
  6829.             }
  6830.             bool result = (::MoveFileA(sourceFilePath, targetFilePath) == TRUE);
  6831.             return(result);
  6832.         }
  6833.  
  6834.         fpl_platform_api bool FileDelete(const char *filePath) {
  6835.             if(filePath == nullptr) {
  6836.                 common::ArgumentNullError("File path");
  6837.                 return false;
  6838.             }
  6839.             bool result = (::DeleteFileA(filePath) == TRUE);
  6840.             return(result);
  6841.         }
  6842.  
  6843.         fpl_platform_api bool DirectoryExists(const char *path) {
  6844.             bool result = false;
  6845.             if(path != nullptr) {
  6846.                 WIN32_FIND_DATAA findData;
  6847.                 HANDLE searchHandle = ::FindFirstFileA(path, &findData);
  6848.                 if(searchHandle != INVALID_HANDLE_VALUE) {
  6849.                     result = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0;
  6850.                     ::FindClose(searchHandle);
  6851.                 }
  6852.             }
  6853.             return(result);
  6854.         }
  6855.  
  6856.         fpl_platform_api bool CreateDirectories(const char *path) {
  6857.             if(path == nullptr) {
  6858.                 common::ArgumentNullError("Path");
  6859.                 return false;
  6860.             }
  6861.             bool result = ::CreateDirectoryA(path, nullptr) > 0;
  6862.             return(result);
  6863.         }
  6864.         fpl_platform_api bool RemoveEmptyDirectory(const char *path) {
  6865.             if(path == nullptr) {
  6866.                 common::ArgumentNullError("Path");
  6867.                 return false;
  6868.             }
  6869.             bool result = ::RemoveDirectoryA(path) > 0;
  6870.             return(result);
  6871.         }
  6872.         fpl_internal_inline void Win32FillFileEntry(const WIN32_FIND_DATAA &findData, FileEntry &entry) {
  6873.             strings::CopyAnsiString(findData.cFileName, strings::GetAnsiStringLength(findData.cFileName), entry.path, FPL_ARRAYCOUNT(entry.path));
  6874.  
  6875.             entry.type = FileEntryType::Unknown;
  6876.             if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  6877.                 entry.type = FileEntryType::Directory;
  6878.             } else if(
  6879.                 (findData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
  6880.                 (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
  6881.                 (findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ||
  6882.                 (findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ||
  6883.                 (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) {
  6884.                 entry.type = FileEntryType::File;
  6885.             }
  6886.  
  6887.             entry.attributes = FileAttributeFlags::None;
  6888.             if(findData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) {
  6889.                 entry.attributes = FileAttributeFlags::Normal;
  6890.             } else {
  6891.                 if(findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
  6892.                     entry.attributes |= FileAttributeFlags::Hidden;
  6893.                 }
  6894.                 if(findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  6895.                     entry.attributes |= FileAttributeFlags::ReadOnly;
  6896.                 }
  6897.                 if(findData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) {
  6898.                     entry.attributes |= FileAttributeFlags::Archive;
  6899.                 }
  6900.                 if(findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
  6901.                     entry.attributes |= FileAttributeFlags::System;
  6902.                 }
  6903.             }
  6904.         }
  6905.         fpl_platform_api bool ListFilesBegin(const char *pathAndFilter, FileEntry &firstEntry) {
  6906.             if(pathAndFilter == nullptr) {
  6907.                 return false;
  6908.             }
  6909.             bool result = false;
  6910.             WIN32_FIND_DATAA findData;
  6911.             HANDLE searchHandle = ::FindFirstFileA(pathAndFilter, &findData);
  6912.             if(searchHandle != INVALID_HANDLE_VALUE) {
  6913.                 firstEntry = {};
  6914.                 firstEntry.internalHandle.win32FileHandle = searchHandle;
  6915.                 Win32FillFileEntry(findData, firstEntry);
  6916.                 result = true;
  6917.             }
  6918.             return(result);
  6919.         }
  6920.         fpl_platform_api bool ListFilesNext(FileEntry &nextEntry) {
  6921.             bool result = false;
  6922.             if(nextEntry.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6923.                 HANDLE searchHandle = nextEntry.internalHandle.win32FileHandle;
  6924.                 WIN32_FIND_DATAA findData;
  6925.                 if(::FindNextFileA(searchHandle, &findData)) {
  6926.                     Win32FillFileEntry(findData, nextEntry);
  6927.                     result = true;
  6928.                 }
  6929.             }
  6930.             return(result);
  6931.         }
  6932.         fpl_platform_api void ListFilesEnd(FileEntry &lastEntry) {
  6933.             if(lastEntry.internalHandle.win32FileHandle != INVALID_HANDLE_VALUE) {
  6934.                 HANDLE searchHandle = lastEntry.internalHandle.win32FileHandle;
  6935.                 ::FindClose(searchHandle);
  6936.                 lastEntry = {};
  6937.             }
  6938.         }
  6939.     } // files
  6940.  
  6941.     //
  6942.     // Win32 Path/Directories
  6943.     //
  6944.     namespace paths {
  6945. #   if defined(UNICODE)
  6946.         fpl_platform_api char *GetExecutableFilePath(char *destPath, const uint32_t maxDestLen) {
  6947.             if(destPath == nullptr) {
  6948.                 common::ArgumentNullError("Dest path");
  6949.                 return nullptr;
  6950.             }
  6951.             size_t requiredMaxDestLen = MAX_PATH + 1;
  6952.             if(maxDestLen < requiredMaxDestLen) {
  6953.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredMaxDestLen);
  6954.                 return nullptr;
  6955.             }
  6956.             wchar_t modulePath[MAX_PATH];
  6957.             ::GetModuleFileNameW(nullptr, modulePath, MAX_PATH);
  6958.             strings::WideStringToAnsiString(modulePath, strings::GetWideStringLength(modulePath), destPath, maxDestLen);
  6959.             return(destPath);
  6960.         }
  6961. #   else
  6962.         fpl_platform_api char *GetExecutableFilePath(char *destPath, const uint32_t maxDestLen) {
  6963.             if(destPath == nullptr) {
  6964.                 common::ArgumentNullError("Dest path");
  6965.                 return nullptr;
  6966.             }
  6967.             size_t requiredMaxDestLen = MAX_PATH + 1;
  6968.             if(maxDestLen < requiredMaxDestLen) {
  6969.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredMaxDestLen);
  6970.                 return nullptr;
  6971.             }
  6972.             char modulePath[MAX_PATH];
  6973.             ::GetModuleFileNameA(nullptr, modulePath, MAX_PATH);
  6974.             strings::CopyAnsiString(modulePath, strings::GetAnsiStringLength(modulePath), destPath, maxDestLen);
  6975.             return(destPath);
  6976.         }
  6977. #   endif // UNICODE
  6978.  
  6979. #   if defined(UNICODE)
  6980.         fpl_platform_api char *GetHomePath(char *destPath, const uint32_t maxDestLen) {
  6981.             if(destPath == nullptr) {
  6982.                 common::ArgumentNullError("Dest path");
  6983.                 return nullptr;
  6984.             }
  6985.             size_t requiredMaxDestLen = MAX_PATH + 1;
  6986.             if(maxDestLen < requiredMaxDestLen) {
  6987.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredMaxDestLen);
  6988.                 return nullptr;
  6989.             }
  6990.             if(platform::global__AppState == nullptr) {
  6991.                 common::PushError("Platform is not initialized");
  6992.                 return nullptr;
  6993.             }
  6994.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  6995.             wchar_t homePath[MAX_PATH];
  6996.             wapi.shell.shGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, 0, homePath);
  6997.             strings::WideStringToAnsiString(homePath, strings::GetWideStringLength(homePath), destPath, maxDestLen);
  6998.             return(destPath);
  6999.         }
  7000. #   else
  7001.         fpl_platform_api char *GetHomePath(char *destPath, const uint32_t maxDestLen) {
  7002.             if(destPath == nullptr) {
  7003.                 common::ArgumentNullError("Dest path");
  7004.                 return nullptr;
  7005.             }
  7006.             size_t requiredMaxDestLen = MAX_PATH + 1;
  7007.             if(maxDestLen < requiredMaxDestLen) {
  7008.                 common::ArgumentSizeTooSmallError("Max dest len", maxDestLen, requiredMaxDestLen);
  7009.                 return nullptr;
  7010.             }
  7011.             if(platform::global__AppState == nullptr) {
  7012.                 common::PushError("Platform is not initialized");
  7013.                 return nullptr;
  7014.             }
  7015.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  7016.             char homePath[MAX_PATH];
  7017.             wapi.shell.shGetFolderPathA(nullptr, CSIDL_PROFILE, nullptr, 0, homePath);
  7018.             strings::CopyAnsiString(homePath, strings::GetAnsiStringLength(homePath), destPath, maxDestLen);
  7019.             return(destPath);
  7020.         }
  7021. #   endif // UNICODE
  7022.     } // paths
  7023.  
  7024.     //
  7025.     // Win32 Timings
  7026.     //
  7027.     namespace timings {
  7028.         fpl_platform_api double GetHighResolutionTimeInSeconds() {
  7029.             const platform_win32::Win32InitState &initState = platform::global__InitState.win32;
  7030.             LARGE_INTEGER time;
  7031.             ::QueryPerformanceCounter(&time);
  7032.             double result = time.QuadPart / (double)initState.performanceFrequency.QuadPart;
  7033.             return(result);
  7034.         }
  7035.  
  7036.         fpl_platform_api uint64_t GetTimeInMilliseconds() {
  7037.             uint64_t result = ::GetTickCount();
  7038.             return(result);
  7039.         }
  7040.     } // timings
  7041.  
  7042.     //
  7043.     // Win32 Strings
  7044.     //
  7045.     namespace strings {
  7046.         fpl_platform_api char *WideStringToAnsiString(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *ansiDest, const uint32_t maxAnsiDestLen) {
  7047.             if(wideSource == nullptr) {
  7048.                 common::ArgumentNullError("Wide source");
  7049.                 return nullptr;
  7050.             }
  7051.             if(ansiDest == nullptr) {
  7052.                 common::ArgumentNullError("Ansi dest");
  7053.                 return nullptr;
  7054.             }
  7055.             uint32_t requiredLen = ::WideCharToMultiByte(CP_ACP, 0, wideSource, maxWideSourceLen, nullptr, 0, nullptr, nullptr);
  7056.             size_t minRequiredLen = requiredLen + 1;
  7057.             if(maxAnsiDestLen < minRequiredLen) {
  7058.                 common::ArgumentSizeTooSmallError("Max ansi dest len", maxAnsiDestLen, minRequiredLen);
  7059.                 return nullptr;
  7060.             }
  7061.             ::WideCharToMultiByte(CP_ACP, 0, wideSource, maxWideSourceLen, ansiDest, maxAnsiDestLen, nullptr, nullptr);
  7062.             ansiDest[requiredLen] = 0;
  7063.             return(ansiDest);
  7064.         }
  7065.         fpl_platform_api char *WideStringToUTF8String(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *utf8Dest, const uint32_t maxUtf8DestLen) {
  7066.             if(wideSource == nullptr) {
  7067.                 common::ArgumentNullError("Wide source");
  7068.                 return nullptr;
  7069.             }
  7070.             if(utf8Dest == nullptr) {
  7071.                 common::ArgumentNullError("UTF8 dest");
  7072.                 return nullptr;
  7073.             }
  7074.             uint32_t requiredLen = ::WideCharToMultiByte(CP_UTF8, 0, wideSource, maxWideSourceLen, nullptr, 0, nullptr, nullptr);
  7075.             uint32_t minRequiredLen = requiredLen + 1;
  7076.             if(maxUtf8DestLen < minRequiredLen) {
  7077.                 common::ArgumentSizeTooSmallError("Max utf8 dest len", maxUtf8DestLen, minRequiredLen);
  7078.                 return nullptr;
  7079.             }
  7080.             ::WideCharToMultiByte(CP_UTF8, 0, wideSource, maxWideSourceLen, utf8Dest, maxUtf8DestLen, nullptr, nullptr);
  7081.             utf8Dest[requiredLen] = 0;
  7082.             return(utf8Dest);
  7083.         }
  7084.         fpl_platform_api wchar_t *AnsiStringToWideString(const char *ansiSource, const uint32_t ansiSourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen) {
  7085.             if(ansiSource == nullptr) {
  7086.                 common::ArgumentNullError("Ansi source");
  7087.                 return nullptr;
  7088.             }
  7089.             if(wideDest == nullptr) {
  7090.                 common::ArgumentNullError("Wide dest");
  7091.                 return nullptr;
  7092.             }
  7093.             uint32_t requiredLen = ::MultiByteToWideChar(CP_ACP, 0, ansiSource, ansiSourceLen, nullptr, 0);
  7094.             uint32_t minRequiredLen = requiredLen + 1;
  7095.             if(maxWideDestLen < minRequiredLen) {
  7096.                 common::ArgumentSizeTooSmallError("Max wide dest len", maxWideDestLen, minRequiredLen);
  7097.                 return nullptr;
  7098.             }
  7099.             ::MultiByteToWideChar(CP_ACP, 0, ansiSource, ansiSourceLen, wideDest, maxWideDestLen);
  7100.             wideDest[requiredLen] = 0;
  7101.             return(wideDest);
  7102.         }
  7103.         fpl_platform_api wchar_t *UTF8StringToWideString(const char *utf8Source, const uint32_t utf8SourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen) {
  7104.             if(utf8Source == nullptr) {
  7105.                 common::ArgumentNullError("UTF8 source");
  7106.                 return nullptr;
  7107.             }
  7108.             if(wideDest == nullptr) {
  7109.                 common::ArgumentNullError("Wide dest");
  7110.                 return nullptr;
  7111.             }
  7112.             uint32_t requiredLen = ::MultiByteToWideChar(CP_UTF8, 0, utf8Source, utf8SourceLen, nullptr, 0);
  7113.             uint32_t minRequiredLen = requiredLen + 1;
  7114.             if(maxWideDestLen < minRequiredLen) {
  7115.                 common::ArgumentSizeTooSmallError("Max wide dest len", maxWideDestLen, minRequiredLen);
  7116.                 return nullptr;
  7117.             }
  7118.             ::MultiByteToWideChar(CP_UTF8, 0, utf8Source, utf8SourceLen, wideDest, maxWideDestLen);
  7119.             wideDest[requiredLen] = 0;
  7120.             return(wideDest);
  7121.         }
  7122.         fpl_platform_api char *FormatAnsiString(char *ansiDestBuffer, const uint32_t maxAnsiDestBufferLen, const char *format, ...) {
  7123.             if(ansiDestBuffer == nullptr) {
  7124.                 common::ArgumentNullError("Ansi dest buffer");
  7125.                 return nullptr;
  7126.             }
  7127.             if(maxAnsiDestBufferLen == 0) {
  7128.                 common::ArgumentZeroError("Max ansi dest len");
  7129.                 return nullptr;
  7130.             }
  7131.             if(format == nullptr) {
  7132.                 common::ArgumentNullError("Format");
  7133.                 return nullptr;
  7134.             }
  7135.             va_list argList;
  7136.             va_start(argList, format);
  7137.             // @NOTE(final): Need to clear the first character, otherwise vsnprintf() does weird things... O_o
  7138.             ansiDestBuffer[0] = 0;
  7139.             int charCount = ::vsnprintf(ansiDestBuffer, maxAnsiDestBufferLen, format, argList);
  7140.             if(charCount < 0) {
  7141.                 common::PushError("Format parameter are '%s' are invalid!", format);
  7142.                 return nullptr;
  7143.             }
  7144.             uint32_t requiredMaxAnsiDestBufferLen = charCount + 1;
  7145.             if((int)maxAnsiDestBufferLen < requiredMaxAnsiDestBufferLen) {
  7146.                 common::ArgumentSizeTooSmallError("Max ansi dest len", maxAnsiDestBufferLen, requiredMaxAnsiDestBufferLen);
  7147.                 return nullptr;
  7148.             }
  7149.             va_end(argList);
  7150.             FPL_ASSERT(charCount > 0);
  7151.             ansiDestBuffer[charCount] = 0;
  7152.             char *result = ansiDestBuffer;
  7153.             return(result);
  7154.         }
  7155.     } // strings
  7156.  
  7157.     //
  7158.     // Win32 Library
  7159.     //
  7160.     namespace library {
  7161.         fpl_platform_api DynamicLibraryHandle DynamicLibraryLoad(const char *libraryFilePath) {
  7162.             DynamicLibraryHandle result = {};
  7163.             if(libraryFilePath != nullptr) {
  7164.                 HMODULE libModule = ::LoadLibraryA(libraryFilePath);
  7165.                 if(libModule != nullptr) {
  7166.                     result.internalHandle.win32LibraryHandle = libModule;
  7167.                     result.isValid = true;
  7168.                 }
  7169.             }
  7170.             return(result);
  7171.         }
  7172.         fpl_platform_api void *GetDynamicLibraryProc(const DynamicLibraryHandle &handle, const char *name) {
  7173.             void *result = nullptr;
  7174.             if(handle.internalHandle.win32LibraryHandle != nullptr && name != nullptr) {
  7175.                 HMODULE libModule = handle.internalHandle.win32LibraryHandle;
  7176.                 result = (void *)::GetProcAddress(libModule, name);
  7177.             }
  7178.             return(result);
  7179.         }
  7180.         fpl_platform_api void DynamicLibraryUnload(DynamicLibraryHandle &handle) {
  7181.             if(handle.internalHandle.win32LibraryHandle != nullptr) {
  7182.                 HMODULE libModule = (HMODULE)handle.internalHandle.win32LibraryHandle;
  7183.                 ::FreeLibrary(libModule);
  7184.                 handle = {};
  7185.             }
  7186.         }
  7187.     } // library
  7188.  
  7189. #if defined(FPL_ENABLE_WINDOW)
  7190.     //
  7191.     // Win32 Window
  7192.     //
  7193.     namespace window {
  7194.         fpl_platform_api WindowSize GetWindowArea() {
  7195.             FPL_ASSERT(platform::global__AppState != nullptr);
  7196.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7197.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7198.             const platform_win32::Win32Api &wapi = appState.winApi;
  7199.             WindowSize result = {};
  7200.             RECT windowRect;
  7201.             if(wapi.user.getClientRect(windowState.windowHandle, &windowRect)) {
  7202.                 result.width = windowRect.right - windowRect.left;
  7203.                 result.height = windowRect.bottom - windowRect.top;
  7204.             }
  7205.             return(result);
  7206.         }
  7207.  
  7208.         fpl_platform_api void SetWindowArea(const uint32_t width, const uint32_t height) {
  7209.             FPL_ASSERT(platform::global__AppState != nullptr);
  7210.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7211.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7212.             const platform_win32::Win32Api &wapi = appState.winApi;
  7213.             RECT clientRect, windowRect;
  7214.             if(wapi.user.getClientRect(windowState.windowHandle, &clientRect) &&
  7215.                wapi.user.getWindowRect(windowState.windowHandle, &windowRect)) {
  7216.                 int borderWidth = (windowRect.right - windowRect.left) - (clientRect.right - clientRect.left);
  7217.                 int borderHeight = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
  7218.                 int newWidth = width + borderWidth;
  7219.                 int newHeight = height + borderHeight;
  7220.                 wapi.user.setWindowPos(windowState.windowHandle, 0, 0, 0, newWidth, newHeight, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  7221.             }
  7222.         }
  7223.  
  7224.         fpl_platform_api bool IsWindowResizable() {
  7225.             FPL_ASSERT(platform::global__AppState != nullptr);
  7226.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7227.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7228.             DWORD style = win32_getWindowLong(windowState.windowHandle, GWL_STYLE);
  7229.             bool result = (style & WS_THICKFRAME) > 0;
  7230.             return(result);
  7231.         }
  7232.  
  7233.         fpl_platform_api void SetWindowResizeable(const bool value) {
  7234.             FPL_ASSERT(platform::global__AppState != nullptr);
  7235.             platform::PlatformAppState *appState = platform::global__AppState;
  7236.             const platform_win32::Win32WindowState &windowState = appState->window.win32;
  7237.             const platform_win32::Win32AppState &win32State = appState->win32;
  7238.             if(!appState->currentSettings.window.isFullscreen) {
  7239.                 DWORD style;
  7240.                 DWORD exStyle;
  7241.                 if(value) {
  7242.                     style = platform_win32::Win32ResizeableWindowStyle;
  7243.                     exStyle = platform_win32::Win32ResizeableWindowExtendedStyle;
  7244.                 } else {
  7245.                     style = platform_win32::Win32NonResizableWindowStyle;
  7246.                     exStyle = platform_win32::Win32NonResizableWindowExtendedStyle;
  7247.                 }
  7248.                 win32_setWindowLong(windowState.windowHandle, GWL_STYLE, style);
  7249.                 win32_setWindowLong(windowState.windowHandle, GWL_EXSTYLE, exStyle);
  7250.                 appState->currentSettings.window.isResizable = value;
  7251.             }
  7252.         }
  7253.  
  7254.         fpl_platform_api bool IsWindowFullscreen() {
  7255.             FPL_ASSERT(platform::global__AppState != nullptr);
  7256.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7257.             HWND windowHandle = windowState.windowHandle;
  7258.             DWORD style = win32_getWindowLong(windowHandle, GWL_STYLE);
  7259.             bool result = (style & platform_win32::Win32FullscreenWindowStyle) > 0;
  7260.             return(result);
  7261.         }
  7262.  
  7263.         fpl_platform_api bool SetWindowFullscreen(const bool value, const uint32_t fullscreenWidth, const uint32_t fullscreenHeight, const uint32_t refreshRate) {
  7264.             FPL_ASSERT(platform::global__AppState != nullptr);
  7265.             platform::PlatformAppState *appState = platform::global__AppState;
  7266.             platform_win32::Win32AppState &win32AppState = appState->win32;
  7267.             platform_win32::Win32WindowState &windowState = appState->window.win32;
  7268.             WindowSettings &windowSettings = appState->currentSettings.window;
  7269.             platform_win32::Win32LastWindowInfo &fullscreenState = windowState.lastFullscreenInfo;
  7270.             const platform_win32::Win32Api &wapi = win32AppState.winApi;
  7271.  
  7272.             HWND windowHandle = windowState.windowHandle;
  7273.  
  7274.             // Save current window info if not already fullscreen
  7275.             if(!windowSettings.isFullscreen) {
  7276.                 fullscreenState.isMaximized = !!wapi.user.isZoomed(windowHandle);
  7277.                 if(fullscreenState.isMaximized) {
  7278.                     win32_sendMessage(windowHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
  7279.                 }
  7280.                 fullscreenState.style = win32_getWindowLong(windowHandle, GWL_STYLE);
  7281.                 fullscreenState.exStyle = win32_getWindowLong(windowHandle, GWL_EXSTYLE);
  7282.                 wapi.user.getWindowPlacement(windowHandle, &fullscreenState.placement);
  7283.             }
  7284.  
  7285.             if(value) {
  7286.                 // Enter fullscreen mode or fallback to window mode
  7287.                 windowSettings.isFullscreen = platform_win32::Win32EnterFullscreen(fullscreenWidth, fullscreenHeight, refreshRate, 0);
  7288.                 if(!windowSettings.isFullscreen) {
  7289.                     platform_win32::Win32LeaveFullscreen();
  7290.                 }
  7291.             } else {
  7292.                 platform_win32::Win32LeaveFullscreen();
  7293.                 windowSettings.isFullscreen = false;
  7294.             }
  7295.             return(windowSettings.isFullscreen);
  7296.         }
  7297.  
  7298.         fpl_platform_api WindowPosition GetWindowPosition() {
  7299.             FPL_ASSERT(platform::global__AppState != nullptr);
  7300.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7301.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7302.             const platform_win32::Win32Api &wapi = appState.winApi;
  7303.  
  7304.             WindowPosition result = {};
  7305.             WINDOWPLACEMENT placement = {};
  7306.             placement.length = sizeof(WINDOWPLACEMENT);
  7307.             if(wapi.user.getWindowPlacement(windowState.windowHandle, &placement) == TRUE) {
  7308.                 switch(placement.showCmd) {
  7309.                     case SW_MAXIMIZE:
  7310.                     {
  7311.                         result.left = placement.ptMaxPosition.x;
  7312.                         result.top = placement.ptMaxPosition.y;
  7313.                     } break;
  7314.                     case SW_MINIMIZE:
  7315.                     {
  7316.                         result.left = placement.ptMinPosition.x;
  7317.                         result.top = placement.ptMinPosition.y;
  7318.                     } break;
  7319.                     default:
  7320.                     {
  7321.                         result.left = placement.rcNormalPosition.left;
  7322.                         result.top = placement.rcNormalPosition.top;
  7323.                     } break;
  7324.                 }
  7325.             }
  7326.             return(result);
  7327.         }
  7328.  
  7329.         fpl_platform_api void SetWindowTitle(const char *title) {
  7330.             FPL_ASSERT(platform::global__AppState != nullptr);
  7331.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7332.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7333.             const platform_win32::Win32Api &wapi = appState.winApi;
  7334.  
  7335.             // @TODO(final): Add function for setting the unicode window title!
  7336.             HWND handle = windowState.windowHandle;
  7337.             wapi.user.setWindowTextA(handle, title);
  7338.         }
  7339.  
  7340.         fpl_platform_api void SetWindowPosition(const int32_t left, const int32_t top) {
  7341.             FPL_ASSERT(platform::global__AppState != nullptr);
  7342.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7343.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7344.             const platform_win32::Win32Api &wapi = appState.winApi;
  7345.  
  7346.             WINDOWPLACEMENT placement = {};
  7347.             placement.length = sizeof(WINDOWPLACEMENT);
  7348.             RECT windowRect;
  7349.             if(wapi.user.getWindowPlacement(windowState.windowHandle, &placement) &&
  7350.                wapi.user.getWindowRect(windowState.windowHandle, &windowRect)) {
  7351.                 switch(placement.showCmd) {
  7352.                     case SW_NORMAL:
  7353.                     case SW_SHOW:
  7354.                     {
  7355.                         placement.rcNormalPosition.left = left;
  7356.                         placement.rcNormalPosition.top = top;
  7357.                         placement.rcNormalPosition.right = placement.rcNormalPosition.left + (windowRect.right - windowRect.left);
  7358.                         placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + (windowRect.bottom - windowRect.top);
  7359.                         wapi.user.setWindowPlacement(windowState.windowHandle, &placement);
  7360.                     } break;
  7361.                 }
  7362.             }
  7363.         }
  7364.  
  7365.         fpl_platform_api void SetWindowCursorEnabled(const bool value) {
  7366.             FPL_ASSERT(platform::global__AppState != nullptr);
  7367.             platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7368.             windowState.isCursorActive = value;
  7369.         }
  7370.  
  7371.         fpl_platform_api bool PushWindowEvent() {
  7372.             FPL_ASSERT(platform::global__AppState != nullptr);
  7373.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  7374.             bool result = false;
  7375.             MSG msg;
  7376.             BOOL R = win32_peekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
  7377.             if(R == TRUE) {
  7378.                 wapi.user.translateMessage(&msg);
  7379.                 win32_dispatchMessage(&msg);
  7380.                 result = true;
  7381.             }
  7382.             return (result);
  7383.         }
  7384.  
  7385.         fpl_platform_api void UpdateGameControllers() {
  7386.             FPL_ASSERT(platform::global__AppState != nullptr);
  7387.             platform::PlatformAppState *appState = platform::global__AppState;
  7388.             platform_win32::Win32AppState &win32AppState = appState->win32;
  7389.             const platform_win32::Win32InitState &win32InitState = platform::global__InitState.win32;
  7390.             platform_win32::Win32PollControllers(appState->currentSettings, win32InitState, win32AppState.xinput);
  7391.         }
  7392.  
  7393.         fpl_platform_api bool WindowUpdate() {
  7394.             FPL_ASSERT(platform::global__AppState != nullptr);
  7395.             platform::PlatformAppState *appState = platform::global__AppState;
  7396.             platform_win32::Win32AppState &win32AppState = appState->win32;
  7397.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7398.             const platform_win32::Win32InitState &win32InitState = platform::global__InitState.win32;
  7399.             const platform_win32::Win32Api &wapi = win32AppState.winApi;
  7400.  
  7401.             bool result = false;
  7402.  
  7403.             // Poll gamepad controller states
  7404.             platform_win32::Win32PollControllers(appState->currentSettings, win32InitState, win32AppState.xinput);
  7405.  
  7406.             // Poll window events
  7407.             if(windowState.windowHandle != 0) {
  7408.                 MSG msg;
  7409.                 while(win32_peekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != 0) {
  7410.                     wapi.user.translateMessage(&msg);
  7411.                     win32_dispatchMessage(&msg);
  7412.                 }
  7413.                 result = windowState.isRunning;
  7414.             }
  7415.  
  7416.             return(result);
  7417.         }
  7418.  
  7419.         fpl_platform_api bool IsWindowRunning() {
  7420.             FPL_ASSERT(platform::global__AppState != nullptr);
  7421.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7422.             bool result = windowState.isRunning;
  7423.             return(result);
  7424.         }
  7425.  
  7426.         fpl_platform_api char *GetClipboardAnsiText(char *dest, const uint32_t maxDestLen) {
  7427.             FPL_ASSERT(platform::global__AppState != nullptr);
  7428.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7429.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7430.             const platform_win32::Win32Api &wapi = appState.winApi;
  7431.             char *result = nullptr;
  7432.             if(wapi.user.openClipboard(windowState.windowHandle)) {
  7433.                 if(wapi.user.isClipboardFormatAvailable(CF_TEXT)) {
  7434.                     HGLOBAL dataHandle = wapi.user.getClipboardData(CF_TEXT);
  7435.                     if(dataHandle != nullptr) {
  7436.                         const char *stringValue = (const char *)GlobalLock(dataHandle);
  7437.                         result = strings::CopyAnsiString(stringValue, dest, maxDestLen);
  7438.                         GlobalUnlock(dataHandle);
  7439.                     }
  7440.                 }
  7441.                 wapi.user.closeClipboard();
  7442.             }
  7443.             return(result);
  7444.         }
  7445.  
  7446.         fpl_platform_api wchar_t *GetClipboardWideText(wchar_t *dest, const uint32_t maxDestLen) {
  7447.             FPL_ASSERT(platform::global__AppState != nullptr);
  7448.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7449.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7450.             const platform_win32::Win32Api &wapi = appState.winApi;
  7451.             wchar_t *result = nullptr;
  7452.             if(wapi.user.openClipboard(windowState.windowHandle)) {
  7453.                 if(wapi.user.isClipboardFormatAvailable(CF_UNICODETEXT)) {
  7454.                     HGLOBAL dataHandle = wapi.user.getClipboardData(CF_UNICODETEXT);
  7455.                     if(dataHandle != nullptr) {
  7456.                         const wchar_t *stringValue = (const wchar_t *)GlobalLock(dataHandle);
  7457.                         result = strings::CopyWideString(stringValue, dest, maxDestLen);
  7458.                         GlobalUnlock(dataHandle);
  7459.                     }
  7460.                 }
  7461.                 wapi.user.closeClipboard();
  7462.             }
  7463.             return(result);
  7464.         }
  7465.  
  7466.         fpl_platform_api bool SetClipboardText(const char *ansiSource) {
  7467.             FPL_ASSERT(platform::global__AppState != nullptr);
  7468.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7469.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7470.             const platform_win32::Win32Api &wapi = appState.winApi;
  7471.             bool result = false;
  7472.             if(wapi.user.openClipboard(windowState.windowHandle)) {
  7473.                 const uint32_t ansiLen = strings::GetAnsiStringLength(ansiSource);
  7474.                 const uint32_t ansiBufferLen = ansiLen + 1;
  7475.                 HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)ansiBufferLen * sizeof(char));
  7476.                 if(handle != nullptr) {
  7477.                     char *target = (char*)GlobalLock(handle);
  7478.                     strings::CopyAnsiString(ansiSource, ansiLen, target, ansiBufferLen);
  7479.                     GlobalUnlock(handle);
  7480.                     wapi.user.emptyClipboard();
  7481.                     wapi.user.setClipboardData(CF_TEXT, handle);
  7482.                     result = true;
  7483.                 }
  7484.                 wapi.user.closeClipboard();
  7485.             }
  7486.             return(result);
  7487.         }
  7488.  
  7489.         fpl_platform_api bool SetClipboardText(const wchar_t *wideSource) {
  7490.             FPL_ASSERT(platform::global__AppState != nullptr);
  7491.             const platform_win32::Win32AppState &appState = platform::global__AppState->win32;
  7492.             const platform_win32::Win32WindowState &windowState = platform::global__AppState->window.win32;
  7493.             const platform_win32::Win32Api &wapi = appState.winApi;
  7494.             bool result = false;
  7495.             if(wapi.user.openClipboard(windowState.windowHandle)) {
  7496.                 const uint32_t wideLen = strings::GetWideStringLength(wideSource);
  7497.                 const uint32_t wideBufferLen = wideLen + 1;
  7498.                 HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wideBufferLen * sizeof(wchar_t));
  7499.                 if(handle != nullptr) {
  7500.                     wchar_t *wideTarget = (wchar_t*)GlobalLock(handle);
  7501.                     strings::CopyWideString(wideSource, wideLen, wideTarget, wideBufferLen);
  7502.                     GlobalUnlock(handle);
  7503.                     wapi.user.emptyClipboard();
  7504.                     wapi.user.setClipboardData(CF_UNICODETEXT, handle);
  7505.                     result = true;
  7506.                 }
  7507.                 wapi.user.closeClipboard();
  7508.             }
  7509.             return(result);
  7510.         }
  7511.     } // window
  7512. #endif // FPL_ENABLE_WINDOW
  7513.  
  7514. } // fpl
  7515.  
  7516. #   if defined(FPL_ENABLE_WINDOW)
  7517.  
  7518. #           if defined(UNICODE)
  7519.  
  7520. int WINAPI wWinMain(HINSTANCE appInstance, HINSTANCE prevInstance, LPWSTR cmdLine, int cmdShow) {
  7521.     fpl::platform_win32::Win32CommandLineUTF8Arguments args = fpl::platform_win32::Win32ParseWideArguments(cmdLine);
  7522.     int result = main(args.count, args.args);
  7523.     fpl::memory::MemoryFree(args.mem);
  7524.     return(result);
  7525. }
  7526.  
  7527. #           else
  7528.  
  7529. int WINAPI WinMain(HINSTANCE appInstance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow) {
  7530.     fpl::platform_win32::Win32CommandLineUTF8Arguments args = fpl::platform_win32::Win32ParseAnsiArguments(cmdLine);
  7531.     int result = main(args.count, args.args);
  7532.     fpl::memory::MemoryFree(args.mem);
  7533.     return(result);
  7534. }
  7535. #           endif // UNICODE
  7536.  
  7537. #   endif // FPL_ENABLE_WINDOW
  7538.  
  7539. #endif // FPL_PLATFORM_WIN32
  7540.  
  7541. // ############################################################################
  7542. //
  7543. // > POSIX_SUBPLATFORM (Linux, Unix)
  7544. //
  7545. // ############################################################################
  7546. #if defined(FPL_SUBPLATFORM_POSIX)
  7547. namespace fpl {
  7548.     namespace subplatform_posix {
  7549.         fpl_internal void PosixReleaseSubplatform(PosixAppState &appState) {
  7550.             UnloadPThreadApi(appState.pthreadApi);
  7551.         }
  7552.  
  7553.         fpl_internal bool PosixInitSubplatform(const InitFlags initFlags, const Settings &initSettings, PosixInitState &initState, PosixAppState &appState) {
  7554.             if(!LoadPThreadApi(appState.pthreadApi)) {
  7555.                 common::PushError("Failed initializing PThread API");
  7556.                 return false;
  7557.             }
  7558.             return true;
  7559.         }
  7560.  
  7561.         void *PosixThreadProc(void *data) {
  7562.             threading::ThreadHandle *thread = (threading::ThreadHandle *)data;
  7563.             FPL_ASSERT(thread != nullptr);
  7564.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)threading::ThreadState::Running);
  7565.             if(thread->runFunc != nullptr) {
  7566.                 thread->runFunc(*thread, thread->data);
  7567.             }
  7568.             atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)threading::ThreadState::Stopped);
  7569.             pthread_exit(nullptr);
  7570.         }
  7571.  
  7572.         fpl_internal bool PosixMutexLock(const PThreadApi &pthreadAPI, pthread_mutex_t *handle) {
  7573.             int lockRes;
  7574.             do {
  7575.                 lockRes = pthreadAPI.pthread_mutex_lock(handle);
  7576.             } while(lockRes == EAGAIN);
  7577.             bool result = (lockRes == 0);
  7578.             return(result);
  7579.         }
  7580.  
  7581.         fpl_internal bool PosixMutexUnlock(const PThreadApi &pthreadAPI, pthread_mutex_t *handle) {
  7582.             int unlockRes;
  7583.             do {
  7584.                 unlockRes = pthreadAPI.pthread_mutex_unlock(handle);
  7585.             } while(unlockRes == EAGAIN);
  7586.             bool result = (unlockRes == 0);
  7587.             return(result);
  7588.         }
  7589.  
  7590.         fpl_internal int PosixMutexCreate(const PThreadApi &pthreadAPI, pthread_mutex_t *handle) {
  7591.             *handle = PTHREAD_MUTEX_INITIALIZER;
  7592.             int mutexRes;
  7593.             do {
  7594.                 mutexRes = pthreadAPI.pthread_mutex_init(handle, nullptr);
  7595.             } while(mutexRes == EAGAIN);
  7596.             return(mutexRes);
  7597.         }
  7598.  
  7599.         fpl_internal int PosixConditionCreate(const PThreadApi &pthreadAPI, pthread_cond_t *handle) {
  7600.             *handle = PTHREAD_COND_INITIALIZER;
  7601.             int condRes;
  7602.             do {
  7603.                 condRes = pthreadAPI.pthread_cond_init(handle, nullptr);
  7604.             } while(condRes == EAGAIN);
  7605.             return(condRes);
  7606.         }
  7607.  
  7608.         fpl_internal_inline timespec CreateWaitTimeSpec(const uint32_t milliseconds) {
  7609.             time_t secs = milliseconds / 1000;
  7610.             uint64_t nanoSecs = (milliseconds - (secs * 1000)) * 1000000;
  7611.             if(nanoSecs >= 1000000000) {
  7612.                 time_t addonSecs = (time_t)(nanoSecs / 1000000000);
  7613.                 nanoSecs -= (addonSecs * 1000000000);
  7614.                 secs += addonSecs;
  7615.             }
  7616.             timespec result;
  7617.             clock_gettime(CLOCK_REALTIME, &result);
  7618.             result.tv_sec += secs;
  7619.             result.tv_nsec += nanoSecs;
  7620.             return(result);
  7621.         }
  7622.  
  7623.         fpl_internal bool PosixThreadWaitForMultiple(threading::ThreadHandle *threads[], const uint32_t minCount, const uint32_t maxCount, const uint32_t maxMilliseconds) {
  7624.             if(threads == nullptr) {
  7625.                 common::ArgumentNullError("Threads");
  7626.                 return false;
  7627.             }
  7628.             if(maxCount > common::MAX_THREAD_COUNT) {
  7629.                 common::ArgumentSizeTooBigError("Max count", maxCount, common::MAX_THREAD_COUNT);
  7630.                 return false;
  7631.             }
  7632.             for(uint32_t index = 0; index < maxCount; ++index) {
  7633.                 threading::ThreadHandle *thread = threads[index];
  7634.                 if(thread == nullptr) {
  7635.                     common::PushError("Thread for index '%d' are not allowed to be null", index);
  7636.                     return false;
  7637.                 }
  7638.                 if(!thread->isValid) {
  7639.                     common::PushError("Thread for index '%d' is not valid", index);
  7640.                     return false;
  7641.                 }
  7642.             }
  7643.  
  7644.             volatile bool isRunning[fpl::common::MAX_THREAD_COUNT];
  7645.             for(uint32_t index = 0; index < maxCount; ++index) {
  7646.                 isRunning[index] = true;
  7647.             }
  7648.  
  7649.             volatile uint32_t completeCount = 0;
  7650.             volatile uint64_t startTime = timings::GetTimeInMilliseconds();
  7651.             bool result = false;
  7652.             while(completeCount < minCount) {
  7653.                 for(uint32_t index = 0; index < maxCount; ++index) {
  7654.                     threading::ThreadHandle *thread = threads[index];
  7655.                     if(isRunning[index]) {
  7656.                         threading::ThreadState state = threading::GetThreadState(thread);
  7657.                         if(state == threading::ThreadState::Stopped) {
  7658.                             isRunning[index] = false;
  7659.                             ++completeCount;
  7660.                             if(completeCount >= minCount) {
  7661.                                 result = true;
  7662.                                 break;
  7663.                             }
  7664.                         }
  7665.                     }
  7666.                     threading::ThreadSleep(10);
  7667.                 }
  7668.                 if((maxMilliseconds != UINT32_MAX) && (timings::GetTimeInMilliseconds() - startTime) >= maxMilliseconds) {
  7669.                     result = false;
  7670.                     break;
  7671.                 }
  7672.             }
  7673.             return(result);
  7674.         }
  7675.  
  7676.         fpl_internal bool PosixSignalWaitForMultiple(const PThreadApi &pthreadAPI, threading::MutexHandle &mutex, threading::SignalHandle *signals[], const uint32_t minCount, const uint32_t maxCount, const uint32_t maxMilliseconds, const uint32_t smallWaitDuration = 5) {
  7677.             if(signals == nullptr) {
  7678.                 common::ArgumentNullError("Signals");
  7679.                 return false;
  7680.             }
  7681.             if(maxCount > common::MAX_SIGNAL_COUNT) {
  7682.                 common::ArgumentSizeTooBigError("Max count", maxCount, common::MAX_SIGNAL_COUNT);
  7683.                 return false;
  7684.             }
  7685.             for(uint32_t index = 0; index < maxCount; ++index) {
  7686.                 threading::SignalHandle *signal = signals[index];
  7687.                 if(signal == nullptr) {
  7688.                     common::PushError("Signal for index '%d' are not allowed to be null", index);
  7689.                     return false;
  7690.                 }
  7691.                 if(!signal->isValid) {
  7692.                     common::PushError("Signal for index '%d' is not valid", index);
  7693.                     return false;
  7694.                 }
  7695.             }
  7696.  
  7697.             volatile bool isSignaled[fpl::common::MAX_SIGNAL_COUNT];
  7698.             for(uint32_t index = 0; index < maxCount; ++index) {
  7699.                 isSignaled[index] = false;
  7700.             }
  7701.  
  7702.  
  7703.             volatile uint32_t signaledCount = 0;
  7704.             volatile uint64_t startTime = timings::GetTimeInMilliseconds();
  7705.             bool result = false;
  7706.             while(signaledCount < minCount) {
  7707.                 for(uint32_t index = 0; index < maxCount; ++index) {
  7708.                     threading::SignalHandle *signal = signals[index];
  7709.                     if(!isSignaled[index]) {
  7710.                         timespec t = CreateWaitTimeSpec(smallWaitDuration);
  7711.                         int condRes = pthreadAPI.pthread_cond_timedwait(&signal->internalHandle.posixCondition, &mutex.internalHandle.posixMutex, &t);
  7712.                         if(condRes == 0) {
  7713.                             isSignaled[index] = true;
  7714.                             ++signaledCount;
  7715.                             if(signaledCount >= minCount) {
  7716.                                 result = true;
  7717.                                 break;
  7718.                             }
  7719.                         }
  7720.                     }
  7721.                 }
  7722.                 if((maxMilliseconds != UINT32_MAX) && (timings::GetTimeInMilliseconds() - startTime) >= maxMilliseconds) {
  7723.                     result = false;
  7724.                     break;
  7725.                 }
  7726.             }
  7727.             return(result);
  7728.         }
  7729.     } // subplatform_posix
  7730.  
  7731.     //
  7732.     // POSIX Atomics
  7733.     //
  7734.     namespace atomics {
  7735. #   if defined(FPL_COMPILER_GCC)
  7736.         // @NOTE(final): See: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins
  7737.         fpl_platform_api void AtomicReadFence() {
  7738.             // @TODO(final): Wrong to ensure a full memory fence here!
  7739.             __sync_synchronize();
  7740.         }
  7741.         fpl_platform_api void AtomicWriteFence() {
  7742.             // @TODO(final): Wrong to ensure a full memory fence here!
  7743.             __sync_synchronize();
  7744.         }
  7745.         fpl_platform_api void AtomicReadWriteFence() {
  7746.             __sync_synchronize();
  7747.         }
  7748.  
  7749.         fpl_platform_api uint32_t AtomicExchangeU32(volatile uint32_t *target, const uint32_t value) {
  7750.             uint32_t result = __sync_lock_test_and_set(target, value);
  7751.             __sync_synchronize();
  7752.             return(result);
  7753.         }
  7754.         fpl_platform_api int32_t AtomicExchangeS32(volatile int32_t *target, const int32_t value) {
  7755.             int32_t result = __sync_lock_test_and_set(target, value);
  7756.             __sync_synchronize();
  7757.             return(result);
  7758.         }
  7759.         fpl_platform_api uint64_t AtomicExchangeU64(volatile uint64_t *target, const uint64_t value) {
  7760.             uint64_t result = __sync_lock_test_and_set(target, value);
  7761.             __sync_synchronize();
  7762.             return(result);
  7763.         }
  7764.         fpl_platform_api int64_t AtomicExchangeS64(volatile int64_t *target, const int64_t value) {
  7765.             int64_t result = __sync_lock_test_and_set(target, value);
  7766.             __sync_synchronize();
  7767.             return(result);
  7768.         }
  7769.  
  7770.         fpl_platform_api uint32_t AtomicAddU32(volatile uint32_t *value, const uint32_t addend) {
  7771.             FPL_ASSERT(value != nullptr);
  7772.             uint32_t result = __sync_fetch_and_add(value, addend);
  7773.             return (result);
  7774.         }
  7775.         fpl_platform_api int32_t AtomicAddS32(volatile int32_t *value, const int32_t addend) {
  7776.             FPL_ASSERT(value != nullptr);
  7777.             uint32_t result = __sync_fetch_and_add(value, addend);
  7778.             return (result);
  7779.         }
  7780.         fpl_platform_api uint64_t AtomicAddU64(volatile uint64_t *value, const uint64_t addend) {
  7781.             FPL_ASSERT(value != nullptr);
  7782.             uint32_t result = __sync_fetch_and_add(value, addend);
  7783.             return (result);
  7784.         }
  7785.         fpl_platform_api int64_t AtomicAddS64(volatile int64_t *value, const int64_t addend) {
  7786.             FPL_ASSERT(value != nullptr);
  7787.             uint32_t result = __sync_fetch_and_add(value, addend);
  7788.             return (result);
  7789.         }
  7790.  
  7791.         fpl_platform_api uint32_t AtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
  7792.             FPL_ASSERT(dest != nullptr);
  7793.             uint32_t result = __sync_val_compare_and_swap(dest, comparand, exchange);
  7794.             return (result);
  7795.         }
  7796.         fpl_platform_api int32_t AtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
  7797.             FPL_ASSERT(dest != nullptr);
  7798.             int32_t result = __sync_val_compare_and_swap(dest, comparand, exchange);
  7799.             return (result);
  7800.         }
  7801.         fpl_platform_api uint64_t AtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
  7802.             FPL_ASSERT(dest != nullptr);
  7803.             uint64_t result = __sync_val_compare_and_swap(dest, comparand, exchange);
  7804.             return (result);
  7805.         }
  7806.         fpl_platform_api int64_t AtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
  7807.             FPL_ASSERT(dest != nullptr);
  7808.             int64_t result = __sync_val_compare_and_swap(dest, comparand, exchange);
  7809.             return (result);
  7810.         }
  7811.  
  7812.         fpl_platform_api bool IsAtomicCompareAndExchangeU32(volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
  7813.             FPL_ASSERT(dest != nullptr);
  7814.             bool result = __sync_bool_compare_and_swap(dest, comparand, exchange);
  7815.             return (result);
  7816.         }
  7817.         fpl_platform_api bool IsAtomicCompareAndExchangeS32(volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
  7818.             FPL_ASSERT(dest != nullptr);
  7819.             bool result = __sync_bool_compare_and_swap(dest, comparand, exchange);
  7820.             return (result);
  7821.         }
  7822.         fpl_platform_api bool IsAtomicCompareAndExchangeU64(volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
  7823.             FPL_ASSERT(dest != nullptr);
  7824.             bool result = __sync_bool_compare_and_swap(dest, comparand, exchange);
  7825.             return (result);
  7826.         }
  7827.         fpl_platform_api bool IsAtomicCompareAndExchangeS64(volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
  7828.             FPL_ASSERT(dest != nullptr);
  7829.             bool result = __sync_bool_compare_and_swap(dest, comparand, exchange);
  7830.             return (result);
  7831.         }
  7832.  
  7833.         fpl_platform_api uint32_t AtomicLoadU32(volatile uint32_t *source) {
  7834.             uint32_t result = __sync_fetch_and_or(source, 0);
  7835.             return(result);
  7836.         }
  7837.         fpl_platform_api uint64_t AtomicLoadU64(volatile uint64_t *source) {
  7838.             uint64_t result = __sync_fetch_and_or(source, 0);
  7839.             return(result);
  7840.         }
  7841.         fpl_platform_api int32_t AtomicLoadS32(volatile int32_t *source) {
  7842.             int32_t result = __sync_fetch_and_or(source, 0);
  7843.             return(result);
  7844.         }
  7845.         fpl_platform_api int64_t AtomicLoadS64(volatile int64_t *source) {
  7846.             int64_t result = __sync_fetch_and_or(source, 0);
  7847.             return(result);
  7848.         }
  7849.  
  7850.         fpl_platform_api void AtomicStoreU32(volatile uint32_t *dest, const uint32_t value) {
  7851.             __sync_lock_test_and_set(dest, value);
  7852.             __sync_synchronize();
  7853.         }
  7854.         fpl_platform_api void AtomicStoreU64(volatile uint64_t *dest, const uint64_t value) {
  7855.             __sync_lock_test_and_set(dest, value);
  7856.             __sync_synchronize();
  7857.         }
  7858.         fpl_platform_api void AtomicStoreS32(volatile int32_t *dest, const int32_t value) {
  7859.             __sync_lock_test_and_set(dest, value);
  7860.             __sync_synchronize();
  7861.         }
  7862.         fpl_platform_api void AtomicStoreS64(volatile int64_t *dest, const int64_t value) {
  7863.             __sync_lock_test_and_set(dest, value);
  7864.             __sync_synchronize();
  7865.         }
  7866. #   else
  7867. #       error "This POSIX compiler/platform is not supported!"
  7868. #   endif
  7869.     }
  7870.  
  7871.     //
  7872.     // POSIX Timings
  7873.     //
  7874.     namespace timings {
  7875.         fpl_platform_api double GetHighResolutionTimeInSeconds() {
  7876.             // @TODO(final): Do we need to take the performance frequency into account?
  7877.             timespec t;
  7878.             clock_gettime(CLOCK_MONOTONIC, &t);
  7879.             double result = (double)t.tv_sec + ((double)t.tv_nsec * 1e-9);
  7880.             return(result);
  7881.         }
  7882.  
  7883.         fpl_platform_api uint64_t GetTimeInMilliseconds() {
  7884.             // @TODO(final): Find a faster way to get the milliseconds
  7885.             timespec t;
  7886.             clock_gettime(CLOCK_MONOTONIC, &t);
  7887.             uint64_t result = t.tv_sec * 1000 + (uint64_t)(t.tv_nsec / 1.0e6);
  7888.             return(result);
  7889.         }
  7890.     }
  7891.  
  7892.     //
  7893.     // POSIX Threading
  7894.     //
  7895.     namespace threading {
  7896.         fpl_platform_api void ThreadDestroy(ThreadHandle *thread) {
  7897.             FPL_ASSERT(platform::global__AppState != nullptr);
  7898.             const platform::PlatformAppState *appState = platform::global__AppState;
  7899.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  7900.             FPL_ASSERT(pthreadAPI.libHandle != nullptr);
  7901.             if(thread != nullptr && thread->isValid) {
  7902.                 pthread_t threadHandle = thread->internalHandle.posix.thread;
  7903.                 pthread_mutex_t *mutexHandle = &thread->internalHandle.posix.mutex;
  7904.                 pthread_cond_t *condHandle = &thread->internalHandle.posix.stopCondition;
  7905.  
  7906.                 // If thread is not stopped yet, kill it and wait for termination
  7907.                 if(pthreadAPI.pthread_kill(threadHandle, 0) == 0) {
  7908.                     pthreadAPI.pthread_join(threadHandle, nullptr);
  7909.                 }
  7910.                 pthreadAPI.pthread_cond_destroy(condHandle);
  7911.                 pthreadAPI.pthread_mutex_destroy(mutexHandle);
  7912.                 atomics::AtomicStoreU32((volatile uint32_t *)&thread->currentState, (uint32_t)ThreadState::Stopped);
  7913.                 *thread = {};
  7914.             }
  7915.         }
  7916.  
  7917.         fpl_platform_api ThreadHandle *ThreadCreate(run_thread_function *runFunc, void *data) {
  7918.             FPL_ASSERT(platform::global__AppState != nullptr);
  7919.             const platform::PlatformAppState *appState = platform::global__AppState;
  7920.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  7921.             ThreadHandle *result = nullptr;
  7922.             ThreadHandle *thread = common::GetFreeThread();
  7923.             if(thread != nullptr) {
  7924.                 thread->currentState = ThreadState::Stopped;
  7925.                 thread->data = data;
  7926.                 thread->runFunc = runFunc;
  7927.                 thread->isValid = false;
  7928.                 thread->isStopping = false;
  7929.  
  7930.                 // Create mutex
  7931.                 int mutexRes = subplatform_posix::PosixMutexCreate(pthreadAPI, &thread->internalHandle.posix.mutex);
  7932.                 if(mutexRes != 0) {
  7933.                     common::PushError("Failed creating pthread mutex, error code: %d", mutexRes);
  7934.                 }
  7935.  
  7936.                 // Create stop condition
  7937.                 int condRes = -1;
  7938.                 if(mutexRes == 0) {
  7939.                     condRes = subplatform_posix::PosixConditionCreate(pthreadAPI, &thread->internalHandle.posix.stopCondition);
  7940.                     if(condRes != 0) {
  7941.                         common::PushError("Failed creating pthread condition, error code: %d", condRes);
  7942.                         pthreadAPI.pthread_mutex_destroy(&thread->internalHandle.posix.mutex);
  7943.                     }
  7944.                 }
  7945.  
  7946.                 // Create thread
  7947.                 int threadRes = -1;
  7948.                 if(condRes == 0) {
  7949.                     thread->isValid = true;
  7950.                     // @TODO(final): Better pthread id!
  7951.                     memory::MemoryCopy(&thread->internalHandle.posix.thread, FPL_MIN(sizeof(thread->id), sizeof(thread->internalHandle.posix.thread)), &thread->id);
  7952.                     do {
  7953.                         threadRes = pthreadAPI.pthread_create(&thread->internalHandle.posix.thread, nullptr, subplatform_posix::PosixThreadProc, (void *)thread);
  7954.                     } while(threadRes == EAGAIN);
  7955.                     if(threadRes != 0) {
  7956.                         common::PushError("Failed creating pthread, error code: %d", threadRes);
  7957.                         pthreadAPI.pthread_cond_destroy(&thread->internalHandle.posix.stopCondition);
  7958.                         pthreadAPI.pthread_mutex_destroy(&thread->internalHandle.posix.mutex);
  7959.                     }
  7960.                 }
  7961.  
  7962.                 if(threadRes == 0) {
  7963.                     result = thread;
  7964.                 } else {
  7965.                     *thread = {};
  7966.                 }
  7967.             } else {
  7968.                 common::PushError("All %d threads are in use, you cannot create until you free one", common::MAX_THREAD_COUNT);
  7969.             }
  7970.             return(result);
  7971.         }
  7972.  
  7973.         fpl_platform_api bool ThreadWaitForOne(ThreadHandle *thread, const uint32_t maxMilliseconds) {
  7974.             const platform::PlatformAppState *appState = platform::global__AppState;
  7975.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  7976.             FPL_ASSERT(pthreadAPI.libHandle != nullptr);
  7977.             bool result = false;
  7978.             if(thread != nullptr && thread->isValid) {
  7979.                 // Set a flag and signal indicating that this thread is being stopped
  7980.                 pthread_mutex_t *mutexHandle = &thread->internalHandle.posix.mutex;
  7981.                 pthread_cond_t *condHandle = &thread->internalHandle.posix.stopCondition;
  7982.                 if(subplatform_posix::PosixMutexLock(pthreadAPI, mutexHandle)) {
  7983.                     thread->isStopping = true;
  7984.                     pthreadAPI.pthread_cond_signal(condHandle);
  7985.                     pthreadAPI.pthread_cond_broadcast(condHandle);
  7986.                     subplatform_posix::PosixMutexUnlock(pthreadAPI, mutexHandle);
  7987.                 }
  7988.  
  7989.                 // Wait until it shuts down
  7990.                 pthread_t threadHandle = thread->internalHandle.posix.thread;
  7991.                 int joinRes = pthreadAPI.pthread_join(threadHandle, nullptr);
  7992.                 result = (joinRes == 0);
  7993.             }
  7994.             return (result);
  7995.         }
  7996.  
  7997.         fpl_platform_api bool ThreadWaitForAll(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds) {
  7998.             bool result = subplatform_posix::PosixThreadWaitForMultiple(threads, count, count, maxMilliseconds);
  7999.             return(result);
  8000.         }
  8001.  
  8002.         fpl_platform_api bool ThreadWaitForAny(ThreadHandle *threads[], const uint32_t count, const uint32_t maxMilliseconds) {
  8003.             bool result = subplatform_posix::PosixThreadWaitForMultiple(threads, 1, count, maxMilliseconds);
  8004.             return(result);
  8005.         }
  8006.  
  8007.         fpl_platform_api void ThreadSleep(const uint32_t milliseconds) {
  8008.             uint32_t ms;
  8009.             uint32_t s;
  8010.             if(milliseconds > 1000) {
  8011.                 s = milliseconds / 1000;
  8012.                 ms = milliseconds % 1000;
  8013.             } else {
  8014.                 s = 0;
  8015.                 ms = milliseconds;
  8016.             }
  8017.             timespec input, output;
  8018.             input.tv_sec = s;
  8019.             input.tv_nsec = ms * 1000000;
  8020.             nanosleep(&input, &output);
  8021.         }
  8022.  
  8023.         fpl_platform_api MutexHandle MutexCreate() {
  8024.             const platform::PlatformAppState *appState = platform::global__AppState;
  8025.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8026.             MutexHandle result = {};
  8027.             int mutexRes = subplatform_posix::PosixMutexCreate(pthreadAPI, &result.internalHandle.posixMutex);
  8028.             result.isValid = (mutexRes == 0);
  8029.             return(result);
  8030.         }
  8031.  
  8032.         fpl_platform_api void MutexDestroy(MutexHandle &mutex) {
  8033.             const platform::PlatformAppState *appState = platform::global__AppState;
  8034.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8035.             if(mutex.isValid) {
  8036.                 pthread_mutex_t *handle = &mutex.internalHandle.posixMutex;
  8037.                 pthreadAPI.pthread_mutex_destroy(handle);
  8038.             }
  8039.             mutex = {};
  8040.         }
  8041.  
  8042.         fpl_platform_api bool MutexLock(MutexHandle &mutex, const uint32_t maxMilliseconds) {
  8043.             const platform::PlatformAppState *appState = platform::global__AppState;
  8044.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8045.             bool result = false;
  8046.             if(mutex.isValid) {
  8047.                 pthread_mutex_t *handle = &mutex.internalHandle.posixMutex;
  8048.                 result = subplatform_posix::PosixMutexLock(pthreadAPI, handle);
  8049.             }
  8050.             return (result);
  8051.         }
  8052.  
  8053.         fpl_platform_api bool MutexUnlock(MutexHandle &mutex) {
  8054.             const platform::PlatformAppState *appState = platform::global__AppState;
  8055.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8056.             bool result = false;
  8057.             if(mutex.isValid) {
  8058.                 pthread_mutex_t *handle = &mutex.internalHandle.posixMutex;
  8059.                 result = subplatform_posix::PosixMutexUnlock(pthreadAPI, handle);
  8060.             }
  8061.             return (result);
  8062.         }
  8063.  
  8064.         fpl_platform_api SignalHandle SignalCreate() {
  8065.             const platform::PlatformAppState *appState = platform::global__AppState;
  8066.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8067.             SignalHandle result = {};
  8068.             int condRes = subplatform_posix::PosixConditionCreate(pthreadAPI, &result.internalHandle.posixCondition);
  8069.             result.isValid = (condRes == 0);
  8070.             return(result);
  8071.         }
  8072.  
  8073.         fpl_platform_api void SignalDestroy(SignalHandle &signal) {
  8074.             const platform::PlatformAppState *appState = platform::global__AppState;
  8075.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8076.             if(signal.isValid) {
  8077.                 pthread_cond_t *handle = &signal.internalHandle.posixCondition;
  8078.                 pthreadAPI.pthread_cond_destroy(handle);
  8079.             }
  8080.             signal = {};
  8081.         }
  8082.  
  8083.  
  8084.  
  8085.         fpl_platform_api bool SignalWaitForOne(MutexHandle &mutex, SignalHandle &signal, const uint32_t maxMilliseconds) {
  8086.             const platform::PlatformAppState *appState = platform::global__AppState;
  8087.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8088.             if(!signal.isValid) {
  8089.                 common::PushError("Signal is not valid");
  8090.                 return(false);
  8091.             }
  8092.             if(!mutex.isValid) {
  8093.                 common::PushError("Mutex is not valid");
  8094.                 return(false);
  8095.             }
  8096.             if(maxMilliseconds != UINT32_MAX) {
  8097.                 timespec t = subplatform_posix::CreateWaitTimeSpec(maxMilliseconds);
  8098.                 pthreadAPI.pthread_cond_timedwait(&signal.internalHandle.posixCondition, &mutex.internalHandle.posixMutex, &t);
  8099.             } else {
  8100.                 pthreadAPI.pthread_cond_wait(&signal.internalHandle.posixCondition, &mutex.internalHandle.posixMutex);
  8101.             }
  8102.             return(true);
  8103.         }
  8104.  
  8105.         fpl_platform_api bool SignalWaitForAll(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds) {
  8106.             const platform::PlatformAppState *appState = platform::global__AppState;
  8107.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8108.             bool result = subplatform_posix::PosixSignalWaitForMultiple(pthreadAPI, mutex, signals, count, count, maxMilliseconds);
  8109.             return(result);
  8110.         }
  8111.  
  8112.         fpl_platform_api bool SignalWaitForAny(MutexHandle &mutex, SignalHandle *signals[], const uint32_t count, const uint32_t maxMilliseconds) {
  8113.             const platform::PlatformAppState *appState = platform::global__AppState;
  8114.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8115.             bool result = subplatform_posix::PosixSignalWaitForMultiple(pthreadAPI, mutex, signals, 1, count, maxMilliseconds);
  8116.             return(result);
  8117.         }
  8118.  
  8119.         fpl_platform_api bool SignalSet(SignalHandle &signal) {
  8120.             const platform::PlatformAppState *appState = platform::global__AppState;
  8121.             const subplatform_posix::PThreadApi &pthreadAPI = appState->posix.pthreadApi;
  8122.             bool result = false;
  8123.             if(signal.isValid) {
  8124.                 pthread_cond_t *handle = &signal.internalHandle.posixCondition;
  8125.                 int condRes = pthreadAPI.pthread_cond_signal(handle);
  8126.                 pthreadAPI.pthread_cond_broadcast(handle);
  8127.                 result = (condRes == 0);
  8128.             }
  8129.             return(result);
  8130.         }
  8131.     }
  8132.  
  8133.     //
  8134.     // POSIX Library
  8135.     //
  8136.     namespace library {
  8137.         fpl_platform_api DynamicLibraryHandle DynamicLibraryLoad(const char *libraryFilePath) {
  8138.             DynamicLibraryHandle result = {};
  8139.             if(libraryFilePath != nullptr) {
  8140.                 void *p = ::dlopen(libraryFilePath, subplatform_posix::DL_LOADTYPE);
  8141.                 if(p != nullptr) {
  8142.                     result.internalHandle.posixLibraryHandle = p;
  8143.                     result.isValid = true;
  8144.                 }
  8145.             }
  8146.             return(result);
  8147.         }
  8148.  
  8149.         fpl_platform_api void *GetDynamicLibraryProc(const DynamicLibraryHandle &handle, const char *name) {
  8150.             void *result = nullptr;
  8151.             if(handle.internalHandle.posixLibraryHandle != nullptr && name != nullptr) {
  8152.                 void *p = handle.internalHandle.posixLibraryHandle;
  8153.                 result = ::dlsym(p, name);
  8154.             }
  8155.             return(result);
  8156.         }
  8157.  
  8158.         fpl_platform_api void DynamicLibraryUnload(DynamicLibraryHandle &handle) {
  8159.             if(handle.internalHandle.posixLibraryHandle != nullptr) {
  8160.                 void *p = handle.internalHandle.posixLibraryHandle;
  8161.                 ::dlclose(p);
  8162.                 handle = {};
  8163.             }
  8164.         }
  8165.     }
  8166.  
  8167.  
  8168.     //
  8169.     // POSIX Console
  8170.     //
  8171.     namespace console {
  8172.     }
  8173.  
  8174.     //
  8175.     // POSIX Memory
  8176.     //
  8177.     namespace memory {
  8178.         fpl_platform_api void *MemoryAllocate(const size_t size) {
  8179.             // @NOTE(final): MAP_ANONYMOUS ensures that the memory is cleared to zero.
  8180.  
  8181.             // Allocate empty memory to hold the size + some arbitary padding + the actual data
  8182.             size_t newSize = sizeof(size_t) + platform::SIZE_PADDING + size;
  8183.             void *basePtr = ::mmap(nullptr, newSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  8184.  
  8185.             // Write the size at the beginning
  8186.             *(size_t *)basePtr = newSize;
  8187.  
  8188.             // The resulting address starts after the arbitary padding
  8189.             void *result = (uint8_t *)basePtr + sizeof(size_t) + platform::SIZE_PADDING;
  8190.             return(result);
  8191.         }
  8192.  
  8193.         fpl_platform_api void MemoryFree(void *ptr) {
  8194.             // Free the base pointer which is stored to the left at the start of the size_t
  8195.             void *basePtr = (void *)((uint8_t *)ptr - (sizeof(uintptr_t) + sizeof(size_t)));
  8196.             size_t storedSize = *(size_t *)basePtr;
  8197.             ::munmap(basePtr, storedSize);
  8198.         }
  8199.     }
  8200.  
  8201.     //
  8202.     // POSIX Files
  8203.     //
  8204.     namespace files {
  8205.         fpl_platform_api FileHandle OpenBinaryFile(const char *filePath) {
  8206.             FileHandle result = {};
  8207.             if(filePath != nullptr) {
  8208.                 int posixFileHandle;
  8209.                 do {
  8210.                     posixFileHandle = ::open(filePath, O_RDONLY);
  8211.                 } while(posixFileHandle == -1 && errno == EINTR);
  8212.                 if(posixFileHandle != -1) {
  8213.                     result.isValid = true;
  8214.                     result.internalHandle.posixFileHandle = posixFileHandle;
  8215.                 }
  8216.             }
  8217.             return(result);
  8218.         }
  8219.         fpl_platform_api FileHandle OpenBinaryFile(const wchar_t *filePath) {
  8220.             FileHandle result = {};
  8221.             if(filePath != nullptr) {
  8222.                 char utf8FilePath[1024] = {};
  8223.                 strings::WideStringToAnsiString(filePath, strings::GetWideStringLength(filePath), utf8FilePath, FPL_ARRAYCOUNT(utf8FilePath));
  8224.                 result = OpenBinaryFile(utf8FilePath);
  8225.             }
  8226.             return(result);
  8227.         }
  8228.  
  8229.         fpl_platform_api FileHandle CreateBinaryFile(const char *filePath) {
  8230.             FileHandle result = {};
  8231.             if(filePath != nullptr) {
  8232.                 int posixFileHandle;
  8233.                 do {
  8234.                     posixFileHandle = ::open(filePath, O_WRONLY | O_CREAT | O_TRUNC);
  8235.                 } while(posixFileHandle == -1 && errno == EINTR);
  8236.                 if(posixFileHandle != -1) {
  8237.                     result.isValid = true;
  8238.                     result.internalHandle.posixFileHandle = posixFileHandle;
  8239.                 }
  8240.             }
  8241.             return(result);
  8242.         }
  8243.         fpl_platform_api FileHandle CreateBinaryFile(const wchar_t *filePath) {
  8244.             FileHandle result = {};
  8245.             if(filePath != nullptr) {
  8246.                 char utf8FilePath[1024] = {};
  8247.                 strings::WideStringToAnsiString(filePath, strings::GetWideStringLength(filePath), utf8FilePath, FPL_ARRAYCOUNT(utf8FilePath));
  8248.                 result = CreateBinaryFile(utf8FilePath);
  8249.             }
  8250.             return(result);
  8251.         }
  8252.  
  8253.         fpl_platform_api uint32_t ReadFileBlock32(const FileHandle &fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize) {
  8254.             if(sizeToRead == 0) {
  8255.                 return 0;
  8256.             }
  8257.             if(targetBuffer == nullptr) {
  8258.                 common::ArgumentNullError("Target buffer");
  8259.                 return 0;
  8260.             }
  8261.             if(!fileHandle.internalHandle.posixFileHandle) {
  8262.                 common::PushError("File handle is not opened for reading");
  8263.                 return 0;
  8264.             }
  8265.             int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8266.  
  8267.             ssize_t res;
  8268.             do {
  8269.                 res = ::read(posixFileHandle, targetBuffer, sizeToRead);
  8270.             } while(res == -1 && errno == EINTR);
  8271.  
  8272.             uint32_t result = 0;
  8273.             if(res != -1) {
  8274.                 result = (uint32_t)res;
  8275.             }
  8276.             return(result);
  8277.         }
  8278.  
  8279.         fpl_platform_api uint32_t WriteFileBlock32(const FileHandle &fileHandle, void *sourceBuffer, const uint32_t sourceSize) {
  8280.             if(sourceSize == 0) {
  8281.                 return 0;
  8282.             }
  8283.             if(sourceBuffer == nullptr) {
  8284.                 common::ArgumentNullError("Source buffer");
  8285.                 return 0;
  8286.             }
  8287.             if(!fileHandle.internalHandle.posixFileHandle) {
  8288.                 common::PushError("File handle is not opened for writing");
  8289.                 return 0;
  8290.             }
  8291.  
  8292.             int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8293.  
  8294.             ssize_t res;
  8295.             do {
  8296.                 res = ::write(posixFileHandle, sourceBuffer, sourceSize);
  8297.             } while(res == -1 && errno == EINTR);
  8298.  
  8299.             uint32_t result = 0;
  8300.             if(res != -1) {
  8301.                 result = (uint32_t)res;
  8302.             }
  8303.             return(result);
  8304.         }
  8305.  
  8306.         fpl_platform_api void SetFilePosition32(const FileHandle &fileHandle, const int32_t position, const FilePositionMode mode) {
  8307.             if(fileHandle.internalHandle.posixFileHandle) {
  8308.                 int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8309.                 int whence = SEEK_SET;
  8310.                 if(mode == FilePositionMode::Current) {
  8311.                     whence = SEEK_CUR;
  8312.                 } else if(mode == FilePositionMode::End) {
  8313.                     whence = SEEK_END;
  8314.                 }
  8315.                 ::lseek(posixFileHandle, position, whence);
  8316.             }
  8317.         }
  8318.  
  8319.         fpl_platform_api uint32_t GetFilePosition32(const FileHandle &fileHandle) {
  8320.             uint32_t result = 0;
  8321.             if(fileHandle.internalHandle.posixFileHandle) {
  8322.                 int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8323.                 off_t res = ::lseek(posixFileHandle, 0, SEEK_CUR);
  8324.                 if(res != -1) {
  8325.                     result = (uint32_t)res;
  8326.                 }
  8327.             }
  8328.             return(result);
  8329.         }
  8330.  
  8331.         fpl_platform_api void CloseFile(FileHandle &fileHandle) {
  8332.             if(fileHandle.internalHandle.posixFileHandle) {
  8333.                 int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8334.                 ::close(posixFileHandle);
  8335.                 fileHandle = {};
  8336.             }
  8337.         }
  8338.  
  8339.         fpl_platform_api uint32_t GetFileSize32(const char *filePath) {
  8340.             uint32_t result = 0;
  8341.             if(filePath != nullptr) {
  8342.                 int posixFileHandle;
  8343.                 do {
  8344.                     posixFileHandle = ::open(filePath, O_RDONLY);
  8345.                 } while(posixFileHandle == -1 && errno == EINTR);
  8346.                 if(posixFileHandle != -1) {
  8347.                     off_t res = ::lseek(posixFileHandle, 0, SEEK_END);
  8348.                     if(res != -1) {
  8349.                         result = (uint32_t)res;
  8350.                     }
  8351.                     ::close(posixFileHandle);
  8352.                 }
  8353.             }
  8354.             return(result);
  8355.         }
  8356.  
  8357.         fpl_platform_api uint32_t GetFileSize32(const FileHandle &fileHandle) {
  8358.             uint32_t result = 0;
  8359.             if(fileHandle.internalHandle.posixFileHandle) {
  8360.                 int posixFileHandle = fileHandle.internalHandle.posixFileHandle;
  8361.                 off_t curPos = ::lseek(posixFileHandle, 0, SEEK_CUR);
  8362.                 if(curPos != -1) {
  8363.                     result = (uint32_t)::lseek(posixFileHandle, 0, SEEK_END);
  8364.                     ::lseek(posixFileHandle, curPos, SEEK_SET);
  8365.                 }
  8366.             }
  8367.             return(result);
  8368.         }
  8369.  
  8370.         fpl_platform_api bool FileExists(const char *filePath) {
  8371.             bool result = false;
  8372.             if(filePath != nullptr) {
  8373.                 result = ::access(filePath, F_OK) != -1;
  8374.             }
  8375.             return(result);
  8376.         }
  8377.  
  8378.         fpl_platform_api bool FileCopy(const char *sourceFilePath, const char *targetFilePath, const bool overwrite) {
  8379.             if(sourceFilePath == nullptr) {
  8380.                 common::ArgumentNullError("Source file path");
  8381.                 return false;
  8382.             }
  8383.             if(targetFilePath == nullptr) {
  8384.                 common::ArgumentNullError("Target file path");
  8385.                 return false;
  8386.             }
  8387.             bool result = false;
  8388.  
  8389.             // @IMPLEMENT(final): POSIX FileCopy - there is no built-in copy-file function in POSIX so we open a file and buffer copy it over
  8390.  
  8391.             return(result);
  8392.         }
  8393.  
  8394.         fpl_platform_api bool FileMove(const char *sourceFilePath, const char *targetFilePath) {
  8395.             if(sourceFilePath == nullptr) {
  8396.                 common::ArgumentNullError("Source file path");
  8397.                 return false;
  8398.             }
  8399.             if(targetFilePath == nullptr) {
  8400.                 common::ArgumentNullError("Target file path");
  8401.                 return false;
  8402.             }
  8403.             bool result = ::rename(sourceFilePath, targetFilePath) == 0;
  8404.             return(result);
  8405.         }
  8406.  
  8407.         fpl_platform_api bool FileDelete(const char *filePath) {
  8408.             if(filePath == nullptr) {
  8409.                 common::ArgumentNullError("File path");
  8410.                 return false;
  8411.             }
  8412.             bool result = ::unlink(filePath) == 0;
  8413.             return(result);
  8414.         }
  8415.  
  8416.         fpl_platform_api bool DirectoryExists(const char *path) {
  8417.             bool result = false;
  8418.             if(path != nullptr) {
  8419.                 struct stat sb;
  8420.                 result = (::stat(path, &sb) == 0) && S_ISDIR(sb.st_mode);
  8421.             }
  8422.             return(result);
  8423.         }
  8424.  
  8425.         fpl_platform_api bool CreateDirectories(const char *path) {
  8426.             if(path == nullptr) {
  8427.                 common::ArgumentNullError("Path");
  8428.                 return false;
  8429.             }
  8430.             bool result = ::mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) == 0;
  8431.             return(result);
  8432.         }
  8433.         fpl_platform_api bool RemoveEmptyDirectory(const char *path) {
  8434.             if(path == nullptr) {
  8435.                 common::ArgumentNullError("Path");
  8436.                 return false;
  8437.             }
  8438.             bool result = ::rmdir(path) == 0;
  8439.             return(result);
  8440.         }
  8441.         fpl_platform_api bool ListFilesBegin(const char *pathAndFilter, FileEntry &firstEntry) {
  8442.             if(pathAndFilter == nullptr) {
  8443.                 common::ArgumentNullError("Path and filter");
  8444.                 return false;
  8445.             }
  8446.             bool result = false;
  8447.             // @IMPLEMENT(final): POSIX ListFilesBegin
  8448.             return(result);
  8449.         }
  8450.         fpl_platform_api bool ListFilesNext(FileEntry &nextEntry) {
  8451.             bool result = false;
  8452.             if(nextEntry.internalHandle.posixFileHandle) {
  8453.                 // @IMPLEMENT(final): POSIX ListFilesNext
  8454.             }
  8455.             return(result);
  8456.         }
  8457.         fpl_platform_api void ListFilesEnd(FileEntry &lastEntry) {
  8458.             if(lastEntry.internalHandle.posixFileHandle) {
  8459.                 // @IMPLEMENT(final): POSIX ListFilesEnd
  8460.                 lastEntry = {};
  8461.             }
  8462.         }
  8463.     } // files
  8464. } // fpl
  8465.  
  8466. #endif // FPL_SUBPLATFORM_POSIX
  8467.  
  8468. // ############################################################################
  8469. //
  8470. // > STD_STRINGS_SUBPLATFORM
  8471. //
  8472. // Strings Implementation using C Standard Library
  8473. //
  8474. // ############################################################################
  8475. #if defined(FPL_SUBPLATFORM_STD_STRINGS)
  8476. // @NOTE(final): stdio.h is already included
  8477. namespace fpl {
  8478.     namespace strings {
  8479.         fpl_platform_api char *WideStringToAnsiString(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *ansiDest, const uint32_t maxAnsiDestLen) {
  8480.             if(wideSource == nullptr) {
  8481.                 common::ArgumentNullError("Wide source");
  8482.                 return nullptr;
  8483.             }
  8484.             if(ansiDest == nullptr) {
  8485.                 common::ArgumentNullError("Ansi dest");
  8486.                 return nullptr;
  8487.             }
  8488.             uint32_t requiredLen = ::wcstombs(nullptr, wideSource, maxWideSourceLen);
  8489.             uint32_t minRequiredLen = requiredLen + 1;
  8490.             if(maxAnsiDestLen < minRequiredLen) {
  8491.                 common::ArgumentSizeTooSmallError("Max ansi dest len", maxAnsiDestLen, minRequiredLen);
  8492.                 return nullptr;
  8493.             }
  8494.             ::wcstombs(ansiDest, wideSource, maxWideSourceLen);
  8495.             ansiDest[requiredLen] = 0;
  8496.             return(ansiDest);
  8497.         }
  8498.         fpl_platform_api char *WideStringToUTF8String(const wchar_t *wideSource, const uint32_t maxWideSourceLen, char *utf8Dest, const uint32_t maxUtf8DestLen) {
  8499.             if(wideSource == nullptr) {
  8500.                 common::ArgumentNullError("Wide source");
  8501.                 return nullptr;
  8502.             }
  8503.             if(utf8Dest == nullptr) {
  8504.                 common::ArgumentNullError("UTF8 dest");
  8505.                 return nullptr;
  8506.             }
  8507.             // @TODO(final): UTF-8!
  8508.             uint32_t requiredLen = ::wcstombs(nullptr, wideSource, maxWideSourceLen);
  8509.             uint32_t minRequiredLen = requiredLen + 1;
  8510.             if(maxUtf8DestLen < minRequiredLen) {
  8511.                 common::ArgumentSizeTooSmallError("Max utf8 dest len", maxUtf8DestLen, minRequiredLen);
  8512.                 return nullptr;
  8513.             }
  8514.             ::wcstombs(utf8Dest, wideSource, maxWideSourceLen);
  8515.             utf8Dest[requiredLen] = 0;
  8516.             return(utf8Dest);
  8517.         }
  8518.         fpl_platform_api wchar_t *AnsiStringToWideString(const char *ansiSource, const uint32_t ansiSourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen) {
  8519.             if(ansiSource == nullptr) {
  8520.                 common::ArgumentNullError("Ansi source");
  8521.                 return nullptr;
  8522.             }
  8523.             if(wideDest == nullptr) {
  8524.                 common::ArgumentNullError("Wide dest");
  8525.                 return nullptr;
  8526.             }
  8527.             uint32_t requiredLen = ::mbstowcs(nullptr, ansiSource, ansiSourceLen);
  8528.             uint32_t minRequiredLen = requiredLen + 1;
  8529.             if(maxWideDestLen < minRequiredLen) {
  8530.                 common::ArgumentSizeTooSmallError("Max wide dest len", maxWideDestLen, minRequiredLen);
  8531.                 return nullptr;
  8532.             }
  8533.             ::mbstowcs(wideDest, ansiSource, ansiSourceLen);
  8534.             wideDest[requiredLen] = 0;
  8535.             return(wideDest);
  8536.         }
  8537.         fpl_platform_api wchar_t *UTF8StringToWideString(const char *utf8Source, const uint32_t utf8SourceLen, wchar_t *wideDest, const uint32_t maxWideDestLen) {
  8538.             if(utf8Source == nullptr) {
  8539.                 common::ArgumentNullError("UTF8 source");
  8540.                 return nullptr;
  8541.             }
  8542.             if(wideDest == nullptr) {
  8543.                 common::ArgumentNullError("Wide dest");
  8544.                 return nullptr;
  8545.             }
  8546.             // @TODO(final): UTF-8!
  8547.             uint32_t requiredLen = ::mbstowcs(nullptr, utf8Source, utf8SourceLen);
  8548.             uint32_t minRequiredLen = requiredLen + 1;
  8549.             if(maxWideDestLen < minRequiredLen) {
  8550.                 common::ArgumentSizeTooSmallError("Max wide dest len", maxWideDestLen, minRequiredLen);
  8551.                 return nullptr;
  8552.             }
  8553.             ::mbstowcs(wideDest, utf8Source, utf8SourceLen);
  8554.             wideDest[requiredLen] = 0;
  8555.             return(wideDest);
  8556.         }
  8557.         fpl_platform_api char *FormatAnsiString(char *ansiDestBuffer, const uint32_t maxAnsiDestBufferLen, const char *format, ...) {
  8558.             if(ansiDestBuffer == nullptr) {
  8559.                 common::ArgumentNullError("Ansi dest buffer");
  8560.                 return nullptr;
  8561.             }
  8562.             if(maxAnsiDestBufferLen == 0) {
  8563.                 common::ArgumentZeroError("Max ansi dest len");
  8564.                 return nullptr;
  8565.             }
  8566.             if(format == nullptr) {
  8567.                 common::ArgumentNullError("Format");
  8568.                 return nullptr;
  8569.             }
  8570.             va_list argList;
  8571.             va_start(argList, format);
  8572.             // @NOTE(final): Need to clear the first character, otherwise vsnprintf() does weird things... O_o
  8573.             ansiDestBuffer[0] = 0;
  8574.             int charCount = ::vsnprintf(ansiDestBuffer, maxAnsiDestBufferLen, format, argList);
  8575.             if(charCount < 0) {
  8576.                 common::PushError("Format parameter are '%s' are invalid!", format);
  8577.                 return nullptr;
  8578.             }
  8579.             uint32_t minAnsiDestBufferLen = charCount + 1;
  8580.             if(maxAnsiDestBufferLen < minAnsiDestBufferLen) {
  8581.                 common::ArgumentSizeTooSmallError("Max ansi dest len", maxAnsiDestBufferLen, minAnsiDestBufferLen);
  8582.                 return nullptr;
  8583.             }
  8584.             va_end(argList);
  8585.             FPL_ASSERT(charCount > 0);
  8586.             ansiDestBuffer[charCount] = 0;
  8587.             char *result = ansiDestBuffer;
  8588.             return(result);
  8589.         }
  8590.     } // strings
  8591. } // fpl
  8592. #endif // FPL_SUBPLATFORM_STD_STRINGS
  8593.  
  8594. // ############################################################################
  8595. //
  8596. // > STD_CONSOLE_SUBPLATFORM
  8597. //
  8598. // Console Implementation using C Standard Library
  8599. //
  8600. // ############################################################################
  8601. #if defined(FPL_SUBPLATFORM_STD_CONSOLE)
  8602. // @NOTE(final): stdio.h is already included
  8603. namespace fpl {
  8604.     namespace console {
  8605.         fpl_platform_api void ConsoleOut(const char *text) {
  8606.             if(text != nullptr) {
  8607.                 ::fprintf(stdout, "%s", text);
  8608.             }
  8609.         }
  8610.         fpl_platform_api void ConsoleFormatOut(const char *format, ...) {
  8611.             if(format != nullptr) {
  8612.                 va_list vaList;
  8613.                 va_start(vaList, format);
  8614.                 ::vfprintf(stdout, format, vaList);
  8615.                 va_end(vaList);
  8616.             }
  8617.         }
  8618.         fpl_platform_api void ConsoleError(const char *text) {
  8619.             if(text != nullptr) {
  8620.                 ::fprintf(stderr, "%s", text);
  8621.             }
  8622.         }
  8623.         fpl_platform_api void ConsoleFormatError(const char *format, ...) {
  8624.             if(format != nullptr) {
  8625.                 va_list vaList;
  8626.                 va_start(vaList, format);
  8627.                 ::vfprintf(stderr, format, vaList);
  8628.                 va_end(vaList);
  8629.             }
  8630.         }
  8631.         fpl_platform_api const char ConsoleWaitForCharInput() {
  8632.             int c = ::getchar();
  8633.             const char result = (c >= 0 && c < 256) ? (char)c : 0;
  8634.             return(result);
  8635.         }
  8636.     } // console
  8637. } // fpl
  8638. #endif // FPL_SUBPLATFORM_STD_CONSOLE
  8639.  
  8640. // ############################################################################
  8641. //
  8642. // > X11_SUBPLATFORM
  8643. //
  8644. // ############################################################################
  8645. #if defined(FPL_SUBPLATFORM_X11)
  8646. namespace fpl {
  8647.     namespace subplatform_x11 {
  8648.  
  8649.         fpl_internal void X11ReleaseSubplatform(X11SubplatformState &subplatform) {
  8650.             UnloadX11Api(subplatform.api);
  8651.         }
  8652.  
  8653.         fpl_internal bool X11InitSubplatform(X11SubplatformState &subplatform) {
  8654.             if(!LoadX11Api(subplatform.api)) {
  8655.                 common::PushError("Failed loading x11 api!");
  8656.                 return false;
  8657.             }
  8658.             return true;
  8659.         }
  8660.  
  8661.         fpl_internal void X11ReleaseWindow(const X11SubplatformState &subplatform, X11WindowState &windowState) {
  8662.             const X11Api &x11Api = subplatform.api;
  8663.             if(windowState.window) {
  8664.                 x11Api.XDestroyWindow(windowState.display, windowState.window);
  8665.                 windowState.window = 0;
  8666.             }
  8667.             if(windowState.colorMap) {
  8668.                 x11Api.XFreeColormap(windowState.display, windowState.colorMap);
  8669.                 windowState.colorMap = 0;
  8670.             }
  8671.             if(windowState.display) {
  8672.                 x11Api.XCloseDisplay(windowState.display);
  8673.                 windowState.display = nullptr;
  8674.             }
  8675.             windowState = {};
  8676.         }
  8677.  
  8678.         fpl_internal bool X11InitWindow(const Settings &initSettings, WindowSettings &currentWindowSettings, platform::PlatformAppState *appState, X11SubplatformState &subplatform, X11WindowState &windowState, const platform::SetupWindowCallbacks &setupCallbacks) {
  8679.             const X11Api &x11Api = subplatform.api;
  8680.             windowState.display = x11Api.XOpenDisplay(nullptr);
  8681.             if(windowState.display == nullptr) {
  8682.                 return false;
  8683.             }
  8684.  
  8685.             windowState.screen = x11Api.XDefaultScreen(windowState.display);
  8686.  
  8687.             windowState.root = x11Api.XRootWindow(windowState.display, windowState.screen);
  8688.  
  8689.             bool usePreSetupWindow = false;
  8690.             platform::PreSetupWindowResult setupResult = {};
  8691.             if(setupCallbacks.preSetup != nullptr) {
  8692.                 usePreSetupWindow = setupCallbacks.preSetup(appState, appState->initFlags, initSettings, setupResult);
  8693.             }
  8694.  
  8695.             Visual *visual = nullptr;
  8696.             int colorDepth = 0;
  8697.             Colormap colormap;
  8698.             if(usePreSetupWindow) {
  8699.                 FPL_ASSERT(setupResult.x11.visual != nullptr);
  8700.                 visual = setupResult.x11.visual;
  8701.                 colorDepth = setupResult.x11.colorDepth;
  8702.                 colormap = x11Api.XCreateColormap(windowState.display, windowState.root, visual, AllocNone);
  8703.             } else {
  8704.                 colormap = x11Api.XDefaultColormap(windowState.display, windowState.root);
  8705.                 visual = x11Api.XDefaultVisual(windowState.display, windowState.root);
  8706.                 colorDepth = x11Api.XDefaultDepth(windowState.display, windowState.root);
  8707.             }
  8708.  
  8709.             windowState.colorMap = colormap;
  8710.  
  8711.             XSetWindowAttributes swa;
  8712.             swa.colormap = colormap;
  8713.             swa.event_mask = StructureNotifyMask;
  8714.  
  8715.             uint32_t windowWidth = 640;
  8716.             uint32_t windowHeight = 640;
  8717.  
  8718.             windowState.window = x11Api.XCreateWindow(windowState.display,
  8719.                                                       windowState.root,
  8720.                                                       0,
  8721.                                                       0,
  8722.                                                       windowWidth,
  8723.                                                       windowHeight,
  8724.                                                       0,
  8725.                                                       colorDepth,
  8726.                                                       InputOutput,
  8727.                                                       visual,
  8728.                                                       CWColormap | CWEventMask,
  8729.                                                       &swa);
  8730.             if(!windowState.window) {
  8731.                 X11ReleaseWindow(subplatform, windowState);
  8732.                 return false;
  8733.             }
  8734.  
  8735.             char nameBuffer[1024] = {};
  8736.             strings::CopyAnsiString("Unnamed FPL X11 Window", nameBuffer, FPL_ARRAYCOUNT(nameBuffer));
  8737.             x11Api.XStoreName(windowState.display, windowState.window, nameBuffer);
  8738.             x11Api.XMapWindow(windowState.display, windowState.window);
  8739.  
  8740.             return true;
  8741.         }
  8742.     } // subplatform_x11
  8743.  
  8744.     namespace window {
  8745.         fpl_platform_api bool PushWindowEvent() {
  8746.             // @IMPLEMENT(final): X11 PushWindowEvent
  8747.             return false;
  8748.         }
  8749.  
  8750.         fpl_platform_api void UpdateGameControllers() {
  8751.             // @IMPLEMENT(final): X11 UpdateGameControllers
  8752.         }
  8753.  
  8754.         fpl_platform_api bool IsWindowRunning() {
  8755.             // @IMPLEMENT(final): X11 IsWindowRunning
  8756.             return false;
  8757.         }
  8758.  
  8759.         fpl_platform_api bool WindowUpdate() {
  8760.             // @IMPLEMENT(final): X11 WindowUpdate
  8761.             return false;
  8762.         }
  8763.  
  8764.         fpl_platform_api void SetWindowCursorEnabled(const bool value) {
  8765.             // @IMPLEMENT(final): X11 SetWindowCursorEnabled
  8766.         }
  8767.  
  8768.         fpl_platform_api WindowSize GetWindowArea() {
  8769.             WindowSize result = {};
  8770.             // @IMPLEMENT(final): X11 GetWindowArea
  8771.             return(result);
  8772.         }
  8773.  
  8774.         fpl_platform_api void SetWindowArea(const uint32_t width, const uint32_t height) {
  8775.             // @IMPLEMENT(final): X11 SetWindowArea
  8776.         }
  8777.  
  8778.         fpl_platform_api bool IsWindowResizable() {
  8779.             // @IMPLEMENT(final): X11 IsWindowResizable
  8780.             return false;
  8781.         }
  8782.  
  8783.         fpl_platform_api void SetWindowResizeable(const bool value) {
  8784.             // @IMPLEMENT(final): X11 SetWindowResizeable
  8785.         }
  8786.  
  8787.         fpl_platform_api bool SetWindowFullscreen(const bool value, const uint32_t fullscreenWidth, const uint32_t fullscreenHeight, const uint32_t refreshRate) {
  8788.             // @IMPLEMENT(final): X11 SetWindowFullscreen
  8789.             return false;
  8790.         }
  8791.  
  8792.         fpl_platform_api bool IsWindowFullscreen() {
  8793.             // @IMPLEMENT(final): X11 IsWindowFullscreen
  8794.             return false;
  8795.         }
  8796.  
  8797.         fpl_platform_api WindowPosition GetWindowPosition() {
  8798.             WindowPosition result = {};
  8799.             // @IMPLEMENT(final): X11 GetWindowPosition
  8800.             return(result);
  8801.         }
  8802.  
  8803.         fpl_platform_api void SetWindowPosition(const int32_t left, const int32_t top) {
  8804.             // @IMPLEMENT(final): X11 SetWindowPosition
  8805.         }
  8806.  
  8807.         fpl_platform_api void SetWindowTitle(const char *title) {
  8808.             // @IMPLEMENT(final): X11 SetWindowTitle
  8809.         }
  8810.  
  8811.         fpl_platform_api char *GetClipboardAnsiText(char *dest, const uint32_t maxDestLen) {
  8812.             // @IMPLEMENT(final): X11 GetClipboardAnsiText
  8813.             return nullptr;
  8814.         }
  8815.  
  8816.         fpl_platform_api wchar_t *GetClipboardWideText(wchar_t *dest, const uint32_t maxDestLen) {
  8817.             // @IMPLEMENT(final): X11 GetClipboardWideText
  8818.             return nullptr;
  8819.         }
  8820.  
  8821.         fpl_platform_api bool SetClipboardText(const char *ansiSource) {
  8822.             // @IMPLEMENT(final): X11 SetClipboardText (ansi)
  8823.             return false;
  8824.         }
  8825.  
  8826.         fpl_platform_api bool SetClipboardText(const wchar_t *wideSource) {
  8827.             // @IMPLEMENT(final): X11 SetClipboardText (wide)
  8828.             return false;
  8829.         }
  8830.     } // window
  8831.  
  8832. } // fpl
  8833. #endif // FPL_SUBPLATFORM_X11
  8834.  
  8835. // ############################################################################
  8836. //
  8837. // > LINUX_PLATFORM
  8838. //
  8839. // ############################################################################
  8840. #if defined(FPL_PLATFORM_LINUX)
  8841. #   include <ctype.h> // isspace
  8842.  
  8843. namespace fpl {
  8844.     namespace platform_linux {
  8845.         fpl_internal void LinuxReleasePlatform(platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  8846.             FPL_LOG_BLOCK;
  8847.         }
  8848.  
  8849.         fpl_internal bool LinuxInitPlatform(const InitFlags initFlags, const Settings &initSettings, platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  8850.             FPL_LOG_BLOCK;
  8851.  
  8852.             return true;
  8853.         }
  8854.     } // platform_linux
  8855.  
  8856.     // Linux Hardware
  8857.     namespace hardware {
  8858.         fpl_platform_api uint32_t GetProcessorCoreCount() {
  8859.             uint32_t result = sysconf(_SC_NPROCESSORS_ONLN);
  8860.             return(result);
  8861.         }
  8862.  
  8863.         fpl_platform_api char *GetProcessorName(char *destBuffer, const uint32_t maxDestBufferLen) {
  8864.             if(destBuffer == nullptr) {
  8865.                 common::ArgumentNullError("Dest buffer");
  8866.                 return nullptr;
  8867.             }
  8868.             if(maxDestBufferLen == 0) {
  8869.                 common::ArgumentZeroError("Max dest buffer len");
  8870.                 return nullptr;
  8871.             }
  8872.             char *result = nullptr;
  8873.             FILE *fileHandle = fopen("/proc/cpuinfo", "rb");
  8874.             if(fileHandle != nullptr) {
  8875.                 char buffer[256];
  8876.                 char line[256];
  8877.                 const size_t maxBufferSize = FPL_ARRAYCOUNT(buffer);
  8878.                 int32_t readSize = maxBufferSize;
  8879.                 int32_t readPos = 0;
  8880.                 bool found = false;
  8881.                 int bytesRead = 0;
  8882.                 while((bytesRead = fread(&buffer[readPos], readSize, 1, fileHandle)) > 0) {
  8883.                     char *lastP = &buffer[0];
  8884.                     char *p = &buffer[0];
  8885.                     while(*p) {
  8886.                         if(*p == '\n') {
  8887.                             int32_t len = p - lastP;
  8888.                             FPL_ASSERT(len > 0);
  8889.                             if(strings::IsStringEqual(lastP, 10, "model name", 10)) {
  8890.                                 strings::CopyAnsiString(lastP, len, line, FPL_ARRAYCOUNT(line));
  8891.                                 found = true;
  8892.                                 break;
  8893.                             }
  8894.                             lastP = p + 1;
  8895.                         }
  8896.                         ++p;
  8897.                     }
  8898.                     if(found) {
  8899.                         break;
  8900.                     }
  8901.  
  8902.                     int32_t remaining = &buffer[maxBufferSize] - lastP;
  8903.                     FPL_ASSERT(remaining >= 0);
  8904.                     if(remaining > 0) {
  8905.                         // Buffer does not contain a line separator - copy back to remaining characters to the line
  8906.                         strings::CopyAnsiString(lastP, remaining, line, FPL_ARRAYCOUNT(line));
  8907.                         // Copy back line to buffer and use a different read position/size
  8908.                         strings::CopyAnsiString(line, remaining, buffer, maxBufferSize);
  8909.                         readPos = remaining;
  8910.                         readSize = maxBufferSize - remaining;
  8911.                     } else {
  8912.                         readPos = 0;
  8913.                         readSize = maxBufferSize;
  8914.                     }
  8915.                 }
  8916.                 if(found) {
  8917.                     char *p = line;
  8918.                     while(*p) {
  8919.                         if(*p == ':') {
  8920.                             ++p;
  8921.                             // Skip whitespaces
  8922.                             while(*p && isspace(*p)) {
  8923.                                 ++p;
  8924.                             }
  8925.                             break;
  8926.                         }
  8927.                         ++p;
  8928.                     }
  8929.                     if(p != line) {
  8930.                         strings::CopyAnsiString(p, destBuffer, maxDestBufferLen);
  8931.                         result = destBuffer;
  8932.                     }
  8933.                 }
  8934.                 fclose(fileHandle);
  8935.             }
  8936.             return(result);
  8937.         }
  8938.  
  8939.         fpl_platform_api MemoryInfos GetSystemMemoryInfos() {
  8940.             MemoryInfos result = {};
  8941.             return(result);
  8942.         }
  8943.     } // hardware
  8944.  
  8945.     namespace paths {
  8946.         fpl_platform_api char *GetExecutableFilePath(char *destPath, const uint32_t maxDestLen) {
  8947.             return nullptr;
  8948.         }
  8949.  
  8950.         fpl_platform_api char *GetHomePath(char *destPath, const uint32_t maxDestLen) {
  8951.             return nullptr;
  8952.         }
  8953.     } // paths
  8954. } // fpl
  8955. #endif // FPL_PLATFORM_LINUX
  8956.  
  8957. // ****************************************************************************
  8958. //
  8959. // > VIDEO_DRIVERS
  8960. //
  8961. // ****************************************************************************
  8962. #if !defined(FPL_VIDEO_DRIVERS_IMPLEMENTED)
  8963. #   define FPL_VIDEO_DRIVERS_IMPLEMENTED
  8964.  
  8965. //
  8966. // Includes for drivers must be on root level!
  8967. //
  8968. #   if defined(FPL_ENABLE_VIDEO_OPENGL)
  8969. #       if defined(FPL_SUBPLATFORM_X11)
  8970. #           include <GL/glx.h> // XVisualInfo, GLXContext, GLXDrawable
  8971. #       endif
  8972. #   endif
  8973.  
  8974. namespace fpl {
  8975.     namespace drivers {
  8976.  
  8977. // ############################################################################
  8978. //
  8979. // > VIDEO_DRIVER_OPENGL_WIN32
  8980. //
  8981. // ############################################################################
  8982. #if defined(FPL_ENABLE_VIDEO_OPENGL)
  8983. #   if defined(FPL_PLATFORM_WIN32)
  8984.         //
  8985.         // OpenGL Constants and Function-Prototypes
  8986.         //
  8987. #       define FPL_GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
  8988. #       define FPL_GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
  8989. #       define FPL_GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
  8990. #       define FPL_GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008
  8991. #       define FPL_GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
  8992. #       define FPL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
  8993.  
  8994. #       define FPL_WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
  8995. #       define FPL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
  8996. #       define FPL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
  8997. #       define FPL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
  8998. #       define FPL_WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
  8999. #       define FPL_WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
  9000. #       define FPL_WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
  9001. #       define FPL_WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
  9002. #       define FPL_WGL_CONTEXT_FLAGS_ARB 0x2094
  9003.  
  9004. #       define FPL_WGL_DRAW_TO_WINDOW_ARB 0x2001
  9005. #       define FPL_WGL_ACCELERATION_ARB 0x2003
  9006. #       define FPL_WGL_SWAP_METHOD_ARB 0x2007
  9007. #       define FPL_WGL_SUPPORT_OPENGL_ARB 0x2010
  9008. #       define FPL_WGL_DOUBLE_BUFFER_ARB 0x2011
  9009. #       define FPL_WGL_PIXEL_TYPE_ARB 0x2013
  9010. #       define FPL_WGL_COLOR_BITS_ARB 0x2014
  9011. #       define FPL_WGL_DEPTH_BITS_ARB 0x2022
  9012. #       define FPL_WGL_STENCIL_BITS_ARB 0x2023
  9013. #       define FPL_WGL_FULL_ACCELERATION_ARB 0x2027
  9014. #       define FPL_WGL_SWAP_EXCHANGE_ARB 0x2028
  9015. #       define FPL_WGL_TYPE_RGBA_ARB 0x202B
  9016.  
  9017. #       define FPL_FUNC_WGL_MAKE_CURRENT(name) BOOL WINAPI name(HDC deviceContext, HGLRC renderingContext)
  9018.         typedef FPL_FUNC_WGL_MAKE_CURRENT(win32_func_wglMakeCurrent);
  9019. #       define FPL_FUNC_WGL_GET_PROC_ADDRESS(name) PROC WINAPI name(LPCSTR procedure)
  9020.         typedef FPL_FUNC_WGL_GET_PROC_ADDRESS(win32_func_wglGetProcAddress);
  9021. #       define FPL_FUNC_WGL_DELETE_CONTEXT(name) BOOL WINAPI name(HGLRC renderingContext)
  9022.         typedef FPL_FUNC_WGL_DELETE_CONTEXT(win32_func_wglDeleteContext);
  9023. #       define FPL_FUNC_WGL_CREATE_CONTEXT(name) HGLRC WINAPI name(HDC deviceContext)
  9024.         typedef FPL_FUNC_WGL_CREATE_CONTEXT(win32_func_wglCreateContext);
  9025.  
  9026. #       define FPL_FUNC_WGL_CHOOSE_PIXEL_FORMAT_ARB(name) BOOL WINAPI name(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats)
  9027.         typedef FPL_FUNC_WGL_CHOOSE_PIXEL_FORMAT_ARB(win32_func_wglChoosePixelFormatARB);
  9028. #       define FPL_FUNC_WGL_CREATE_CONTEXT_ATTRIBS_ARB(name) HGLRC WINAPI name(HDC hDC, HGLRC hShareContext, const int *attribList)
  9029.         typedef FPL_FUNC_WGL_CREATE_CONTEXT_ATTRIBS_ARB(win32_func_wglCreateContextAttribsARB);
  9030. #       define FPL_FUNC_WGL_SWAP_INTERVAL_EXT(name) BOOL WINAPI name(int interval)
  9031.         typedef FPL_FUNC_WGL_SWAP_INTERVAL_EXT(win32_func_wglSwapIntervalEXT);
  9032.  
  9033.         struct Win32OpenGLApi {
  9034.             HMODULE openglLibrary;
  9035.             win32_func_wglMakeCurrent *wglMakeCurrent;
  9036.             win32_func_wglGetProcAddress *wglGetProcAddress;
  9037.             win32_func_wglDeleteContext *wglDeleteContext;
  9038.             win32_func_wglCreateContext *wglCreateContext;
  9039.             win32_func_wglChoosePixelFormatARB *wglChoosePixelFormatArb;
  9040.             win32_func_wglCreateContextAttribsARB *wglCreateContextAttribsArb;
  9041.             win32_func_wglSwapIntervalEXT *wglSwapIntervalExt;
  9042.         };
  9043.  
  9044.         fpl_internal void Win32UnloadVideoOpenGLApi(Win32OpenGLApi &api) {
  9045.             if(api.openglLibrary != nullptr) {
  9046.                 ::FreeLibrary(api.openglLibrary);
  9047.             }
  9048.             api = {};
  9049.         }
  9050.  
  9051.         fpl_internal bool Win32LoadVideoOpenGLApi(Win32OpenGLApi &api) {
  9052.             const char *openglLibraryName = "opengl32.dll";
  9053.             api = {};
  9054.  
  9055.             api.openglLibrary = ::LoadLibraryA("opengl32.dll");
  9056.             if(api.openglLibrary == nullptr) {
  9057.                 common::PushError("Failed loading opengl library '%s'", openglLibraryName);
  9058.                 return false;
  9059.             }
  9060.  
  9061.             FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(api.openglLibrary, openglLibraryName, api.wglGetProcAddress, win32_func_wglGetProcAddress, "wglGetProcAddress");
  9062.             FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(api.openglLibrary, openglLibraryName, api.wglCreateContext, win32_func_wglCreateContext, "wglCreateContext");
  9063.             FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(api.openglLibrary, openglLibraryName, api.wglDeleteContext, win32_func_wglDeleteContext, "wglDeleteContext");
  9064.             FPL_WIN32_GET_FUNCTION_ADDRESS_RETURN(api.openglLibrary, openglLibraryName, api.wglMakeCurrent, win32_func_wglMakeCurrent, "wglMakeCurrent");
  9065.  
  9066.             return true;
  9067.         }
  9068.  
  9069.         struct Win32VideoOpenGLState {
  9070.             HGLRC renderingContext;
  9071.             Win32OpenGLApi api;
  9072.         };
  9073.  
  9074.         fpl_internal bool Win32PostSetupWindowForOpenGL(platform_win32::Win32AppState &appState, const platform_win32::Win32WindowState &windowState, const VideoSettings &videoSettings) {
  9075.             const platform_win32::Win32Api &wapi = appState.winApi;
  9076.  
  9077.             //
  9078.             // Prepare window for OpenGL
  9079.             //
  9080.             HDC deviceContext = windowState.deviceContext;
  9081.             HWND handle = windowState.windowHandle;
  9082.  
  9083.             PIXELFORMATDESCRIPTOR pfd = {};
  9084.             pfd.nSize = sizeof(pfd);
  9085.             pfd.nVersion = 1;
  9086.             pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
  9087.             pfd.iPixelType = PFD_TYPE_RGBA;
  9088.             pfd.cColorBits = 32;
  9089.             pfd.cDepthBits = 24;
  9090.             pfd.cAlphaBits = 8;
  9091.             pfd.iLayerType = PFD_MAIN_PLANE;
  9092.  
  9093.             int pixelFormat = wapi.gdi.choosePixelFormat(deviceContext, &pfd);
  9094.             if(!pixelFormat) {
  9095.                 common::PushError("Failed choosing RGBA Legacy Pixelformat for Color/Depth/Alpha (%d,%d,%d) and DC '%x'", pfd.cColorBits, pfd.cDepthBits, pfd.cAlphaBits, deviceContext);
  9096.                 return false;
  9097.             }
  9098.  
  9099.             if(!wapi.gdi.setPixelFormat(deviceContext, pixelFormat, &pfd)) {
  9100.                 common::PushError("Failed setting RGBA Pixelformat '%d' for Color/Depth/Alpha (%d,%d,%d and DC '%x')", pixelFormat, pfd.cColorBits, pfd.cDepthBits, pfd.cAlphaBits, deviceContext);
  9101.                 return false;
  9102.             }
  9103.  
  9104.             wapi.gdi.describePixelFormat(deviceContext, pixelFormat, sizeof(pfd), &pfd);
  9105.  
  9106.             return true;
  9107.         }
  9108.  
  9109.         fpl_internal bool Win32InitVideoOpenGL(const platform_win32::Win32AppState &appState, const platform_win32::Win32WindowState &windowState, const VideoSettings &videoSettings, Win32VideoOpenGLState &glState) {
  9110.             const platform_win32::Win32Api &wapi = appState.winApi;
  9111.             Win32OpenGLApi &glapi = glState.api;
  9112.  
  9113.             //
  9114.             // Create opengl rendering context
  9115.             //
  9116.             HDC deviceContext = windowState.deviceContext;
  9117.             HGLRC legacyRenderingContext = glapi.wglCreateContext(deviceContext);
  9118.             if(!legacyRenderingContext) {
  9119.                 common::PushError("Failed creating Legacy OpenGL Rendering Context for DC '%x')", deviceContext);
  9120.                 return false;
  9121.             }
  9122.  
  9123.             if(!glapi.wglMakeCurrent(deviceContext, legacyRenderingContext)) {
  9124.                 common::PushError("Failed activating Legacy OpenGL Rendering Context for DC '%x' and RC '%x')", deviceContext, legacyRenderingContext);
  9125.                 glapi.wglDeleteContext(legacyRenderingContext);
  9126.                 return false;
  9127.             }
  9128.  
  9129.             // Load WGL Extensions
  9130.             glapi.wglSwapIntervalExt = (win32_func_wglSwapIntervalEXT *)glapi.wglGetProcAddress("wglSwapIntervalEXT");
  9131.             glapi.wglChoosePixelFormatArb = (win32_func_wglChoosePixelFormatARB *)glapi.wglGetProcAddress("wglChoosePixelFormatARB");
  9132.             glapi.wglCreateContextAttribsArb = (win32_func_wglCreateContextAttribsARB *)glapi.wglGetProcAddress("wglCreateContextAttribsARB");
  9133.  
  9134.             // Disable legacy context
  9135.             glapi.wglMakeCurrent(nullptr, nullptr);
  9136.  
  9137.             HGLRC activeRenderingContext;
  9138.             if(videoSettings.graphics.opengl.compabilityFlags != OpenGLCompabilityFlags::Legacy) {
  9139.                 // @NOTE(final): This is only available in OpenGL 3.0+
  9140.                 if(!(videoSettings.graphics.opengl.majorVersion >= 3 && videoSettings.graphics.opengl.minorVersion >= 0)) {
  9141.                     common::PushError("You have not specified the 'majorVersion' and 'minorVersion' in the VideoSettings");
  9142.                     return false;
  9143.                 }
  9144.  
  9145.                 if(glapi.wglChoosePixelFormatArb == nullptr) {
  9146.                     common::PushError("wglChoosePixelFormatARB is not available, modern OpenGL is not available for your video card");
  9147.                     return false;
  9148.                 }
  9149.                 if(glapi.wglCreateContextAttribsArb == nullptr) {
  9150.                     common::PushError("wglCreateContextAttribsARB is not available, modern OpenGL is not available for your video card");
  9151.                     return false;
  9152.                 }
  9153.  
  9154.                 int profile = 0;
  9155.                 int flags = 0;
  9156.                 if(videoSettings.graphics.opengl.compabilityFlags & OpenGLCompabilityFlags::Core) {
  9157.                     profile = FPL_WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
  9158.                 } else if(videoSettings.graphics.opengl.compabilityFlags & OpenGLCompabilityFlags::Compability) {
  9159.                     profile = FPL_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
  9160.                 } else {
  9161.                     common::PushError("No opengl compability profile selected, please specific Core OpenGLCompabilityFlags::Core or OpenGLCompabilityFlags::Compability");
  9162.                     return false;
  9163.                 }
  9164.                 if(videoSettings.graphics.opengl.compabilityFlags & OpenGLCompabilityFlags::Forward) {
  9165.                     flags = FPL_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
  9166.                 }
  9167.  
  9168.                 int contextAttribIndex = 0;
  9169.                 int contextAttribList[20 + 1] = {};
  9170.                 contextAttribList[contextAttribIndex++] = FPL_WGL_CONTEXT_MAJOR_VERSION_ARB;
  9171.                 contextAttribList[contextAttribIndex++] = (int)videoSettings.graphics.opengl.majorVersion;
  9172.                 contextAttribList[contextAttribIndex++] = FPL_WGL_CONTEXT_MINOR_VERSION_ARB;
  9173.                 contextAttribList[contextAttribIndex++] = (int)videoSettings.graphics.opengl.minorVersion;
  9174.                 contextAttribList[contextAttribIndex++] = FPL_WGL_CONTEXT_PROFILE_MASK_ARB;
  9175.                 contextAttribList[contextAttribIndex++] = profile;
  9176.                 if(flags > 0) {
  9177.                     contextAttribList[contextAttribIndex++] = FPL_WGL_CONTEXT_FLAGS_ARB;
  9178.                     contextAttribList[contextAttribIndex++] = flags;
  9179.                 }
  9180.  
  9181.                 // Create modern opengl rendering context
  9182.                 HGLRC modernRenderingContext = glapi.wglCreateContextAttribsArb(deviceContext, 0, contextAttribList);
  9183.                 if(modernRenderingContext) {
  9184.                     if(!glapi.wglMakeCurrent(deviceContext, modernRenderingContext)) {
  9185.                         common::PushError("Warning: Failed activating Modern OpenGL Rendering Context for version (%d.%d) and compability flags (%d) and DC '%x') -> Fallback to legacy context", videoSettings.graphics.opengl.majorVersion, videoSettings.graphics.opengl.minorVersion, videoSettings.graphics.opengl.compabilityFlags, deviceContext);
  9186.  
  9187.                         glapi.wglDeleteContext(modernRenderingContext);
  9188.                         modernRenderingContext = nullptr;
  9189.  
  9190.                         // Fallback to legacy context
  9191.                         glapi.wglMakeCurrent(deviceContext, legacyRenderingContext);
  9192.                         activeRenderingContext = legacyRenderingContext;
  9193.                     } else {
  9194.                         // Destroy legacy rendering context
  9195.                         glapi.wglDeleteContext(legacyRenderingContext);
  9196.                         legacyRenderingContext = nullptr;
  9197.                         activeRenderingContext = modernRenderingContext;
  9198.                     }
  9199.                 } else {
  9200.                     common::PushError("Warning: Failed creating Modern OpenGL Rendering Context for version (%d.%d) and compability flags (%d) and DC '%x') -> Fallback to legacy context", videoSettings.graphics.opengl.majorVersion, videoSettings.graphics.opengl.minorVersion, videoSettings.graphics.opengl.compabilityFlags, deviceContext);
  9201.  
  9202.                     // Fallback to legacy context
  9203.                     glapi.wglMakeCurrent(deviceContext, legacyRenderingContext);
  9204.                     activeRenderingContext = legacyRenderingContext;
  9205.                 }
  9206.             } else {
  9207.                 // Caller wants legacy context
  9208.                 glapi.wglMakeCurrent(deviceContext, legacyRenderingContext);
  9209.                 activeRenderingContext = legacyRenderingContext;
  9210.             }
  9211.  
  9212.             FPL_ASSERT(activeRenderingContext != nullptr);
  9213.  
  9214.             glState.renderingContext = activeRenderingContext;
  9215.  
  9216.             // Set vertical syncronisation if available
  9217.             if(glapi.wglSwapIntervalExt != nullptr) {
  9218.                 int swapInterval = videoSettings.isVSync ? 1 : 0;
  9219.                 glapi.wglSwapIntervalExt(swapInterval);
  9220.             }
  9221.  
  9222.             return true;
  9223.         }
  9224.  
  9225.         fpl_internal void Win32ReleaseVideoOpenGL(Win32VideoOpenGLState &glState) {
  9226.             const Win32OpenGLApi &glapi = glState.api;
  9227.             if(glState.renderingContext) {
  9228.                 glapi.wglMakeCurrent(nullptr, nullptr);
  9229.                 glapi.wglDeleteContext(glState.renderingContext);
  9230.                 glState.renderingContext = nullptr;
  9231.             }
  9232.         }
  9233. #   endif // FPL_PLATFORM_WIN32
  9234. #endif // FPL_ENABLE_VIDEO_OPENGL
  9235.  
  9236. // ############################################################################
  9237. //
  9238. // > VIDEO_DRIVER_OPENGL_X11
  9239. //
  9240. // ############################################################################
  9241. #if defined(FPL_ENABLE_VIDEO_OPENGL)
  9242. #   if defined(FPL_SUBPLATFORM_X11)
  9243.         // GLX function prototypes
  9244. #       define FPL_FUNC_GL_X_CHOOSE_VISUAL(name) XVisualInfo* name(Display *dpy, int screen, int *attribList)
  9245.         typedef FPL_FUNC_GL_X_CHOOSE_VISUAL(fpl_func_glx_glXChooseVisual);
  9246. #       define FPL_FUNC_GL_X_CREATE_CONTEXT(name) GLXContext name(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct)
  9247.         typedef FPL_FUNC_GL_X_CREATE_CONTEXT(fpl_func_glx_glXCreateContext);
  9248. #       define FPL_FUNC_GL_X_CREATE_NEW_CONTEXT(name) GLXContext name(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
  9249.         typedef FPL_FUNC_GL_X_CREATE_NEW_CONTEXT(fpl_func_glx_glXCreateNewContext);
  9250. #       define FPL_FUNC_GL_X_DESTROY_CONTEXT(name) void name(Display *dpy, GLXContext ctx)
  9251.         typedef FPL_FUNC_GL_X_DESTROY_CONTEXT(fpl_func_glx_glXDestroyContext);
  9252. #       define FPL_FUNC_GL_X_MAKE_CURRENT(name) Bool name(Display *dpy, GLXDrawable drawable, GLXContext ctx)
  9253.         typedef FPL_FUNC_GL_X_MAKE_CURRENT(fpl_func_glx_glXMakeCurrent);
  9254. #       define FPL_FUNC_GL_X_SWAP_BUFFERS(name) void name(Display *dpy, GLXDrawable drawable)
  9255.         typedef FPL_FUNC_GL_X_SWAP_BUFFERS(fpl_func_glx_glXSwapBuffers);
  9256. #       define FPL_FUNC_GL_X_GET_PROC_ADDRESS(name) void *name(const GLubyte *procname)
  9257.         typedef FPL_FUNC_GL_X_GET_PROC_ADDRESS(fpl_func_glx_glXGetProcAddress);
  9258. #       define FPL_FUNC_GL_X_CHOOSE_FB_CONFIG(name) GLXFBConfig *name(Display *dpy, int screen, const int *attrib_list,  int *nelements)
  9259.         typedef FPL_FUNC_GL_X_CHOOSE_FB_CONFIG(fpl_func_glx_glXChooseFBConfig);
  9260. #       define FPL_FUNC_GL_X_GET_FB_CONFIGS(name) GLXFBConfig *name(Display *dpy, int screen, int *nelements)
  9261.         typedef FPL_FUNC_GL_X_GET_FB_CONFIGS(fpl_func_glx_glXGetFBConfigs);
  9262. #       define FPL_FUNC_GL_X_GET_VISUAL_FROM_FB_CONFIG(name) XVisualInfo *name(Display *dpy, GLXFBConfig config)
  9263.         typedef FPL_FUNC_GL_X_GET_VISUAL_FROM_FB_CONFIG(fpl_func_glx_glXGetVisualFromFBConfig);
  9264. #       define FPL_FUNC_GL_X_GET_FB_CONFIG_ATTRIB(name) int name(Display *dpy, GLXFBConfig config, int attribute, int *value)
  9265.         typedef FPL_FUNC_GL_X_GET_FB_CONFIG_ATTRIB(fpl_func_glx_glXGetFBConfigAttrib);
  9266. #       define FPL_FUNC_GL_X_CREATE_WINDOW(name) GLXWindow name(Display *dpy, GLXFBConfig config, Window win,  const int *attrib_list)
  9267.         typedef FPL_FUNC_GL_X_CREATE_WINDOW(fpl_func_glx_glXCreateWindow);
  9268. #       define FPL_FUNC_GL_X_QUERY_EXTENSION(name) Bool name(Display *dpy,  int *errorBase,  int *eventBase)
  9269.         typedef FPL_FUNC_GL_X_QUERY_EXTENSION(fpl_func_glx_glXQueryExtension);
  9270.  
  9271.         struct X11VideoOpenGLApi {
  9272.             void *libHandle;
  9273.             fpl_func_glx_glXChooseVisual *glXChooseVisual;
  9274.             fpl_func_glx_glXCreateContext *glXCreateContext;
  9275.             fpl_func_glx_glXDestroyContext *glXDestroyContext;
  9276.             fpl_func_glx_glXCreateNewContext *glXCreateNewContext;
  9277.             fpl_func_glx_glXMakeCurrent *glXMakeCurrent;
  9278.             fpl_func_glx_glXSwapBuffers *glXSwapBuffers;
  9279.             fpl_func_glx_glXGetProcAddress *glXGetProcAddress;
  9280.             fpl_func_glx_glXChooseFBConfig *glXChooseFBConfig;
  9281.             fpl_func_glx_glXGetFBConfigs *glXGetFBConfigs;
  9282.             fpl_func_glx_glXGetVisualFromFBConfig *glXGetVisualFromFBConfig;
  9283.             fpl_func_glx_glXGetFBConfigAttrib *glXGetFBConfigAttrib;
  9284.             fpl_func_glx_glXCreateWindow *glXCreateWindow;
  9285.             fpl_func_glx_glXQueryExtension *glXQueryExtension;
  9286.         };
  9287.  
  9288.         fpl_internal void X11UnloadVideoOpenGLApi(X11VideoOpenGLApi &api) {
  9289.             FPL_LOG_BLOCK;
  9290.  
  9291.             if(api.libHandle != nullptr) {
  9292.                 FPL_LOG("GLX", "Unload Api (Library '%p')", api.libHandle);
  9293.                 ::dlclose(api.libHandle);
  9294.             }
  9295.             api = {};
  9296.         }
  9297.  
  9298.         fpl_internal bool X11LoadVideoOpenGLApi(X11VideoOpenGLApi &api) {
  9299.             FPL_LOG_BLOCK;
  9300.  
  9301.             const char* libFileNames[] = {
  9302.                 "libGLX.so",
  9303.                 "libGLX.so.0",
  9304.             };
  9305.             bool result = false;
  9306.             for(uint32_t index = 0; index < FPL_ARRAYCOUNT(libFileNames); ++index) {
  9307.                 const char *libName = libFileNames[index];
  9308.                 FPL_LOG("GLX", "Load GLX Api from Library: %s", libName);
  9309.                 void *libHandle = api.libHandle = ::dlopen(libName, subplatform_posix::DL_LOADTYPE);
  9310.                 if(libHandle != nullptr) {
  9311.                     FPL_LOG("GLX", "Library Found: '%s', Resolving Procedures", libName);
  9312.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXChooseVisual, fpl_func_glx_glXChooseVisual, "glXChooseVisual");
  9313.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXCreateContext, fpl_func_glx_glXCreateContext, "glXCreateContext");
  9314.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXDestroyContext, fpl_func_glx_glXDestroyContext, "glXDestroyContext");
  9315.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXCreateNewContext, fpl_func_glx_glXCreateNewContext, "glXCreateNewContext");
  9316.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXMakeCurrent, fpl_func_glx_glXMakeCurrent, "glXMakeCurrent");
  9317.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXSwapBuffers, fpl_func_glx_glXSwapBuffers, "glXSwapBuffers");
  9318.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXGetProcAddress, fpl_func_glx_glXGetProcAddress, "glXGetProcAddress");
  9319.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXChooseFBConfig, fpl_func_glx_glXChooseFBConfig, "glXChooseFBConfig");
  9320.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXGetFBConfigs, fpl_func_glx_glXGetFBConfigs, "glXGetFBConfigs");
  9321.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXGetVisualFromFBConfig, fpl_func_glx_glXGetVisualFromFBConfig, "glXGetVisualFromFBConfig");
  9322.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXGetFBConfigAttrib, fpl_func_glx_glXGetFBConfigAttrib, "glXGetFBConfigAttrib");
  9323.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXCreateWindow, fpl_func_glx_glXCreateWindow, "glXCreateWindow");
  9324.                     FPL_POSIX_GET_FUNCTION_ADDRESS_BREAK(libHandle, libName, api.glXQueryExtension, fpl_func_glx_glXQueryExtension, "glXQueryExtension");
  9325.                     FPL_LOG("GLX", "Successfully loaded GLX Api from Library '%s'", libName);
  9326.                     result = true;
  9327.                     break;
  9328.                 }
  9329.                 X11UnloadVideoOpenGLApi(api);
  9330.             }
  9331.             return (result);
  9332.         }
  9333.  
  9334.         struct X11VideoOpenGLVisual {
  9335.             XVisualInfo *visualInfo;
  9336.         };
  9337.  
  9338.         struct X11VideoOpenGLState {
  9339.             X11VideoOpenGLApi api;
  9340.             X11VideoOpenGLVisual visual;
  9341.             GLXContext context;
  9342.             bool isActiveContext;
  9343.         };
  9344.  
  9345.         fpl_internal void X11ReleaseVisualForVideoOpenGL(const subplatform_x11::X11Api &x11Api, X11VideoOpenGLVisual &visual) {
  9346.             if(visual.visualInfo != nullptr) {
  9347.                 x11Api.XFree(visual.visualInfo);
  9348.                 visual.visualInfo = nullptr;
  9349.             }
  9350.         }
  9351.  
  9352.         fpl_internal bool X11InitVisualForVideoOpenGL(const subplatform_x11::X11Api &x11Api, const subplatform_x11::X11WindowState &windowState, const X11VideoOpenGLApi &glApi, X11VideoOpenGLVisual &visual) {
  9353.             FPL_ASSERT(visual.visualInfo == nullptr);
  9354.  
  9355.             int attr[32];
  9356.             int* p = attr;
  9357.             *p++ = GLX_X_VISUAL_TYPE; *p++ = GLX_TRUE_COLOR;
  9358.             *p++ = GLX_DOUBLEBUFFER;  *p++ = True;
  9359.             *p++ = GLX_RED_SIZE;      *p++ = 8;
  9360.             *p++ = GLX_GREEN_SIZE;    *p++ = 8;
  9361.             *p++ = GLX_BLUE_SIZE;     *p++ = 8;
  9362.             *p++ = GLX_DEPTH_SIZE;    *p++ = 24;
  9363.             *p++ = GLX_STENCIL_SIZE;  *p++ = 8;
  9364.             *p++ = 0;
  9365.  
  9366.             int configCount = 0;
  9367.             GLXFBConfig *configs = glApi.glXChooseFBConfig(windowState.display, windowState.screen, attr, &configCount);
  9368.             if(configs == nullptr || !configCount) {
  9369.                 X11ReleaseVisualForVideoOpenGL(x11Api, visual);
  9370.                 return false;
  9371.             }
  9372.  
  9373.             GLXFBConfig firstConfig = configs[0];
  9374.             XVisualInfo *visualInfo = glApi.glXGetVisualFromFBConfig(windowState.display, firstConfig);
  9375.             x11Api.XFree(configs);
  9376.  
  9377.             if(visualInfo == nullptr) {
  9378.                 X11ReleaseVisualForVideoOpenGL(x11Api, visual);
  9379.                 return false;
  9380.             }
  9381.            
  9382.             visual.visualInfo = visualInfo;
  9383.  
  9384.             return true;
  9385.         }
  9386.  
  9387.         fpl_internal void X11ReleaseVideoOpenGL(const subplatform_x11::X11WindowState &windowState, X11VideoOpenGLState &glState) {
  9388.             // @NOTE(final): Visual is released before the api is released.
  9389.             // Do never release it here!
  9390.  
  9391.             const X11VideoOpenGLApi &glApi = glState.api;
  9392.  
  9393.             if(glState.isActiveContext) {
  9394.                 glApi.glXMakeCurrent(windowState.display, 0, nullptr);
  9395.                 glState.isActiveContext = false;
  9396.             }
  9397.  
  9398.             if(glState.context != nullptr) {
  9399.                 glApi.glXDestroyContext(windowState.display, glState.context);
  9400.                 glState.context = nullptr;
  9401.             }
  9402.         }
  9403.  
  9404.         fpl_internal bool X11InitVideoOpenGL(const subplatform_x11::X11SubplatformState &subplatform, const subplatform_x11::X11WindowState &windowState, const VideoSettings &videoSettings, X11VideoOpenGLState &glState) {
  9405.             const X11VideoOpenGLApi &glApi = glState.api;
  9406.             const X11VideoOpenGLVisual &vis = glState.visual;
  9407.  
  9408.             if(vis.visualInfo == nullptr) {
  9409.                 return false;
  9410.             }
  9411.  
  9412.             glState.context = glApi.glXCreateContext(windowState.display, vis.visualInfo, nullptr, GL_TRUE);
  9413.             if(glState.context == nullptr) {
  9414.                 return false;
  9415.             }
  9416.  
  9417.             if(!glApi.glXMakeCurrent(windowState.display, windowState.window, glState.context)) {
  9418.                 X11ReleaseVideoOpenGL(windowState, glState);
  9419.                 return false;
  9420.             }
  9421.  
  9422.             glState.isActiveContext = true;
  9423.  
  9424.             return true;
  9425.         }
  9426. #   endif // FPL_SUBPLATFORM_X11
  9427.  
  9428. #endif // FPL_ENABLE_VIDEO_OPENGL
  9429.  
  9430. #   if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  9431.  
  9432. // ############################################################################
  9433. //
  9434. // > VIDEO_DRIVER_SOFTWARE_WIN32
  9435. //
  9436. // ############################################################################
  9437. #       if defined(FPL_PLATFORM_WIN32)
  9438.         struct Win32VideoSoftwareState {
  9439.             BITMAPINFO bitmapInfo;
  9440.         };
  9441.  
  9442.         fpl_internal bool Win32InitVideoSoftware(const video::VideoBackBuffer &backbuffer, Win32VideoSoftwareState &software) {
  9443.             software = {};
  9444.             software.bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  9445.             software.bitmapInfo.bmiHeader.biWidth = (LONG)backbuffer.width;
  9446.             software.bitmapInfo.bmiHeader.biHeight = (LONG)backbuffer.height;
  9447.             software.bitmapInfo.bmiHeader.biBitCount = 32;
  9448.             software.bitmapInfo.bmiHeader.biCompression = BI_RGB;
  9449.             software.bitmapInfo.bmiHeader.biPlanes = 1;
  9450.             software.bitmapInfo.bmiHeader.biSizeImage = (DWORD)(backbuffer.height * backbuffer.lineWidth);
  9451.             return true;
  9452.         }
  9453.  
  9454.         fpl_internal void Win32ReleaseVideoSoftware(Win32VideoSoftwareState &softwareState) {
  9455.             softwareState = {};
  9456.         }
  9457. #       endif // FPL_PLATFORM_WIN32
  9458.  
  9459. #   endif // FPL_ENABLE_VIDEO_SOFTWARE
  9460.     }
  9461. }
  9462. #endif // FPL_VIDEO_DRIVERS_IMPLEMENTED
  9463.  
  9464. // ****************************************************************************
  9465. //
  9466. // > AUDIO_DRIVERS
  9467. //
  9468. // ****************************************************************************
  9469. #if !defined(FPL_AUDIO_DRIVERS_IMPLEMENTED)
  9470. #   define FPL_AUDIO_DRIVERS_IMPLEMENTED
  9471.  
  9472. // ############################################################################
  9473. //
  9474. // > AUDIO_DRIVER_DIRECTSOUND
  9475. //
  9476. // ############################################################################
  9477. #if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  9478. #   include <mmreg.h>
  9479. #   include <dsound.h>
  9480. #endif
  9481. namespace fpl {
  9482.     namespace drivers {
  9483.  
  9484. #   if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  9485.         //
  9486.         // DirectSound
  9487.         //
  9488. #       define FPL_FUNC_DIRECT_SOUND_CREATE(name) HRESULT WINAPI name(const GUID* pcGuidDevice, LPDIRECTSOUND *ppDS8, LPUNKNOWN pUnkOuter)
  9489.         typedef FPL_FUNC_DIRECT_SOUND_CREATE(func_DirectSoundCreate);
  9490. #       define FPL_FUNC_DIRECT_SOUND_ENUMERATE_A(name) HRESULT WINAPI name(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext)
  9491.         typedef FPL_FUNC_DIRECT_SOUND_ENUMERATE_A(func_DirectSoundEnumerateA);
  9492.  
  9493.         fpl_constant GUID FPL_IID_IDirectSoundNotify = { 0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16} };
  9494.  
  9495.         fpl_constant uint32_t FPL_DIRECTSOUND_MAX_PERIODS = 4;
  9496.  
  9497.         struct DirectSoundState {
  9498.             HMODULE dsoundLibrary;
  9499.             LPDIRECTSOUND directSound;
  9500.             LPDIRECTSOUNDBUFFER primaryBuffer;
  9501.             LPDIRECTSOUNDBUFFER secondaryBuffer;
  9502.             LPDIRECTSOUNDNOTIFY notify;
  9503.             HANDLE notifyEvents[FPL_DIRECTSOUND_MAX_PERIODS];
  9504.             HANDLE stopEvent;
  9505.             uint32_t lastProcessedFrame;
  9506.             bool breakMainLoop;
  9507.         };
  9508.  
  9509.         struct DirectSoundDeviceInfos {
  9510.             uint32_t foundDeviceCount;
  9511.             AudioDeviceInfo *deviceInfos;
  9512.             uint32_t maxDeviceCount;
  9513.         };
  9514.  
  9515.         fpl_internal BOOL CALLBACK GetDeviceCallbackDirectSound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext) {
  9516.             (void)lpcstrModule;
  9517.  
  9518.             DirectSoundDeviceInfos *infos = (DirectSoundDeviceInfos *)lpContext;
  9519.             FPL_ASSERT(infos != nullptr);
  9520.             if(infos->deviceInfos != nullptr) {
  9521.                 uint32_t index = infos->foundDeviceCount++;
  9522.                 if(index < infos->maxDeviceCount) {
  9523.                     AudioDeviceInfo *deviceInfo = infos->deviceInfos + index;
  9524.                     *deviceInfo = {};
  9525.                     strings::CopyAnsiString(lpcstrDescription, deviceInfo->name, FPL_ARRAYCOUNT(deviceInfo->name));
  9526.                     if(lpGuid != nullptr) {
  9527.                         memory::MemoryCopy(lpGuid, sizeof(deviceInfo->id.dshow), &deviceInfo->id.dshow);
  9528.                     }
  9529.                     return TRUE;
  9530.                 }
  9531.             }
  9532.             return FALSE;
  9533.         }
  9534.  
  9535.         fpl_internal uint32_t GetDevicesDirectSound(DirectSoundState &dsoundState, AudioDeviceInfo *deviceInfos, uint32_t maxDeviceCount) {
  9536.             uint32_t result = 0;
  9537.             func_DirectSoundEnumerateA *directSoundEnumerateA = (func_DirectSoundEnumerateA *)::GetProcAddress(dsoundState.dsoundLibrary, "DirectSoundEnumerateA");
  9538.             if(directSoundEnumerateA != nullptr) {
  9539.                 DirectSoundDeviceInfos infos = {};
  9540.                 infos.maxDeviceCount = maxDeviceCount;
  9541.                 infos.deviceInfos = deviceInfos;
  9542.                 directSoundEnumerateA(GetDeviceCallbackDirectSound, &infos);
  9543.                 result = infos.foundDeviceCount;
  9544.             }
  9545.             return(result);
  9546.         }
  9547.  
  9548.         fpl_internal bool ReleaseDirectSound(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9549.             if(dsoundState.dsoundLibrary != nullptr) {
  9550.                 if(dsoundState.stopEvent != nullptr) {
  9551.                     ::CloseHandle(dsoundState.stopEvent);
  9552.                 }
  9553.  
  9554.                 for(uint32_t i = 0; i < commonAudio.internalFormat.periods; ++i) {
  9555.                     if(dsoundState.notifyEvents[i]) {
  9556.                         ::CloseHandle(dsoundState.notifyEvents[i]);
  9557.                     }
  9558.                 }
  9559.  
  9560.                 if(dsoundState.notify != nullptr) {
  9561.                     dsoundState.notify->Release();
  9562.                 }
  9563.  
  9564.                 if(dsoundState.secondaryBuffer != nullptr) {
  9565.                     dsoundState.secondaryBuffer->Release();
  9566.                 }
  9567.  
  9568.                 if(dsoundState.primaryBuffer != nullptr) {
  9569.                     dsoundState.primaryBuffer->Release();
  9570.                 }
  9571.  
  9572.                 if(dsoundState.directSound != nullptr) {
  9573.                     dsoundState.directSound->Release();
  9574.                 }
  9575.  
  9576.                 ::FreeLibrary(dsoundState.dsoundLibrary);
  9577.                 dsoundState = {};
  9578.             }
  9579.  
  9580.             return true;
  9581.         }
  9582.  
  9583.         fpl_internal audio::AudioResult InitDirectSound(const AudioSettings &audioSettings, common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9584.             FPL_ASSERT(platform::global__AppState != nullptr);
  9585.             platform::PlatformAppState *appState = platform::global__AppState;
  9586.             platform_win32::Win32AppState &win32AppState = appState->win32;
  9587.             const platform_win32::Win32Api &apiFuncs = win32AppState.winApi;
  9588.  
  9589.             // Load direct sound library
  9590.             dsoundState.dsoundLibrary = ::LoadLibraryA("dsound.dll");
  9591.             func_DirectSoundCreate *directSoundCreate = (func_DirectSoundCreate *)::GetProcAddress(dsoundState.dsoundLibrary, "DirectSoundCreate");
  9592.             if(directSoundCreate == nullptr) {
  9593.                 ReleaseDirectSound(commonAudio, dsoundState);
  9594.                 return audio::AudioResult::Failed;
  9595.             }
  9596.  
  9597.             // Load direct sound object
  9598.             const GUID *deviceId = nullptr;
  9599.             if(strings::GetAnsiStringLength(audioSettings.deviceInfo.name) > 0) {
  9600.                 deviceId = &audioSettings.deviceInfo.id.dshow;
  9601.             }
  9602.             if(!SUCCEEDED(directSoundCreate(deviceId, &dsoundState.directSound, nullptr))) {
  9603.                 ReleaseDirectSound(commonAudio, dsoundState);
  9604.                 return audio::AudioResult::Failed;
  9605.             }
  9606.  
  9607.             // Setup wave format ex
  9608.             WAVEFORMATEXTENSIBLE wf = {};
  9609.             wf.Format.cbSize = sizeof(wf);
  9610.             wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  9611.             wf.Format.nChannels = (WORD)audioSettings.deviceFormat.channels;
  9612.             wf.Format.nSamplesPerSec = (DWORD)audioSettings.deviceFormat.sampleRate;
  9613.             wf.Format.wBitsPerSample = audio::GetAudioSampleSizeInBytes(audioSettings.deviceFormat.type) * 8;
  9614.             wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
  9615.             wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
  9616.             wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
  9617.             if((audioSettings.deviceFormat.type == AudioFormatType::F32) || (audioSettings.deviceFormat.type == AudioFormatType::F64)) {
  9618.                 wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  9619.             } else {
  9620.                 wf.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  9621.             }
  9622.  
  9623.             // Get either local window handle or desktop handle
  9624.             HWND windowHandle = nullptr;
  9625. #       if defined(FPL_ENABLE_WINDOW)
  9626.             if(appState->initFlags & InitFlags::Window) {
  9627.                 windowHandle = appState->window.win32.windowHandle;
  9628.             }
  9629. #       endif
  9630.             if(windowHandle == nullptr) {
  9631.                 windowHandle = apiFuncs.user.getDesktopWindow();
  9632.             }
  9633.  
  9634.             // The cooperative level must be set before doing anything else
  9635.             if(FAILED(dsoundState.directSound->SetCooperativeLevel(windowHandle, (audioSettings.preferExclusiveMode) ? DSSCL_EXCLUSIVE : DSSCL_PRIORITY))) {
  9636.                 ReleaseDirectSound(commonAudio, dsoundState);
  9637.                 return audio::AudioResult::Failed;
  9638.             }
  9639.  
  9640.             // Create primary buffer
  9641.             DSBUFFERDESC descDSPrimary = {};
  9642.             descDSPrimary.dwSize = sizeof(DSBUFFERDESC);
  9643.             descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
  9644.             if(FAILED(dsoundState.directSound->CreateSoundBuffer(&descDSPrimary, &dsoundState.primaryBuffer, nullptr))) {
  9645.                 ReleaseDirectSound(commonAudio, dsoundState);
  9646.                 return audio::AudioResult::Failed;
  9647.             }
  9648.  
  9649.             // Set format
  9650.             if(FAILED(dsoundState.primaryBuffer->SetFormat((WAVEFORMATEX*)&wf))) {
  9651.                 ReleaseDirectSound(commonAudio, dsoundState);
  9652.                 return audio::AudioResult::Failed;
  9653.             }
  9654.  
  9655.             // Get the required size in bytes
  9656.             DWORD requiredSize;
  9657.             if(FAILED(dsoundState.primaryBuffer->GetFormat(nullptr, 0, &requiredSize))) {
  9658.                 ReleaseDirectSound(commonAudio, dsoundState);
  9659.                 return audio::AudioResult::Failed;
  9660.             }
  9661.  
  9662.             // Get actual format
  9663.             char rawdata[1024];
  9664.             WAVEFORMATEXTENSIBLE* pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
  9665.             if(FAILED(dsoundState.primaryBuffer->GetFormat((WAVEFORMATEX*)pActualFormat, requiredSize, nullptr))) {
  9666.                 ReleaseDirectSound(commonAudio, dsoundState);
  9667.                 return audio::AudioResult::Failed;
  9668.             }
  9669.  
  9670.             // Set internal format
  9671.             AudioDeviceFormat internalFormat = {};
  9672.             if(IsEqualGUID(pActualFormat->SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
  9673.                 if(pActualFormat->Format.wBitsPerSample == 64) {
  9674.                     internalFormat.type = AudioFormatType::F64;
  9675.                 } else {
  9676.                     internalFormat.type = AudioFormatType::F32;
  9677.                 }
  9678.             } else {
  9679.                 switch(pActualFormat->Format.wBitsPerSample) {
  9680.                     case 8:
  9681.                         internalFormat.type = AudioFormatType::U8;
  9682.                         break;
  9683.                     case 16:
  9684.                         internalFormat.type = AudioFormatType::S16;
  9685.                         break;
  9686.                     case 24:
  9687.                         internalFormat.type = AudioFormatType::S24;
  9688.                         break;
  9689.                     case 32:
  9690.                         internalFormat.type = AudioFormatType::S32;
  9691.                         break;
  9692.                     case 64:
  9693.                         internalFormat.type = AudioFormatType::S64;
  9694.                         break;
  9695.                 }
  9696.             }
  9697.             internalFormat.channels = pActualFormat->Format.nChannels;
  9698.             internalFormat.sampleRate = pActualFormat->Format.nSamplesPerSec;
  9699.  
  9700.             // @NOTE(final): We divide up our playback buffer into this number of periods and let directsound notify us when one of it needs to play.
  9701.             internalFormat.periods = 2;
  9702.             internalFormat.bufferSizeInFrames = audio::GetAudioBufferSizeInFrames(internalFormat.sampleRate, audioSettings.bufferSizeInMilliSeconds);
  9703.             internalFormat.bufferSizeInBytes = internalFormat.bufferSizeInFrames * internalFormat.channels * audio::GetAudioSampleSizeInBytes(internalFormat.type);
  9704.  
  9705.             commonAudio.internalFormat = internalFormat;
  9706.  
  9707.             // Create secondary buffer
  9708.             DSBUFFERDESC descDS = {};
  9709.             descDS.dwSize = sizeof(DSBUFFERDESC);
  9710.             descDS.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
  9711.             descDS.dwBufferBytes = (DWORD)internalFormat.bufferSizeInBytes;
  9712.             descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
  9713.             if(FAILED(dsoundState.directSound->CreateSoundBuffer(&descDS, &dsoundState.secondaryBuffer, nullptr))) {
  9714.                 ReleaseDirectSound(commonAudio, dsoundState);
  9715.                 return audio::AudioResult::Failed;
  9716.             }
  9717.  
  9718.             // Notifications are set up via a DIRECTSOUNDNOTIFY object which is retrieved from the buffer.
  9719.             if(FAILED(dsoundState.secondaryBuffer->QueryInterface(FPL_IID_IDirectSoundNotify, (void**)&dsoundState.notify))) {
  9720.                 ReleaseDirectSound(commonAudio, dsoundState);
  9721.                 return audio::AudioResult::Failed;
  9722.             }
  9723.  
  9724.             // Setup notifications
  9725.             uint32_t periodSizeInBytes = internalFormat.bufferSizeInBytes / internalFormat.periods;
  9726.             DSBPOSITIONNOTIFY notifyPoints[FPL_DIRECTSOUND_MAX_PERIODS];
  9727.             for(uint32_t i = 0; i < internalFormat.periods; ++i) {
  9728.                 dsoundState.notifyEvents[i] = CreateEventA(nullptr, false, false, nullptr);
  9729.                 if(dsoundState.notifyEvents[i] == nullptr) {
  9730.                     ReleaseDirectSound(commonAudio, dsoundState);
  9731.                     return audio::AudioResult::Failed;
  9732.                 }
  9733.  
  9734.                 // The notification offset is in bytes.
  9735.                 notifyPoints[i].dwOffset = i * periodSizeInBytes;
  9736.                 notifyPoints[i].hEventNotify = dsoundState.notifyEvents[i];
  9737.             }
  9738.             if(FAILED(dsoundState.notify->SetNotificationPositions(internalFormat.periods, notifyPoints))) {
  9739.                 ReleaseDirectSound(commonAudio, dsoundState);
  9740.                 return audio::AudioResult::Failed;
  9741.             }
  9742.  
  9743.             // Create stop event
  9744.             dsoundState.stopEvent = ::CreateEventA(nullptr, false, false, nullptr);
  9745.             if(dsoundState.stopEvent == nullptr) {
  9746.                 ReleaseDirectSound(commonAudio, dsoundState);
  9747.                 return audio::AudioResult::Failed;
  9748.             }
  9749.  
  9750.             return audio::AudioResult::Success;
  9751.         }
  9752.  
  9753.         fpl_internal_inline void StopMainLoopDirectSound(DirectSoundState &dsoundState) {
  9754.             dsoundState.breakMainLoop = true;
  9755.             ::SetEvent(dsoundState.stopEvent);
  9756.         }
  9757.  
  9758.         fpl_internal bool GetCurrentFrameDirectSound(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState, uint32_t* pCurrentPos) {
  9759.             FPL_ASSERT(pCurrentPos != nullptr);
  9760.             *pCurrentPos = 0;
  9761.  
  9762.             FPL_ASSERT(dsoundState.secondaryBuffer != nullptr);
  9763.             DWORD dwCurrentPosition;
  9764.             if(FAILED(dsoundState.secondaryBuffer->GetCurrentPosition(nullptr, &dwCurrentPosition))) {
  9765.                 return false;
  9766.             }
  9767.  
  9768.             FPL_ASSERT(commonAudio.internalFormat.channels > 0);
  9769.             *pCurrentPos = (uint32_t)dwCurrentPosition / audio::GetAudioSampleSizeInBytes(commonAudio.internalFormat.type) / commonAudio.internalFormat.channels;
  9770.             return true;
  9771.         }
  9772.  
  9773.         fpl_internal uint32_t GetAvailableFramesDirectSound(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9774.             // Get current frame from current play position
  9775.             uint32_t currentFrame;
  9776.             if(!GetCurrentFrameDirectSound(commonAudio, dsoundState, &currentFrame)) {
  9777.                 return 0;
  9778.             }
  9779.  
  9780.             // In a playback device the last processed frame should always be ahead of the current frame. The space between
  9781.             // the last processed and current frame (moving forward, starting from the last processed frame) is the amount
  9782.             // of space available to write.
  9783.             uint32_t totalFrameCount = commonAudio.internalFormat.bufferSizeInFrames;
  9784.             uint32_t committedBeg = currentFrame;
  9785.             uint32_t committedEnd;
  9786.             committedEnd = dsoundState.lastProcessedFrame;
  9787.             if(committedEnd <= committedBeg) {
  9788.                 committedEnd += totalFrameCount;
  9789.             }
  9790.  
  9791.             uint32_t committedSize = (committedEnd - committedBeg);
  9792.             FPL_ASSERT(committedSize <= totalFrameCount);
  9793.  
  9794.             return totalFrameCount - committedSize;
  9795.         }
  9796.  
  9797.         fpl_internal uint32_t WaitForFramesDirectSound(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9798.             FPL_ASSERT(commonAudio.internalFormat.sampleRate > 0);
  9799.             FPL_ASSERT(commonAudio.internalFormat.periods > 0);
  9800.  
  9801.             // The timeout to use for putting the thread to sleep is based on the size of the buffer and the period count.
  9802.             DWORD timeoutInMilliseconds = (commonAudio.internalFormat.bufferSizeInFrames / (commonAudio.internalFormat.sampleRate / 1000)) / commonAudio.internalFormat.periods;
  9803.             if(timeoutInMilliseconds < 1) {
  9804.                 timeoutInMilliseconds = 1;
  9805.             }
  9806.  
  9807.             // Copy event handles so we can wait for each one
  9808.             unsigned int eventCount = commonAudio.internalFormat.periods + 1;
  9809.             HANDLE pEvents[FPL_DIRECTSOUND_MAX_PERIODS + 1]; // +1 for the stop event.
  9810.             memory::MemoryCopy(dsoundState.notifyEvents, sizeof(HANDLE) * commonAudio.internalFormat.periods, pEvents);
  9811.             pEvents[eventCount - 1] = dsoundState.stopEvent;
  9812.  
  9813.             while(!dsoundState.breakMainLoop) {
  9814.                 // Get available frames from directsound
  9815.                 uint32_t framesAvailable = GetAvailableFramesDirectSound(commonAudio, dsoundState);
  9816.                 if(framesAvailable > 0) {
  9817.                     return framesAvailable;
  9818.                 }
  9819.  
  9820.                 // If we get here it means we weren't able to find any frames. We'll just wait here for a bit.
  9821.                 ::WaitForMultipleObjects(eventCount, pEvents, FALSE, timeoutInMilliseconds);
  9822.             }
  9823.  
  9824.             // We'll get here if the loop was terminated. Just return whatever's available.
  9825.             return GetAvailableFramesDirectSound(commonAudio, dsoundState);
  9826.         }
  9827.  
  9828.         fpl_internal bool StopDirectSound(DirectSoundState &dsoundState) {
  9829.             FPL_ASSERT(dsoundState.secondaryBuffer != nullptr);
  9830.             if(FAILED(dsoundState.secondaryBuffer->Stop())) {
  9831.                 return false;
  9832.             }
  9833.             dsoundState.secondaryBuffer->SetCurrentPosition(0);
  9834.             return true;
  9835.         }
  9836.  
  9837.         fpl_internal audio::AudioResult StartDirectSound(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9838.             FPL_ASSERT(commonAudio.internalFormat.channels > 0);
  9839.             FPL_ASSERT(commonAudio.internalFormat.periods > 0);
  9840.             uint32_t audioSampleSizeBytes = audio::GetAudioSampleSizeInBytes(commonAudio.internalFormat.type);
  9841.             FPL_ASSERT(audioSampleSizeBytes > 0);
  9842.  
  9843.             // Before playing anything we need to grab an initial group of samples from the client.
  9844.             uint32_t framesToRead = commonAudio.internalFormat.bufferSizeInFrames / commonAudio.internalFormat.periods;
  9845.             uint32_t desiredLockSize = framesToRead * commonAudio.internalFormat.channels * audioSampleSizeBytes;
  9846.  
  9847.             void* pLockPtr;
  9848.             DWORD actualLockSize;
  9849.             void* pLockPtr2;
  9850.             DWORD actualLockSize2;
  9851.             if(SUCCEEDED(dsoundState.secondaryBuffer->Lock(0, desiredLockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) {
  9852.                 framesToRead = actualLockSize / audioSampleSizeBytes / commonAudio.internalFormat.channels;
  9853.                 common::ReadAudioFramesFromClient(commonAudio, framesToRead, pLockPtr);
  9854.                 dsoundState.secondaryBuffer->Unlock(pLockPtr, actualLockSize, pLockPtr2, actualLockSize2);
  9855.                 dsoundState.lastProcessedFrame = framesToRead;
  9856.                 if(FAILED(dsoundState.secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING))) {
  9857.                     return audio::AudioResult::Failed;
  9858.                 }
  9859.             } else {
  9860.                 return audio::AudioResult::Failed;
  9861.             }
  9862.             return audio::AudioResult::Success;
  9863.         }
  9864.  
  9865.         fpl_internal void DirectSoundMainLoop(const common::CommonAudioState &commonAudio, DirectSoundState &dsoundState) {
  9866.             FPL_ASSERT(commonAudio.internalFormat.channels > 0);
  9867.             uint32_t audioSampleSizeBytes = audio::GetAudioSampleSizeInBytes(commonAudio.internalFormat.type);
  9868.             FPL_ASSERT(audioSampleSizeBytes > 0);
  9869.  
  9870.             // Make sure the stop event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects().
  9871.             ::ResetEvent(dsoundState.stopEvent);
  9872.  
  9873.             // Main loop
  9874.             dsoundState.breakMainLoop = false;
  9875.             while(!dsoundState.breakMainLoop) {
  9876.                 // Wait until we get available frames from directsound
  9877.                 uint32_t framesAvailable = WaitForFramesDirectSound(commonAudio, dsoundState);
  9878.                 if(framesAvailable == 0) {
  9879.                     continue;
  9880.                 }
  9881.  
  9882.                 // Don't bother grabbing more data if the device is being stopped.
  9883.                 if(dsoundState.breakMainLoop) {
  9884.                     break;
  9885.                 }
  9886.  
  9887.                 // Lock playback buffer
  9888.                 DWORD lockOffset = dsoundState.lastProcessedFrame * commonAudio.internalFormat.channels * audioSampleSizeBytes;
  9889.                 DWORD lockSize = framesAvailable * commonAudio.internalFormat.channels * audioSampleSizeBytes;
  9890.                 {
  9891.                     void* pLockPtr;
  9892.                     DWORD actualLockSize;
  9893.                     void* pLockPtr2;
  9894.                     DWORD actualLockSize2;
  9895.                     if(FAILED(dsoundState.secondaryBuffer->Lock(lockOffset, lockSize, &pLockPtr, &actualLockSize, &pLockPtr2, &actualLockSize2, 0))) {
  9896.                         // @TODO(final): Handle error
  9897.                         break;
  9898.                     }
  9899.  
  9900.                     // Read actual frames from user
  9901.                     uint32_t frameCount = actualLockSize / audioSampleSizeBytes / commonAudio.internalFormat.channels;
  9902.                     common::ReadAudioFramesFromClient(commonAudio, frameCount, pLockPtr);
  9903.                     dsoundState.lastProcessedFrame = (dsoundState.lastProcessedFrame + frameCount) % commonAudio.internalFormat.bufferSizeInFrames;
  9904.  
  9905.                     // Unlock playback buffer
  9906.                     dsoundState.secondaryBuffer->Unlock(pLockPtr, actualLockSize, pLockPtr2, actualLockSize2);
  9907.                 }
  9908.             }
  9909.         }
  9910. #   endif //FPL_ENABLE_AUDIO_DIRECTSOUND
  9911.  
  9912.     } // drivers
  9913. } // fpl
  9914. #endif // FPL_AUDIO_DRIVERS_IMPLEMENTED
  9915.  
  9916. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  9917. //
  9918. // > SYSTEM_AUDIO_L1 (Audio System, Private Implementation)
  9919. //
  9920. // The audio system is based on a stripped down version of "mini_al.h" by David Reid.
  9921. // See: https://github.com/dr-soft/mini_al
  9922. //
  9923. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  9924. #if defined(FPL_ENABLE_AUDIO)
  9925. namespace fpl {
  9926.     namespace common_audio {
  9927.         enum class AudioDeviceState : uint32_t {
  9928.             Uninitialized = 0,
  9929.             Stopped,
  9930.             Started,
  9931.             Starting,
  9932.             Stopping,
  9933.         };
  9934.  
  9935.         struct AudioState {
  9936.             common::CommonAudioState common;
  9937.  
  9938.             threading::MutexHandle lock;
  9939.             threading::ThreadHandle *workerThread;
  9940.             threading::SignalHandle startSignal;
  9941.             threading::SignalHandle stopSignal;
  9942.             threading::SignalHandle wakeupSignal;
  9943.             volatile AudioDeviceState state;
  9944.             volatile audio::AudioResult workResult;
  9945.  
  9946.             AudioDriverType activeDriver;
  9947.             uint32_t periods;
  9948.             uint32_t bufferSizeInFrames;
  9949.             uint32_t bufferSizeInBytes;
  9950.             bool isAsyncDriver;
  9951.  
  9952.             union {
  9953. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  9954.                 drivers::DirectSoundState dsound;
  9955. #           endif
  9956.             };
  9957.         };
  9958.  
  9959.         fpl_internal_inline AudioState *GetAudioState(platform::PlatformAppState *appState) {
  9960.             FPL_ASSERT(appState != nullptr);
  9961.             FPL_ASSERT(appState->audio.mem != nullptr);
  9962.             AudioState *audioState = (AudioState *)appState->audio.mem;
  9963.             return(audioState);
  9964.         }
  9965.  
  9966.         fpl_internal void AudioDeviceStopMainLoop(AudioState &audioState) {
  9967.             FPL_ASSERT(audioState.activeDriver > AudioDriverType::Auto);
  9968.             switch(audioState.activeDriver) {
  9969.  
  9970. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  9971.                 case AudioDriverType::DirectSound:
  9972.                 {
  9973.                     drivers::StopMainLoopDirectSound(audioState.dsound);
  9974.                 } break;
  9975. #           endif
  9976.  
  9977.                 default:
  9978.                     break;
  9979.             }
  9980.         }
  9981.  
  9982.         fpl_internal bool AudioReleaseDevice(AudioState &audioState) {
  9983.             FPL_ASSERT(audioState.activeDriver > AudioDriverType::Auto);
  9984.             bool result = false;
  9985.             switch(audioState.activeDriver) {
  9986.  
  9987. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  9988.                 case AudioDriverType::DirectSound:
  9989.                 {
  9990.                     result = drivers::ReleaseDirectSound(audioState.common, audioState.dsound);
  9991.                 } break;
  9992. #           endif
  9993.  
  9994.                 default:
  9995.                     break;
  9996.             }
  9997.             return (result);
  9998.         }
  9999.  
  10000.         fpl_internal bool AudioStopDevice(AudioState &audioState) {
  10001.             FPL_ASSERT(audioState.activeDriver > AudioDriverType::Auto);
  10002.             bool result = false;
  10003.             switch(audioState.activeDriver) {
  10004.  
  10005. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  10006.                 case AudioDriverType::DirectSound:
  10007.                 {
  10008.                     result = drivers::StopDirectSound(audioState.dsound);
  10009.                 } break;
  10010. #           endif
  10011.  
  10012.                 default:
  10013.                     break;
  10014.             }
  10015.             return (result);
  10016.         }
  10017.  
  10018.         fpl_internal audio::AudioResult AudioStartDevice(AudioState &audioState) {
  10019.             FPL_ASSERT(audioState.activeDriver > AudioDriverType::Auto);
  10020.             audio::AudioResult result = audio::AudioResult::Failed;
  10021.             switch(audioState.activeDriver) {
  10022.  
  10023. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  10024.                 case AudioDriverType::DirectSound:
  10025.                 {
  10026.                     result = drivers::StartDirectSound(audioState.common, audioState.dsound);
  10027.                 } break;
  10028. #           endif
  10029.  
  10030.                 default:
  10031.                     break;
  10032.             }
  10033.             return (result);
  10034.         }
  10035.  
  10036.         fpl_internal void AudioDeviceMainLoop(AudioState &audioState) {
  10037.             FPL_ASSERT(audioState.activeDriver > AudioDriverType::Auto);
  10038.             switch(audioState.activeDriver) {
  10039.  
  10040. #           if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  10041.                 case AudioDriverType::DirectSound:
  10042.                 {
  10043.                     drivers::DirectSoundMainLoop(audioState.common, audioState.dsound);
  10044.                 } break;
  10045. #           endif
  10046.  
  10047.                 default:
  10048.                     break;
  10049.             }
  10050.         }
  10051.  
  10052.         fpl_internal_inline bool IsAudioDriverAsync(AudioDriverType audioDriver) {
  10053.             switch(audioDriver) {
  10054.                 case AudioDriverType::DirectSound:
  10055.                     return false;
  10056.                 default:
  10057.                     return false;
  10058.             }
  10059.         }
  10060.  
  10061.         fpl_internal_inline void AudioSetDeviceState(AudioState &audioState, AudioDeviceState newState) {
  10062.             atomics::AtomicStoreU32((volatile uint32_t *)&audioState.state, (uint32_t)newState);
  10063.         }
  10064.  
  10065.         fpl_internal_inline AudioDeviceState AudioGetDeviceState(AudioState &audioState) {
  10066.             AudioDeviceState result = (AudioDeviceState)atomics::AtomicLoadU32((volatile uint32_t *)&audioState.state);
  10067.             return(result);
  10068.         }
  10069.  
  10070.         fpl_internal_inline bool IsAudioDeviceInitialized(AudioState *audioState) {
  10071.             if(audioState == nullptr) {
  10072.                 return false;
  10073.             }
  10074.             AudioDeviceState state = AudioGetDeviceState(*audioState);
  10075.             return(state != AudioDeviceState::Uninitialized);
  10076.         }
  10077.  
  10078.         fpl_internal_inline bool IsAudioDeviceStarted(AudioState *audioState) {
  10079.             if(audioState == nullptr) {
  10080.                 return false;
  10081.             }
  10082.             AudioDeviceState state = AudioGetDeviceState(*audioState);
  10083.             return(state == AudioDeviceState::Started);
  10084.         }
  10085.  
  10086.         fpl_internal void AudioWorkerThread(const threading::ThreadHandle &context, void *data) {
  10087. #       if defined(FPL_PLATFORM_WIN32)
  10088.             FPL_ASSERT(platform::global__AppState != nullptr);
  10089.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  10090. #       endif
  10091.  
  10092.             AudioState *audioState = (AudioState *)data;
  10093.             FPL_ASSERT(audioState != nullptr);
  10094.             FPL_ASSERT(audioState->activeDriver != AudioDriverType::None);
  10095.  
  10096. #       if defined(FPL_PLATFORM_WIN32)
  10097.             wapi.ole.coInitializeEx(nullptr, 0);
  10098. #       endif
  10099.  
  10100.             for(;;) {
  10101.                 // Stop the device at the start of the iteration always
  10102.                 AudioStopDevice(*audioState);
  10103.  
  10104.                 // Let the other threads know that the device has been stopped.
  10105.                 AudioSetDeviceState(*audioState, AudioDeviceState::Stopped);
  10106.                 threading::SignalSet(audioState->stopSignal);
  10107.  
  10108.                 // We wait until the audio device gets wake up
  10109.                 threading::SignalWaitForOne(audioState->lock, audioState->wakeupSignal);
  10110.  
  10111.                 // Default result code.
  10112.                 audioState->workResult = audio::AudioResult::Success;
  10113.  
  10114.                 // Just break if we're terminating.
  10115.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Uninitialized) {
  10116.                     break;
  10117.                 }
  10118.  
  10119.                 // Expect that the device is currently be started by the client
  10120.                 FPL_ASSERT(AudioGetDeviceState(*audioState) == AudioDeviceState::Starting);
  10121.  
  10122.                 // Start audio device
  10123.                 audioState->workResult = AudioStartDevice(*audioState);
  10124.                 if(audioState->workResult != audio::AudioResult::Success) {
  10125.                     threading::SignalSet(audioState->startSignal);
  10126.                     continue;
  10127.                 }
  10128.  
  10129.                 // The audio device is started, mark it as such
  10130.                 AudioSetDeviceState(*audioState, AudioDeviceState::Started);
  10131.                 threading::SignalSet(audioState->startSignal);
  10132.  
  10133.                 // Enter audio device main loop
  10134.                 AudioDeviceMainLoop(*audioState);
  10135.             }
  10136.  
  10137.             // Signal to stop any audio threads, in case there are some waiting
  10138.             threading::SignalSet(audioState->stopSignal);
  10139.  
  10140. #       if defined(FPL_PLATFORM_WIN32)
  10141.             wapi.ole.coUninitialize();
  10142. #       endif
  10143.         }
  10144.  
  10145.         fpl_internal void ReleaseAudio(AudioState *audioState) {
  10146.             FPL_ASSERT(audioState != nullptr);
  10147.  
  10148. #       if defined(FPL_PLATFORM_WIN32)
  10149.             FPL_ASSERT(platform::global__AppState != nullptr);
  10150.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  10151. #       endif
  10152.  
  10153.             if(IsAudioDeviceInitialized(audioState)) {
  10154.  
  10155.                 // Wait until the audio device is stopped
  10156.                 if(IsAudioDeviceStarted(audioState)) {
  10157.                     while(audio::StopAudio() == audio::AudioResult::DeviceBusy) {
  10158.                         threading::ThreadSleep(1);
  10159.                     }
  10160.                 }
  10161.  
  10162.                 // Putting the device into an uninitialized state will make the worker thread return.
  10163.                 AudioSetDeviceState(*audioState, AudioDeviceState::Uninitialized);
  10164.  
  10165.                 // Wake up the worker thread and wait for it to properly terminate.
  10166.                 SignalSet(audioState->wakeupSignal);
  10167.                 ThreadWaitForOne(audioState->workerThread);
  10168.                 ThreadDestroy(audioState->workerThread);
  10169.  
  10170.                 // Release signals and thread
  10171.                 threading::SignalDestroy(audioState->stopSignal);
  10172.                 threading::SignalDestroy(audioState->startSignal);
  10173.                 threading::SignalDestroy(audioState->wakeupSignal);
  10174.                 threading::MutexDestroy(audioState->lock);
  10175.  
  10176.                 // Release audio device
  10177.                 AudioReleaseDevice(*audioState);
  10178.  
  10179.                 // Clear audio state
  10180.                 audioState = {};
  10181.             }
  10182.  
  10183. #       if defined(FPL_PLATFORM_WIN32)
  10184.             wapi.ole.coUninitialize();
  10185. #       endif
  10186.         }
  10187.  
  10188.         fpl_internal audio::AudioResult InitAudio(const AudioSettings &audioSettings, AudioState *audioState) {
  10189.             FPL_ASSERT(audioState != nullptr);
  10190.  
  10191. #       if defined(FPL_PLATFORM_WIN32)
  10192.             FPL_ASSERT(platform::global__AppState != nullptr);
  10193.             const platform_win32::Win32Api &wapi = platform::global__AppState->win32.winApi;
  10194. #       endif
  10195.  
  10196.             if(audioState->activeDriver != AudioDriverType::None) {
  10197.                 ReleaseAudio(audioState);
  10198.                 return audio::AudioResult::Failed;
  10199.             }
  10200.  
  10201.             if(audioSettings.deviceFormat.channels == 0) {
  10202.                 ReleaseAudio(audioState);
  10203.                 return audio::AudioResult::Failed;
  10204.             }
  10205.             if(audioSettings.deviceFormat.sampleRate == 0) {
  10206.                 ReleaseAudio(audioState);
  10207.                 return audio::AudioResult::Failed;
  10208.             }
  10209.             if(audioSettings.bufferSizeInMilliSeconds == 0) {
  10210.                 ReleaseAudio(audioState);
  10211.                 return audio::AudioResult::Failed;
  10212.             }
  10213.  
  10214.             audioState->common.clientReadCallback = audioSettings.clientReadCallback;
  10215.             audioState->common.clientUserData = audioSettings.userData;
  10216.  
  10217. #       if defined(FPL_PLATFORM_WIN32)
  10218.             wapi.ole.coInitializeEx(nullptr, 0);
  10219. #       endif
  10220.  
  10221.             // Create mutex and signals
  10222.             audioState->lock = threading::MutexCreate();
  10223.             if(!audioState->lock.isValid) {
  10224.                 ReleaseAudio(audioState);
  10225.                 return audio::AudioResult::Failed;
  10226.             }
  10227.             audioState->wakeupSignal = threading::SignalCreate();
  10228.             if(!audioState->wakeupSignal.isValid) {
  10229.                 ReleaseAudio(audioState);
  10230.                 return audio::AudioResult::Failed;
  10231.             }
  10232.             audioState->startSignal = threading::SignalCreate();
  10233.             if(!audioState->startSignal.isValid) {
  10234.                 ReleaseAudio(audioState);
  10235.                 return audio::AudioResult::Failed;
  10236.             }
  10237.             audioState->stopSignal = threading::SignalCreate();
  10238.             if(!audioState->stopSignal.isValid) {
  10239.                 ReleaseAudio(audioState);
  10240.                 return audio::AudioResult::Failed;
  10241.             }
  10242.  
  10243.             // Prope drivers
  10244.             AudioDriverType propeDrivers[16];
  10245.             uint32_t driverCount = 0;
  10246.             if(audioSettings.driver == AudioDriverType::Auto) {
  10247.                 // @NOTE(final): Add all audio drivers here, regardless of the platform.
  10248.                 propeDrivers[driverCount++] = AudioDriverType::DirectSound;
  10249.             } else {
  10250.                 // @NOTE(final): Forced audio driver
  10251.                 propeDrivers[driverCount++] = audioSettings.driver;
  10252.             }
  10253.             audio::AudioResult initResult = audio::AudioResult::Failed;
  10254.             for(uint32_t driverIndex = 0; driverIndex < driverCount; ++driverIndex) {
  10255.                 AudioDriverType propeDriver = propeDrivers[driverIndex];
  10256.  
  10257.                 initResult = audio::AudioResult::Failed;
  10258.                 switch(propeDriver) {
  10259.  
  10260. #               if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  10261.                     case AudioDriverType::DirectSound:
  10262.                     {
  10263.                         initResult = drivers::InitDirectSound(audioSettings, audioState->common, audioState->dsound);
  10264.                         if(initResult != audio::AudioResult::Success) {
  10265.                             drivers::ReleaseDirectSound(audioState->common, audioState->dsound);
  10266.                         }
  10267.                     } break;
  10268. #               endif
  10269.  
  10270.                     default:
  10271.                         break;
  10272.                 }
  10273.                 if(initResult == audio::AudioResult::Success) {
  10274.                     audioState->activeDriver = propeDriver;
  10275.                     audioState->isAsyncDriver = IsAudioDriverAsync(propeDriver);
  10276.                     break;
  10277.                 }
  10278.             }
  10279.  
  10280.             if(initResult != audio::AudioResult::Success) {
  10281.                 ReleaseAudio(audioState);
  10282.                 return initResult;
  10283.             }
  10284.  
  10285.             if(!audioState->isAsyncDriver) {
  10286.                 // Create and start worker thread
  10287.                 audioState->workerThread = threading::ThreadCreate(AudioWorkerThread, audioState);
  10288.                 if(audioState->workerThread == nullptr) {
  10289.                     ReleaseAudio(audioState);
  10290.                     return audio::AudioResult::Failed;
  10291.                 }
  10292.                 // Wait for the worker thread to put the device into the stopped state.
  10293.                 SignalWaitForOne(audioState->lock, audioState->stopSignal);
  10294.             } else {
  10295.                 AudioSetDeviceState(*audioState, AudioDeviceState::Stopped);
  10296.             }
  10297.  
  10298.             FPL_ASSERT(AudioGetDeviceState(*audioState) == AudioDeviceState::Stopped);
  10299.  
  10300.             return(audio::AudioResult::Success);
  10301.         }
  10302.     } // common_audio
  10303. } // fpl
  10304. #endif // FPL_ENABLE_AUDIO
  10305.  
  10306. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10307. //
  10308. // > SYSTEM_VIDEO_L1 (Video System, Private Implementation)
  10309. //
  10310. // The audio system is based on a stripped down version of "mini_al.h" by David Reid.
  10311. // See: https://github.com/dr-soft/mini_al
  10312. //
  10313. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10314. #if defined(FPL_ENABLE_VIDEO)
  10315. namespace fpl {
  10316.     namespace common_video {
  10317.  
  10318. #   if defined(FPL_PLATFORM_WIN32)
  10319.         struct Win32VideoState {
  10320. #       if defined(FPL_ENABLE_VIDEO_OPENGL)
  10321.             drivers::Win32VideoOpenGLState opengl;
  10322. #       endif
  10323. #       if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10324.             drivers::Win32VideoSoftwareState software;
  10325. #       endif
  10326.         };
  10327. #   elif defined(FPL_SUBPLATFORM_X11)
  10328.         struct X11VideoState {
  10329. #       if defined(FPL_ENABLE_VIDEO_OPENGL)
  10330.             drivers::X11VideoOpenGLState opengl;
  10331. #       endif
  10332.         };
  10333. #   endif // FPL_PLATFORM
  10334.  
  10335.         struct VideoState {
  10336.             VideoDriverType activeDriver;
  10337. #       if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10338.             video::VideoBackBuffer softwareBackbuffer;
  10339. #       endif
  10340.             union {
  10341. #           if defined(FPL_PLATFORM_WIN32)
  10342.                 Win32VideoState win32;
  10343. #           elif defined(FPL_SUBPLATFORM_X11)
  10344.                 X11VideoState x11;
  10345. #           endif // FPL_PLATFORM
  10346.             };
  10347.         };
  10348.  
  10349.         fpl_internal_inline VideoState *GetVideoState(platform::PlatformAppState *appState) {
  10350.             FPL_ASSERT(appState != nullptr);
  10351.             FPL_ASSERT(appState->video.mem != nullptr);
  10352.             VideoState *videoState = (VideoState *)appState->video.mem;
  10353.             return(videoState);
  10354.         }
  10355.  
  10356.         fpl_internal void ShutdownVideo(platform::PlatformAppState *appState, VideoState *videoState) {
  10357.             FPL_LOG_BLOCK;
  10358.             FPL_ASSERT(appState != nullptr);
  10359.             if(videoState != nullptr) {
  10360.                 switch(videoState->activeDriver) {
  10361. #               if defined(FPL_ENABLE_VIDEO_OPENGL)
  10362.                     case VideoDriverType::OpenGL:
  10363.                     {
  10364. #                   if defined(FPL_PLATFORM_WIN32)
  10365.                         drivers::Win32ReleaseVideoOpenGL(videoState->win32.opengl);
  10366. #                   elif defined(FPL_SUBPLATFORM_X11)
  10367.                         drivers::X11ReleaseVideoOpenGL(appState->window.x11, videoState->x11.opengl);
  10368. #                   endif
  10369.                     } break;
  10370. #               endif // FPL_ENABLE_VIDEO_OPENGL
  10371.  
  10372. #               if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10373.                     case VideoDriverType::Software:
  10374.                     {
  10375. #                   if defined(FPL_PLATFORM_WIN32)
  10376.                         drivers::Win32ReleaseVideoSoftware(videoState->win32.software);
  10377. #                   elif defined(FPL_SUBPLATFORM_X11)
  10378. #                   endif
  10379.                     } break;
  10380. #               endif // FPL_ENABLE_VIDEO_SOFTWARE
  10381.  
  10382.                     default:
  10383.                     {
  10384.                     } break;
  10385.                 }
  10386.  
  10387. #           if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10388.                 fpl::video::VideoBackBuffer &backbuffer = videoState->softwareBackbuffer;
  10389.                 if(backbuffer.pixels != nullptr) {
  10390.                     memory::MemoryAlignedFree(backbuffer.pixels);
  10391.                 }
  10392.                 backbuffer = {};
  10393. #           endif
  10394.             }
  10395.         }
  10396.  
  10397.         fpl_internal void ReleaseVideoState(platform::PlatformAppState *appState, VideoState *videoState) {
  10398.             FPL_LOG_BLOCK;
  10399.  
  10400.             switch(videoState->activeDriver) {
  10401. #           if defined(FPL_ENABLE_VIDEO_OPENGL)
  10402.                 case VideoDriverType::OpenGL:
  10403.                 {
  10404. #               if defined(FPL_PLATFORM_WIN32)
  10405.                     drivers::Win32UnloadVideoOpenGLApi(videoState->win32.opengl.api);
  10406. #               elif defined(FPL_SUBPLATFORM_X11)
  10407.                     drivers::X11ReleaseVisualForVideoOpenGL(appState->x11.api, videoState->x11.opengl.visual);
  10408.                     drivers::X11UnloadVideoOpenGLApi(videoState->x11.opengl.api);
  10409. #               endif
  10410.                 }; break;
  10411. #           endif
  10412.  
  10413. #           if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10414.                 case VideoDriverType::Software:
  10415.                 {
  10416.                     // Nothing todo
  10417.                 }; break;
  10418. #           endif
  10419.  
  10420.                 default:
  10421.                     break;
  10422.             }
  10423.             videoState = {};
  10424.         }
  10425.  
  10426.         fpl_internal bool LoadVideoState(const VideoDriverType driver, VideoState *videoState) {
  10427.             FPL_LOG_BLOCK;
  10428.  
  10429.             bool result = true;
  10430.  
  10431.             switch(driver) {
  10432. #           if defined(FPL_ENABLE_VIDEO_OPENGL)
  10433.                 case VideoDriverType::OpenGL:
  10434.                 {
  10435. #               if defined(FPL_PLATFORM_WIN32)
  10436.                     result = drivers::Win32LoadVideoOpenGLApi(videoState->win32.opengl.api);
  10437. #               elif defined(FPL_SUBPLATFORM_X11)
  10438.                     result = drivers::X11LoadVideoOpenGLApi(videoState->x11.opengl.api);
  10439. #               endif
  10440.                 }; break;
  10441. #           endif
  10442.  
  10443.                 default:
  10444.                     break;
  10445.             }
  10446.             return(result);
  10447.         }
  10448.  
  10449.         fpl_internal bool InitVideo(const VideoDriverType driver, const VideoSettings &videoSettings, const uint32_t windowWidth, const uint32_t windowHeight, platform::PlatformAppState *appState, VideoState *videoState) {
  10450.             FPL_LOG_BLOCK;
  10451.  
  10452.             // @NOTE(final): Video drivers are platform independent, so we cannot have to same system as audio.
  10453.             FPL_ASSERT(appState != nullptr);
  10454.             FPL_ASSERT(videoState != nullptr);
  10455.  
  10456.             videoState->activeDriver = driver;
  10457.  
  10458.             // Allocate backbuffer context if needed
  10459. #       if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10460.             if(driver == VideoDriverType::Software) {
  10461.                 fpl::video::VideoBackBuffer &backbuffer = videoState->softwareBackbuffer;
  10462.                 backbuffer.width = windowWidth;
  10463.                 backbuffer.height = windowHeight;
  10464.                 backbuffer.pixelStride = sizeof(uint32_t);
  10465.                 backbuffer.lineWidth = backbuffer.width * backbuffer.pixelStride;
  10466.                 size_t size = backbuffer.lineWidth * backbuffer.height;
  10467.                 backbuffer.pixels = (uint32_t *)memory::MemoryAlignedAllocate(size, 4);
  10468.                 if(backbuffer.pixels == nullptr) {
  10469.                     common::PushError("Failed allocating video software backbuffer of size %xu bytes", size);
  10470.                     ShutdownVideo(appState, videoState);
  10471.                     return false;
  10472.                 }
  10473.  
  10474.                 // Clear to black by default
  10475.                 // @NOTE(final): Bitmap is top-down, 0xAABBGGRR
  10476.                 // @TODO(final): Backbuffer endianess???
  10477.                 uint32_t *p = backbuffer.pixels;
  10478.                 for(uint32_t y = 0; y < backbuffer.height; ++y) {
  10479.                     uint32_t color = 0xFF000000;
  10480.                     for(uint32_t x = 0; x < backbuffer.width; ++x) {
  10481.                         *p++ = color;
  10482.                     }
  10483.                 }
  10484.             }
  10485. #       endif // FPL_ENABLE_VIDEO_SOFTWARE
  10486.  
  10487.             bool videoInitResult = false;
  10488.             switch(driver) {
  10489. #           if defined(FPL_ENABLE_VIDEO_OPENGL)
  10490.                 case VideoDriverType::OpenGL:
  10491.                 {
  10492. #               if defined(FPL_PLATFORM_WIN32)
  10493.                     videoInitResult = drivers::Win32InitVideoOpenGL(appState->win32, appState->window.win32, videoSettings, videoState->win32.opengl);
  10494. #               elif defined(FPL_SUBPLATFORM_X11)
  10495.                     videoInitResult = drivers::X11InitVideoOpenGL(appState->x11, appState->window.x11, videoSettings, videoState->x11.opengl);
  10496. #               endif
  10497.                 } break;
  10498. #           endif // FPL_ENABLE_VIDEO_OPENGL
  10499.  
  10500. #           if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10501.                 case VideoDriverType::Software:
  10502.                 {
  10503. #               if defined(FPL_PLATFORM_WIN32)
  10504.                     videoInitResult = drivers::Win32InitVideoSoftware(videoState->softwareBackbuffer, videoState->win32.software);
  10505. #               elif defined(FPL_SUBPLATFORM_X11)
  10506. #               endif
  10507.                 } break;
  10508. #           endif // FPL_ENABLE_VIDEO_SOFTWARE
  10509.  
  10510.                 default:
  10511.                 {
  10512.                     common::PushError("Unsupported video driver '%s' for this platform", fpl::video::GetVideoDriverString(videoSettings.driver));
  10513.                 } break;
  10514.             }
  10515.             if(!videoInitResult) {
  10516.                 FPL_ASSERT(fpl::GetPlatformErrorCount() > 0);
  10517.                 ShutdownVideo(appState, videoState);
  10518.                 return false;
  10519.             }
  10520.  
  10521.             return true;
  10522.         }
  10523.     } // common_video
  10524. } // fpl
  10525. #endif // FPL_ENABLE_VIDEO
  10526.  
  10527. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10528. //
  10529. // > SYSTEM_WINDOW (Window System, Private Implementation)
  10530. //
  10531. // - Init window
  10532. // - Release window
  10533. //
  10534. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10535. #if defined(FPL_ENABLE_WINDOW)
  10536. namespace fpl {
  10537.     namespace common_window {
  10538.         fpl_internal FPL_FUNC_PRE_SETUP_WINDOW(PreSetupWindowDefault) {
  10539.             FPL_ASSERT(appState != nullptr);
  10540.             bool result = false;
  10541.  
  10542. #       if defined(FPL_ENABLE_VIDEO)
  10543.             if(initFlags & InitFlags::Video) {
  10544.                 common_video::VideoState *videoState = common_video::GetVideoState(appState);
  10545.                 switch(initSettings.video.driver) {
  10546. #               if defined(FPL_ENABLE_VIDEO_OPENGL)
  10547.                     case VideoDriverType::OpenGL:
  10548.                     {
  10549. #                   if defined(FPL_SUBPLATFORM_X11)
  10550.                         drivers::X11VideoOpenGLVisual &vis = videoState->x11.opengl.visual;
  10551.                         result = drivers::X11InitVisualForVideoOpenGL(appState->x11.api, appState->window.x11, videoState->x11.opengl.api, vis);
  10552.                         if(result) {
  10553.                             FPL_ASSERT(vis.visualInfo != nullptr);
  10554.                             outResult.x11.visual = vis.visualInfo->visual;
  10555.                             outResult.x11.colorDepth = vis.visualInfo->depth;
  10556.                         }
  10557. #                   endif
  10558.                     } break;
  10559. #               endif // FPL_ENABLE_VIDEO_OPENGL
  10560.  
  10561.                     default:
  10562.                     {
  10563.                     } break;
  10564.                 }
  10565.             }
  10566. #       endif // FPL_ENABLE_VIDEO
  10567.  
  10568.             return(result);
  10569.         }
  10570.  
  10571.         fpl_internal FPL_FUNC_POST_SETUP_WINDOW(PostSetupWindowDefault) {
  10572.             FPL_ASSERT(appState != nullptr);
  10573.  
  10574. #       if defined(FPL_ENABLE_VIDEO)
  10575.             if(initFlags & InitFlags::Video) {
  10576.                 switch(initSettings.video.driver) {
  10577. #               if defined(FPL_ENABLE_VIDEO_OPENGL)
  10578.                     case VideoDriverType::OpenGL:
  10579.                     {
  10580. #                   if defined(FPL_PLATFORM_WIN32)
  10581.                         if(!drivers::Win32PostSetupWindowForOpenGL(appState->win32, appState->window.win32, initSettings.video)) {
  10582.                             return false;
  10583.                         }
  10584. #                   endif
  10585.                     } break;
  10586. #               endif // FPL_ENABLE_VIDEO_OPENGL
  10587.  
  10588.                     default:
  10589.                     {
  10590.                     } break;
  10591.                 }
  10592.             }
  10593. #       endif // FPL_ENABLE_VIDEO
  10594.  
  10595.             return false;
  10596.         }
  10597.  
  10598.         fpl_internal bool InitWindow(const Settings &initSettings, WindowSettings &currentWindowSettings, platform::PlatformAppState *appState, const platform::SetupWindowCallbacks &setupCallbacks) {
  10599.             FPL_LOG_BLOCK;
  10600.  
  10601.             bool result = false;
  10602.             if(appState != nullptr) {
  10603. #           if defined(FPL_PLATFORM_WIN32)
  10604.                 result = platform_win32::Win32InitWindow(initSettings, currentWindowSettings, appState, appState->win32, appState->window.win32, setupCallbacks);
  10605. #           elif defined(FPL_SUBPLATFORM_X11)
  10606.                 result = subplatform_x11::X11InitWindow(initSettings, currentWindowSettings, appState, appState->x11, appState->window.x11, setupCallbacks);
  10607. #           endif
  10608.             }
  10609.             return (result);
  10610.         }
  10611.  
  10612.         fpl_internal void ReleaseWindow(const platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  10613.             FPL_LOG_BLOCK;
  10614.  
  10615.             if(appState != nullptr) {
  10616. #           if defined(FPL_PLATFORM_WIN32)
  10617.                 platform_win32::Win32ReleaseWindow(initState.win32, appState->win32, appState->window.win32);
  10618. #           elif defined(FPL_SUBPLATFORM_X11)
  10619.                 subplatform_x11::X11ReleaseWindow(appState->x11, appState->window.x11);
  10620. #           endif
  10621.             }
  10622.         }
  10623.     } // common_window
  10624. } // fpl
  10625. #endif // FPL_ENABLE_WINDOW
  10626.  
  10627. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10628. //
  10629. // > SYSTEM_AUDIO_L2 (Audio System, Public Implementation)
  10630. //
  10631. // - Stop audio
  10632. // - Play audio
  10633. //
  10634. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10635. #if defined(FPL_ENABLE_AUDIO)
  10636. namespace fpl {
  10637.     namespace audio {
  10638.         fpl_common_api AudioResult StopAudio() {
  10639.             using namespace common_audio;
  10640.  
  10641.             FPL_ASSERT(platform::global__AppState != nullptr);
  10642.             platform::PlatformAudioState &platAudioState = platform::global__AppState->audio;
  10643.             if(platAudioState.mem == nullptr) {
  10644.                 return AudioResult::Failed;
  10645.             }
  10646.             AudioState *audioState = (AudioState *)platAudioState.mem;
  10647.  
  10648.             if(AudioGetDeviceState(*audioState) == AudioDeviceState::Uninitialized) {
  10649.                 return AudioResult::DeviceNotInitialized;
  10650.             }
  10651.  
  10652.             AudioResult result = AudioResult::Failed;
  10653.             MutexLock(audioState->lock);
  10654.             {
  10655.                 // Check if the device is already stopped
  10656.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Stopping) {
  10657.                     MutexUnlock(audioState->lock);
  10658.                     return AudioResult::DeviceAlreadyStopped;
  10659.                 }
  10660.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Stopped) {
  10661.                     MutexUnlock(audioState->lock);
  10662.                     return AudioResult::DeviceAlreadyStopped;
  10663.                 }
  10664.  
  10665.                 // The device needs to be in a started state. If it's not, we just let the caller know the device is busy.
  10666.                 if(AudioGetDeviceState(*audioState) != AudioDeviceState::Started) {
  10667.                     MutexUnlock(audioState->lock);
  10668.                     return AudioResult::DeviceBusy;
  10669.                 }
  10670.  
  10671.                 AudioSetDeviceState(*audioState, AudioDeviceState::Stopping);
  10672.  
  10673.                 if(audioState->isAsyncDriver) {
  10674.                     // Asynchronous drivers (Has their own thread)
  10675.                     AudioStopDevice(*audioState);
  10676.                 } else {
  10677.                     // Synchronous drivers
  10678.  
  10679.                     // The audio worker thread is most likely in a wait state, so let it stop properly.
  10680.                     AudioDeviceStopMainLoop(*audioState);
  10681.  
  10682.                     // We need to wait for the worker thread to become available for work before returning.
  10683.                     // @NOTE(final): The audio worker thread will be the one who puts the device into the stopped state.
  10684.                     SignalWaitForOne(audioState->lock, audioState->stopSignal);
  10685.                     result = AudioResult::Success;
  10686.                 }
  10687.             }
  10688.             MutexUnlock(audioState->lock);
  10689.  
  10690.             return result;
  10691.         }
  10692.  
  10693.         fpl_common_api AudioResult PlayAudio() {
  10694.             using namespace common_audio;
  10695.  
  10696.             FPL_ASSERT(platform::global__AppState != nullptr);
  10697.             platform::PlatformAudioState &platAudioState = platform::global__AppState->audio;
  10698.             if(platAudioState.mem == nullptr) {
  10699.                 return AudioResult::Failed;
  10700.             }
  10701.             AudioState *audioState = (AudioState *)platAudioState.mem;
  10702.  
  10703.             if(!IsAudioDeviceInitialized(audioState)) {
  10704.                 return AudioResult::DeviceNotInitialized;
  10705.             }
  10706.  
  10707.             AudioResult result = AudioResult::Failed;
  10708.             MutexLock(audioState->lock);
  10709.             {
  10710.                 // Be a bit more descriptive if the device is already started or is already in the process of starting.
  10711.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Starting) {
  10712.                     MutexUnlock(audioState->lock);
  10713.                     return AudioResult::DeviceAlreadyStarted;
  10714.                 }
  10715.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Started) {
  10716.                     MutexUnlock(audioState->lock);
  10717.                     return AudioResult::DeviceAlreadyStarted;
  10718.                 }
  10719.  
  10720.                 // The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy.
  10721.                 if(AudioGetDeviceState(*audioState) != AudioDeviceState::Stopped) {
  10722.                     MutexUnlock(audioState->lock);
  10723.                     return AudioResult::DeviceBusy;
  10724.                 }
  10725.  
  10726.                 AudioSetDeviceState(*audioState, AudioDeviceState::Starting);
  10727.  
  10728.                 if(audioState->isAsyncDriver) {
  10729.                     // Asynchronous drivers (Has their own thread)
  10730.                     AudioStartDevice(*audioState);
  10731.                     AudioSetDeviceState(*audioState, AudioDeviceState::Started);
  10732.                 } else {
  10733.                     // Synchronous drivers
  10734.                     SignalSet(audioState->wakeupSignal);
  10735.  
  10736.                     // Wait for the worker thread to finish starting the device.
  10737.                     // @NOTE(final): The audio worker thread will be the one who puts the device into the started state.
  10738.                     SignalWaitForOne(audioState->lock, audioState->startSignal);
  10739.                     result = audioState->workResult;
  10740.                 }
  10741.             }
  10742.             MutexUnlock(audioState->lock);
  10743.  
  10744.             return result;
  10745.         }
  10746.  
  10747.         fpl_common_api AudioDeviceFormat GetAudioHardwareFormat() {
  10748.             FPL_ASSERT(platform::global__AppState != nullptr);
  10749.             platform::PlatformAudioState &platAudioState = platform::global__AppState->audio;
  10750.             if(platAudioState.mem == nullptr) {
  10751.                 return {};
  10752.             }
  10753.             common_audio::AudioState *audioState = (common_audio::AudioState *)platAudioState.mem;
  10754.             return audioState->common.internalFormat;
  10755.         }
  10756.  
  10757.         fpl_common_api void SetAudioClientReadCallback(AudioClientReadFunction *newCallback, void *userData) {
  10758.             using namespace common_audio;
  10759.  
  10760.             FPL_ASSERT(platform::global__AppState != nullptr);
  10761.             platform::PlatformAudioState &platAudioState = platform::global__AppState->audio;
  10762.             if(platAudioState.mem == nullptr) {
  10763.                 return;
  10764.             }
  10765.             AudioState *audioState = (AudioState *)platAudioState.mem;
  10766.             if(audioState->activeDriver > AudioDriverType::Auto) {
  10767.                 if(AudioGetDeviceState(*audioState) == AudioDeviceState::Stopped) {
  10768.                     audioState->common.clientReadCallback = newCallback;
  10769.                     audioState->common.clientUserData = userData;
  10770.                 }
  10771.             }
  10772.         }
  10773.  
  10774.         fpl_common_api uint32_t GetAudioDevices(AudioDeviceInfo *devices, uint32_t maxDeviceCount) {
  10775.             using namespace common_audio;
  10776.  
  10777.             if(devices == nullptr) {
  10778.                 return 0;
  10779.             }
  10780.             if(maxDeviceCount == 0) {
  10781.                 return 0;
  10782.             }
  10783.  
  10784.             FPL_ASSERT(platform::global__AppState != nullptr);
  10785.             platform::PlatformAudioState &platAudioState = platform::global__AppState->audio;
  10786.             if(platAudioState.mem == nullptr) {
  10787.                 return 0;
  10788.             }
  10789.             AudioState *audioState = (AudioState *)platAudioState.mem;
  10790.  
  10791.             uint32_t result = 0;
  10792.             if(audioState->activeDriver > AudioDriverType::Auto) {
  10793.                 switch(audioState->activeDriver) {
  10794. #               if defined(FPL_ENABLE_AUDIO_DIRECTSOUND)
  10795.                     case AudioDriverType::DirectSound:
  10796.                     {
  10797.                         result = drivers::GetDevicesDirectSound(audioState->dsound, devices, maxDeviceCount);
  10798.                     } break;
  10799. #               endif
  10800.                 }
  10801.             }
  10802.             return(result);
  10803.         }
  10804.     } // audio
  10805. } // fpl
  10806. #endif // FPL_ENABLE_AUDIO
  10807.  
  10808. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10809. //
  10810. // > SYSTEM_VIDEO_L2 (Video System, Public Implementation)
  10811. //
  10812. // - Video Backbuffer Access
  10813. // - Frame flipping
  10814. // - Utiltity functions
  10815. //
  10816. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10817. #if defined(FPL_ENABLE_VIDEO)
  10818. namespace fpl {
  10819.     namespace video {
  10820.         fpl_common_api VideoBackBuffer *GetVideoBackBuffer() {
  10821.             FPL_ASSERT(platform::global__AppState != nullptr);
  10822.             platform::PlatformAppState *appState = platform::global__AppState;
  10823.  
  10824.             VideoBackBuffer *result = nullptr;
  10825.             if(appState->video.mem != nullptr) {
  10826.                 common_video::VideoState *videoState = (common_video::VideoState *)appState->video.mem;
  10827. #           if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10828.                 if(appState->currentSettings.video.driver == VideoDriverType::Software) {
  10829.                     result = &videoState->softwareBackbuffer;
  10830.                 }
  10831. #           endif
  10832.             }
  10833.  
  10834.             return(result);
  10835.         }
  10836.  
  10837.         fpl_common_api VideoDriverType GetVideoDriver() {
  10838.             FPL_ASSERT(platform::global__AppState != nullptr);
  10839.             const platform::PlatformAppState *appState = platform::global__AppState;
  10840.             VideoDriverType result = appState->currentSettings.video.driver;
  10841.             return(result);
  10842.         }
  10843.  
  10844.         fpl_common_api bool ResizeVideoBackBuffer(const uint32_t width, const uint32_t height) {
  10845.             FPL_ASSERT(platform::global__AppState != nullptr);
  10846.             platform::PlatformAppState *appState = platform::global__AppState;
  10847.             platform::PlatformVideoState &video = appState->video;
  10848.             common_video::VideoState *videoState = common_video::GetVideoState(appState);
  10849.  
  10850.             bool result = false;
  10851.  
  10852.             if(video.mem != nullptr) {
  10853. #           if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10854.                 if(appState->currentSettings.video.driver == VideoDriverType::Software) {
  10855.                     common_video::ShutdownVideo(appState, videoState);
  10856.                     result = common_video::InitVideo(VideoDriverType::Software, appState->currentSettings.video, width, height, appState, videoState);
  10857.                 }
  10858. #           endif
  10859.             }
  10860.  
  10861.             return (result);
  10862.         }
  10863.  
  10864.         fpl_common_api void VideoFlip() {
  10865.             FPL_ASSERT(platform::global__AppState != nullptr);
  10866.             const platform::PlatformAppState *appState = platform::global__AppState;
  10867.             const platform::PlatformVideoState &video = appState->video;
  10868.  
  10869.             if(video.mem != nullptr) {
  10870. #       if defined(FPL_PLATFORM_WIN32)
  10871.                 const platform_win32::Win32AppState &win32AppState = appState->win32;
  10872.                 const platform_win32::Win32WindowState &win32WindowState = appState->window.win32;
  10873.                 const platform_win32::Win32Api &wapi = win32AppState.winApi;
  10874.                 switch(appState->currentSettings.video.driver) {
  10875. #               if defined(FPL_ENABLE_VIDEO_SOFTWARE)
  10876.                     case VideoDriverType::Software:
  10877.                     {
  10878.                         const common_video::VideoState *videoState = (common_video::VideoState *)video.mem;
  10879.                         const drivers::Win32VideoSoftwareState &software = videoState->win32.software;
  10880.                         const video::VideoBackBuffer &backbuffer = videoState->softwareBackbuffer;
  10881.                         window::WindowSize area = window::GetWindowArea();
  10882.                         int32_t targetX = 0;
  10883.                         int32_t targetY = 0;
  10884.                         int32_t targetWidth = area.width;
  10885.                         int32_t targetHeight = area.height;
  10886.                         int32_t sourceWidth = backbuffer.width;
  10887.                         int32_t sourceHeight = backbuffer.height;
  10888.                         if(backbuffer.useOutputRect) {
  10889.                             targetX = backbuffer.outputRect.x;
  10890.                             targetY = backbuffer.outputRect.y;
  10891.                             targetWidth = backbuffer.outputRect.width;
  10892.                             targetHeight = backbuffer.outputRect.height;
  10893.                             wapi.gdi.stretchDIBits(win32WindowState.deviceContext, 0, 0, area.width, area.height, 0, 0, 0, 0, nullptr, nullptr, DIB_RGB_COLORS, BLACKNESS);
  10894.                         }
  10895.                         wapi.gdi.stretchDIBits(win32WindowState.deviceContext, targetX, targetY, targetWidth, targetHeight, 0, 0, sourceWidth, sourceHeight, backbuffer.pixels, &software.bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  10896.                     } break;
  10897. #               endif
  10898.  
  10899. #               if defined(FPL_ENABLE_VIDEO_OPENGL)
  10900.                     case VideoDriverType::OpenGL:
  10901.                     {
  10902.                         wapi.gdi.swapBuffers(win32WindowState.deviceContext);
  10903.                     } break;
  10904. #               endif
  10905.  
  10906.                     default:
  10907.                         break;
  10908.                 }
  10909. #           endif // FPL_PLATFORM_WIN32
  10910.             }
  10911.         }
  10912.     } // video
  10913. } // fpl
  10914. #endif // FPL_ENABLE_VIDEO
  10915.  
  10916. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10917. //
  10918. // > SYSTEM_INIT
  10919. //
  10920. // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10921. #if !defined(FPL_SYSTEM_INIT_DEFINED)
  10922. #define FPL_SYSTEM_INIT_DEFINED
  10923.  
  10924. namespace fpl {
  10925.     namespace common_init {
  10926.         fpl_internal void ReleasePlatformStates(platform::PlatformInitState &initState, platform::PlatformAppState *appState) {
  10927.             FPL_LOG_BLOCK;
  10928.  
  10929.         // Release audio
  10930. #       if defined(FPL_ENABLE_AUDIO)
  10931.             {
  10932.                 FPL_LOG("Core", "Release Audio");
  10933.                 common_audio::AudioState *audioState = common_audio::GetAudioState(appState);
  10934.                 if(audioState != nullptr) {
  10935.                     // @TODO(final): Rename to ShutdownAudio
  10936.                     common_audio::ReleaseAudio(audioState);
  10937.                 }
  10938.             }
  10939. #       endif
  10940.  
  10941.         // Shutdown video (Release context only)
  10942. #       if defined(FPL_ENABLE_VIDEO)
  10943.             {
  10944.                 common_video::VideoState *videoState = common_video::GetVideoState(appState);
  10945.                 if(videoState != nullptr) {
  10946.                     FPL_LOG("Core", "Shutdown Video for Driver '%s'", video::GetVideoDriverString(videoState->activeDriver));
  10947.                     common_video::ShutdownVideo(appState, videoState);
  10948.                 }
  10949.             }
  10950. #       endif
  10951.  
  10952.         // Release window
  10953. #       if defined(FPL_ENABLE_WINDOW)
  10954.             {
  10955.                 FPL_LOG("Core", "Release Window");
  10956.                 common_window::ReleaseWindow(initState, appState);
  10957.             }
  10958. #       endif
  10959.  
  10960.         // Release video state
  10961. #       if defined(FPL_ENABLE_VIDEO)
  10962.             {
  10963.                 common_video::VideoState *videoState = common_video::GetVideoState(appState);
  10964.                 if(videoState != nullptr) {
  10965.                     FPL_LOG("Core", "Release Video for Driver '%s'", video::GetVideoDriverString(videoState->activeDriver));
  10966.                     common_video::ReleaseVideoState(appState, videoState);
  10967.                 }
  10968.             }
  10969. #       endif
  10970.  
  10971.             // @TODO(final): Release audio state here
  10972.  
  10973.             if(appState != nullptr) {
  10974.                 // Release actual platform (There can only be one platform!)
  10975.                 {
  10976. #               if defined(FPL_PLATFORM_WIN32)
  10977.                     FPL_LOG("Core", "Release Win32 Platform");
  10978.                     platform_win32::Win32ReleasePlatform(initState, appState);
  10979. #               elif defined(FPL_PLATFORM_LINUX)
  10980.                     FPL_LOG("Core", "Release Linux Platform");
  10981.                     platform_linux::LinuxReleasePlatform(initState, appState);
  10982. #               endif
  10983.                 }
  10984.  
  10985.                 // Release sub platforms
  10986.                 {
  10987. #               if defined(FPL_SUBPLATFORM_X11)
  10988.                     FPL_LOG("Core", "Release X11 Subplatform");
  10989.                     subplatform_x11::X11ReleaseSubplatform(appState->x11);
  10990. #               endif
  10991. #               if defined(FPL_SUBPLATFORM_POSIX)
  10992.                     FPL_LOG("Core", "Release POSIX Subplatform");
  10993.                     subplatform_posix::PosixReleaseSubplatform(appState->posix);
  10994. #               endif
  10995.                 }
  10996.  
  10997.                 // Release platform applicatiom state memory
  10998.                 FPL_LOG("Core", "Release allocated Platform App State Memory");
  10999.                 memory::MemoryFree(appState);
  11000.                 platform::global__AppState = nullptr;
  11001.             }
  11002.  
  11003.             initState.isInitialized = false;
  11004.         }
  11005.     } // common
  11006.  
  11007.     fpl_common_api void ReleasePlatform() {
  11008.         FPL_LOG_BLOCK;
  11009.  
  11010.         // Exit out if platform is not initialized
  11011.         platform::PlatformInitState &initState = platform::global__InitState;
  11012.         if(!initState.isInitialized) {
  11013.             common::PushError("Platform is not initialized");
  11014.             return;
  11015.         }
  11016.         platform::PlatformAppState *appState = platform::global__AppState;
  11017.         common_init::ReleasePlatformStates(initState, appState);
  11018.         FPL_LOG("Core", "Platform released");
  11019.     }
  11020.  
  11021.     fpl_common_api bool InitPlatform(const InitFlags initFlags, const Settings &initSettings) {
  11022.         FPL_LOG_BLOCK;
  11023.  
  11024.         // Exit out if platform is already initialized
  11025.         if(platform::global__InitState.isInitialized) {
  11026.             common::PushError("Platform is already initialized");
  11027.             return false;
  11028.         }
  11029.  
  11030.         // Allocate platform app state memory (By boundary of 16-bytes)
  11031.         size_t platformAppStateSize = FPL_ALIGNED_SIZE(sizeof(platform::PlatformAppState), 16);
  11032.  
  11033.         // Include video/audio state memory in app state memory as well
  11034. #if defined(FPL_ENABLE_VIDEO)
  11035.         size_t videoMemoryOffset = 0;
  11036.         if(initFlags & InitFlags::Video) {
  11037.             platformAppStateSize += platform::SIZE_PADDING;
  11038.             videoMemoryOffset = platformAppStateSize;
  11039.             platformAppStateSize += sizeof(common_video::VideoState);
  11040.         }
  11041. #endif
  11042.  
  11043. #if defined(FPL_ENABLE_AUDIO)
  11044.         size_t audioMemoryOffset = 0;
  11045.         if(initFlags & InitFlags::Audio) {
  11046.             platformAppStateSize += platform::SIZE_PADDING;
  11047.             audioMemoryOffset = platformAppStateSize;
  11048.             platformAppStateSize += sizeof(common_audio::AudioState);
  11049.         }
  11050. #endif
  11051.  
  11052.         FPL_LOG("Core", "Allocate Platform App State Memory of size '%zu':", platformAppStateSize);
  11053.         FPL_ASSERT(platform::global__AppState == nullptr);
  11054.         void *platformAppStateMemory = memory::MemoryAllocate(platformAppStateSize);
  11055.         if(platformAppStateMemory == nullptr) {
  11056.             FPL_LOG("Core", "Failed Allocating Platform App State Memory of size '%zu'", platformAppStateSize);
  11057.             common::PushError("Failed allocating app state memory of size '%zu'", platformAppStateSize);
  11058.             return false;
  11059.         }
  11060.  
  11061.         platform::PlatformAppState *appState = platform::global__AppState = (platform::PlatformAppState *)platformAppStateMemory;
  11062.         appState->initSettings = initSettings;
  11063.         appState->initFlags = initFlags;
  11064.         appState->currentSettings = initSettings;
  11065.  
  11066.         platform::PlatformInitState &initState = platform::global__InitState;
  11067.         initState = {};
  11068.         FPL_LOG("Core", "Successfully allocated Platform App State Memory of size '%zu'", platformAppStateSize);
  11069.  
  11070.     // Window is required for video always
  11071. #   if defined(FPL_ENABLE_VIDEO)
  11072.         if(appState->initFlags & InitFlags::Video) {
  11073.             appState->initFlags |= InitFlags::Window;
  11074.         }
  11075. #   endif
  11076.  
  11077.     // Initialize sub-platforms
  11078. #   if defined(FPL_SUBPLATFORM_POSIX)
  11079.         {
  11080.             FPL_LOG("Core", "Initialize POSIX Subplatform:");
  11081.             if(!subplatform_posix::PosixInitSubplatform(initFlags, initSettings, initState.posix, appState->posix)) {
  11082.                 FPL_LOG("Core", "Failed initializing POSIX Subplatform!");
  11083.                 common::PushError("Failed initializing POSIX Subplatform");
  11084.                 common_init::ReleasePlatformStates(initState, appState);
  11085.                 return false;
  11086.             }
  11087.             FPL_LOG("Core", "Successfully initialized POSIX Subplatform");
  11088.         }
  11089. #   endif // FPL_SUBPLATFORM_POSIX
  11090.  
  11091. #   if defined(FPL_SUBPLATFORM_X11)
  11092.         {
  11093.             FPL_LOG("Core", "Initialize X11 Subplatform:");
  11094.             if(!subplatform_x11::X11InitSubplatform(appState->x11)) {
  11095.                 FPL_LOG("Core", "Failed initializing X11 Subplatform!");
  11096.                 common::PushError("Failed initializing X11 Subplatform");
  11097.                 common_init::ReleasePlatformStates(initState, appState);
  11098.                 return false;
  11099.             }
  11100.             FPL_LOG("Core", "Successfully initialized X11 Subplatform");
  11101.         }
  11102. #   endif // FPL_SUBPLATFORM_X11
  11103.  
  11104.         // Initialize the actual platform (There can only be one at a time!)
  11105.         bool isInitialized = false;
  11106.         FPL_LOG("Core", "Initialize %s Platform:", FPL_PLATFORM_NAME);
  11107. #   if defined(FPL_PLATFORM_WIN32)
  11108.         isInitialized = platform_win32::Win32InitPlatform(appState->initFlags, initSettings, initState, appState);
  11109. #   elif defined(FPL_PLATFORM_LINUX)
  11110.         isInitialized = platform_linux::LinuxInitPlatform(appState->initFlags, initSettings, initState, appState);
  11111. #   endif
  11112.  
  11113.         if(!isInitialized) {
  11114.             FPL_LOG("Core", "Failed initializing %s Platform!", FPL_PLATFORM_NAME);
  11115.             common_init::ReleasePlatformStates(initState, appState);
  11116.             return false;
  11117.         }
  11118.         FPL_LOG("Core", "Successfully initialized %s Platform", FPL_PLATFORM_NAME);
  11119.  
  11120.     // Init video state
  11121. #   if defined(FPL_ENABLE_VIDEO)
  11122.         if(appState->initFlags & InitFlags::Video) {
  11123.             FPL_LOG("Core", "Init video state:");
  11124.             appState->video.mem = (uint8_t *)platformAppStateMemory + videoMemoryOffset;
  11125.             appState->video.memSize = sizeof(common_video::VideoState);
  11126.             common_video::VideoState *videoState = common_video::GetVideoState(appState);
  11127.             FPL_ASSERT(videoState != nullptr);
  11128.  
  11129.             VideoDriverType videoDriver = initSettings.video.driver;
  11130.             const char *videoDriverString = video::GetVideoDriverString(videoDriver);
  11131.             FPL_LOG("Core", "Load Video API for Driver '%s':", videoDriverString);
  11132.             {
  11133.                 if(!common_video::LoadVideoState(videoDriver, videoState)) {
  11134.                     FPL_LOG("Core", "Failed loading Video API for Driver '%s'!", videoDriverString);
  11135.                     common_init::ReleasePlatformStates(initState, appState);
  11136.                     return false;
  11137.                 }
  11138.             }
  11139.             FPL_LOG("Core", "Successfully loaded Video API for Driver '%s'", videoDriverString);
  11140.         }
  11141. #   endif // FPL_ENABLE_VIDEO
  11142.  
  11143.     // Init Window & event queue
  11144. #   if defined(FPL_ENABLE_WINDOW)
  11145.         if(appState->initFlags & InitFlags::Window) {
  11146.             FPL_LOG("Core", "Init Window:");
  11147.             platform::SetupWindowCallbacks winCallbacks = {};
  11148.             winCallbacks.postSetup = common_window::PostSetupWindowDefault;
  11149.             winCallbacks.preSetup = common_window::PreSetupWindowDefault;
  11150.             if(!common_window::InitWindow(initSettings, appState->currentSettings.window, appState, winCallbacks)) {
  11151.                 FPL_LOG("Core", "Failed initializing Window!");
  11152.                 common::PushError("Failed initialization window");
  11153.                 common_init::ReleasePlatformStates(initState, appState);
  11154.                 return false;
  11155.             }
  11156.             FPL_LOG("Core", "Successfully initialized Window");
  11157.         }
  11158. #   endif // FPL_ENABLE_WINDOW
  11159.  
  11160.     // Init Video
  11161. #   if defined(FPL_ENABLE_VIDEO)
  11162.         if(appState->initFlags & InitFlags::Video) {
  11163.             common_video::VideoState *videoState = common_video::GetVideoState(appState);
  11164.             FPL_ASSERT(videoState != nullptr);
  11165.             uint32_t windowWidth, windowHeight;
  11166.             if(appState->currentSettings.window.isFullscreen) {
  11167.                 windowWidth = appState->currentSettings.window.fullscreenWidth;
  11168.                 windowHeight = appState->currentSettings.window.fullscreenHeight;
  11169.             } else {
  11170.                 windowWidth = appState->currentSettings.window.windowWidth;
  11171.                 windowHeight = appState->currentSettings.window.windowWidth;
  11172.             }
  11173.             const char *videoDriverName = video::GetVideoDriverString(initSettings.video.driver);
  11174.             FPL_LOG("Core", "Init Video with Driver '%s':", videoDriverName);
  11175.             if(!common_video::InitVideo(initSettings.video.driver, initSettings.video, windowWidth, windowHeight, appState, videoState)) {
  11176.                 FPL_LOG("Core", "Failed initializing Video Driver '%s'!", videoDriverName);
  11177.                 common::PushError("Failed initialization video with settings (Driver=%s, Width=%d, Height=%d)", videoDriverName, windowWidth, windowHeight);
  11178.                 common_init::ReleasePlatformStates(initState, appState);
  11179.                 return false;
  11180.             }
  11181.             FPL_LOG("Core", "Successfully initialized Video Driver '%s'", videoDriverName);
  11182.         }
  11183. #   endif // FPL_ENABLE_VIDEO
  11184.  
  11185.     // Init Audio
  11186. #   if defined(FPL_ENABLE_AUDIO)
  11187.         if(appState->initFlags & InitFlags::Audio) {
  11188.             appState->audio.mem = (uint8_t *)platformAppStateMemory + audioMemoryOffset;
  11189.             appState->audio.memSize = sizeof(common_audio::AudioState);
  11190.             const char *audioDriverName = audio::GetAudioDriverString(initSettings.audio.driver);
  11191.             FPL_LOG("Core", "Init Audio with Driver '%s':", audioDriverName);
  11192.             common_audio::AudioState *audioState = common_audio::GetAudioState(appState);
  11193.             FPL_ASSERT(audioState != nullptr);
  11194.             if(common_audio::InitAudio(initSettings.audio, audioState) != audio::AudioResult::Success) {
  11195.                 FPL_LOG("Core", "Failed initializing Audio Driver '%s'!", audioDriverName);
  11196.                 common::PushError("Failed initialization audio with settings (Driver=%s, Format=%s, SampleRate=%d, Channels=%d, BufferSize=%d)", audioDriverName, audio::GetAudioFormatString(initSettings.audio.deviceFormat.type), initSettings.audio.deviceFormat.sampleRate, initSettings.audio.deviceFormat.channels);
  11197.                 common_init::ReleasePlatformStates(initState, appState);
  11198.                 return false;
  11199.             }
  11200.             FPL_LOG("Core", "Successfully initialized Audio Driver '%s'", audioDriverName);
  11201.         }
  11202. #   endif // FPL_ENABLE_AUDIO
  11203.  
  11204.         initState.isInitialized = true;
  11205.         return true;
  11206.     }
  11207. } // fpl
  11208.  
  11209. #endif // FPL_SYSTEM_INIT_DEFINED
  11210.  
  11211. #endif // FPL_IMPLEMENTATION && !FPL_IMPLEMENTED
  11212.  
  11213. #include <GL/gl.h>
  11214.  
  11215. int main(int argc, char *args[]) {
  11216.     if (fpl::InitPlatform(fpl::InitFlags::Video)) {
  11217.         const char *renderer = (const char *)glGetString(GL_RENDERER);
  11218.         fpl::console::ConsoleFormatOut("%s\n", renderer);
  11219.         fpl::ReleasePlatform();
  11220.         return 0;
  11221.     } else {
  11222.         return -1;
  11223.     }
  11224. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement