-
Notifications
You must be signed in to change notification settings - Fork 13
final platform layer h
Finalspace edited this page May 29, 2026
·
1 revision
Go to the documentation of this file.
/*
░▒▓████████▓▒░▒▓█▓▒░▒▓███████▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██████▓▒░░▒▓███████▓▒░░▒▓██████████████▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓███████▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓██████▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓█▓▒░ ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░░▒▓██████▓▒░░▒▓██████▓▒░ ░▒▓███████▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░
░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░
-------------------------------------------------------------------------------
About
-------------------------------------------------------------------------------
Final Platform Layer is a single-header-file cross-platform C/C++ development library designed to abstract the underlying platform to a simple and easy-to-use API, providing low-level access to (Window, Video, Audio, Input, File/Path IO, Threads, Memory, Hardware, etc.).
The main focus is game/media/simulation development, so the default settings will create a window, set up an OpenGL rendering context, and initialize audio playback on any platform.
It is written in C99 for simplicity and best portability but is C++ compatible as well.
FPL supports the platforms Windows/Linux/Unix for the architectures x86/x64/ARM.
The only dependencies are built-in operating system libraries and a C99 or C++11 compliant compiler.
It is licensed under the MIT License. This license allows you to use FPL freely in any software.
-------------------------------------------------------------------------------
Author
-------------------------------------------------------------------------------
- Torsten Spaete (alias Finalspace)
- Professional application developer
- 30+ years of programming experience
- Data visualization, Software-Architecture, Multimedia & Physics & Game development
-------------------------------------------------------------------------------
Getting started
-------------------------------------------------------------------------------
- Drop this file into any C/C++ project you want and include it in any place you want.
- In your main translation unit, provide the typical main() entry point.
- Define FPL_IMPLEMENTATION in at least one translation unit before including this header file.
- Initialize the platform using fplPlatformInit().
- Use the features you want.
- Release the platform when you are done using fplPlatformRelease().
-------------------------------------------------------------------------------
Usage: Hello World Console Application
-------------------------------------------------------------------------------
#define FPL_IMPLEMENTATION
#include <final_platform_layer.h>
int main(int argc, char **args) {
if (fplPlatformInit(fplInitFlags_None, fpl_null)) {
fplConsoleOut("Hello World!");
fplPlatformRelease();
return 0;
} else {
return -1;
}
}
-------------------------------------------------------------------------------
Usage: OpenGL Legacy or Modern Application
-------------------------------------------------------------------------------
#define FPL_IMPLEMENTATION
#include <final_platform_layer.h>
int main(int argc, char **args) {
// Create default settings
fplSettings settings = fplMakeDefaultSettings();
// Overwrite the video backend
settings.video.backend = fplVideoBackendType_OpenGL;
// Legacy OpenGL
settings.video.graphics.opengl.compatibilityFlags = fplOpenGLCompatibilityFlags_Legacy;
// or
// Modern OpenGL
settings.video.graphics.opengl.compatibilityFlags = fplOpenGLCompatibilityFlags_Core;
settings.video.graphics.opengl.majorVersion = 3;
settings.video.graphics.opengl.minorVersion = 3;
if (fplPlatformInit(fplInitFlags_Video, &settings)) {
// Event/Main loop
while (fplWindowUpdate()) {
// Poll events
fplEvent ev;
while (fplPollEvent(&ev)) {
// ...
}
// Your code goes here
fplVideoFlip();
}
fplPlatformRelease();
return 0;
} else {
return -1;
}
}
-------------------------------------------------------------------------------
Output Buffer Conventions
-------------------------------------------------------------------------------
All functions that fill a destination buffer (string copy, append, format, path,
UTF-8/wide conversion) follow a single contract:
- The return type is size_t. The value is the number of characters required
(excluding the NUL terminator), NOT a pointer.
- Query mode: if dest is NULL or maxDestLen is 0, the function returns the
required size and writes nothing. Use this to size a buffer ahead of time.
- Buffer too small: if the required size exceeds maxDestLen, the function
returns 0 and does not leave a partial buffer behind.
- Success: when dest is non-NULL and large enough, the buffer is always
NUL-terminated and the function returns the required size (excluding NUL).
- Hard errors (NULL input, format error) return 0.
Functions that follow this contract: fplCopyString, fplCopyStringLen,
fplStringAppend, fplStringAppendLen, fplEnforcePathSeparator,
fplEnforcePathSeparatorLen, fplStringFormat, fplStringFormatArgs,
fplPathCombine, fplPathNormalize, fplUTF8StringToWideString,
fplWideStringToUTF8String, fplGetWindowTitle, fplGetExecutableFilePath,
fplGetHomePath.
-------------------------------------------------------------------------------
License
-------------------------------------------------------------------------------
Final Platform Layer is released under the following license:
MIT License
Copyright (c) 2017-2026 Torsten Spaete
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// ----------------------------------------------------------------------------
// > CHANGELOG
// ----------------------------------------------------------------------------
// ****************************************************************************
//
// > HEADER
//
// ****************************************************************************
#ifndef FPL_HEADER_H
#define FPL_HEADER_H
//
// C++/C99 preprocessor detection
//
// https://en.wikipedia.org/wiki/C99#Version_detection
//
// @note C99 is supported since MSVC 2015.
// @note C11 is supported since MSVC 2019.
// @note C17 is supported since MSVC 2019 16.8 (/std:c17).
// @note C23 is partially supported since MSVC 2022 17.9 (/std:clatest).
//
#if defined(__cplusplus)
# define FPL_IS_CPP
# if (__cplusplus >= 201103L)
# define FPL_IS_CPP11
# endif
# if (__cplusplus >= 201402L)
# define FPL_IS_CPP14
# endif
# if (__cplusplus >= 201703L)
# define FPL_IS_CPP17
# endif
# if (__cplusplus >= 202004L)
# define FPL_IS_CPP20
# endif
# if (__cplusplus >= 202302L)
# define FPL_IS_CPP23
# endif
#elif defined(_MSC_VER)
# if (_MSC_VER >= 1900)
# define FPL_IS_C99
# if (_MSC_VER >= 1920)
# define FPL_IS_C11
# endif
# if (_MSC_VER >= 1928)
# define FPL_IS_C17
# endif
# if (_MSC_VER >= 1939)
# define FPL_IS_C23
# endif
# else
# error "This MSVC compiler does not support C99 or higher!"
# endif
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
# define FPL_IS_C99
# if __STDC_VERSION__ >= 201112L
# define FPL_IS_C11
# endif
# if __STDC_VERSION__ >= 201710L
# define FPL_IS_C17
# endif
# if __STDC_VERSION__ >= 202311L
# define FPL_IS_C23
# endif
#else
# error "This C compiler is not supported!"
#endif
//
// Architecture preprocessor detection (x86, x64, arm32, arm64, apple arm64, riscv, powerpc, mips, sparc)
//
// https://sourceforge.net/p/predef/wiki/Architectures/
//
#if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__)
# define FPL_ARCH_X64
#elif defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_)
# define FPL_ARCH_X86
#elif defined(__aarch64__) || defined(_M_ARM64)
# if defined(__APPLE__)
# define FPL_ARCH_APPLE_ARM64
# else
# define FPL_ARCH_ARM64
# endif
#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7__) || defined(__armv7__)
# define FPL_ARCH_ARM32
#elif defined(__riscv) || defined(__riscv_xlen)
# define FPL_ARCH_RISCV
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(_ARCH_PPC64)
# define FPL_ARCH_POWERPC64
#elif defined(__powerpc__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC)
# define FPL_ARCH_POWERPC32
#elif defined(__mips__) || defined(__mips64) || defined(_MIPS_ARCH)
# define FPL_ARCH_MIPS
#elif defined(__sparc__) || defined(__sparcv9)
# define FPL_ARCH_SPARC
#else
# error "This architecture is not supported!"
#endif // FPL_ARCH
//
// CPU width preprocessor detection
//
#if defined(_WIN32)
# if defined(_WIN64)
# define FPL__M_CPU_64BIT // 64-bit system
# else
# define FPL__M_CPU_32BIT // 32-bit system
# endif
#elif defined(__GNUC__) || defined(__clang__)
# if defined(__LP64__) || defined(_LP64)
# define FPL__M_CPU_64BIT // 64-bit system
# else
# define FPL__M_CPU_32BIT // 32-bit system
# endif
#elif defined(_MSC_VER)
# if defined(_WIN64) || defined(_M_X64) || defined(__x86_64__)
# define FPL__M_CPU_64BIT // 64-bit system
# else
# define FPL__M_CPU_32BIT // 32-bit system
# endif
#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__)
# if defined(__x86_64__) || defined(__aarch64__) || defined(__ppc64__)
# define FPL__M_CPU_64BIT // 64-bit system
# else
# define FPL__M_CPU_32BIT // 32-bit system
# endif
#else
# if (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8) || (sizeof(void *) == 8)
# define FPL__M_CPU_64BIT // 64-bit system
# else
# define FPL__M_CPU_32BIT // 32-bit system
# endif
#endif
#if defined(FPL__M_CPU_64BIT)
# define FPL_CPU_64BIT
#elif defined(FPL__M_CPU_32BIT)
# define FPL_CPU_32BIT
#endif
//
// Cacheline preprocessor detection
//
// - X86 has a cacheline size of 64 bytes, since pentium pro
// - Apple M* has a cacheline size of 128 bytes
//
#if defined(FPL_ARCH_X64) || defined(FPL_ARCH_X86)
# define FPL_CACHELINE_SIZE 64
#elif defined(FPL_ARCH_ARM32)
# define FPL_CACHELINE_SIZE 32
#elif defined(FPL_ARCH_ARM64) || defined(FPL_ARCH_APPLE_ARM64)
# define FPL_CACHELINE_SIZE 128
#elif defined(FPL_ARCH_POWERPC64)
# define FPL_CACHELINE_SIZE 128
#else
# define FPL_CACHELINE_SIZE 64
#endif
//
// Compiler preprocessor detection
//
// http://beefchunk.com/documentation/lang/c/pre-defined-c/precomp.html
// http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros
//
#if defined(__clang__)
# define FPL_COMPILER_CLANG
#elif defined(__INTEL_COMPILER)
# define FPL_COMPILER_INTEL
#elif defined(__MINGW32__) || defined(__MINGW64__)
# define FPL_COMPILER_MINGW
#elif defined(__CC_ARM)
# define FPL_COMPILER_ARM
#elif defined(__GNUC__)
# define FPL_COMPILER_GCC
#elif defined(_MSC_VER)
# define FPL_COMPILER_MSVC
#elif defined(__APPLE__)
# define FPL_COMPILER_APPLE_CLANG
#elif defined(__BORLANDC__)
# define FPL_COMPILER_BORLAND
#elif defined(__TCC__)
# define FPL_COMPILER_TCC
#elif defined(__DMC__)
# define FPL_COMPILER_DMC
#elif defined(__CSMC__)
# define FPL_COMPILER_CSMC
#elif defined(__LINARO__)
# define FPL_COMPILER_LINARO
#else
# error "This compiler is not supported!"
#endif // FPL_COMPILER
//
// HasInclude
// Must be available before platform detection, so X11 subplatform can be gated on header presence.
//
#if defined(__has_include)
# define fpl__m_HasInclude(inc) __has_include(inc)
#else
# define fpl__m_HasInclude(inc) (1)
#endif
#define fplHasInclude(inc) fpl__m_HasInclude(inc)
//
// Platform preprocessor detection
//
// https://sourceforge.net/p/predef/wiki/OperatingSystems/
//
// Only platforms that are supported are listed
//
#if defined(_WIN32) || defined(_WIN64)
# define FPL_PLATFORM_WINDOWS
# define FPL_PLATFORM_NAME "Windows"
#elif defined(__linux__) || defined(__gnu_linux__)
# define FPL_PLATFORM_LINUX
# define FPL_PLATFORM_NAME "Linux"
# define FPL_SUBPLATFORM_POSIX
# if fplHasInclude(<X11/X.h>)
# define FPL_SUBPLATFORM_X11
# endif
# define FPL_SUBPLATFORM_STD_STRINGS
# define FPL_SUBPLATFORM_STD_CONSOLE
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__bsdi__)
// @NOTE(final): BSD is treated as a subplatform for now
// MAP_ANON and other BSD APIs are gated behind __BSD_VISIBLE in <sys/cdefs.h>.
// Compiling with -std=c99 implicitly sets _POSIX_C_SOURCE which disables __BSD_VISIBLE.
// Force it on before any system header is included.
# if !defined(__BSD_VISIBLE)
# define __BSD_VISIBLE 1
# endif
# define FPL_PLATFORM_UNIX
# define FPL_PLATFORM_NAME "BSD"
# define FPL_SUBPLATFORM_BSD
# define FPL_SUBPLATFORM_POSIX
# if fplHasInclude(<X11/X.h>)
# define FPL_SUBPLATFORM_X11
# endif
# define FPL_SUBPLATFORM_STD_STRINGS
# define FPL_SUBPLATFORM_STD_CONSOLE
#elif defined(unix) || defined(__unix) || defined(__unix__)
# define FPL_PLATFORM_UNIX
# define FPL_PLATFORM_NAME "Unix"
# define FPL_SUBPLATFORM_POSIX
# if fplHasInclude(<X11/X.h>)
# define FPL_SUBPLATFORM_X11
# endif
# define FPL_SUBPLATFORM_STD_STRINGS
# define FPL_SUBPLATFORM_STD_CONSOLE
#else
# error "This platform is not supported!"
#endif // FPL_PLATFORM
//
// Assembler keyword is compiler specific
//
#if defined(FPL_COMPILER_CLANG) || defined(FPL_COMPILER_GCC)
# define fpl__m_Asm __asm__
#elif defined(FPL_COMPILER_MSVC)
# define fpl__m_Asm __asm
#else
# define fpl__m_Asm asm
#endif
#define fplAsm fpl__m_Asm
//
// Minimum alignment
//
#if defined(FPL_COMPILER_MSVC)
# define fpl__MinAlignment 8
#elif defined(FPL_COMPILER_GCC) || defined(FPL_COMPILER_CLANG)
# if defined(FPL_CPU_64BIT)
# define fpl__MinAlignment 8
# else
# define fpl__MinAlignment 4
# endif
#else
# define fpl__MinAlignment 8
#endif
#define fplMinAlignment fpl__MinAlignment
//
// Alignment keyword
//
#if defined(FPL_IS_CPP11)
# define fpl__m_AlignAs(N) alignas(N)
#elif defined(FPL_COMPILER_MSVC)
# define fpl__m_AlignAs(N) __declspec(align(N))
#elif defined(FPL_COMPILER_GCC) || defined(FPL_COMPILER_CLANG)
# define fpl__m_AlignAs(N) __attribute__((aligned(N)))
#else
# define fpl__m_AlignAs(N)
#endif
#define fplAlignAs(N) fpl__m_AlignAs(N)
//
// Defines required for POSIX (mmap, 64-bit file io, etc.)
//
#if defined(FPL_SUBPLATFORM_POSIX)
# if !defined(_XOPEN_SOURCE)
# define _XOPEN_SOURCE 600
# endif
# if !defined(_DEFAULT_SOURCE)
# define _DEFAULT_SOURCE 1
# endif
# if !defined(__STDC_FORMAT_MACROS)
# define __STDC_FORMAT_MACROS
# endif
# if !defined(__STDC_LIMIT_MACROS)
# define __STDC_LIMIT_MACROS
# endif
# if !defined(_LARGEFILE_SOURCE)
# define _LARGEFILE_SOURCE
# endif
# if !defined(_LARGEFILE64_SOURCE)
# define _LARGEFILE64_SOURCE
# endif
# if !defined(_FILE_OFFSET_BITS)
# define _FILE_OFFSET_BITS 64
# endif
#endif
#if defined(FPL_PLATFORM_LINUX)
# define FPL__INCLUDE_ALLOCA
#else
# define FPL__INCLUDE_MALLOC
#endif
// MingW compiler hack
#if defined(FPL_PLATFORM_WINDOWS) && defined(FPL_COMPILER_MINGW)
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0600
# endif
#endif // FPL_COMPILER_MINGW
//
// Storage class identifiers
//
#define fpl_globalvar static
#define fpl_localvar static
#define fpl_internal static
#define fpl_inline inline
#if defined(FPL_IS_CPP)
# define fpl_internal_inline inline
#else
# define fpl_internal_inline static inline
#endif
#if defined(FPL_IS_CPP)
# define fpl_extern_inline inline
#else
# define fpl_extern_inline extern inline
#endif
#if defined(FPL_IS_CPP)
# define fpl_extern
#else
# define fpl_extern extern
#endif
//
// DLL Export/Import definition
//
#if defined(_WIN32) || defined(__CYGWIN__)
# ifdef __GNUC__
# define fpl__m_dllexport __attribute__ ((dllexport))
# define fpl__m_dllimport __attribute__ ((dllimport))
# else
# define fpl__m_dllexport __declspec(dllexport)
# define fpl__m_dllimport __declspec(dllimport)
# endif
# define fpl__m_dlllocal
#else
# if __GNUC__ >= 4
# define fpl__m_dllimport __attribute__((visibility("default")))
# define fpl__m_dllexport __attribute__((visibility("default")))
# define fpl__m_dlllocal __attribute__((visibility("hidden")))
# else
# define fpl__m_dllimport
# define fpl__m_dllexport
# define fpl__m_dlllocal
# endif
#endif
#define fpl_dllimport fpl__m_dllimport
#define fpl_dllexport fpl__m_dllexport
#define fpl_dlllocal fpl__m_dlllocal
//
// API Call
//
#if defined(FPL_API_AS_PRIVATE)
# define fpl__m_api static
#elif defined(FPL_DLLEXPORT)
# define fpl__m_api fpl_dllexport
#elif defined(FPL_DLLIMPORT)
# define fpl__m_api fpl_dllimport
#else
# define fpl__m_api fpl_extern
#endif // FPL_API_AS_PRIVATE
#define fpl_api fpl__m_api
#define fpl_main
#if defined(FPL_IS_CPP)
# define fpl__m_platform_api extern "C" fpl_api
# define fpl__m_common_api extern "C" fpl_api
#else
# define fpl__m_platform_api fpl_api
# define fpl__m_common_api fpl_api
#endif
#define fpl_platform_api fpl__m_platform_api
#define fpl_common_api fpl__m_common_api
//
// Inlining
//
#if defined(FPL_COMPILER_MSVC)
# define fpl__m_force_inline __forceinline
# define fpl__m_no_inline __declspec(noinline)
#elif defined(FPL_COMPILER_GCC) || defined(FPL_COMPILER_CLANG)
# define fpl__m_force_inline __attribute__((__always_inline__)) inline
# define fpl__m_no_inline __attribute__((noinline))
#else
# define fpl__m_force_inline inline
# define fpl__m_no_inline
#endif
#define fpl_force_inline fpl__m_force_inline
#define fpl_no_inline fpl__m_no_inline
//
// When C-Runtime is disabled we cannot use any function from the C-Standard Library <stdio.h> or <stdlib.h>
//
#if defined(FPL_NO_CRT)
# if defined(FPL_SUBPLATFORM_STD_CONSOLE)
# undef FPL_SUBPLATFORM_STD_CONSOLE
# endif
# if defined(FPL_SUBPLATFORM_STD_STRINGS)
# undef FPL_SUBPLATFORM_STD_STRINGS
# endif
# if !defined(FPL_USERFUNC_vsnprintf)
# error "You need to provide a replacement for vsnprintf() by defining FPL_USERFUNC_vsnprintf!"
# endif
#endif
//
// Application type preprocessor setup
//
// FPL_NO_CRT = Either FPL_APPTYPE_CONSOLE or FPL_APPTYPE_WINDOW must be set manually
// FPL_NO_APPTYPE = Disable app type detection entirely
// FPL_APPTYPE_CONSOLE = Console application
// FPL_APPTYPE_WINDOW = Window application
//
#if defined(FPL_APPTYPE_CONSOLE) && defined(FPL_APPTYPE_WINDOW)
# error "It is not allowed to define both FPL_APPTYPE_CONSOLE and FPL_APPTYPE_WINDOW!"
#endif
#if defined(FPL_NO_CRT)
# if !defined(FPL_APPTYPE_CONSOLE) && !defined(FPL_APPTYPE_WINDOW)
# error "In 'No-CRT' mode you need to define either FPL_APPTYPE_CONSOLE or FPL_APPTYPE_WINDOW manually!"
# endif
#elif !defined(FPL_NO_APPTYPE) && !(defined(FPL_APPTYPE_CONSOLE) || defined(FPL_APPTYPE_WINDOW))
# if !defined(FPL_NO_WINDOW)
# define FPL_APPTYPE_WINDOW
# else
# define FPL_APPTYPE_CONSOLE
# endif
#endif
//
// Include entry points always when its not disabled and implementation block is compiled in
//
#if defined(FPL_IMPLEMENTATION) && !defined(FPL_NO_ENTRYPOINT)
# define FPL_ENTRYPOINT
#endif
//
// Debug/Release preprocessor setup
//
#if defined(FPL_DEBUG)
# define FPL__ENABLE_DEBUG
#elif defined(FPL_RELEASE)
# define FPL__ENABLE_RELEASE
#endif
//
// Compiler preprocessor setup
//
#if defined(FPL_COMPILER_MSVC)
// Debug/Release detection
# if !defined(FPL__ENABLE_DEBUG) && !defined(FPL__ENABLE_RELEASE)
# if defined(_DEBUG) || (!defined(NDEBUG))
# define FPL__ENABLE_DEBUG
# else
# define FPL__ENABLE_RELEASE
# endif
# endif
// Function name macro (Win32)
# define FPL__M_FUNCTION_NAME __FUNCTION__
// Setup MSVC subsystem hints
# if defined(FPL_APPTYPE_WINDOW)
# pragma comment(linker, "/SUBSYSTEM:WINDOWS")
# elif defined(FPL_APPTYPE_CONSOLE)
# pragma comment(linker, "/SUBSYSTEM:CONSOLE")
# endif
// Setup MSVC linker hints
# pragma comment(lib, "kernel32.lib")
#else
// Function name macro (Other compilers)
# define FPL__M_FUNCTION_NAME __FUNCTION__
#endif // FPL_COMPILER
// Debug Release fallback
#if !defined(FPL__ENABLE_DEBUG) && !defined(FPL__ENABLE_RELEASE)
# define FPL__ENABLE_DEBUG
#endif
#if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__)
# define FPL__M_IS_IDE 1
#else
# define FPL__M_IS_IDE 0
#endif
#define FPL_IS_IDE FPL__M_IS_IDE
#define FPL_FUNCTION_NAME FPL__M_FUNCTION_NAME
//
// Options & Feature detection
//
//
// CPU Instruction Set Detection based on compiler settings
//
typedef enum {
= 0,
,
,
,
,
,
,
,
,
,
,
} ;
#if defined(__AVX512F__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_AVX512
#elif defined(__AVX2__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_AVX2
#elif defined(__AVX__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_AVX
#elif defined(__SSE4_2__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSE4_2
#elif defined(__SSE4_1__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSE4_1
#elif defined(__SSSE3__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSSE3
#elif defined(__SSE3__)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSE3
#elif defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(FPL_ARCH_X64)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSE2
#elif defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_SSE
#elif defined(FPL_ARCH_X86)
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_IA32
#else
# define FPL__M_X86_CPU_INSTR_SET_LEVEL fplX86InstructionSetLevel_None
#endif
#define FPL_X86_CPU_INSTR_SET_LEVEL FPL__M_X86_CPU_INSTR_SET_LEVEL
//
// Assertions preprocessor setup
//
// FPL_NO_WINDOW or FPL_APPTYPE_CONSOLE = Disable window support entirely
// FPL_NO_ASSERTIONS = Disable assertions entirely
// FPL_FORCE_ASSERTIONS = Force assertions always
// FPL_NO_C_ASSERT or FPL_NO_CRT = Do not allow C-Runtime assertions, use custom macros instead
//
#if !defined(FPL_NO_ASSERTIONS)
# if !defined(FPL_FORCE_ASSERTIONS)
# if defined(FPL__ENABLE_DEBUG)
# define FPL__ENABLE_ASSERTIONS
# endif
# else
# define FPL__ENABLE_ASSERTIONS
# endif
#endif // !FPL_NO_ASSERTIONS
#if defined(FPL__ENABLE_ASSERTIONS)
# if !defined(FPL_NO_C_ASSERT) && !defined(FPL_NO_CRT)
# define FPL__ENABLE_C_ASSERT
# endif
#endif // FPL__ENABLE_ASSERTIONS
//
// Window preprocessor setup
//
// FPL_NO_WINDOW or FPL_APPTYPE_CONSOLE = Disable window support entirely
//
#if !defined(FPL_NO_WINDOW) && !defined(FPL_APPTYPE_CONSOLE)
# define FPL__SUPPORT_WINDOW
#endif
#if defined(FPL__SUPPORT_WINDOW)
# if (defined(FPL_PLATFORM_LINUX) || defined(FPL_PLATFORM_UNIX)) && !defined(FPL_SUBPLATFORM_X11)
# warning "FPL-Warning: X11 development library is missing, windowing support is disabled. Please install 'libX11-dev' and try again!"
# undef FPL__SUPPORT_WINDOW
# endif
#endif // FPL__SUPPORT_WINDOW
//
// Video preprocessor setup
//
// FPL_NO_VIDEO = Disable video support entirely
// FPL_NO_VIDEO_OPENGL = Disable all OpenGL video backends
// FPL_NO_VIDEO_VULKAN = Disable Vulkan video backend
// FPL_NO_VIDEO_SOFTWARE = Disable all Software video backends
//
#if !defined(FPL_NO_VIDEO)
# define FPL__SUPPORT_VIDEO
#endif // !FPL_NO_VIDEO
#if defined(FPL__SUPPORT_VIDEO)
# if !defined(FPL_NO_VIDEO_OPENGL)
# define FPL__SUPPORT_VIDEO_OPENGL
# endif
# if !defined(FPL_NO_VIDEO_VULKAN)
# define FPL__SUPPORT_VIDEO_VULKAN
# endif
# if !defined(FPL_NO_VIDEO_SOFTWARE)
# define FPL__SUPPORT_VIDEO_SOFTWARE
# endif
#endif // FPL__SUPPORT_VIDEO
//
// Remove video support when the Window is disabled.
//
#if !defined(FPL__SUPPORT_WINDOW)
# if defined(FPL__SUPPORT_VIDEO)
# undef FPL__SUPPORT_VIDEO
# endif
# if defined(FPL__SUPPORT_VIDEO_OPENGL)
# undef FPL__SUPPORT_VIDEO_OPENGL
# endif
# if defined(FPL__SUPPORT_VIDEO_VULKAN)
# undef FPL__SUPPORT_VIDEO_VULKAN
# endif
# if defined(FPL__SUPPORT_VIDEO_SOFTWARE)
# undef FPL__SUPPORT_VIDEO_SOFTWARE
# endif
#endif // !FPL__SUPPORT_WINDOW
//
// Audio preprocessor setup
//
// FPL_NO_AUDIO = Disable audio support entirely
// FPL_NO_AUDIO_DIRECTSOUND = Disable DirectSound audio backend
// FPL_NO_AUDIO_WASAPI = Disable WASAPI audio backend
// FPL_NO_AUDIO_ALSA = Disable ALSA audio backend
// FPL_NO_AUDIO_PULSEAUDIO = Disable PulseAudio audio backend
// FPL_NO_AUDIO_PIPEWIRE = Disable PipeWire audio backend
// FPL_NO_AUDIO_OSS = Disable OSS audio backend
//
#if !defined(FPL_NO_AUDIO)
# define FPL__SUPPORT_AUDIO
#endif // !FPL_NO_AUDIO
#if defined(FPL__SUPPORT_AUDIO)
# if !defined(FPL_NO_AUDIO_DIRECTSOUND) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_AUDIO_DIRECTSOUND // <dsound.h> is always present on windows
# endif
# if !defined(FPL_NO_AUDIO_WASAPI) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_AUDIO_WASAPI // WASAPI uses runtime linking to ole32.dll, no dev headers required
# endif
# if !defined(FPL_NO_AUDIO_ALSA) && defined(FPL_PLATFORM_LINUX)
# if !defined(FPL_NO_RUNTIME_LINKING) || fplHasInclude(<alsa/asoundlib.h>)
# define FPL__SUPPORT_AUDIO_ALSA
# endif
# endif
# if !defined(FPL_NO_AUDIO_PULSEAUDIO) && (defined(FPL_PLATFORM_LINUX) || defined(FPL_PLATFORM_UNIX))
# if !defined(FPL_NO_RUNTIME_LINKING) || fplHasInclude(<pulse/pulseaudio.h>)
# define FPL__SUPPORT_AUDIO_PULSEAUDIO // PulseAudio backend uses runtime linking to libpulse.so.0, no dev headers are required
# endif
# endif
# if !defined(FPL_NO_AUDIO_PIPEWIRE) && (defined(FPL_PLATFORM_LINUX) || defined(FPL_PLATFORM_UNIX))
# if !defined(FPL_NO_RUNTIME_LINKING) || fplHasInclude(<pipewire/pipewire.h>)
# define FPL__SUPPORT_AUDIO_PIPEWIRE // PipeWire backend uses runtime linking to libpipewire-0.3.so.0, no dev headers are required
# endif
# endif
# if !defined(FPL_NO_AUDIO_OSS) && (defined(FPL_PLATFORM_LINUX) || defined(FPL_PLATFORM_UNIX))
# if !defined(FPL_NO_RUNTIME_LINKING) || fplHasInclude(<sys/soundcard.h>)
# define FPL__SUPPORT_AUDIO_OSS // OSS backend uses direct ioctl/write on /dev/dsp, no library linking required
# endif
# endif
#endif // FPL__SUPPORT_AUDIO
//
// Input preprocessor setup
//
// FPL_NO_INPUT = Disable input subsystem entirely
// FPL_NO_INPUT_XINPUT = Disable XInput backend (Windows)
// FPL_NO_INPUT_DINPUT = Disable DirectInput backend (Windows)
// FPL_NO_INPUT_RAWINPUT = Disable RawInput backend (Windows)
// FPL_NO_INPUT_WIN32 = Disable Win32 keyboard/mouse backend
// FPL_NO_INPUT_X11 = Disable X11 keyboard/mouse backend
// FPL_NO_INPUT_LINUX_JOYSTICK = Disable /dev/input/jsX backend (Linux)
// FPL_NO_INPUT_UNIX_GAMEPAD = Disable BSD/Unix gamepad backend
//
#if !defined(FPL_NO_INPUT)
# define FPL__SUPPORT_INPUT
#endif // !FPL_NO_INPUT
#if defined(FPL__SUPPORT_INPUT)
# if !defined(FPL_NO_INPUT_XINPUT) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_INPUT_XINPUT
# endif
# if !defined(FPL_NO_INPUT_DINPUT) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_INPUT_DINPUT
# endif
# if !defined(FPL_NO_INPUT_RAWINPUT) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_INPUT_RAWINPUT
# endif
# if !defined(FPL_NO_INPUT_WIN32) && defined(FPL_PLATFORM_WINDOWS)
# define FPL__SUPPORT_INPUT_WIN32
# endif
# if !defined(FPL_NO_INPUT_X11) && defined(FPL_SUBPLATFORM_X11)
# define FPL__SUPPORT_INPUT_X11
# endif
# if !defined(FPL_NO_INPUT_LINUX_JOYSTICK) && defined(FPL_PLATFORM_LINUX)
# define FPL__SUPPORT_INPUT_LINUX_JOYSTICK
# endif
# if !defined(FPL_NO_INPUT_UNIX_GAMEPAD) && defined(FPL_SUBPLATFORM_POSIX)
# define FPL__SUPPORT_INPUT_UNIX_GAMEPAD
# endif
#endif // FPL__SUPPORT_INPUT
//
// Drop subplatform X11, when neither window nor X11-input is supported
//
#if !defined(FPL__SUPPORT_WINDOW) && !defined(FPL__SUPPORT_INPUT_X11)
# if defined(FPL_SUBPLATFORM_X11)
# undef FPL_SUBPLATFORM_X11
# endif
#endif
//
// Enable supports (FPL uses _ENABLE_ internally only)
//
#if defined(FPL__SUPPORT_WINDOW)
# define FPL__ENABLE_WINDOW
#endif // FPL__SUPPORT_WINDOW
#if defined(FPL__SUPPORT_VIDEO)
# define FPL__ENABLE_VIDEO
# if defined(FPL__SUPPORT_VIDEO_OPENGL)
# define FPL__ENABLE_VIDEO_OPENGL
# endif
# if defined(FPL__SUPPORT_VIDEO_VULKAN)
# define FPL__ENABLE_VIDEO_VULKAN
# endif
# if defined(FPL__SUPPORT_VIDEO_SOFTWARE)
# define FPL__ENABLE_VIDEO_SOFTWARE
# endif
#endif // FPL__SUPPORT_VIDEO
#if defined(FPL__SUPPORT_AUDIO)
# define FPL__ENABLE_AUDIO
# if defined(FPL__SUPPORT_AUDIO_DIRECTSOUND)
# define FPL__ENABLE_AUDIO_DIRECTSOUND
# endif
# if defined(FPL__SUPPORT_AUDIO_WASAPI)
# define FPL__ENABLE_AUDIO_WASAPI
# endif
# if defined(FPL__SUPPORT_AUDIO_ALSA)
# define FPL__ENABLE_AUDIO_ALSA
# endif
# if defined(FPL__SUPPORT_AUDIO_PULSEAUDIO)
# define FPL__ENABLE_AUDIO_PULSEAUDIO
# endif
# if defined(FPL__SUPPORT_AUDIO_PIPEWIRE)
# define FPL__ENABLE_AUDIO_PIPEWIRE
# endif
# if defined(FPL__SUPPORT_AUDIO_OSS)
# define FPL__ENABLE_AUDIO_OSS
# endif
#endif // FPL__SUPPORT_AUDIO
#if defined(FPL__SUPPORT_INPUT)
# define FPL__ENABLE_INPUT
# if defined(FPL__SUPPORT_INPUT_XINPUT)
# define FPL__ENABLE_INPUT_XINPUT
# endif
# if defined(FPL__SUPPORT_INPUT_DINPUT)
# define FPL__ENABLE_INPUT_DINPUT
# endif
# if defined(FPL__SUPPORT_INPUT_RAWINPUT)
# define FPL__ENABLE_INPUT_RAWINPUT
# endif
# if defined(FPL__SUPPORT_INPUT_WIN32)
# define FPL__ENABLE_INPUT_WIN32
# endif
# if defined(FPL__SUPPORT_INPUT_X11)
# define FPL__ENABLE_INPUT_X11
# endif
# if defined(FPL__SUPPORT_INPUT_LINUX_JOYSTICK)
# define FPL__ENABLE_INPUT_LINUX_JOYSTICK
# endif
# if defined(FPL__SUPPORT_INPUT_UNIX_GAMEPAD)
# define FPL__ENABLE_INPUT_UNIX_GAMEPAD
# endif
#endif // FPL__SUPPORT_INPUT
#if defined(FPL_LOGGING)
# define FPL__ENABLE_LOGGING
# if defined(FPL_LOG_MULTIPLE_WRITERS)
# define FPL__ENABLE_LOG_MULTIPLE_WRITERS
# endif
#endif // FPL_LOGGING
//
// Assertions & Debug
//
#if defined(FPL__ENABLE_ASSERTIONS)
# if defined(FPL__ENABLE_C_ASSERT) && !defined(FPL_FORCE_ASSERTIONS)
# define FPL__INCLUDE_ASSERT
# define fpl__m_Assert(exp) assert(exp)
# if defined(__cplusplus)
# define fpl__m_StaticAssert(exp) static_assert(exp, "fpl_static_assert")
# endif
# else
# define fpl__m_Assert(exp) if(!(exp)) {*(int *)0 = 0;}
# endif // FPL__ENABLE_C_ASSERT
# if !defined(fpl__m_StaticAssert)
# define FPL__M_STATICASSERT_0(exp, line, counter) \
int fpl__ct_assert_##line##_##counter(int ct_assert_failed[(exp)?1:-1])
# define fpl__m_StaticAssert(exp) \
FPL__M_STATICASSERT_0(exp, __LINE__, __COUNTER__)
# endif
#else
# define fpl__m_Assert(exp)
# define fpl__m_StaticAssert(exp)
#endif // FPL__ENABLE_ASSERTIONS
#define fplAssert(exp) fpl__m_Assert(exp)
#define fplStaticAssert(exp) fpl__m_StaticAssert(exp)
#define fplAlwaysAssert(exp) if(!(exp)) {*(int *)0 = 0;}
#define fplAssertPtr(ptr) fpl__m_Assert((ptr) != fpl_null)
//
// Debug-Break
// Based on: https://stackoverflow.com/questions/173618/is-there-a-portable-equivalent-to-debugbreak-debugbreak
//
#if defined(__has_builtin)
# if __has_builtin(__builtin_debugtrap)
# define fpl__m_DebugBreak() __builtin_debugtrap()
# elif __has_builtin(__debugbreak)
# define fpl__m_DebugBreak() __debugbreak()
# endif
#endif
#if !defined(fpl__m_DebugBreak)
# if defined(FPL_COMPILER_MSVC) || defined(FPL_COMPILER_INTEL)
# define fpl__m_DebugBreak() __debugbreak()
# elif defined(FPL_COMPILER_ARM)
# define fpl__m_DebugBreak() __breakpoint(42)
# elif defined(FPL_ARCH_X86) || defined(FPL_ARCH_X64)
void fpl__m_DebugBreak(void) { __asm__ __volatile__("int $03"); }
# elif defined(__thumb__)
void fpl__m_DebugBreak(void) { __asm__ __volatile__(".inst 0xde01"); }
# elif defined(FPL_ARCH_ARM64)
void fpl__m_DebugBreak(void) { __asm__ __volatile__(".inst 0xd4200000"); }
# elif defined(FPL_ARCH_ARM32)
void fpl__m_DebugBreak(void) { __asm__ __volatile__(".inst 0xe7f001f0"); }
# elif defined(FPL_COMPILER_GCC)
# define fpl__m_DebugBreak() __builtin_trap()
# else
# define FPL__INCLUDE_SIGNAL
# if defined(SIGTRAP)
# define fpl__m_DebugBreak() raise(SIGTRAP)
# else
# define fpl__m_DebugBreak() raise(SIGABRT)
# endif
# endif
#endif
#define fplDebugBreak() fpl__m_DebugBreak()
//
// Memory macros
//
#if !defined(FPL_NO_MEMORY_MACROS) || defined(FPL_FORCE_MEMORY_MACROS)
# define FPL__ENABLE_MEMORY_MACROS
#endif
//
// Types & Limits
//
#include <stdint.h> // uint32_t, ...
#include <stddef.h> // size_t
#include <stdbool.h> // bool
#include <stdarg.h> // va_start, va_end, va_list, va_arg
#include <limits.h> // UINT32_MAX, ...
#if defined(FPL__INCLUDE_ASSERT)
# include <assert.h> // assert
#endif
#if defined(FPL__INCLUDE_SIGNAL)
# include <signal.h>
#endif
#if defined(FPL__INCLUDE_MALLOC)
# include <malloc.h> // malloc/free/realloc/_alloca
#endif
#if defined(FPL__INCLUDE_ALLOCA)
# include <alloca.h> // alloca
#endif
#if !defined(FPL_NO_CRT)
# include <stdlib.h> // _countof
#endif
#if !defined(UINT32_MAX)
// On android or older posix versions there is no UINT32_MAX
# define UINT32_MAX (0xFFFFFFFFU)
#endif
#if defined(FPL_IS_CPP11)
# define fpl__m_null nullptr
#elif defined(NULL)
# define fpl__m_null NULL
#else
# define fpl__m_null 0
#endif
#define fpl_null fpl__m_null
typedef int32_t ;
//
// Test sizes
//
#if defined(FPL_CPU_64BIT)
(sizeof(uint64_t) == 8);
(sizeof(uint32_t) == 4);
(sizeof(uintptr_t) == sizeof(uint64_t));
(sizeof(size_t) == sizeof(uint64_t));
#elif defined(FPL_CPU_32BIT)
(sizeof(uint64_t) == 8);
(sizeof(uint32_t) == 4);
(sizeof(uintptr_t) == sizeof(uint32_t));
(sizeof(size_t) == sizeof(uint32_t));
#endif
#if CHAR_BIT != 8
#error "Unsupported Char Size, expect 8 bits in CHAR_BIT"
#endif
//
// Macro functions
//
#define FPL_NOT_IMPLEMENTED {*(int *)0 = 0xBAD;}
#if defined(FPL_IS_C99)
# define fpl__m_ZeroInit {0}
# define fpl__m_StructSet(ptr, type, value) *(ptr) = (type)value
# define fpl__m_StructInit(type, ...) (type){__VA_ARGS__}
# define fpl__m_StructField(type, name, ...) .name = __VA_ARGS__
#else
# define fpl__m_ZeroInit {}
# define fpl__m_StructSet(ptr, type, value) *(ptr) = value
# define fpl__m_StructInit(type, ...) {__VA_ARGS__}
# define fpl__m_StructField(type, name, ...) __VA_ARGS__
#endif
#define fplZeroInit fpl__m_ZeroInit
#define fplStructSet fpl__m_StructSet
#define fplStructInit fpl__m_StructInit
#define fplStructField fpl__m_StructField
#define fplGetAlignmentOffset(value, alignment) ( (((alignment) > 1) && (((value) & ((alignment) - 1)) != 0)) ? ((alignment) - ((value) & ((alignment) - 1))) : 0)
#define fplGetAlignedSize(size, alignment) (((size) > 0 && (alignment) > 0) ? ((size) + fplGetAlignmentOffset(size, alignment)) : (size))
#define fplIsAligned(ptr, alignment) (((uintptr_t)(const void *)(ptr)) % (alignment) == 0)
#define fplIsPowerOfTwo(value) (((value) != 0) && (((value) & (~(value) + 1)) == (value)))
#define fplIsBitSet(value, bit) (((value) >> (bit)) & 0x1)
#define fplKiloBytes(value) (((value) * 1024ull))
#define fplMegaBytes(value) ((fplKiloBytes(value) * 1024ull))
#define fplGigaBytes(value) ((fplMegaBytes(value) * 1024ull))
#define fplTeraBytes(value) ((fplGigaBytes(value) * 1024ull))
#define fplIsMaskSet(value, mask) (((value) & (mask)) == (mask))
//
// Endianess
//
typedef enum {
= 0x04030201,
= 0x01020304,
} ;
typedef union {
unsigned char [4];
uint32_t ;
} ;
// The current endianess value
const fpl__global_endianessOrder = { 1, 2, 3, 4 };
#define fplIsBigEndian() (fpl__global_endianessOrder.value == fplEndianessType_Big)
#define fplIsLittleEndian() (fpl__global_endianessOrder.value == fplEndianessType_Little)
#define fplGetEndianess32() (fpl__global_endianessOrder.value)
#define fplClearStruct(ptr) fplMemoryClear((void *)(ptr), sizeof(*(ptr)))
#define fplCopyStruct(src, dst) fplMemoryCopy(src, sizeof(*(src)), dst)
//
// Array count
//
#if defined(_countof)
# define fpl__m_ArrayCount(arr) _countof(arr)
#elif defined(ARRAY_SIZE)
# define fpl__m_ArrayCount(arr) ARRAY_SIZE(arr)
#else
# define fpl__m_ArrayCount(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
#define fplArrayCount(arr) fpl__m_ArrayCount(arr)
#define fplOffsetOf(type, field) ((size_t)(&(((type*)(0))->field)))
#define fplMin(a, b) ((a) < (b) ? (a) : (b))
#define fplMax(a, b) ((a) > (b) ? (a) : (b))
#if defined(FPL_PLATFORM_WINDOWS)
# define fpl__m_StackAllocate(size) _alloca(size)
#else
# define fpl__m_StackAllocate(size) alloca(size)
#endif
#define fplStackAllocate(size) fpl__m_StackAllocate(size)
#if defined(FPL_IS_CPP)
# define FPL__M_ENUM_AS_FLAGS_OPERATORS(etype) \
inline etype operator | (etype a, etype b) { \
return static_cast<etype>(static_cast<int>(a) | static_cast<int>(b)); \
} \
inline etype& operator |= (etype &a, etype b) { \
return a = a | b; \
} \
inline etype operator & (etype a, etype b) { \
return static_cast<etype>(static_cast<int>(a) & static_cast<int>(b)); \
} \
inline etype& operator &= (etype &a, etype b) { \
return a = a & b; \
} \
inline etype operator ~ (etype a) { \
return static_cast<etype>(~static_cast<int>(a)); \
} \
inline etype operator ^ (etype a, etype b) { \
return static_cast<etype>(static_cast<int>(a) ^ static_cast<int>(b)); \
} \
inline etype& operator ^= (etype &a, etype b) { \
return a = a ^ b; \
}
#else
# define FPL__M_ENUM_AS_FLAGS_OPERATORS(etype)
#endif
#define FPL_ENUM_AS_FLAGS_OPERATORS(type) FPL__M_ENUM_AS_FLAGS_OPERATORS(type)
//
// Platform Includes
//
#if !defined(FPL_NO_PLATFORM_INCLUDES) && !defined(FPL__HAS_PLATFORM_INCLUDES)
# define FPL__HAS_PLATFORM_INCLUDES
# if defined(FPL_PLATFORM_WINDOWS)
// @NOTE(final): windef.h defines min/max macros in lowercase, this will break for example std::min/max, so we have to tell the header we dont want this!
# if !defined(NOMINMAX)
# define NOMINMAX
# endif
// @NOTE(final): For now we dont want any network, com or gdi stuff at all, maybe later who knows.
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN 1
# endif
// @HACK(final/Win32): Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here"
struct IUnknown;
# include <windows.h> // Win32 api
# if _WIN32_WINNT < 0x0600
# error "Windows Vista or higher required!"
# endif
# endif // FPL_PLATFORM_WINDOWS
# if defined(FPL_SUBPLATFORM_X11)
# include <X11/X.h> // Window
# include <X11/Xlib.h> // Display
# include <X11/Xutil.h> // XVisualInfo
# include <X11/Xatom.h> // XA_CARDINAL
# include <X11/keysym.h> // Keyboard symbols (XK_Escape, etc.)
# endif // FPL_SUBPLATFORM_X11
#endif // !FPL_NO_PLATFORM_INCLUDES
// NOTE(final): pthread.h/semaphore.h is always present in POSIX
#if defined(FPL_SUBPLATFORM_POSIX)
# include <pthread.h> // pthread_t, pthread_mutex_, pthread_cond_, pthread_barrier_
# include <semaphore.h> // sem_t
#endif // FPL_SUBPLATFORM_POSIX
//
// Special Includes, such as intrin.h or cpuid.h
// CRT Includes, such as stdio.h, stdlib.h, when enabled
//
#if defined(FPL_COMPILER_MSVC)
# include <intrin.h> // __cpuid, _Interlocked*
#elif defined(FPL_COMPILER_GCC) || defined(FPL_COMPILER_CLANG)
# if defined(FPL_ARCH_X86) || defined(FPL_ARCH_X64)
# include <cpuid.h> // __cpuid_count
# endif // X86 or X64
#endif
// Only include CRT, when needed
#if !defined(FPL_NO_CRT)
# include <stdio.h> // stdin, stdout, stderr, fprintf, vfprintf, vsnprintf, getchar
# include <stdlib.h> // wcstombs, mbstowcs, getenv
# include <wchar.h> // mbrtowc, wcsrtombs, mbsrtowcs
# include <locale.h> // setlocale, struct lconv, localeconv
#endif
// Always include sched.h and dirint.h
#if defined(FPL_SUBPLATFORM_POSIX)
# include <sched.h> // sched_param, sched_get_priority_max, SCHED_FIFO
# include <dirent.h> // DIR, dirent
#endif
// ****************************************************************************
//
// > X11_ABI
//
// Self-contained X11 type/constant definitions, prefixed with fpl__X11_ / FPL__X11_.
// The whole X11 subplatform uses only these names, never the raw X11 names.
// With platform includes the names map onto the real X11 types; otherwise the
// complete X11 ABI is self-defined, so no X11 headers are required.
//
// ****************************************************************************
#if defined(FPL_SUBPLATFORM_X11)
#if defined(FPL__HAS_PLATFORM_INCLUDES)
// Pass-through: real X11 headers are included; map the fpl__X11_* names onto the real X11 types.
typedef Display fpl__X11_Display;
typedef Screen fpl__X11_Screen;
typedef Visual fpl__X11_Visual;
typedef XImage fpl__X11_XImage;
typedef GC fpl__X11_GC;
typedef XID fpl__X11_XID;
typedef Window fpl__X11_Window;
typedef Drawable fpl__X11_Drawable;
typedef Colormap fpl__X11_Colormap;
typedef Pixmap fpl__X11_Pixmap;
typedef Cursor fpl__X11_Cursor;
typedef Font fpl__X11_Font;
typedef Atom fpl__X11_Atom;
typedef VisualID fpl__X11_VisualID;
typedef Time fpl__X11_Time;
typedef KeySym fpl__X11_KeySym;
typedef KeyCode fpl__X11_KeyCode;
typedef Bool fpl__X11_Bool;
typedef Status fpl__X11_Status;
typedef XPointer fpl__X11_XPointer;
typedef XEvent fpl__X11_XEvent;
typedef XAnyEvent fpl__X11_XAnyEvent;
typedef XKeyEvent fpl__X11_XKeyEvent;
typedef XButtonEvent fpl__X11_XButtonEvent;
typedef XMotionEvent fpl__X11_XMotionEvent;
typedef XFocusChangeEvent fpl__X11_XFocusChangeEvent;
typedef XExposeEvent fpl__X11_XExposeEvent;
typedef XConfigureEvent fpl__X11_XConfigureEvent;
typedef XPropertyEvent fpl__X11_XPropertyEvent;
typedef XSelectionEvent fpl__X11_XSelectionEvent;
typedef XSelectionRequestEvent fpl__X11_XSelectionRequestEvent;
typedef XClientMessageEvent fpl__X11_XClientMessageEvent;
typedef XErrorEvent fpl__X11_XErrorEvent;
typedef XErrorHandler fpl__X11_XErrorHandler;
typedef XComposeStatus fpl__X11_XComposeStatus;
typedef XSetWindowAttributes fpl__X11_XSetWindowAttributes;
typedef XWindowAttributes fpl__X11_XWindowAttributes;
typedef XVisualInfo fpl__X11_XVisualInfo;
typedef XSizeHints fpl__X11_XSizeHints;
typedef XTextProperty fpl__X11_XTextProperty;
typedef XClassHint fpl__X11_XClassHint;
typedef XGCValues fpl__X11_XGCValues;
typedef XColor fpl__X11_XColor;
#define FPL__X11_None None
#define FPL__X11_True True
#define FPL__X11_False False
#define FPL__X11_Success Success
#define FPL__X11_AllocNone AllocNone
#define FPL__X11_AnyPropertyType AnyPropertyType
#define FPL__X11_CurrentTime CurrentTime
#define FPL__X11_NoSymbol NoSymbol
#define FPL__X11_InputOutput InputOutput
#define FPL__X11_ZPixmap ZPixmap
#define FPL__X11_XYBitmap XYBitmap
#define FPL__X11_XYPixmap XYPixmap
#define FPL__X11_IsUnmapped IsUnmapped
#define FPL__X11_IsUnviewable IsUnviewable
#define FPL__X11_IsViewable IsViewable
#define FPL__X11_WithdrawnState WithdrawnState
#define FPL__X11_NormalState NormalState
#define FPL__X11_IconicState IconicState
#define FPL__X11_NorthWestGravity NorthWestGravity
#define FPL__X11_PropModeReplace PropModeReplace
#define FPL__X11_PropModePrepend PropModePrepend
#define FPL__X11_PropModeAppend PropModeAppend
#define FPL__X11_QueuedAlready QueuedAlready
#define FPL__X11_QueuedAfterReading QueuedAfterReading
#define FPL__X11_QueuedAfterFlush QueuedAfterFlush
#define FPL__X11_NotifyNormal NotifyNormal
#define FPL__X11_NotifyGrab NotifyGrab
#define FPL__X11_NotifyUngrab NotifyUngrab
#define FPL__X11_KeyPress KeyPress
#define FPL__X11_KeyRelease KeyRelease
#define FPL__X11_ButtonPress ButtonPress
#define FPL__X11_ButtonRelease ButtonRelease
#define FPL__X11_MotionNotify MotionNotify
#define FPL__X11_FocusIn FocusIn
#define FPL__X11_FocusOut FocusOut
#define FPL__X11_Expose Expose
#define FPL__X11_ConfigureNotify ConfigureNotify
#define FPL__X11_PropertyNotify PropertyNotify
#define FPL__X11_SelectionClear SelectionClear
#define FPL__X11_SelectionRequest SelectionRequest
#define FPL__X11_SelectionNotify SelectionNotify
#define FPL__X11_ClientMessage ClientMessage
#define FPL__X11_MappingNotify MappingNotify
#define FPL__X11_GenericEvent GenericEvent
#define FPL__X11_Button1 Button1
#define FPL__X11_Button2 Button2
#define FPL__X11_Button3 Button3
#define FPL__X11_Button4 Button4
#define FPL__X11_Button5 Button5
#define FPL__X11_PMinSize PMinSize
#define FPL__X11_PMaxSize PMaxSize
#define FPL__X11_NoEventMask NoEventMask
#define FPL__X11_KeyPressMask KeyPressMask
#define FPL__X11_KeyReleaseMask KeyReleaseMask
#define FPL__X11_ButtonPressMask ButtonPressMask
#define FPL__X11_ButtonReleaseMask ButtonReleaseMask
#define FPL__X11_EnterWindowMask EnterWindowMask
#define FPL__X11_LeaveWindowMask LeaveWindowMask
#define FPL__X11_PointerMotionMask PointerMotionMask
#define FPL__X11_ButtonMotionMask ButtonMotionMask
#define FPL__X11_ExposureMask ExposureMask
#define FPL__X11_VisibilityChangeMask VisibilityChangeMask
#define FPL__X11_StructureNotifyMask StructureNotifyMask
#define FPL__X11_SubstructureNotifyMask SubstructureNotifyMask
#define FPL__X11_SubstructureRedirectMask SubstructureRedirectMask
#define FPL__X11_FocusChangeMask FocusChangeMask
#define FPL__X11_PropertyChangeMask PropertyChangeMask
#define FPL__X11_ShiftMask ShiftMask
#define FPL__X11_ControlMask ControlMask
#define FPL__X11_Mod1Mask Mod1Mask
#define FPL__X11_Mod4Mask Mod4Mask
#define FPL__X11_Button1Mask Button1Mask
#define FPL__X11_Button2Mask Button2Mask
#define FPL__X11_Button3Mask Button3Mask
#define FPL__X11_CWBackPixel CWBackPixel
#define FPL__X11_CWBorderPixel CWBorderPixel
#define FPL__X11_CWBitGravity CWBitGravity
#define FPL__X11_CWWinGravity CWWinGravity
#define FPL__X11_CWEventMask CWEventMask
#define FPL__X11_CWColormap CWColormap
#define FPL__X11_XA_ATOM XA_ATOM
#define FPL__X11_XA_CARDINAL XA_CARDINAL
#define FPL__X11_XA_STRING XA_STRING
#define FPL__X11_XK_0 XK_0
#define FPL__X11_XK_1 XK_1
#define FPL__X11_XK_2 XK_2
#define FPL__X11_XK_3 XK_3
#define FPL__X11_XK_4 XK_4
#define FPL__X11_XK_5 XK_5
#define FPL__X11_XK_6 XK_6
#define FPL__X11_XK_7 XK_7
#define FPL__X11_XK_8 XK_8
#define FPL__X11_XK_9 XK_9
#define FPL__X11_XK_a XK_a
#define FPL__X11_XK_Alt_L XK_Alt_L
#define FPL__X11_XK_Alt_R XK_Alt_R
#define FPL__X11_XK_b XK_b
#define FPL__X11_XK_BackSpace XK_BackSpace
#define FPL__X11_XK_c XK_c
#define FPL__X11_XK_Caps_Lock XK_Caps_Lock
#define FPL__X11_XK_comma XK_comma
#define FPL__X11_XK_Control_L XK_Control_L
#define FPL__X11_XK_Control_R XK_Control_R
#define FPL__X11_XK_d XK_d
#define FPL__X11_XK_Delete XK_Delete
#define FPL__X11_XK_Down XK_Down
#define FPL__X11_XK_e XK_e
#define FPL__X11_XK_End XK_End
#define FPL__X11_XK_Escape XK_Escape
#define FPL__X11_XK_f XK_f
#define FPL__X11_XK_F1 XK_F1
#define FPL__X11_XK_F10 XK_F10
#define FPL__X11_XK_F11 XK_F11
#define FPL__X11_XK_F12 XK_F12
#define FPL__X11_XK_F13 XK_F13
#define FPL__X11_XK_F14 XK_F14
#define FPL__X11_XK_F15 XK_F15
#define FPL__X11_XK_F16 XK_F16
#define FPL__X11_XK_F17 XK_F17
#define FPL__X11_XK_F18 XK_F18
#define FPL__X11_XK_F19 XK_F19
#define FPL__X11_XK_F2 XK_F2
#define FPL__X11_XK_F20 XK_F20
#define FPL__X11_XK_F21 XK_F21
#define FPL__X11_XK_F22 XK_F22
#define FPL__X11_XK_F23 XK_F23
#define FPL__X11_XK_F24 XK_F24
#define FPL__X11_XK_F3 XK_F3
#define FPL__X11_XK_F4 XK_F4
#define FPL__X11_XK_F5 XK_F5
#define FPL__X11_XK_F6 XK_F6
#define FPL__X11_XK_F7 XK_F7
#define FPL__X11_XK_F8 XK_F8
#define FPL__X11_XK_F9 XK_F9
#define FPL__X11_XK_g XK_g
#define FPL__X11_XK_h XK_h
#define FPL__X11_XK_Home XK_Home
#define FPL__X11_XK_i XK_i
#define FPL__X11_XK_Insert XK_Insert
#define FPL__X11_XK_ISO_Level3_Shift XK_ISO_Level3_Shift
#define FPL__X11_XK_j XK_j
#define FPL__X11_XK_k XK_k
#define FPL__X11_XK_KP_0 XK_KP_0
#define FPL__X11_XK_KP_1 XK_KP_1
#define FPL__X11_XK_KP_2 XK_KP_2
#define FPL__X11_XK_KP_3 XK_KP_3
#define FPL__X11_XK_KP_4 XK_KP_4
#define FPL__X11_XK_KP_5 XK_KP_5
#define FPL__X11_XK_KP_6 XK_KP_6
#define FPL__X11_XK_KP_7 XK_KP_7
#define FPL__X11_XK_KP_8 XK_KP_8
#define FPL__X11_XK_KP_9 XK_KP_9
#define FPL__X11_XK_KP_Add XK_KP_Add
#define FPL__X11_XK_KP_Delete XK_KP_Delete
#define FPL__X11_XK_KP_Divide XK_KP_Divide
#define FPL__X11_XK_KP_Multiply XK_KP_Multiply
#define FPL__X11_XK_KP_Subtract XK_KP_Subtract
#define FPL__X11_XK_l XK_l
#define FPL__X11_XK_Left XK_Left
#define FPL__X11_XK_m XK_m
#define FPL__X11_XK_Meta_L XK_Meta_L
#define FPL__X11_XK_Meta_R XK_Meta_R
#define FPL__X11_XK_minus XK_minus
#define FPL__X11_XK_Mode_switch XK_Mode_switch
#define FPL__X11_XK_n XK_n
#define FPL__X11_XK_o XK_o
#define FPL__X11_XK_p XK_p
#define FPL__X11_XK_Page_Down XK_Page_Down
#define FPL__X11_XK_Page_Up XK_Page_Up
#define FPL__X11_XK_Pause XK_Pause
#define FPL__X11_XK_period XK_period
#define FPL__X11_XK_plus XK_plus
#define FPL__X11_XK_Print XK_Print
#define FPL__X11_XK_q XK_q
#define FPL__X11_XK_r XK_r
#define FPL__X11_XK_Return XK_Return
#define FPL__X11_XK_Right XK_Right
#define FPL__X11_XK_s XK_s
#define FPL__X11_XK_Shift_L XK_Shift_L
#define FPL__X11_XK_Shift_R XK_Shift_R
#define FPL__X11_XK_space XK_space
#define FPL__X11_XK_Super_L XK_Super_L
#define FPL__X11_XK_Super_R XK_Super_R
#define FPL__X11_XK_t XK_t
#define FPL__X11_XK_Tab XK_Tab
#define FPL__X11_XK_u XK_u
#define FPL__X11_XK_Up XK_Up
#define FPL__X11_XK_v XK_v
#define FPL__X11_XK_w XK_w
#define FPL__X11_XK_x XK_x
#define FPL__X11_XK_y XK_y
#define FPL__X11_XK_z XK_z
#else // !FPL__HAS_PLATFORM_INCLUDES
// Self-defined: no X11 headers are required; the entire X11 ABI is declared here.
typedef struct fpl__X11_DisplayRec fpl__X11_Display;
typedef struct fpl__X11_ScreenRec fpl__X11_Screen;
typedef struct fpl__X11_VisualRec fpl__X11_Visual;
typedef struct fpl__X11_XImageRec fpl__X11_XImage;
typedef struct fpl__X11_GCRec *fpl__X11_GC;
typedef unsigned long fpl__X11_XID;
typedef unsigned long fpl__X11_Window;
typedef unsigned long fpl__X11_Drawable;
typedef unsigned long fpl__X11_Colormap;
typedef unsigned long fpl__X11_Pixmap;
typedef unsigned long fpl__X11_Cursor;
typedef unsigned long fpl__X11_Font;
typedef unsigned long fpl__X11_Atom;
typedef unsigned long fpl__X11_VisualID;
typedef unsigned long fpl__X11_Time;
typedef unsigned long fpl__X11_KeySym;
typedef unsigned char fpl__X11_KeyCode;
typedef int fpl__X11_Bool;
typedef int fpl__X11_Status;
typedef char *fpl__X11_XPointer;
typedef struct fpl__X11_XAnyEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
} fpl__X11_XAnyEvent;
typedef struct fpl__X11_XKeyEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
fpl__X11_Window root;
fpl__X11_Window subwindow;
fpl__X11_Time time;
int x, y;
int x_root, y_root;
unsigned int state;
unsigned int keycode;
fpl__X11_Bool same_screen;
} fpl__X11_XKeyEvent;
typedef struct fpl__X11_XButtonEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
fpl__X11_Window root;
fpl__X11_Window subwindow;
fpl__X11_Time time;
int x, y;
int x_root, y_root;
unsigned int state;
unsigned int button;
fpl__X11_Bool same_screen;
} fpl__X11_XButtonEvent;
typedef struct fpl__X11_XMotionEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
fpl__X11_Window root;
fpl__X11_Window subwindow;
fpl__X11_Time time;
int x, y;
int x_root, y_root;
unsigned int state;
char is_hint;
fpl__X11_Bool same_screen;
} fpl__X11_XMotionEvent;
typedef struct fpl__X11_XFocusChangeEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
int mode;
int detail;
} fpl__X11_XFocusChangeEvent;
typedef struct fpl__X11_XExposeEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
int x, y;
int width, height;
int count;
} fpl__X11_XExposeEvent;
typedef struct fpl__X11_XConfigureEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window event;
fpl__X11_Window window;
int x, y;
int width, height;
int border_width;
fpl__X11_Window above;
fpl__X11_Bool override_redirect;
} fpl__X11_XConfigureEvent;
typedef struct fpl__X11_XPropertyEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
fpl__X11_Atom atom;
fpl__X11_Time time;
int state;
} fpl__X11_XPropertyEvent;
typedef struct fpl__X11_XSelectionEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window requestor;
fpl__X11_Atom selection;
fpl__X11_Atom target;
fpl__X11_Atom property;
fpl__X11_Time time;
} fpl__X11_XSelectionEvent;
typedef struct fpl__X11_XSelectionRequestEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window owner;
fpl__X11_Window requestor;
fpl__X11_Atom selection;
fpl__X11_Atom target;
fpl__X11_Atom property;
fpl__X11_Time time;
} fpl__X11_XSelectionRequestEvent;
typedef struct fpl__X11_XClientMessageEvent {
int type;
unsigned long serial;
fpl__X11_Bool send_event;
fpl__X11_Display *display;
fpl__X11_Window window;
fpl__X11_Atom message_type;
int format;
union {
char b[20];
short s[10];
long l[5];
} data;
} fpl__X11_XClientMessageEvent;
typedef union fpl__X11_XEvent {
int type;
fpl__X11_XAnyEvent xany;
fpl__X11_XKeyEvent xkey;
fpl__X11_XButtonEvent xbutton;
fpl__X11_XMotionEvent xmotion;
fpl__X11_XFocusChangeEvent xfocus;
fpl__X11_XExposeEvent xexpose;
fpl__X11_XConfigureEvent xconfigure;
fpl__X11_XPropertyEvent xproperty;
fpl__X11_XSelectionEvent xselection;
fpl__X11_XSelectionRequestEvent xselectionrequest;
fpl__X11_XClientMessageEvent xclient;
long pad[24];
} fpl__X11_XEvent;
// Opaque incomplete type, only ever used through a pointer
typedef struct fpl__X11_XErrorEventRec fpl__X11_XErrorEvent;
typedef int (*fpl__X11_XErrorHandler)(fpl__X11_Display *, fpl__X11_XErrorEvent *);
// Opaque incomplete type, only ever used through a pointer
typedef struct fpl__X11_XComposeStatusRec fpl__X11_XComposeStatus;
typedef struct fpl__X11_XSetWindowAttributes {
fpl__X11_Pixmap background_pixmap;
unsigned long background_pixel;
fpl__X11_Pixmap border_pixmap;
unsigned long border_pixel;
int bit_gravity;
int win_gravity;
int backing_store;
unsigned long backing_planes;
unsigned long backing_pixel;
fpl__X11_Bool save_under;
long event_mask;
long do_not_propagate_mask;
fpl__X11_Bool override_redirect;
fpl__X11_Colormap colormap;
fpl__X11_Cursor cursor;
} fpl__X11_XSetWindowAttributes;
typedef struct fpl__X11_XWindowAttributes {
int x, y;
int width, height;
int border_width;
int depth;
fpl__X11_Visual *visual;
fpl__X11_Window root;
#if defined(__cplusplus)
int c_class;
#else
int class;
#endif
int bit_gravity;
int win_gravity;
int backing_store;
unsigned long backing_planes;
unsigned long backing_pixel;
fpl__X11_Bool save_under;
fpl__X11_Colormap colormap;
fpl__X11_Bool map_installed;
int map_state;
long all_event_masks;
long your_event_mask;
long do_not_propagate_mask;
fpl__X11_Bool override_redirect;
fpl__X11_Screen *screen;
} fpl__X11_XWindowAttributes;
typedef struct fpl__X11_XVisualInfo {
fpl__X11_Visual *visual;
fpl__X11_VisualID visualid;
int screen;
int depth;
#if defined(__cplusplus)
int c_class;
#else
int class;
#endif
unsigned long red_mask;
unsigned long green_mask;
unsigned long blue_mask;
int colormap_size;
int bits_per_rgb;
} fpl__X11_XVisualInfo;
typedef struct fpl__X11_XSizeHints {
long flags;
int x, y;
int width, height;
int min_width, min_height;
int max_width, max_height;
int width_inc, height_inc;
struct {
int x;
int y;
} min_aspect, max_aspect;
int base_width, base_height;
int win_gravity;
} fpl__X11_XSizeHints;
typedef struct fpl__X11_XClassHint {
char *res_name;
char *res_class;
} fpl__X11_XClassHint;
// Opaque incomplete type, only ever used through a pointer
typedef struct fpl__X11_XTextPropertyRec fpl__X11_XTextProperty;
// Opaque incomplete type, only ever used through a pointer
typedef struct fpl__X11_XGCValuesRec fpl__X11_XGCValues;
typedef struct fpl__X11_XColor {
unsigned long pixel;
unsigned short red, green, blue;
char flags;
char pad;
} fpl__X11_XColor;
#define FPL__X11_None 0L
#define FPL__X11_True 1
#define FPL__X11_False 0
#define FPL__X11_Success 0
#define FPL__X11_AllocNone 0
#define FPL__X11_AnyPropertyType 0L
#define FPL__X11_CurrentTime 0L
#define FPL__X11_NoSymbol 0L
#define FPL__X11_InputOutput 1
#define FPL__X11_ZPixmap 2
#define FPL__X11_XYBitmap 0
#define FPL__X11_XYPixmap 1
#define FPL__X11_IsUnmapped 0
#define FPL__X11_IsUnviewable 1
#define FPL__X11_IsViewable 2
#define FPL__X11_WithdrawnState 0
#define FPL__X11_NormalState 1
#define FPL__X11_IconicState 3
#define FPL__X11_NorthWestGravity 1
#define FPL__X11_PropModeReplace 0
#define FPL__X11_PropModePrepend 1
#define FPL__X11_PropModeAppend 2
#define FPL__X11_QueuedAlready 0
#define FPL__X11_QueuedAfterReading 1
#define FPL__X11_QueuedAfterFlush 2
#define FPL__X11_NotifyNormal 0
#define FPL__X11_NotifyGrab 1
#define FPL__X11_NotifyUngrab 2
#define FPL__X11_KeyPress 2
#define FPL__X11_KeyRelease 3
#define FPL__X11_ButtonPress 4
#define FPL__X11_ButtonRelease 5
#define FPL__X11_MotionNotify 6
#define FPL__X11_FocusIn 9
#define FPL__X11_FocusOut 10
#define FPL__X11_Expose 12
#define FPL__X11_ConfigureNotify 22
#define FPL__X11_PropertyNotify 28
#define FPL__X11_SelectionClear 29
#define FPL__X11_SelectionRequest 30
#define FPL__X11_SelectionNotify 31
#define FPL__X11_ClientMessage 33
#define FPL__X11_MappingNotify 34
#define FPL__X11_GenericEvent 35
#define FPL__X11_Button1 1
#define FPL__X11_Button2 2
#define FPL__X11_Button3 3
#define FPL__X11_Button4 4
#define FPL__X11_Button5 5
#define FPL__X11_PMinSize (1L << 4)
#define FPL__X11_PMaxSize (1L << 5)
#define FPL__X11_NoEventMask 0L
#define FPL__X11_KeyPressMask (1L<<0)
#define FPL__X11_KeyReleaseMask (1L<<1)
#define FPL__X11_ButtonPressMask (1L<<2)
#define FPL__X11_ButtonReleaseMask (1L<<3)
#define FPL__X11_EnterWindowMask (1L<<4)
#define FPL__X11_LeaveWindowMask (1L<<5)
#define FPL__X11_PointerMotionMask (1L<<6)
#define FPL__X11_ButtonMotionMask (1L<<13)
#define FPL__X11_ExposureMask (1L<<15)
#define FPL__X11_VisibilityChangeMask (1L<<16)
#define FPL__X11_StructureNotifyMask (1L<<17)
#define FPL__X11_SubstructureNotifyMask (1L<<19)
#define FPL__X11_SubstructureRedirectMask (1L<<20)
#define FPL__X11_FocusChangeMask (1L<<21)
#define FPL__X11_PropertyChangeMask (1L<<22)
#define FPL__X11_ShiftMask (1<<0)
#define FPL__X11_ControlMask (1<<2)
#define FPL__X11_Mod1Mask (1<<3)
#define FPL__X11_Mod4Mask (1<<6)
#define FPL__X11_Button1Mask (1<<8)
#define FPL__X11_Button2Mask (1<<9)
#define FPL__X11_Button3Mask (1<<10)
#define FPL__X11_CWBackPixel (1L<<1)
#define FPL__X11_CWBorderPixel (1L<<3)
#define FPL__X11_CWBitGravity (1L<<4)
#define FPL__X11_CWWinGravity (1L<<5)
#define FPL__X11_CWEventMask (1L<<11)
#define FPL__X11_CWColormap (1L<<13)
#define FPL__X11_XA_ATOM ((fpl__X11_Atom)4)
#define FPL__X11_XA_CARDINAL ((fpl__X11_Atom)6)
#define FPL__X11_XA_STRING ((fpl__X11_Atom)31)
#define FPL__X11_XK_0 0x0030
#define FPL__X11_XK_1 0x0031
#define FPL__X11_XK_2 0x0032
#define FPL__X11_XK_3 0x0033
#define FPL__X11_XK_4 0x0034
#define FPL__X11_XK_5 0x0035
#define FPL__X11_XK_6 0x0036
#define FPL__X11_XK_7 0x0037
#define FPL__X11_XK_8 0x0038
#define FPL__X11_XK_9 0x0039
#define FPL__X11_XK_a 0x0061
#define FPL__X11_XK_Alt_L 0xffe9
#define FPL__X11_XK_Alt_R 0xffea
#define FPL__X11_XK_b 0x0062
#define FPL__X11_XK_BackSpace 0xff08
#define FPL__X11_XK_c 0x0063
#define FPL__X11_XK_Caps_Lock 0xffe5
#define FPL__X11_XK_comma 0x002c
#define FPL__X11_XK_Control_L 0xffe3
#define FPL__X11_XK_Control_R 0xffe4
#define FPL__X11_XK_d 0x0064
#define FPL__X11_XK_Delete 0xffff
#define FPL__X11_XK_Down 0xff54
#define FPL__X11_XK_e 0x0065
#define FPL__X11_XK_End 0xff57
#define FPL__X11_XK_Escape 0xff1b
#define FPL__X11_XK_f 0x0066
#define FPL__X11_XK_F1 0xffbe
#define FPL__X11_XK_F10 0xffc7
#define FPL__X11_XK_F11 0xffc8
#define FPL__X11_XK_F12 0xffc9
#define FPL__X11_XK_F13 0xffca
#define FPL__X11_XK_F14 0xffcb
#define FPL__X11_XK_F15 0xffcc
#define FPL__X11_XK_F16 0xffcd
#define FPL__X11_XK_F17 0xffce
#define FPL__X11_XK_F18 0xffcf
#define FPL__X11_XK_F19 0xffd0
#define FPL__X11_XK_F2 0xffbf
#define FPL__X11_XK_F20 0xffd1
#define FPL__X11_XK_F21 0xffd2
#define FPL__X11_XK_F22 0xffd3
#define FPL__X11_XK_F23 0xffd4
#define FPL__X11_XK_F24 0xffd5
#define FPL__X11_XK_F3 0xffc0
#define FPL__X11_XK_F4 0xffc1
#define FPL__X11_XK_F5 0xffc2
#define FPL__X11_XK_F6 0xffc3
#define FPL__X11_XK_F7 0xffc4
#define FPL__X11_XK_F8 0xffc5
#define FPL__X11_XK_F9 0xffc6
#define FPL__X11_XK_g 0x0067
#define FPL__X11_XK_h 0x0068
#define FPL__X11_XK_Home 0xff50
#define FPL__X11_XK_i 0x0069
#define FPL__X11_XK_Insert 0xff63
#define FPL__X11_XK_ISO_Level3_Shift 0xfe03
#define FPL__X11_XK_j 0x006a
#define FPL__X11_XK_k 0x006b
#define FPL__X11_XK_KP_0 0xffb0
#define FPL__X11_XK_KP_1 0xffb1
#define FPL__X11_XK_KP_2 0xffb2
#define FPL__X11_XK_KP_3 0xffb3
#define FPL__X11_XK_KP_4 0xffb4
#define FPL__X11_XK_KP_5 0xffb5
#define FPL__X11_XK_KP_6 0xffb6
#define FPL__X11_XK_KP_7 0xffb7
#define FPL__X11_XK_KP_8 0xffb8
#define FPL__X11_XK_KP_9 0xffb9
#define FPL__X11_XK_KP_Add 0xffab
#define FPL__X11_XK_KP_Delete 0xff9f
#define FPL__X11_XK_KP_Divide 0xffaf
#define FPL__X11_XK_KP_Multiply 0xffaa
#define FPL__X11_XK_KP_Subtract 0xffad
#define FPL__X11_XK_l 0x006c
#define FPL__X11_XK_Left 0xff51
#define FPL__X11_XK_m 0x006d
#define FPL__X11_XK_Meta_L 0xffe7
#define FPL__X11_XK_Meta_R 0xffe8
#define FPL__X11_XK_minus 0x002d
#define FPL__X11_XK_Mode_switch 0xff7e
#define FPL__X11_XK_n 0x006e
#define FPL__X11_XK_o 0x006f
#define FPL__X11_XK_p 0x0070
#define FPL__X11_XK_Page_Down 0xff56
#define FPL__X11_XK_Page_Up 0xff55
#define FPL__X11_XK_Pause 0xff13
#define FPL__X11_XK_period 0x002e
#define FPL__X11_XK_plus 0x002b
#define FPL__X11_XK_Print 0xff61
#define FPL__X11_XK_q 0x0071
#define FPL__X11_XK_r 0x0072
#define FPL__X11_XK_Return 0xff0d
#define FPL__X11_XK_Right 0xff53
#define FPL__X11_XK_s 0x0073
#define FPL__X11_XK_Shift_L 0xffe1
#define FPL__X11_XK_Shift_R 0xffe2
#define FPL__X11_XK_space 0x0020
#define FPL__X11_XK_Super_L 0xffeb
#define FPL__X11_XK_Super_R 0xffec
#define FPL__X11_XK_t 0x0074
#define FPL__X11_XK_Tab 0xff09
#define FPL__X11_XK_u 0x0075
#define FPL__X11_XK_Up 0xff52
#define FPL__X11_XK_v 0x0076
#define FPL__X11_XK_w 0x0077
#define FPL__X11_XK_x 0x0078
#define FPL__X11_XK_y 0x0079
#define FPL__X11_XK_z 0x007a
#endif // FPL__HAS_PLATFORM_INCLUDES
#endif // FPL_SUBPLATFORM_X11
//
// Platform handles
//
#if !defined(FPL__HAS_PLATFORM_INCLUDES) || defined(FPL_OPAQUE_HANDLES)
# if defined(FPL_PLATFORM_WINDOWS)
typedef struct fpl__Win32Guid {
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
} fpl__Win32Guid;
typedef void *fpl__Win32Handle;
typedef fpl__Win32Handle fpl__Win32InstanceHandle;
typedef fpl__Win32Handle fpl__Win32LibraryHandle;
typedef fpl__Win32Handle fpl__Win32FileHandle;
typedef fpl__Win32Handle fpl__Win32ThreadHandle;
typedef uint64_t fpl__Win32MutexHandle[16];
typedef fpl__Win32Handle fpl__Win32SignalHandle;
typedef void *fpl__Win32ConditionVariable;
typedef fpl__Win32Handle fpl__Win32SemaphoreHandle;
typedef fpl__Win32Handle fpl__Win32WindowHandle;
typedef fpl__Win32Handle fpl__Win32DeviceContext;
typedef fpl__Win32Handle fpl__Win32RenderingContext;
typedef union fpl__Win32LargeInteger {
int64_t QuadPart;
struct {
int32_t LowPart;
int32_t HighPart;
};
} fpl__Win32LargeInteger;
# endif // FPL_PLATFORM_WINDOWS
# if defined(FPL_SUBPLATFORM_POSIX)
typedef void *fpl__POSIXLibraryHandle;
typedef int fpl__POSIXFileHandle;
typedef void *fpl__POSIXDirHandle;
typedef uint64_t fpl__POSIXThreadHandle;
typedef uint64_t fpl__POSIXMutexHandle[16];
typedef uint64_t fpl__POSIXSemaphoreHandle[8];
typedef uint64_t fpl__POSIXConditionVariable[16];
# endif // FPL_SUBPLATFORM_POSIX
# if defined(FPL_PLATFORM_LINUX)
typedef int fpl__LinuxSignalHandle;
# endif // FPL_PLATFORM_LINUX
#else
# if defined(FPL_PLATFORM_WINDOWS)
typedef GUID fpl__Win32Guid;
typedef HANDLE fpl__Win32Handle;
typedef HINSTANCE fpl__Win32InstanceHandle;
typedef HMODULE fpl__Win32LibraryHandle;
typedef HANDLE fpl__Win32ThreadHandle;
typedef HANDLE fpl__Win32FileHandle;
typedef CRITICAL_SECTION fpl__Win32MutexHandle;
typedef HANDLE fpl__Win32SignalHandle;
typedef CONDITION_VARIABLE fpl__Win32ConditionVariable;
typedef HANDLE fpl__Win32SemaphoreHandle;
typedef HWND fpl__Win32WindowHandle;
typedef HDC fpl__Win32DeviceContext;
typedef HGLRC fpl__Win32RenderingContext;
typedef LARGE_INTEGER fpl__Win32LargeInteger;
// Sanity checks that the real Win32 types fit into the opaque-branch buffers (keep these in sync with the opaque typedefs above).
(sizeof(GUID) == sizeof(fpl__Win32Guid));
(sizeof(CRITICAL_SECTION) <= sizeof(uint64_t[16]));
# endif // FPL_PLATFORM_WINDOWS
# if defined(FPL_SUBPLATFORM_POSIX)
typedef void *fpl__POSIXLibraryHandle;
typedef int fpl__POSIXFileHandle;
typedef DIR *fpl__POSIXDirHandle;
typedef pthread_t fpl__POSIXThreadHandle;
typedef pthread_mutex_t fpl__POSIXMutexHandle;
typedef sem_t fpl__POSIXSemaphoreHandle;
typedef pthread_cond_t fpl__POSIXConditionVariable;
// Sanity checks that the real POSIX types fit into the opaque-branch buffers (keep these in sync with the opaque typedefs above).
(sizeof(pthread_t) <= sizeof(uint64_t));
(sizeof(pthread_mutex_t) <= sizeof(uint64_t[16]));
(sizeof(sem_t) <= sizeof(uint64_t[8]));
(sizeof(pthread_cond_t) <= sizeof(uint64_t[16]));
# endif // FPL_SUBPLATFORM_POSIX
# if defined(FPL_PLATFORM_LINUX)
typedef int fpl__LinuxSignalHandle;
# endif // FPL_PLATFORM_LINUX
#endif
//
// Constants
//
#if defined(FPL_PLATFORM_WINDOWS)
# if defined(MAX_PATH)
# define FPL__M_MAX_FILENAME_LENGTH (MAX_PATH)
# define FPL__M_MAX_PATH_LENGTH (MAX_PATH * 2)
# else
# define FPL__M_MAX_FILENAME_LENGTH (260)
# define FPL__M_MAX_PATH_LENGTH (260 * 2)
# endif
# define FPL__M_PATH_SEPARATOR '\\'
# define FPL__M_FILE_EXT_SEPARATOR '.'
#else
# define FPL__M_MAX_FILENAME_LENGTH (512)
# define FPL__M_MAX_PATH_LENGTH (2048)
# define FPL__M_PATH_SEPARATOR '/'
# define FPL__M_FILE_EXT_SEPARATOR '.'
#endif
#define FPL_MAX_FILENAME_LENGTH FPL__M_MAX_FILENAME_LENGTH
#define FPL_MAX_PATH_LENGTH FPL__M_MAX_PATH_LENGTH
#define FPL_PATH_SEPARATOR FPL__M_PATH_SEPARATOR
#define FPL_FILE_EXT_SEPARATOR FPL__M_FILE_EXT_SEPARATOR
#define FPL_MAX_NAME_LENGTH (256)
#define FPL_MAX_BUFFER_LENGTH (2048)
// ****************************************************************************
//
// > API
//
// ****************************************************************************
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
struct {
fpl__Win32LargeInteger qpc;
uint64_t ticks;
} win32;
#elif defined(FPL_SUBPLATFORM_POSIX)
struct {
uint64_t seconds;
int64_t nanoSeconds;
} posix;
#endif
uint64_t ;
} ;
typedef uint32_t ;
#define FPL_TIMEOUT_INFINITE UINT32_MAX
typedef double ;
typedef uint64_t ;
(void);
(void);
(const start, const finish);
typedef enum {
= 0,
= 1,
} ;
typedef struct {
uint64_t ;
uint32_t ;
int32_t ;
} ;
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
= 1 << 4,
= 1 << 5,
} ;
();
typedef struct {
;
;
bool ;
uint8_t [3];
} ;
(const uint16_t year, const uint8_t month, const uint8_t day, const uint8_t hour, const uint8_t minute, const uint8_t second, const uint16_t millisecond, const int32_t utcOffset);
typedef struct {
uint16_t ;
uint16_t ;
uint8_t ;
uint8_t ;
uint8_t ;
uint8_t ;
uint8_t ;
uint8_t [7];
} ;
(const type);
(const dateTime, const type);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
//
// Barrier/Fence
//
void (void);
void (void);
void (void);
//
// Exchange
//
uint32_t (volatile uint32_t *target, const uint32_t value);
uint64_t (volatile uint64_t *target, const uint64_t value);
int32_t (volatile int32_t *target, const int32_t value);
int64_t (volatile int64_t *target, const int64_t value);
void *(volatile void **target, const void *value);
size_t (volatile size_t *target, const size_t value);
//
// Fetch and Add
//
uint32_t (volatile uint32_t *value, const uint32_t addend);
uint64_t (volatile uint64_t *value, const uint64_t addend);
int32_t (volatile int32_t *value, const int32_t addend);
int64_t (volatile int64_t *value, const int64_t addend);
size_t (volatile size_t *dest, const size_t addend);
void *(volatile void **dest, const intptr_t addend);
//
// Add and Fetch
//
uint32_t (volatile uint32_t *dest, const uint32_t addend);
uint64_t (volatile uint64_t *dest, const uint64_t addend);
int32_t (volatile int32_t *dest, const int32_t addend);
int64_t (volatile int64_t *dest, const int64_t addend);
size_t (volatile size_t *dest, const size_t addend);
void *(volatile void **dest, const intptr_t addend);
//
// Increment
//
uint32_t (volatile uint32_t *dest);
uint64_t (volatile uint64_t *dest);
int32_t (volatile int32_t *dest);
int64_t (volatile int64_t *dest);
size_t (volatile size_t *dest);
void *(volatile void **dest);
//
// CAS
//
uint32_t (volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange);
uint64_t (volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange);
int32_t (volatile int32_t *dest, const int32_t comparand, const int32_t exchange);
int64_t (volatile int64_t *dest, const int64_t comparand, const int64_t exchange);
size_t (volatile size_t *dest, const size_t comparand, const size_t exchange);
void *(volatile void **dest, const void *comparand, const void *exchange);
bool (volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange);
bool (volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange);
bool (volatile int32_t *dest, const int32_t comparand, const int32_t exchange);
bool (volatile int64_t *dest, const int64_t comparand, const int64_t exchange);
bool (volatile size_t *dest, const size_t comparand, const size_t exchange);
bool (volatile void **dest, const void *comparand, const void *exchange);
//
// Load
//
uint32_t (volatile uint32_t *source);
uint64_t (volatile uint64_t *source);
int32_t (volatile int32_t *source);
int64_t (volatile int64_t *source);
size_t (volatile size_t *source);
void *(volatile void **source);
//
// Store
//
void (volatile uint32_t *dest, const uint32_t value);
void (volatile uint64_t *dest, const uint64_t value);
void (volatile int32_t *dest, const int32_t value);
void (volatile int64_t *dest, const int64_t value);
void (volatile size_t *dest, const size_t value);
void (volatile void **dest, const void *value);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef struct {
void *;
size_t ;
} ;
typedef struct {
uint64_t ;
uint64_t ;
uint64_t ;
uint64_t ;
uint64_t ;
uint64_t ;
uint64_t ;
uint64_t ;
} ;
void (void *mem, const size_t size);
void (void *mem, const uint8_t value, const size_t size);
void (const void *sourceMem, const size_t sourceSize, void *targetMem);
void *(const size_t size);
void (void *ptr);
void *(const size_t size, const size_t alignment);
void (void *ptr);
bool ( *outInfos);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
#define FPL_MAX_VERSION_PART_LENGTH 8
typedef char [ + 1];
typedef struct {
char [];
union {
struct {
;
;
;
;
} ;
[4];
} ;
} ;
typedef struct {
char [];
char [];
;
;
} ;
bool ( *outInfos);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
size_t (char *nameBuffer, const size_t maxNameBufferLen);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
,
,
,
,
= ,
= ,
} ;
typedef enum {
= 0,
,
,
= ,
= ,
} ;
const char *(const type);
typedef struct {
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
} ;
(sizeof() <= 28);
typedef struct {
bool ;
bool ;
bool ;
bool ;
bool ;
bool ;
} ;
(sizeof() <= 28);
typedef struct {
;
union {
;
;
uint8_t [28];
};
} ;
(sizeof() == 32);
typedef union {
struct {
uint32_t ;
uint32_t ;
uint32_t ;
uint32_t ;
};
uint32_t [4];
} ;
(sizeof() == 16);
bool (const uint32_t functionId, *outLeaf);
uint64_t (void);
uint64_t (void);
const char *(const type);
size_t (void);
size_t (char *destBuffer, const size_t maxDestBufferLen);
bool ( *outCaps);
(void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
= 1 << 4,
= 1 << 5,
= 1 << 6,
= | | ,
= | | | | ,
} ;
();
typedef enum {
= 0,
,
,
,
= ,
= ,
} ;
typedef enum {
= -6,
= -5,
= -4,
= -3,
= -2,
= -1,
= 0,
= 1,
= ,
= ,
} ;
const char *(const type);
typedef enum {
= 0,
,
,
,
= ,
= ,
} ;
#if defined(FPL__ENABLE_VIDEO_OPENGL)
typedef enum {
= 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
} ;
typedef struct {
const char *;
;
uint32_t ;
uint32_t ;
uint8_t ;
} ;
#endif // FPL__ENABLE_VIDEO_OPENGL
#if defined(FPL__ENABLE_VIDEO_VULKAN)
typedef void ()(void *userData, const char *message, const uint32_t messageSeverity, const uint32_t messageType, const void *debugUtilsMessengerCallbackData);
typedef enum {
= 0,
,
,
} ;
typedef enum {
= 0,
= 1,
= 2,
= 3,
= 4,
= INT32_MAX,
} ;
typedef struct {
;
;
;
const char *;
const char *;
const char *;
void *;
const void *;
*;
void *;
;
;
} ;
#endif // FPL__ENABLE_VIDEO_VULKAN
typedef struct {
#if defined(FPL__ENABLE_VIDEO_OPENGL)
;
#endif
#if defined(FPL__ENABLE_VIDEO_VULKAN)
;
#endif
int ;
} ;
typedef struct {
;
;
;
;
} ;
void ( *video);
typedef enum {
= 0,
,
,
,
,
,
,
,
= ,
= ,
} ;
typedef enum {
= 0,
,
,
,
,
,
,
,
= ,
= ,
} ;
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
= 1 << 4,
= 1 << 5,
} ;
();
typedef enum {
= 0,
,
} ;
typedef enum {
= 0,
,
} ;
typedef enum {
= 0,
,
,
,
} ;
typedef enum {
= -1,
= 0,
,
,
,
,
,
,
,
,
,
,
,
= ,
= ,
} ;
typedef enum {
= 0,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
= ,
= ,
} ;
();
const char *(const type);
#define FPL_MAX_AUDIO_CHANNEL_COUNT 32
typedef struct {
[];
} ;
typedef struct {
uint32_t ;
uint32_t ;
uint32_t ;
uint16_t ;
uint16_t ;
;
;
;
;
} ;
typedef union {
#if defined(FPL__ENABLE_AUDIO_DIRECTSOUND)
fpl__Win32Guid dshow;
#endif
#if defined(FPL__ENABLE_AUDIO_WASAPI)
wchar_t wasapi[128];
#endif
#if defined(FPL__ENABLE_AUDIO_ALSA)
char alsa[256];
#endif
#if defined(FPL__ENABLE_AUDIO_PULSEAUDIO)
uint32_t pulse;
#endif
#if defined(FPL__ENABLE_AUDIO_PIPEWIRE)
uint32_t pipewire;
#endif
#if defined(FPL__ENABLE_AUDIO_OSS)
char oss[256];
#endif
uint8_t [256];
} ;
typedef uint64_t ;
typedef struct {
char [ - 1];
bool ;
;
} ;
#if defined(FPL__ENABLE_AUDIO_ALSA)
typedef struct fplAlsaAudioSettings {
noMMap;
} fplAlsaAudioSettings;
#endif
#if defined(FPL__ENABLE_AUDIO_PULSEAUDIO)
typedef struct fplPulseAudioSettings {
char serverName[256];
char applicationName[256];
char streamName[256];
} fplPulseAudioSettings;
#endif
#if defined(FPL__ENABLE_AUDIO_PIPEWIRE)
typedef struct fplPipeWireAudioSettings {
char applicationName[256];
char streamName[256];
char mediaRole[64];
} fplPipeWireAudioSettings;
#endif
#if defined(FPL__ENABLE_AUDIO_OSS)
typedef struct fplOSSAudioSettings {
noNonBlocking;
uint32_t fragmentExponent;
} fplOSSAudioSettings;
#endif
typedef union {
#if defined(FPL__ENABLE_AUDIO_ALSA)
fplAlsaAudioSettings alsa;
#endif
#if defined(FPL__ENABLE_AUDIO_PULSEAUDIO)
fplPulseAudioSettings pulse;
#endif
#if defined(FPL__ENABLE_AUDIO_PIPEWIRE)
fplPipeWireAudioSettings pipewire;
#endif
#if defined(FPL__ENABLE_AUDIO_OSS)
fplOSSAudioSettings oss;
#endif
int ;
} ;
typedef uint32_t()(const *deviceFormat, const uint32_t frameCount, void *outputSamples, void *userData);
typedef struct {
;
;
;
*;
void *;
;
;
;
;
} ;
void ( *audio);
typedef enum {
= 0,
,
} ;
typedef struct {
const uint8_t *;
uint32_t ;
uint32_t ;
;
} ;
typedef bool ()(const platformType, void *windowState, void *rawEventData, void *userData);
typedef ;
typedef struct {
*;
void *;
*;
void *;
} ;
typedef struct {
uint32_t ;
uint32_t ;
} ;
typedef struct {
int32_t ;
int32_t ;
} ;
typedef union {
struct {
uint8_t ;
uint8_t ;
uint8_t ;
uint8_t ;
} ;
uint32_t ;
uint8_t [4];
} ;
(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a);
typedef struct {
char [];
[2];
;
;
;
;
uint32_t ;
;
;
;
;
;
;
} ;
void ( *window);
typedef struct {
char [];
} ;
void ( *console);
// Forward declarations for the gamepad mapping resolver hook. Full definitions live further down with the other gamepad types.
typedef struct ;
typedef struct ;
#define FPL_GAMEPAD_MAPPING_RESOLVE_CALLBACK(name) bool name(const fplGamepadInfo *info, fplGamepadMapping *outMapping, void *userData)
typedef ();
typedef struct {
uint32_t ;
uint32_t ;
*;
void *;
} ;
void ( *gamepadSettings);
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= | | ,
} ;
();
typedef enum {
= 0,
,
,
,
,
,
,
= ,
= ,
} ;
#define FPL_MAX_INPUT_BACKEND_COUNT 16
typedef struct {
uint32_t ;
} ;
bool (const *mask, const type);
void ( *mask, const type);
void ( *mask, const type);
typedef struct {
;
;
;
;
;
;
;
} ;
void ( *input);
typedef void *()(void *userData, const size_t size, const size_t alignment);
typedef void ()(void *userData, void *ptr);
typedef enum {
= 0,
,
} ;
typedef struct {
;
*;
*;
void *;
} ;
typedef struct {
;
;
} ;
typedef struct {
;
;
;
;
;
;
} ;
void ( *settings);
(void);
const *(void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
(void);
const char *(const type);
bool (const initFlags, const *initSettings);
(void);
void (void);
bool (void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= -1,
= 0,
= 1,
= 2,
= 3,
= 4,
= 5,
= 6,
= ,
= ,
} ;
#if defined(FPL__ENABLE_LOGGING)
typedef void ()(const char *funcName, const int lineNumber, const level, const char *message);
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
} ;
();
typedef struct {
int ;
} ;
typedef struct {
*;
} ;
typedef struct {
;
;
;
} ;
typedef struct {
#if defined(FPL__ENABLE_LOG_MULTIPLE_WRITERS)
union {
[6];
struct {
criticalWriter;
errorWriter;
warningWriter;
infoWriter;
verboseWriter;
debugWriter;
};
};
#else
[1];
#endif // FPL_USE_LOG_SIMPLE
fplLogLevel maxLevel;
;
} ;
void (const *params);
const *(void);
void (const maxLevel);
(void);
#endif // FPL__ENABLE_LOGGING
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const char *(void);
const char *(const size_t index);
size_t (void);
void (void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32LibraryHandle win32LibraryHandle;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXLibraryHandle posixLibraryHandle;
#endif
} ;
typedef struct {
;
;
} ;
bool (const char *libraryFilePath, *outHandle);
void *(const *handle, const char *name);
void ( *handle);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void (const char *text);
void (const char *format, ...);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void (const char *text);
void (const char *text);
char (void);
void (const char *format, ...);
void (const char *format, ...);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
,
,
} ;
typedef uint32_t ;
typedef enum {
= -10,
= -2,
= -1,
= 0,
= 1,
= 2,
= ,
= ,
= ,
= ,
} ;
// Forward declaration; the documented definition lives a few lines below.
typedef struct ;
typedef void ()(const *thread, void *data);
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32ThreadHandle win32ThreadHandle;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXThreadHandle posixThread;
#endif
} ;
typedef struct {
void *;
*;
size_t ;
;
} ;
typedef struct {
;
;
volatile ;
// 64-bit to portably hold pthread_t (which is a pointer on glibc/FreeBSD) without truncation.
uint64_t ;
volatile ;
volatile ;
} ;
#if defined(FPL_PLATFORM_WINDOWS)
typedef struct fpl__Win32InternalSemaphore {
fpl__Win32SemaphoreHandle handle;
volatile int32_t value;
} fpl__Win32InternalSemaphore;
#endif
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32InternalSemaphore win32;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXSemaphoreHandle posixHandle;
#endif
} ;
typedef struct {
;
;
} ;
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32MutexHandle win32CriticalSection;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXMutexHandle posixMutex;
#endif
} ;
typedef struct {
;
;
} ;
#if defined(FPL_PLATFORM_UNIX)
typedef struct fplUnixSignalEvent {
fpl__POSIXMutexHandle mutex;
fpl__POSIXConditionVariable cond;
uint32_t isSet;
uint32_t manualReset;
} fplUnixSignalEvent;
#endif
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32SignalHandle win32EventHandle;
#elif defined(FPL_PLATFORM_LINUX)
fpl__LinuxSignalHandle linuxEventHandle;
#elif defined(FPL_PLATFORM_UNIX)
fplUnixSignalEvent unixEvent;
#endif
} ;
typedef struct {
;
;
} ;
typedef enum {
= 0,
= 1,
} ;
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32ConditionVariable win32Condition;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXConditionVariable posixCondition;
#endif
int ;
} ;
typedef struct {
;
;
} ;
( *thread);
const *(void);
size_t (void);
size_t (void);
uint64_t (void);
*( *runFunc, void *data);
*( *parameters);
( *thread);
bool ( *thread, const newPriority);
void (const uint32_t milliseconds);
bool (void);
bool ( *thread);
bool ( *thread, const timeout);
bool ( **threads, const size_t count, const size_t stride, const timeout);
bool ( **threads, const size_t count, const size_t stride, const timeout);
bool ( *mutex);
void ( *mutex);
bool ( *mutex);
bool ( *mutex);
bool ( *mutex);
bool ( *signal, const initialValue);
void ( *signal);
bool ( *signal, const timeout);
bool ( **signals, const size_t count, const size_t stride, const timeout);
bool ( **signals, const size_t count, const size_t stride, const timeout);
bool ( *signal);
bool ( *signal);
bool ( *condition);
void ( *condition);
bool ( *condition, *mutex, const timeout);
bool ( *condition);
bool ( *condition);
bool ( *semaphore, const uint32_t initialValue);
void ( *semaphore);
bool ( *semaphore, const timeout);
bool ( *semaphore);
int32_t ( *semaphore);
bool ( *semaphore);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
bool (const char *source, const char *wildcard);
bool (const char *a, const size_t aLen, const char *b, const size_t bLen);
bool (const char *a, const char *b);
size_t (char *path, size_t maxPathLen);
size_t (char *path);
size_t (const char *appended, const size_t appendedLen, char *buffer, size_t maxBufferLen);
size_t (const char *appended, char *buffer, size_t maxBufferLen);
size_t (const char *str);
size_t (const char *source, const size_t sourceLen, char *dest, const size_t maxDestLen);
size_t (const char *source, char *dest, const size_t maxDestLen);
size_t (const wchar_t *wideSource, const size_t wideSourceLen, char *utf8Dest, const size_t maxUtf8DestLen);
size_t (const char *utf8Source, const size_t utf8SourceLen, wchar_t *wideDest, const size_t maxWideDestLen);
size_t (char *destBuffer, const size_t maxDestBufferLen, const char *format, ...);
size_t (char *destBuffer, const size_t maxDestBufferLen, const char *format, va_list argList);
int32_t (const char *str, const size_t len);
int32_t (const char *str);
bool (const char *str, const size_t len, int32_t *outValue);
bool (const char *str, int32_t *outValue);
size_t (const int32_t value, char *buffer, const size_t maxBufferLen);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32FileHandle win32FileHandle;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXFileHandle posixFileHandle;
#endif
} ;
typedef struct {
;
;
} ;
typedef enum {
= 0,
,
} ;
typedef enum {
= 0,
,
} ;
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
} ;
();
typedef enum {
= 0,
= 0xFF0000,
= 0x00FF00,
= 0x0000FF,
} ;
();
typedef union {
struct {
uint8_t ;
uint8_t ;
uint8_t ;
uint8_t ;
};
uint32_t ;
} ;
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3
} ;
();
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32FileHandle win32FileHandle;
#elif defined(FPL_SUBPLATFORM_POSIX)
fpl__POSIXDirHandle posixDirHandle;
#endif
} ;
typedef struct {
char [];
char [];
} ;
typedef uint64_t ;
typedef struct {
;
;
;
} ;
typedef struct {
char [];
;
;
;
;
;
;
size_t ;
} ;
bool (const char *filePath, *outHandle);
bool (const char *filePath, *outHandle);
bool (const char *filePath, *outHandle);
uint32_t (const *fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize);
uint64_t (const *fileHandle, const uint64_t sizeToRead, void *targetBuffer, const uint64_t maxTargetBufferSize);
size_t (const *fileHandle, const size_t sizeToRead, void *targetBuffer, const size_t maxTargetBufferSize);
uint32_t (const *fileHandle, const void *sourceBuffer, const uint32_t sourceSize);
uint64_t (const *fileHandle, const void *sourceBuffer, const uint64_t sourceSize);
size_t (const *fileHandle, const void *sourceBuffer, const size_t sourceSize);
uint32_t (const *fileHandle, const int32_t position, const mode);
uint64_t (const *fileHandle, const int64_t position, const mode);
size_t (const *fileHandle, const intptr_t position, const mode);
uint32_t (const *fileHandle);
uint64_t (const *fileHandle);
size_t (const *fileHandle);
bool ( *fileHandle);
void ( *fileHandle);
uint32_t (const char *filePath);
uint64_t (const char *filePath);
size_t (const char *filePath);
bool (const char *filePath, uint64_t *outSize);
uint32_t (const *fileHandle);
uint64_t (const *fileHandle);
size_t (const *fileHandle);
bool (const *fileHandle, uint64_t *outSize);
bool (const char *filePath, *outStamps);
bool (const *fileHandle, *outStamps);
bool (const char *filePath);
bool (const char *sourceFilePath, const char *targetFilePath, const bool overwrite);
bool (const char *sourceFilePath, const char *targetFilePath);
bool (const char *filePath);
bool (const char *path);
bool (const char *path);
bool (const char *path);
bool (const char *path, const char *filter, *entry);
bool ( *entry);
void ( *entry);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
size_t (char *destPath, const size_t maxDestLen);
size_t (char *destPath, const size_t maxDestLen);
size_t (const char *sourcePath, char *destPath, const size_t maxDestLen);
size_t (const char *sourcePath, char *destPath, const size_t maxDestLen);
const char *(const char *sourcePath);
const char *(const char *sourcePath);
size_t (const char *filePath, const char *newFileExtension, char *destPath, const size_t maxDestLen);
size_t (char *destPath, const size_t maxDestPathLen, const size_t pathCount, ...);
// ****************************************************************************
//
// Window / Events / Input
//
// ****************************************************************************
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT)
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
= 1,
= 2,
} ;
typedef enum {
= 0,
// 0x01-0x07: Undefined
= 0x08,
= 0x09,
// 0x0A-0x0B: Reserved
= 0x0C,
= 0x0D,
// 0x0E-0x0F: Undefined
= 0x10,
= 0x11,
= 0x12,
= 0x13,
= 0x14,
// 0x15: IME-Keys
// 0x16: Undefined
// 0x17-0x19 IME-Keys
// 0x1A: Undefined
= 0x1B,
// 0x1C-0x1F: IME-Keys
= 0x20,
= 0x21,
= 0x22,
= 0x23,
= 0x24,
= 0x25,
= 0x26,
= 0x27,
= 0x28,
= 0x29,
= 0x2A,
= 0x2B,
= 0x2C,
= 0x2D,
= 0x2E,
= 0x2F,
= 0x30,
= 0x31,
= 0x32,
= 0x33,
= 0x34,
= 0x35,
= 0x36,
= 0x37,
= 0x38,
= 0x39,
// 0x3A-0x40: Undefined
= 0x41,
= 0x42,
= 0x43,
= 0x44,
= 0x45,
= 0x46,
= 0x47,
= 0x48,
= 0x49,
= 0x4A,
= 0x4B,
= 0x4C,
= 0x4D,
= 0x4E,
= 0x4F,
= 0x50,
= 0x51,
= 0x52,
= 0x53,
= 0x54,
= 0x55,
= 0x56,
= 0x57,
= 0x58,
= 0x59,
= 0x5A,
= 0x5B,
= 0x5C,
= 0x5D,
// 0x5E: Reserved
= 0x5F,
= 0x60,
= 0x61,
= 0x62,
= 0x63,
= 0x64,
= 0x65,
= 0x66,
= 0x67,
= 0x68,
= 0x69,
= 0x6A,
= 0x6B,
= 0x6C,
= 0x6D,
= 0x6E,
= 0x6F,
= 0x70,
= 0x71,
= 0x72,
= 0x73,
= 0x74,
= 0x75,
= 0x76,
= 0x77,
= 0x78,
= 0x79,
= 0x7A,
= 0x7B,
= 0x7C,
= 0x7D,
= 0x7E,
= 0x7F,
= 0x80,
= 0x81,
= 0x82,
= 0x83,
= 0x84,
= 0x85,
= 0x86,
= 0x87,
// 0x88-0x8F: Unassigned
= 0x90,
= 0x91,
// 0x92-0x96: OEM specific
// 0x97-0x9F: Unassigned
= 0xA0,
= 0xA1,
= 0xA2,
= 0xA3,
= 0xA4,
= 0xA5,
// 0xA6-0xAC: Don't care
= 0xAD,
= 0xAE,
= 0xAF,
= 0xB0,
= 0xB1,
= 0xB2,
= 0xB3,
// 0xB4-0xB9: Don't care
= 0xBA,
= 0xBB,
= 0xBC,
= 0xBD,
= 0xBE,
= 0xBF,
= 0xC0,
// 0xC1-0xD7: Reserved
//
// 0xD8-0xDA: Unassigned
= 0xDB,
= 0xDC,
= 0xDD,
= 0xDE,
= 0xDF,
// 0xE0-0xFE: Don't care
= 0xFF,
= ,
} ;
const char *(const key);
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
= 1 << 3,
= 1 << 4,
= 1 << 5,
= 1 << 6,
= 1 << 7,
= 1 << 8,
= 1 << 9,
= 1 << 10,
} ;
();
#define FPL_MAX_KEYBOARD_STATE_COUNT 256
typedef struct {
;
[];
[];
} ;
bool ( *outState);
typedef enum {
= -1,
= 0,
= 1,
= 2,
= 3,
= 4,
,
} ;
typedef struct {
[];
int32_t ;
int32_t ;
float ;
float ;
} ;
bool ( *outState);
typedef char [];
#define FPL_GAMEPAD_GUID_SIZE 16
typedef uint8_t [];
typedef struct {
;
} ;
typedef enum {
= 0,
,
,
,
,
,
,
,
,
,
,
,
,
,
} ;
typedef struct {
union {
struct {
;
;
;
;
union {
struct {
;
;
;
;
};
struct {
;
;
;
;
};
[4];
};
;
;
;
;
;
;
};
[14];
};
const char *;
float ;
float ;
float ;
float ;
float ;
float ;
;
;
} ;
typedef enum {
= 0,
,
,
,
} ;
typedef struct {
;
const char *;
;
uint32_t ;
} ;
#define FPL_MAX_GAMEPAD_STATE_COUNT 4
typedef struct {
[];
} ;
bool ( *outStates);
typedef enum {
= 0,
,
,
,
} ;
typedef enum {
= 0,
,
,
} ;
typedef struct {
;
uint32_t ;
uint32_t ;
;
bool ;
} ;
typedef enum {
= 0,
,
,
,
,
,
,
} ;
typedef enum {
= 0,
,
,
,
,
,
} ;
#define FPL_GAMEPAD_BUTTON_COUNT 14
typedef struct {
;
[];
[];
;
} ;
#define FPL_GAMEPAD_DATA_MAX_AXES 8
#define FPL_GAMEPAD_DATA_MAX_BUTTONS 32
#define FPL_GAMEPAD_DATA_MAX_HATS 8
typedef struct {
float [];
bool [];
uint8_t [];
uint32_t ;
uint32_t ;
uint32_t ;
} ;
typedef struct {
;
const char *;
uint32_t ;
;
uint16_t ;
uint16_t ;
uint16_t ;
uint32_t ;
uint32_t ;
uint32_t ;
} ;
bool (const *mapping, const *input, *outState);
bool (const *input, *outState);
#define FPL_MAX_INPUT_DEVICE_NAME 64
#define FPL_MAX_INPUT_DEVICE_COUNT 32
typedef struct {
uint8_t [16];
} ;
typedef enum {
= 0,
= 1 << 0,
= 1 << 1,
= 1 << 2,
} ;
();
typedef enum {
= 0,
,
,
} ;
typedef struct {
;
char [];
uint32_t ;
;
;
;
;
union {
keyboard;
mouse;
gamepad;
} ;
} ;
typedef struct {
const char *;
;
;
;
;
;
uint8_t [4];
} ;
uint32_t ( *outSupports, const uint32_t maxCount);
bool (const type, *outSupport);
uint32_t (const sourceFilter, *outDevices, const uint32_t maxDevices);
bool (const *guid, *outDevice);
uint32_t ( *outDevices, const uint32_t maxDevices);
uint32_t ( *outDevices, const uint32_t maxDevices);
uint32_t ( *outDevices, const uint32_t maxDevices);
bool (void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
,
,
,
,
,
,
,
,
,
,
,
} ;
typedef struct {
;
const char **;
size_t ;
} ;
typedef struct {
;
union {
;
;
;
};
} ;
typedef enum {
= 0,
,
,
} ;
typedef struct {
uint64_t ;
;
;
;
;
} ;
typedef enum {
,
,
,
,
} ;
typedef struct {
;
;
;
int32_t ;
int32_t ;
float ;
} ;
typedef enum {
= 0,
,
,
,
,
} ;
typedef struct {
;
union {
;
;
;
;
};
} ;
bool ( *ev);
void (void);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
,
,
,
} ;
typedef enum {
= 0,
,
,
} ;
bool (void);
void (void);
bool (void);
void (const bool value);
bool ( *outSize);
void (const uint32_t width, const uint32_t height);
bool (void);
void (const bool value);
bool (void);
void (const bool value);
bool (void);
void (const bool value);
bool (const bool value, const uint32_t fullscreenWidth, const uint32_t fullscreenHeight, const uint32_t refreshRate);
bool (const bool value, const int32_t x, const int32_t y, const int32_t width, const int32_t height);
bool (void);
bool (void);
bool (void);
bool ( *outPos);
void (const int32_t left, const int32_t top);
void (const char *title);
size_t (char *outTitle, const size_t maxOutTitleLength);
(void);
bool (const newState);
void (const bool enabled);
bool (int32_t *outX, int32_t *outY);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef struct {
char id[];
;
;
;
;
} ;
typedef struct {
uint32_t ;
uint32_t ;
uint32_t ;
uint32_t ;
} ;
size_t (void);
size_t ( *outDisplays, const size_t maxDisplayCount);
bool ( *outInfo);
bool ( *outInfo);
bool (const int32_t x, const int32_t y, *outInfo);
size_t (const char *id, *outModes, const size_t maxDisplayModeCount);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
bool (char *dest, const uint32_t maxDestLen);
bool (const char *text);
#endif // FPL__ENABLE_WINDOW || FPL__ENABLE_INPUT
#if defined(FPL__ENABLE_VIDEO)
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef struct {
int32_t ;
int32_t ;
int32_t ;
int32_t ;
} ;
(int32_t left, int32_t top, int32_t right, int32_t bottom);
typedef struct {
uint32_t *;
uint32_t ;
uint32_t ;
size_t ;
size_t ;
;
;
} ;
#if defined(FPL__ENABLE_VIDEO_VULKAN)
typedef struct {
void *;
void *;
} ;
#endif
#if defined(FPL__ENABLE_VIDEO_OPENGL)
typedef struct {
void *;
} ;
#endif
#if defined(FPL_PLATFORM_WINDOWS)
typedef struct fplVideoWindowWin32 {
fpl__Win32WindowHandle windowHandle;
fpl__Win32DeviceContext deviceContext;
} fplVideoWindowWin32;
#endif
#if defined(FPL_SUBPLATFORM_X11)
typedef struct fplVideoWindowX11 {
fpl__X11_Window window;
fpl__X11_Display *display;
fpl__X11_Visual *visual;
int screen;
} fplVideoWindowX11;
#endif // FPL_SUBPLATFORM_X11
typedef union {
#if defined(FPL_PLATFORM_WINDOWS)
fplVideoWindowWin32 win32;
#elif defined(FPL_SUBPLATFORM_X11)
fplVideoWindowX11 x11;
#endif
int ;
} ;
typedef struct {
;
#if defined(FPL__ENABLE_VIDEO_VULKAN)
;
#endif
#if defined(FPL__ENABLE_VIDEO_OPENGL)
;
#endif
int ;
} ;
#if defined(FPL__ENABLE_VIDEO_VULKAN)
typedef struct {
const char *[2];
uint32_t ;
} ;
#endif // FPL__ENABLE_VIDEO_VULKAN
typedef union {
#if defined(FPL__ENABLE_VIDEO_VULKAN)
;
#endif // FPL__ENABLE_VIDEO_VULKAN
int dummy;
} ;
(void);
const char *( backendType);
*(void);
bool (const uint32_t width, const uint32_t height);
void (void);
const void *(const char *procName);
const *(void);
bool (const backendType, *requirements);
#endif // FPL__ENABLE_VIDEO
#if defined(FPL__ENABLE_AUDIO)
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
= ,
= ,
} ;
(void);
(void);
(void);
( *audioSettings);
bool (void);
bool ( *outFormat);
bool ( *outDevice);
const char *(void);
bool ( *outMapping);
bool ( *newCallback, void *userData);
uint32_t (const uint32_t maxDeviceCount, const uint32_t deviceInfoSize, *outDevices);
bool (const *deviceId, *outDeviceInfo);
uint32_t (const format);
const char *(const format);
const char *(const backendType);
uint32_t (const uint32_t sampleRate, const uint32_t bufferSizeInMilliSeconds);
uint32_t (const uint32_t sampleRate, const uint32_t frameCount);
uint32_t (const format, const uint16_t channelCount);
uint32_t (const format, const uint16_t channelCount, const uint32_t frameCount);
uint32_t (const uint32_t inputFrameCount, const uint32_t inputSampleRate, const uint32_t outputSampleRate);
(const uint16_t channelCount);
uint16_t (const channelLayout);
(const mode);
(const mode);
(const latencyType, const shareMode);
(const uint32_t sampleRate, const uint16_t channels, const type);
bool (const format64, uint32_t *outSampleRate, uint16_t *outChannels, *outType);
#endif // FPL__ENABLE_AUDIO
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef enum {
= 0,
,
} ;
size_t (const targetFormat, char *buffer, const size_t maxBufferLen);
size_t (const targetFormat, char *buffer, const size_t maxBufferLen);
size_t (const targetFormat, char *buffer, const size_t maxBufferLen);
// Ignore any doxygen documentation from here
// ****************************************************************************
//
// > EXPORT
//
// Internal functions for static library
// Entry-Point forward declaration
//
// ****************************************************************************
#if defined(FPL_PLATFORM_WINDOWS)
# if defined(FPL_ENTRYPOINT)
// @NOTE(final): Required for access "main" from the actual win32 entry point
int main(int argc, char **args);
# endif
#endif // FPL_PLATFORM_WINDOWS
#endif // FPL_HEADER_H
// ****************************************************************************
//
// > IMPLEMENTATION
//
// FPL uses several implementation blocks to structure things in categories.
// Each block has its own ifdef definition to collapse it down if needed.
// But the baseline structure is the following:
//
// - Compiler settings (Disable warnings, etc.)
// - Platform Constants & Types (All required structs, Constants, Global variables, etc.)
// - Common implementations
// - Actual platform implementations (Win32, Linux)
// - Sub platform implementations (X11, POSIX, STD)
// - Backend implementations (Video: OpenGL/Software/Vulkan, Audio: DirectSound/Alsa)
// - Systems (Audio, Video, Window systems)
// - Core (Init & Release of the specific platform by selection)
//
// You can use the following strings to search for implementation blocks - including the > prefix:
//
// > COMPILER_CONFIG
//
// > INTERNAL_TOP
// > INTERNAL_LOGGING
//
// > PLATFORM_CONSTANTS
// > UTILITY_FUNCTIONS
//
// > TYPES
// > TYPES_WIN32
// > TYPES_POSIX
// > TYPES_LINUX
// > TYPES_UNIX
// > TYPES_X11
//
// > PLATFORM_STATES
//
// > COMMON
//
// > WIN32_PLATFORM
// > WIN32_XINPUT
// > WIN32_DINPUT
// > WIN32_INPUT_KBM
// > POSIX_SUBPLATFORM (Linux, Unix)
// > STD_STRINGS_SUBPLATFORM
// > STD_CONSOLE_SUBPLATFORM
// > X11_SUBPLATFORM
// > X11_INPUT_KBM
// > LINUX_PLATFORM
// > UNIX_PLATFORM
//
// > VIDEO_BACKENDS
// > VIDEO_BACKEND_OPENGL_WIN32
// > VIDEO_BACKEND_OPENGL_X11
// > VIDEO_BACKEND_SOFTWARE_WIN32
// > VIDEO_BACKEND_SOFTWARE_X11
// > VIDEO_BACKEND_VULKAN
//
// > AUDIO_BACKEND_API
// > AUDIO_BACKENDS
// > AUDIO_WIN32_SHARED
// > AUDIO_BACKEND_DIRECTSOUND
// > AUDIO_BACKEND_WASAPI
// > AUDIO_BACKEND_ALSA
// > AUDIO_BACKEND_OSS
// > AUDIO_BACKEND_PULSEAUDIO
// > AUDIO_BACKEND_PIPEWIRE
//
// > SYSTEM_AUDIO_L1
// > SYSTEM_VIDEO_L1
// > SYSTEM_WINDOW
// > SYSTEM_AUDIO_L2
// > SYSTEM_VIDEO_L2 (Video backbuffer access and present of the frame)
// > SYSTEM_INPUT
// > SYSTEM_INIT (Init & Release of the Platform)
//
// ****************************************************************************
#if (defined(FPL_IMPLEMENTATION) || FPL_IS_IDE) && !defined(FPL__IMPLEMENTED)
#define FPL__IMPLEMENTED
// ############################################################################
//
// > COMPILER_CONFIG
//
// ############################################################################
#if !defined(FPL__COMPILER_CONFIG_DEFINED)
#define FPL__COMPILER_CONFIG_DEFINED
//
// Compiler warnings
//
#if defined(FPL_COMPILER_MSVC)
// Start to overwrite warning settings (MSVC)
# pragma warning( push )
// Disable noexcept compiler warning for C++
# pragma warning( disable : 4577 )
// Disable "switch statement contains 'default' but no 'case' labels" compiler warning for C++
# pragma warning( disable : 4065 )
// Disable "conditional expression is constant" warning
# pragma warning( disable : 4127 )
// Disable "unreferenced formal parameter" warning
# pragma warning( disable : 4100 )
// Disable "nonstandard extension used: nameless struct/union" warning
# pragma warning( disable : 4201 )
// Disable "local variable is initialized but not referenced" warning
# pragma warning( disable : 4189 )
// Disable "nonstandard extension used: non-constant aggregate initializer" warning
# pragma warning( disable : 4204 )
#elif defined(FPL_COMPILER_GCC)
// Start to overwrite warning settings (GCC)
# pragma GCC diagnostic push
// Disable warning -Wunused-variable
# pragma GCC diagnostic ignored "-Wunused-variable"
// Disable warning -Wunused-function
# pragma GCC diagnostic ignored "-Wunused-function"
#elif defined(FPL_COMPILER_CLANG)
// Start to overwrite warning settings (Clang)
# pragma clang diagnostic push
// Disable warning -Wunused-variable
# pragma clang diagnostic ignored "-Wunused-variable"
// Disable warning -Wunused-function
# pragma clang diagnostic ignored "-Wunused-function"
#endif // FPL_COMPILER
#endif // FPL__COMPILER_CONFIG_DEFINED
// ############################################################################
//
// > INTERNAL_TOP
//
// ############################################################################
#if !defined(FPL__INTERNAL_TOP_DEFINED)
#define FPL__INTERNAL_TOP_DEFINED
// Module constants used for logging
#define FPL__MODULE_CORE "Core"
#define FPL__MODULE_FILES "Files"
#define FPL__MODULE_THREADING "Threading"
#define FPL__MODULE_MEMORY "Memory"
#define FPL__MODULE_WINDOW "Window"
#define FPL__MODULE_LIBRARIES "Libraries"
#define FPL__MODULE_OS "OS"
#define FPL__MODULE_HARDWARE "Hardware"
#define FPL__MODULE_STRINGS "Strings"
#define FPL__MODULE_PATHS "Paths"
#define FPL__MODULE_ARGS "Arguments"
#define FPL__MODULE_AUDIO "Audio"
#define FPL__MODULE_AUDIO_DIRECTSOUND "DirectSound"
#define FPL__MODULE_AUDIO_WASAPI "WASAPI"
#define FPL__MODULE_AUDIO_ALSA "ALSA"
#define FPL__MODULE_AUDIO_PULSEAUDIO "PulseAudio"
#define FPL__MODULE_AUDIO_PIPEWIRE "PipeWire"
#define FPL__MODULE_AUDIO_OSS "OSS"
#define FPL__MODULE_VIDEO "Video"
#define FPL__MODULE_VIDEO_OPENGL "OpenGL"
#define FPL__MODULE_VIDEO_VULKAN "Vulkan"
#define FPL__MODULE_VIDEO_SOFTWARE "Software"
#define FPL__MODULE_WIN32 "Win32"
#define FPL__MODULE_XINPUT "XInput"
#define FPL__MODULE_LINUX "Linux"
#define FPL__MODULE_UNIX "Unix"
#define FPL__MODULE_POSIX "POSIX"
#define FPL__MODULE_PTHREAD "pthread"
#define FPL__MODULE_X11 "X11"
#define FPL__MODULE_XRANDR "XrandR"
#define FPL__MODULE_XINERAMA "Xinerama"
#define FPL__MODULE_GLX "GLX"
//
// Enum macros
//
// Get number of enum values from the specifie first and last enum value
#define FPL__ENUM_COUNT(first, last) ((last) - (first) + 1)
// Get array index for the specified enum value with the first and last enum value
#define FPL__ENUM_VALUE_TO_ARRAY_INDEX(value, first, last) (((value) >= (first) && (value) <= (last)) ? ((value) - (first)) : 0)
// Define the name for a enum value in a mapping table
#define FPL__ENUM_NAME(str, enumValue) str
//
// Internal memory
//
void *fpl__AllocateMemory(const *allocSettings, const size_t size, const size_t alignment);
void fpl__ReleaseMemory(const *allocSettings, void *ptr);
#endif // FPL__INTERNAL_TOP_DEFINED
// ############################################################################
//
// > INTERNAL_LOGGING
//
// ############################################################################
#if !defined(FPL__INTERNAL_LOGGING_DEFINED)
#define FPL__INTERNAL_LOGGING_DEFINED
#define FPL__MODULE_CONCAT(mod, format) "[" mod "] " format
#if defined(FPL__ENABLE_LOGGING)
fpl__global__LogSettings = ;
#define FPL__LOGLEVEL_COUNT FPL__ENUM_COUNT(fplLogLevel_First, fplLogLevel_Last)
( == );
( == );
const char *fpl__LogLevelNameTable[] = {
FPL__ENUM_NAME("All", ),
FPL__ENUM_NAME("Critical", ),
FPL__ENUM_NAME("Error", ),
FPL__ENUM_NAME("Warning", ),
FPL__ENUM_NAME("Info", ),
FPL__ENUM_NAME("Verbose", ),
FPL__ENUM_NAME("Debug", ),
FPL__ENUM_NAME("Trace", ),
};
((fpl__LogLevelNameTable) == FPL__LOGLEVEL_COUNT);
const char *fpl__LogLevelToString(const level) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(level, , );
const char *result = fpl__LogLevelNameTable[index];
return(result);
}
void fpl__LogWrite(const char *funcName, const int lineNumber, const level, const char *message) {
*settings = &fpl__global__LogSettings;
if (!settings->) {
#if defined(FPL_LOG_MULTIPLE_WRITERS)
settings->criticalWriter.console.logToError = true;
settings->criticalWriter.flags = | ;
settings->errorWriter = settings->criticalWriter;
settings->warningWriter = settings->criticalWriter;
settings->infoWriter.flags = | ;
settings->verboseWriter = settings->infoWriter;
settings->debugWriter.flags = ;
#else
settings->[0]. = | ;
#endif
settings-> = ;
settings-> = true;
}
if ((settings-> == -1) || (level <= settings->maxLevel)) {
#if defined(FPL_LOG_MULTIPLE_WRITERS)
(level < (settings->));
const *writer = &settings->[(int)level];
#else
const *writer = &settings->[0];
#endif
const char *levelStr = fpl__LogLevelToString(level);
if ((writer->, )) {
("[%s:%d][%s] %s\n", funcName, lineNumber, levelStr, message);
}
if ((writer->, )) {
("[%s:%d][%s] %s\n", funcName, lineNumber, levelStr, message);
}
if ((writer->, )) {
("[%s:%d][%s] %s\n", funcName, lineNumber, levelStr, message);
}
if ((writer->, ) && writer->. != ) {
writer->.(funcName, lineNumber, level, message);
}
}
}
void fpl__LogWriteArgs(const char *funcName, const int lineNumber, const level, const char *format, va_list argList) {
va_list listCopy;
va_copy(listCopy, argList);
char buffer[];
size_t formattedLen = (buffer, (buffer), format, listCopy);
if (formattedLen > 0) {
fpl__LogWrite(funcName, lineNumber, level, buffer);
}
va_end(listCopy);
}
void fpl__LogWriteVarArgs(const char *funcName, const int lineNumber, const level, const char *format, ...) {
va_list argList;
va_start(argList, format);
fpl__LogWriteArgs(funcName, lineNumber, level, format, argList);
va_end(argList);
}
# define FPL_LOG(lvl, mod, format, ...) fpl__LogWriteVarArgs(FPL_FUNCTION_NAME, __LINE__, lvl, FPL__MODULE_CONCAT(mod, format), ## __VA_ARGS__)
# define FPL_LOG_CRITICAL(mod, format, ...) FPL_LOG(fplLogLevel_Critical, mod, format, ## __VA_ARGS__)
# define FPL_LOG_ERROR(mod, format, ...) FPL_LOG(fplLogLevel_Error, mod, format, ## __VA_ARGS__)
# define FPL_LOG_WARN(mod, format, ...) FPL_LOG(fplLogLevel_Warning, mod, format, ## __VA_ARGS__)
# define FPL_LOG_INFO(mod, format, ...) FPL_LOG(fplLogLevel_Info, mod, format, ## __VA_ARGS__)
# define FPL_LOG_VERBOSE(mod, format, ...) FPL_LOG(fplLogLevel_Verbose, mod, format, ## __VA_ARGS__)
# define FPL_LOG_DEBUG(mod, format, ...) FPL_LOG(fplLogLevel_Debug, mod, format, ## __VA_ARGS__)
# define FPL_LOG_TRACE(mod, format, ...) FPL_LOG(fplLogLevel_Trace, mod, format, ## __VA_ARGS__)
# define FPL__LOG_FUNCTION_N(mod, name) FPL_LOG(fplLogLevel_Debug, mod, "-> %s()", name)
# define FPL_LOG_FUNCTION(mod) FPL__LOG_FUNCTION_N(mod, FPL_FUNCTION_NAME)
#else
# define FPL_LOG(lvl, mod, format, ...)
# define FPL_LOG_CRITICAL(mod, format, ...)
# define FPL_LOG_ERROR(mod, format, ...)
# define FPL_LOG_WARN(mod, format, ...)
# define FPL_LOG_INFO(mod, format, ...)
# define FPL_LOG_VERBOSE(mod, format, ...)
# define FPL_LOG_DEBUG(mod, format, ...)
# define FPL_LOG_TRACE(mod, format, ...)
# define FPL_LOG_FUNCTION(mod)
#endif
//
// Error handling
//
#define FPL__M_CRITICAL(funcName, line, mod, format, ...) fpl__HandleError(funcName, line, fplLogLevel_Critical, FPL__MODULE_CONCAT(mod, format), ## __VA_ARGS__)
#define FPL__M_ERROR(funcName, line, mod, format, ...) fpl__HandleError(funcName, line, fplLogLevel_Error, FPL__MODULE_CONCAT(mod, format), ## __VA_ARGS__)
#define FPL__M_WARNING(funcName, line, mod, format, ...) fpl__HandleError(funcName, line, fplLogLevel_Warning, FPL__MODULE_CONCAT(mod, format), ## __VA_ARGS__)
#define FPL__CRITICAL(mod, format, ...) FPL__M_CRITICAL(FPL_FUNCTION_NAME, __LINE__, mod, format, ## __VA_ARGS__)
#define FPL__ERROR(mod, format, ...) FPL__M_ERROR(FPL_FUNCTION_NAME, __LINE__, mod, format, ## __VA_ARGS__)
#define FPL__WARNING(mod, format, ...) FPL__M_WARNING(FPL_FUNCTION_NAME, __LINE__, mod, format, ## __VA_ARGS__)
#endif // FPL__INTERNAL_LOGGING_DEFINED
// ############################################################################
//
// > PLATFORM_CONSTANTS
//
// ############################################################################
#if !defined(FPL__PLATFORM_CONSTANTS_DEFINED)
#define FPL__PLATFORM_CONSTANTS_DEFINED
// One cacheline worth of padding
#define FPL__ARBITARY_PADDING 64
// Small padding to split sections in memory blocks
#define FPL__MEMORY_PADDING sizeof(uintptr_t)
struct fpl__PlatformAppState *fpl__global__AppState = ;
void fpl__HandleError(const char *funcName, const int lineNumber, const level, const char *format, ...);
#endif // FPL__PLATFORM_CONSTANTS_DEFINED
// ############################################################################
//
// > UTILITY_FUNCTIONS
//
// ############################################################################
void *fpl__AllocateMemory(const *allocSettings, const size_t size, const size_t alignment) {
if (allocSettings-> == ) {
if (allocSettings-> != && allocSettings-> != ) {
return allocSettings->(allocSettings->, size, alignment);
}
}
return (size, alignment);
}
void fpl__ReleaseMemory(const *allocSettings, void *ptr) {
if (allocSettings-> == ) {
if (allocSettings-> != && allocSettings-> != ) {
allocSettings->(allocSettings->, ptr);
return;
}
}
(ptr);
}
// Forward declarations of internal memory
void *fpl__AllocateDynamicMemory(const size_t size, const size_t alignment);
void fpl__ReleaseDynamicMemory(void *ptr);
void *fpl__AllocateTemporaryMemory(const size_t size, const size_t alignment);
void fpl__ReleaseTemporaryMemory(void *ptr);
uint32_t fpl__NextPowerOfTwo(const uint32_t input) {
uint32_t x = input;
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return(x);
}
uint32_t fpl__PrevPowerOfTwo(const uint32_t input) {
uint32_t result = fpl__NextPowerOfTwo(input) >> 1;
return(result);
}
const char *fpl__StringFindChar(const char *s, const char c) {
if (s == ) {
return ;
}
while (*s != '\0') {
if (*s == c) {
return s;
}
++s;
}
return ;
}
const char *fpl__StringFindSubstr(const char *haystack, const char *needle) {
if (haystack == || needle == ) {
return ;
}
size_t needleLen = 0;
while (needle[needleLen] != '\0') {
++needleLen;
}
if (needleLen == 0) {
return haystack;
}
for (const char *p = haystack; *p != '\0'; ++p) {
size_t i = 0;
while (i < needleLen && p[i] == needle[i]) {
++i;
}
if (i == needleLen) {
return p;
}
}
return ;
}
bool fpl__AddLineWhenAnyMatches(const char *line, const char **wildcards, const size_t maxWildcardCount, const size_t maxLineSize, const size_t maxLineCount, char **outLines, size_t *outCount) {
for (size_t i = 0; i < maxWildcardCount; ++i) {
const char *wildcard = wildcards[i];
if ((line, wildcard)) {
size_t index = *outCount;
char *target = outLines[index];
(line, target, maxLineSize);
*outCount = index + 1;
break;
}
}
bool result = *outCount < maxLineCount;
return(result);
}
size_t fpl__ParseTextFile(const char *filePath, const char **wildcards, const size_t maxWildcardCount, const size_t maxLineSize, const size_t maxLineCount, char **outLines) {
if (filePath == || wildcards == || maxWildcardCount == 0 || maxLineSize == 0 || maxLineCount == 0 || outLines == ) {
return(0);
}
// @NOTE(final): Forced Zero-Terminator is not nessecary here, but we do it here to debug it better
// This function supports maxLineSize < fplArrayCount(buffer)
// We allocate the line buffer on the stack because we do not know how large the line will be on compile time
size_t result = 0;
fileHandle = ;
if ((filePath, &fileHandle)) {
char *line = (char *)fpl__AllocateTemporaryMemory(maxLineSize, fpl__MinAlignment);
char buffer[];
const size_t maxBufferSize = (buffer) - 1;
size_t bytesRead = 0;
size_t posLineBytes = 0;
bool done = false;
while (!done && ((bytesRead = (&fileHandle, maxBufferSize, &buffer[0], maxBufferSize)) > 0)) {
buffer[bytesRead] = 0;
char *start = &buffer[0];
char *p = start;
size_t readPos = 0;
size_t lineSizeToRead = 0;
while (readPos < bytesRead) {
if (*p == '\n') {
size_t remainingLineBytes = maxLineSize - posLineBytes;
char *lineTargetP = line + posLineBytes;
if (lineSizeToRead < remainingLineBytes) {
(start, lineSizeToRead, lineTargetP, remainingLineBytes);
} else {
(start, remainingLineBytes - 1, lineTargetP, remainingLineBytes);
}
if (!fpl__AddLineWhenAnyMatches(line, wildcards, maxWildcardCount, maxLineSize, maxLineCount, outLines, &result)) {
done = true;
break;
}
start = p + 1;
line[0] = 0;
lineSizeToRead = 0;
posLineBytes = 0;
} else {
++lineSizeToRead;
}
++p;
++readPos;
}
if (done) {
break;
}
if (lineSizeToRead > 0) {
size_t remainingLineBytes = maxLineSize - posLineBytes;
char *lineTargetP = line + posLineBytes;
if (lineSizeToRead < remainingLineBytes) {
(start, lineSizeToRead, lineTargetP, remainingLineBytes);
posLineBytes += lineSizeToRead;
if (bytesRead <= maxBufferSize) {
if (!fpl__AddLineWhenAnyMatches(line, wildcards, maxWildcardCount, maxLineSize, maxLineCount, outLines, &result)) {
done = true;
}
}
} else {
(start, remainingLineBytes - 1, lineTargetP, remainingLineBytes);
line[0] = 0;
lineSizeToRead = 0;
posLineBytes = 0;
if (!fpl__AddLineWhenAnyMatches(line, wildcards, maxWildcardCount, maxLineSize, maxLineCount, outLines, &result)) {
done = true;
}
}
}
}
fpl__ReleaseTemporaryMemory(line);
(&fileHandle);
}
return(result);
}
void fpl__ParseVersionString(const char *versionStr, *versionInfo) {
(versionStr, versionInfo->, (versionInfo->));
if (versionStr != ) {
const char *p = versionStr;
for (int i = 0; i < 4; ++i) {
const char *digitStart = p;
while (*p >= '0' && *p <= '9') {
++p;
}
size_t len = p - digitStart;
if (len <= (versionInfo->.[i])) {
(digitStart, len, versionInfo->.[i], (versionInfo->.[i]));
} else {
versionInfo->.[i][0] = 0;
}
if (*p != '.' && *p != '-') break;
++p;
}
}
}
// ****************************************************************************
//
// > TYPES
//
// This implementation block includes all the required platform-specific
// header files and defines all the constants, structures and types.
//
// Also some backends structs are included as well, such as XInput/DInput, etc.
//
// ****************************************************************************
// Tries to load the dynamic library and breaks the loop, when it fails
#define FPL__AUTO_LOAD_LIBRARY_BREAK(mod, target, libName) \
if(!fplDynamicLibraryLoad(libName, (target))) { \
FPL__WARNING(mod, "Failed loading library '%s'", (libName)); \
break; \
}
// Tries to load the dynamic library and continues the loop, when it fails
#define FPL__AUTO_LOAD_LIBRARY_CONTINUE(mod, target, libName) \
if(!fplDynamicLibraryLoad(libName, target)) { \
FPL__WARNING(mod, "Failed loading library '%s'", (libName)); \
continue; \
}
// Tries to get the proc address from the dynamic library and continues the loop, when it fails
#define FPL__AUTO_GET_FUNCTION_ADDRESS_CONTINUE(mod, libHandle, libName, target, type, name) \
(target)->name = (type)fplGetDynamicLibraryProc(&libHandle, #name); \
if ((target)->name == fpl_null) { \
FPL__WARNING(mod, "Failed getting procedure address '%s' from library '%s'", #name, libName); \
continue; \
}
// Tries to get the proc address from the dynamic library and breaks the loop, when it fails
#define FPL__AUTO_GET_FUNCTION_ADDRESS_BREAK(mod, libHandle, libName, target, type, name) \
(target)->name = (type *)fplGetDynamicLibraryProc(&libHandle, #name); \
if ((target)->name == fpl_null) { \
FPL__WARNING(mod, "Failed getting procedure address '%s' from library '%s'", #name, libName); \
break; \
}
#if !defined(FPL_NO_RUNTIME_LINKING)
# define FPL__AUTO_LOAD_LIBRARY(mod, target, libName) FPL__AUTO_LOAD_LIBRARY_BREAK(mod, target, libName)
# define FPL__AUTO_UNLOAD_LIBRARY(target) fplDynamicLibraryUnload(target)
# define FPL__AUTO_GET_FUNCTION_ADDRESS(mod, libHandle, libName, target, type, name) FPL__AUTO_GET_FUNCTION_ADDRESS_BREAK(mod, libHandle, libName, target, type, name)
#else
# define FPL__AUTO_LOAD_LIBRARY(mod, target, libName)
# define FPL__AUTO_UNLOAD_LIBRARY(target)
# define FPL__AUTO_GET_FUNCTION_ADDRESS(mod, libHandle, libName, target, type, name) \
(target)->name = name
#endif
// ############################################################################
//
// > TYPES_WIN32
//
// ############################################################################
#if defined(FPL_PLATFORM_WINDOWS)
# include <windowsx.h> // Macros for window messages
# include <shlobj.h> // SHGetFolderPath
# include <shellapi.h> // HDROP
# include <xinput.h> // XInput
# if !defined(DIRECTINPUT_VERSION)
# define DIRECTINPUT_VERSION 0x0800
# endif
# include <dinput.h> // DirectInput8
# if defined(FPL_IS_CPP)
# define fpl__Win32IsEqualGuid(a, b) InlineIsEqualGUID(a, b)
# define fpl__Win32CopyGuid(src, dst) fplMemoryCopy(src, sizeof(*(src)), dst)
# else
# define fpl__Win32IsEqualGuid(a, b) InlineIsEqualGUID(&a, &b)
# define fpl__Win32CopyGuid(src, dst) fplMemoryCopy(src, sizeof(*(src)), dst)
# endif
const fpl__Win32Guid FPL__WIN32_GUID_ZERO = { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } };
const char *fpl__Win32FormatGuidString(char *buffer, const size_t maxBufferLen, const fpl__Win32Guid *guid) {
(buffer, maxBufferLen, "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
return(buffer);
}
// Little macro to not write 5 lines of code all the time
#define FPL__WIN32_LOAD_LIBRARY_BREAK(mod, target, libName) \
(target) = LoadLibraryA(libName); \
if((target) == fpl_null) { \
FPL__WARNING(mod, "Failed loading library '%s'", (libName)); \
break; \
}
#define FPL__WIN32_GET_FUNCTION_ADDRESS_BREAK(mod, libHandle, libName, target, type, name) \
(target)->name = (type *)(void *)GetProcAddress(libHandle, #name); \
if ((target)->name == fpl_null) { \
FPL__WARNING(mod, "Failed getting procedure address '%s' from library '%s'", #name, libName); \
break; \
}
#if !defined(FPL_NO_RUNTIME_LINKING)
# define FPL__WIN32_LOAD_LIBRARY FPL__WIN32_LOAD_LIBRARY_BREAK
# define FPL__WIN32_GET_FUNCTION_ADDRESS FPL__WIN32_GET_FUNCTION_ADDRESS_BREAK
#else
# define FPL__WIN32_LOAD_LIBRARY(mod, target, libName)
# define FPL__WIN32_GET_FUNCTION_ADDRESS(mod, libHandle, libName, target, type, name) \
(target)->name = name
#endif
#if defined(FPL__ENABLE_INPUT_XINPUT)
// XInput Types
#define FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetState(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
typedef FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetState(fpl__func_input_win32_xinput_XInputGetState);
#define FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetCapabilities(name) DWORD WINAPI name(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
typedef FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetCapabilities(fpl__func_input_win32_xinput_XInputGetCapabilities);
typedef struct fpl__InputWin32XInputApi {
HMODULE xinputLibrary;
fpl__func_input_win32_xinput_XInputGetState *XInputGetState;
fpl__func_input_win32_xinput_XInputGetCapabilities *XInputGetCapabilities;
} fpl__InputWin32XInputApi;
// XInput backend instance owned by fpl__InputContext.
typedef struct fpl__InputBackendXInput {
deviceNames[XUSER_MAX_COUNT];
isConnected[XUSER_MAX_COUNT];
fpl__InputWin32XInputApi api;
lastDeviceSearchTime;
lastUpdateStatesTime;
bool isInitialized;
} fpl__InputBackendXInput;
#endif // FPL__ENABLE_INPUT_XINPUT
#if defined(FPL__ENABLE_INPUT_DINPUT)
// DirectInput 8 — uses <dinput.h> for all types, GUIDs and constants.
// DirectInput8Create is the only function we runtime-link from dinput8.dll, so we
// avoid pulling in dinput8.lib. Per-interface GUIDs (IID_IDirectInput8W, axis GUIDs)
// are defined as private static constants to keep us off dxguid.lib too.
// Maximum DirectInput slots tracked. Mirrors the XInput slot count to keep the
// merged fplGamepadStates array layout sane.
#define FPL__DINPUT_MAX_DEVICES 8
#define FPL__FUNC_INPUT_WIN32_DINPUT_DirectInput8Create(name) HRESULT WINAPI name(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter)
typedef FPL__FUNC_INPUT_WIN32_DINPUT_DirectInput8Create(fpl__func_input_win32_dinput_DirectInput8Create);
typedef struct fpl__Win32DInputApi {
HMODULE dinputLibrary;
fpl__func_input_win32_dinput_DirectInput8Create *DirectInput8Create;
} fpl__Win32DInputApi;
// One DirectInput slot. ffi mirrors the XInput merge contract: the slot owns
// its IDirectInputDevice8W*, last-known fplGamepadState, and a stable name.
typedef struct fpl__InputBackendDInputSlot {
IDirectInputDevice8W *device;
GUID guidInstance;
uint16_t vendorID;
uint16_t productID;
bool isAcquired;
bool isConnected;
deviceName;
fplGamepadState lastState;
// Snapshot built from DIJOYSTATE every poll, fed into the active mapping.
fplGamepadData raw;
// Mapping installed by the user resolver at connect time (only valid when hasMapping is true).
fplGamepadMapping mapping;
// True when the resolver returned a mapping, false to fall back to fplGamepadMappingApplyDefault.
bool hasMapping;
} fpl__InputBackendDInputSlot;
// DirectInput backend instance owned by fpl__InputContext.
// Coexists with XInput; XInput-compatible devices are skipped at enumeration time
// (matched by VID/PID against device names containing "IG_" reported via RawInput).
typedef struct fpl__InputBackendDInput {
fpl__Win32DInputApi api;
IDirectInput8W *iface;
fpl__InputBackendDInputSlot slots[FPL__DINPUT_MAX_DEVICES];
uint32_t xinputVidPids[16];
uint32_t xinputVidPidCount;
lastDeviceSearchTime;
bool isInitialized;
} fpl__InputBackendDInput;
#endif // FPL__ENABLE_INPUT_DINPUT
#if defined(FPL__ENABLE_INPUT_WIN32)
// Win32 keyboard/mouse backend instance owned by fpl__InputContext.
// In windowed mode WM_* events arrive via fpl__InputSystem_HandleNativeEvent and polling uses the user window for ScreenToClient.
// In detached mode (FPL_NO_WINDOW or fplInputSettings.detachFromWindow) the backend creates a hidden HWND_MESSAGE.
typedef struct fpl__InputBackendWin32 {
HWND messageWindow;
ATOM messageWindowClass;
bool isInitialized;
bool detached;
} fpl__InputBackendWin32;
#endif // FPL__ENABLE_INPUT_WIN32
//
// WINAPI functions
//
// GDI32
#define FPL__FUNC_WIN32_ChoosePixelFormat(name) int WINAPI name(HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd)
typedef FPL__FUNC_WIN32_ChoosePixelFormat(fpl__win32_func_ChoosePixelFormat);
#define FPL__FUNC_WIN32_SetPixelFormat(name) BOOL WINAPI name(HDC hdc, int format, CONST PIXELFORMATDESCRIPTOR *ppfd)
typedef FPL__FUNC_WIN32_SetPixelFormat(fpl__win32_func_SetPixelFormat);
#define FPL__FUNC_WIN32_DescribePixelFormat(name) int WINAPI name(HDC hdc, int iPixelFormat, UINT nBytes, LPPIXELFORMATDESCRIPTOR ppfd)
typedef FPL__FUNC_WIN32_DescribePixelFormat(fpl__win32_func_DescribePixelFormat);
#define FPL__FUNC_WIN32_GetDeviceCaps(name) int WINAPI name(HDC hdc, int index)
typedef FPL__FUNC_WIN32_GetDeviceCaps(fpl__win32_func_GetDeviceCaps);
#define FPL__FUNC_WIN32_StretchDIBits(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)
typedef FPL__FUNC_WIN32_StretchDIBits(fpl__win32_func_StretchDIBits);
#define FPL__FUNC_WIN32_DeleteObject(name) BOOL WINAPI name( _In_ HGDIOBJ ho)
typedef FPL__FUNC_WIN32_DeleteObject(fpl__win32_func_DeleteObject);
#define FPL__FUNC_WIN32_SwapBuffers(name) BOOL WINAPI name(HDC)
typedef FPL__FUNC_WIN32_SwapBuffers(fpl__win32_func_SwapBuffers);
#define FPL__FUNC_WIN32_CreateDIBSection(name) HBITMAP WINAPI name(HDC hdc, CONST BITMAPINFO *pbmi, UINT usage, VOID **ppvBits, HANDLE hSection, DWORD offset)
typedef FPL__FUNC_WIN32_CreateDIBSection(fpl__win32_func_CreateDIBSection);
#define FPL__FUNC_WIN32_CreateBitmap(name) HBITMAP WINAPI name(int nWidth, int nHeight, UINT nPlanes, UINT nBitCount, CONST VOID *lpBits)
typedef FPL__FUNC_WIN32_CreateBitmap(fpl__win32_func_CreateBitmap);
#define FPL__FUNC_WIN32_CreateSolidBrush(name) HBRUSH WINAPI name(COLORREF color)
typedef FPL__FUNC_WIN32_CreateSolidBrush(fpl__win32_func_CreateSolidBrush);
// ShellAPI
#define FPL__FUNC_WIN32_SHGetFolderPathW(name) HRESULT WINAPI name(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath)
typedef FPL__FUNC_WIN32_SHGetFolderPathW(fpl__win32_func_SHGetFolderPathW);
#define FPL__FUNC_WIN32_DragQueryFileW(name) UINT WINAPI name(HDROP hDrop, UINT iFile, LPWSTR lpszFile, UINT cch)
typedef FPL__FUNC_WIN32_DragQueryFileW(fpl__win32_func_DragQueryFileW);
#define FPL__FUNC_WIN32_DragAcceptFiles(name) void WINAPI name(HWND hWnd, BOOL fAccept)
typedef FPL__FUNC_WIN32_DragAcceptFiles(fpl__win32_func_DragAcceptFiles);
// User32
#define FPL__FUNC_WIN32_RegisterClassExW(name) ATOM WINAPI name(CONST WNDCLASSEXW *)
typedef FPL__FUNC_WIN32_RegisterClassExW(fpl__win32_func_RegisterClassExW);
#define FPL__FUNC_WIN32_UnregisterClassW(name) BOOL WINAPI name(LPCWSTR lpClassName, HINSTANCE hInstance)
typedef FPL__FUNC_WIN32_UnregisterClassW(fpl__win32_func_UnregisterClassW);
#define FPL__FUNC_WIN32_ShowWindow(name) BOOL WINAPI name(HWND hWnd, int nCmdShow)
typedef FPL__FUNC_WIN32_ShowWindow(fpl__win32_func_ShowWindow);
#define FPL__FUNC_WIN32_DestroyWindow(name) BOOL WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_DestroyWindow(fpl__win32_func_DestroyWindow);
#define FPL__FUNC_WIN32_UpdateWindow(name) BOOL WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_UpdateWindow(fpl__win32_func_UpdateWindow);
#define FPL__FUNC_WIN32_TranslateMessage(name) BOOL WINAPI name(CONST MSG *lpMsg)
typedef FPL__FUNC_WIN32_TranslateMessage(fpl__win32_func_TranslateMessage);
#define FPL__FUNC_WIN32_DispatchMessageW(name) LRESULT WINAPI name(CONST MSG *lpMsg)
typedef FPL__FUNC_WIN32_DispatchMessageW(fpl__win32_func_DispatchMessageW);
#define FPL__FUNC_WIN32_PeekMessageW(name) BOOL WINAPI name(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
typedef FPL__FUNC_WIN32_PeekMessageW(fpl__win32_func_PeekMessageW);
#define FPL__FUNC_WIN32_DefWindowProcW(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
typedef FPL__FUNC_WIN32_DefWindowProcW(fpl__win32_func_DefWindowProcW);
#define FPL__FUNC_WIN32_CreateWindowExW(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)
typedef FPL__FUNC_WIN32_CreateWindowExW(fpl__win32_func_CreateWindowExW);
#define FPL__FUNC_WIN32_SetWindowPos(name) BOOL WINAPI name(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags)
typedef FPL__FUNC_WIN32_SetWindowPos(fpl__win32_func_SetWindowPos);
#define FPL__FUNC_WIN32_GetWindowPlacement(name) BOOL WINAPI name(HWND hWnd, WINDOWPLACEMENT *lpwndpl)
typedef FPL__FUNC_WIN32_GetWindowPlacement(fpl__win32_func_GetWindowPlacement);
#define FPL__FUNC_WIN32_SetWindowPlacement(name) BOOL WINAPI name(HWND hWnd, CONST WINDOWPLACEMENT *lpwndpl)
typedef FPL__FUNC_WIN32_SetWindowPlacement(fpl__win32_func_SetWindowPlacement);
#define FPL__FUNC_WIN32_GetClientRect(name) BOOL WINAPI name(HWND hWnd, LPRECT lpRect)
typedef FPL__FUNC_WIN32_GetClientRect(fpl__win32_func_GetClientRect);
#define FPL__FUNC_WIN32_GetWindowRect(name) BOOL WINAPI name(HWND hWnd, LPRECT lpRect)
typedef FPL__FUNC_WIN32_GetWindowRect(fpl__win32_func_GetWindowRect);
#define FPL__FUNC_WIN32_AdjustWindowRect(name) BOOL WINAPI name(LPRECT lpRect, DWORD dwStyle, BOOL bMenu)
typedef FPL__FUNC_WIN32_AdjustWindowRect(fpl__win32_func_AdjustWindowRect);
#define FPL__FUNC_WIN32_ClientToScreen(name) BOOL WINAPI name(HWND hWnd, LPPOINT lpPoint)
typedef FPL__FUNC_WIN32_ClientToScreen(fpl__win32_func_ClientToScreen);
#define FPL__FUNC_WIN32_GetAsyncKeyState(name) SHORT WINAPI name(int vKey)
typedef FPL__FUNC_WIN32_GetAsyncKeyState(fpl__win32_func_GetAsyncKeyState);
#define FPL__FUNC_WIN32_GetKeyState(name) SHORT WINAPI name(int vKey)
typedef FPL__FUNC_WIN32_GetKeyState(fpl__win32_func_GetKeyState);
#define FPL__FUNC_WIN32_MapVirtualKeyW(name) UINT WINAPI name(UINT uCode, UINT uMapType)
typedef FPL__FUNC_WIN32_MapVirtualKeyW(fpl__win32_func_MapVirtualKeyW);
#define FPL__FUNC_WIN32_SetCursor(name) HCURSOR WINAPI name(HCURSOR hCursor)
typedef FPL__FUNC_WIN32_SetCursor(fpl__win32_func_SetCursor);
#define FPL__FUNC_WIN32_GetCursor(name) HCURSOR WINAPI name(VOID)
typedef FPL__FUNC_WIN32_GetCursor(fpl__win32_func_GetCursor);
#define FPL__FUNC_WIN32_GetCursorPos(name) BOOL WINAPI name(LPPOINT lpPoint)
typedef FPL__FUNC_WIN32_GetCursorPos(fpl__win32_func_GetCursorPos);
#define FPL__FUNC_WIN32_WindowFromPoint(name) HWND WINAPI name(POINT Point)
typedef FPL__FUNC_WIN32_WindowFromPoint(fpl__win32_func_WindowFromPoint);
#define FPL__FUNC_WIN32_PtInRect(name) BOOL WINAPI name(CONST RECT *lprc, POINT pt)
typedef FPL__FUNC_WIN32_PtInRect(fpl__win32_func_PtInRect);
#define FPL__FUNC_WIN32_LoadCursorA(name) HCURSOR WINAPI name(HINSTANCE hInstance, LPCSTR lpCursorName)
typedef FPL__FUNC_WIN32_LoadCursorA(fpl__win32_func_LoadCursorA);
#define FPL__FUNC_WIN32_LoadCursorW(name) HCURSOR WINAPI name(HINSTANCE hInstance, LPCWSTR lpCursorName)
typedef FPL__FUNC_WIN32_LoadCursorW(fpl__win32_func_LoadCursorW);
#define FPL__FUNC_WIN32_LoadIconA(name) HICON WINAPI name(HINSTANCE hInstance, LPCSTR lpIconName)
typedef FPL__FUNC_WIN32_LoadIconA(fpl__win32_func_LoadIconA);
#define FPL__FUNC_WIN32_LoadIconW(name) HICON WINAPI name(HINSTANCE hInstance, LPCWSTR lpIconName)
typedef FPL__FUNC_WIN32_LoadIconW(fpl__win32_func_LoadIconW);
#define FPL__FUNC_WIN32_SetWindowTextW(name) BOOL WINAPI name(HWND hWnd, LPCWSTR lpString)
typedef FPL__FUNC_WIN32_SetWindowTextW(fpl__win32_func_SetWindowTextW);
#define FPL__FUNC_WIN32_GetWindowTextW(name) int WINAPI name(HWND hWnd, LPWSTR lpString, int nMaxCount)
typedef FPL__FUNC_WIN32_GetWindowTextW(fpl__win32_func_GetWindowTextW);
#define FPL__FUNC_WIN32_SetWindowLongW(name) LONG WINAPI name(HWND hWnd, int nIndex, LONG dwNewLong)
typedef FPL__FUNC_WIN32_SetWindowLongW(fpl__win32_func_SetWindowLongW);
#define FPL__FUNC_WIN32_GetWindowLongW(name) LONG WINAPI name(HWND hWnd, int nIndex)
typedef FPL__FUNC_WIN32_GetWindowLongW(fpl__win32_func_GetWindowLongW);
#if defined(FPL_ARCH_X64)
#define FPL__FUNC_WIN32_SetWindowLongPtrW(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
typedef FPL__FUNC_WIN32_SetWindowLongPtrW(fpl__win32_func_SetWindowLongPtrW);
#define FPL__FUNC_WIN32_GetWindowLongPtrW(name) LONG_PTR WINAPI name(HWND hWnd, int nIndex)
typedef FPL__FUNC_WIN32_GetWindowLongPtrW(fpl__win32_func_GetWindowLongPtrW);
#endif
#define FPL__FUNC_WIN32_ReleaseDC(name) int WINAPI name(HWND hWnd, HDC hDC)
typedef FPL__FUNC_WIN32_ReleaseDC(fpl__win32_func_ReleaseDC);
#define FPL__FUNC_WIN32_GetDC(name) HDC WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_GetDC(fpl__win32_func_GetDC);
#define FPL__FUNC_WIN32_ChangeDisplaySettingsW(name) LONG WINAPI name(DEVMODEW* lpDevMode, DWORD dwFlags)
typedef FPL__FUNC_WIN32_ChangeDisplaySettingsW(fpl__win32_func_ChangeDisplaySettingsW);
#define FPL__FUNC_WIN32_EnumDisplaySettingsW(name) BOOL WINAPI name(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode)
typedef FPL__FUNC_WIN32_EnumDisplaySettingsW(fpl__win32_func_EnumDisplaySettingsW);
#define FPL__FUNC_WIN32_OpenClipboard(name) BOOL WINAPI name(HWND hWndNewOwner)
typedef FPL__FUNC_WIN32_OpenClipboard(fpl__win32_func_OpenClipboard);
#define FPL__FUNC_WIN32_CloseClipboard(name) BOOL WINAPI name(VOID)
typedef FPL__FUNC_WIN32_CloseClipboard(fpl__win32_func_CloseClipboard);
#define FPL__FUNC_WIN32_EmptyClipboard(name) BOOL WINAPI name(VOID)
typedef FPL__FUNC_WIN32_EmptyClipboard(fpl__win32_func_EmptyClipboard);
#define FPL__FUNC_WIN32_IsClipboardFormatAvailable(name) BOOL WINAPI name(UINT format)
typedef FPL__FUNC_WIN32_IsClipboardFormatAvailable(fpl__win32_func_IsClipboardFormatAvailable);
#define FPL__FUNC_WIN32_SetClipboardData(name) HANDLE WINAPI name(UINT uFormat, HANDLE hMem)
typedef FPL__FUNC_WIN32_SetClipboardData(fpl__win32_func_SetClipboardData);
#define FPL__FUNC_WIN32_GetClipboardData(name) HANDLE WINAPI name(UINT uFormat)
typedef FPL__FUNC_WIN32_GetClipboardData(fpl__win32_func_GetClipboardData);
#define FPL__FUNC_WIN32_GetDesktopWindow(name) HWND WINAPI name(VOID)
typedef FPL__FUNC_WIN32_GetDesktopWindow(fpl__win32_func_GetDesktopWindow);
#define FPL__FUNC_WIN32_GetForegroundWindow(name) HWND WINAPI name(VOID)
typedef FPL__FUNC_WIN32_GetForegroundWindow(fpl__win32_func_GetForegroundWindow);
#define FPL__FUNC_WIN32_IsZoomed(name) BOOL WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_IsZoomed(fpl__win32_func_IsZoomed);
#define FPL__FUNC_WIN32_IsIconic(name) BOOL WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_IsIconic(fpl__win32_func_IsIconic);
#define FPL__FUNC_WIN32_SendMessageW(name) LRESULT WINAPI name(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
typedef FPL__FUNC_WIN32_SendMessageW(fpl__win32_func_SendMessageW);
#define FPL__FUNC_WIN32_GetMonitorInfoW(name) BOOL WINAPI name(HMONITOR hMonitor, LPMONITORINFO lpmi)
typedef FPL__FUNC_WIN32_GetMonitorInfoW(fpl__win32_func_GetMonitorInfoW);
#define FPL__FUNC_WIN32_EnumDisplayMonitors(name) BOOL WINAPI name(HDC hdc, LPCRECT lprcClip, MONITORENUMPROC lpfnEnum,LPARAM dwData)
typedef FPL__FUNC_WIN32_EnumDisplayMonitors(fpl__win32_func_EnumDisplayMonitors);
#define FPL__FUNC_WIN32_MonitorFromRect(name) HMONITOR WINAPI name(LPCRECT lprc, DWORD dwFlags)
typedef FPL__FUNC_WIN32_MonitorFromRect(fpl__win32_func_MonitorFromRect);
#define FPL__FUNC_WIN32_MonitorFromPoint(name) HMONITOR WINAPI name(POINT pt, DWORD dwFlags)
typedef FPL__FUNC_WIN32_MonitorFromPoint(fpl__win32_func_MonitorFromPoint);
#define FPL__FUNC_WIN32_MonitorFromWindow(name) HMONITOR WINAPI name(HWND hwnd, DWORD dwFlags)
typedef FPL__FUNC_WIN32_MonitorFromWindow(fpl__win32_func_MonitorFromWindow);
#define FPL__FUNC_WIN32_RegisterRawInputDevices(name) BOOL WINAPI name(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize)
typedef FPL__FUNC_WIN32_RegisterRawInputDevices(fpl__win32_func_RegisterRawInputDevices);
#define FPL__FUNC_WIN32_GetRawInputDeviceList(name) UINT WINAPI name(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize)
typedef FPL__FUNC_WIN32_GetRawInputDeviceList(fpl__win32_func_GetRawInputDeviceList);
#define FPL__FUNC_WIN32_GetRawInputDeviceInfoW(name) UINT WINAPI name(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
typedef FPL__FUNC_WIN32_GetRawInputDeviceInfoW(fpl__win32_func_GetRawInputDeviceInfoW);
#define FPL__FUNC_WIN32_ClipCursor(name) BOOL WINAPI name(CONST RECT *lpRect)
typedef FPL__FUNC_WIN32_ClipCursor(fpl__win32_func_ClipCursor);
#define FPL__FUNC_WIN32_PostQuitMessage(name) VOID WINAPI name(int nExitCode)
typedef FPL__FUNC_WIN32_PostQuitMessage(fpl__win32_func_PostQuitMessage);
#define FPL__FUNC_WIN32_CreateIconIndirect(name) HICON WINAPI name(PICONINFO piconinfo)
typedef FPL__FUNC_WIN32_CreateIconIndirect(fpl__win32_func_CreateIconIndirect);
#define FPL__FUNC_WIN32_GetKeyboardLayout(name) HKL WINAPI name(DWORD idThread)
typedef FPL__FUNC_WIN32_GetKeyboardLayout(fpl__win32_func_GetKeyboardLayout);
#define FPL__FUNC_WIN32_SetCapture(name) HWND WINAPI name(HWND hWnd)
typedef FPL__FUNC_WIN32_SetCapture(fpl__win32_func_SetCapture);
#define FPL__FUNC_WIN32_ReleaseCapture(name) BOOL WINAPI name(VOID)
typedef FPL__FUNC_WIN32_ReleaseCapture(fpl__win32_func_ReleaseCapture);
#define FPL__FUNC_WIN32_ScreenToClient(name) BOOL WINAPI name(HWND hWnd, LPPOINT lpPoint)
typedef FPL__FUNC_WIN32_ScreenToClient(fpl__win32_func_ScreenToClient);
#define FPL__FUNC_WIN32_BeginPaint(name) HDC WINAPI name(_In_ HWND hWnd, _Out_ LPPAINTSTRUCT lpPaint)
typedef FPL__FUNC_WIN32_BeginPaint(fpl__win32_func_BeginPaint);
#define FPL__FUNC_WIN32_EndPaint(name) BOOL WINAPI name(_In_ HWND hWnd, _In_ CONST PAINTSTRUCT *lpPaint)
typedef FPL__FUNC_WIN32_EndPaint(fpl__win32_func_EndPaint);
#define FPL__FUNC_WIN32_SetForegroundWindow(name) BOOL WINAPI name(_In_ HWND hWnd)
typedef FPL__FUNC_WIN32_SetForegroundWindow(fpl__win32_func_SetForegroundWindow);
#define FPL__FUNC_WIN32_SetFocus(name) HWND WINAPI name(_In_opt_ HWND hWnd)
typedef FPL__FUNC_WIN32_SetFocus(fpl__win32_func_SetFocus);
#define FPL__FUNC_WIN32_SetTimer(name) UINT_PTR WINAPI name(_In_opt_ HWND hWnd, _In_ UINT_PTR nIDEvent, _In_ UINT uElapse, _In_opt_ TIMERPROC lpTimerFunc)
typedef FPL__FUNC_WIN32_SetTimer(fpl__win32_func_SetTimer);
#define FPL__FUNC_WIN32_GetSysColorBrush(name) HBRUSH WINAPI name(_In_ int nIndex)
typedef FPL__FUNC_WIN32_GetSysColorBrush(fpl__win32_func_GetSysColorBrush);
#define FPL__FUNC_WIN32_GetSysColorBrush(name) HBRUSH WINAPI name(_In_ int nIndex)
typedef FPL__FUNC_WIN32_GetSysColorBrush(fpl__win32_func_GetSysColorBrush);
// OLE32
#define FPL__FUNC_WIN32_CoInitializeEx(name) HRESULT WINAPI name(LPVOID pvReserved, DWORD dwCoInit)
typedef FPL__FUNC_WIN32_CoInitializeEx(fpl__win32_func_CoInitializeEx);
#define FPL__FUNC_WIN32_CoUninitialize(name) void WINAPI name(void)
typedef FPL__FUNC_WIN32_CoUninitialize(fpl__win32_func_CoUninitialize);
#define FPL__FUNC_WIN32_CoCreateInstance(name) HRESULT WINAPI name(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv)
typedef FPL__FUNC_WIN32_CoCreateInstance(fpl__win32_func_CoCreateInstance);
#define FPL__FUNC_WIN32_CoTaskMemFree(name) void WINAPI name(LPVOID pv)
typedef FPL__FUNC_WIN32_CoTaskMemFree(fpl__win32_func_CoTaskMemFree);
#define FPL__FUNC_WIN32_PropVariantClear(name) HRESULT WINAPI name(PROPVARIANT *pvar)
typedef FPL__FUNC_WIN32_PropVariantClear(fpl__win32_func_PropVariantClear);
typedef struct fpl__Win32GdiApi {
HMODULE gdiLibrary;
fpl__win32_func_ChoosePixelFormat *ChoosePixelFormat;
fpl__win32_func_SetPixelFormat *SetPixelFormat;
fpl__win32_func_DescribePixelFormat *DescribePixelFormat;
fpl__win32_func_GetDeviceCaps *GetDeviceCaps;
fpl__win32_func_StretchDIBits *StretchDIBits;
fpl__win32_func_DeleteObject *DeleteObject;
fpl__win32_func_SwapBuffers *SwapBuffers;
fpl__win32_func_CreateDIBSection *CreateDIBSection;
fpl__win32_func_CreateBitmap *CreateBitmap;
fpl__win32_func_CreateSolidBrush *CreateSolidBrush;
} fpl__Win32GdiApi;
typedef struct fpl__Win32ShellApi {
HMODULE shellLibrary;
fpl__win32_func_SHGetFolderPathW *SHGetFolderPathW;
fpl__win32_func_DragQueryFileW *DragQueryFileW;
fpl__win32_func_DragAcceptFiles *DragAcceptFiles;
} fpl__Win32ShellApi;
typedef struct fpl__Win32UserApi {
HMODULE userLibrary;
fpl__win32_func_RegisterClassExW *RegisterClassExW;
fpl__win32_func_UnregisterClassW *UnregisterClassW;
fpl__win32_func_ShowWindow *ShowWindow;
fpl__win32_func_DestroyWindow *DestroyWindow;
fpl__win32_func_UpdateWindow *UpdateWindow;
fpl__win32_func_TranslateMessage *TranslateMessage;
fpl__win32_func_DispatchMessageW *DispatchMessageW;
fpl__win32_func_PeekMessageW *PeekMessageW;
fpl__win32_func_DefWindowProcW *DefWindowProcW;
fpl__win32_func_CreateWindowExW *CreateWindowExW;
fpl__win32_func_SetWindowPos *SetWindowPos;
fpl__win32_func_GetWindowPlacement *GetWindowPlacement;
fpl__win32_func_SetWindowPlacement *SetWindowPlacement;
fpl__win32_func_GetClientRect *GetClientRect;
fpl__win32_func_GetWindowRect *GetWindowRect;
fpl__win32_func_AdjustWindowRect *AdjustWindowRect;
fpl__win32_func_GetAsyncKeyState *GetAsyncKeyState;
fpl__win32_func_MapVirtualKeyW *MapVirtualKeyW;
fpl__win32_func_SetCursor *SetCursor;
fpl__win32_func_GetCursor *GetCursor;
fpl__win32_func_LoadCursorA *LoadCursorA;
fpl__win32_func_LoadCursorW *LoadCursorW;
fpl__win32_func_LoadIconA *LoadIconA;
fpl__win32_func_LoadIconW *LoadIconW;
fpl__win32_func_SetWindowTextW *SetWindowTextW;
fpl__win32_func_GetWindowTextW *GetWindowTextW;
fpl__win32_func_SetWindowLongW *SetWindowLongW;
fpl__win32_func_GetWindowLongW *GetWindowLongW;
#if defined(FPL_ARCH_X64)
fpl__win32_func_SetWindowLongPtrW *SetWindowLongPtrW;
fpl__win32_func_GetWindowLongPtrW *GetWindowLongPtrW;
#endif
fpl__win32_func_ReleaseDC *ReleaseDC;
fpl__win32_func_GetDC *GetDC;
fpl__win32_func_ChangeDisplaySettingsW *ChangeDisplaySettingsW;
fpl__win32_func_EnumDisplaySettingsW *EnumDisplaySettingsW;
fpl__win32_func_OpenClipboard *OpenClipboard;
fpl__win32_func_CloseClipboard *CloseClipboard;
fpl__win32_func_EmptyClipboard *EmptyClipboard;
fpl__win32_func_IsClipboardFormatAvailable *IsClipboardFormatAvailable;
fpl__win32_func_SetClipboardData *SetClipboardData;
fpl__win32_func_GetClipboardData *GetClipboardData;
fpl__win32_func_GetDesktopWindow *GetDesktopWindow;
fpl__win32_func_GetForegroundWindow *GetForegroundWindow;
fpl__win32_func_IsZoomed *IsZoomed;
fpl__win32_func_IsIconic *IsIconic;
fpl__win32_func_SendMessageW *SendMessageW;
fpl__win32_func_GetMonitorInfoW *GetMonitorInfoW;
fpl__win32_func_EnumDisplayMonitors *EnumDisplayMonitors;
fpl__win32_func_MonitorFromRect *MonitorFromRect;
fpl__win32_func_MonitorFromPoint *MonitorFromPoint;
fpl__win32_func_MonitorFromWindow *MonitorFromWindow;
fpl__win32_func_GetCursorPos *GetCursorPos;
fpl__win32_func_WindowFromPoint *WindowFromPoint;
fpl__win32_func_ClientToScreen *ClientToScreen;
fpl__win32_func_PtInRect *PtInRect;
fpl__win32_func_RegisterRawInputDevices *RegisterRawInputDevices;
fpl__win32_func_GetRawInputDeviceList *GetRawInputDeviceList;
fpl__win32_func_GetRawInputDeviceInfoW *GetRawInputDeviceInfoW;
fpl__win32_func_ClipCursor *ClipCursor;
fpl__win32_func_PostQuitMessage *PostQuitMessage;
fpl__win32_func_CreateIconIndirect *CreateIconIndirect;
fpl__win32_func_GetKeyboardLayout *GetKeyboardLayout;
fpl__win32_func_GetKeyState *GetKeyState;
fpl__win32_func_SetCapture *SetCapture;
fpl__win32_func_ReleaseCapture *ReleaseCapture;
fpl__win32_func_ScreenToClient *ScreenToClient;
fpl__win32_func_BeginPaint *BeginPaint;
fpl__win32_func_EndPaint *EndPaint;
fpl__win32_func_SetForegroundWindow *SetForegroundWindow;
fpl__win32_func_SetFocus *SetFocus;
fpl__win32_func_SetTimer *SetTimer;
fpl__win32_func_GetSysColorBrush *GetSysColorBrush;
} fpl__Win32UserApi;
typedef struct fpl__Win32OleApi {
HMODULE oleLibrary;
fpl__win32_func_CoInitializeEx *CoInitializeEx;
fpl__win32_func_CoUninitialize *CoUninitialize;
fpl__win32_func_CoCreateInstance *CoCreateInstance;
fpl__win32_func_CoTaskMemFree *CoTaskMemFree;
fpl__win32_func_PropVariantClear *PropVariantClear;
} fpl__Win32OleApi;
typedef struct fpl__Win32Api {
fpl__Win32GdiApi gdi;
fpl__Win32ShellApi shell;
fpl__Win32UserApi user;
fpl__Win32OleApi ole;
isValid;
} fpl__Win32Api;
void fpl__Win32UnloadApi(fpl__Win32Api *wapi) {
(wapi != );
if (wapi->ole.oleLibrary != ) {
FreeLibrary(wapi->ole.oleLibrary);
}
(&wapi->ole);
if (wapi->gdi.gdiLibrary != ) {
FreeLibrary(wapi->gdi.gdiLibrary);
}
(&wapi->gdi);
if (wapi->user.userLibrary != ) {
FreeLibrary(wapi->user.userLibrary);
}
(&wapi->user);
if (wapi->shell.shellLibrary != ) {
FreeLibrary(wapi->shell.shellLibrary);
}
(&wapi->shell);
wapi->isValid = false;
}
bool fpl__Win32LoadApi(fpl__Win32Api *wapi) {
(wapi != );
bool result = false;
(wapi);
do {
// Shell32
const char *shellLibraryName = "shell32.dll";
HMODULE shellLibrary = ;
FPL__WIN32_LOAD_LIBRARY(FPL__MODULE_WIN32, shellLibrary, shellLibraryName);
wapi->shell.shellLibrary = shellLibrary;
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, shellLibrary, shellLibraryName, &wapi->shell, fpl__win32_func_SHGetFolderPathW, SHGetFolderPathW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, shellLibrary, shellLibraryName, &wapi->shell, fpl__win32_func_DragQueryFileW, DragQueryFileW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, shellLibrary, shellLibraryName, &wapi->shell, fpl__win32_func_DragAcceptFiles, DragAcceptFiles);
// User32
const char *userLibraryName = "user32.dll";
HMODULE userLibrary = ;
FPL__WIN32_LOAD_LIBRARY(FPL__MODULE_WIN32, userLibrary, userLibraryName);
wapi->user.userLibrary = userLibrary;
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_RegisterClassExW, RegisterClassExW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_UnregisterClassW, UnregisterClassW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ShowWindow, ShowWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_DestroyWindow, DestroyWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_UpdateWindow, UpdateWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_TranslateMessage, TranslateMessage);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_DispatchMessageW, DispatchMessageW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_PeekMessageW, PeekMessageW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_DefWindowProcW, DefWindowProcW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_CreateWindowExW, CreateWindowExW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetWindowPos, SetWindowPos);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetWindowPlacement, GetWindowPlacement);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetWindowPlacement, SetWindowPlacement);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetClientRect, GetClientRect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetWindowRect, GetWindowRect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_AdjustWindowRect, AdjustWindowRect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetAsyncKeyState, GetAsyncKeyState);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_MapVirtualKeyW, MapVirtualKeyW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetCursor, SetCursor);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetCursor, GetCursor);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_LoadCursorA, LoadCursorA);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_LoadCursorW, LoadCursorW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetCursorPos, GetCursorPos);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_WindowFromPoint, WindowFromPoint);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_LoadIconA, LoadIconA);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_LoadIconW, LoadIconW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetWindowTextW, SetWindowTextW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetWindowLongW, SetWindowLongW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetWindowLongW, GetWindowLongW);
# if defined(FPL_ARCH_X64)
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetWindowLongPtrW, SetWindowLongPtrW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetWindowLongPtrW, GetWindowLongPtrW);
# endif
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ReleaseDC, ReleaseDC);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetDC, GetDC);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ChangeDisplaySettingsW, ChangeDisplaySettingsW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_EnumDisplaySettingsW, EnumDisplaySettingsW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_IsClipboardFormatAvailable, IsClipboardFormatAvailable);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_OpenClipboard, OpenClipboard);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_CloseClipboard, CloseClipboard);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_EmptyClipboard, EmptyClipboard);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetClipboardData, SetClipboardData);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetClipboardData, GetClipboardData);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetDesktopWindow, GetDesktopWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetForegroundWindow, GetForegroundWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_IsZoomed, IsZoomed);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_IsIconic, IsIconic);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SendMessageW, SendMessageW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetMonitorInfoW, GetMonitorInfoW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_EnumDisplayMonitors, EnumDisplayMonitors);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_MonitorFromRect, MonitorFromRect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_MonitorFromPoint, MonitorFromPoint);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_MonitorFromWindow, MonitorFromWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ClientToScreen, ClientToScreen);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_PtInRect, PtInRect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_RegisterRawInputDevices, RegisterRawInputDevices);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetRawInputDeviceList, GetRawInputDeviceList);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetRawInputDeviceInfoW, GetRawInputDeviceInfoW);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ClipCursor, ClipCursor);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_PostQuitMessage, PostQuitMessage);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_CreateIconIndirect, CreateIconIndirect);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetKeyboardLayout, GetKeyboardLayout);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetKeyState, GetKeyState);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetCapture, SetCapture);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ReleaseCapture, ReleaseCapture);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_ScreenToClient, ScreenToClient);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_BeginPaint, BeginPaint);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_EndPaint, EndPaint);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetForegroundWindow, SetForegroundWindow);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetFocus, SetFocus);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_SetTimer, SetTimer);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, userLibrary, userLibraryName, &wapi->user, fpl__win32_func_GetSysColorBrush, GetSysColorBrush);
// GDI32
const char *gdiLibraryName = "gdi32.dll";
HMODULE gdiLibrary = ;
FPL__WIN32_LOAD_LIBRARY(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName);
wapi->gdi.gdiLibrary = gdiLibrary;
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_ChoosePixelFormat, ChoosePixelFormat);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_SetPixelFormat, SetPixelFormat);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_DescribePixelFormat, DescribePixelFormat);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_StretchDIBits, StretchDIBits);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_DeleteObject, DeleteObject);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_SwapBuffers, SwapBuffers);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_GetDeviceCaps, GetDeviceCaps);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_CreateDIBSection, CreateDIBSection);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_CreateBitmap, CreateBitmap);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, gdiLibrary, gdiLibraryName, &wapi->gdi, fpl__win32_func_CreateSolidBrush, CreateSolidBrush);
// OLE32
const char *oleLibraryName = "ole32.dll";
HMODULE oleLibrary = ;
FPL__WIN32_LOAD_LIBRARY(FPL__MODULE_WIN32, oleLibrary, oleLibraryName);
wapi->ole.oleLibrary = oleLibrary;
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, oleLibrary, oleLibraryName, &wapi->ole, fpl__win32_func_CoInitializeEx, CoInitializeEx);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, oleLibrary, oleLibraryName, &wapi->ole, fpl__win32_func_CoUninitialize, CoUninitialize);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, oleLibrary, oleLibraryName, &wapi->ole, fpl__win32_func_CoCreateInstance, CoCreateInstance);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, oleLibrary, oleLibraryName, &wapi->ole, fpl__win32_func_CoTaskMemFree, CoTaskMemFree);
FPL__WIN32_GET_FUNCTION_ADDRESS(FPL__MODULE_WIN32, oleLibrary, oleLibraryName, &wapi->ole, fpl__win32_func_PropVariantClear, PropVariantClear);
result = true;
} while (0);
if (!result) {
fpl__Win32UnloadApi(wapi);
}
wapi->isValid = result;
return(result);
}
// Win32 unicode dependend stuff
#define FPL__WIN32_CLASSNAME L"FPLWindowClassW"
#define FPL__WIN32_UNNAMED_WINDOW L"Unnamed FPL Unicode Window"
#define FPL__WIN32_UNNAMED_CONSOLE L"Unnamed FPL Unicode Console"
#if defined(FPL_ARCH_X64)
# define fpl__win32_SetWindowLongPtr fpl__global__AppState->win32.winApi.user.SetWindowLongPtrW
#else
# define fpl__win32_SetWindowLongPtr fpl__global__AppState->win32.winApi.user.SetWindowLongW
#endif
#define fpl__win32_SetWindowLong fpl__global__AppState->win32.winApi.user.SetWindowLongW
#define fpl__win32_GetWindowLong fpl__global__AppState->win32.winApi.user.GetWindowLongW
#if defined(UNICODE)
# define fpl__win32_LoadIcon fpl__global__AppState->win32.winApi.user.LoadIconW
# define fpl__win32_LoadCursor fpl__global__AppState->win32.winApi.user.LoadCursorW
#else
# define fpl__win32_LoadIcon fpl__global__AppState->win32.winApi.user.LoadIconA
# define fpl__win32_LoadCursor fpl__global__AppState->win32.winApi.user.LoadCursorA
#endif
typedef struct fpl__Win32InitState {
HINSTANCE appInstance;
LARGE_INTEGER qpf;
} fpl__Win32InitState;
typedef struct fpl__Win32AppState {
fpl__Win32Api winApi;
} fpl__Win32AppState;
#if defined(FPL__ENABLE_WINDOW)
typedef struct fpl__Win32LastWindowInfo {
WINDOWPLACEMENT placement;
DWORD style;
DWORD exStyle;
isMaximized;
isMinimized;
wasResolutionChanged;
} fpl__Win32LastWindowInfo;
typedef struct fpl__Win32WindowState {
wchar_t windowClass[256];
fpl__Win32LastWindowInfo lastFullscreenInfo;
void *mainFiber;
void *messageFiber;
HWND windowHandle;
HDC deviceContext;
HBRUSH backgroundBrush;
HCURSOR defaultCursor;
int pixelFormat;
isCursorActive;
isFrameInteraction;
} fpl__Win32WindowState;
#endif // FPL__ENABLE_WINDOW
#endif // FPL_PLATFORM_WINDOWS
// ############################################################################
//
// > TYPES_POSIX
//
// ############################################################################
#if defined(FPL_SUBPLATFORM_POSIX)
# include <sys/types.h> // data types
# include <sys/mman.h> // mmap, munmap
# include <sys/stat.h> // mkdir
# include <sys/errno.h> // errno
# include <sys/time.h> // gettimeofday
# include <sys/utsname.h> // uname
# include <signal.h> // pthread_kill
# include <time.h> // clock_gettime, nanosleep
# include <dlfcn.h> // dlopen, dlclose
# include <fcntl.h> // open
# include <unistd.h> // read, write, close, access, rmdir, getpid, sysconf, geteuid
# include <ctype.h> // isspace
# include <pwd.h> // getpwuid
# include <dirent.h> // DIR, dirent
// Map st_atime/st_mtime/st_ctime to the POSIX.1-2008 nanosecond fields (st_atim.tv_sec, ...)
// when available. On older POSIX or platforms without timespec stat fields, fall back to the
// legacy time_t members directly (no remap needed).
// Android has its own definitions, so we skip the remap there.
#if !defined(FPL_PLATFORM_ANDROID)
# if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L) || \
(defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || \
defined(__USE_XOPEN2K8) || defined(_STATBUF_ST_NSEC) || \
defined(FPL_PLATFORM_LINUX)
# define st_atime st_atim.tv_sec
# define st_mtime st_mtim.tv_sec
# define st_ctime st_ctim.tv_sec
# endif
#endif
#if defined(FPL_PLATFORM_LINUX)
# define fpl__lseek64 lseek64
# define fpl__off64_t off64_t
#else
# define fpl__lseek64 lseek
# define fpl__off64_t off_t
#endif
// Little macros for loading a library and getting proc address for POSIX
#define FPL__POSIX_LOAD_LIBRARY_BREAK(mod, target, libName) \
(target) = dlopen(libName, FPL__POSIX_DL_LOADTYPE); \
if((target) == fpl_null) { \
FPL__WARNING(mod, "Failed loading library '%s'", (libName)); \
break; \
}
#define FPL__POSIX_GET_FUNCTION_ADDRESS_BREAK(mod, libHandle, libName, target, type, name) \
(target)->name = (type *)dlsym(libHandle, #name); \
if ((target)->name == fpl_null) { \
FPL__WARNING(mod, "Failed getting procedure address '%s' from library '%s'", #name, libName); \
break; \
}
#if !defined(FPL_NO_RUNTIME_LINKING)
# define FPL__POSIX_LOAD_LIBRARY FPL__POSIX_LOAD_LIBRARY_BREAK
# define FPL__POSIX_GET_FUNCTION_ADDRESS_OPTIONAL(mod, libHandle, libName, target, type, name) \
(target)->name = (type *)dlsym(libHandle, #name)
# define FPL__POSIX_GET_FUNCTION_ADDRESS FPL__POSIX_GET_FUNCTION_ADDRESS_BREAK
#else
# define FPL__POSIX_LOAD_LIBRARY(mod, target, libName)
// NOTE(final): Without runtime linking optional functions cannot be probed and may not even be declared (e.g. pthread_yield is removed in glibc 2.34, pthread_timedjoin_np is a GNU extension), so they are left null and the caller falls back.
# define FPL__POSIX_GET_FUNCTION_ADDRESS_OPTIONAL(mod, libHandle, libName, target, type, name) \
(target)->name = fpl_null
// NOTE(final): The cast mirrors the runtime-linking path and is required when opaque handles make the FPL prototype differ from the real one.
# define FPL__POSIX_GET_FUNCTION_ADDRESS(mod, libHandle, libName, target, type, name) \
(target)->name = (type *)name
#endif
#define FPL__FUNC_PTHREAD_pthread_self(name) pthread_t name(void)
typedef FPL__FUNC_PTHREAD_pthread_self(fpl__pthread_func_pthread_self);
#define FPL__FUNC_PTHREAD_pthread_setschedparam(name) int name(pthread_t thread, int policy, const struct sched_param *param)
typedef FPL__FUNC_PTHREAD_pthread_setschedparam(fpl__pthread_func_pthread_setschedparam);
#define FPL__FUNC_PTHREAD_pthread_getschedparam(name) int name(pthread_t thread, int *policy, struct sched_param *param)
typedef FPL__FUNC_PTHREAD_pthread_getschedparam(fpl__pthread_func_pthread_getschedparam);
#define FPL__FUNC_PTHREAD_pthread_attr_init(name) int name(pthread_attr_t *attr)
typedef FPL__FUNC_PTHREAD_pthread_attr_init(fpl__pthread_func_pthread_attr_init);
#define FPL__FUNC_PTHREAD_pthread_attr_getschedparam(name) int name(const pthread_attr_t *__restrict__ attr, struct sched_param *__restrict__ param)
typedef FPL__FUNC_PTHREAD_pthread_attr_getschedparam(fpl__pthread_func_pthread_attr_getschedparam);
#define FPL__FUNC_PTHREAD_pthread_attr_setschedparam(name) int name(pthread_attr_t *__restrict__ attr, const struct sched_param *__restrict__ param)
typedef FPL__FUNC_PTHREAD_pthread_attr_setschedparam(fpl__pthread_func_pthread_attr_setschedparam);
#define FPL__FUNC_PTHREAD_pthread_attr_setstacksize(name) int name(pthread_attr_t *attr, size_t stacksize)
typedef FPL__FUNC_PTHREAD_pthread_attr_setstacksize(fpl__pthread_func_pthread_attr_setstacksize);
#define FPL__FUNC_PTHREAD_pthread_attr_setdetachstate(name) int name(pthread_attr_t *attr, int detachstate);
typedef FPL__FUNC_PTHREAD_pthread_attr_setdetachstate(fpl__pthread_func_pthread_attr_setdetachstate);
#define FPL__FUNC_PTHREAD_pthread_attr_setschedpolicy(name) int name(pthread_attr_t *__attr, int __policy)
typedef FPL__FUNC_PTHREAD_pthread_attr_setschedpolicy(fpl__pthread_func_pthread_attr_setschedpolicy);
#define FPL__FUNC_PTHREAD_pthread_create(name) int name(pthread_t *, const pthread_attr_t *, void *(*__start_routine) (void *), void *)
typedef FPL__FUNC_PTHREAD_pthread_create(fpl__pthread_func_pthread_create);
#define FPL__FUNC_PTHREAD_pthread_kill(name) int name(pthread_t thread, int sig)
typedef FPL__FUNC_PTHREAD_pthread_kill(fpl__pthread_func_pthread_kill);
#define FPL__FUNC_PTHREAD_pthread_join(name) int name(pthread_t __th, void **retval)
typedef FPL__FUNC_PTHREAD_pthread_join(fpl__pthread_func_pthread_join);
#define FPL__FUNC_PTHREAD_pthread_exit(name) void name(void *__retval)
typedef FPL__FUNC_PTHREAD_pthread_exit(fpl__pthread_func_pthread_exit);
#define FPL__FUNC_PTHREAD_pthread_yield(name) int name(void)
typedef FPL__FUNC_PTHREAD_pthread_yield(fpl__pthread_func_pthread_yield);
#define FPL__FUNC_PTHREAD_pthread_timedjoin_np(name) int name(pthread_t thread, void **retval, const struct timespec *abstime)
typedef FPL__FUNC_PTHREAD_pthread_timedjoin_np(fpl__pthread_func_pthread_timedjoin_np);
#define FPL__FUNC_PTHREAD_pthread_mutex_init(name) int name(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
typedef FPL__FUNC_PTHREAD_pthread_mutex_init(fpl__pthread_func_pthread_mutex_init);
#define FPL__FUNC_PTHREAD_pthread_mutex_destroy(name) int name(pthread_mutex_t *mutex)
typedef FPL__FUNC_PTHREAD_pthread_mutex_destroy(fpl__pthread_func_pthread_mutex_destroy);
#define FPL__FUNC_PTHREAD_pthread_mutex_lock(name) int name(pthread_mutex_t *mutex)
typedef FPL__FUNC_PTHREAD_pthread_mutex_lock(fpl__pthread_func_pthread_mutex_lock);
#define FPL__FUNC_PTHREAD_pthread_mutex_trylock(name) int name(pthread_mutex_t *mutex)
typedef FPL__FUNC_PTHREAD_pthread_mutex_trylock(fpl__pthread_func_pthread_mutex_trylock);
#define FPL__FUNC_PTHREAD_pthread_mutex_unlock(name) int name(pthread_mutex_t *mutex)
typedef FPL__FUNC_PTHREAD_pthread_mutex_unlock(fpl__pthread_func_pthread_mutex_unlock);
#define FPL__FUNC_PTHREAD_pthread_cond_init(name) int name(pthread_cond_t *cond, const pthread_condattr_t *attr)
typedef FPL__FUNC_PTHREAD_pthread_cond_init(fpl__pthread_func_pthread_cond_init);
#define FPL__FUNC_PTHREAD_pthread_cond_destroy(name) int name(pthread_cond_t *cond)
typedef FPL__FUNC_PTHREAD_pthread_cond_destroy(fpl__pthread_func_pthread_cond_destroy);
#define FPL__FUNC_PTHREAD_pthread_cond_timedwait(name) int name(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
typedef FPL__FUNC_PTHREAD_pthread_cond_timedwait(fpl__pthread_func_pthread_cond_timedwait);
#define FPL__FUNC_PTHREAD_pthread_cond_wait(name) int name(pthread_cond_t *cond, pthread_mutex_t *mutex)
typedef FPL__FUNC_PTHREAD_pthread_cond_wait(fpl__pthread_func_pthread_cond_wait);
#define FPL__FUNC_PTHREAD_pthread_cond_broadcast(name) int name(pthread_cond_t *cond)
typedef FPL__FUNC_PTHREAD_pthread_cond_broadcast(fpl__pthread_func_pthread_cond_broadcast);
#define FPL__FUNC_PTHREAD_pthread_cond_signal(name) int name(pthread_cond_t *cond)
typedef FPL__FUNC_PTHREAD_pthread_cond_signal(fpl__pthread_func_pthread_cond_signal);
#define FPL__FUNC_PTHREAD_sem_init(name) int name(fpl__POSIXSemaphoreHandle *__sem, int __pshared, unsigned int __value)
typedef FPL__FUNC_PTHREAD_sem_init(fpl__pthread_func_sem_init);
#define FPL__FUNC_PTHREAD_sem_destroy(name) int name(fpl__POSIXSemaphoreHandle *__sem)
typedef FPL__FUNC_PTHREAD_sem_destroy(fpl__pthread_func_sem_destroy);
#define FPL__FUNC_PTHREAD_sem_wait(name) int name(fpl__POSIXSemaphoreHandle *__sem)
typedef FPL__FUNC_PTHREAD_sem_wait(fpl__pthread_func_sem_wait);
#define FPL__FUNC_PTHREAD_sem_timedwait(name) int name(fpl__POSIXSemaphoreHandle *__restrict __sem, const struct timespec *__restrict __abstime)
typedef FPL__FUNC_PTHREAD_sem_timedwait(fpl__pthread_func_sem_timedwait);
#define FPL__FUNC_PTHREAD_sem_trywait(name) int name(fpl__POSIXSemaphoreHandle *__sem)
typedef FPL__FUNC_PTHREAD_sem_trywait(fpl__pthread_func_sem_trywait);
#define FPL__FUNC_PTHREAD_sem_post(name) int name(fpl__POSIXSemaphoreHandle *__sem)
typedef FPL__FUNC_PTHREAD_sem_post(fpl__pthread_func_sem_post);
#define FPL__FUNC_PTHREAD_sem_getvalue(name) int name(fpl__POSIXSemaphoreHandle *__restrict __sem, int *__restrict __sval)
typedef FPL__FUNC_PTHREAD_sem_getvalue(fpl__pthread_func_sem_getvalue);
typedef struct fpl__PThreadApi {
void *libHandle;
// pthread_t
fpl__pthread_func_pthread_self *pthread_self;
fpl__pthread_func_pthread_setschedparam *pthread_setschedparam;
fpl__pthread_func_pthread_getschedparam *pthread_getschedparam;
fpl__pthread_func_pthread_create *pthread_create;
fpl__pthread_func_pthread_kill *pthread_kill;
fpl__pthread_func_pthread_join *pthread_join;
fpl__pthread_func_pthread_exit *pthread_exit;
fpl__pthread_func_pthread_yield *pthread_yield;
fpl__pthread_func_pthread_timedjoin_np *pthread_timedjoin_np;
// pthread_attr_t
fpl__pthread_func_pthread_attr_init *pthread_attr_init;
fpl__pthread_func_pthread_attr_getschedparam *pthread_attr_getschedparam;
fpl__pthread_func_pthread_attr_setschedparam *pthread_attr_setschedparam;
fpl__pthread_func_pthread_attr_setstacksize *pthread_attr_setstacksize;
fpl__pthread_func_pthread_attr_setdetachstate *pthread_attr_setdetachstate;
fpl__pthread_func_pthread_attr_setschedpolicy *pthread_attr_setschedpolicy;
// pthread_mutex_t
fpl__pthread_func_pthread_mutex_init *pthread_mutex_init;
fpl__pthread_func_pthread_mutex_destroy *pthread_mutex_destroy;
fpl__pthread_func_pthread_mutex_lock *pthread_mutex_lock;
fpl__pthread_func_pthread_mutex_trylock *pthread_mutex_trylock;
fpl__pthread_func_pthread_mutex_unlock *pthread_mutex_unlock;
// pthread_cond_t
fpl__pthread_func_pthread_cond_init *pthread_cond_init;
fpl__pthread_func_pthread_cond_destroy *pthread_cond_destroy;
fpl__pthread_func_pthread_cond_timedwait *pthread_cond_timedwait;
fpl__pthread_func_pthread_cond_wait *pthread_cond_wait;
fpl__pthread_func_pthread_cond_broadcast *pthread_cond_broadcast;
fpl__pthread_func_pthread_cond_signal *pthread_cond_signal;
// sem_t
fpl__pthread_func_sem_init *sem_init;
fpl__pthread_func_sem_destroy *sem_destroy;
fpl__pthread_func_sem_wait *sem_wait;
fpl__pthread_func_sem_timedwait *sem_timedwait;
fpl__pthread_func_sem_trywait *sem_trywait;
fpl__pthread_func_sem_post *sem_post;
fpl__pthread_func_sem_getvalue *sem_getvalue;
} fpl__PThreadApi;
#define FPL__POSIX_DL_LOADTYPE RTLD_NOW
void fpl__PThreadUnloadApi(fpl__PThreadApi *pthreadApi) {
(pthreadApi != );
if (pthreadApi->libHandle != ) {
dlclose(pthreadApi->libHandle);
}
(pthreadApi);
}
bool fpl__PThreadLoadApi(fpl__PThreadApi *pthreadApi) {
const char *libpthreadFileNames[] = {
#if defined(FPL_SUBPLATFORM_BSD)
"libthr.so",
"libthr.so.3",
#endif
"libpthread.so",
"libpthread.so.0",
};
bool result = false;
for (uint32_t index = 0; index < (libpthreadFileNames); ++index) {
const char *libName = libpthreadFileNames[index];
(pthreadApi);
do {
void *libHandle = ;
FPL__POSIX_LOAD_LIBRARY(FPL__MODULE_PTHREAD, libHandle, libName);
// pthread_t
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_self, pthread_self);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_setschedparam, pthread_setschedparam);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_getschedparam, pthread_getschedparam);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_create, pthread_create);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_kill, pthread_kill);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_join, pthread_join);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_exit, pthread_exit);
FPL__POSIX_GET_FUNCTION_ADDRESS_OPTIONAL(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_yield, pthread_yield);
FPL__POSIX_GET_FUNCTION_ADDRESS_OPTIONAL(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_timedjoin_np, pthread_timedjoin_np);
// pthread_attr_t
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_init, pthread_attr_init);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_getschedparam, pthread_attr_getschedparam);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_setschedparam, pthread_attr_setschedparam);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_setstacksize, pthread_attr_setstacksize);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_setdetachstate, pthread_attr_setdetachstate);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
// pthread_mutex_t
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_mutex_init, pthread_mutex_init);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_mutex_destroy, pthread_mutex_destroy);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_mutex_lock, pthread_mutex_lock);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_mutex_trylock, pthread_mutex_trylock);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_mutex_unlock, pthread_mutex_unlock);
// pthread_cond_t
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_init, pthread_cond_init);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_destroy, pthread_cond_destroy);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_timedwait, pthread_cond_timedwait);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_wait, pthread_cond_wait);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_broadcast, pthread_cond_broadcast);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_pthread_cond_signal, pthread_cond_signal);
// sem_t
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_init, sem_init);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_destroy, sem_destroy);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_wait, sem_wait);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_timedwait, sem_timedwait);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_trywait, sem_trywait);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_post, sem_post);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_PTHREAD, libHandle, libName, pthreadApi, fpl__pthread_func_sem_getvalue, sem_getvalue);
pthreadApi->libHandle = libHandle;
result = true;
} while (0);
if (result) {
break;
}
fpl__PThreadUnloadApi(pthreadApi);
}
return(result);
}
typedef struct fpl__PosixInitState {
int dummy;
} fpl__PosixInitState;
typedef struct fpl__PosixAppState {
fpl__PThreadApi pthreadApi;
} fpl__PosixAppState;
#endif // FPL_SUBPLATFORM_POSIX
// ############################################################################
//
// > TYPES_LINUX
//
// ############################################################################
#if defined(FPL_PLATFORM_LINUX)
typedef struct fpl__LinuxInitState {
char prevLocale[256];
hasPrevLocale;
} fpl__LinuxInitState;
#if defined(FPL__ENABLE_INPUT_LINUX_JOYSTICK)
#define FPL__INPUT_LINUX_JOYSTICK_MAX_JOYPAD_COUNT 4
#define FPL__INPUT_LINUX_JOYSTICK_SCAN_COUNT 32
typedef struct fpl__InputLinuxJoystickGamepad {
char deviceName[512 + 1];
char displayName[];
// Device handle
int fd;
int slotIndex;
uint8_t axisCount;
uint8_t buttonCount;
// joydev axis indices that carry ABS_HAT0X / ABS_HAT0Y (resolved via JSIOCGAXMAP at connect). 0xFF means "this controller has no DPad-as-axis on hat 0". SDL's gamecontrollerdb encodes the DPad as `h0.*` for nearly every Linux pad regardless of whether the kernel exposes the DPad as a real hat or as a pair of axes, so we synthesize raw.hats[0] from these joydev axes to make SDL mappings resolve uniformly. Different controllers place the HAT axes at different joydev indices (XInput F310 → 6/7, DInput F310 → 4/5).
uint8_t hat0XAxis;
uint8_t hat0YAxis;
fplGamepadState state;
// Snapshot built from JS_EVENT_AXIS/BUTTON every drain, fed into the active mapping.
fplGamepadData raw;
// Mapping installed by the user resolver at connect time (only valid when hasMapping is true).
fplGamepadMapping mapping;
// True when the resolver returned a mapping. When false, the legacy hardcoded fpl__InputLinuxJoystickStateUpdateEvent path is used unchanged.
bool hasMapping;
} fpl__InputLinuxJoystickGamepad;
// Linux /dev/input/jsX backend instance owned by fpl__InputContext.
typedef struct fpl__InputBackendLinuxJoystick {
fpl__InputLinuxJoystickGamepad gamepads[FPL__INPUT_LINUX_JOYSTICK_MAX_JOYPAD_COUNT];
bool triedSlot[FPL__INPUT_LINUX_JOYSTICK_SCAN_COUNT];
uint64_t lastCheckTime;
bool isInitialized;
} fpl__InputBackendLinuxJoystick;
#endif // FPL__ENABLE_INPUT_LINUX_JOYSTICK
typedef struct fpl__LinuxAppState {
int dummy;
} fpl__LinuxAppState;
#endif // FPL_PLATFORM_LINUX
// ############################################################################
//
// > TYPES_UNIX
//
// ############################################################################
#if defined(FPL_PLATFORM_UNIX)
typedef struct fpl__UnixInitState {
char prevLocale[256];
hasPrevLocale;
} fpl__UnixInitState;
typedef struct fpl__UnixAppState {
// Global mutex to lock signal multiple waiters
pthread_mutex_t signalMultipleWaitMutex;
// Global condition to wake up multiple waiters
pthread_cond_t signalMultipleWaitCondition;
} fpl__UnixAppState;
#endif // FPL_PLATFORM_UNIX
// ############################################################################
//
// > TYPES_X11
//
// ############################################################################
#if defined(FPL_SUBPLATFORM_X11)
#if defined(FPL__ENABLE_INPUT_X11)
// X11 keyboard/mouse backend instance owned by fpl__InputContext.
// In windowed mode display + window come from fpl__X11WindowState; in detached mode
// (FPL_NO_WINDOW or fplInputSettings.detachFromWindow) the backend opens its own
// Display* and uses the default screen's root window for pointer queries (step 9b).
// XEvents arrive via fpl__InputSystem_HandleNativeEvent in windowed mode; detached mode
// is polling-only — events from a private Display are not forwarded.
typedef struct fpl__InputBackendX11Kbm {
fpl__X11_Display *display;
fpl__X11_Window root;
detachedKeyMap[256];
bool isInitialized;
bool detached;
bool ownsDisplay;
} fpl__InputBackendX11Kbm;
#endif // FPL__ENABLE_INPUT_X11
//
// X11 Api
//
#define FPL__FUNC_X11_XFree(name) int name(void *data)
typedef FPL__FUNC_X11_XFree(fpl__func_x11_XFree);
#define FPL__FUNC_X11_XFlush(name) int name(fpl__X11_Display *display)
typedef FPL__FUNC_X11_XFlush(fpl__func_x11_XFlush);
#define FPL__FUNC_X11_XOpenDisplay(name) fpl__X11_Display *name(const char *display_name)
typedef FPL__FUNC_X11_XOpenDisplay(fpl__func_x11_XOpenDisplay);
#define FPL__FUNC_X11_XCloseDisplay(name) int name(fpl__X11_Display *display)
typedef FPL__FUNC_X11_XCloseDisplay(fpl__func_x11_XCloseDisplay);
#define FPL__FUNC_X11_XDefaultScreen(name) int name(fpl__X11_Display *display)
typedef FPL__FUNC_X11_XDefaultScreen(fpl__func_x11_XDefaultScreen);
#define FPL__FUNC_X11_XRootWindow(name) fpl__X11_Window name(fpl__X11_Display *display, int screen_number)
typedef FPL__FUNC_X11_XRootWindow(fpl__func_x11_XRootWindow);
#define FPL__FUNC_X11_XCreateWindow(name) fpl__X11_Window name(fpl__X11_Display *display, fpl__X11_Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width, int depth, unsigned int clazz, fpl__X11_Visual *visual, unsigned long valuemask, fpl__X11_XSetWindowAttributes *attributes)
typedef FPL__FUNC_X11_XCreateWindow(fpl__func_x11_XCreateWindow);
#define FPL__FUNC_X11_XDestroyWindow(name) int name(fpl__X11_Display *display, fpl__X11_Window w)
typedef FPL__FUNC_X11_XDestroyWindow(fpl__func_x11_XDestroyWindow);
#define FPL__FUNC_X11_XCreateColormap(name) fpl__X11_Colormap name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_Visual *visual, int alloc)
typedef FPL__FUNC_X11_XCreateColormap(fpl__func_x11_XCreateColormap);
#define FPL__FUNC_X11_XDefaultColormap(name) fpl__X11_Colormap name(fpl__X11_Display *display, int screen_number)
typedef FPL__FUNC_X11_XDefaultColormap(fpl__func_x11_XDefaultColormap);
#define FPL__FUNC_X11_XFreeColormap(name) int name(fpl__X11_Display *display, fpl__X11_Colormap colormap)
typedef FPL__FUNC_X11_XFreeColormap(fpl__func_x11_XFreeColormap);
#define FPL__FUNC_X11_XMapWindow(name) int name(fpl__X11_Display *display, fpl__X11_Window w)
typedef FPL__FUNC_X11_XMapWindow(fpl__func_x11_XMapWindow);
#define FPL__FUNC_X11_XUnmapWindow(name) int name(fpl__X11_Display *display, fpl__X11_Window w)
typedef FPL__FUNC_X11_XUnmapWindow(fpl__func_x11_XUnmapWindow);
#define FPL__FUNC_X11_XStoreName(name) int name(fpl__X11_Display *display, fpl__X11_Window w, const char *window_name)
typedef FPL__FUNC_X11_XStoreName(fpl__func_x11_XStoreName);
#define FPL__FUNC_X11_XDefaultVisual(name) fpl__X11_Visual *name(fpl__X11_Display *display, int screen_number)
typedef FPL__FUNC_X11_XDefaultVisual(fpl__func_x11_XDefaultVisual);
#define FPL__FUNC_X11_XDefaultDepth(name) int name(fpl__X11_Display *display, int screen_number)
typedef FPL__FUNC_X11_XDefaultDepth(fpl__func_x11_XDefaultDepth);
#define FPL__FUNC_X11_XInternAtom(name) fpl__X11_Atom name(fpl__X11_Display *display, const char *atom_name, fpl__X11_Bool only_if_exists)
typedef FPL__FUNC_X11_XInternAtom(fpl__func_x11_XInternAtom);
#define FPL__FUNC_X11_XSetWMProtocols(name) fpl__X11_Status name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_Atom *protocols, int count)
typedef FPL__FUNC_X11_XSetWMProtocols(fpl__func_x11_XSetWMProtocols);
#define FPL__FUNC_X11_XPending(name) int name(fpl__X11_Display *display)
typedef FPL__FUNC_X11_XPending(fpl__func_x11_XPending);
#define FPL__FUNC_X11_XSync(name) int name(fpl__X11_Display *display, fpl__X11_Bool discard)
typedef FPL__FUNC_X11_XSync(fpl__func_x11_XSync);
#define FPL__FUNC_X11_XNextEvent(name) int name(fpl__X11_Display *display, fpl__X11_XEvent *event_return)
typedef FPL__FUNC_X11_XNextEvent(fpl__func_x11_XNextEvent);
#define FPL__FUNC_X11_XPeekEvent(name) int name(fpl__X11_Display *display, fpl__X11_XEvent *event_return)
typedef FPL__FUNC_X11_XPeekEvent(fpl__func_x11_XPeekEvent);
#define FPL__FUNC_X11_XEventsQueued(name) int name(fpl__X11_Display *display, int mode)
typedef FPL__FUNC_X11_XEventsQueued(fpl__func_x11_XEventsQueued);
#define FPL__FUNC_X11_XGetWindowAttributes(name) fpl__X11_Status name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_XWindowAttributes *window_attributes_return)
typedef FPL__FUNC_X11_XGetWindowAttributes(fpl__func_x11_XGetWindowAttributes);
#define FPL__FUNC_X11_XResizeWindow(name) int name(fpl__X11_Display *display, fpl__X11_Window w, unsigned int width, unsigned int height)
typedef FPL__FUNC_X11_XResizeWindow(fpl__func_x11_XResizeWindow);
#define FPL__FUNC_X11_XMoveWindow(name) int name(fpl__X11_Display *display, fpl__X11_Window w, int x, int y)
typedef FPL__FUNC_X11_XMoveWindow(fpl__func_x11_XMoveWindow);
#define FPL__FUNC_X11_XGetKeyboardMapping(name) fpl__X11_KeySym *name(fpl__X11_Display *display, fpl__X11_KeyCode first_keycode, int keycode_count, int *keysyms_per_keycode_return)
typedef FPL__FUNC_X11_XGetKeyboardMapping(fpl__func_x11_XGetKeyboardMapping);
#define FPL__FUNC_X11_XLookupString(name) int name(fpl__X11_XKeyEvent* event_struct, char* buffer_return, int bytes_buffer, fpl__X11_KeySym* keysym_return, fpl__X11_XComposeStatus* status_in_out)
typedef FPL__FUNC_X11_XLookupString(fpl__func_x11_XLookupString);
#define FPL__FUNC_X11_XSendEvent(name) fpl__X11_Status name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_Bool propagate, long event_mask, fpl__X11_XEvent *event_send)
typedef FPL__FUNC_X11_XSendEvent(fpl__func_x11_XSendEvent);
#define FPL__FUNC_X11_XMatchVisualInfo(name) fpl__X11_Status name(fpl__X11_Display* display, int screen, int depth, int clazz, fpl__X11_XVisualInfo* vinfo_return)
typedef FPL__FUNC_X11_XMatchVisualInfo(fpl__func_x11_XMatchVisualInfo);
#define FPL__FUNC_X11_XCreateGC(name) fpl__X11_GC name(fpl__X11_Display* display, fpl__X11_Drawable d, unsigned long valuemask, fpl__X11_XGCValues* values)
typedef FPL__FUNC_X11_XCreateGC(fpl__func_x11_XCreateGC);
#define FPL__FUNC_X11_XGetImage(name) fpl__X11_XImage *name(fpl__X11_Display* display, fpl__X11_Drawable d, int x, int y, unsigned int width, unsigned int height, unsigned long plane_mask, int format)
typedef FPL__FUNC_X11_XGetImage(fpl__func_x11_XGetImage);
#define FPL__FUNC_X11_XCreateImage(name) fpl__X11_XImage *name(fpl__X11_Display *display, fpl__X11_Visual *visual, unsigned int depth, int format, int offset, char *data, unsigned int width, unsigned int height, int bitmap_pad, int bytes_per_line)
typedef FPL__FUNC_X11_XCreateImage(fpl__func_x11_XCreateImage);
#define FPL__FUNC_X11_XPutImage(name) int name(fpl__X11_Display *display, fpl__X11_Drawable d, fpl__X11_GC gc, fpl__X11_XImage *image, int src_x, int src_y, int dest_x, int dest_y, unsigned int width, unsigned int height)
typedef FPL__FUNC_X11_XPutImage(fpl__func_x11_XPutImage);
#define FPL__FUNC_X11_XMapRaised(name) int name(fpl__X11_Display *display, fpl__X11_Window w)
typedef FPL__FUNC_X11_XMapRaised(fpl__func_x11_XMapRaised);
#define FPL__FUNC_X11_XCreatePixmap(name) fpl__X11_Pixmap name(fpl__X11_Display * display, fpl__X11_Drawable d, unsigned int width, unsigned int height, unsigned int depth)
typedef FPL__FUNC_X11_XCreatePixmap(fpl__func_x11_XCreatePixmap);
#define FPL__FUNC_X11_XSelectInput(name) int name(fpl__X11_Display * display, fpl__X11_Window w, long eventMask)
typedef FPL__FUNC_X11_XSelectInput(fpl__func_x11_XSelectInput);
#define FPL__FUNC_X11_XGetWindowProperty(name) int name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_Atom prop, long long_offset, long long_length, fpl__X11_Bool del, fpl__X11_Atom req_type, fpl__X11_Atom* actual_type_return, int* actual_format_return, unsigned long* nitems_return, unsigned long* bytes_after_return, unsigned char** prop_return)
typedef FPL__FUNC_X11_XGetWindowProperty(fpl__func_x11_XGetWindowProperty);
#define FPL__FUNC_X11_XChangeProperty(name) int name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_Atom property, fpl__X11_Atom type, int format, int mode, const unsigned char* data, int nelements)
typedef FPL__FUNC_X11_XChangeProperty(fpl__func_x11_XChangeProperty);
#define FPL__FUNC_X11_XDeleteProperty(name) int name(fpl__X11_Display* display, fpl__X11_Window w,fpl__X11_Atom prop)
typedef FPL__FUNC_X11_XDeleteProperty(fpl__func_x11_XDeleteProperty);
#define FPL__FUNC_X11_XStringListToTextProperty(name) fpl__X11_Status name(char** list, int count, fpl__X11_XTextProperty* text_prop_return)
typedef FPL__FUNC_X11_XStringListToTextProperty(fpl__func_x11_XStringListToTextProperty);
#define FPL__FUNC_X11_XSetWMIconName(name) void name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_XTextProperty *text_prop)
typedef FPL__FUNC_X11_XSetWMIconName(fpl__func_x11_XSetWMIconName);
#define FPL__FUNC_X11_XSetWMName(name) void name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_XTextProperty *text_prop)
typedef FPL__FUNC_X11_XSetWMName(fpl__func_x11_XSetWMName);
#define FPL__FUNC_X11_XSetClassHint(name) fpl__X11_Status name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_XClassHint *class_hints)
typedef FPL__FUNC_X11_XSetClassHint(fpl__func_x11_XSetClassHint);
#define FPL__FUNC_X11_XQueryKeymap(name) int name(fpl__X11_Display* display, char [32])
typedef FPL__FUNC_X11_XQueryKeymap(fpl__func_x11_XQueryKeymap);
#define FPL__FUNC_X11_XQueryPointer(name) fpl__X11_Bool name(fpl__X11_Display* display, fpl__X11_Window w, fpl__X11_Window* root_return, fpl__X11_Window* child_return, int* root_x_return, int* root_y_return, int* win_x_return, int* win_y_return, unsigned int* mask_return)
typedef FPL__FUNC_X11_XQueryPointer(fpl__func_x11_XQueryPointer);
#define FPL__FUNC_X11_XConvertSelection(name) int name(fpl__X11_Display *display, fpl__X11_Atom selection, fpl__X11_Atom target, fpl__X11_Atom property, fpl__X11_Window requestor, fpl__X11_Time time)
typedef FPL__FUNC_X11_XConvertSelection(fpl__func_x11_XConvertSelection);
#define FPL__FUNC_X11_XInitThreads(name) fpl__X11_Status name(void)
typedef FPL__FUNC_X11_XInitThreads(fpl__func_x11_XInitThreads);
#define FPL__FUNC_X11_XSetErrorHandler(name) fpl__X11_XErrorHandler name(fpl__X11_XErrorHandler handler)
typedef FPL__FUNC_X11_XSetErrorHandler(fpl__func_x11_XSetErrorHandler);
#define FPL__FUNC_X11_XIconifyWindow(name) fpl__X11_Status name(fpl__X11_Display *display, fpl__X11_Window w, int screen_number)
typedef FPL__FUNC_X11_XIconifyWindow(fpl__func_x11_XIconifyWindow);
#define FPL__FUNC_X11_XAllocSizeHints(name) fpl__X11_XSizeHints *name(void)
typedef FPL__FUNC_X11_XAllocSizeHints(fpl__func_x11_XAllocSizeHints);
#define FPL__FUNC_X11_XSetWMNormalHints(name) void name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_XSizeHints *hints)
typedef FPL__FUNC_X11_XSetWMNormalHints(fpl__func_x11_XSetWMNormalHints);
#define FPL__FUNC_X11_XGetWMNormalHints(name) fpl__X11_Status name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_XSizeHints *hints_return, long *supplied_return)
typedef FPL__FUNC_X11_XGetWMNormalHints(fpl__func_x11_XGetWMNormalHints);
#define FPL__FUNC_X11_XDefineCursor(name) int name(fpl__X11_Display *display, fpl__X11_Window w, fpl__X11_Cursor cursor)
typedef FPL__FUNC_X11_XDefineCursor(fpl__func_x11_XDefineCursor);
#define FPL__FUNC_X11_XUndefineCursor(name) int name(fpl__X11_Display *display, fpl__X11_Window w)
typedef FPL__FUNC_X11_XUndefineCursor(fpl__func_x11_XUndefineCursor);
#define FPL__FUNC_X11_XFreeCursor(name) int name(fpl__X11_Display *display, fpl__X11_Cursor cursor)
typedef FPL__FUNC_X11_XFreeCursor(fpl__func_x11_XFreeCursor);
#define FPL__FUNC_X11_XCreateBitmapFromData(name) fpl__X11_Pixmap name(fpl__X11_Display *display, fpl__X11_Drawable d, const char *data, unsigned int width, unsigned int height)
typedef FPL__FUNC_X11_XCreateBitmapFromData(fpl__func_x11_XCreateBitmapFromData);
#define FPL__FUNC_X11_XCreatePixmapCursor(name) fpl__X11_Cursor name(fpl__X11_Display *display, fpl__X11_Pixmap source, fpl__X11_Pixmap mask, fpl__X11_XColor *foreground_color, fpl__X11_XColor *background_color, unsigned int x, unsigned int y)
typedef FPL__FUNC_X11_XCreatePixmapCursor(fpl__func_x11_XCreatePixmapCursor);
#define FPL__FUNC_X11_XSetSelectionOwner(name) int name(fpl__X11_Display *display, fpl__X11_Atom selection, fpl__X11_Window owner, fpl__X11_Time time)
typedef FPL__FUNC_X11_XSetSelectionOwner(fpl__func_x11_XSetSelectionOwner);
#define FPL__FUNC_X11_XGetSelectionOwner(name) fpl__X11_Window name(fpl__X11_Display *display, fpl__X11_Atom selection)
typedef FPL__FUNC_X11_XGetSelectionOwner(fpl__func_x11_XGetSelectionOwner);
#define FPL__FUNC_X11_XCheckTypedWindowEvent(name) fpl__X11_Bool name(fpl__X11_Display *display, fpl__X11_Window w, int event_type, fpl__X11_XEvent *event_return)
typedef FPL__FUNC_X11_XCheckTypedWindowEvent(fpl__func_x11_XCheckTypedWindowEvent);
#define FPL__FUNC_X11_XTranslateCoordinates(name) fpl__X11_Bool name(fpl__X11_Display *display, fpl__X11_Window src_w, fpl__X11_Window dest_w, int src_x, int src_y, int *dest_x_return, int *dest_y_return, fpl__X11_Window *child_return)
typedef FPL__FUNC_X11_XTranslateCoordinates(fpl__func_x11_XTranslateCoordinates);
// Direct extern declarations for non-runtime-linking builds (no X11 headers present)
#if defined(FPL_NO_RUNTIME_LINKING) && !defined(FPL__HAS_PLATFORM_INCLUDES)
extern FPL__FUNC_X11_XAllocSizeHints(XAllocSizeHints);
extern FPL__FUNC_X11_XChangeProperty(XChangeProperty);
extern FPL__FUNC_X11_XCheckTypedWindowEvent(XCheckTypedWindowEvent);
extern FPL__FUNC_X11_XCloseDisplay(XCloseDisplay);
extern FPL__FUNC_X11_XConvertSelection(XConvertSelection);
extern FPL__FUNC_X11_XCreateBitmapFromData(XCreateBitmapFromData);
extern FPL__FUNC_X11_XCreateColormap(XCreateColormap);
extern FPL__FUNC_X11_XCreateGC(XCreateGC);
extern FPL__FUNC_X11_XCreateImage(XCreateImage);
extern FPL__FUNC_X11_XCreatePixmap(XCreatePixmap);
extern FPL__FUNC_X11_XCreatePixmapCursor(XCreatePixmapCursor);
extern FPL__FUNC_X11_XCreateWindow(XCreateWindow);
extern FPL__FUNC_X11_XDefaultColormap(XDefaultColormap);
extern FPL__FUNC_X11_XDefaultDepth(XDefaultDepth);
extern FPL__FUNC_X11_XDefaultScreen(XDefaultScreen);
extern FPL__FUNC_X11_XDefaultVisual(XDefaultVisual);
extern FPL__FUNC_X11_XDefineCursor(XDefineCursor);
extern FPL__FUNC_X11_XDeleteProperty(XDeleteProperty);
extern FPL__FUNC_X11_XDestroyWindow(XDestroyWindow);
extern FPL__FUNC_X11_XEventsQueued(XEventsQueued);
extern FPL__FUNC_X11_XFlush(XFlush);
extern FPL__FUNC_X11_XFree(XFree);
extern FPL__FUNC_X11_XFreeColormap(XFreeColormap);
extern FPL__FUNC_X11_XFreeCursor(XFreeCursor);
extern FPL__FUNC_X11_XGetImage(XGetImage);
extern FPL__FUNC_X11_XGetKeyboardMapping(XGetKeyboardMapping);
extern FPL__FUNC_X11_XGetSelectionOwner(XGetSelectionOwner);
extern FPL__FUNC_X11_XGetWMNormalHints(XGetWMNormalHints);
extern FPL__FUNC_X11_XGetWindowAttributes(XGetWindowAttributes);
extern FPL__FUNC_X11_XGetWindowProperty(XGetWindowProperty);
extern FPL__FUNC_X11_XIconifyWindow(XIconifyWindow);
extern FPL__FUNC_X11_XInitThreads(XInitThreads);
extern FPL__FUNC_X11_XInternAtom(XInternAtom);
extern FPL__FUNC_X11_XLookupString(XLookupString);
extern FPL__FUNC_X11_XMapRaised(XMapRaised);
extern FPL__FUNC_X11_XMapWindow(XMapWindow);
extern FPL__FUNC_X11_XMatchVisualInfo(XMatchVisualInfo);
extern FPL__FUNC_X11_XMoveWindow(XMoveWindow);
extern FPL__FUNC_X11_XNextEvent(XNextEvent);
extern FPL__FUNC_X11_XOpenDisplay(XOpenDisplay);
extern FPL__FUNC_X11_XPeekEvent(XPeekEvent);
extern FPL__FUNC_X11_XPending(XPending);
extern FPL__FUNC_X11_XPutImage(XPutImage);
extern FPL__FUNC_X11_XQueryKeymap(XQueryKeymap);
extern FPL__FUNC_X11_XQueryPointer(XQueryPointer);
extern FPL__FUNC_X11_XResizeWindow(XResizeWindow);
extern FPL__FUNC_X11_XRootWindow(XRootWindow);
extern FPL__FUNC_X11_XSelectInput(XSelectInput);
extern FPL__FUNC_X11_XSendEvent(XSendEvent);
extern FPL__FUNC_X11_XSetErrorHandler(XSetErrorHandler);
extern FPL__FUNC_X11_XSetSelectionOwner(XSetSelectionOwner);
extern FPL__FUNC_X11_XSetWMIconName(XSetWMIconName);
extern FPL__FUNC_X11_XSetWMName(XSetWMName);
extern FPL__FUNC_X11_XSetClassHint(XSetClassHint);
extern FPL__FUNC_X11_XSetWMNormalHints(XSetWMNormalHints);
extern FPL__FUNC_X11_XSetWMProtocols(XSetWMProtocols);
extern FPL__FUNC_X11_XStoreName(XStoreName);
extern FPL__FUNC_X11_XStringListToTextProperty(XStringListToTextProperty);
extern FPL__FUNC_X11_XSync(XSync);
extern FPL__FUNC_X11_XTranslateCoordinates(XTranslateCoordinates);
extern FPL__FUNC_X11_XUndefineCursor(XUndefineCursor);
extern FPL__FUNC_X11_XUnmapWindow(XUnmapWindow);
#endif
typedef struct fpl__X11Api {
void *libHandle;
fpl__func_x11_XFlush *XFlush;
fpl__func_x11_XFree *XFree;
fpl__func_x11_XOpenDisplay *XOpenDisplay;
fpl__func_x11_XCloseDisplay *XCloseDisplay;
fpl__func_x11_XDefaultScreen *XDefaultScreen;
fpl__func_x11_XRootWindow *XRootWindow;
fpl__func_x11_XCreateWindow *XCreateWindow;
fpl__func_x11_XDestroyWindow *XDestroyWindow;
fpl__func_x11_XCreateColormap *XCreateColormap;
fpl__func_x11_XFreeColormap *XFreeColormap;
fpl__func_x11_XDefaultColormap *XDefaultColormap;
fpl__func_x11_XMapWindow *XMapWindow;
fpl__func_x11_XUnmapWindow *XUnmapWindow;
fpl__func_x11_XStoreName *XStoreName;
fpl__func_x11_XDefaultVisual *XDefaultVisual;
fpl__func_x11_XDefaultDepth *XDefaultDepth;
fpl__func_x11_XInternAtom *XInternAtom;
fpl__func_x11_XSetWMProtocols *XSetWMProtocols;
fpl__func_x11_XPending *XPending;
fpl__func_x11_XSync *XSync;
fpl__func_x11_XNextEvent *XNextEvent;
fpl__func_x11_XPeekEvent *XPeekEvent;
fpl__func_x11_XEventsQueued *XEventsQueued;
fpl__func_x11_XGetWindowAttributes *XGetWindowAttributes;
fpl__func_x11_XResizeWindow *XResizeWindow;
fpl__func_x11_XMoveWindow *XMoveWindow;
fpl__func_x11_XGetKeyboardMapping *XGetKeyboardMapping;
fpl__func_x11_XLookupString *XLookupString;
fpl__func_x11_XSendEvent *XSendEvent;
fpl__func_x11_XMatchVisualInfo *XMatchVisualInfo;
fpl__func_x11_XCreateGC *XCreateGC;
fpl__func_x11_XGetImage *XGetImage;
fpl__func_x11_XPutImage *XPutImage;
fpl__func_x11_XMapRaised *XMapRaised;
fpl__func_x11_XCreateImage *XCreateImage;
fpl__func_x11_XCreatePixmap *XCreatePixmap;
fpl__func_x11_XSelectInput *XSelectInput;
fpl__func_x11_XGetWindowProperty *XGetWindowProperty;
fpl__func_x11_XChangeProperty *XChangeProperty;
fpl__func_x11_XDeleteProperty *XDeleteProperty;
fpl__func_x11_XStringListToTextProperty *XStringListToTextProperty;
fpl__func_x11_XSetWMIconName *XSetWMIconName;
fpl__func_x11_XSetWMName *XSetWMName;
fpl__func_x11_XSetClassHint *XSetClassHint;
fpl__func_x11_XQueryKeymap *XQueryKeymap;
fpl__func_x11_XQueryPointer *XQueryPointer;
fpl__func_x11_XConvertSelection *XConvertSelection;
fpl__func_x11_XInitThreads *XInitThreads;
fpl__func_x11_XSetErrorHandler *XSetErrorHandler;
fpl__func_x11_XIconifyWindow *XIconifyWindow;
fpl__func_x11_XAllocSizeHints *XAllocSizeHints;
fpl__func_x11_XSetWMNormalHints *XSetWMNormalHints;
fpl__func_x11_XGetWMNormalHints *XGetWMNormalHints;
fpl__func_x11_XDefineCursor *XDefineCursor;
fpl__func_x11_XUndefineCursor *XUndefineCursor;
fpl__func_x11_XFreeCursor *XFreeCursor;
fpl__func_x11_XCreateBitmapFromData *XCreateBitmapFromData;
fpl__func_x11_XCreatePixmapCursor *XCreatePixmapCursor;
fpl__func_x11_XSetSelectionOwner *XSetSelectionOwner;
fpl__func_x11_XGetSelectionOwner *XGetSelectionOwner;
fpl__func_x11_XCheckTypedWindowEvent *XCheckTypedWindowEvent;
fpl__func_x11_XTranslateCoordinates *XTranslateCoordinates;
} fpl__X11Api;
void fpl__UnloadX11Api(fpl__X11Api *x11Api) {
(x11Api != );
if (x11Api->libHandle != ) {
dlclose(x11Api->libHandle);
}
(x11Api);
}
bool fpl__LoadX11Api(fpl__X11Api *x11Api) {
(x11Api != );
const char *libFileNames[] = {
"libX11.so",
"libX11.so.7",
"libX11.so.6",
"libX11.so.5",
};
bool result = false;
for (uint32_t index = 0; index < (libFileNames); ++index) {
const char *libName = libFileNames[index];
(x11Api);
do {
void *libHandle = ;
FPL__POSIX_LOAD_LIBRARY(FPL__MODULE_X11, libHandle, libName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XFlush, XFlush);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XFree, XFree);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XOpenDisplay, XOpenDisplay);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCloseDisplay, XCloseDisplay);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDefaultScreen, XDefaultScreen);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XRootWindow, XRootWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreateWindow, XCreateWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDestroyWindow, XDestroyWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreateColormap, XCreateColormap);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XFreeColormap, XFreeColormap);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDefaultColormap, XDefaultColormap);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XMapWindow, XMapWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XUnmapWindow, XUnmapWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XStoreName, XStoreName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDefaultVisual, XDefaultVisual);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDefaultDepth, XDefaultDepth);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XInternAtom, XInternAtom);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetWMProtocols, XSetWMProtocols);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XPending, XPending);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSync, XSync);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XNextEvent, XNextEvent);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XPeekEvent, XPeekEvent);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XEventsQueued, XEventsQueued);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetWindowAttributes, XGetWindowAttributes);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XResizeWindow, XResizeWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XMoveWindow, XMoveWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetKeyboardMapping, XGetKeyboardMapping);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XLookupString, XLookupString);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSendEvent, XSendEvent);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XMatchVisualInfo, XMatchVisualInfo);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreateGC, XCreateGC);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetImage, XGetImage);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XPutImage, XPutImage);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XMapRaised, XMapRaised);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreateImage, XCreateImage);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreatePixmap, XCreatePixmap);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSelectInput, XSelectInput);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetWindowProperty, XGetWindowProperty);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XChangeProperty, XChangeProperty);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDeleteProperty, XDeleteProperty);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XStringListToTextProperty, XStringListToTextProperty);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetWMIconName, XSetWMIconName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetWMName, XSetWMName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetClassHint, XSetClassHint);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XQueryKeymap, XQueryKeymap);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XQueryPointer, XQueryPointer);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XConvertSelection, XConvertSelection);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XInitThreads, XInitThreads);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetErrorHandler, XSetErrorHandler);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XIconifyWindow, XIconifyWindow);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XAllocSizeHints, XAllocSizeHints);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetWMNormalHints, XSetWMNormalHints);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetWMNormalHints, XGetWMNormalHints);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XDefineCursor, XDefineCursor);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XUndefineCursor, XUndefineCursor);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XFreeCursor, XFreeCursor);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreateBitmapFromData, XCreateBitmapFromData);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCreatePixmapCursor, XCreatePixmapCursor);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XSetSelectionOwner, XSetSelectionOwner);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XGetSelectionOwner, XGetSelectionOwner);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XCheckTypedWindowEvent, XCheckTypedWindowEvent);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_X11, libHandle, libName, x11Api, fpl__func_x11_XTranslateCoordinates, XTranslateCoordinates);
x11Api->libHandle = libHandle;
result = true;
} while (0);
if (result) {
break;
}
fpl__UnloadX11Api(x11Api);
}
return(result);
}
//
// XrandR Api (optional)
//
typedef unsigned long fpl__RROutput;
typedef unsigned long fpl__RRCrtc;
typedef unsigned long fpl__RRMode;
typedef unsigned short fpl__RRConnection;
typedef unsigned short fpl__RRSubpixelOrder;
typedef unsigned short fpl__RRRotation;
typedef struct fpl__XRRModeInfo {
fpl__RRMode id;
unsigned int width;
unsigned int height;
unsigned long dotClock;
unsigned int hSyncStart;
unsigned int hSyncEnd;
unsigned int hTotal;
unsigned int hSkew;
unsigned int vSyncStart;
unsigned int vSyncEnd;
unsigned int vTotal;
char *name;
unsigned int nameLength;
unsigned long modeFlags;
} fpl__XRRModeInfo;
typedef struct fpl__XRRScreenResources {
fpl__X11_Time timestamp;
fpl__X11_Time configTimestamp;
int ncrtc;
fpl__RRCrtc *crtcs;
int noutput;
fpl__RROutput *outputs;
int nmode;
fpl__XRRModeInfo *modes;
} fpl__XRRScreenResources;
typedef struct fpl__XRRCrtcInfo {
fpl__X11_Time timestamp;
int x, y;
unsigned int width, height;
fpl__RRMode mode;
fpl__RRRotation rotation;
int noutput;
fpl__RROutput *outputs;
fpl__RRRotation rotations;
int npossible;
fpl__RROutput *possible;
} fpl__XRRCrtcInfo;
typedef struct fpl__XRROutputInfo {
fpl__X11_Time timestamp;
fpl__RRCrtc crtc;
char *name;
int nameLen;
unsigned long mm_width;
unsigned long mm_height;
fpl__RRConnection connection;
fpl__RRSubpixelOrder subpixel_order;
int ncrtc;
fpl__RRCrtc *crtcs;
int nclone;
fpl__RROutput *clones;
int nmode;
int npreferred;
fpl__RRMode *modes;
} fpl__XRROutputInfo;
#define FPL__FUNC_XRR_XRRQueryExtension(name) fpl__X11_Bool name(fpl__X11_Display *dpy, int *event_base_return, int *error_base_return)
typedef FPL__FUNC_XRR_XRRQueryExtension(fpl__func_xrr_XRRQueryExtension);
#define FPL__FUNC_XRR_XRRGetScreenResourcesCurrent(name) fpl__XRRScreenResources *name(fpl__X11_Display *dpy, fpl__X11_Window window)
typedef FPL__FUNC_XRR_XRRGetScreenResourcesCurrent(fpl__func_xrr_XRRGetScreenResourcesCurrent);
#define FPL__FUNC_XRR_XRRFreeScreenResources(name) void name(fpl__XRRScreenResources *resources)
typedef FPL__FUNC_XRR_XRRFreeScreenResources(fpl__func_xrr_XRRFreeScreenResources);
#define FPL__FUNC_XRR_XRRGetCrtcInfo(name) fpl__XRRCrtcInfo *name(fpl__X11_Display *dpy, fpl__XRRScreenResources *resources, fpl__RRCrtc crtc)
typedef FPL__FUNC_XRR_XRRGetCrtcInfo(fpl__func_xrr_XRRGetCrtcInfo);
#define FPL__FUNC_XRR_XRRFreeCrtcInfo(name) void name(fpl__XRRCrtcInfo *crtcInfo)
typedef FPL__FUNC_XRR_XRRFreeCrtcInfo(fpl__func_xrr_XRRFreeCrtcInfo);
#define FPL__FUNC_XRR_XRRGetOutputInfo(name) fpl__XRROutputInfo *name(fpl__X11_Display *dpy, fpl__XRRScreenResources *resources, fpl__RROutput output)
typedef FPL__FUNC_XRR_XRRGetOutputInfo(fpl__func_xrr_XRRGetOutputInfo);
#define FPL__FUNC_XRR_XRRFreeOutputInfo(name) void name(fpl__XRROutputInfo *outputInfo)
typedef FPL__FUNC_XRR_XRRFreeOutputInfo(fpl__func_xrr_XRRFreeOutputInfo);
#define FPL__FUNC_XRR_XRRGetOutputPrimary(name) fpl__RROutput name(fpl__X11_Display *dpy, fpl__X11_Window window)
typedef FPL__FUNC_XRR_XRRGetOutputPrimary(fpl__func_xrr_XRRGetOutputPrimary);
// Direct extern declarations for non-runtime-linking builds (no X11 headers present)
// The XRandR library exports C symbols - C linkage is required so C++ builds do not mangle them
#if defined(FPL_NO_RUNTIME_LINKING)
#if defined(__cplusplus)
extern "C" {
#endif
extern FPL__FUNC_XRR_XRRFreeCrtcInfo(XRRFreeCrtcInfo);
extern FPL__FUNC_XRR_XRRFreeOutputInfo(XRRFreeOutputInfo);
extern FPL__FUNC_XRR_XRRFreeScreenResources(XRRFreeScreenResources);
extern FPL__FUNC_XRR_XRRGetCrtcInfo(XRRGetCrtcInfo);
extern FPL__FUNC_XRR_XRRGetOutputInfo(XRRGetOutputInfo);
extern FPL__FUNC_XRR_XRRGetOutputPrimary(XRRGetOutputPrimary);
extern FPL__FUNC_XRR_XRRGetScreenResourcesCurrent(XRRGetScreenResourcesCurrent);
extern FPL__FUNC_XRR_XRRQueryExtension(XRRQueryExtension);
#if defined(__cplusplus)
}
#endif
#endif
typedef struct fpl__XrandRApi {
void *libHandle;
fpl__func_xrr_XRRQueryExtension *XRRQueryExtension;
fpl__func_xrr_XRRGetScreenResourcesCurrent *XRRGetScreenResourcesCurrent;
fpl__func_xrr_XRRFreeScreenResources *XRRFreeScreenResources;
fpl__func_xrr_XRRGetCrtcInfo *XRRGetCrtcInfo;
fpl__func_xrr_XRRFreeCrtcInfo *XRRFreeCrtcInfo;
fpl__func_xrr_XRRGetOutputInfo *XRRGetOutputInfo;
fpl__func_xrr_XRRFreeOutputInfo *XRRFreeOutputInfo;
fpl__func_xrr_XRRGetOutputPrimary *XRRGetOutputPrimary;
} fpl__XrandRApi;
void fpl__UnloadXrandRApi(fpl__XrandRApi *xrandrApi) {
(xrandrApi != );
if (xrandrApi->libHandle != ) {
dlclose(xrandrApi->libHandle);
}
(xrandrApi);
}
bool fpl__LoadXrandRApi(fpl__XrandRApi *xrandrApi) {
(xrandrApi != );
const char *libFileNames[] = {
"libXrandr.so.2",
"libXrandr.so",
};
bool result = false;
for (uint32_t index = 0; index < (libFileNames); ++index) {
const char *libName = libFileNames[index];
(xrandrApi);
do {
void *libHandle = ;
FPL__POSIX_LOAD_LIBRARY(FPL__MODULE_XRANDR, libHandle, libName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRQueryExtension, XRRQueryExtension);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRGetScreenResourcesCurrent, XRRGetScreenResourcesCurrent);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRFreeScreenResources, XRRFreeScreenResources);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRGetCrtcInfo, XRRGetCrtcInfo);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRFreeCrtcInfo, XRRFreeCrtcInfo);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRGetOutputInfo, XRRGetOutputInfo);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRFreeOutputInfo, XRRFreeOutputInfo);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XRANDR, libHandle, libName, xrandrApi, fpl__func_xrr_XRRGetOutputPrimary, XRRGetOutputPrimary);
xrandrApi->libHandle = libHandle;
result = true;
} while (0);
if (result) {
break;
}
fpl__UnloadXrandRApi(xrandrApi);
}
return(result);
}
//
// Xinerama Api (optional)
//
typedef struct fpl__XineramaScreenInfo {
int screen_number;
short x_org;
short y_org;
short width;
short height;
} fpl__XineramaScreenInfo;
#define FPL__FUNC_XINERAMA_XineramaQueryExtension(name) fpl__X11_Bool name(fpl__X11_Display *dpy, int *event_base, int *error_base)
typedef FPL__FUNC_XINERAMA_XineramaQueryExtension(fpl__func_xinerama_XineramaQueryExtension);
#define FPL__FUNC_XINERAMA_XineramaIsActive(name) fpl__X11_Bool name(fpl__X11_Display *dpy)
typedef FPL__FUNC_XINERAMA_XineramaIsActive(fpl__func_xinerama_XineramaIsActive);
#define FPL__FUNC_XINERAMA_XineramaQueryScreens(name) fpl__XineramaScreenInfo *name(fpl__X11_Display *dpy, int *number)
typedef FPL__FUNC_XINERAMA_XineramaQueryScreens(fpl__func_xinerama_XineramaQueryScreens);
// Direct extern declarations for non-runtime-linking builds (no X11 headers present)
// The Xinerama library exports C symbols - C linkage is required so C++ builds do not mangle them
#if defined(FPL_NO_RUNTIME_LINKING)
#if defined(__cplusplus)
extern "C" {
#endif
extern FPL__FUNC_XINERAMA_XineramaIsActive(XineramaIsActive);
extern FPL__FUNC_XINERAMA_XineramaQueryExtension(XineramaQueryExtension);
extern FPL__FUNC_XINERAMA_XineramaQueryScreens(XineramaQueryScreens);
#if defined(__cplusplus)
}
#endif
#endif
typedef struct fpl__XineramaApi {
void *libHandle;
fpl__func_xinerama_XineramaQueryExtension *XineramaQueryExtension;
fpl__func_xinerama_XineramaIsActive *XineramaIsActive;
fpl__func_xinerama_XineramaQueryScreens *XineramaQueryScreens;
} fpl__XineramaApi;
void fpl__UnloadXineramaApi(fpl__XineramaApi *xineramaApi) {
(xineramaApi != );
if (xineramaApi->libHandle != ) {
dlclose(xineramaApi->libHandle);
}
(xineramaApi);
}
bool fpl__LoadXineramaApi(fpl__XineramaApi *xineramaApi) {
(xineramaApi != );
const char *libFileNames[] = {
"libXinerama.so.1",
"libXinerama.so",
};
bool result = false;
for (uint32_t index = 0; index < (libFileNames); ++index) {
const char *libName = libFileNames[index];
(xineramaApi);
do {
void *libHandle = ;
FPL__POSIX_LOAD_LIBRARY(FPL__MODULE_XINERAMA, libHandle, libName);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XINERAMA, libHandle, libName, xineramaApi, fpl__func_xinerama_XineramaQueryExtension, XineramaQueryExtension);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XINERAMA, libHandle, libName, xineramaApi, fpl__func_xinerama_XineramaIsActive, XineramaIsActive);
FPL__POSIX_GET_FUNCTION_ADDRESS(FPL__MODULE_XINERAMA, libHandle, libName, xineramaApi, fpl__func_xinerama_XineramaQueryScreens, XineramaQueryScreens);
xineramaApi->libHandle = libHandle;
result = true;
} while (0);
if (result) {
break;
}
fpl__UnloadXineramaApi(xineramaApi);
}
return(result);
}
typedef struct fpl__X11SubplatformState {
fpl__X11Api api;
fpl__XrandRApi xrandr;
fpl__XineramaApi xinerama;
} fpl__X11SubplatformState;
typedef struct fpl__X11WindowStateInfo {
state;
visibility;
fplWindowPosition position;
fplWindowSize size;
} fpl__X11WindowStateInfo;
typedef struct fpl__X11Xdnd {
int version;
fpl__X11_Window source;
fpl__X11_Atom format;
} fpl__X11Xdnd;
typedef struct fpl__X11WindowState {
fpl__X11WindowStateInfo lastWindowStateInfo;
fpl__X11_Colormap colorMap;
fpl__X11_Display *display;
fpl__X11Xdnd xdnd;
fpl__X11_Window root;
fpl__X11_Window window;
fpl__X11_Visual *visual;
fpl__X11_Atom wmProtocols;
fpl__X11_Atom wmDeleteWindow;
fpl__X11_Atom wmState;
fpl__X11_Atom netWMPing;
fpl__X11_Atom netWMState;
fpl__X11_Atom netWMStateFocused;
fpl__X11_Atom netWMStateFullscreen;
fpl__X11_Atom netWMStateHidden;
fpl__X11_Atom netWMStateMaximizedVert;
fpl__X11_Atom netWMStateMaximizedHorz;
fpl__X11_Atom netWMPid;
fpl__X11_Atom netWMIcon;
fpl__X11_Atom netWMName;
fpl__X11_Atom netWMIconName;
fpl__X11_Atom utf8String;
fpl__X11_Atom motifWMHints;
// drag and drop
fpl__X11_Atom xdndAware;
fpl__X11_Atom xdndEnter;
fpl__X11_Atom xdndPosition;
fpl__X11_Atom xdndStatus;
fpl__X11_Atom xdndActionCopy;
fpl__X11_Atom xdndDrop;
fpl__X11_Atom xdndFinished;
fpl__X11_Atom xdndSelection;
fpl__X11_Atom xdndTypeList;
fpl__X11_Atom textUriList;
// Window styles
fpl__X11_Atom netWMStateAbove;
// Cursor
fpl__X11_Cursor invisibleCursor;
bool cursorEnabled;
// Clipboard
fpl__X11_Atom clipboardAtom;
fpl__X11_Atom targetsAtom;
fpl__X11_Atom incrAtom;
fpl__X11_Atom selectionPropAtom;
char clipboardOut[];
size_t clipboardOutLen;
int screen;
int colorDepth;
} fpl__X11WindowState;
#define FPL__XDND_VERSION 5
#endif // FPL_SUBPLATFORM_X11
// ****************************************************************************
//
// > PLATFORM_STATES
//
// - Defines the final PlatformInitState and PlatformAppState
// - Declares all required global variables
//
// ****************************************************************************
#if !defined(FPL__PLATFORM_STATES_DEFINED)
#define FPL__PLATFORM_STATES_DEFINED
//
// Backend state
//
typedef struct {
void *mem;
size_t memSize;
size_t maxBackendSize;
uintptr_t offsetToBackend;
} fpl__PlatformBackendState;
//
// Platform initialization state
//
typedef struct {
memorySettings;
} fpl__PlatformInitSettings;
typedef struct {
size_t size;
// Current offset of the memory block, for the next memory pointer to start at
uintptr_t offset;
} fpl__PlatformMemoryBlock;
//
// Platform memory block
//
uintptr_t fpl__PushPlatformMemory(fpl__PlatformMemoryBlock *block, const size_t size, const size_t alignment, const size_t padding) {
uintptr_t offset = block->offset;
size_t alignedSize = (size, alignment);
size_t addonSize = padding + alignedSize;
block->size += addonSize;
block->offset += alignedSize + padding;
return offset;
}
typedef struct {
fpl__PlatformMemoryBlock memoryBlocks[16];
#if defined(FPL_SUBPLATFORM_POSIX)
fpl__PosixInitState posix;
#endif
fpl__PlatformInitSettings initSettings;
initResult;
isInitialized;
union {
# if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32InitState win32;
# elif defined(FPL_PLATFORM_LINUX)
fpl__LinuxInitState plinux;
# elif defined(FPL_PLATFORM_UNIX)
fpl__UnixInitState punix;
# endif
};
} fpl__PlatformInitState;
fpl__PlatformInitState fpl__global__InitState = ;
// Event queue is shared by window and (no-window) input subsystems. Available whenever input or window is enabled.
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT)
#define FPL__MAX_EVENT_COUNT 32768
typedef struct {
events[FPL__MAX_EVENT_COUNT];
volatile size_t pushIndex; // atomic
volatile size_t popIndex; // atomic
} fpl__EventQueue;
#endif // FPL__ENABLE_WINDOW || FPL__ENABLE_INPUT
#if defined(FPL__ENABLE_WINDOW)
typedef struct {
keyMap[256];
keyStates[256];
uint64_t keyPressTimes[256];
mouseStates[5];
isRunning;
#if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32WindowState win32;
#endif
#if defined(FPL_SUBPLATFORM_X11)
fpl__X11WindowState x11;
#endif
} fpl__PlatformWindowState;
#endif // FPL__ENABLE_WINDOW
//
// Platform application state
//
#if defined(FPL__ENABLE_INPUT)
// Native event payload kinds used by the window-to-input bridge. Payload pointer interpretation depends on kind.
typedef enum fpl__NativeInputEventKind {
fpl__NativeInputEventKind_None = 0,
fpl__NativeInputEventKind_Win32Msg,
fpl__NativeInputEventKind_X11Event,
fpl__NativeInputEventKind_Custom,
} fpl__NativeInputEventKind;
// Neutral wrapper carrying a native input event from the window backend to the input subsystem.
typedef struct fpl__NativeInputEvent {
fpl__NativeInputEventKind kind;
void *payload;
} fpl__NativeInputEvent;
// Holds settings, tracks initialization, and embeds active backend instances.
typedef struct fpl__InputContext {
fplInputSettings settings;
initFlags;
bool isInitialized;
uint32_t backendCount;
#if defined(FPL__ENABLE_INPUT_XINPUT)
fpl__InputBackendXInput xinput;
#endif
#if defined(FPL__ENABLE_INPUT_DINPUT)
fpl__InputBackendDInput dinput;
#endif
#if defined(FPL__ENABLE_INPUT_WIN32)
fpl__InputBackendWin32 win32kbm;
#endif
#if defined(FPL__ENABLE_INPUT_X11)
fpl__InputBackendX11Kbm x11kbm;
#endif
#if defined(FPL__ENABLE_INPUT_LINUX_JOYSTICK)
fpl__InputBackendLinuxJoystick linuxJoystick;
#endif
} fpl__InputContext;
// Forward declarations for fpl__InputSystem_* — definitions live in the SYSTEM_INIT section.
bool fpl__InputSystem_Init(fpl__InputContext *ctx, const initFlags, const *settings);
void fpl__InputSystem_Release(fpl__InputContext *ctx);
void fpl__InputSystem_Update(fpl__InputContext *ctx);
bool fpl__InputSystem_HandleNativeEvent(fpl__InputContext *ctx, const fpl__NativeInputEvent *ev);
bool fpl__InputSystem_IsEnabled(const fpl__InputContext *ctx, source);
bool fpl__InputSystem_PollGamepad(fpl__InputContext *ctx, *outStates);
bool fpl__InputSystem_PollKeyboard(fpl__InputContext *ctx, *outState);
bool fpl__InputSystem_PollMouse(fpl__InputContext *ctx, *outState);
#endif // FPL__ENABLE_INPUT
typedef struct fpl__PlatformAppState fpl__PlatformAppState;
struct fpl__PlatformAppState {
// Subplatforms
#if defined(FPL_SUBPLATFORM_POSIX)
fpl__PosixAppState posix;
#endif
#if defined(FPL_SUBPLATFORM_X11)
fpl__X11SubplatformState x11;
#endif
// Event queue (shared by window + input)
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT)
fpl__EventQueue eventQueue;
#endif
// Window/video/audio
#if defined(FPL__ENABLE_WINDOW)
fpl__PlatformWindowState window;
#endif
#if defined(FPL__ENABLE_VIDEO)
fpl__PlatformBackendState video;
#endif
#if defined(FPL__ENABLE_AUDIO)
fpl__PlatformBackendState audio;
#endif
#if defined(FPL__ENABLE_INPUT)
fpl__InputContext input;
#endif
// Settings
fplSettings initSettings;
fplSettings currentSettings;
initFlags;
// Platforms
union {
# if defined(FPL_PLATFORM_WINDOWS)
fpl__Win32AppState win32;
# elif defined(FPL_PLATFORM_LINUX)
fpl__LinuxAppState plinux;
# elif defined(FPL_PLATFORM_UNIX)
fpl__UnixAppState punix;
# endif
};
};
//
// Internal event queue (shared by window + input subsystems)
//
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT)
size_t fpl__HasInternalEvents(void) {
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__EventQueue *eventQueue = &appState->eventQueue;
size_t currentPop = (&eventQueue->popIndex);
size_t currentPush = (&eventQueue->pushIndex);
bool result = currentPop < currentPush;
return result;
}
void fpl__ClearInternalEvents(void) {
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__EventQueue *eventQueue = &appState->eventQueue;
size_t currentPop = (&eventQueue->popIndex);
size_t currentPush = (&eventQueue->pushIndex);
for (size_t i = currentPop; i < currentPush; ++i) {
*ev = &eventQueue->events[i % FPL__MAX_EVENT_COUNT];
if (ev-> == && ev->. == ) {
if (ev->... != ) {
fpl__ReleaseDynamicMemory(ev->...);
(&ev->..);
}
}
}
(&eventQueue->popIndex, 0);
(&eventQueue->pushIndex, 0);
}
bool fpl__PollInternalEvent( *ev) {
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__EventQueue *eventQueue = &appState->eventQueue;
size_t currentPop;
size_t currentPush;
size_t newPop;
do {
currentPop = (&eventQueue->popIndex);
currentPush = (&eventQueue->pushIndex);
if (currentPop >= currentPush) {
return false;
}
newPop = currentPop + 1;
} while (!(&eventQueue->popIndex, currentPop, newPop));
size_t index = currentPop % FPL__MAX_EVENT_COUNT;
*ev = eventQueue->events[index];
return true;
}
void fpl__PushInternalEvent(const *event) {
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__EventQueue *eventQueue = &appState->eventQueue;
size_t currentPush;
size_t currentPop;
size_t newPush;
do {
currentPush = (&eventQueue->pushIndex);
currentPop = (&eventQueue->popIndex);
if ((currentPush - currentPop) >= FPL__MAX_EVENT_COUNT) {
// Queue full, drop event or handle overflow
return;
}
newPush = currentPush + 1;
} while (!(&eventQueue->pushIndex, currentPush, newPush));
size_t index = currentPush % FPL__MAX_EVENT_COUNT;
eventQueue->events[index] = *event;
}
void fpl__PushGamepadConnectionEvent(const uint32_t deviceIndex, const char *deviceName, const bool isConnected) {
ev = ;
ev. = ;
ev.. = isConnected ? : ;
ev.. = deviceIndex;
ev.. = deviceName;
ev... = isConnected;
ev... = deviceName;
fpl__PushInternalEvent(&ev);
}
void fpl__PushGamepadStateEvent(const uint32_t deviceIndex, const char *deviceName, const *newState) {
ev = ;
ev. = ;
ev.. = ;
ev.. = deviceIndex;
ev.. = deviceName;
ev.. = *newState;
fpl__PushInternalEvent(&ev);
}
// Threshold above which an analog input is treated as a digital press inside fplGamepadMappingApply.
#define FPL__GAMEPAD_DIGITAL_THRESHOLD 0.5f
// Per-axis deadzone applied to thumb sticks inside fplGamepadMappingApply. Below this magnitude the stick component is forced to zero, above it the remaining range is rescaled to (0..1] so small motions feel responsive without leaking center jitter. Set to 0.0f to disable while diagnosing raw stick behavior.
#define FPL__GAMEPAD_STICK_DEADZONE 0.01f
// Returns the digital (button-style) reading produced by a single binding against the given raw input.
bool fpl__GamepadEvalBindingDigital(const *b, const *in) {
switch (b->) {
case : {
if (b-> >= in->) {
return false;
}
return in->[b->];
}
case : {
if (b-> >= in->) {
return false;
}
return (in->[b->] & (uint8_t)b->) != 0;
}
case : {
if (b-> >= in->) {
return false;
}
float v = in->[b->];
if (b->) {
v = -v;
}
if (b-> == ) {
v = -v;
}
return v > FPL__GAMEPAD_DIGITAL_THRESHOLD;
}
default: {
return false;
}
}
}
// Returns the analog (axis-style) reading produced by a single binding against the given raw input.
float fpl__GamepadEvalBindingAnalog(const *b, const *in) {
switch (b->) {
case : {
if (b-> >= in->) {
return 0.0f;
}
return in->[b->] ? 1.0f : 0.0f;
}
case : {
if (b-> >= in->) {
return 0.0f;
}
return (in->[b->] & (uint8_t)b->) ? 1.0f : 0.0f;
}
case : {
if (b-> >= in->) {
return 0.0f;
}
float v = in->[b->];
if (b->) {
v = -v;
}
// Half-axis: remap [-1..+1] to [0..1] using only the requested half (used by triggers).
if (b-> == ) {
return (v + 1.0f) * 0.5f;
}
if (b-> == ) {
return (-v + 1.0f) * 0.5f;
}
return v;
}
default: {
return 0.0f;
}
}
}
// Trigger axes follow SDL convention: when a full-range axis (no `+`/`-` prefix) is bound to a trigger destination, the source idles at -1 and pulls to +1. Remap to the [0..1] range expected by fplGamepadState. Half-axis (+/-) bindings already produce 0..1 from fpl__GamepadEvalBindingAnalog, so pass them through unchanged. Non-axis bindings (e.g. trigger as button) also pass through.
float fpl__GamepadEvalTrigger(const *b, const *in) {
float v = fpl__GamepadEvalBindingAnalog(b, in);
if (b-> == && b-> == ) {
v = (v + 1.0f) * 0.5f;
}
if (v < 0.0f) {
v = 0.0f;
} else if (v > 1.0f) {
v = 1.0f;
}
return v;
}
// Applies a per-axis deadzone to a single stick component: values within FPL__GAMEPAD_STICK_DEADZONE collapse to 0, values beyond are rescaled so the remaining range still spans 0..1. Avoids pulling in math.h for sqrt; the tiny corner artifact of a non-radial deadzone is acceptable for stick centering.
float fpl__GamepadApplyStickDeadzone(float v) {
float dz = FPL__GAMEPAD_STICK_DEADZONE;
float a = v < 0.0f ? -v : v;
if (a <= dz) {
return 0.0f;
}
float scaled = (a - dz) / (1.0f - dz);
if (scaled > 1.0f) {
scaled = 1.0f;
}
return v < 0.0f ? -scaled : scaled;
}
bool (const *mapping, const *input, *outState) {
if (mapping == || input == || outState == ) {
return false;
}
for (size_t i = 0; i < (mapping->); ++i) {
const *b = &mapping->[i];
bool down = (b-> != ) && fpl__GamepadEvalBindingDigital(b, input);
outState->[i]. = down ? 1 : 0;
}
// SDL's stick convention is +Y = down. fplGamepadState uses +Y = up (XInput convention) so the Y axes are negated here. Mappings authored with `~` (axisInverted) reverse it inside fpl__GamepadEvalBindingAnalog.
outState-> = fpl__GamepadApplyStickDeadzone( fpl__GamepadEvalBindingAnalog(&mapping->[], input));
outState-> = fpl__GamepadApplyStickDeadzone(-fpl__GamepadEvalBindingAnalog(&mapping->[], input));
outState-> = fpl__GamepadApplyStickDeadzone( fpl__GamepadEvalBindingAnalog(&mapping->[], input));
outState-> = fpl__GamepadApplyStickDeadzone(-fpl__GamepadEvalBindingAnalog(&mapping->[], input));
outState-> = fpl__GamepadEvalTrigger(&mapping->[], input);
outState-> = fpl__GamepadEvalTrigger(&mapping->[], input);
return true;
}
bool (const *input, *outState) {
if (input == || outState == ) {
return false;
}
// Sticks (DInput convention: Z = right X, RZ = right Y; Y inverted to XInput sense).
if (input-> > 0) {
outState-> = input->[0];
}
if (input-> > 1) {
outState-> = -input->[1];
}
if (input-> > 2) {
outState-> = input->[2];
}
if (input-> > 5) {
outState-> = -input->[5];
}
// Triggers map from -1..+1 to 0..1 to match XInput sense.
if (input-> > 6) {
outState-> = (input->[6] + 1.0f) * 0.5f;
}
if (input-> > 7) {
outState-> = (input->[7] + 1.0f) * 0.5f;
}
// Buttons by SDL's unknown-DInput convention.
static const struct { uint32_t btn; size_t off; } map[] = {
{ 0, (, actionA) },
{ 1, (, actionB) },
{ 2, (, actionX) },
{ 3, (, actionY) },
{ 4, (, leftShoulder) },
{ 5, (, rightShoulder) },
{ 8, (, back) },
{ 9, (, start) },
{ 10, (, leftThumb) },
{ 11, (, rightThumb) },
};
for (size_t i = 0; i < (map); ++i) {
if (map[i].btn < input->buttonCount && input->[map[i].btn]) {
*btn = ( *)((uint8_t *)outState + map[i].off);
btn-> = 1;
}
}
// Hat 0 → dpad.
if (input-> > 0) {
uint8_t h = input->[0];
outState->. = (h & 0x1) != 0;
outState->. = (h & 0x2) != 0;
outState->. = (h & 0x4) != 0;
outState->. = (h & 0x8) != 0;
}
return true;
}
// Recomputes isActive for the given state by inspecting analog axes and digital buttons. Used by raw-HID backends after producing a state via fplGamepadMappingApply / fplGamepadMappingApplyDefault.
void fpl__GamepadFinalizeState( *state) {
bool active = false;
if (state-> != 0.0f || state-> != 0.0f) {
active = true;
}
if (state-> != 0.0f || state-> != 0.0f) {
active = true;
}
if (state-> != 0.0f || state-> != 0.0f) {
active = true;
}
for (int i = 0; i < ; ++i) {
if (state->[i].) {
active = true;
break;
}
}
state-> = active;
}
// Builds a 16-byte SDL-style gamepad GUID from a USB VID/PID/version triple. Used by raw-HID backends (DInput, Linux joydev, etc.) when filling fplGamepadInfo for the resolver.
void fpl__GamepadBuildSDLGuid(const uint16_t bus, const uint16_t vid, const uint16_t pid, const uint16_t version, const uint16_t nameCrc16, outGuid) {
outGuid[0] = (uint8_t)(bus & 0xFF);
outGuid[1] = (uint8_t)((bus >> 8) & 0xFF);
outGuid[2] = (uint8_t)(nameCrc16 & 0xFF);
outGuid[3] = (uint8_t)((nameCrc16 >> 8) & 0xFF);
outGuid[4] = (uint8_t)(vid & 0xFF);
outGuid[5] = (uint8_t)((vid >> 8) & 0xFF);
outGuid[6] = 0;
outGuid[7] = 0;
outGuid[8] = (uint8_t)(pid & 0xFF);
outGuid[9] = (uint8_t)((pid >> 8) & 0xFF);
outGuid[10] = 0;
outGuid[11] = 0;
outGuid[12] = (uint8_t)(version & 0xFF);
outGuid[13] = (uint8_t)((version >> 8) & 0xFF);
outGuid[14] = 0;
outGuid[15] = 0;
}
// Keyboard / mouse event push primitives. Live in the WINDOW || INPUT block (rather than the
// window-only block below) so the no-window input backends can push events directly without
// requiring a window state. The window-only fpl__Handle*Event wrappers below add keymap lookup
// + repeat tracking on top of these primitives.
void fpl__PushKeyboardButtonEvent(const uint64_t keyCode, const mappedKey, const modifiers, const buttonState) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent.. = keyCode;
newEvent.. = modifiers;
newEvent.. = buttonState;
newEvent.. = mappedKey;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushKeyboardInputEvent(const uint32_t textCode, const mappedKey) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent.. = (uint64_t)textCode;
newEvent.. = mappedKey;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushMouseButtonEvent(const int32_t x, const int32_t y, const mouseButton, const buttonState) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent.. = x;
newEvent.. = y;
newEvent.. = mouseButton;
newEvent.. = buttonState;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushMouseWheelEvent(const int32_t x, const int32_t y, const float wheelDelta) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent.. = ;
newEvent.. = x;
newEvent.. = y;
newEvent.. = wheelDelta;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushMouseMoveEvent(const int32_t x, const int32_t y) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent.. = ;
newEvent.. = x;
newEvent.. = y;
fpl__PushInternalEvent(&newEvent);
}
#endif // FPL__ENABLE_WINDOW || FPL__ENABLE_INPUT
//
// Internal window
//
#if defined(FPL__ENABLE_WINDOW)
fpl__GetMappedKey(const fpl__PlatformWindowState *windowState, const uint64_t keyCode) {
result;
if (keyCode < (windowState->keyMap))
result = windowState->keyMap[keyCode];
else
result = ;
return(result);
}
void fpl__PushWindowStateEvent(const windowType) {
newEvent = ;
newEvent. = ;
newEvent.. = windowType;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushWindowSizeEvent(const windowType, uint32_t w, uint32_t h) {
newEvent = ;
newEvent. = ;
newEvent.. = windowType;
newEvent... = w;
newEvent... = h;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushWindowPositionEvent(const windowType, int32_t x, int32_t y) {
newEvent = ;
newEvent. = ;
newEvent.. = windowType;
newEvent... = x;
newEvent... = y;
fpl__PushInternalEvent(&newEvent);
}
void fpl__PushWindowDropFilesEvent(const char *filePath, const size_t fileCount, const char **files, const *memory) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
newEvent... = fileCount;
newEvent... = files;
newEvent... = *memory;
fpl__PushInternalEvent(&newEvent);
}
void fpl__HandleKeyboardButtonEvent(fpl__PlatformWindowState *windowState, const uint64_t time, const uint64_t keyCode, const modifiers, const buttonState, const bool force) {
#if defined(FPL_LOG_KEY_EVENTS)
const char *buttonStateName = "";
if (buttonState == )
buttonStateName = "Press";
else if (buttonState == )
buttonStateName = "Repeat";
else
buttonStateName = "Released";
FPL_LOG_TRACE(FPL__MODULE_OS, "[%llu] Keyboard button event with keycode: '%llu', state: '%s'", time, keyCode, buttonStateName);
#endif
mappedKey = fpl__GetMappedKey(windowState, keyCode);
bool repeat = false;
if (force) {
repeat = (buttonState == );
windowState->keyStates[keyCode] = buttonState;
} else {
if (keyCode < (windowState->keyStates)) {
if ((buttonState == ) && (windowState->keyStates[keyCode] == )) {
return;
}
if ((buttonState == ) && (windowState->keyStates[keyCode] >= )) {
repeat = true;
}
windowState->keyStates[keyCode] = buttonState;
}
}
fpl__PushKeyboardButtonEvent(keyCode, mappedKey, modifiers, repeat ? : buttonState);
}
void fpl__HandleKeyboardInputEvent(fpl__PlatformWindowState *windowState, const uint64_t keyCode, const uint32_t textCode) {
mappedKey = fpl__GetMappedKey(windowState, keyCode);
fpl__PushKeyboardInputEvent(textCode, mappedKey);
}
void fpl__HandleMouseButtonEvent(fpl__PlatformWindowState *windowState, const int32_t x, const int32_t y, const mouseButton, const buttonState) {
if (mouseButton < (windowState->mouseStates)) {
windowState->mouseStates[(int)mouseButton] = buttonState;
}
fpl__PushMouseButtonEvent(x, y, mouseButton, buttonState);
}
void fpl__HandleMouseMoveEvent(fpl__PlatformWindowState *windowState, const int32_t x, const int32_t y) {
fpl__PushMouseMoveEvent(x, y);
}
void fpl__HandleMouseWheelEvent(fpl__PlatformWindowState *windowState, const int32_t x, const int32_t y, const float wheelDelta) {
fpl__PushMouseWheelEvent(x, y, wheelDelta);
}
// @NOTE(final): Callback used for setup a window before it is created
#define FPL__FUNC_PREPARE_VIDEO_WINDOW(name) bool name(fpl__PlatformAppState *appState, const fplInitFlags initFlags, const fplSettings *initSettings)
typedef FPL__FUNC_PREPARE_VIDEO_WINDOW(callback_PreSetupWindow);
// @NOTE(final): Callback used for setup a window after it was created
#define FPL__FUNC_FINALIZE_VIDEO_WINDOW(name) bool name(fpl__PlatformAppState *appState, const fplInitFlags initFlags, const fplSettings *initSettings)
typedef FPL__FUNC_FINALIZE_VIDEO_WINDOW(callback_PostSetupWindow);
typedef struct fpl__SetupWindowCallbacks {
callback_PreSetupWindow *preSetup;
callback_PostSetupWindow *postSetup;
} fpl__SetupWindowCallbacks;
#endif // FPL__ENABLE_WINDOW
#endif // FPL__PLATFORM_STATES_DEFINED
// ****************************************************************************
//
// > COMMON (Common Implementations)
//
// - Standard C library includes
// - Internal macros
// - Error state handling
// - Threading state handling
// - CommonAudioState
// - Common Implementations (Strings, Memory, Atomics, Path, etc.)
//
// ****************************************************************************
#if !defined(FPL__COMMON_DEFINED)
#define FPL__COMMON_DEFINED
//
// Internal memory
//
void *fpl__AllocateDynamicMemory(const size_t size, const size_t alignment) {
void *result = fpl__AllocateMemory(&fpl__global__InitState.initSettings.memorySettings.dynamic, size, alignment);
return(result);
}
void fpl__ReleaseDynamicMemory(void *ptr) {
fpl__ReleaseMemory(&fpl__global__InitState.initSettings.memorySettings.dynamic, ptr);
}
void *fpl__AllocateTemporaryMemory(const size_t size, const size_t alignment) {
void *result = fpl__AllocateMemory(&fpl__global__InitState.initSettings.memorySettings.temporary, size, alignment);
return(result);
}
void fpl__ReleaseTemporaryMemory(void *ptr) {
fpl__ReleaseMemory(&fpl__global__InitState.initSettings.memorySettings.temporary, ptr);
}
//
// Audio constants
//
static const uint32_t FPL__DEFAULT_AUDIO_SAMPLERATE = 44100;
static const FPL__DEFAULT_AUDIO_FORMAT = ;
static const uint16_t FPL__DEFAULT_AUDIO_CHANNELS = 2;
static const uint16_t FPL__DEFAULT_AUDIO_PERIODS = 3;
static const uint32_t FPL__DEFAULT_AUDIO_BUFFERSIZE_LOWLATENCY_IN_MSECS = 10;
static const uint32_t FPL__DEFAULT_AUDIO_BUFFERSIZE_CONSERVATIVE_IN_MSECS = 25;
//
// Internal types and functions
//
#define FPL__MAX_LAST_ERROR_STRING_LENGTH 256
#define FPL__MAX_ERRORSTATE_COUNT 256
typedef struct fpl__ErrorState {
char errors[FPL__MAX_ERRORSTATE_COUNT][FPL__MAX_LAST_ERROR_STRING_LENGTH];
// Monotonic total error count. Slot index = (count - 1) % FPL__MAX_ERRORSTATE_COUNT.
volatile uint32_t count;
} fpl__ErrorState;
fpl__ErrorState fpl__global__LastErrorState = ;
void fpl__PushError_Formatted(const char *funcName, const int lineNumber, const level, const char *format, va_list argList) {
(format != );
if (level <= ) {
fpl__ErrorState *state = &fpl__global__LastErrorState;
char buffer[FPL__MAX_LAST_ERROR_STRING_LENGTH] = ;
size_t formattedLen = (buffer, (buffer), format, argList);
if (formattedLen > 0) {
// Atomically claim a unique ring slot so concurrent writers do not collide.
uint32_t prevTotal = (&state->count, 1);
size_t errorIndex = (size_t)(prevTotal % FPL__MAX_ERRORSTATE_COUNT);
(buffer, formattedLen, state->errors[errorIndex], FPL__MAX_LAST_ERROR_STRING_LENGTH);
}
}
#if defined(FPL__ENABLE_LOGGING)
va_list listCopy;
va_copy(listCopy, argList);
fpl__LogWriteArgs(funcName, lineNumber, level, format, listCopy);
va_end(listCopy);
#endif
}
void fpl__HandleError(const char *funcName, const int lineNumber, const level, const char *format, ...) {
va_list valist;
va_start(valist, format);
fpl__PushError_Formatted(funcName, lineNumber, level, format, valist);
va_end(valist);
#if defined(FPL_CRASH_ON_ERROR) || defined(FPL_CRASH_ON_WARNING)
minErrorLevel = ;
# if defined(FPL_CRASH_ON_WARNING)
minErrorLevel = ;
# endif
if (level >= minErrorLevel) {
// @NOTE(final): Force a null pointer assignment crash here
*(int *)0 = 0;
}
#endif
}
//
// Argument Errors
//
//
void fpl__ArgumentInvalidError(const char *funcName, const int line, const char *paramName) {
FPL__M_ERROR(funcName, line, FPL__MODULE_ARGS, "%s parameter are not valid", paramName);
}
void fpl__ArgumentNullError(const char *funcName, const int line, const char *paramName) {
FPL__M_ERROR(funcName, line, FPL__MODULE_ARGS, "%s parameter are not allowed to be null", paramName);
}
void fpl__ArgumentZeroError(const char *funcName, const int line, const char *paramName) {
FPL__M_ERROR(funcName, line, FPL__MODULE_ARGS, "%s parameter must be greater than zero", paramName);
}
void fpl__ArgumentMinError(const char *funcName, const int line, const char *paramName, const size_t value, const size_t minValue) {
FPL__M_ERROR(funcName, line, FPL__MODULE_ARGS, "%s parameter '%zu' must be greater or equal than '%zu'", paramName, value, minValue);
}
void fpl__ArgumentMaxError(const char *funcName, const int line, const char *paramName, const size_t value, const size_t maxValue) {
FPL__M_ERROR(funcName, line, FPL__MODULE_ARGS, "%s parameter '%zu' must be less or equal than '%zu'", paramName, value, maxValue);
}
#define FPL__CheckArgumentInvalid(arg, cond, ret) \
if((cond)) { \
fpl__ArgumentInvalidError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return (ret); \
}
#define FPL__CheckArgumentInvalidNoRet(arg, cond) \
if((cond)) { \
fpl__ArgumentInvalidError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return; \
}
#define FPL__CheckArgumentNull(arg, ret) \
if((arg) == fpl_null) { \
fpl__ArgumentNullError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return (ret); \
}
#define FPL__CheckArgumentNullNoRet(arg) \
if((arg) == fpl_null) { \
fpl__ArgumentNullError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return; \
}
#define FPL__CheckArgumentZero(arg, ret) \
if((arg) == 0) { \
fpl__ArgumentZeroError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return (ret); \
}
#define FPL__CheckArgumentZeroNoRet(arg) \
if((arg) == 0) { \
fpl__ArgumentZeroError(FPL_FUNCTION_NAME, __LINE__, #arg); \
return; \
}
#define FPL__CheckArgumentMin(arg, minValue, ret) \
if((arg) < (minValue)) { \
fpl__ArgumentMinError(FPL_FUNCTION_NAME, __LINE__, #arg, arg, minValue); \
return (ret); \
}
#define FPL__CheckArgumentMax(arg, maxValue, ret) \
if((arg) > (maxValue)) { \
fpl__ArgumentMaxError(FPL_FUNCTION_NAME, __LINE__, #arg, arg, maxValue); \
return (ret); \
}
#define FPL__CheckPlatform(ret) \
if(fpl__global__AppState == fpl_null) { \
FPL__ERROR(FPL__MODULE_CORE, "[%s] Platform is not initialized", FPL_FUNCTION_NAME); \
return (ret); \
}
#define FPL__CheckPlatformNoRet() \
if(fpl__global__AppState == fpl_null) { \
FPL__ERROR(FPL__MODULE_CORE, "[%s] Platform is not initialized", FPL_FUNCTION_NAME); \
return; \
}
#define FPL__CheckApi(cond, name, ret) \
if(!(cond)) { \
FPL__ERROR(FPL__MODULE_API, "The API '%s' is not loaded", (name)); \
return (ret); \
}
#define FPL__CheckApiNoRet(cond, name) \
if(!(cond)) { \
FPL__ERROR(FPL__MODULE_API, "The API '%s' is not loaded", (name)); \
return; \
}
#if !defined(FPL_MAX_THREAD_COUNT)
// Maximum number of active threads you can have in your process
# define FPL_MAX_THREAD_COUNT 256
#endif
#if !defined(FPL_MAX_SIGNAL_COUNT)
// Maximum number of active signals you can wait for
# define FPL_MAX_SIGNAL_COUNT 256
#endif
typedef struct fpl__ThreadState {
fplThreadHandle mainThread;
fplThreadHandle threads[FPL_MAX_THREAD_COUNT];
} fpl__ThreadState;
fpl__ThreadState fpl__global__ThreadState = ;
*fpl__GetFreeThread(void) {
*result = ;
for (uint32_t index = 0; index < FPL_MAX_THREAD_COUNT; ++index) {
*thread = fpl__global__ThreadState.threads + index;
state = (thread);
if (state == ) {
result = thread;
break;
}
}
return(result);
}
bool fpl__IsEqualsMemory(const void *a, const void *b, const size_t size) {
const uint8_t *ptrA = (const uint8_t *)a;
const uint8_t *ptrB = (const uint8_t *)b;
size_t s = size;
// @SPEED(final): This may be very slow, so we should use a faster function for comparing memory.
bool result = true;
while (s-- > 0) {
if (*ptrA != *ptrB) {
result = false;
break;
}
ptrA++;
ptrB++;
}
return(result);
}
bool fpl__IsZeroMemory(const void *memory, const size_t size) {
const uint8_t *ptr = (const uint8_t *)memory;
// @SPEED(final): This may be very slow, so we should use a faster function for comparing memory.
bool result = true;
size_t s = size;
while (s-- > 0) {
if (*ptr) {
result = false;
break;
}
ptr++;
}
return(result);
}
//
// Common Strings
//
#if !defined(FPL__COMMON_STRINGS_DEFINED)
#define FPL__COMMON_STRINGS_DEFINED
bool (const char *source, const char *wildcard) {
// Supported patterns:
// * = Match zero or more characters
// ? = Match one character
if (source == || wildcard == ) {
return false;
}
const char *s = source;
const char *w = wildcard;
while (*w) {
if (*w == '?') {
if (!*s) {
return false;
}
++s;
} else if (*w == '*') {
while (*s) {
char nw = w[1];
if (nw != 0) {
if ((*s == nw) || (nw == '?') || (nw == '*')) {
break;
}
}
++s;
}
} else {
if (*s != *w) {
return false;
}
++s;
}
++w;
}
return true;
}
bool (const char *a, const size_t aLen, const char *b, const size_t bLen) {
if ((a == ) || (b == )) {
return false;
}
if (aLen != bLen) {
return false;
}
bool result = true;
for (size_t index = 0; index < aLen; ++index) {
char aChar = a[index];
char bChar = b[index];
if (aChar != bChar) {
result = false;
break;
}
}
return(result);
}
bool (const char *a, const char *b) {
if ((a == ) || (b == )) {
return (a == b);
}
bool result = true;
for (;;) {
const char aChar = *(a++);
const char bChar = *(b++);
if (aChar == 0 || bChar == 0) {
result = (aChar == bChar);
break;
}
if (aChar != bChar) {
result = false;
break;
}
}
return(result);
}
size_t (char *path, size_t maxPathLen) {
FPL__CheckArgumentNull(path, 0);
FPL__CheckArgumentZero(maxPathLen, 0);
size_t len = (path);
if (len == 0) {
return(0);
}
if (path[len - 1] == ) {
return(len);
}
size_t requiredLen = len + 1;
if (requiredLen + 1 > maxPathLen) {
FPL__ERROR(FPL__MODULE_PATHS, "Cannot append path separator: Max length '%zu' of path '%s' is exceeded", maxPathLen, path);
return(0);
}
path[len] = ;
path[len + 1] = 0;
return(requiredLen);
}
size_t (char *path) {
FPL__CheckArgumentNull(path, 0);
size_t len = (path);
if (len == 0) {
return(0);
}
if (path[len - 1] == ) {
return(len);
}
path[len] = ;
path[len + 1] = 0;
return(len + 1);
}
size_t (const char *appended, const size_t appendedLen, char *buffer, size_t maxBufferLen) {
FPL__CheckArgumentNull(appended, 0);
if (appendedLen == 0) {
return(buffer != ? (buffer) : 0);
}
size_t curBufferLen = (buffer != ) ? (buffer) : 0;
size_t requiredLen = curBufferLen + appendedLen;
if (buffer == ) {
return(requiredLen);
}
FPL__CheckArgumentZero(maxBufferLen, 0);
size_t requiredSize = requiredLen + 1;
FPL__CheckArgumentMin(maxBufferLen, requiredSize, 0);
(appended, appendedLen * sizeof(char), buffer + curBufferLen);
buffer[requiredLen] = 0;
return(requiredLen);
}
size_t (const char *appended, char *buffer, size_t maxBufferLen) {
size_t appendedLen = (appended);
return((appended, appendedLen, buffer, maxBufferLen));
}
size_t (const char *str) {
size_t result = 0;
if (str != ) {
while (*str++) {
result++;
}
}
return(result);
}
size_t (const char *source, const size_t sourceLen, char *dest, const size_t maxDestLen) {
FPL__CheckArgumentNull(source, 0);
if (dest == ) {
return(sourceLen);
}
FPL__CheckArgumentZero(maxDestLen, 0);
size_t requiredLen = sourceLen + 1;
FPL__CheckArgumentMin(maxDestLen, requiredLen, 0);
if (sourceLen > 0) {
(source, sourceLen * sizeof(char), dest);
}
dest[sourceLen] = 0;
return(sourceLen);
}
size_t (const char *source, char *dest, const size_t maxDestLen) {
FPL__CheckArgumentNull(source, 0);
size_t sourceLen = (source);
return((source, sourceLen, dest, maxDestLen));
}
size_t (char *destBuffer, const size_t maxDestBufferLen, const char *format, va_list argList) {
FPL__CheckArgumentNull(format, 0);
if (destBuffer != ) {
FPL__CheckArgumentMin(maxDestBufferLen, 1, 0);
}
// First pass: query the required length using a dummy buffer when destBuffer is null/too-small.
va_list listCopy;
va_copy(listCopy, argList);
int charCount = 0;
# if defined(FPL_NO_CRT)
# if defined(FPL_USERFUNC_vsnprintf)
if (destBuffer != ) {
destBuffer[0] = 0;
charCount = FPL_USERFUNC_vsnprintf(destBuffer, maxDestBufferLen, format, listCopy);
} else {
charCount = FPL_USERFUNC_vsnprintf(, 0, format, listCopy);
}
# else
charCount = 0;
# endif
# else
if (destBuffer != ) {
destBuffer[0] = 0;
charCount = vsnprintf(destBuffer, maxDestBufferLen, format, listCopy);
} else {
charCount = vsnprintf(, 0, format, listCopy);
}
# endif
va_end(listCopy);
if (charCount < 0) {
FPL__ERROR(FPL__MODULE_STRINGS, "Format parameter '%s' is invalid, return code was: %d", format, charCount);
if (destBuffer != && maxDestBufferLen > 0) {
destBuffer[0] = 0;
}
return(0);
}
const size_t requiredLen = (size_t)charCount;
if (destBuffer == ) {
// Query mode: return what would be needed.
return(requiredLen);
}
if (requiredLen + 1 > maxDestBufferLen) {
// Too small: do not leave a partially-filled buffer for the caller to consume.
destBuffer[0] = 0;
return(0);
}
destBuffer[requiredLen] = 0;
return(requiredLen);
}
size_t (char *destBuffer, const size_t maxDestBufferLen, const char *format, ...) {
FPL__CheckArgumentNull(format, 0);
va_list argList;
va_start(argList, format);
size_t result = (destBuffer, maxDestBufferLen, format, argList);
va_end(argList);
return(result);
}
size_t (const int32_t value, char *buffer, const size_t maxBufferLen) {
int32_t v = value;
bool isNegative = false;
if (value < 0) {
isNegative = true;
// Convert to unsigned to avoid overflow on INT32_MIN
v = (uint32_t)(-(value + 1)) + 1;
} else {
v = (uint32_t)value;
}
// Count digits
uint32_t tmp = v;
size_t digitCount = 0;
do {
tmp /= 10;
digitCount++;
} while (tmp != 0);
size_t result = digitCount + (isNegative ? 1 : 0);
if (buffer != ) {
size_t requiredLen = result + 1; // include null terminator
FPL__CheckArgumentMin(maxBufferLen, requiredLen, 0);
char *p = buffer;
if (isNegative) {
*p++ = '-';
}
// Go back to the very end, because we are writing the digits back in reverse order
p += digitCount;
char *lastP = p;
const char *digits = "0123456789";
tmp = v;
do {
*--p = digits[tmp % 10];
tmp /= 10;
} while (tmp != 0);
*lastP = 0;
}
return result;
}
bool (const char *str, const size_t len, int32_t *outValue) {
if (str == || len == 0) {
return(false);
}
const char *p = str;
const char *end = str + len;
while (p < end && (*p == ' ' || *p == '\t')) {
++p;
}
bool isNegative = false;
if (p < end && (*p == '-' || *p == '+')) {
isNegative = (*p == '-');
++p;
}
if (p >= end || *p < '0' || *p > '9') {
return(false);
}
const uint32_t signedMaxAbs = (uint32_t)INT32_MAX + 1u;
const uint32_t posMaxAbs = (uint32_t)INT32_MAX;
const uint32_t maxAbs = isNegative ? signedMaxAbs : posMaxAbs;
uint32_t value = 0;
bool overflow = false;
while (p < end && *p) {
char c = *p;
if (c < '0' || c > '9') {
return(false);
}
uint32_t digit = (uint32_t)(c - '0');
if (!overflow) {
if (value > (maxAbs - digit) / 10u) {
overflow = true;
} else {
value = value * 10u + digit;
}
}
++p;
}
int32_t result;
if (overflow) {
result = isNegative ? INT32_MIN : INT32_MAX;
} else if (isNegative) {
result = (value == signedMaxAbs) ? INT32_MIN : -(int32_t)value;
} else {
result = (int32_t)value;
}
if (outValue != ) {
*outValue = result;
}
return(true);
}
bool (const char *str, int32_t *outValue) {
if (str == ) {
return(false);
}
size_t len = (str);
return((str, len, outValue));
}
int32_t (const char *str, const size_t len) {
int32_t result = 0;
(void)(str, len, &result);
return(result);
}
int32_t (const char *str) {
int32_t result = 0;
(void)(str, &result);
return(result);
}
#endif // FPL__COMMON_STRINGS_DEFINED
//
// Common Console
//
#if !defined(FPL__COMMON_CONSOLE_DEFINED)
#define FPL__COMMON_CONSOLE_DEFINED
void (const char *format, ...) {
FPL__CheckArgumentNullNoRet(format);
char buffer[];
va_list argList;
va_start(argList, format);
size_t len = (buffer, (buffer), format, argList);
va_end(argList);
if (len > 0) {
(buffer);
}
}
void (const char *format, ...) {
FPL__CheckArgumentNullNoRet(format);
char buffer[];
va_list argList;
va_start(argList, format);
size_t len = (buffer, (buffer), format, argList);
va_end(argList);
if (len > 0) {
(buffer);
}
}
#endif // FPL__COMMON_CONSOLE_DEFINED
//
// Common Memory
//
#if !defined(FPL__COMMON_MEMORY_DEFINED)
#define FPL__COMMON_MEMORY_DEFINED
void *(const size_t size, const size_t alignment) {
FPL__CheckArgumentZero(size, );
FPL__CheckArgumentZero(alignment, );
uintptr_t mask = alignment - 1;
if ((alignment, mask)) {
FPL__ERROR(FPL__MODULE_MEMORY, "Alignment parameter '%zu' must be a power of two", alignment);
return ;
}
// Allocate empty memory to hold a size of a pointer + alignment padding + the actual data
size_t newSize = sizeof(void *) + (alignment << 1) + size;
void *basePtr = (newSize);
// The resulting address starts after the stored base pointer
void *alignedPtr = (void *)((uint8_t *)basePtr + sizeof(void *));
// Move the resulting address to a aligned one when not aligned
if ((alignment > 1) && (((uintptr_t)alignedPtr & mask) != 0)) {
uintptr_t offset = ((uintptr_t)alignment - ((uintptr_t)alignedPtr & mask));
alignedPtr = (uint8_t *)alignedPtr + offset;
}
// Write the base pointer before the alignment pointer
*(void **)((void *)((uint8_t *)alignedPtr - sizeof(void *))) = basePtr;
// Ensure alignment
((alignedPtr, alignment));
return(alignedPtr);
}
void (void *ptr) {
FPL__CheckArgumentNullNoRet(ptr);
// Free the base pointer which is stored to the left from the given pointer
void *basePtr = *(void **)((void *)((uint8_t *)ptr - sizeof(void *)));
(basePtr != );
(basePtr);
}
#define FPL__MEM_SHIFT_64 3
#define FPL__MEM_MASK_64 0x00000007
#define FPL__MEM_SHIFT_32 2
#define FPL__MEM_MASK_32 0x00000003
#define FPL__MEM_SHIFT_16 1
#define FPL__MEM_MASK_16 0x0000000
// Clearing memory in chunks
#define FPL__MEMORY_SET(T, memory, size, shift, mask, value) \
do { \
size_t setBytes = 0; \
if (sizeof(T) > sizeof(uint8_t)) { \
T setValue = 0; \
for (uint32_t bytesIncrement = 0; bytesIncrement < sizeof(T); ++bytesIncrement) { \
uint32_t bitShift = bytesIncrement * 8; \
setValue |= ((T)value << bitShift); \
} \
T *dataBlock = (T *)(memory); \
T *dataBlockEnd = (T *)(memory) + (size >> shift); \
while (dataBlock < dataBlockEnd) { \
*dataBlock++ = setValue; \
setBytes += sizeof(T); \
} \
} \
uint8_t *data8 = (uint8_t *)memory + setBytes; \
uint8_t *data8End = (uint8_t *)memory + size; \
while (data8 < data8End) { \
*data8++ = value; \
} \
} while (0);
#define FPL__MEMORY_CLEAR(T, memory, size, shift, mask) \
do { \
size_t clearBytes = 0; \
if (sizeof(T) > sizeof(uint8_t)) { \
T *dataBlock = (T *)(memory); \
T *dataBlockEnd = (T *)(memory) + (size >> shift); \
while (dataBlock < dataBlockEnd) { \
*dataBlock++ = 0; \
clearBytes += sizeof(T); \
} \
} \
uint8_t *data8 = (uint8_t *)memory + clearBytes; \
uint8_t *data8End = (uint8_t *)memory + size; \
while (data8 < data8End) { \
*data8++ = 0; \
} \
} while (0);
#define FPL__MEMORY_COPY(T, source, sourceSize, dest, shift, mask) \
do { \
size_t copiedBytes = 0; \
if (sizeof(T) > sizeof(uint8_t)) { \
const T *sourceDataBlock = (const T *)(source); \
const T *sourceDataBlockEnd = (const T *)(source) + (sourceSize >> shift); \
T *destDataBlock = (T *)(dest); \
while (sourceDataBlock < sourceDataBlockEnd) { \
*destDataBlock++ = *sourceDataBlock++; \
copiedBytes += sizeof(T); \
} \
} \
const uint8_t *sourceData8 = (const uint8_t *)source + copiedBytes; \
const uint8_t *sourceData8End = (const uint8_t *)source + sourceSize; \
uint8_t *destData8 = (uint8_t *)dest + copiedBytes; \
while (sourceData8 < sourceData8End) { \
*destData8++ = *sourceData8++; \
} \
} while (0);
void (void *mem, const uint8_t value, const size_t size) {
FPL__CheckArgumentNullNoRet(mem);
FPL__CheckArgumentZeroNoRet(size);
#if defined(FPL__ENABLE_MEMORY_MACROS)
if (size % 8 == 0) {
FPL__MEMORY_SET(uint64_t, mem, size, FPL__MEM_SHIFT_64, FPL__MEM_MASK_64, value);
} else if (size % 4 == 0) {
FPL__MEMORY_SET(uint32_t, mem, size, FPL__MEM_SHIFT_32, FPL__MEM_MASK_32, value);
} else if (size % 2 == 0) {
FPL__MEMORY_SET(uint16_t, mem, size, FPL__MEM_SHIFT_16, FPL__MEM_MASK_16, value);
} else {
FPL__MEMORY_SET(uint8_t, mem, size, 0, 0, value);
}
#elif defined(FPL_PLATFORM_WINDOWS)
FillMemory(mem, size, value);
#else
memset(mem, value, size);
#endif
}
void (void *mem, const size_t size) {
FPL__CheckArgumentNullNoRet(mem);
FPL__CheckArgumentZeroNoRet(size);
#if defined(FPL__ENABLE_MEMORY_MACROS)
if (size % 8 == 0) {
FPL__MEMORY_CLEAR(uint64_t, mem, size, FPL__MEM_SHIFT_64, FPL__MEM_MASK_64);
} else if (size % 4 == 0) {
FPL__MEMORY_CLEAR(uint32_t, mem, size, FPL__MEM_SHIFT_32, FPL__MEM_MASK_32);
} else if (size % 2 == 0) {
FPL__MEMORY_CLEAR(uint16_t, mem, size, FPL__MEM_SHIFT_16, FPL__MEM_MASK_16);
} else {
FPL__MEMORY_CLEAR(uint8_t, mem, size, 0, 0);
}
#elif defined(FPL_PLATFORM_WINDOWS)
ZeroMemory(mem, size);
#else
memset(mem, 0, size);
#endif
}
void (const void *sourceMem, const size_t sourceSize, void *targetMem) {
FPL__CheckArgumentNullNoRet(sourceMem);
FPL__CheckArgumentZeroNoRet(sourceSize);
FPL__CheckArgumentNullNoRet(targetMem);
#if defined(FPL__ENABLE_MEMORY_MACROS)
if (sourceSize % 8 == 0) {
FPL__MEMORY_COPY(uint64_t, sourceMem, sourceSize, targetMem, FPL__MEM_SHIFT_64, FPL__MEM_MASK_64);
} else if (sourceSize % 4 == 0) {
FPL__MEMORY_COPY(uint32_t, sourceMem, sourceSize, targetMem, FPL__MEM_SHIFT_32, FPL__MEM_MASK_32);
} else if (sourceSize % 2 == 0) {
FPL__MEMORY_COPY(uint16_t, sourceMem, sourceSize, targetMem, FPL__MEM_SHIFT_16, FPL__MEM_MASK_16);
} else {
FPL__MEMORY_COPY(uint8_t, sourceMem, sourceSize, targetMem, 0, 0);
}
#elif defined(FPL_PLATFORM_WINDOWS)
CopyMemory(targetMem, sourceMem, sourceSize);
#else
memcpy(targetMem, sourceMem, sourceSize);
#endif
}
#endif // FPL__COMMON_MEMORY_DEFINED
//
// Common Timing
//
#if !defined(FPL__COMMON_TIMINGS_DEFINED)
#define FPL__COMMON_TIMINGS_DEFINED
bool fpl__IsLeapYear(const uint16_t year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
uint8_t fpl__GetMonthDays(const uint16_t year, const uint8_t month) {
switch (month) {
case 1: return 31; // January
case 2: return fpl__IsLeapYear(year) ? 29 : 28; // February
case 3: return 31; // March
case 4: return 30; // April
case 5: return 31; // May
case 6: return 30; // June
case 7: return 31; // July
case 8: return 31; // August
case 9: return 30; // September
case 10: return 31; // October
case 11: return 30; // November
case 12: return 31; // December
default: return 0; // Invalid month
}
}
(const uint16_t year, const uint8_t month, const uint8_t day, const uint8_t hour, const uint8_t minute, const uint8_t second, const uint16_t millisecond, const int32_t utcOffset) {
// Validate input
errors = ;
if (year < 1970) {
errors |= ;
}
if (month < 1 || month > 12) {
errors |= ;
}
uint8_t monthDays = fpl__GetMonthDays(year, month);
if (day < 1 || day > monthDays) {
errors |= ;
}
if (hour > 23) {
errors |= ;
}
if (minute > 59) {
errors |= ;
}
if (second > 59) {
errors |= ;
}
if (errors != ) {
failed = ;
failed. = errors;
return failed;
}
// Calculate the number of days since the Unix epoch (1970-01-01)
uint64_t days = 0;
for (uint16_t y = 1970; y < year; ++y) {
days += fpl__IsLeapYear(y) ? 366 : 365;
}
for (uint8_t m = 1; m < month; ++m) {
days += fpl__GetMonthDays(year, m);
}
days += (uint64_t)day - 1; // Add days in the current month
// Calculate total seconds
uint64_t totalSeconds = days * 86400ULL + hour * 3600ULL + minute * 60ULL + second;
// Create the fplDateTime structure
dateTime = ;
dateTime. = totalSeconds;
dateTime. = millisecond;
dateTime. = utcOffset;
// Output
result = ;
result. = dateTime;
result. = true;
return result;
}
#endif // FPL__COMMON_TIMINGS_DEFINED
//
// Common Hardware
//
// https://github.com/google/cpu_features
// https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h
//
// X86/X64 only (CPUID, XCR0, RDTSC)
//
#if defined(FPL_ARCH_X64) || defined(FPL_ARCH_X86)
# define FPL__CPU_BRAND_BUFFER_SIZE 0x40
# if defined(FPL_COMPILER_MSVC)
// CPUID/XCR0 for MSVC
# if _MSC_VER >= 1400
# define fpl__m_CPUID(outLeaf, functionId) __cpuid((int *)(outLeaf)->raw, (int)(functionId))
# endif
# if _MSC_VER >= 1600
# define fpl__m_GetXCR0() ((uint64_t)_xgetbv(0))
# endif
// RDTSC for MSVC
# define fpl__m_RDTSC() ((uint64_t)__rdtsc())
# elif defined(FPL_COMPILER_GCC) ||defined(FPL_COMPILER_CLANG)
// CPUID for GCC/CLANG
void fpl__m_CPUID_Impl( *outLeaf, const uint32_t functionId) {
int eax = 0, ebx = 0, ecx = 0, edx = 0;
__cpuid_count(functionId, 0, eax, ebx, ecx, edx);
outLeaf-> = eax;
outLeaf-> = ebx;
outLeaf-> = ecx;
outLeaf-> = edx;
}
# define fpl__m_CPUID(outLeaf, functionId) fpl__m_CPUID_Impl(outLeaf, functionId)
// XCR0 for GCC/CLANG
uint64_t fpl__m_GetXCR0_Impl(void) {
uint32_t eax, edx;
__asm(".byte 0x0F, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0));
return eax;
}
# define fpl__m_GetXCR0() fpl__m_GetXCR0_Impl()
// RDTSC for non-MSVC
# if defined(FPL_ARCH_X86)
uint64_t fpl__m_RDTSC_Impl(void) {
unsigned long long int result;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (result));
return((uint64_t)result);
}
# define fpl__m_RDTSC() fpl__m_RDTSC_Impl()
# elif defined(FPL_ARCH_X64)
uint64_t fpl__m_RDTSC_Impl(void) {
unsigned hi, lo;
__asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
uint64_t result = (uint64_t)(((unsigned long long)lo) | (((unsigned long long)hi) << 32));
return (result);
}
# define fpl__m_RDTSC() fpl__m_RDTSC_Impl()
# endif
# endif
bool (const uint32_t functionId, *outLeaf) {
#if defined(fpl__m_CPUID)
fpl__m_CPUID(outLeaf, functionId);
return true;
#endif
return false;
}
uint64_t (void) {
#if defined(fpl__m_GetXCR0)
uint64_t result = fpl__m_GetXCR0();
return(result);
#else
return(0ULL);
#endif
}
uint64_t (void) {
#if defined(fpl__m_RDTSC)
uint64_t result = fpl__m_RDTSC();
return(result);
#else
return(0ULL);
#endif
}
bool ( *outCaps) {
(outCaps);
outCaps-> = ;
info0 = ;
info1 = ;
info7 = ;
tempLeaf = ;
if (!(0, &info0))
return false;
uint32_t maxFunctionId = info0.;
if (1 <= maxFunctionId) {
if (!(1, &info1))
return false;
}
if (7 <= maxFunctionId) {
if (!(7, &info7))
return false;
}
bool hasXSave = (info1., 26) && (info1., 27);
uint64_t xcr0 = hasXSave ? () : 0;
const uint32_t MASK_XMM = 0x2;
const uint32_t MASK_YMM = 0x4;
const uint32_t MASK_MASKREG = 0x20;
const uint32_t MASK_ZMM0_15 = 0x40;
const uint32_t MASK_ZMM16_31 = 0x80;
const uint32_t MASK_SSE = MASK_XMM;
const uint32_t MASK_AVX = MASK_XMM | MASK_YMM;
const uint32_t MASK_AVX_512 = MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31;
bool hasSSESupport = (xcr0, MASK_SSE);
bool hasAVXSupport = (xcr0, MASK_AVX);
bool hasAVX512Support = (xcr0, MASK_AVX_512);
outCaps->. = (info1., 23);
if (hasSSESupport) {
outCaps->. = (info1., 25);
outCaps->. = (info1., 26);
outCaps->. = (info1., 0);
outCaps->. = (info1., 9);
outCaps->. = (info1., 19);
outCaps->. = (info1., 20);
}
if (hasAVXSupport) {
outCaps->. = (info1., 28);
outCaps->. = (info7., 5);
}
if (hasAVX512Support) {
outCaps->. = (info7., 16);
}
outCaps->. = (info1., 12);
outCaps->. = (info1., 25);
outCaps->. = (info7., 29);
outCaps->. = (info7., 3);
outCaps->. = (info7., 8);
outCaps->. = (info7., 19);
outCaps->. = (info1., 29);
if ((0x80000001, &tempLeaf)) {
outCaps->. = (info1., 29);
}
return(true);
}
size_t (char *destBuffer, const size_t maxDestBufferLen) {
cpuInfo = ;
(0x80000000, &cpuInfo);
uint32_t extendedIds = cpuInfo.;
// Get the information associated with each extended ID. Interpret CPU brand string.
char cpuBrandBuffer[FPL__CPU_BRAND_BUFFER_SIZE] = ;
uint32_t max = (extendedIds, 0x80000004);
for (uint32_t i = 0x80000002; i <= max; ++i) {
(i, &cpuInfo);
uint32_t offset = (i - 0x80000002) << 4;
(cpuInfo., sizeof(cpuInfo), cpuBrandBuffer + offset);
}
size_t result = (cpuBrandBuffer);
if (destBuffer != ) {
// Copy result back to the dest buffer
size_t requiredDestBufferLen = result + 1;
FPL__CheckArgumentMin(maxDestBufferLen, requiredDestBufferLen, 0);
(cpuBrandBuffer, result, destBuffer, maxDestBufferLen);
}
return(result);
}
#else
uint64_t (void) {
#if defined(FPL_ARCH_ARM64)
int64_t virtual_timer_value;
volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return (uint64_t)virtual_timer_value;
#elif defined(FPL_ARCH_ARM32) && (__ARM_ARCH >= 6)
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
if ((pmuseren, 1)) {
// Allows reading perfmon counters for user mode code.
volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
if ((pmcntenset, 0x80000000ul)) {
// Is it counting?
volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
// The counter is set up to count every 64th cycle
return (uint64_t)pmccntr * 64ULL; // Should optimize to << 6
}
}
#endif
struct timeval tv;
gettimeofday(&tv, );
return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
}
uint64_t (void) {
// Not supported on non-x86 platforms
return(0);
}
bool (const uint32_t functionId, *outLeaf) {
// Not supported on non-x86 platforms
return(false);
}
bool ( *outCaps) {
// @IMPLEMENT(final): fplCPUGetCapabilities for non-x86 architectures
return(false);
}
size_t (char *destBuffer, const size_t maxDestBufferLen) {
// @IMPLEMENT(final): fplCPUGetName for non-x86 architectures
return(0);
}
#endif
//
// Common Atomics
//
#if !defined(FPL__COMMON_ATOMICS_DEFINED)
#define FPL__COMMON_ATOMICS_DEFINED
size_t (volatile size_t *dest, const size_t addend) {
(dest != );
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)dest, (uint64_t)addend);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)dest, (uint32_t)addend);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
void *(volatile void **dest, const intptr_t addend) {
(dest != );
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile int64_t *)dest, (int64_t)addend);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile int32_t *)dest, (int32_t)addend);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
size_t (volatile size_t *value, const size_t addend) {
(value != );
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)value, (uint64_t)addend);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)value, (uint32_t)addend);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
void *(volatile void **value, const intptr_t addend) {
(value != );
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile uint64_t *)value, (uint64_t)addend);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile uint32_t *)value, (uint32_t)addend);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
size_t (volatile size_t *value) {
(value != );
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)value);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)value);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
void *(volatile void **value) {
(value != );
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile uint64_t *)value, 8);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile uint32_t *)value, 4);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
size_t (volatile size_t *target, const size_t value) {
(target != );
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)target, (uint64_t)value);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)target, (uint32_t)value);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
void *(volatile void **target, const void *value) {
(target != );
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile uint64_t *)target, (uint64_t)value);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile uint32_t *)target, (uint32_t)value);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
size_t (volatile size_t *dest, const size_t comparand, const size_t exchange) {
(dest != );
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
void *(volatile void **dest, const void *comparand, const void *exchange) {
(dest != );
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
bool (volatile size_t *dest, const size_t comparand, const size_t exchange) {
(dest != );
#if defined(FPL_CPU_64BIT)
bool result = ((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
#elif defined(FPL_CPU_32BIT)
bool result = ((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
bool (volatile void **dest, const void *comparand, const void *exchange) {
(dest != );
#if defined(FPL_CPU_64BIT)
bool result = ((volatile uint64_t *)dest, (uint64_t)comparand, (uint64_t)exchange);
#elif defined(FPL_CPU_32BIT)
bool result = ((volatile uint32_t *)dest, (uint32_t)comparand, (uint32_t)exchange);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return (result);
}
size_t (volatile size_t *source) {
#if defined(FPL_CPU_64BIT)
size_t result = (size_t)((volatile uint64_t *)source);
#elif defined(FPL_CPU_32BIT)
size_t result = (size_t)((volatile uint32_t *)source);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return(result);
}
void (volatile size_t *dest, const size_t value) {
#if defined(FPL_CPU_64BIT)
((volatile uint64_t *)dest, (uint64_t)value);
#elif defined(FPL_CPU_32BIT)
((volatile uint32_t *)dest, (uint32_t)value);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
}
void *(volatile void **source) {
#if defined(FPL_CPU_64BIT)
void *result = (void *)((volatile uint64_t *)source);
#elif defined(FPL_CPU_32BIT)
void *result = (void *)((volatile uint32_t *)source);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
return(result);
}
void (volatile void **dest, const void *value) {
#if defined(FPL_CPU_64BIT)
((volatile uint64_t *)dest, (uint64_t)value);
#elif defined(FPL_CPU_32BIT)
((volatile uint32_t *)dest, (uint32_t)value);
#else
# error "Unsupported architecture/platform!"
#endif // FPL_ARCH
}
#endif // FPL__COMMON_ATOMICS_DEFINED
//
// Common Threading
//
( *thread) {
if (thread == ) {
return ;
}
result = ()((volatile uint32_t *)&thread->);
return(result);
}
const *(void) {
const *result = &fpl__global__ThreadState.mainThread;
return(result);
}
size_t (void) {
size_t result = 0;
for (size_t threadIndex = 0; threadIndex < FPL_MAX_THREAD_COUNT; ++threadIndex) {
state = ()((volatile uint32_t *)&fpl__global__ThreadState.threads[threadIndex].currentState);
if (state == ) {
++result;
}
}
return(result);
}
size_t (void) {
size_t result = 0;
for (size_t threadIndex = 0; threadIndex < FPL_MAX_THREAD_COUNT; ++threadIndex) {
state = ()((volatile uint32_t *)&fpl__global__ThreadState.threads[threadIndex].currentState);
if (state != ) {
++result;
}
}
return(result);
}
//
// Common Files
//
#if !defined(FPL__COMMON_FILES_DEFINED)
#define FPL__COMMON_FILES_DEFINED
size_t (const *fileHandle, const size_t sizeToRead, void *targetBuffer, const size_t maxTargetBufferSize) {
#if defined(FPL_CPU_64BIT)
return (fileHandle, sizeToRead, targetBuffer, maxTargetBufferSize);
#else
return (fileHandle, (uint32_t)sizeToRead, targetBuffer, (uint32_t)maxTargetBufferSize);
#endif
}
size_t (const *fileHandle, const void *sourceBuffer, const size_t sourceSize) {
#if defined(FPL_CPU_64BIT)
return (fileHandle, sourceBuffer, sourceSize);
#else
return (fileHandle, sourceBuffer, (uint32_t)sourceSize);
#endif
}
size_t (const *fileHandle, const intptr_t position, const mode) {
#if defined(FPL_CPU_64BIT)
return (fileHandle, position, mode);
#else
return (fileHandle, (int32_t)position, mode);
#endif
}
size_t (const *fileHandle) {
#if defined(FPL_CPU_64BIT)
return (fileHandle);
#else
return (fileHandle);
#endif
}
size_t (const char *filePath) {
#if defined(FPL_CPU_64BIT)
return (filePath);
#else
return (filePath);
#endif
}
size_t (const *fileHandle) {
#if defined(FPL_CPU_64BIT)
return (fileHandle);
#else
return (fileHandle);
#endif
}
#endif // FPL__COMMON_FILES_DEFINED
//
// Common Paths
//
#if !defined(FPL__COMMON_PATHS_DEFINED)
#define FPL__COMMON_PATHS_DEFINED
size_t (const char *sourcePath, char *destPath, const size_t maxDestLen) {
FPL__CheckArgumentNull(sourcePath, 0);
size_t sourceLen = (sourcePath);
size_t result = 0;
if (sourceLen > 0) {
size_t pathLen = 0;
const char *chPtr = (const char *)sourcePath;
while (*chPtr) {
if (*chPtr == ) {
pathLen = (size_t)(chPtr - sourcePath);
}
++chPtr;
}
result = pathLen;
if (destPath != ) {
size_t requiredDestLen = pathLen + 1;
FPL__CheckArgumentMin(maxDestLen, requiredDestLen, 0);
(sourcePath, pathLen, destPath, maxDestLen);
}
}
return(result);
}
const char *(const char *sourcePath) {
const char *result = ;
if (sourcePath != ) {
const char *chPtr = sourcePath;
// Find last separator first
const char *lastPathSep = ;
while (*chPtr) {
if (*chPtr == ) {
lastPathSep = chPtr;
}
++chPtr;
}
// Start either by the last found separator or from the very start
if (lastPathSep != ) {
chPtr = lastPathSep;
} else {
chPtr = sourcePath;
}
const char *lastExt = ;
while (*chPtr) {
if (*chPtr == ) {
lastExt = chPtr;
}
++chPtr;
}
if (lastExt != ) {
result = lastExt;
}
}
return(result);
}
const char *(const char *sourcePath) {
const char *result = ;
if (sourcePath) {
result = sourcePath;
const char *chPtr = sourcePath;
while (*chPtr) {
if (*chPtr == ) {
result = chPtr + 1;
}
++chPtr;
}
}
return(result);
}
size_t (const char *filePath, const char *newFileExtension, char *destPath, const size_t maxDestLen) {
FPL__CheckArgumentNull(filePath, 0);
FPL__CheckArgumentNull(newFileExtension, 0);
size_t filePathLen = (filePath);
FPL__CheckArgumentZero(filePathLen, 0);
size_t extLen = (newFileExtension);
size_t result = 0;
if (filePath != ) {
// Find last path
const char *chPtr = (const char *)filePath;
const char *lastPathSeparatorPtr = ;
while (*chPtr) {
if (*chPtr == ) {
lastPathSeparatorPtr = chPtr;
}
++chPtr;
}
// Find last ext separator
if (lastPathSeparatorPtr != ) {
chPtr = lastPathSeparatorPtr + 1;
} else {
chPtr = (const char *)filePath;
}
const char *lastExtSeparatorPtr = ;
while (*chPtr) {
if (*chPtr == ) {
lastExtSeparatorPtr = chPtr;
}
++chPtr;
}
size_t filenameLen;
if (lastExtSeparatorPtr != ) {
filenameLen = (size_t)((uintptr_t)lastExtSeparatorPtr - (uintptr_t)filePath);
} else {
filenameLen = filePathLen;
}
result = filenameLen + extLen;
// Copy parts
if (destPath != ) {
size_t requiredDestLen = result + 1;
FPL__CheckArgumentMin(maxDestLen, requiredDestLen, 0);
(filePath, filenameLen, destPath, maxDestLen);
char *destExtPtr = destPath + filenameLen;
(newFileExtension, extLen, destExtPtr, maxDestLen - filenameLen);
}
}
return(result);
}
#define FPL__PATHCOMBINE_STACK_SEGMENTS 16
size_t (char *destPath, const size_t maxDestPathLen, const size_t pathCount, ...) {
FPL__CheckArgumentZero(pathCount, 0);
va_list args;
// First pass: compute total length
va_start(args, pathCount);
size_t totalLen = 0;
bool prevHasTrailingSep = false;
for (size_t i = 0; i < pathCount; ++i) {
const char *path = va_arg(args, const char *);
if (path == ) {
continue;
}
const size_t len = (path);
if (i > 0 && len > 0 && !prevHasTrailingSep) {
totalLen += 1; // separator
}
totalLen += len;
if (len > 0) {
prevHasTrailingSep = (path[len - 1] == );
}
}
va_end(args);
// Write result if buffer provided
if (destPath != ) {
const size_t requiredLen = totalLen + 1;
FPL__CheckArgumentMin(maxDestPathLen, requiredLen, 0);
va_start(args, pathCount);
size_t pos = 0;
prevHasTrailingSep = false;
for (size_t i = 0; i < pathCount; ++i) {
const char *path = va_arg(args, const char *);
if (path == ) {
continue;
}
const size_t len = (path);
if (i > 0 && len > 0 && !prevHasTrailingSep) {
destPath[pos++] = ;
}
if (len > 0) {
(path, len * sizeof(char), destPath + pos);
pos += len;
prevHasTrailingSep = (path[len - 1] == );
}
}
va_end(args);
destPath[pos] = '\0';
}
return totalLen;
}
#endif // FPL__COMMON_PATHS_DEFINED
//
// Common Window
//
#if defined(FPL__ENABLE_WINDOW) && !defined(FPL__COMMON_WINDOW_DEFINED)
#define FPL__COMMON_WINDOW_DEFINED
size_t (char *outTitle, const size_t maxOutTitleLength) {
FPL__CheckPlatform(0);
fpl__PlatformAppState *appState = fpl__global__AppState;
size_t result = (appState->currentSettings.window.title, outTitle, maxOutTitleLength);
return(result);
}
void (const bool enabled) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
appState->currentSettings.input.disabledEvents = !enabled;
}
#define FPL__KEY_COUNT FPL__ENUM_COUNT(fplKey_First, fplKey_Last)
const char *fpl__global_KeyNameTable[] = {
FPL__ENUM_NAME("None", ), // 0x00
// 0x00–0x07 Undefined
FPL__ENUM_NAME(, ), // 0x01
FPL__ENUM_NAME(, ), // 0x02
FPL__ENUM_NAME(, ), // 0x03
FPL__ENUM_NAME(, ), // 0x04
FPL__ENUM_NAME(, ), // 0x05
FPL__ENUM_NAME(, ), // 0x06
FPL__ENUM_NAME(, ), // 0x07
// 0x08–0x09 Control keys
FPL__ENUM_NAME("Backspace", ), // 0x08
FPL__ENUM_NAME("Tab", ), // 0x09
// 0x0A–0x0B Reserved
FPL__ENUM_NAME(, ), // 0x0A
FPL__ENUM_NAME(, ), // 0x0B
// 0x0C–0x0D Control keys
FPL__ENUM_NAME("Clear", ), // 0x0C
FPL__ENUM_NAME("Return", ), // 0x0D
// 0x0E–0x0F Undefined
FPL__ENUM_NAME(, ), // 0x0E
FPL__ENUM_NAME(, ), // 0x0F
// 0x10–0x14 Modifier keys
FPL__ENUM_NAME("Shift", ), // 0x10
FPL__ENUM_NAME("Control", ), // 0x11
FPL__ENUM_NAME("Alt", ), // 0x12
FPL__ENUM_NAME("Pause", ), // 0x13
FPL__ENUM_NAME("CapsLock", ), // 0x14
// 0x15–0x1A IME / Undefined
FPL__ENUM_NAME(, ), // 0x15
FPL__ENUM_NAME(, ), // 0x16
FPL__ENUM_NAME(, ), // 0x17
FPL__ENUM_NAME(, ), // 0x18
FPL__ENUM_NAME(, ), // 0x19
FPL__ENUM_NAME(, ), // 0x1A
// 0x1B Escape
FPL__ENUM_NAME("Escape", ), // 0x1B
// 0x1C–0x1F IME
FPL__ENUM_NAME(, ), // 0x1C
FPL__ENUM_NAME(, ), // 0x1D
FPL__ENUM_NAME(, ), // 0x1E
FPL__ENUM_NAME(, ), // 0x1F
// 0x20–0x2F Navigation & editing keys
FPL__ENUM_NAME("Space", ), // 0x20
FPL__ENUM_NAME("PageUp", ), // 0x21
FPL__ENUM_NAME("PageDown", ), // 0x22
FPL__ENUM_NAME("End", ), // 0x23
FPL__ENUM_NAME("Home", ), // 0x24
FPL__ENUM_NAME("Left", ), // 0x25
FPL__ENUM_NAME("Up", ), // 0x26
FPL__ENUM_NAME("Right", ), // 0x27
FPL__ENUM_NAME("Down", ), // 0x28
FPL__ENUM_NAME("Select", ), // 0x29
FPL__ENUM_NAME("Print", ), // 0x2A
FPL__ENUM_NAME("Execute", ), // 0x2B
FPL__ENUM_NAME("Snapshot", ), // 0x2C
FPL__ENUM_NAME("Insert", ), // 0x2D
FPL__ENUM_NAME("Delete", ), // 0x2E
FPL__ENUM_NAME("Help", ), // 0x2F
// 0x30–0x39 Number keys
FPL__ENUM_NAME("0", ), // 0x30
FPL__ENUM_NAME("1", ), // 0x31
FPL__ENUM_NAME("2", ), // 0x32
FPL__ENUM_NAME("3", ), // 0x33
FPL__ENUM_NAME("4", ), // 0x34
FPL__ENUM_NAME("5", ), // 0x35
FPL__ENUM_NAME("6", ), // 0x36
FPL__ENUM_NAME("7", ), // 0x37
FPL__ENUM_NAME("8", ), // 0x38
FPL__ENUM_NAME("9", ), // 0x39
// 0x3A–0x40 Undefined
FPL__ENUM_NAME(, ), // 0x3A
FPL__ENUM_NAME(, ), // 0x3B
FPL__ENUM_NAME(, ), // 0x3C
FPL__ENUM_NAME(, ), // 0x3D
FPL__ENUM_NAME(, ), // 0x3E
FPL__ENUM_NAME(, ), // 0x3F
FPL__ENUM_NAME(, ), // 0x40
// 0x41–0x5A Letter keys
FPL__ENUM_NAME("A", ), // 0x41
FPL__ENUM_NAME("B", ), // 0x42
FPL__ENUM_NAME("C", ), // 0x43
FPL__ENUM_NAME("D", ), // 0x44
FPL__ENUM_NAME("E", ), // 0x45
FPL__ENUM_NAME("F", ), // 0x46
FPL__ENUM_NAME("G", ), // 0x47
FPL__ENUM_NAME("H", ), // 0x48
FPL__ENUM_NAME("I", ), // 0x49
FPL__ENUM_NAME("J", ), // 0x4A
FPL__ENUM_NAME("K", ), // 0x4B
FPL__ENUM_NAME("L", ), // 0x4C
FPL__ENUM_NAME("M", ), // 0x4D
FPL__ENUM_NAME("N", ), // 0x4E
FPL__ENUM_NAME("O", ), // 0x4F
FPL__ENUM_NAME("P", ), // 0x50
FPL__ENUM_NAME("Q", ), // 0x51
FPL__ENUM_NAME("R", ), // 0x52
FPL__ENUM_NAME("S", ), // 0x53
FPL__ENUM_NAME("T", ), // 0x54
FPL__ENUM_NAME("U", ), // 0x55
FPL__ENUM_NAME("V", ), // 0x56
FPL__ENUM_NAME("W", ), // 0x57
FPL__ENUM_NAME("X", ), // 0x58
FPL__ENUM_NAME("Y", ), // 0x59
FPL__ENUM_NAME("Z", ), // 0x5A
// 0x5B–0x5D Windows / Apps keys
FPL__ENUM_NAME("LeftSuper", ), // 0x5B
FPL__ENUM_NAME("RightSuper", ), // 0x5C
FPL__ENUM_NAME("Apps", ), // 0x5D
// 0x5E Reserved
FPL__ENUM_NAME(, ), // 0x5E
// 0x5F Sleep
FPL__ENUM_NAME("Sleep", ), // 0x5F
// 0x60–0x69 NumPad digits
FPL__ENUM_NAME("NumPad0", ), // 0x60
FPL__ENUM_NAME("NumPad1", ), // 0x61
FPL__ENUM_NAME("NumPad2", ), // 0x62
FPL__ENUM_NAME("NumPad3", ), // 0x63
FPL__ENUM_NAME("NumPad4", ), // 0x64
FPL__ENUM_NAME("NumPad5", ), // 0x65
FPL__ENUM_NAME("NumPad6", ), // 0x66
FPL__ENUM_NAME("NumPad7", ), // 0x67
FPL__ENUM_NAME("NumPad8", ), // 0x68
FPL__ENUM_NAME("NumPad9", ), // 0x69
// 0x6A–0x6F NumPad operations
FPL__ENUM_NAME("Multiply", ), // 0x6A
FPL__ENUM_NAME("Add", ), // 0x6B
FPL__ENUM_NAME("Separator", ), // 0x6C
FPL__ENUM_NAME("Substract", ), // 0x6D
FPL__ENUM_NAME("Decimal", ), // 0x6E
FPL__ENUM_NAME("Divide", ), // 0x6F
// 0x70–0x87 Function keys F1–F16
FPL__ENUM_NAME("F1", ), // 0x70
FPL__ENUM_NAME("F2", ), // 0x71
FPL__ENUM_NAME("F3", ), // 0x72
FPL__ENUM_NAME("F4", ), // 0x73
FPL__ENUM_NAME("F5", plKey_F5), // 0x74
FPL__ENUM_NAME("F6", ), // 0x75
FPL__ENUM_NAME("F7", ), // 0x76
FPL__ENUM_NAME("F8", ), // 0x77
FPL__ENUM_NAME("F9", ), // 0x78
FPL__ENUM_NAME("F10", ), // 0x79
FPL__ENUM_NAME("F11", ), // 0x7A
FPL__ENUM_NAME("F12", ), // 0x7B
FPL__ENUM_NAME("F13", ), // 0x7C
FPL__ENUM_NAME("F14", ), // 0x7D
FPL__ENUM_NAME("F15", ), // 0x7E
FPL__ENUM_NAME("F16", ), // 0x7F
FPL__ENUM_NAME("F17", ), // 0x80
FPL__ENUM_NAME("F18", ), // 0x81
FPL__ENUM_NAME("F19", ), // 0x82
FPL__ENUM_NAME("F20", ), // 0x83
FPL__ENUM_NAME("F21", ), // 0x84
FPL__ENUM_NAME("F22", ), // 0x85
FPL__ENUM_NAME("F23", ), // 0x86
FPL__ENUM_NAME("F24", ), // 0x87
// 0x88–0x8F Unassigned
FPL__ENUM_NAME(, ), // 0x88
FPL__ENUM_NAME(, ), // 0x89
FPL__ENUM_NAME(, ), // 0x8A
FPL__ENUM_NAME(, ), // 0x8B
FPL__ENUM_NAME(, ), // 0x8C
FPL__ENUM_NAME(, ), // 0x8D
FPL__ENUM_NAME(, ), // 0x8E
FPL__ENUM_NAME(, ), // 0x8F
// 0x90–0x91 Lock keys
FPL__ENUM_NAME("NumLock", ), // 0x90
FPL__ENUM_NAME("Scroll", ), // 0x91
// 0x92–0x96 OEM specific (unmapped)
FPL__ENUM_NAME(, ), // 0x92
FPL__ENUM_NAME(, ), // 0x93
FPL__ENUM_NAME(, ), // 0x94
FPL__ENUM_NAME(, ), // 0x95
FPL__ENUM_NAME(, ), // 0x96
// 0x97–0x9F Unassigned
FPL__ENUM_NAME(, ), // 0x97
FPL__ENUM_NAME(, ), // 0x98
FPL__ENUM_NAME(, ), // 0x99
FPL__ENUM_NAME(, ), // 0x9A
FPL__ENUM_NAME(, ), // 0x9B
FPL__ENUM_NAME(, ), // 0x9C
FPL__ENUM_NAME(, ), // 0x9D
FPL__ENUM_NAME(, ), // 0x9E
FPL__ENUM_NAME(, ), // 0x9F
// 0xA0–0xA5 Modifier keys (Left/Right Shift, Ctrl, Alt)
FPL__ENUM_NAME("LeftShift", ), // 0xA0
FPL__ENUM_NAME("RightShift", ), // 0xA1
FPL__ENUM_NAME("LeftControl", ), // 0xA2
FPL__ENUM_NAME("RightControl", ), // 0xA3
FPL__ENUM_NAME("LeftAlt", ), // 0xA4
FPL__ENUM_NAME("RightAlt", ), // 0xA5
// 0xA6–0xAC Don't care
FPL__ENUM_NAME(, ), // 0xA6
FPL__ENUM_NAME(, ), // 0xA7
FPL__ENUM_NAME(, ), // 0xA8
FPL__ENUM_NAME(, ), // 0xA9
FPL__ENUM_NAME(, ), // 0xAA
FPL__ENUM_NAME(, ), // 0xAB
FPL__ENUM_NAME(, ), // 0xAC
// 0xAD–0xB3 Media keys
FPL__ENUM_NAME("VolumeMute", ), // 0xAD
FPL__ENUM_NAME("VolumeDown", ), // 0xAE
FPL__ENUM_NAME("VolumeUp", ), // 0xAF
FPL__ENUM_NAME("MediaNextTrack", ), // 0xB0
FPL__ENUM_NAME("MediaPrevTrack", ), // 0xB1
FPL__ENUM_NAME("MediaStop", ), // 0xB2
FPL__ENUM_NAME("MediaPlayPause", ), // 0xB3
// 0xB4–0xB9 Don't care
FPL__ENUM_NAME(, ), // 0xB4
FPL__ENUM_NAME(, ), // 0xB5
FPL__ENUM_NAME(, ), // 0xB6
FPL__ENUM_NAME(, ), // 0xB7
FPL__ENUM_NAME(, ), // 0xB8
FPL__ENUM_NAME(, ), // 0xB9
// 0xBA–0xC0 OEM punctuation keys
FPL__ENUM_NAME("Oem1", ), // 0xBA
FPL__ENUM_NAME("OemPlus", ), // 0xBB
FPL__ENUM_NAME("OemComma", ), // 0xBC
FPL__ENUM_NAME("OemMinus", ), // 0xBD
FPL__ENUM_NAME("OemPeriod",), // 0xBE
FPL__ENUM_NAME("Oem2", ), // 0xBF
FPL__ENUM_NAME("Oem3", ), // 0xC0
// 0xC1–0xD7 Reserved
FPL__ENUM_NAME(, ), // 0xC1
FPL__ENUM_NAME(, ), // 0xC2
FPL__ENUM_NAME(, ), // 0xC3
FPL__ENUM_NAME(, ), // 0xC4
FPL__ENUM_NAME(, ), // 0xC5
FPL__ENUM_NAME(, ), // 0xC6
FPL__ENUM_NAME(, ), // 0xC7
FPL__ENUM_NAME(, ), // 0xC8
FPL__ENUM_NAME(, ), // 0xC9
FPL__ENUM_NAME(, ), // 0xCA
FPL__ENUM_NAME(, ), // 0xCB
FPL__ENUM_NAME(, ), // 0xCC
FPL__ENUM_NAME(, ), // 0xCD
FPL__ENUM_NAME(, ), // 0xCE
FPL__ENUM_NAME(, ), // 0xCF
FPL__ENUM_NAME(, ), // 0xD0
FPL__ENUM_NAME(, ), // 0xD1
FPL__ENUM_NAME(, ), // 0xD2
FPL__ENUM_NAME(, ), // 0xD3
FPL__ENUM_NAME(, ), // 0xD4
FPL__ENUM_NAME(, ), // 0xD5
FPL__ENUM_NAME(, ), // 0xD6
FPL__ENUM_NAME(, ), // 0xD7
// 0xD8–0xDA Unassigned
FPL__ENUM_NAME(, ), // 0xD8
FPL__ENUM_NAME(, ), // 0xD9
FPL__ENUM_NAME(, ), // 0xDA
// 0xDB–0xDF OEM keys
FPL__ENUM_NAME("Oem4", ), // 0xDB
FPL__ENUM_NAME("Oem5", ), // 0xDC
FPL__ENUM_NAME("Oem6", ), // 0xDD
FPL__ENUM_NAME("Oem7", ), // 0xDE
FPL__ENUM_NAME("Oem8", ), // 0xDF
// 0xE0–0xFE Don't care
FPL__ENUM_NAME(, ), // 0xE0
FPL__ENUM_NAME(, ), // 0xE1
FPL__ENUM_NAME(, ), // 0xE2
FPL__ENUM_NAME(, ), // 0xE3
FPL__ENUM_NAME(, ), // 0xE4
FPL__ENUM_NAME(, ), // 0xE5
FPL__ENUM_NAME(, ), // 0xE6
FPL__ENUM_NAME(, ), // 0xE7
FPL__ENUM_NAME(, ), // 0xE8
FPL__ENUM_NAME(, ), // 0xE9
FPL__ENUM_NAME(, ), // 0xEA
FPL__ENUM_NAME(, ), // 0xEB
FPL__ENUM_NAME(, ), // 0xEC
FPL__ENUM_NAME(, ), // 0xED
FPL__ENUM_NAME(, ), // 0xEE
FPL__ENUM_NAME(, ), // 0xEF
FPL__ENUM_NAME(, ), // 0xF0
FPL__ENUM_NAME(, ), // 0xF1
FPL__ENUM_NAME(, ), // 0xF2
FPL__ENUM_NAME(, ), // 0xF3
FPL__ENUM_NAME(, ), // 0xF4
FPL__ENUM_NAME(, ), // 0xF5
FPL__ENUM_NAME(, ), // 0xF6
FPL__ENUM_NAME(, ), // 0xF7
FPL__ENUM_NAME(, ), // 0xF8
FPL__ENUM_NAME(, ), // 0xF9
FPL__ENUM_NAME(, ), // 0xFA
FPL__ENUM_NAME(, ), // 0xFB
FPL__ENUM_NAME(, ), // 0xFC
FPL__ENUM_NAME(, ), // 0xFD
FPL__ENUM_NAME(, ), // 0xFE
// 0xFF Last key
FPL__ENUM_NAME("Last", ), // 0xFF
};
((fpl__global_KeyNameTable) == FPL__KEY_COUNT);
( == );
const char *(const key) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(key, , );
const char *result = fpl__global_KeyNameTable[index];
return(result);
}
#endif // FPL__ENABLE_WINDOW && FPL__COMMON_WINDOW_DEFINED
//
// Common Logging
//
#if defined(FPL__ENABLE_LOGGING)
void (const *params) {
FPL__CheckArgumentNullNoRet(params);
fpl__global__LogSettings = *params;
fpl__global__LogSettings. = true;
}
const *(void) {
return &fpl__global__LogSettings;
}
void (const maxLevel) {
fpl__global__LogSettings.maxLevel = maxLevel;
}
(void) {
return fpl__global__LogSettings.maxLevel;
}
#endif // FPL__ENABLE_LOGGING
const char *(void) {
const char *result = "";
const fpl__ErrorState *errorState = &fpl__global__LastErrorState;
uint32_t total = errorState->count;
if (total > 0) {
size_t slot = (size_t)((total - 1) % FPL__MAX_ERRORSTATE_COUNT);
result = errorState->errors[slot];
}
return (result);
}
const char *(const size_t index) {
const char *result = "";
const fpl__ErrorState *errorState = &fpl__global__LastErrorState;
uint32_t total = errorState->count;
if (total == 0) {
return (result);
}
size_t visible = (total < FPL__MAX_ERRORSTATE_COUNT) ? (size_t)total : (size_t)FPL__MAX_ERRORSTATE_COUNT;
size_t effectiveIndex = (index < visible) ? index : (visible - 1);
size_t slot;
if (total <= FPL__MAX_ERRORSTATE_COUNT) {
slot = effectiveIndex;
} else {
// Ring has wrapped: oldest slot is the next-write slot.
size_t oldestSlot = (size_t)(total % FPL__MAX_ERRORSTATE_COUNT);
slot = (oldestSlot + effectiveIndex) % FPL__MAX_ERRORSTATE_COUNT;
}
result = errorState->errors[slot];
return (result);
}
size_t (void) {
const fpl__ErrorState *errorState = &fpl__global__LastErrorState;
uint32_t total = errorState->count;
size_t result = (total < FPL__MAX_ERRORSTATE_COUNT) ? (size_t)total : (size_t)FPL__MAX_ERRORSTATE_COUNT;
return (result);
}
void (void) {
fpl__ErrorState *errorState = &fpl__global__LastErrorState;
(errorState);
}
const *(void) {
FPL__CheckPlatform();
const fpl__PlatformAppState *appState = fpl__global__AppState;
return &appState->currentSettings;
}
void ( *video) {
FPL__CheckArgumentNullNoRet(video);
(video);
video-> = false;
video-> = true;
#if defined(FPL__ENABLE_VIDEO_OPENGL)
video->.. = ;
video->.. = ;
#endif
#if defined(FPL__ENABLE_VIDEO_VULKAN)
video->.. = ;
video->.. = (, "1.0.0", "1", "0", "0", "0");
video->.. = (, "1.0.0", "1", "0", "0", "0");
video->.. = (, "1.1.0", "1", "1", "0", "0");
video->.. = ;
#endif
// @NOTE(final): Auto detect video backend
#if defined(FPL__ENABLE_VIDEO_OPENGL)
video-> = ;
#elif defined(FPL__ENABLE_VIDEO_SOFTWARE)
video-> = ;
#elif defined(FPL__ENABLE_VIDEO_VULKAN)
video-> = ;
#else
video-> = ;
#endif
}
#define FPL__AUDIO_CHANNEL_TYPE_COUNT FPL__ENUM_COUNT(fplAudioChannelType_First, fplAudioChannelType_Last)
( == );
( == );
const char *fpl__global_audioChannelTypeNameTable[] = {
FPL__ENUM_NAME("None", ),
FPL__ENUM_NAME("Front Left", ),
FPL__ENUM_NAME("Front Right", ),
FPL__ENUM_NAME("Front Center", ),
FPL__ENUM_NAME("Low Frequency", ),
FPL__ENUM_NAME("Back Left", ),
FPL__ENUM_NAME("Back Right", ),
FPL__ENUM_NAME("Front Left Of Center", ),
FPL__ENUM_NAME("Front Right Of Center", ),
FPL__ENUM_NAME("Back Center", ),
FPL__ENUM_NAME("Side Left", ),
FPL__ENUM_NAME("Side Right", ),
FPL__ENUM_NAME("Top Center", ),
FPL__ENUM_NAME("Top Front Left", ),
FPL__ENUM_NAME("Top Front Center", ),
FPL__ENUM_NAME("Top Front Right", ),
FPL__ENUM_NAME("Top Back Left", ),
FPL__ENUM_NAME("Top Back Center", ),
FPL__ENUM_NAME("Top Back Right", ),
FPL__ENUM_NAME("AUX 0", ),
FPL__ENUM_NAME("AUX 1", ),
FPL__ENUM_NAME("AUX 2", ),
FPL__ENUM_NAME("AUX 3", ),
FPL__ENUM_NAME("AUX 4", ),
FPL__ENUM_NAME("AUX 5", ),
FPL__ENUM_NAME("AUX 6", ),
FPL__ENUM_NAME("AUX 7", ),
FPL__ENUM_NAME("AUX 8", ),
FPL__ENUM_NAME("AUX 9", ),
FPL__ENUM_NAME("AUX 10", ),
FPL__ENUM_NAME("AUX 11", ),
FPL__ENUM_NAME("AUX 12", ),
FPL__ENUM_NAME("AUX 13", ),
FPL__ENUM_NAME("AUX 14", ),
FPL__ENUM_NAME("AUX 15", ),
};
((fpl__global_audioChannelTypeNameTable) == FPL__AUDIO_CHANNEL_TYPE_COUNT);
const char *(const type) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(type, , );
const char *result = fpl__global_audioChannelTypeNameTable[index];
return(result);
}
void ( *audio) {
FPL__CheckArgumentNullNoRet(audio);
(audio);
audio-> = true;
audio-> = true;
audio-> = false;
audio-> = ;
}
void ( *window) {
FPL__CheckArgumentNullNoRet(window);
(window);
window->[0] = 0;
window->. = 0;
window->. = 0;
window->. = 0;
window->. = 0;
window-> = false;
window-> = true;
window-> = true;
window-> = false;
window-> = false;
window-> = false;
}
void ( *console) {
FPL__CheckArgumentNullNoRet(console);
(console);
console->[0] = 0;
}
void ( *gamepadSettings) {
gamepadSettings-> = 1000;
gamepadSettings-> = 0;
gamepadSettings-> = ;
gamepadSettings-> = ;
}
void ( *input) {
FPL__CheckArgumentNullNoRet(input);
(input);
(&input->);
input-> = ;
input->. = 0xFFFFFFFFu;
input-> = false;
input-> = true;
input-> = true;
input-> = false;
}
// Input subsystem device/backend enumeration.
#if defined(FPL__ENABLE_INPUT)
// Deterministic GUID derived from (backend, source, slot) so successive calls return stable identifiers.
void fpl__MakeInputDeviceGuid( *outGuid, const backend, const source, const uint32_t slot) {
(outGuid);
outGuid->[0] = 'F';
outGuid->[1] = 'P';
outGuid->[2] = 'L';
outGuid->[3] = 'I';
outGuid->[4] = (uint8_t)backend;
outGuid->[5] = (uint8_t)source;
outGuid->[6] = (uint8_t)(slot & 0xFFu);
outGuid->[7] = (uint8_t)((slot >> 8) & 0xFFu);
outGuid->[8] = (uint8_t)((slot >> 16) & 0xFFu);
outGuid->[9] = (uint8_t)((slot >> 24) & 0xFFu);
}
// Static descriptor for backends compiled into this build.
typedef struct fpl__InputBackendDescriptor {
const char *name;
type;
supportedSources;
supportsEvents;
supportsPolling;
supportsHotplug;
} fpl__InputBackendDescriptor;
uint32_t fpl__BuildInputBackendDescriptors(fpl__InputBackendDescriptor *out, const uint32_t maxCount) {
uint32_t count = 0;
# if defined(FPL__ENABLE_INPUT_XINPUT)
if (count < maxCount) {
out[count].name = "XInput";
out[count].type = ;
out[count].supportedSources = ;
out[count].supportsEvents = true;
out[count].supportsPolling = true;
out[count].supportsHotplug = true;
count++;
}
# endif
# if defined(FPL__ENABLE_INPUT_DINPUT)
if (count < maxCount) {
out[count].name = "DirectInput";
out[count].type = ;
out[count].supportedSources = ;
out[count].supportsEvents = true;
out[count].supportsPolling = true;
out[count].supportsHotplug = true;
count++;
}
# endif
# if defined(FPL__ENABLE_INPUT_WIN32)
if (count < maxCount) {
out[count].name = "Win32 Keyboard/Mouse";
out[count].type = ;
out[count].supportedSources = ()( | );
out[count].supportsEvents = true;
out[count].supportsPolling = true;
out[count].supportsHotplug = false;
count++;
}
# endif
# if defined(FPL__ENABLE_INPUT_X11)
if (count < maxCount) {
out[count].name = "X11 Keyboard/Mouse";
out[count].type = ;
out[count].supportedSources = ()( | );
out[count].supportsEvents = true;
out[count].supportsPolling = true;
out[count].supportsHotplug = false;
count++;
}
# endif
# if defined(FPL__ENABLE_INPUT_LINUX_JOYSTICK)
if (count < maxCount) {
out[count].name = "Linux Joystick (/dev/input/jsX)";
out[count].type = ;
out[count].supportedSources = ;
out[count].supportsEvents = true;
out[count].supportsPolling = true;
out[count].supportsHotplug = false;
count++;
}
# endif
return count;
}
uint32_t ( *outSupports, const uint32_t maxCount) {
fpl__InputBackendDescriptor descriptors[];
uint32_t total = fpl__BuildInputBackendDescriptors(descriptors, (descriptors));
if (outSupports == || maxCount == 0) return total;
uint32_t writeCount = total < maxCount ? total : maxCount;
for (uint32_t i = 0; i < writeCount; ++i) {
(&outSupports[i]);
outSupports[i]. = descriptors[i].name;
outSupports[i]. = descriptors[i].type;
outSupports[i]. = descriptors[i].supportedSources;
outSupports[i]. = descriptors[i].supportsEvents;
outSupports[i]. = descriptors[i].supportsPolling;
outSupports[i]. = descriptors[i].supportsHotplug;
}
return writeCount;
}
bool (const type, *outSupport) {
if (outSupport != ) {
(outSupport);
}
fpl__InputBackendDescriptor descriptors[];
uint32_t total = fpl__BuildInputBackendDescriptors(descriptors, (descriptors));
for (uint32_t i = 0; i < total; ++i) {
if (descriptors[i].type != type) continue;
if (outSupport != ) {
outSupport-> = descriptors[i].name;
outSupport-> = descriptors[i].type;
outSupport-> = descriptors[i].supportedSources;
outSupport-> = descriptors[i].supportsEvents;
outSupport-> = descriptors[i].supportsPolling;
outSupport-> = descriptors[i].supportsHotplug;
}
return true;
}
return false;
}
// Single internal enumerator: walks active backends, writes filtered devices into out (when not null), returns total.
// When out is null or maxDevices is 0, returns the would-be device count.
uint32_t fpl__EnumerateInputDevices(const sourceFilter, *out, const uint32_t maxDevices) {
uint32_t count = 0;
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return 0;
const fpl__InputContext *ctx = &appState->input;
if (!ctx->isInitialized) return 0;
const kbmFeatures = ()( | );
const padFeatures = ()( | | );
# if defined(FPL__ENABLE_INPUT_WIN32)
if (ctx->win32kbm.isInitialized) {
if ((sourceFilter & ) != 0) {
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , 0);
("Win32 Keyboard", dev->, (dev->));
dev-> = 0;
dev-> = ;
dev-> = ;
dev-> = kbmFeatures;
dev-> = ;
}
count++;
}
if ((sourceFilter & ) != 0) {
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , 0);
("Win32 Mouse", dev->, (dev->));
dev-> = 0;
dev-> = ;
dev-> = ;
dev-> = kbmFeatures;
dev-> = ;
}
count++;
}
}
# endif
# if defined(FPL__ENABLE_INPUT_X11)
if (ctx->x11kbm.isInitialized) {
if ((sourceFilter & ) != 0) {
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , 0);
("X11 Keyboard", dev->, (dev->));
dev-> = 0;
dev-> = ;
dev-> = ;
dev-> = kbmFeatures;
dev-> = ;
}
count++;
}
if ((sourceFilter & ) != 0) {
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , 0);
("X11 Mouse", dev->, (dev->));
dev-> = 0;
dev-> = ;
dev-> = ;
dev-> = kbmFeatures;
dev-> = ;
}
count++;
}
}
# endif
# if defined(FPL__ENABLE_INPUT_XINPUT)
if (ctx->xinput.isInitialized && (sourceFilter & ) != 0) {
for (uint32_t i = 0; i < XUSER_MAX_COUNT; ++i) {
if (!ctx->xinput.isConnected[i]) continue;
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , i);
(ctx->xinput.deviceNames[i], dev->, (dev->));
dev-> = i;
dev-> = ;
dev-> = ;
dev-> = padFeatures;
dev-> = ;
}
count++;
}
}
# endif
# if defined(FPL__ENABLE_INPUT_DINPUT)
if (ctx->dinput.isInitialized && (sourceFilter & ) != 0) {
for (uint32_t i = 0; i < (ctx->dinput.slots); ++i) {
if (!ctx->dinput.slots[i].isConnected) continue;
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , i);
(ctx->dinput.slots[i].deviceName, dev->, (dev->));
dev-> = i;
dev-> = ;
dev-> = ;
dev-> = padFeatures;
dev-> = ;
dev->.gamepad = ctx->dinput.slots[i].lastState;
}
count++;
}
}
# endif
# if defined(FPL__ENABLE_INPUT_LINUX_JOYSTICK)
if (ctx->linuxJoystick.isInitialized && (sourceFilter & ) != 0) {
for (uint32_t i = 0; i < (ctx->linuxJoystick.gamepads); ++i) {
const fpl__InputLinuxJoystickGamepad *controller = &ctx->linuxJoystick.gamepads[i];
if (controller->fd <= 0) continue;
if (out != && count < maxDevices) {
*dev = &out[count];
(dev);
fpl__MakeInputDeviceGuid(&dev->, , , i);
const char *displayName = controller->displayName[0] != 0 ? controller->displayName : controller->deviceName;
(displayName, dev->, (dev->));
dev-> = i;
dev-> = ;
dev-> = ;
dev-> = padFeatures;
dev-> = ;
dev->.gamepad = controller->state;
}
count++;
}
}
# endif
return count;
}
uint32_t (const sourceFilter, *outDevices, const uint32_t maxDevices) {
if (outDevices == || maxDevices == 0) {
return fpl__EnumerateInputDevices(sourceFilter, , 0);
}
uint32_t total = fpl__EnumerateInputDevices(sourceFilter, outDevices, maxDevices);
return total < maxDevices ? total : maxDevices;
}
bool (const *guid, *outDevice) {
if (outDevice != ) {
(outDevice);
}
if (guid == ) return false;
scratch[];
uint32_t total = fpl__EnumerateInputDevices(, scratch, (scratch));
if (total > (scratch)) total = (scratch);
for (uint32_t i = 0; i < total; ++i) {
if (fpl__IsEqualsMemory(scratch[i].guid., guid->, sizeof(guid->))) {
if (outDevice != ) {
*outDevice = scratch[i];
}
return true;
}
}
return false;
}
uint32_t ( *outDevices, const uint32_t maxDevices) {
return (, outDevices, maxDevices);
}
uint32_t ( *outDevices, const uint32_t maxDevices) {
return (, outDevices, maxDevices);
}
uint32_t ( *outDevices, const uint32_t maxDevices) {
return (, outDevices, maxDevices);
}
// Drives the input subsystem update: detection + state events flow into the queue.
// Console-only apps (no window/no fplWindowUpdate) call this each frame to advance gamepad state.
bool (void) {
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return false;
if (appState->currentSettings.input.disabledEvents) return false;
fpl__InputSystem_Update(&appState->input);
return true;
}
// No-window event pump. The platform-specific fplPollEvent/fplPollEvents in the FPL__ENABLE_WINDOW
// blocks drain the OS message queue (Win32 PeekMessage / X11 XNextEvent). When no window is enabled,
// those impls don't compile and we provide a common version that drives fpl__InputSystem_Update and
// drains the internal event queue. Backends that own a no-window event source (Win32 RawInput on
// HWND_MESSAGE, future X11 InputOnly window) push into the queue from their _Update path.
#if !defined(FPL__ENABLE_WINDOW)
bool ( *ev) {
FPL__CheckArgumentNull(ev, false);
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return false;
if (fpl__PollInternalEvent(ev)) return true;
if (!appState->currentSettings.input.disabledEvents) {
fpl__InputSystem_Update(&appState->input);
}
return fpl__PollInternalEvent(ev);
}
void (void) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return;
if (!appState->currentSettings.input.disabledEvents) {
fpl__InputSystem_Update(&appState->input);
}
fpl__ClearInternalEvents();
}
#endif // !FPL__ENABLE_WINDOW
#endif // FPL__ENABLE_INPUT
void ( *settings) {
FPL__CheckArgumentNullNoRet(settings);
(settings);
(&settings->);
(&settings->);
(&settings->);
(&settings->);
}
(void) {
result;
(&result);
return(result);
}
#define FPL__PLATFORMRESULTTYPE_COUNT FPL__ENUM_COUNT(fplPlatformResultType_First, fplPlatformResultType_Last)
( == );
( == );
const char *fpl__global_platformResultTypeNameTable[] = {
FPL__ENUM_NAME("Failed Window", ),
FPL__ENUM_NAME("Failed Audio", ),
FPL__ENUM_NAME("Failed Video", ),
FPL__ENUM_NAME("Failed Platform", ),
FPL__ENUM_NAME("Out of Memory", ),
FPL__ENUM_NAME("Already Initialized", ),
FPL__ENUM_NAME("Not Initialized", ),
FPL__ENUM_NAME("Success", ),
};
((fpl__global_platformResultTypeNameTable) == FPL__PLATFORMRESULTTYPE_COUNT);
const char *(const type) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(type, , );
const char *result = fpl__global_platformResultTypeNameTable[index];
return(result);
}
#define FPL__ARCHTYPE_COUNT FPL__ENUM_COUNT(fplCPUArchType_First, fplCPUArchType_Last)
( == );
( == );
const char *fpl__global_ArchTypeNameTable[] = {
FPL__ENUM_NAME("Unknown", ),
FPL__ENUM_NAME("x86", ),
FPL__ENUM_NAME("x86_64", ),
FPL__ENUM_NAME("x64", ),
FPL__ENUM_NAME("arm32", ),
FPL__ENUM_NAME("arm64", ),
};
((fpl__global_ArchTypeNameTable) == FPL__ARCHTYPE_COUNT);
const char *(const type) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(type, , );
const char *result = fpl__global_ArchTypeNameTable[index];
return(result);
}
#define FPL__CPU_CAPABILITIESTYPE_COUNT FPL__ENUM_COUNT(fplCPUCapabilitiesType_First, fplCPUCapabilitiesType_Last)
( == );
( == );
const char *fpl__global_CPUCapabilitesTypeNameTable[] = {
FPL__ENUM_NAME("Unknown", ),
FPL__ENUM_NAME("X86", ),
FPL__ENUM_NAME("ARM", ),
};
((fpl__global_CPUCapabilitesTypeNameTable) == FPL__CPU_CAPABILITIESTYPE_COUNT);
const char *(const type) {
uint32_t index = FPL__ENUM_VALUE_TO_ARRAY_INDEX(type, , );
const char *result = fpl__global_CPUCapabilitesTypeNameTable[index];
return(result);
}
//
// Debug out
//
#if defined(FPL_PLATFORM_WINDOWS)
void (const char *text) {
wchar_t buffer[];
(text, (text), buffer, (buffer));
OutputDebugStringW(buffer);
}
#else
void (const char *text) {
(text);
}
#endif
void (const char *format, ...) {
if (format != ) {
char buffer[];
va_list argList;
va_start(argList, format);
(buffer, (buffer), format, argList);
va_end(argList);
(buffer);
}
}
//
// Color
//
(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a) {
result = (, { b, g, r, a });
return(result);
}
#endif // FPL__COMMON_DEFINED
// ############################################################################
//
// > WIN32_PLATFORM (Win32, Win64)
//
// ############################################################################
#if defined(FPL_PLATFORM_WINDOWS)
# if defined(FPL_ARCH_X86)
# define FPL_MEMORY_BARRIER() \
LONG barrier; \
_InterlockedOr(&barrier, 0);
# elif defined(FPL_ARCH_X64)
// @NOTE(final): No need for hardware memory fence on X64 because the hardware guarantees memory order always.
# define FPL_MEMORY_BARRIER()
# endif
#if defined(FPL__ENABLE_WINDOW)
DWORD fpl__Win32MakeWindowStyle(const *settings) {
DWORD result = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
if (settings-> || !settings->) {
result |= WS_POPUP;
} else {
result |= WS_OVERLAPPEDWINDOW;
if (!settings->) {
result &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
}
}
return(result);
}
DWORD fpl__Win32MakeWindowExStyle(const *settings) {
DWORD result = WS_EX_APPWINDOW;
if (settings-> || settings->) {
result |= WS_EX_TOPMOST;
}
return(result);
}
void fpl__Win32SaveWindowState(const fpl__Win32Api *wapi, fpl__Win32LastWindowInfo *target, HWND windowHandle) {
target->isMaximized = !!wapi->user.IsZoomed(windowHandle);
target->isMinimized = !!wapi->user.IsIconic(windowHandle);
target->style = fpl__win32_GetWindowLong(windowHandle, GWL_STYLE);
target->exStyle = fpl__win32_GetWindowLong(windowHandle, GWL_EXSTYLE);
wapi->user.GetWindowPlacement(windowHandle, &target->placement);
}
void fpl__Win32RestoreWindowState(const fpl__Win32Api *wapi, const fpl__Win32LastWindowInfo *target, HWND windowHandle) {
(target->style > 0 && target->exStyle > 0);
fpl__win32_SetWindowLong(windowHandle, GWL_STYLE, target->style);
fpl__win32_SetWindowLong(windowHandle, GWL_EXSTYLE, target->exStyle);
wapi->user.SetWindowPlacement(windowHandle, &target->placement);
wapi->user.SetWindowPos(windowHandle, , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
if (target->isMaximized) {
wapi->user.SendMessageW(windowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
} else if (target->isMinimized) {
wapi->user.SendMessageW(windowHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
}
bool fpl__Win32LeaveFullscreen(void) {
const fpl__PlatformAppState *platState = fpl__global__AppState;
(platState != );
const fpl__Win32AppState *win32State = &platState->win32;
const fpl__Win32Api *wapi = &win32State->winApi;
const *settings = &platState->currentSettings.window;
const fpl__Win32WindowState *win32Window = &platState->window.win32;
const fpl__Win32LastWindowInfo *fullscreenInfo = &win32Window->lastFullscreenInfo;
HWND windowHandle = win32Window->windowHandle;
fpl__Win32RestoreWindowState(wapi, fullscreenInfo, windowHandle);
bool result;
if (fullscreenInfo->wasResolutionChanged) {
result = (wapi->user.ChangeDisplaySettingsW(, CDS_RESET) == DISP_CHANGE_SUCCESSFUL);
} else {
result = true;
}
return(result);
}
bool fpl__Win32EnterFullscreen(const int32_t xpos, const int32_t ypos, const int32_t fullscreenWidth, const int32_t fullscreenHeight, const uint32_t refreshRate, const uint32_t colorBits, const bool allowResolutionChange) {
fpl__PlatformAppState *platState = fpl__global__AppState;
(platState != );
fpl__Win32AppState *win32State = &platState->win32;
const fpl__Win32Api *wapi = &win32State->winApi;
const *settings = &platState->currentSettings.window;
fpl__Win32WindowState *win32Window = &platState->window.win32;
fpl__Win32LastWindowInfo *fullscreenInfo = &win32Window->lastFullscreenInfo;
HWND windowHandle = win32Window->windowHandle;
HDC deviceContext = win32Window->deviceContext;
(fullscreenInfo->style > 0 && fullscreenInfo->exStyle > 0);
fpl__win32_SetWindowLong(windowHandle, GWL_STYLE, fullscreenInfo->style & ~(WS_CAPTION | WS_THICKFRAME));
fpl__win32_SetWindowLong(windowHandle, GWL_EXSTYLE, fullscreenInfo->exStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
MONITORINFO monitor = ;
monitor.cbSize = sizeof(monitor);
wapi->user.GetMonitorInfoW(wapi->user.MonitorFromWindow(windowHandle, MONITOR_DEFAULTTONEAREST), &monitor);
bool result;
if (allowResolutionChange && (fullscreenWidth > 0) && (fullscreenHeight > 0)) {
int32_t useFullscreenWidth = fullscreenWidth;
int32_t useFullscreenHeight = fullscreenHeight;
DWORD useRefreshRate = refreshRate;
if (!useRefreshRate) {
useRefreshRate = wapi->gdi.GetDeviceCaps(deviceContext, VREFRESH);
}
DWORD useColourBits = colorBits;
if (!useColourBits) {
useColourBits = wapi->gdi.GetDeviceCaps(deviceContext, BITSPIXEL);
}
RECT windowRect;
// Anchor to xpos/ypos when valid, otherwise to the target monitor's origin (multi-monitor safe).
if ((xpos != INT32_MAX) && (ypos != INT32_MAX)) {
windowRect.left = xpos;
windowRect.top = ypos;
} else {
windowRect.left = monitor.rcMonitor.left;
windowRect.top = monitor.rcMonitor.top;
}
windowRect.right = windowRect.left + useFullscreenWidth;
windowRect.bottom = windowRect.top + useFullscreenHeight;
WINDOWPLACEMENT placement = ;
placement.length = sizeof(placement);
placement.rcNormalPosition = windowRect;
placement.showCmd = SW_SHOW;
wapi->user.SetWindowPlacement(windowHandle, &placement);
wapi->user.SetWindowPos(windowHandle, , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
DEVMODEW fullscreenSettings = ;
wapi->user.EnumDisplaySettingsW(, 0, &fullscreenSettings);
fullscreenSettings.dmPelsWidth = useFullscreenWidth;
fullscreenSettings.dmPelsHeight = useFullscreenHeight;
fullscreenSettings.dmBitsPerPel = useColourBits;
fullscreenSettings.dmDisplayFrequency = useRefreshRate;
fullscreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
result = (wapi->user.ChangeDisplaySettingsW(&fullscreenSettings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL);
fullscreenInfo->wasResolutionChanged = true;
} else {
RECT windowRect = ;
if ((xpos != INT32_MAX) && (ypos != INT32_MAX) && (fullscreenWidth != 0) && (fullscreenHeight != 0)) {
windowRect.left = xpos;
windowRect.top = ypos;
windowRect.right = xpos + fullscreenWidth;
windowRect.bottom = ypos + fullscreenHeight;
} else {
windowRect = monitor.rcMonitor;
}
WINDOWPLACEMENT placement = ;
placement.length = sizeof(placement);
placement.rcNormalPosition = windowRect;
placement.showCmd = SW_SHOWNORMAL;
wapi->user.SetWindowPlacement(windowHandle, &placement);
wapi->user.SetWindowPos(windowHandle, , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
result = true;
fullscreenInfo->wasResolutionChanged = false;
}
return(result);
}
bool fpl__Win32SetWindowFullscreen(const bool value, const int32_t x, const int32_t y, const int32_t w, const int32_t h, const uint32_t refreshRate, const bool allowResolutionChange) {
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__Win32AppState *win32AppState = &appState->win32;
fpl__Win32WindowState *windowState = &appState->window.win32;
*windowSettings = &appState->currentSettings.window;
fpl__Win32LastWindowInfo *fullscreenState = &windowState->lastFullscreenInfo;
const fpl__Win32Api *wapi = &win32AppState->winApi;
HWND windowHandle = windowState->windowHandle;
// Save current window info if not already fullscreen
if (!windowSettings->) {
fpl__Win32SaveWindowState(wapi, fullscreenState, windowHandle);
if (fullscreenState->isMaximized || fullscreenState->isMinimized) {
wapi->user.ShowWindow(windowHandle, SW_RESTORE);
}
}
if (value) {
// Enter fullscreen mode or fallback to window mode
windowSettings-> = fpl__Win32EnterFullscreen(x, y, w, h, refreshRate, 0, allowResolutionChange);
if (!windowSettings->) {
fpl__Win32LeaveFullscreen();
}
} else {
fpl__Win32LeaveFullscreen();
windowSettings-> = false;
}
bool result = windowSettings-> != 0;
return(result);
}
#endif // FPL__ENABLE_WINDOW (briefly closed so input backend can use the key-state helpers without a window)
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT_WIN32)
bool fpl__Win32IsKeyDown(const fpl__Win32Api *wapi, const int virtualKey) {
bool result = (wapi->user.GetAsyncKeyState(virtualKey) & 0x8000) != 0;
return(result);
}
bool fpl__Win32IsKeyActive(const fpl__Win32Api *wapi, const int virtualKey) {
bool result = (wapi->user.GetKeyState(virtualKey) & 0x0001) != 0;
return(result);
}
#endif
#if defined(FPL__ENABLE_WINDOW)
bool fpl__Win32IsCursorInWindow(const fpl__Win32Api *wapi, const fpl__Win32WindowState *win32Window) {
POINT pos;
if (!wapi->user.GetCursorPos(&pos)) {
return false;
}
// Not this window?
if (wapi->user.WindowFromPoint(pos) != win32Window->windowHandle) {
return false;
}
// Cursor in client rect?
RECT area;
wapi->user.GetClientRect(win32Window->windowHandle, &area);
wapi->user.ClientToScreen(win32Window->windowHandle, (LPPOINT)&area.left);
wapi->user.ClientToScreen(win32Window->windowHandle, (LPPOINT)&area.right);
bool result = wapi->user.PtInRect(&area, pos) == TRUE;
return(result);
}
void fpl__Win32LoadCursor(const fpl__Win32Api *wapi, const fpl__Win32WindowState *window) {
if (window->isCursorActive) {
wapi->user.SetCursor(fpl__win32_LoadCursor(, IDC_ARROW));
} else {
wapi->user.SetCursor();
}
}
void fpl__Win32SetCursorState(const fpl__Win32Api *wapi, fpl__Win32WindowState *window, const bool state) {
// @NOTE(final): We use RAWINPUT to remove the mouse device entirely when it needs to be hidden
if (!state) {
const RAWINPUTDEVICE rid = (RAWINPUTDEVICE, 0x01, 0x02, 0, window->windowHandle);
if (!wapi->user.RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
FPL__ERROR(FPL__MODULE_WINDOW, "Failed register raw input mouse device for window handle '%p'", window->windowHandle);
}
} else {
const RAWINPUTDEVICE rid = (RAWINPUTDEVICE, 0x01, 0x02, RIDEV_REMOVE, );
if (!wapi->user.RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
FPL__ERROR(FPL__MODULE_WINDOW, "Failed to unregister raw input mouse device");
}
}
if (fpl__Win32IsCursorInWindow(wapi, window)) {
fpl__Win32LoadCursor(wapi, window);
}
}
void fpl__Win32ShowCursor(const fpl__Win32Api *wapi, fpl__Win32WindowState *window) {
fpl__Win32SetCursorState(wapi, window, false);
}
void fpl__Win32HideCursor(const fpl__Win32Api *wapi, fpl__Win32WindowState *window) {
fpl__Win32SetCursorState(wapi, window, true);
}
#endif // FPL__ENABLE_WINDOW (briefly closed so input backend can use the modifier helper without a window)
#if defined(FPL__ENABLE_WINDOW) || defined(FPL__ENABLE_INPUT_WIN32)
fpl__Win32GetKeyboardModifiers(const fpl__Win32Api *wapi) {
modifiers = ;
bool lAltKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_LMENU);
bool rAltKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_RMENU);
bool lShiftKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_LSHIFT);
bool rShiftKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_RSHIFT);
bool lCtrlKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_LCONTROL);
bool rCtrlKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_RCONTROL);
bool lSuperKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_LWIN);
bool rSuperKeyIsDown = fpl__Win32IsKeyDown(wapi, VK_RWIN);
bool capsLockActive = fpl__Win32IsKeyActive(wapi, VK_CAPITAL);
bool numLockActive = fpl__Win32IsKeyActive(wapi, VK_NUMLOCK);
bool scrollLockActive = fpl__Win32IsKeyActive(wapi, VK_SCROLL);
if (lAltKeyIsDown) {
modifiers |= ;
}
if (rAltKeyIsDown) {
modifiers |= ;
}
if (lShiftKeyIsDown) {
modifiers |= ;
}
if (rShiftKeyIsDown) {
modifiers |= ;
}
if (lCtrlKeyIsDown) {
modifiers |= ;
}
if (rCtrlKeyIsDown) {
modifiers |= ;
}
if (lSuperKeyIsDown) {
modifiers |= ;
}
if (rSuperKeyIsDown) {
modifiers |= ;
}
if (capsLockActive) {
modifiers |= ;
}
if (numLockActive) {
modifiers |= ;
}
if (scrollLockActive) {
modifiers |= ;
}
return(modifiers);
}
#endif // FPL__ENABLE_WINDOW || FPL__ENABLE_INPUT_WIN32
#if defined(FPL__ENABLE_WINDOW)
void fpl__Win32HandleMessage(const fpl__Win32Api *wapi, fpl__PlatformAppState *appState, fpl__Win32WindowState *windowState, MSG *msg) {
if (appState->currentSettings.window.callbacks.eventCallback != ) {
appState->currentSettings.window.callbacks.eventCallback((), windowState, &msg, appState->currentSettings.window.callbacks.eventUserData);
}
wapi->user.TranslateMessage(msg);
wapi->user.DispatchMessageW(msg);
}
void CALLBACK fpl__Win32MessageFiberProc(struct fpl__PlatformAppState *appState) {
fpl__Win32AppState *win32State = &appState->win32;
fpl__Win32WindowState *windowState = &appState->window.win32;
const fpl__Win32Api *wapi = &win32State->winApi;
wapi->user.SetTimer(appState->window.win32.windowHandle, 1, 1, 0);
for (;;) {
MSG message;
while (wapi->user.PeekMessageW(&message, 0, 0, 0, PM_REMOVE)) {
fpl__Win32HandleMessage(wapi, appState, windowState, &message);
}
SwitchToFiber(appState->window.win32.mainFiber);
}
}
bool fpl__Win32WindowGotFocus(const fpl__Win32Api *wapi, fpl__Win32WindowState *windowState) {
newEvent = ;
newEvent. = ;
newEvent.. = ;
fpl__PushInternalEvent(&newEvent);
if (!windowState->isCursorActive) {
fpl__Win32HideCursor(wapi, windowState);
}
if (windowState->isFrameInteraction) {
return false;
}
return true;
}
bool fpl__Win32WindowLostFocus(const fpl__Win32Api *wapi, fpl__Win32WindowState *windowState) {
if (!windowState->isCursorActive) {
fpl__Win32ShowCursor(wapi, windowState);
}
newEvent = ;
newEvent. = ;
newEvent.. = ;
fpl__PushInternalEvent(&newEvent);
return true;
}
LRESULT CALLBACK fpl__Win32MessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
fpl__PlatformAppState *appState = fpl__global__AppState;
(appState != );
fpl__Win32AppState *win32State = &appState->win32;
fpl__Win32WindowState *win32Window = &appState->window.win32;
const fpl__Win32Api *wapi = &win32State->winApi;
if (!win32Window->windowHandle) {
return wapi->user.DefWindowProcW(hwnd, msg, wParam, lParam);
}
LRESULT result = 0;
switch (msg) {
case WM_TIMER:
{
if (win32Window->mainFiber != ) {
SwitchToFiber(win32Window->mainFiber);
}
} break;
case WM_DESTROY:
case WM_CLOSE:
{
appState->window.isRunning = false;
} break;
case WM_SIZE:
{
DWORD newWidth = LOWORD(lParam);
DWORD newHeight = HIWORD(lParam);
if (wParam == SIZE_MAXIMIZED) {
fpl__PushWindowSizeEvent(, newWidth, newHeight);
} else if (wParam == SIZE_MINIMIZED) {
fpl__PushWindowSizeEvent(, newWidth, newHeight);
} else if (wParam == SIZE_RESTORED) {
fpl__PushWindowSizeEvent(, newWidth, newHeight);
}
# if defined(FPL__ENABLE_VIDEO_SOFTWARE)
if (appState->currentSettings.video.backend == ) {
if (appState->initSettings.video.isAutoSize) {
(newWidth, newHeight);
}
}
# endif
fpl__PushWindowSizeEvent(, newWidth, newHeight);
return 0;
} break;
case WM_DROPFILES:
{
HDROP dropHandle = (HDROP)wParam;
char fileBufferA[];
UINT fileCount;
wchar_t fileBufferW[];
fileCount = wapi->shell.DragQueryFileW(dropHandle, 0xFFFFFFFF, fileBufferW, 0);
if (fileCount > 0) {
size_t filesTableSize = fileCount * sizeof(char **);
size_t maxFileStride = * 2 + 1;
size_t filesMemorySize = filesTableSize + FPL__ARBITARY_PADDING + maxFileStride * fileCount;
void *filesTableMemory = fpl__AllocateDynamicMemory(filesMemorySize, 16);
char **filesTable = (char **)filesTableMemory;
for (UINT fileIndex = 0; fileIndex < fileCount; ++fileIndex) {
filesTable[fileIndex] = (char *)((uint8_t *)filesTableMemory + filesTableSize + FPL__ARBITARY_PADDING + fileIndex * maxFileStride);
}
for (UINT fileIndex = 0; fileIndex < fileCount; ++fileIndex) {
char *file = filesTable[fileIndex];
fileBufferW[0] = 0;
UINT dragResult = wapi->shell.DragQueryFileW(dropHandle, 0, fileBufferW, (fileBufferW));
size_t sourceLen = lstrlenW(fileBufferW);
(fileBufferW, sourceLen, file, maxFileStride);
}
memory = ;
memory. = filesMemorySize;
memory. = filesTableMemory;
fpl__PushWindowDropFilesEvent(fileBufferA, fileCount, (const char **)filesTable, &memory);
}
} break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
{
#if defined(FPL__ENABLE_INPUT)
MSG forwarded = ;
forwarded.hwnd = hwnd;
forwarded.message = msg;
forwarded.wParam = wParam;
forwarded.lParam = lParam;
fpl__NativeInputEvent ev = ;
ev.kind = fpl__NativeInputEventKind_Win32Msg;
ev.payload = (void *)&forwarded;
fpl__InputSystem_HandleNativeEvent(&appState->input, &ev);
#endif
} break;
case WM_CHAR:
case WM_SYSCHAR:
case WM_UNICHAR:
case WM_DEADCHAR:
{
if ((msg == WM_UNICHAR) && (wParam == UNICODE_NOCHAR)) {
// @NOTE(final): WM_UNICHAR was sent by a third-party input method. Do not add any chars here!
return TRUE;
}
#if defined(FPL__ENABLE_INPUT)
MSG forwarded = ;
forwarded.hwnd = hwnd;
forwarded.message = msg;
forwarded.wParam = wParam;
forwarded.lParam = lParam;
fpl__NativeInputEvent ev = ;
ev.kind = fpl__NativeInputEventKind_Win32Msg;
ev.payload = (void *)&forwarded;
fpl__InputSystem_HandleNativeEvent(&appState->input, &ev);
#endif
return 0;
} break;
case WM_ACTIVATE:
{
} break;
case WM_MOUSEACTIVATE:
{
if (HIWORD(lParam) == WM_LBUTTONDOWN) {
if (LOWORD(lParam) == HTCLOSE || LOWORD(lParam) == HTMINBUTTON || LOWORD(lParam) == HTMAXBUTTON) {
win32Window->isFrameInteraction = true;
}
}
} break;
case WM_CAPTURECHANGED:
{
if (lParam == 0 && win32Window->isFrameInteraction) {
if (!win32Window->isCursorActive) {
fpl__Win32HideCursor(wapi, win32Window);
}
win32Window->isFrameInteraction = false;
}
} break;
case WM_ACTIVATEAPP:
{
if (wParam == 1) {
if (!fpl__Win32WindowGotFocus(wapi, win32Window)) {
break;
}
} else {
if (!fpl__Win32WindowLostFocus(wapi, win32Window)) {
break;
}
}
return 0;
} break;
case WM_ENTERSIZEMOVE:
case WM_ENTERMENULOOP:
{
// Restore cursor when needed
if (!win32Window->isCursorActive) {
fpl__Win32ShowCursor(wapi, win32Window);
}
} break;
case WM_EXITSIZEMOVE:
case WM_EXITMENULOOP:
{
if (!win32Window->isCursorActive) {
fpl__Win32HideCursor(wapi, win32Window);
}
} break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
{
#if defined(FPL__ENABLE_INPUT)
MSG forwarded = ;
forwarded.hwnd = hwnd;
forwarded.message = msg;
forwarded.wParam = wParam;
forwarded.lParam = lParam;
fpl__NativeInputEvent ev = ;
ev.kind = fpl__NativeInputEventKind_Win32Msg;
ev.payload = (void *)&forwarded;
fpl__InputSystem_HandleNativeEvent(&appState->input, &ev);
#endif
} break;
case WM_SETCURSOR:
{
if (LOWORD(lParam) == HTCLIENT) {
fpl__Win32LoadCursor(wapi, win32Window);
return TRUE;
}
} break;
case WM_PAINT:
{
if (appState->currentSettings.window.callbacks.exposedCallback != ) {
MSG msgData = ;
msgData.message = msg;
msgData.hwnd = hwnd;
msgData.wParam = wParam;
msgData.lParam = lParam;
appState->currentSettings.window.callbacks.exposedCallback((), win32Window, &msgData, appState->currentSettings.window.callbacks.exposedUserData);
} else {
if (appState->currentSettings.video.backend == ) {
PAINTSTRUCT ps;
HDC hdc = wapi->user.BeginPaint(hwnd, &ps);
wapi->user.EndPaint(hwnd, &ps);
return(0);
}
}
} break;
case WM_ERASEBKGND:
{
// Prevent erasing of the background always, but only if a video backend is being used
// @NOTE(tspaete): Do not prevent the erasing of the backend for software video output, otherwise we will get weird flickering issue at startup
if (appState->currentSettings.video.backend != && appState->currentSettings.video.backend != ) {
return 1;
}
} break;
case WM_SYSCOMMAND:
{
WPARAM masked = wParam & 0xFFF0;
switch (masked) {
case SC_SCREENSAVE:
case SC_MONITORPOWER: {
if (appState->currentSettings.window.isScreenSaverPrevented || appState->currentSettings.window.isMonitorPowerPrevented) {
return 0;
}
} break;
}
} break;
default:
break;
}
result = wapi->user.DefWindowProcW(hwnd, msg, wParam, lParam);
return (result);
}
HICON fpl__Win32LoadIconFromImageSource(const fpl__Win32Api *wapi, const HINSTANCE appInstance, const *imageSource) {
(imageSource != );
HICON result = 0;
if (imageSource-> > 0 && imageSource-> > 0 && imageSource-> != ) {
BITMAPV5HEADER bi = ;
bi.bV5Size = sizeof(bi);
bi.bV5Width = (LONG)imageSource->;
bi.bV5Height = -(LONG)imageSource->;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
bi.bV5RedMask = 0x00ff0000;
bi.bV5GreenMask = 0x0000ff00;
bi.bV5BlueMask = 0x000000ff;
bi.bV5AlphaMask = 0xff000000;
uint8_t *targetData = ;
HDC dc = wapi->user.GetDC();
HBITMAP colorBitmap = wapi->gdi.CreateDIBSection(dc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetData, , (DWORD)0);
if (colorBitmap == ) {
FPL__ERROR(FPL__MODULE_WIN32, "Failed to create DIBSection from image with size %lu x %lu", imageSource->, imageSource->);
}
wapi->user.ReleaseDC(, dc);
HBITMAP maskBitmap = wapi->gdi.CreateBitmap(imageSource->, imageSource->, 1, 1, );
if (maskBitmap == ) {
FPL__ERROR(FPL__MODULE_WIN32, "Failed to create Bitmap Mask from image with size %lu x %lu", imageSource->, imageSource->);
}
if (colorBitmap != && maskBitmap != ) {
(targetData != );
uint8_t *dst = targetData;
const uint8_t *src = imageSource->;
if (imageSource-> == ) {
for (uint32_t i = 0; i < imageSource-> * imageSource->; ++i) {
dst[0] = src[2]; // R > B
dst[1] = src[1]; // G > G
dst[2] = src[0]; // B > R
dst[3] = src[3]; // A > A
src += 4;
dst += 4;
}
ICONINFO ii = ;
ii.fIcon = TRUE;
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = maskBitmap;
ii.hbmColor = colorBitmap;
result = wapi->user.CreateIconIndirect(&ii);
} else {
FPL__ERROR(FPL__MODULE_WIN32, "Image source type '%d' for icon is not supported", imageSource->);
}
}
if (colorBitmap != ) {
wapi->gdi.DeleteObject(colorBitmap);
}
if (maskBitmap != ) {
wapi->gdi.DeleteObject(maskBitmap);
}
}
if (result == 0) {
result = fpl__win32_LoadIcon(appInstance, IDI_APPLICATION);
}
return(result);
}
fpl__Win32TranslateVirtualKey(const fpl__Win32Api *wapi, const uint64_t virtualKey) {
switch (virtualKey) {
case VK_BACK:
return ;
case VK_TAB:
return ;
case VK_CLEAR:
return ;
case VK_RETURN:
return ;
case VK_SHIFT:
return ;
case VK_CONTROL:
return ;
case VK_MENU:
return ;
case VK_PAUSE:
return ;
case VK_CAPITAL:
return ;
case VK_ESCAPE:
return ;
case VK_SPACE:
return ;
case VK_PRIOR:
return ;
case VK_NEXT:
return ;
case VK_END:
return ;
case VK_HOME:
return ;
case VK_LEFT:
return ;
case VK_UP:
return ;
case VK_RIGHT:
return ;
case VK_DOWN:
return ;
case VK_SELECT:
return ;
case VK_PRINT:
return ;
case VK_EXECUTE:
return ;
case VK_SNAPSHOT:
return ;
case VK_INSERT:
return ;
case VK_DELETE:
return ;
case VK_HELP:
return ;
case 0x30:
return ;
case 0x31:
return ;
case 0x32:
return ;
case 0x33:
return ;
case 0x34:
return ;
case 0x35:
return ;
case 0x36:
return ;
case 0x37:
return ;
case 0x38:
return ;
case 0x39:
return ;
case 0x41:
return ;
case 0x42:
return ;
case 0x43:
return ;
case 0x44:
return ;
case 0x45:
return ;
case 0x46:
return ;
case 0x47:
return ;
case 0x48:
return ;
case 0x49:
return ;
case 0x4A:
return ;
case 0x4B:
return ;
case 0x4C:
return ;
case 0x4D:
return ;
case 0x4E:
return ;
case 0x4F:
return ;
case 0x50:
return ;
case 0x51:
return ;
case 0x52:
return ;
case 0x53:
return ;
case 0x54:
return ;
case 0x55:
return ;
case 0x56:
return ;
case 0x57:
return ;
case 0x58:
return ;
case 0x59:
return ;
case 0x5A:
return ;
case VK_LWIN:
return ;
case VK_RWIN:
return ;
case VK_APPS:
return ;
case VK_SLEEP:
return ;
case VK_NUMPAD0:
return ;
case VK_NUMPAD1:
return ;
case VK_NUMPAD2:
return ;
case VK_NUMPAD3:
return ;
case VK_NUMPAD4:
return ;
case VK_NUMPAD5:
return ;
case VK_NUMPAD6:
return ;
case VK_NUMPAD7:
return ;
case VK_NUMPAD8:
return ;
case VK_NUMPAD9:
return ;
case VK_MULTIPLY:
return ;
case VK_ADD:
return ;
case VK_SEPARATOR:
return ;
case VK_SUBTRACT:
return ;
case VK_DECIMAL:
return ;
case VK_DIVIDE:
return ;
case VK_F1:
return ;
case VK_F2:
return ;
case VK_F3:
return ;
case VK_F4:
return ;
case VK_F5:
return ;
case VK_F6:
return ;
case VK_F7:
return ;
case VK_F8:
return ;
case VK_F9:
return ;
case VK_F10:
return ;
case VK_F11:
return ;
case VK_F12:
return ;
case VK_F13:
return ;
case VK_F14:
return ;
case VK_F15:
return ;
case VK_F16:
return ;
case VK_F17:
return ;
case VK_F18:
return ;
case VK_F19:
return ;
case VK_F20:
return ;
case VK_F21:
return ;
case VK_F22:
return ;
case VK_F23:
return ;
case VK_F24:
return ;
case VK_LSHIFT:
return ;
case VK_RSHIFT:
return ;
case VK_LCONTROL:
return ;
case VK_RCONTROL:
return ;
case VK_LMENU:
return ;
case VK_RMENU:
return ;
case VK_VOLUME_MUTE:
return ;
case VK_VOLUME_DOWN:
return ;
case VK_VOLUME_UP:
return ;
case VK_MEDIA_NEXT_TRACK:
return ;
case VK_MEDIA_PREV_TRACK:
return ;
case VK_MEDIA_STOP:
return ;
case VK_MEDIA_PLAY_PAUSE:
return ;
case VK_OEM_MINUS:
return ;
case VK_OEM_PLUS:
return ;
case VK_OEM_COMMA:
return ;
case VK_OEM_PERIOD:
return ;
case VK_OEM_1:
return ;
case VK_OEM_2:
return ;
case VK_OEM_3:
return ;
case VK_OEM_4:
return ;
case VK_OEM_5:
return ;
case VK_OEM_6:
return ;
case VK_OEM_7:
return ;
case VK_OEM_8:
return ;
default:
return ;
}
}
bool fpl__Win32InitWindow(const *initSettings, *currentWindowSettings, fpl__PlatformAppState *platAppState, fpl__Win32AppState *appState, fpl__Win32WindowState *windowState, const fpl__SetupWindowCallbacks *setupCallbacks) {
(appState != );
const fpl__Win32Api *wapi = &appState->winApi;
const *initWindowSettings = &initSettings->;
// Init keymap
(platAppState->window.keyMap);
for (int i = 0; i < 256; ++i) {
int vk = wapi->user.MapVirtualKeyW(MAPVK_VSC_TO_VK, i);
if (vk == 0) {
vk = i;
}
platAppState->window.keyMap[i] = fpl__Win32TranslateVirtualKey(wapi, vk);
}
// Hint for windows to know, that the application is in use always
if (initSettings->. || initSettings->.) {
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
} else {
SetThreadExecutionState(ES_CONTINUOUS);
}
// Presetup window
if (setupCallbacks->preSetup != ) {
setupCallbacks->preSetup(platAppState, platAppState->initFlags, &platAppState->initSettings);
}
// Register window class
WNDCLASSEXW windowClass = ;
windowClass.cbSize = sizeof(windowClass);
windowClass.hInstance = GetModuleHandleA();
// Set window background, either as system brush or custom brush which needs to be released when changed or the platform is released
if (initWindowSettings->. == 0) {
windowState->backgroundBrush = ;
windowClass.hbrBackground = wapi->user.GetSysColorBrush(COLOR_BACKGROUND);
} else {
COLORREF brushColor = RGB(initWindowSettings->.., initWindowSettings->.., initWindowSettings->..);
windowState->backgroundBrush = wapi->gdi.CreateSolidBrush(brushColor);
windowClass.hbrBackground = windowState->backgroundBrush;
}
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.hCursor = fpl__win32_LoadCursor(windowClass.hInstance, IDC_ARROW);
windowClass.hIconSm = fpl__Win32LoadIconFromImageSource(wapi, windowClass.hInstance, &initWindowSettings->[0]);
windowClass.hIcon = fpl__Win32LoadIconFromImageSource(wapi, windowClass.hInstance, &initWindowSettings->[1]);
windowClass.lpszClassName = FPL__WIN32_CLASSNAME;
windowClass.lpfnWndProc = fpl__Win32MessageProc;
windowClass.style |= CS_OWNDC;
lstrcpynW(windowState->windowClass, windowClass.lpszClassName, (windowState->windowClass));
if (wapi->user.RegisterClassExW(&windowClass) == 0) {
FPL__ERROR(FPL__MODULE_WINDOW, "Failed registering window class '%s'", windowState->windowClass);
return false;
}
// Set window title
wchar_t windowTitleBuffer[];
if ((initWindowSettings->) > 0) {
(initWindowSettings->, (initWindowSettings->), windowTitleBuffer, (windowTitleBuffer));
} else {
const wchar_t *defaultTitle = FPL__WIN32_UNNAMED_WINDOW;
lstrcpynW(windowTitleBuffer, defaultTitle, (windowTitleBuffer));
}
wchar_t *windowTitle = windowTitleBuffer;
(windowTitle, lstrlenW(windowTitle), currentWindowSettings->, (currentWindowSettings->));
// Create Fibers
windowState->mainFiber = ConvertThreadToFiber(0);
windowState->messageFiber = CreateFiber(0, (PFIBER_START_ROUTINE)fpl__Win32MessageFiberProc, platAppState);
// Prepare window style, size and position
DWORD style = fpl__Win32MakeWindowStyle(&initSettings->);
DWORD exStyle = fpl__Win32MakeWindowExStyle(&initSettings->);
if (initSettings->.) {
currentWindowSettings-> = true;
} else {
currentWindowSettings-> = false;
}
int windowX = CW_USEDEFAULT;
int windowY = CW_USEDEFAULT;
int windowWidth;
int windowHeight;
if ((initWindowSettings->. > 0) &&
(initWindowSettings->. > 0)) {
RECT windowRect;
windowRect.left = 0;
windowRect.top = 0;
windowRect.right = initWindowSettings->.;
windowRect.bottom = initWindowSettings->.;
wapi->user.AdjustWindowRect(&windowRect, style, false);
windowWidth = windowRect.right - windowRect.left;
windowHeight = windowRect.bottom - windowRect.top;
} else {
// @NOTE(final): Operating system decide how big the window should be.
windowWidth = CW_USEDEFAULT;
windowHeight = CW_USEDEFAULT;
}
// Create window
windowState->windowHandle = wapi->user.CreateWindowExW(exStyle, windowClass.lpszClassName, windowTitle, style, windowX, windowY, windowWidth, windowHeight, , , windowClass.hInstance, );
if (windowState->windowHandle == ) {
FPL__ERROR(FPL__MODULE_WINDOW, "Failed creating window for class '%s' and position (%d x %d) with size (%d x %d)", windowState->windowClass, windowX, windowY, windowWidth, windowHeight);
return false;
}
// Accept files as drag & drop source
wapi->shell.DragAcceptFiles(windowState->windowHandle, TRUE);
// Get actual window size and store results
currentWindowSettings->. = windowWidth;
currentWindowSettings->. = windowHeight;
RECT clientRect;
if (wapi->user.GetClientRect(windowState->windowHandle, &clientRect)) {
currentWindowSettings->. = clientRect.right - clientRect.left;
currentWindowSettings->. = clientRect.bottom - clientRect.top;
}
// Get device context so we can swap the back and front buffer
windowState->deviceContext = wapi->user.GetDC(windowState->windowHandle);
if (windowState->deviceContext == ) {
FPL__ERROR(FPL__MODULE_WINDOW, "Failed aquiring device context from window '%d'", windowState->windowHandle);
return false;
}
// Call post window setup callback
if (setupCallbacks->postSetup != ) {
setupCallbacks->postSetup(platAppState, platAppState->initFlags, initSettings);
}
// Enter fullscreen if needed
if (initWindowSettings->) {
(true, initWindowSettings->., initWindowSettings->., initWindowSettings->);
}
// Show window
wapi->user.ShowWindow(windowState->windowHandle, SW_SHOW);
wapi->user.SetForegroundWindow(windowState->windowHandle);
wapi->user.SetFocus(windowState->windowHandle);
// Cursor is visible at start
windowState->defaultCursor = windowClass.hCursor;
windowState->isCursorActive = true;
platAppState->window.isRunning = true;
return true;
}
void fpl__Win32ReleaseWindow(const fpl__Win32InitState *initState, const fpl__Win32AppState *appState, fpl__Win32WindowState *windowState) {
const fpl__Win32Api *wapi = &appState->winApi;
if (windowState->deviceContext != ) {
wapi->user.ReleaseDC(windowState->windowHandle, windowState->deviceContext);
windowState->deviceContext = ;
}
if (windowState->windowHandle != ) {
wapi->user.DestroyWindow(windowState->windowHandle);
windowState->windowHandle = ;
wapi->user.UnregisterClassW(windowState->windowClass, initState->appInstance);
}
if (windowState->backgroundBrush != ) {
wapi->gdi.DeleteObject(windowState->backgroundBrush);
windowState->backgroundBrush = ;
}
if (windowState->messageFiber != ) {
DeleteFiber(windowState->messageFiber);
windowState->messageFiber = ;
}
if (windowState->mainFiber != ) {
ConvertFiberToThread();
windowState->mainFiber = ;
}
}
#endif // FPL__ENABLE_WINDOW
// ############################################################################
//
// > WIN32_XINPUT
//
// Always included, when window support is enabled
//
// ############################################################################
#if defined(FPL__ENABLE_INPUT_XINPUT) && !defined(FPL__WIN32_XINPUT_IMPLEMENTED)
#define FPL__WIN32_XINPUT_IMPLEMENTED
FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetState(fpl__InputWin32XInputGetStateStub) {
return(ERROR_DEVICE_NOT_CONNECTED);
}
FPL__FUNC_INPUT_WIN32_XINPUT_XInputGetCapabilities(fpl__InputWin32XInputGetCapabilitiesStub) {
return(ERROR_DEVICE_NOT_CONNECTED);
}
void fpl__Win32UnloadXInputApi(fpl__InputWin32XInputApi *xinputApi) {
(xinputApi != );
if (xinputApi->xinputLibrary) {
FPL_LOG_DEBUG(FPL__MODULE_XINPUT, "Unload XInput Library");
FreeLibrary(xinputApi->xinputLibrary);
xinputApi->xinputLibrary = ;
xinputApi->XInputGetState = fpl__InputWin32XInputGetStateStub;
xinputApi->XInputGetCapabilities = fpl__InputWin32XInputGetCapabilitiesStub;
}
}
void fpl__Win32LoadXInputApi(fpl__InputWin32XInputApi *xinputApi) {
(xinputApi != );
const char *xinputFileNames[] = {
"xinput1_4.dll",
"xinput1_3.dll",
"xinput9_1_0.dll",
};
bool result = false;
for (uint32_t index = 0; index < (xinputFileNames); ++index) {
const char *libName = xinputFileNames[index];
(xinputApi);
do {
HMODULE libHandle = ;
FPL__WIN32_LOAD_LIBRARY_BREAK(FPL__MODULE_XINPUT, libHandle, libName);
xinputApi->xinputLibrary = libHandle;
FPL__WIN32_GET_FUNCTION_ADDRESS_BREAK(FPL__MODULE_XINPUT, libHandle, libName, xinputApi, fpl__func_input_win32_xinput_XInputGetState, XInputGetState);
FPL__WIN32_GET_FUNCTION_ADDRESS_BREAK(FPL__MODULE_XINPUT, libHandle, libName, xinputApi, fpl__func_input_win32_xinput_XInputGetCapabilities, XInputGetCapabilities);
result = true;
} while (0);
if (result) {
break;
}
fpl__Win32UnloadXInputApi(xinputApi);
}
if (!result) {
xinputApi->XInputGetState = fpl__InputWin32XInputGetStateStub;
xinputApi->XInputGetCapabilities = fpl__InputWin32XInputGetCapabilitiesStub;
}
}
float fpl__InputWin32XInput_ProcessStickValue(const SHORT value, const SHORT deadZoneThreshold) {
float result = 0;
if (value < -deadZoneThreshold) {
result = (float)((value + deadZoneThreshold) / (32768.0f - deadZoneThreshold));
} else if (value > deadZoneThreshold) {
result = (float)((value - deadZoneThreshold) / (32767.0f - deadZoneThreshold));
}
return(result);
}
void fpl__InputWin32XInput_GamepadToGamepadState(const XINPUT_GAMEPAD *newState, *outState) {
// If we got here, the controller is definitily by connected
outState-> = true;
// Analog sticks
outState-> = fpl__InputWin32XInput_ProcessStickValue(newState->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
outState-> = fpl__InputWin32XInput_ProcessStickValue(newState->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
outState-> = fpl__InputWin32XInput_ProcessStickValue(newState->sThumbRX, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
outState-> = fpl__InputWin32XInput_ProcessStickValue(newState->sThumbRY, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE);
// Triggers
outState-> = (float)newState->bLeftTrigger / 255.0f;
outState-> = (float)newState->bRightTrigger / 255.0f;
// Digital pad buttons
if ((newState->wButtons, XINPUT_GAMEPAD_DPAD_UP))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_DPAD_DOWN))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_DPAD_LEFT))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_DPAD_RIGHT))
outState->. = true;
// Action buttons
if ((newState->wButtons, XINPUT_GAMEPAD_A))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_B))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_X))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_Y))
outState->. = true;
// Center buttons
if ((newState->wButtons, XINPUT_GAMEPAD_START))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_BACK))
outState->. = true;
// Shoulder buttons
if ((newState->wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER))
outState->. = true;
// Thumb buttons
if ((newState->wButtons, XINPUT_GAMEPAD_LEFT_THUMB))
outState->. = true;
if ((newState->wButtons, XINPUT_GAMEPAD_RIGHT_THUMB))
outState->. = true;
// The controller is only active, when any button or any movement happened
outState-> = !fpl__IsZeroMemory(newState, sizeof(*newState));
}
static size_t fpl__InputWin32XInput_UpdateControllers(const *gamepadSettings, fpl__InputBackendXInput *backend) {
(gamepadSettings);
(backend);
if (backend->lastDeviceSearchTime == 0) {
backend->lastDeviceSearchTime = ();
}
const uint64_t detectionFrequency = gamepadSettings->;
currentTime = ();
uint64_t deltaTime = (currentTime - backend->lastDeviceSearchTime);
if (detectionFrequency > 0 && deltaTime > 0 && deltaTime < detectionFrequency) {
return false;
}
backend->lastDeviceSearchTime = currentTime;
size_t count = 0;
for (DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; ++controllerIndex) {
XINPUT_STATE controllerState = ;
if (backend->api.XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
if (!backend->isConnected[controllerIndex]) {
backend->isConnected[controllerIndex] = true;
(backend->deviceNames[controllerIndex], (backend->deviceNames[controllerIndex]), "XInput-Device [%d]", controllerIndex);
fpl__PushGamepadConnectionEvent(controllerIndex, backend->deviceNames[controllerIndex], true);
++count;
}
} else {
if (backend->isConnected[controllerIndex]) {
backend->isConnected[controllerIndex] = false;
fpl__PushGamepadConnectionEvent(controllerIndex, backend->deviceNames[controllerIndex], false);
++count;
}
}
}
return count;
}
static size_t fpl__InputWin32XInput_CreateEventsForStates(const *gamepadSettings, fpl__InputBackendXInput *backend) {
(gamepadSettings);
(backend);
if (backend->lastUpdateStatesTime == 0) {
backend->lastUpdateStatesTime = ();
}
const uint64_t updateFrequency = gamepadSettings->;
currentTime = ();
uint64_t deltaTime = (currentTime - backend->lastDeviceSearchTime);
if (updateFrequency > 0 && deltaTime > 0 && deltaTime < updateFrequency) {
return false;
}
backend->lastUpdateStatesTime = currentTime;
size_t result = 0;
tempState = ;
for (DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; ++controllerIndex) {
if (backend->isConnected[controllerIndex]) {
XINPUT_STATE controllerState = ;
if (backend->api.XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
(&tempState);
const XINPUT_GAMEPAD *newPadState = &controllerState.Gamepad;
fpl__InputWin32XInput_GamepadToGamepadState(newPadState, &tempState);
tempState. = backend->deviceNames[controllerIndex];
fpl__PushGamepadStateEvent(controllerIndex, backend->deviceNames[controllerIndex], &tempState);
result++;
}
}
}
return result;
}
// Merge contract: caller (fplPollGamepadStates) clears outStates once.
// Each backend writes only into slots that hold a connected device it owns,
// and skips slots already claimed (isConnected=true) by an earlier backend.
static size_t fpl__InputWin32XInput_Poll(fpl__InputBackendXInput *backend, *outStates) {
(backend);
(outStates);
backend->lastDeviceSearchTime = backend->lastUpdateStatesTime = ();
size_t result = 0;
for (DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; ++controllerIndex) {
if (controllerIndex < (outStates->) && outStates->[controllerIndex].) continue;
XINPUT_STATE controllerState = ;
if (backend->api.XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
if (!backend->isConnected[controllerIndex]) {
backend->isConnected[controllerIndex] = true;
(backend->deviceNames[controllerIndex], (backend->deviceNames[controllerIndex]), "XInput-Device [%d]", controllerIndex);
}
const XINPUT_GAMEPAD *newPadState = &controllerState.Gamepad;
*targetPadState = &outStates->[controllerIndex];
fpl__InputWin32XInput_GamepadToGamepadState(newPadState, targetPadState);
targetPadState-> = backend->deviceNames[controllerIndex];
targetPadState-> = true;
result++;
} else {
if (backend->isConnected[controllerIndex]) {
backend->isConnected[controllerIndex] = false;
result++;
}
}
}
return(result);
}
// Backend lifecycle wrappers used by fpl__InputSystem_*.
bool fpl__InputBackendXInput_Init(fpl__InputBackendXInput *backend) {
(backend);
if (backend->isInitialized) return true;
fpl__Win32LoadXInputApi(&backend->api);
backend->isInitialized = true;
return true;
}
void fpl__InputBackendXInput_Release(fpl__InputBackendXInput *backend) {
(backend);
if (!backend->isInitialized) return;
fpl__Win32UnloadXInputApi(&backend->api);
(backend);
}
void fpl__InputBackendXInput_Update(fpl__InputBackendXInput *backend, const *gamepadSettings) {
(backend);
(gamepadSettings);
if (!backend->isInitialized) return;
fpl__InputWin32XInput_UpdateControllers(gamepadSettings, backend);
fpl__InputWin32XInput_CreateEventsForStates(gamepadSettings, backend);
}
bool fpl__InputBackendXInput_PollGamepad(fpl__InputBackendXInput *backend, *outStates) {
(backend);
(outStates);
if (!backend->isInitialized) return false;
size_t result = fpl__InputWin32XInput_Poll(backend, outStates);
return(result > 0);
}
#endif // FPL__WIN32_XINPUT_IMPLEMENTED
// ############################################################################
//
// > WIN32_DINPUT (DirectInput8 gamepad backend)
//
// ############################################################################
#if defined(FPL__ENABLE_INPUT_DINPUT) && !defined(FPL__WIN32_DINPUT_IMPLEMENTED)
#define FPL__WIN32_DINPUT_IMPLEMENTED
#define FPL__MODULE_DINPUT "DInput"
// Some Windows SDKs (and older mingw) miss this — pulled from current dinput.h.
#if !defined(DIDFT_OPTIONAL)
# define DIDFT_OPTIONAL 0x80000000
#endif
// COM/DirectInput GUIDs. Defined inline so we never need to link against dxguid.lib.
static const GUID fpl__IID_IDirectInput8W = { 0xBF798031, 0x483A, 0x4DA2, { 0xAA, 0x99, 0x5D, 0x64, 0xED, 0x36, 0x97, 0x00 } };
static const GUID fpl__GUID_XAxis = { 0xA36D02E0, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_YAxis = { 0xA36D02E1, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_ZAxis = { 0xA36D02E2, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_RxAxis = { 0xA36D02F4, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_RyAxis = { 0xA36D02F5, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_RzAxis = { 0xA36D02E3, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_Slider = { 0xA36D02E4, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
static const GUID fpl__GUID_POV = { 0xA36D02F2, 0xC9F3, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 } };
// REFGUID/REFIID is `const GUID&` in C++ but `const GUID*` in C — pass dereferenced
// in C++, raw pointer in C. ABI is identical.
#if defined(__cplusplus)
# define fpl__DI_RefGuid(g) (*(g))
#else
# define fpl__DI_RefGuid(g) (g)
#endif
// Cross-language COM dispatch helpers. dinput.h exposes IDirectInput8_* / IDirectInputDevice8_*
// macros only in C; in C++ the methods are called directly on the interface.
#if defined(__cplusplus)
# define fpl__DI8_Release(p) ((p)->Release())
# define fpl__DI8_CreateDevice(p,a,b,c) ((p)->CreateDevice(a,b,c))
# define fpl__DI8_EnumDevices(p,a,b,c,d) ((p)->EnumDevices(a,b,c,d))
# define fpl__DID8_Release(p) ((p)->Release())
# define fpl__DID8_GetCapabilities(p,a) ((p)->GetCapabilities(a))
# define fpl__DID8_SetDataFormat(p,a) ((p)->SetDataFormat(a))
# define fpl__DID8_SetCooperativeLevel(p,a,b) ((p)->SetCooperativeLevel(a,b))
# define fpl__DID8_SetProperty(p,a,b) ((p)->SetProperty(a,b))
# define fpl__DID8_Acquire(p) ((p)->Acquire())
# define fpl__DID8_Unacquire(p) ((p)->Unacquire())
# define fpl__DID8_GetDeviceState(p,a,b) ((p)->GetDeviceState(a,b))
# define fpl__DID8_Poll(p) ((p)->Poll())
#else
# define fpl__DI8_Release(p) ((p)->lpVtbl->Release(p))
# define fpl__DI8_CreateDevice(p,a,b,c) ((p)->lpVtbl->CreateDevice(p,a,b,c))
# define fpl__DI8_EnumDevices(p,a,b,c,d) ((p)->lpVtbl->EnumDevices(p,a,b,c,d))
# define fpl__DID8_Release(p) ((p)->lpVtbl->Release(p))
# define fpl__DID8_GetCapabilities(p,a) ((p)->lpVtbl->GetCapabilities(p,a))
# define fpl__DID8_SetDataFormat(p,a) ((p)->lpVtbl->SetDataFormat(p,a))
# define fpl__DID8_SetCooperativeLevel(p,a,b) ((p)->lpVtbl->SetCooperativeLevel(p,a,b))
# define fpl__DID8_SetProperty(p,a,b) ((p)->lpVtbl->SetProperty(p,a,b))
# define fpl__DID8_Acquire(p) ((p)->lpVtbl->Acquire(p))
# define fpl__DID8_Unacquire(p) ((p)->lpVtbl->Unacquire(p))
# define fpl__DID8_GetDeviceState(p,a,b) ((p)->lpVtbl->GetDeviceState(p,a,b))
# define fpl__DID8_Poll(p) ((p)->lpVtbl->Poll(p))
#endif
// Data format mirroring c_dfDIJoystick: 6 axes + 2 sliders + 4 POVs + 32 buttons.
// Bound to the canonical DIJOYSTATE layout via DIJOFS_* offsets. Optional flag
// lets DirectInput silently skip objects the device does not expose.
static DIOBJECTDATAFORMAT fpl__DIJoy_Objects[] = {
{ &fpl__GUID_XAxis, DIJOFS_X, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_YAxis, DIJOFS_Y, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_ZAxis, DIJOFS_Z, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_RxAxis, DIJOFS_RX, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_RyAxis, DIJOFS_RY, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_RzAxis, DIJOFS_RZ, DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_Slider, DIJOFS_SLIDER(0), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_Slider, DIJOFS_SLIDER(1), DIDFT_AXIS | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, DIDOI_ASPECTPOSITION },
{ &fpl__GUID_POV, DIJOFS_POV(0), DIDFT_POV | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ &fpl__GUID_POV, DIJOFS_POV(1), DIDFT_POV | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ &fpl__GUID_POV, DIJOFS_POV(2), DIDFT_POV | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ &fpl__GUID_POV, DIJOFS_POV(3), DIDFT_POV | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 0), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 1), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 2), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 3), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 4), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 5), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 6), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 7), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 8), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON( 9), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(10), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(11), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(12), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(13), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(14), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(15), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(16), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(17), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(18), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(19), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(20), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(21), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(22), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(23), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(24), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(25), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(26), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(27), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(28), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(29), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(30), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
{ , DIJOFS_BUTTON(31), DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 },
};
static const DIDATAFORMAT fpl__DIJoy_DataFormat = {
sizeof(DIDATAFORMAT),
sizeof(DIOBJECTDATAFORMAT),
DIDF_ABSAXIS,
sizeof(DIJOYSTATE),
(DWORD)(sizeof(fpl__DIJoy_Objects) / sizeof(fpl__DIJoy_Objects[0])),
fpl__DIJoy_Objects,
};
void fpl__Win32UnloadDInputApi(fpl__Win32DInputApi *api) {
(api != );
if (api->dinputLibrary) {
FPL_LOG_DEBUG(FPL__MODULE_DINPUT, "Unload DirectInput Library");
FreeLibrary(api->dinputLibrary);
api->dinputLibrary = ;
}
api->DirectInput8Create = ;
}
bool fpl__Win32LoadDInputApi(fpl__Win32DInputApi *api) {
(api != );
const char *libName = "dinput8.dll";
bool result = false;
(api);
do {
HMODULE libHandle = ;
FPL__WIN32_LOAD_LIBRARY_BREAK(FPL__MODULE_DINPUT, libHandle, libName);
api->dinputLibrary = libHandle;
FPL__WIN32_GET_FUNCTION_ADDRESS_BREAK(FPL__MODULE_DINPUT, libHandle, libName, api, fpl__func_input_win32_dinput_DirectInput8Create, DirectInput8Create);
result = true;
} while (0);
if (!result) {
fpl__Win32UnloadDInputApi(api);
}
return result;
}
// Walks all RawInput devices, collects VID/PID for any HID whose device name
// contains "IG_" — these are the XInput-compatible gamepads we want DInput to skip.
void fpl__Win32DInput_CollectXInputVidPids(fpl__InputBackendDInput *backend) {
backend->xinputVidPidCount = 0;
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return;
const fpl__Win32UserApi *uapi = &appState->win32.winApi.user;
if (uapi->GetRawInputDeviceList == || uapi->GetRawInputDeviceInfoW == ) return;
UINT deviceCount = 0;
if (uapi->GetRawInputDeviceList(, &deviceCount, sizeof(RAWINPUTDEVICELIST)) != 0) return;
if (deviceCount == 0) return;
if (deviceCount > 256) deviceCount = 256;
RAWINPUTDEVICELIST list[256];
UINT got = uapi->GetRawInputDeviceList(list, &deviceCount, sizeof(RAWINPUTDEVICELIST));
if (got == (UINT)-1) return;
WCHAR namebuf[512];
for (UINT i = 0; i < got; ++i) {
if (list[i].dwType != RIM_TYPEHID) continue;
UINT nameSize = (UINT)(namebuf);
if (uapi->GetRawInputDeviceInfoW(list[i].hDevice, RIDI_DEVICENAME, namebuf, &nameSize) == (UINT)-1) continue;
// Match "IG_" anywhere in the device path.
bool isXInput = false;
for (UINT k = 0; k + 2 < nameSize; ++k) {
if (namebuf[k] == L'I' && namebuf[k + 1] == L'G' && namebuf[k + 2] == L'_') { isXInput = true; break; }
}
if (!isXInput) continue;
// Extract VID and PID. Format: "\\?\HID#VID_xxxx&PID_yyyy&..."
uint16_t vid = 0, pid = 0;
for (UINT k = 0; k + 7 < nameSize; ++k) {
if (namebuf[k] == L'V' && namebuf[k + 1] == L'I' && namebuf[k + 2] == L'D' && namebuf[k + 3] == L'_') {
for (int d = 0; d < 4; ++d) {
WCHAR c = namebuf[k + 4 + d];
int v = 0;
if (c >= L'0' && c <= L'9') v = c - L'0';
else if (c >= L'A' && c <= L'F') v = c - L'A' + 10;
else if (c >= L'a' && c <= L'f') v = c - L'a' + 10;
else { vid = 0; break; }
vid = (uint16_t)((vid << 4) | v);
}
}
if (namebuf[k] == L'P' && namebuf[k + 1] == L'I' && namebuf[k + 2] == L'D' && namebuf[k + 3] == L'_') {
for (int d = 0; d < 4; ++d) {
WCHAR c = namebuf[k + 4 + d];
int v = 0;
if (c >= L'0' && c <= L'9') v = c - L'0';
else if (c >= L'A' && c <= L'F') v = c - L'A' + 10;
else if (c >= L'a' && c <= L'f') v = c - L'a' + 10;
else { pid = 0; break; }
pid = (uint16_t)((pid << 4) | v);
}
}
}
if (vid == 0 || pid == 0) continue;
uint32_t entry = ((uint32_t)vid << 16) | (uint32_t)pid;
if (backend->xinputVidPidCount >= (backend->xinputVidPids)) break;
// Dedup
bool dup = false;
for (uint32_t k = 0; k < backend->xinputVidPidCount; ++k) {
if (backend->xinputVidPids[k] == entry) { dup = true; break; }
}
if (!dup) backend->xinputVidPids[backend->xinputVidPidCount++] = entry;
}
}
bool fpl__Win32DInput_IsXInputProduct(const fpl__InputBackendDInput *backend, uint16_t vid, uint16_t pid) {
uint32_t entry = ((uint32_t)vid << 16) | (uint32_t)pid;
for (uint32_t k = 0; k < backend->xinputVidPidCount; ++k) {
if (backend->xinputVidPids[k] == entry) return true;
}
return false;
}
int fpl__Win32DInput_FindFreeSlot(fpl__InputBackendDInput *backend) {
for (uint32_t i = 0; i < (backend->slots); ++i) {
if (!backend->slots[i].isConnected) return (int)i;
}
return -1;
}
int fpl__Win32DInput_FindSlotByGuid(fpl__InputBackendDInput *backend, const GUID *guidInstance) {
for (uint32_t i = 0; i < (backend->slots); ++i) {
if (!backend->slots[i].isConnected) continue;
const GUID *g = &backend->slots[i].guidInstance;
if (g->Data1 == guidInstance->Data1 && g->Data2 == guidInstance->Data2 && g->Data3 == guidInstance->Data3) {
bool eq = true;
for (int k = 0; k < 8; ++k) if (g->Data4[k] != guidInstance->Data4[k]) { eq = false; break; }
if (eq) return (int)i;
}
}
return -1;
}
void fpl__Win32DInput_ReleaseSlot(fpl__InputBackendDInput *backend, uint32_t slotIndex) {
fpl__InputBackendDInputSlot *slot = &backend->slots[slotIndex];
if (slot->device != ) {
if (slot->isAcquired) {
fpl__DID8_Unacquire(slot->device);
slot->isAcquired = false;
}
fpl__DID8_Release(slot->device);
slot->device = ;
}
bool wasConnected = slot->isConnected;
(slot);
if (wasConnected) {
fpl__PushGamepadConnectionEvent(slotIndex, , false);
}
}
// Translates a raw DIJOYSTATE into a backend-agnostic fplGamepadData for fplGamepadMappingApply / fplGamepadMappingApplyDefault. Sticks and sliders are normalized to SDL convention (-1..+1, sliders idle at -1).
void fpl__Win32DInput_FillRawInput(const DIJOYSTATE *src, *out) {
zero = ;
*out = zero;
// Sticks: raw [0, 65535] with center 32767 → [-1, +1].
const float center = 32767.5f;
const float invHalf = 1.0f / 32767.5f;
float a[8];
a[0] = ((float)src->lX - center) * invHalf;
a[1] = ((float)src->lY - center) * invHalf;
a[2] = ((float)src->lZ - center) * invHalf;
a[3] = ((float)src->lRx - center) * invHalf;
a[4] = ((float)src->lRy - center) * invHalf;
a[5] = ((float)src->lRz - center) * invHalf;
// Sliders idle at 0, full at 65535 → SDL trigger convention -1..+1.
a[6] = ((float)src->rglSlider[0] * (2.0f / 65535.0f)) - 1.0f;
a[7] = ((float)src->rglSlider[1] * (2.0f / 65535.0f)) - 1.0f;
for (int i = 0; i < 8; ++i) {
if (a[i] < -1.0f) {
a[i] = -1.0f;
} else if (a[i] > 1.0f) {
a[i] = 1.0f;
}
out->[i] = a[i];
}
out-> = 8;
for (int b = 0; b < 32; ++b) {
out->[b] = (src->rgbButtons[b] & 0x80) != 0;
}
out-> = 32;
// POV[0] → hat[0]. Centered values (0xFFFFFFFF / 0xFFFF / -1) leave mask 0.
uint8_t mask = 0;
DWORD pov = src->rgdwPOV[0];
if (pov != 0xFFFFFFFFu && (pov & 0xFFFFu) != 0xFFFFu) {
if (pov >= 31500u || pov < 4500u) {
mask |= 0x1;
}
if (pov >= 4500u && pov < 13500u) {
mask |= 0x2;
}
if (pov >= 13500u && pov < 22500u) {
mask |= 0x4;
}
if (pov >= 22500u && pov < 31500u) {
mask |= 0x8;
}
}
out->[0] = mask;
out-> = 1;
}
typedef struct fpl__Win32DInput_EnumCtx {
fpl__InputBackendDInput *backend;
const fplGamepadSettings *gamepadSettings;
uint32_t added;
} fpl__Win32DInput_EnumCtx;
static BOOL WINAPI fpl__Win32DInput_EnumDevicesCallback(LPCDIDEVICEINSTANCEW ddi, LPVOID pvRef) {
fpl__Win32DInput_EnumCtx *ec = (fpl__Win32DInput_EnumCtx *)pvRef;
fpl__InputBackendDInput *backend = ec->backend;
if (backend->iface == ) return DIENUM_STOP;
// VID/PID encoded in guidProduct.Data1 = MAKELONG(VID, PID) on Windows.
uint16_t vid = (uint16_t)(ddi->guidProduct.Data1 & 0xFFFFu);
uint16_t pid = (uint16_t)((ddi->guidProduct.Data1 >> 16) & 0xFFFFu);
if (fpl__Win32DInput_IsXInputProduct(backend, vid, pid)) return DIENUM_CONTINUE;
// Skip devices already opened on a slot (re-enum each detection cycle).
if (fpl__Win32DInput_FindSlotByGuid(backend, &ddi->guidInstance) >= 0) return DIENUM_CONTINUE;
int slotIndex = fpl__Win32DInput_FindFreeSlot(backend);
if (slotIndex < 0) return DIENUM_STOP;
IDirectInputDevice8W *device = ;
if (FAILED(fpl__DI8_CreateDevice(backend->iface, fpl__DI_RefGuid(&ddi->guidInstance), &device, )) || device == ) {
return DIENUM_CONTINUE;
}
if (FAILED(fpl__DID8_SetDataFormat(device, &fpl__DIJoy_DataFormat))) {
fpl__DID8_Release(device);
return DIENUM_CONTINUE;
}
// Background + nonexclusive cooperative level — works without a visible window.
if (FAILED(fpl__DID8_SetCooperativeLevel(device, , DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) {
fpl__DID8_Release(device);
return DIENUM_CONTINUE;
}
// Reasonable analog deadzone (10% of full range). Ignored when SetProperty fails.
DIPROPDWORD dz = ;
dz.diph.dwSize = sizeof(dz);
dz.diph.dwHeaderSize = sizeof(dz.diph);
dz.diph.dwObj = 0;
dz.diph.dwHow = DIPH_DEVICE;
dz.dwData = 1000;
fpl__DID8_SetProperty(device, DIPROP_DEADZONE, &dz.diph);
fpl__InputBackendDInputSlot *slot = &backend->slots[slotIndex];
(slot);
slot->device = device;
slot->guidInstance = ddi->guidInstance;
slot->vendorID = vid;
slot->productID = pid;
slot->isConnected = true;
slot->isAcquired = false;
// UTF-8 decode of the wide product name.
int wlen = lstrlenW(ddi->tszProductName);
size_t written = 0;
if (wlen > 0) {
written = (ddi->tszProductName, (size_t)wlen, slot->deviceName, (slot->deviceName));
}
if (written == 0) {
(slot->deviceName, (slot->deviceName), "DInput-Device [%d]", slotIndex);
}
fpl__DID8_Acquire(device);
slot->isAcquired = true;
// Resolve a per-device mapping. The resolver runs once per connect; failure or absence falls back to fplGamepadMappingApplyDefault.
slot->hasMapping = false;
if (ec->gamepadSettings != && ec->gamepadSettings->mappingResolver != ) {
info = ;
info. = (uint32_t)slotIndex;
info. = ;
info. = slot->deviceName;
// Bus 0x03 = USB. CRC and version aren't exposed by DInput, so they stay 0.
fpl__GamepadBuildSDLGuid(0x0003u, vid, pid, 0u, 0u, info.);
info. = vid;
info. = pid;
info. = 0;
info. = 32;
info. = 8;
info. = 1;
userMapping = ;
if (ec->gamepadSettings->mappingResolver(&info, &userMapping, ec->gamepadSettings->mappingResolverUserData)) {
slot->mapping = userMapping;
slot->hasMapping = true;
}
}
fpl__PushGamepadConnectionEvent((uint32_t)slotIndex, slot->deviceName, true);
ec->added++;
return DIENUM_CONTINUE;
}
void fpl__Win32DInput_DetectControllers(fpl__InputBackendDInput *backend, const *gamepadSettings) {
if (backend->iface == ) return;
if (backend->lastDeviceSearchTime == 0) backend->lastDeviceSearchTime = ();
const uint64_t freq = gamepadSettings->;
now = ();
uint64_t delta = (uint64_t)(now - backend->lastDeviceSearchTime);
if (freq > 0 && delta > 0 && delta < freq) return;
backend->lastDeviceSearchTime = now;
// Refresh XInput VID/PID list cheaply each scan — devices come and go.
fpl__Win32DInput_CollectXInputVidPids(backend);
fpl__Win32DInput_EnumCtx ec = ;
ec.backend = backend;
ec.gamepadSettings = gamepadSettings;
fpl__DI8_EnumDevices(backend->iface, DI8DEVCLASS_GAMECTRL, fpl__Win32DInput_EnumDevicesCallback, &ec, DIEDFL_ATTACHEDONLY);
}
void fpl__Win32DInput_UpdateStates(fpl__InputBackendDInput *backend) {
for (uint32_t i = 0; i < (backend->slots); ++i) {
fpl__InputBackendDInputSlot *slot = &backend->slots[i];
if (!slot->isConnected || slot->device == ) {
continue;
}
if (!slot->isAcquired) {
HRESULT hrA = fpl__DID8_Acquire(slot->device);
if (FAILED(hrA)) {
continue;
}
slot->isAcquired = true;
}
fpl__DID8_Poll(slot->device);
DIJOYSTATE raw = ;
HRESULT hr = fpl__DID8_GetDeviceState(slot->device, sizeof(raw), &raw);
if (FAILED(hr)) {
// Most likely DIERR_INPUTLOST / DIERR_NOTACQUIRED — try to re-acquire next tick.
fpl__DID8_Unacquire(slot->device);
slot->isAcquired = false;
continue;
}
fpl__Win32DInput_FillRawInput(&raw, &slot->raw);
gs = ;
if (slot->hasMapping) {
(&slot->mapping, &slot->raw, &gs);
} else {
(&slot->raw, &gs);
}
gs. = true;
gs. = slot->deviceName;
fpl__GamepadFinalizeState(&gs);
slot->lastState = gs;
fpl__PushGamepadStateEvent(i, slot->deviceName, &gs);
}
}
bool fpl__InputBackendDInput_Init(fpl__InputBackendDInput *backend) {
(backend);
if (backend->isInitialized) return true;
if (!fpl__Win32LoadDInputApi(&backend->api)) return false;
HINSTANCE hinst = GetModuleHandleW();
HRESULT hr = backend->api.DirectInput8Create(hinst, DIRECTINPUT_VERSION, fpl__DI_RefGuid(&fpl__IID_IDirectInput8W), (LPVOID *)&backend->iface, );
if (FAILED(hr) || backend->iface == ) {
FPL__WARNING(FPL__MODULE_DINPUT, "DirectInput8Create failed (hr=0x%08lX)", (unsigned long)hr);
fpl__Win32UnloadDInputApi(&backend->api);
return false;
}
backend->isInitialized = true;
return true;
}
void fpl__InputBackendDInput_Release(fpl__InputBackendDInput *backend) {
(backend);
if (!backend->isInitialized) return;
for (uint32_t i = 0; i < (backend->slots); ++i) {
if (backend->slots[i].isConnected) {
fpl__Win32DInput_ReleaseSlot(backend, i);
}
}
if (backend->iface != ) {
fpl__DI8_Release(backend->iface);
backend->iface = ;
}
fpl__Win32UnloadDInputApi(&backend->api);
(backend);
}
void fpl__InputBackendDInput_Update(fpl__InputBackendDInput *backend, const *gamepadSettings) {
(backend);
(gamepadSettings);
if (!backend->isInitialized) return;
fpl__Win32DInput_DetectControllers(backend, gamepadSettings);
fpl__Win32DInput_UpdateStates(backend);
}
// Merge contract: caller already cleared outStates. We refresh state by polling each slot,
// then write into our slot index — but only when an earlier backend hasn't already claimed it.
bool fpl__InputBackendDInput_PollGamepad(fpl__InputBackendDInput *backend, *outStates) {
(backend);
(outStates);
if (!backend->isInitialized) return false;
fpl__Win32DInput_UpdateStates(backend);
bool any = false;
for (uint32_t i = 0; i < (backend->slots); ++i) {
if (i >= (outStates->)) break;
if (outStates->[i].) continue;
fpl__InputBackendDInputSlot *slot = &backend->slots[i];
if (!slot->isConnected) continue;
outStates->[i] = slot->lastState;
outStates->[i]. = slot->deviceName;
outStates->[i]. = true;
any = true;
}
return any;
}
#endif // FPL__WIN32_DINPUT_IMPLEMENTED
// ############################################################################
//
// > WIN32_INPUT_KBM (keyboard + mouse backend)
//
// ############################################################################
#if defined(FPL__ENABLE_INPUT_WIN32) && !defined(FPL__WIN32_INPUT_KBM_IMPLEMENTED)
#define FPL__WIN32_INPUT_KBM_IMPLEMENTED
bool fpl__InputBackendWin32_Init(fpl__InputBackendWin32 *backend, const *settings) {
(backend);
if (backend->isInitialized) return true;
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return false;
const fpl__Win32Api *wapi = &appState->win32.winApi;
bool detached = false;
# if defined(FPL__ENABLE_WINDOW)
if (settings != && settings->) {
detached = true;
}
if ((appState->initFlags & ) == 0) {
detached = true;
}
# else
(void)settings;
detached = true;
# endif
if (detached) {
WNDCLASSEXW wc = ;
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = wapi->user.DefWindowProcW;
wc.hInstance = GetModuleHandleW();
wc.lpszClassName = L"FPLInputMessageWindow";
ATOM cls = wapi->user.RegisterClassExW(&wc);
if (cls == 0) {
FPL__ERROR(FPL__MODULE_WIN32, "Failed to register hidden input message-window class");
return false;
}
HWND hwnd = wapi->user.CreateWindowExW(0, (LPCWSTR)wc.lpszClassName, L"", 0, 0, 0, 0, 0, HWND_MESSAGE, , wc.hInstance, );
if (hwnd == ) {
wapi->user.UnregisterClassW((LPCWSTR)wc.lpszClassName, wc.hInstance);
FPL__ERROR(FPL__MODULE_WIN32, "Failed to create hidden input message-window");
return false;
}
backend->messageWindow = hwnd;
backend->messageWindowClass = cls;
}
backend->detached = detached;
backend->isInitialized = true;
return true;
}
void fpl__InputBackendWin32_Release(fpl__InputBackendWin32 *backend) {
(backend);
if (!backend->isInitialized) return;
fpl__PlatformAppState *appState = fpl__global__AppState;
if (backend->messageWindow != && appState != ) {
const fpl__Win32Api *wapi = &appState->win32.winApi;
wapi->user.DestroyWindow(backend->messageWindow);
wapi->user.UnregisterClassW(L"FPLInputMessageWindow", GetModuleHandleW());
}
(backend);
}
bool fpl__InputBackendWin32_PollKeyboard(fpl__InputBackendWin32 *backend, *outState) {
(backend);
(outState);
if (!backend->isInitialized) return false;
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32Api *wapi = &appState->winApi;
(outState);
outState-> = fpl__Win32GetKeyboardModifiers(wapi);
for (uint32_t keyCode = 0; keyCode < 256; ++keyCode) {
int k = wapi->user.MapVirtualKeyW(MAPVK_VSC_TO_VK, keyCode);
if (k == 0) {
k = (int)keyCode;
}
bool down = fpl__Win32IsKeyDown(wapi, k);
outState->[keyCode] = down;
# if defined(FPL__ENABLE_WINDOW)
if (!backend->detached) {
key = fpl__GetMappedKey(&fpl__global__AppState->window, keyCode);
outState->[(int)key] = down ? : ;
}
# endif
}
return true;
}
bool fpl__InputBackendWin32_PollMouse(fpl__InputBackendWin32 *backend, *outState) {
(backend);
(outState);
if (!backend->isInitialized) return false;
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32Api *wapi = &appState->winApi;
POINT p;
if (wapi->user.GetCursorPos(&p) != TRUE) return false;
# if defined(FPL__ENABLE_WINDOW)
if (!backend->detached) {
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
if (!wapi->user.ScreenToClient(windowState->windowHandle, &p)) return false;
}
# endif
(outState);
outState-> = p.x;
outState-> = p.y;
bool leftDown = fpl__Win32IsKeyDown(wapi, VK_LBUTTON);
bool rightDown = fpl__Win32IsKeyDown(wapi, VK_RBUTTON);
bool middleDown = fpl__Win32IsKeyDown(wapi, VK_MBUTTON);
bool x1Down = fpl__Win32IsKeyDown(wapi, VK_XBUTTON1);
bool x2Down = fpl__Win32IsKeyDown(wapi, VK_XBUTTON2);
outState->[] = leftDown ? : ;
outState->[] = rightDown ? : ;
outState->[] = middleDown ? : ;
outState->[] = x1Down ? : ;
outState->[] = x2Down ? : ;
return true;
}
#if defined(FPL__ENABLE_WINDOW)
bool fpl__InputBackendWin32_HandleNativeEvent(fpl__InputBackendWin32 *backend, const fpl__NativeInputEvent *ev) {
(backend);
(ev);
if (!backend->isInitialized) return false;
if (ev->kind != fpl__NativeInputEventKind_Win32Msg) return false;
if (ev->payload == ) return false;
const MSG *msg = (const MSG *)ev->payload;
fpl__PlatformAppState *appState = fpl__global__AppState;
if (appState == ) return false;
const fpl__Win32Api *wapi = &appState->win32.winApi;
const bool eventsDisabled = appState->currentSettings.input.disabledEvents != 0;
switch (msg->message) {
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
{
if (eventsDisabled) return true;
if (!fpl__InputSystem_IsEnabled(&appState->input, )) return true;
uint64_t keyCode = msg->wParam;
bool isDown = (msg->lParam & (1 << 31)) == 0;
keyState = isDown ? : ;
modifiers = fpl__Win32GetKeyboardModifiers(wapi);
fpl__HandleKeyboardButtonEvent(&appState->window, GetTickCount(), keyCode, modifiers, keyState, false);
return true;
}
case WM_CHAR:
case WM_SYSCHAR:
case WM_UNICHAR:
case WM_DEADCHAR:
{
if (eventsDisabled) return true;
if (!fpl__InputSystem_IsEnabled(&appState->input, )) return true;
if ((msg->message == WM_UNICHAR) && (msg->wParam == UNICODE_NOCHAR)) {
return true;
}
fpl__HandleKeyboardInputEvent(&appState->window, (uint64_t)msg->wParam, (uint32_t)msg->wParam);
return true;
}
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
{
if (eventsDisabled) return true;
if (!fpl__InputSystem_IsEnabled(&appState->input, )) return true;
buttonState;
bool isDown = (msg->message == WM_LBUTTONDOWN || msg->message == WM_RBUTTONDOWN || msg->message == WM_MBUTTONDOWN || msg->message == WM_XBUTTONDOWN);
buttonState = isDown ? : ;
if (buttonState == ) {
wapi->user.SetCapture(msg->hwnd);
} else {
wapi->user.ReleaseCapture();
}
mouseButton;
if (msg->message == WM_LBUTTONDOWN || msg->message == WM_LBUTTONUP) {
mouseButton = ;
} else if (msg->message == WM_RBUTTONDOWN || msg->message == WM_RBUTTONUP) {
mouseButton = ;
} else if (msg->message == WM_MBUTTONDOWN || msg->message == WM_MBUTTONUP) {
mouseButton = ;
} else {
WORD which = GET_XBUTTON_WPARAM(msg->wParam);
mouseButton = (which == XBUTTON1) ? : (which == XBUTTON2) ? : ;
}
if (mouseButton != ) {
int32_t mouseX = GET_X_LPARAM(msg->lParam);
int32_t mouseY = GET_Y_LPARAM(msg->lParam);
fpl__HandleMouseButtonEvent(&appState->window, mouseX, mouseY, mouseButton, buttonState);
}
return true;
}
case WM_MOUSEMOVE:
{
if (eventsDisabled) return true;
if (!fpl__InputSystem_IsEnabled(&appState->input, )) return true;
int32_t mouseX = GET_X_LPARAM(msg->lParam);
int32_t mouseY = GET_Y_LPARAM(msg->lParam);
fpl__HandleMouseMoveEvent(&appState->window, mouseX, mouseY);
return true;
}
case WM_MOUSEWHEEL:
{
if (!fpl__InputSystem_IsEnabled(&appState->input, )) return true;
int32_t mouseX = GET_X_LPARAM(msg->lParam);
int32_t mouseY = GET_Y_LPARAM(msg->lParam);
short zDelta = GET_WHEEL_DELTA_WPARAM(msg->wParam);
float wheelDelta = zDelta / (float)WHEEL_DELTA;
fpl__HandleMouseWheelEvent(&appState->window, mouseX, mouseY, wheelDelta);
return true;
}
case WM_MOUSEHWHEEL:
{
// Horizontal wheel is forwarded but not yet surfaced through fpl__HandleMouseWheelEvent.
// Step 9 will extend the public mouse-event API with a horizontal axis.
return true;
}
default:
break;
}
return false;
}
#endif // FPL__ENABLE_WINDOW
#endif // FPL__WIN32_INPUT_KBM_IMPLEMENTED
bool fpl__Win32ThreadWaitForMultiple( **threads, const size_t count, const size_t stride, const timeout, const bool waitForAll) {
FPL__CheckArgumentNull(threads, false);
FPL__CheckArgumentMax(count, FPL_MAX_THREAD_COUNT, false);
(FPL_MAX_THREAD_COUNT >= MAXIMUM_WAIT_OBJECTS);
const size_t actualStride = stride > 0 ? stride : sizeof( *);
for (size_t index = 0; index < count; ++index) {
*thread = *( **)((uint8_t *)threads + index * actualStride);
if (thread == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Thread for index '%d' are not allowed to be null", index);
return false;
}
if ((thread) != ) {
if (thread->.win32ThreadHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Thread handle for index '%d' are not allowed to be null", index);
return false;
}
}
}
// @NOTE(final): WaitForMultipleObjects does not work for us here, because each thread will close its handle automatically
// So we screw it and use a simple while loop and wait until either the timeout has been reached or all threads has been stopped.
startTime = ();
size_t minThreads = waitForAll ? count : 1;
size_t stoppedThreads = 0;
while (stoppedThreads < minThreads) {
stoppedThreads = 0;
for (size_t index = 0; index < count; ++index) {
*thread = *( **)((uint8_t *)threads + index * actualStride);
if ((thread) == ) {
++stoppedThreads;
}
}
if (stoppedThreads >= minThreads) {
break;
}
if (timeout != ) {
if ((() - startTime) >= timeout) {
break;
}
}
();
}
bool result = stoppedThreads >= minThreads;
return(result);
}
bool fpl__Win32SignalWaitForMultiple( **signals, const size_t count, const size_t stride, const timeout, const bool waitForAll) {
FPL__CheckArgumentNull(signals, false);
FPL__CheckArgumentMax(count, FPL_MAX_SIGNAL_COUNT, false);
// @MEMORY(final): This wastes a lot memory, use temporary memory allocation here.
HANDLE signalHandles[FPL_MAX_SIGNAL_COUNT];
const size_t actualStride = stride > 0 ? stride : sizeof( *);
for (uint32_t index = 0; index < count; ++index) {
*availableSignal = *( **)((uint8_t *)signals + index * actualStride);
if (availableSignal == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal for index '%d' are not allowed to be null", index);
return false;
}
if (availableSignal->.win32EventHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal handle for index '%d' are not allowed to be null", index);
return false;
}
HANDLE handle = availableSignal->.win32EventHandle;
signalHandles[index] = handle;
}
DWORD t = timeout == ? INFINITE : timeout;
DWORD code = WaitForMultipleObjects((DWORD)count, signalHandles, waitForAll ? TRUE : FALSE, t);
bool result = (code >= WAIT_OBJECT_0);
return(result);
}
void fpl__Win32ReleasePlatform(fpl__PlatformInitState *initState, fpl__PlatformAppState *appState) {
(appState != );
fpl__Win32AppState *win32AppState = &appState->win32;
fpl__Win32UnloadApi(&win32AppState->winApi);
}
bool fpl__Win32InitPlatform(const initFlags, const *initSettings, fpl__PlatformInitState *initState, fpl__PlatformAppState *appState) {
(initState != );
(appState != );
fpl__Win32InitState *win32InitState = &initState->win32;
fpl__Win32AppState *win32AppState = &appState->win32;
// @NOTE(final): Expect kernel32.lib to be linked always, so VirtualAlloc, LoadLibrary, CreateThread, etc. will always work.
// Get application instance handle
win32InitState->appInstance = GetModuleHandleA();
// Query performance frequency and store it once, it will never change during runtime
QueryPerformanceFrequency(&win32InitState->qpf);
// Get main thread infos
HANDLE mainThreadHandle = GetCurrentThread();
DWORD mainThreadHandleId = GetCurrentThreadId();
*mainThread = &fpl__global__ThreadState.mainThread;
(mainThread);
mainThread-> = mainThreadHandleId;
mainThread->.win32ThreadHandle = mainThreadHandle;
mainThread-> = ;
// Load windows api library
if (!fpl__Win32LoadApi(&win32AppState->winApi)) {
// @NOTE(final): Assume that errors are pushed on already.
fpl__Win32ReleasePlatform(initState, appState);
return false;
}
// Show/Hide console
bool showConsole = (initFlags, );
HWND consoleWindow = GetConsoleWindow();
if (!showConsole) {
if (consoleWindow != ) {
win32AppState->winApi.user.ShowWindow(consoleWindow, SW_HIDE);
} else {
FreeConsole();
}
} else if (consoleWindow != ) {
const *initConsoleSettings = &initSettings->;
*currentConsoleSettings = &appState->currentSettings.console;
// Setup a console title
wchar_t consoleTitleBuffer[];
if ((initConsoleSettings->) > 0) {
(initConsoleSettings->, (initConsoleSettings->), consoleTitleBuffer, (consoleTitleBuffer));
} else {
const wchar_t *defaultTitle = FPL__WIN32_UNNAMED_CONSOLE;
lstrcpynW(consoleTitleBuffer, defaultTitle, (consoleTitleBuffer));
}
wchar_t *windowTitle = consoleTitleBuffer;
(windowTitle, lstrlenW(windowTitle), currentConsoleSettings->, (currentConsoleSettings->));
SetConsoleTitleW(windowTitle);
win32AppState->winApi.user.ShowWindow(consoleWindow, SW_SHOW);
}
return (true);
}
//
// Win32 Atomics
//
void (void) {
FPL_MEMORY_BARRIER();
_ReadBarrier();
}
void (void) {
FPL_MEMORY_BARRIER();
_WriteBarrier();
}
void (void) {
FPL_MEMORY_BARRIER();
_ReadWriteBarrier();
}
uint32_t (volatile uint32_t *target, const uint32_t value) {
(target != );
uint32_t result = InterlockedExchange((volatile LONG *)target, value);
return (result);
}
int32_t (volatile int32_t *target, const int32_t value) {
(target != );
int32_t result = InterlockedExchange((volatile LONG *)target, value);
return (result);
}
uint64_t (volatile uint64_t *target, const uint64_t value) {
(target != );
uint64_t result = InterlockedExchange64((volatile LONG64 *)target, value);
return (result);
}
int64_t (volatile int64_t *target, const int64_t value) {
(target != );
int64_t result = InterlockedExchange64((volatile LONG64 *)target, value);
return (result);
}
uint32_t (volatile uint32_t *value, const uint32_t addend) {
(value != );
uint32_t result = InterlockedExchangeAdd((volatile LONG *)value, addend);
return (result);
}
int32_t (volatile int32_t *value, const int32_t addend) {
(value != );
int32_t result = InterlockedExchangeAdd((volatile LONG *)value, addend);
return (result);
}
uint64_t (volatile uint64_t *value, const uint64_t addend) {
(value != );
uint64_t result = InterlockedExchangeAdd64((volatile LONG64 *)value, addend);
return (result);
}
int64_t (volatile int64_t *value, const int64_t addend) {
(value != );
int64_t result = InterlockedExchangeAdd64((volatile LONG64 *)value, addend);
return(result);
}
uint32_t (volatile uint32_t *value, const uint32_t addend) {
(value != );
uint32_t result = InterlockedAdd((volatile LONG *)value, addend);
return (result);
}
int32_t (volatile int32_t *value, const int32_t addend) {
(value != );
int32_t result = InterlockedAdd((volatile LONG *)value, addend);
return (result);
}
uint64_t (volatile uint64_t *value, const uint64_t addend) {
(value != );
uint64_t result = InterlockedAdd64((volatile LONG64 *)value, addend);
return (result);
}
int64_t (volatile int64_t *value, const int64_t addend) {
(value != );
int64_t result = InterlockedAdd64((volatile LONG64 *)value, addend);
return(result);
}
uint32_t (volatile uint32_t *value) {
(value != );
uint32_t result = InterlockedIncrement((volatile LONG *)value);
return (result);
}
int32_t (volatile int32_t *value) {
(value != );
int32_t result = InterlockedIncrement((volatile LONG *)value);
return (result);
}
uint64_t (volatile uint64_t *value) {
(value != );
uint64_t result = InterlockedIncrement64((volatile LONG64 *)value);
return (result);
}
int64_t (volatile int64_t *value) {
(value != );
int64_t result = InterlockedIncrement64((volatile LONG64 *)value);
return(result);
}
uint32_t (volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
(dest != );
uint32_t result = InterlockedCompareExchange((volatile LONG *)dest, exchange, comparand);
return (result);
}
int32_t (volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
(dest != );
int32_t result = InterlockedCompareExchange((volatile LONG *)dest, exchange, comparand);
return (result);
}
uint64_t (volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
(dest != );
uint64_t result = InterlockedCompareExchange64((volatile LONG64 *)dest, exchange, comparand);
return (result);
}
int64_t (volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
(dest != );
int64_t result = InterlockedCompareExchange64((volatile LONG64 *)dest, exchange, comparand);
return (result);
}
bool (volatile uint32_t *dest, const uint32_t comparand, const uint32_t exchange) {
(dest != );
uint32_t value = InterlockedCompareExchange((volatile LONG *)dest, exchange, comparand);
bool result = (value == comparand);
return (result);
}
bool (volatile int32_t *dest, const int32_t comparand, const int32_t exchange) {
(dest != );
int32_t value = InterlockedCompareExchange((volatile LONG *)dest, exchange, comparand);
bool result = (value == comparand);
return (result);
}
bool (volatile uint64_t *dest, const uint64_t comparand, const uint64_t exchange) {
(dest != );
uint64_t value = InterlockedCompareExchange64((volatile LONG64 *)dest, exchange, comparand);
bool result = (value == comparand);
return (result);
}
bool (volatile int64_t *dest, const int64_t comparand, const int64_t exchange) {
(dest != );
int64_t value = InterlockedCompareExchange64((volatile LONG64 *)dest, exchange, comparand);
bool result = (value == comparand);
return (result);
}
uint32_t (volatile uint32_t *source) {
uint32_t result = InterlockedCompareExchange((volatile LONG *)source, 0, 0);
return(result);
}
uint64_t (volatile uint64_t *source) {
uint64_t result = InterlockedCompareExchange64((volatile LONG64 *)source, 0, 0);
return(result);
}
int32_t (volatile int32_t *source) {
int32_t result = InterlockedCompareExchange((volatile LONG *)source, 0, 0);
return(result);
}
int64_t (volatile int64_t *source) {
int64_t result = InterlockedCompareExchange64((volatile LONG64 *)source, 0, 0);
return(result);
}
void (volatile uint32_t *dest, const uint32_t value) {
InterlockedExchange((volatile LONG *)dest, value);
}
void (volatile uint64_t *dest, const uint64_t value) {
InterlockedExchange64((volatile LONG64 *)dest, value);
}
void (volatile int32_t *dest, const int32_t value) {
InterlockedExchange((volatile LONG *)dest, value);
}
void (volatile int64_t *dest, const int64_t value) {
InterlockedExchange64((volatile LONG64 *)dest, value);
}
//
// Win32 OS
//
const char *fpl__Win32GetVersionName(DWORD major, DWORD minor) {
const char *result;
if (major == 5 && minor == 0) {
result = "Windows 2000";
} else if (major == 5 && minor == 1) {
result = "Windows XP";
} else if (major == 5 && minor == 2) {
result = "Windows XP";
} else if (major == 6 && minor == 0) {
result = "Windows Vista";
} else if (major == 6 && minor == 1) {
result = "Windows 7";
} else if (major == 6 && minor == 2) {
result = "Windows 8";
} else if (major == 6 && minor == 3) {
result = "Windows 8.1";
} else if (major == 10) {
result = "Windows 10";
} else {
result = "Windows";
}
return(result);
}
#define FPL__FUNC_NTDLL_RtlGetVersion(name) DWORD WINAPI name(PRTL_OSVERSIONINFOW lpVersionInformation)
typedef FPL__FUNC_NTDLL_RtlGetVersion(fpl__func_ntdll_RtlGetVersionProc);
#define FPL__FUNC_KERNEL32_GetVersion(name) DWORD WINAPI name(void)
typedef FPL__FUNC_KERNEL32_GetVersion(fpl__func_kernel32_GetVersion);
#define FPL__FUNC_KERNEL32_GetVersionExW(name) BOOL WINAPI name(LPOSVERSIONINFOEXW lpVersionInfo)
typedef FPL__FUNC_KERNEL32_GetVersionExW(fpl__func_kernel32_GetVersionExW);
bool ( *outInfos) {
FPL__CheckArgumentNull(outInfos, false);
(outInfos);
// @NOTE(final): Prefer RtlGetVersion always, because MS might decide to totally remove GetVersion() and GetVersionEx()
HMODULE ntdllModule = GetModuleHandleA("ntdll");
fpl__func_ntdll_RtlGetVersionProc *rtlGetVersionProc = (fpl__func_ntdll_RtlGetVersionProc *)(void *)GetProcAddress(ntdllModule, "RtlGetVersion");
if (rtlGetVersionProc != ) {
RTL_OSVERSIONINFOW info = ;
info.dwOSVersionInfoSize = sizeof(info);
if (rtlGetVersionProc(&info) == 0) {
((int32_t)info.dwMajorVersion, outInfos->..., (outInfos->...));
((int32_t)info.dwMinorVersion, outInfos->..., (outInfos->...));
(0, outInfos->..., (outInfos->...));
((int32_t)info.dwBuildNumber, outInfos->..., (outInfos->...));
(outInfos->., (outInfos->.), "%u.%u.%u.%u", info.dwMajorVersion, info.dwMinorVersion, 0, info.dwBuildNumber);
const char *versionName = fpl__Win32GetVersionName(info.dwMajorVersion, info.dwMinorVersion);
(versionName, outInfos->, (outInfos->));
return(true);
}
}
// @NOTE(final): GetVersion() and GetVersionExA() is deprecated as of windows 8.1, so we load it manually always
HMODULE kernelLib = LoadLibraryA("kernel32.dll");
if (kernelLib == ) {
FPL__ERROR(FPL__MODULE_WIN32, "Kernel32 library could not be loaded");
return false;
}
fpl__func_kernel32_GetVersion *getVersionProc = (fpl__func_kernel32_GetVersion *)(void *)GetProcAddress(kernelLib, "GetVersion");
fpl__func_kernel32_GetVersionExW *getVersionExProc = (fpl__func_kernel32_GetVersionExW *)(void *)GetProcAddress(kernelLib, "GetVersionExW");
FreeLibrary(kernelLib);
if (getVersionExProc != ) {
OSVERSIONINFOEXW infoEx = ;
infoEx.dwOSVersionInfoSize = sizeof(infoEx);
if (getVersionExProc(&infoEx) == TRUE) {
((int32_t)infoEx.dwMajorVersion, outInfos->..., (outInfos->...));
((int32_t)infoEx.dwMinorVersion, outInfos->..., (outInfos->...));
(0, outInfos->..., (outInfos->...));
((int32_t)infoEx.dwBuildNumber, outInfos->..., (outInfos->...));
(outInfos->., (outInfos->.), "%u.%u.%u.%u", infoEx.dwMajorVersion, infoEx.dwMinorVersion, 0, infoEx.dwBuildNumber);
const char *versionName = fpl__Win32GetVersionName(infoEx.dwMajorVersion, infoEx.dwMinorVersion);
(versionName, outInfos->, (outInfos->));
return(true);
}
}
if (getVersionProc != ) {
DWORD dwVersion = getVersionProc();
if (dwVersion > 0) {
DWORD major = (DWORD)(LOBYTE(LOWORD(dwVersion)));
DWORD minor = (DWORD)(HIBYTE(LOWORD(dwVersion)));
DWORD build = 0;
if (dwVersion < 0x80000000) {
build = (DWORD)((DWORD)(HIWORD(dwVersion)));
}
((int32_t)major, outInfos->..., (outInfos->...));
((int32_t)minor, outInfos->..., (outInfos->...));
(0, outInfos->..., (outInfos->...));
((int32_t)build, outInfos->..., (outInfos->...));
(outInfos->., (outInfos->.), "%u.%u.%u.%u", major, minor, 0, build);
const char *versionName = fpl__Win32GetVersionName(major, minor);
(versionName, outInfos->, (outInfos->));
return(true);
}
}
return(false);
}
#define FPL__FUNC_ADV32_GetUserNameW(name) BOOL WINAPI name(LPWSTR lpBuffer, LPDWORD pcbBuffer)
typedef FPL__FUNC_ADV32_GetUserNameW(fpl__func_adv32_GetUserNameW);
size_t (char *nameBuffer, const size_t maxNameBufferLen) {
const char *libName = "advapi32.dll";
HMODULE adv32Lib = LoadLibraryA(libName);
if (adv32Lib == ) {
FPL__ERROR(FPL__MODULE_WIN32, "Failed loading library '%s'", libName);
return false;
}
fpl__func_adv32_GetUserNameW *getUserNameProc = (fpl__func_adv32_GetUserNameW *)(void *)GetProcAddress(adv32Lib, "GetUserNameW");
size_t result = 0;
if (getUserNameProc != ) {
wchar_t wideBuffer[];
DWORD size = (DWORD)(wideBuffer);
if (getUserNameProc(wideBuffer, &size) == TRUE) {
result = (wideBuffer, size, nameBuffer, maxNameBufferLen);
}
}
FreeLibrary(adv32Lib);
return(result);
}
//
// Win32 Hardware
//
size_t (void) {
SYSTEM_INFO sysInfo = ;
GetSystemInfo(&sysInfo);
// @NOTE(final): For now, this returns the number of logical processors, which is the actual core count in most cases.
size_t result = sysInfo.dwNumberOfProcessors;
return(result);
}
#define FPL__WIN32_PROCESSOR_ARCHITECTURE_ARM64 12
(void) {
result;
SYSTEM_INFO sysInfo = ;
BOOL isWow64;
if (IsWow64Process(GetCurrentProcess(), &isWow64)) {
if (isWow64)
GetNativeSystemInfo(&sysInfo);
else
GetSystemInfo(&sysInfo);
} else {
GetSystemInfo(&sysInfo);
}
switch (sysInfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
result = ;
break;
case PROCESSOR_ARCHITECTURE_IA64:
result = ;
break;
case PROCESSOR_ARCHITECTURE_ARM:
result = ;
break;
case FPL__WIN32_PROCESSOR_ARCHITECTURE_ARM64:
result = ;
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
result = ;
break;
case PROCESSOR_ARCHITECTURE_INTEL:
default:
result = ;
break;
}
return(result);
}
#define FPL__FUNC_WIN32_KERNEL32_GetPhysicallyInstalledSystemMemory(name) BOOL WINAPI name(PULONGLONG TotalMemoryInKilobytes)
typedef FPL__FUNC_WIN32_KERNEL32_GetPhysicallyInstalledSystemMemory(fpl__win32_kernel_func_GetPhysicallyInstalledSystemMemory);
bool ( *outInfos) {
FPL__CheckArgumentNull(outInfos, false);
bool result = false;
HMODULE kernel32lib = LoadLibraryA("kernel32.dll");
if (kernel32lib == ) {
return false;
}
fpl__win32_kernel_func_GetPhysicallyInstalledSystemMemory *getPhysicallyInstalledSystemMemory = (fpl__win32_kernel_func_GetPhysicallyInstalledSystemMemory *)(void *)GetProcAddress(kernel32lib, "GetPhysicallyInstalledSystemMemory");
FreeLibrary(kernel32lib);
ULONGLONG installedMemorySize = 0;
if (getPhysicallyInstalledSystemMemory != ) {
getPhysicallyInstalledSystemMemory(&installedMemorySize);
}
SYSTEM_INFO systemInfo = ;
GetSystemInfo(&systemInfo);
MEMORYSTATUSEX statex = ;
statex.dwLength = sizeof(statex);
if (GlobalMemoryStatusEx(&statex)) {
(outInfos);
outInfos-> = installedMemorySize * 1024ull;
outInfos-> = statex.ullTotalPhys;
outInfos-> = statex.ullAvailPhys;
outInfos-> = statex.ullTotalVirtual;
outInfos-> = statex.ullAvailVirtual;
outInfos-> = systemInfo.dwPageSize;
if (outInfos-> > 0) {
outInfos-> = statex.ullTotalPageFile / outInfos->;
outInfos-> = statex.ullAvailPageFile / outInfos->;
}
result = true;
}
return(result);
}
//
// Win32 Threading
//
DWORD WINAPI fpl__Win32ThreadProc(void *data) {
*thread = ( *)data;
(thread != );
((volatile uint32_t *)&thread->, (uint32_t));
parameters = thread->;
if (parameters. != ) {
parameters.(thread, parameters.);
}
((volatile uint32_t *)&thread->, (uint32_t));
HANDLE handle = thread->.win32ThreadHandle;
if (handle != ) {
CloseHandle(handle);
}
thread-> = false;
((volatile uint32_t *)&thread->, (uint32_t));
ExitThread(0);
}
uint64_t (void) {
DWORD threadId = GetCurrentThreadId();
uint64_t result = (uint64_t)threadId;
return(result);
}
bool fpl__Win32SetThreadPriority(HANDLE threadHandle, const newPriority) {
int win32Priority = 0;
switch (newPriority) {
case :
win32Priority = THREAD_PRIORITY_IDLE;
break;
case :
win32Priority = THREAD_PRIORITY_LOWEST;
break;
case :
win32Priority = THREAD_PRIORITY_NORMAL;
break;
case :
win32Priority = THREAD_PRIORITY_HIGHEST;
break;
case :
win32Priority = THREAD_PRIORITY_TIME_CRITICAL;
break;
default:
FPL__ERROR(FPL__MODULE_THREADING, "The thread priority %d is not supported", newPriority);
return(false);
}
bool result = SetThreadPriority(threadHandle, win32Priority) == TRUE;
return(result);
}
*( *parameters) {
FPL__CheckArgumentNull(parameters, );
FPL__CheckArgumentNull(parameters->, );
*result = ;
*thread = fpl__GetFreeThread();
if (thread != ) {
DWORD creationFlags = 0;
DWORD threadId = 0;
SIZE_T stackSize = parameters->;
thread-> = *parameters;
thread-> = ;
HANDLE handle = CreateThread(, stackSize, fpl__Win32ThreadProc, thread, creationFlags, &threadId);
if (handle != ) {
fpl__Win32SetThreadPriority(handle, thread->.);
thread-> = true;
thread-> = threadId;
thread->.win32ThreadHandle = handle;
result = thread;
} else {
FPL__ERROR(FPL__MODULE_THREADING, "Failed creating thread, error code: %d", GetLastError());
}
} else {
FPL__ERROR(FPL__MODULE_THREADING, "All %d threads are in use, you cannot create until you free one", FPL_MAX_THREAD_COUNT);
}
return(result);
}
*( *runFunc, void *data) {
FPL__CheckArgumentNull(runFunc, );
parameters = ;
parameters. = ;
parameters. = runFunc;
parameters. = data;
*result = (¶meters);
return(result);
}
fpl__Win32MapNativeThreadPriority(const int win32ThreadPriority) {
switch (win32ThreadPriority) {
case THREAD_PRIORITY_IDLE:
return ;
case THREAD_PRIORITY_LOWEST:
case THREAD_PRIORITY_BELOW_NORMAL:
return ;
case THREAD_PRIORITY_NORMAL:
return ;
case THREAD_PRIORITY_ABOVE_NORMAL:
case THREAD_PRIORITY_HIGHEST:
return ;
case THREAD_PRIORITY_TIME_CRITICAL:
return ;
default:
return ;
}
}
( *thread) {
FPL__CheckArgumentNull(thread, );
result = ;
if (thread-> && thread->.win32ThreadHandle != ) {
HANDLE threadHandle = thread->.win32ThreadHandle;
int win32ThreadPriority = GetThreadPriority(threadHandle);
result = fpl__Win32MapNativeThreadPriority(win32ThreadPriority);
}
return(result);
}
bool ( *thread, const newPriority) {
FPL__CheckArgumentNull(thread, false);
bool result = false;
if (thread-> && thread->.win32ThreadHandle != ) {
HANDLE threadHandle = thread->.win32ThreadHandle;
result = fpl__Win32SetThreadPriority(threadHandle, newPriority);
}
return(result);
}
void (const uint32_t milliseconds) {
Sleep((DWORD)milliseconds);
}
bool (void) {
YieldProcessor();
return(true);
}
bool ( *thread) {
FPL__CheckArgumentNull(thread, false);
state = (thread);
if (thread-> && (state != && state != )) {
((volatile uint32_t *)&thread->, (uint32_t));
HANDLE handle = thread->.win32ThreadHandle;
if (handle != ) {
TerminateThread(handle, 0);
CloseHandle(handle);
}
thread-> = false;
((volatile uint32_t *)&thread->, (uint32_t));
return true;
} else {
return false;
}
}
bool ( *thread, const timeout) {
FPL__CheckArgumentNull(thread, false);
bool result;
if ((thread) != ) {
if (thread->.win32ThreadHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Win32 thread handle are not allowed to be null");
return false;
}
HANDLE handle = thread->.win32ThreadHandle;
DWORD t = timeout == ? INFINITE : timeout;
result = (WaitForSingleObject(handle, t) == WAIT_OBJECT_0);
} else {
result = true;
}
return(result);
}
bool ( **threads, const size_t count, const size_t stride, const timeout) {
bool result = fpl__Win32ThreadWaitForMultiple(threads, count, stride, timeout, true);
return(result);
}
bool ( **threads, const size_t count, const size_t stride, const timeout) {
bool result = fpl__Win32ThreadWaitForMultiple(threads, count, stride, timeout, false);
return(result);
}
bool ( *mutex) {
FPL__CheckArgumentNull(mutex, false);
if (mutex->) {
FPL__ERROR(FPL__MODULE_THREADING, "Mutex '%p' is already initialized", mutex);
return false;
}
(mutex);
mutex-> = true;
(sizeof(mutex->.win32CriticalSection) >= sizeof(CRITICAL_SECTION));
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
InitializeCriticalSection(critSection);
return true;
}
void ( *mutex) {
FPL__CheckArgumentNullNoRet(mutex);
if (mutex->) {
(sizeof(mutex->.win32CriticalSection) >= sizeof(CRITICAL_SECTION));
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
DeleteCriticalSection(critSection);
(mutex);
}
}
bool ( *mutex) {
FPL__CheckArgumentNull(mutex, false);
if (!mutex->) {
FPL__ERROR(FPL__MODULE_THREADING, "Mutex parameter must be valid");
return false;
}
(sizeof(mutex->.win32CriticalSection) >= sizeof(CRITICAL_SECTION));
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
EnterCriticalSection(critSection);
return true;
}
bool ( *mutex) {
FPL__CheckArgumentNull(mutex, false);
if (!mutex->) {
FPL__ERROR(FPL__MODULE_THREADING, "Mutex parameter must be valid");
return false;
}
(sizeof(mutex->.win32CriticalSection) >= sizeof(CRITICAL_SECTION));
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
bool result = TryEnterCriticalSection(critSection) == TRUE;
return(result);
}
bool ( *mutex) {
FPL__CheckArgumentNull(mutex, false);
if (!mutex->) {
FPL__ERROR(FPL__MODULE_THREADING, "Mutex parameter must be valid");
return false;
}
(sizeof(mutex->.win32CriticalSection) >= sizeof(CRITICAL_SECTION));
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
LeaveCriticalSection(critSection);
return true;
}
bool ( *signal, const initialValue) {
FPL__CheckArgumentNull(signal, false);
if (signal->) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal '%p' is already initialized", signal);
return false;
}
HANDLE handle = CreateEventA(, FALSE, (initialValue == ) ? TRUE : FALSE, );
if (handle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Failed creating signal (Win32 event): %d", GetLastError());
return false;
}
(signal);
signal-> = true;
signal->.win32EventHandle = handle;
return(true);
}
void ( *signal) {
FPL__CheckArgumentNullNoRet(signal);
if (signal->.win32EventHandle != ) {
HANDLE handle = signal->.win32EventHandle;
CloseHandle(handle);
(signal);
}
}
bool ( *signal, const timeout) {
FPL__CheckArgumentNull(signal, false);
if (signal->.win32EventHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal handle are not allowed to be null");
return false;
}
HANDLE handle = signal->.win32EventHandle;
DWORD t = timeout == ? INFINITE : timeout;
bool result = (WaitForSingleObject(handle, t) == WAIT_OBJECT_0);
return(result);
}
bool ( **signals, const size_t count, const size_t stride, const timeout) {
bool result = fpl__Win32SignalWaitForMultiple(signals, count, stride, timeout, true);
return(result);
}
bool ( **signals, const size_t count, const size_t stride, const timeout) {
bool result = fpl__Win32SignalWaitForMultiple(signals, count, stride, timeout, false);
return(result);
}
bool ( *signal) {
FPL__CheckArgumentNull(signal, false);
if (signal->.win32EventHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal handle are not allowed to be null");
return false;
}
HANDLE handle = signal->.win32EventHandle;
bool result = SetEvent(handle) == TRUE;
return(result);
}
bool ( *signal) {
FPL__CheckArgumentNull(signal, false);
if (signal->.win32EventHandle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Signal handle are not allowed to be null");
return false;
}
HANDLE handle = signal->.win32EventHandle;
bool result = ResetEvent(handle) == TRUE;
return(result);
}
bool ( *condition) {
FPL__CheckArgumentNull(condition, false);
(condition);
(sizeof(condition->.win32Condition) == sizeof(CONDITION_VARIABLE));
CONDITION_VARIABLE *condVar = (CONDITION_VARIABLE *)&condition->.win32Condition;
InitializeConditionVariable(condVar);
condition-> = true;
return true;
}
void ( *condition) {
FPL__CheckArgumentNullNoRet(condition);
if (condition->) {
(condition);
}
}
bool ( *condition, *mutex, const timeout) {
FPL__CheckArgumentNull(condition, false);
FPL__CheckArgumentNull(mutex, false);
if (!condition->) {
FPL__ERROR(FPL__MODULE_THREADING, "Condition '%p' is not valid", condition);
return false;
}
if (!mutex->) {
FPL__ERROR(FPL__MODULE_THREADING, "Mutex '%p' is not valid", mutex);
return false;
}
DWORD t = timeout == ? INFINITE : timeout;
CRITICAL_SECTION *critSection = (CRITICAL_SECTION *)&mutex->.win32CriticalSection;
CONDITION_VARIABLE *condVar = (CONDITION_VARIABLE *)&condition->.win32Condition;
bool result = SleepConditionVariableCS(condVar, critSection, t) != 0;
return(result);
}
bool ( *condition) {
FPL__CheckArgumentNull(condition, false);
if (!condition->) {
FPL__ERROR(FPL__MODULE_THREADING, "Condition '%p' is not valid", condition);
return false;
}
CONDITION_VARIABLE *critSection = (CONDITION_VARIABLE *)&condition->.win32Condition;
WakeConditionVariable(critSection);
return true;
}
bool ( *condition) {
FPL__CheckArgumentNull(condition, false);
if (!condition->) {
FPL__ERROR(FPL__MODULE_THREADING, "Condition '%p' is not valid", condition);
return false;
}
CONDITION_VARIABLE *critSection = (CONDITION_VARIABLE *)&condition->.win32Condition;
WakeAllConditionVariable(critSection);
return true;
}
bool ( *semaphore, const uint32_t initialValue) {
FPL__CheckArgumentNull(semaphore, false);
FPL__CheckArgumentMax(initialValue, INT32_MAX, false);
if (semaphore->) {
FPL__ERROR(FPL__MODULE_THREADING, "Semaphore '%p' is already initialized", semaphore);
return false;
}
HANDLE handle = CreateSemaphoreA(, (LONG)initialValue, INT32_MAX, );
if (handle == ) {
FPL__ERROR(FPL__MODULE_THREADING, "Failed creating semaphore");
return false;
}
(semaphore);
semaphore-> = true;
semaphore->.win32.handle = handle;
semaphore->.win32.value = (int32_t)initialValue;
return true;
}
void ( *semaphore) {
FPL__CheckArgumentNullNoRet(semaphore);
if (semaphore->) {
CloseHandle(semaphore->.win32.handle);
(semaphore);
}
}
bool ( *semaphore, const timeout) {
FPL__CheckArgumentNull(semaphore, false);
if (!semaphore->) {
FPL__ERROR(FPL__MODULE_THREADING, "Semaphore '%p' is not valid", semaphore);
return false;
}
DWORD t = timeout == ? INFINITE : timeout;
bool result = false;
if (WaitForSingleObject(semaphore->.win32.handle, timeout) == WAIT_OBJECT_0) {
(&semaphore->.win32.value, -1);
result = true;
}
return(result);
}
bool ( *semaphore) {
FPL__CheckArgumentNull(semaphore, false);
if (!semaphore->) {
FPL__ERROR(FPL__MODULE_THREADING, "Semaphore '%p' is not valid", semaphore);
return false;
}
bool result = false;
if (WaitForSingleObject(semaphore->.win32.handle, 0) == WAIT_OBJECT_0) {
(&semaphore->.win32.value, -1);
result = true;
}
return(result);
}
int32_t ( *semaphore) {
FPL__CheckArgumentNull(semaphore, false);
if (!semaphore->) {
FPL__ERROR(FPL__MODULE_THREADING, "Semaphore '%p' is not valid", semaphore);
return false;
}
int32_t result = (&semaphore->.win32.value);
return(result);
}
bool ( *semaphore) {
FPL__CheckArgumentNull(semaphore, false);
if (!semaphore->) {
FPL__ERROR(FPL__MODULE_THREADING, "Semaphore '%p' is not valid", semaphore);
return false;
}
bool result = true;
int32_t prevValue = (&semaphore->.win32.value, 1);
if (ReleaseSemaphore(semaphore->.win32.handle, 1, ) == FALSE) {
// Restore value when it fails
FPL__ERROR(FPL__MODULE_THREADING, "Failed releasing the semaphore '%p'", semaphore);
(&semaphore->.win32.value, prevValue);
result = false;
}
return(result);
}
//
// Win32 Console
//
void (const char *text) {
DWORD charsToWrite = (DWORD)(text);
DWORD writtenChars = 0;
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
wchar_t wideBuffer[];
(text, charsToWrite, wideBuffer, (wideBuffer));
WriteConsoleW(handle, wideBuffer, charsToWrite, &writtenChars, );
}
void (const char *text) {
DWORD charsToWrite = (DWORD)(text);
DWORD writtenChars = 0;
HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
wchar_t wideBuffer[];
(text, charsToWrite, wideBuffer, (wideBuffer));
WriteConsoleW(handle, wideBuffer, charsToWrite, &writtenChars, );
}
char (void) {
HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD savedMode;
GetConsoleMode(handle, &savedMode);
SetConsoleMode(handle, ENABLE_PROCESSED_INPUT);
char result = 0;
if (WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0) {
DWORD charsRead = 0;
char inputBuffer[2] = ;
if (ReadFile(handle, inputBuffer, 1, &charsRead, ) != 0) {
result = inputBuffer[0];
}
}
SetConsoleMode(handle, savedMode);
return (result);
}
//
// Win32 Memory
//
void *(const size_t size) {
FPL__CheckArgumentZero(size, );
void *result = VirtualAlloc(, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (result == ) {
FPL__ERROR(FPL__MODULE_MEMORY, "Failed allocating memory of %xu bytes", size);
}
return(result);
}
void (void *ptr) {
FPL__CheckArgumentNullNoRet(ptr);
VirtualFree(ptr, 0, MEM_RELEASE);
}
//
// Win32 Files
//
const uint64_t FPL__WIN32_TICKS_PER_SEC = 10000000ULL;
const uint64_t FPL__WIN32_UNIX_EPOCH_DIFFERENCE = 11644473600ULL;
// fplClearStruct zeroes the struct, setting the handle to NULL.
// CreateFileW returns INVALID_HANDLE_VALUE (-1) on error.
// A handle is only safe to use when it is neither NULL nor INVALID_HANDLE_VALUE.
#define FPL__WIN32_IS_VALID_FILE_HANDLE(h) ((h) != fpl_null && (h) != INVALID_HANDLE_VALUE)
fpl__Win32ConvertFileTimeToUnixTimestamp(const FILETIME *fileTime) {
// Ticks are defined in 100 ns = 10000000 secs
// Windows ticks starts at 1601-01-01T00:00:00Z
// Unix secs starts at 1970-01-01T00:00:00Z
result = 0;
if (fileTime != && (fileTime->dwLowDateTime > 0 || fileTime->dwHighDateTime > 0)) {
// Convert to SYSTEMTIME and remove milliseconds
SYSTEMTIME sysTime;
FileTimeToSystemTime(fileTime, &sysTime);
sysTime.wMilliseconds = 0; // Really important, because unix-timestamps does not support milliseconds
// Reconvert to FILETIME to account for removed milliseconds
FILETIME withoutMSecs;
SystemTimeToFileTime(&sysTime, &withoutMSecs);
// Convert to large integer so we can access U64 directly
ULARGE_INTEGER ticks;
ticks.LowPart = withoutMSecs.dwLowDateTime;
ticks.HighPart = withoutMSecs.dwHighDateTime;
// Final conversion from ticks to unix-timestamp
result = (ticks.QuadPart / FPL__WIN32_TICKS_PER_SEC) - FPL__WIN32_UNIX_EPOCH_DIFFERENCE;
}
return(result);
}
bool (const char *filePath, *outHandle) {
FPL__CheckArgumentNull(outHandle, false);
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
(outHandle);
outHandle-> = true;
outHandle->.win32FileHandle = (void *)win32FileHandle;
return true;
}
}
return false;
}
bool (const char *filePath, *outHandle) {
FPL__CheckArgumentNull(outHandle, false);
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_WRITE, FILE_SHARE_WRITE, , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
(outHandle);
outHandle-> = true;
outHandle->.win32FileHandle = (void *)win32FileHandle;
return true;
}
}
return false;
}
bool (const char *filePath, *outHandle) {
FPL__CheckArgumentNull(outHandle, false);
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, FILE_APPEND_DATA, FILE_SHARE_WRITE, , OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
(outHandle);
outHandle-> = true;
outHandle->.win32FileHandle = (void *)win32FileHandle;
return true;
}
}
return false;
}
uint32_t (const *fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize) {
FPL__CheckArgumentNull(fileHandle, 0);
FPL__CheckArgumentZero(sizeToRead, 0);
FPL__CheckArgumentNull(targetBuffer, 0);
FPL__CheckArgumentZero(maxTargetBufferSize, 0);
if (!FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
FPL__ERROR(FPL__MODULE_FILES, "Filehandle is not opened for reading");
return 0;
}
uint32_t actualToRead = (sizeToRead > maxTargetBufferSize) ? maxTargetBufferSize : sizeToRead;
uint32_t result = 0;
HANDLE win32FileHandle = (HANDLE)fileHandle->.win32FileHandle;
DWORD bytesRead = 0;
if (ReadFile(win32FileHandle, targetBuffer, (DWORD)actualToRead, &bytesRead, ) == TRUE) {
result = bytesRead;
}
return(result);
}
uint64_t (const *fileHandle, const uint64_t sizeToRead, void *targetBuffer, const uint64_t maxTargetBufferSize) {
FPL__CheckArgumentNull(fileHandle, 0);
FPL__CheckArgumentZero(sizeToRead, 0);
FPL__CheckArgumentNull(targetBuffer, 0);
FPL__CheckArgumentZero(maxTargetBufferSize, 0);
if (!FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
FPL__ERROR(FPL__MODULE_FILES, "Filehandle is not opened for reading");
return 0;
}
// @NOTE(final): There is no ReadFile64 function in win32, so we have to read it in chunks
uint64_t actualToRead = (sizeToRead > maxTargetBufferSize) ? maxTargetBufferSize : sizeToRead;
uint64_t result = 0;
HANDLE win32FileHandle = (HANDLE)fileHandle->.win32FileHandle;
uint64_t remainingSize = actualToRead;
uint64_t bufferPos = 0;
const uint64_t MaxDWORD = (uint64_t)(DWORD)-1;
while (remainingSize > 0) {
DWORD bytesRead = 0;
uint8_t *target = (uint8_t *)targetBuffer + bufferPos;
uint64_t size = (remainingSize, MaxDWORD);
(size <= MaxDWORD);
if (ReadFile(win32FileHandle, target, (DWORD)size, &bytesRead, ) == TRUE) {
result += bytesRead;
} else {
break;
}
if (bytesRead == 0) {
break;
}
remainingSize -= bytesRead;
bufferPos += bytesRead;
}
return(result);
}
uint32_t (const *fileHandle, const void *sourceBuffer, const uint32_t sourceSize) {
FPL__CheckArgumentNull(fileHandle, 0);
FPL__CheckArgumentZero(sourceSize, 0);
FPL__CheckArgumentNull(sourceBuffer, 0);
if (!FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
FPL__ERROR(FPL__MODULE_FILES, "Filehandle is not opened for writing");
return 0;
}
HANDLE win32FileHandle = (HANDLE)fileHandle->.win32FileHandle;
uint32_t result = 0;
DWORD bytesWritten = 0;
if (WriteFile(win32FileHandle, sourceBuffer, (DWORD)sourceSize, &bytesWritten, ) == TRUE) {
result = bytesWritten;
}
return(result);
}
uint64_t (const *fileHandle, const void *sourceBuffer, const uint64_t sourceSize) {
FPL__CheckArgumentNull(fileHandle, 0);
FPL__CheckArgumentZero(sourceSize, 0);
FPL__CheckArgumentNull(sourceBuffer, 0);
if (!FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
FPL__ERROR(FPL__MODULE_FILES, "Filehandle is not opened for writing");
return 0;
}
HANDLE win32FileHandle = (HANDLE)fileHandle->.win32FileHandle;
uint64_t result = 0;
uint64_t bufferPos = 0;
uint64_t remainingSize = sourceSize;
const uint64_t MaxDWORD = (uint64_t)(DWORD)-1;
while (remainingSize > 0) {
uint8_t *source = (uint8_t *)sourceBuffer + bufferPos;
uint64_t size = (remainingSize, MaxDWORD);
(size <= MaxDWORD);
DWORD bytesWritten = 0;
if (WriteFile(win32FileHandle, source, (DWORD)size, &bytesWritten, ) == TRUE) {
result += bytesWritten;
} else {
break;
}
if (bytesWritten == 0) {
break;
}
remainingSize -= bytesWritten;
bufferPos += bytesWritten;
}
return(result);
}
uint32_t (const *fileHandle, const int32_t position, const mode) {
FPL__CheckArgumentNull(fileHandle, 0);
uint32_t result = 0;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
DWORD moveMethod = FILE_BEGIN;
if (mode == ) {
moveMethod = FILE_CURRENT;
} else if (mode == ) {
moveMethod = FILE_END;
}
LARGE_INTEGER r = ;
LARGE_INTEGER li;
li.QuadPart = (LONGLONG)position;
if (SetFilePointerEx(win32FileHandle, li, &r, moveMethod) == TRUE) {
if (r.QuadPart > (LONGLONG)UINT32_MAX) {
result = UINT32_MAX;
} else {
result = (uint32_t)r.QuadPart;
}
}
}
return(result);
}
uint64_t (const *fileHandle, const int64_t position, const mode) {
FPL__CheckArgumentNull(fileHandle, 0);
uint64_t result = 0;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
DWORD moveMethod = FILE_BEGIN;
if (mode == ) {
moveMethod = FILE_CURRENT;
} else if (mode == ) {
moveMethod = FILE_END;
}
LARGE_INTEGER r = ;
LARGE_INTEGER li;
li.QuadPart = position;
if (SetFilePointerEx(win32FileHandle, li, &r, moveMethod) == TRUE) {
result = (uint64_t)r.QuadPart;
}
}
return(result);
}
uint32_t (const *fileHandle) {
FPL__CheckArgumentNull(fileHandle, 0);
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
DWORD filePosition = SetFilePointer(win32FileHandle, 0L, , FILE_CURRENT);
if (filePosition != INVALID_SET_FILE_POINTER) {
return filePosition;
}
}
return 0;
}
uint64_t (const *fileHandle) {
FPL__CheckArgumentNull(fileHandle, 0);
uint64_t result = 0;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
LARGE_INTEGER r = ;
LARGE_INTEGER li;
li.QuadPart = 0;
if (SetFilePointerEx(win32FileHandle, li, &r, FILE_CURRENT) == TRUE) {
result = (uint64_t)r.QuadPart;
}
}
return result;
}
bool ( *fileHandle) {
FPL__CheckArgumentNull(fileHandle, false);
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
bool result = FlushFileBuffers(win32FileHandle) == TRUE;
return(result);
}
return(false);
}
void ( *fileHandle) {
if ((fileHandle != ) && FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
CloseHandle(win32FileHandle);
(fileHandle);
}
}
uint32_t (const char *filePath) {
uint32_t result = 0;
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
if (li.QuadPart > (LONGLONG)UINT32_MAX) {
result = UINT32_MAX;
} else {
result = (uint32_t)li.QuadPart;
}
}
CloseHandle(win32FileHandle);
}
}
return(result);
}
uint64_t (const char *filePath) {
uint64_t result = 0;
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
result = (uint64_t)li.QuadPart;
}
CloseHandle(win32FileHandle);
}
}
return(result);
}
uint32_t (const *fileHandle) {
FPL__CheckArgumentNull(fileHandle, 0);
uint32_t result = 0;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
if (li.QuadPart > (LONGLONG)UINT32_MAX) {
result = UINT32_MAX;
} else {
result = (uint32_t)li.QuadPart;
}
}
}
return(result);
}
bool (const char *filePath, uint64_t *outSize) {
FPL__CheckArgumentNull(filePath, false);
FPL__CheckArgumentNull(outSize, false);
bool result = false;
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
if (win32FileHandle != INVALID_HANDLE_VALUE) {
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
*outSize = (uint64_t)li.QuadPart;
result = true;
}
CloseHandle(win32FileHandle);
}
return(result);
}
bool (const *fileHandle, uint64_t *outSize) {
FPL__CheckArgumentNull(fileHandle, false);
FPL__CheckArgumentNull(outSize, false);
bool result = false;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
*outSize = (uint64_t)li.QuadPart;
result = true;
}
}
return(result);
}
uint64_t (const *fileHandle) {
FPL__CheckArgumentNull(fileHandle, 0);
uint64_t result = 0;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
LARGE_INTEGER li = ;
if (GetFileSizeEx(win32FileHandle, &li) == TRUE) {
result = (uint64_t)li.QuadPart;
}
}
return(result);
}
bool (const char *filePath, *outStamps) {
FPL__CheckArgumentNull(outStamps, false);
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
HANDLE win32FileHandle = CreateFileW(filePathWide, GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
bool result = false;
if (win32FileHandle != INVALID_HANDLE_VALUE) {
FILETIME times[3];
if (GetFileTime(win32FileHandle, ×[0], ×[1], ×[2]) == TRUE) {
(outStamps);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[0]);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[1]);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[2]);
result = true;
}
CloseHandle(win32FileHandle);
}
return(result);
}
return(false);
}
bool (const *fileHandle, *outStamps) {
FPL__CheckArgumentNull(fileHandle, 0);
FPL__CheckArgumentNull(outStamps, 0);
if (FPL__WIN32_IS_VALID_FILE_HANDLE(fileHandle->.win32FileHandle)) {
HANDLE win32FileHandle = (void *)fileHandle->.win32FileHandle;
FILETIME times[3];
if (GetFileTime(win32FileHandle, ×[0], ×[1], ×[2]) == TRUE) {
(outStamps);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[0]);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[1]);
outStamps-> = fpl__Win32ConvertFileTimeToUnixTimestamp(×[2]);
return(true);
}
}
return(false);
}
bool (const char *filePath) {
bool result = false;
if (filePath != ) {
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
WIN32_FIND_DATAW findData;
HANDLE searchHandle = FindFirstFileW(filePathWide, &findData);
if (searchHandle != INVALID_HANDLE_VALUE) {
result = !(findData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
FindClose(searchHandle);
}
}
return(result);
}
bool (const char *sourceFilePath, const char *targetFilePath, const bool overwrite) {
FPL__CheckArgumentNull(sourceFilePath, false);
FPL__CheckArgumentNull(targetFilePath, false);
wchar_t sourceFilePathWide[];
wchar_t targetFilePathWide[];
(sourceFilePath, (sourceFilePath), sourceFilePathWide, (sourceFilePathWide));
(targetFilePath, (targetFilePath), targetFilePathWide, (targetFilePathWide));
bool result = (CopyFileW(sourceFilePathWide, targetFilePathWide, !overwrite) == TRUE);
return(result);
}
bool (const char *sourceFilePath, const char *targetFilePath) {
FPL__CheckArgumentNull(sourceFilePath, false);
FPL__CheckArgumentNull(targetFilePath, false);
wchar_t sourceFilePathWide[];
wchar_t targetFilePathWide[];
(sourceFilePath, (sourceFilePath), sourceFilePathWide, (sourceFilePathWide));
(targetFilePath, (targetFilePath), targetFilePathWide, (targetFilePathWide));
bool result = (MoveFileW(sourceFilePathWide, targetFilePathWide) == TRUE);
return(result);
}
bool (const char *filePath) {
FPL__CheckArgumentNull(filePath, false);
wchar_t filePathWide[];
(filePath, (filePath), filePathWide, (filePathWide));
bool result = (DeleteFileW(filePathWide) == TRUE);
return(result);
}
bool (const char *path) {
bool result = false;
if (path != ) {
wchar_t pathWide[];
(path, (path), pathWide, (pathWide));
WIN32_FIND_DATAW findData;
HANDLE searchHandle = FindFirstFileW(pathWide, &findData);
if (searchHandle != INVALID_HANDLE_VALUE) {
result = (findData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY);
FindClose(searchHandle);
}
}
return(result);
}
bool (const char *path) {
FPL__CheckArgumentNull(path, false);
wchar_t pathWide[];
(path, (path), pathWide, (pathWide));
bool result = CreateDirectoryW(pathWide, ) > 0;
return(result);
}
bool (const char *path) {
FPL__CheckArgumentNull(path, false);
wchar_t pathWide[];
(path, (path), pathWide, (pathWide));
bool result = RemoveDirectoryW(pathWide) > 0;
return(result);
}
void fpl__Win32FillFileEntry(const char *rootPath, const WIN32_FIND_DATAW *findData, *entry) {
(findData != );
(entry != );
(findData->cFileName, lstrlenW(findData->cFileName), entry->, (entry->));
entry-> = ;
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) {
entry-> = ;
} else if (
(findData->dwFileAttributes, FILE_ATTRIBUTE_NORMAL) ||
(findData->dwFileAttributes, FILE_ATTRIBUTE_HIDDEN) ||
(findData->dwFileAttributes, FILE_ATTRIBUTE_READONLY) ||
(findData->dwFileAttributes, FILE_ATTRIBUTE_ARCHIVE) ||
(findData->dwFileAttributes, FILE_ATTRIBUTE_SYSTEM)) {
entry-> = ;
}
// @TODO(final/Win32): Win32 Read ACL for full permission detection!
entry-> = ;
entry->. = 0;
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_NORMAL)) {
entry-> = ;
} else {
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_HIDDEN)) {
entry-> |= ;
}
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_ARCHIVE)) {
entry-> |= ;
}
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_SYSTEM)) {
entry-> |= ;
}
entry->. |= ;
entry->. |= ;
entry->. |= ;
if ((findData->dwFileAttributes, FILE_ATTRIBUTE_READONLY) || (findData->dwFileAttributes, FILE_ATTRIBUTE_SYSTEM)) {
entry->. &= ;
}
}
if (entry-> == ) {
ULARGE_INTEGER ul;
ul.LowPart = findData->nFileSizeLow;
ul.HighPart = findData->nFileSizeHigh;
entry-> = (size_t)ul.QuadPart;
} else {
entry-> = 0;
}
entry->. = fpl__Win32ConvertFileTimeToUnixTimestamp(&findData->ftCreationTime);
entry->. = fpl__Win32ConvertFileTimeToUnixTimestamp(&findData->ftLastAccessTime);
entry->. = fpl__Win32ConvertFileTimeToUnixTimestamp(&findData->ftLastWriteTime);
}
bool (const char *path, const char *filter, *entry) {
FPL__CheckArgumentNull(path, false);
FPL__CheckArgumentNull(entry, false);
if ((filter) == 0) {
filter = "*";
}
char pathAndFilter[MAX_PATH + 1] = ;
(path, pathAndFilter, (pathAndFilter));
(pathAndFilter, (pathAndFilter));
(filter, pathAndFilter, (pathAndFilter));
wchar_t pathAndFilterWide[MAX_PATH + 1];
(pathAndFilter, (pathAndFilter), pathAndFilterWide, (pathAndFilterWide));
WIN32_FIND_DATAW findData;
HANDLE searchHandle = FindFirstFileW(pathAndFilterWide, &findData);
bool result = false;
if (searchHandle != INVALID_HANDLE_VALUE) {
(entry);
entry->.win32FileHandle = searchHandle;
(path, entry->., (entry->.));
(filter, entry->., (entry->.));
bool foundFirst = true;
while (foundFirst) {
if (lstrcmpW(findData.cFileName, L".") == 0 || lstrcmpW(findData.cFileName, L"..") == 0) {
foundFirst = FindNextFileW(searchHandle, &findData) == TRUE;
} else {
result = true;
fpl__Win32FillFileEntry(path, &findData, entry);
break;
}
}
}
return(result);
}
bool ( *entry) {
FPL__CheckArgumentNull(entry, false);
bool result = false;
if (FPL__WIN32_IS_VALID_FILE_HANDLE(entry->.win32FileHandle)) {
HANDLE searchHandle = entry->.win32FileHandle;
WIN32_FIND_DATAW findData;
bool foundNext;
do {
foundNext = FindNextFileW(searchHandle, &findData) == TRUE;
if (foundNext) {
if (lstrcmpW(findData.cFileName, L".") == 0 || lstrcmpW(findData.cFileName, L"..") == 0) {
continue;
}
fpl__Win32FillFileEntry(entry->., &findData, entry);
result = true;
break;
}
} while (foundNext);
}
return(result);
}
void ( *entry) {
FPL__CheckArgumentNullNoRet(entry);
if (FPL__WIN32_IS_VALID_FILE_HANDLE(entry->.win32FileHandle)) {
HANDLE searchHandle = entry->.win32FileHandle;
FindClose(searchHandle);
(entry);
}
}
//
// Win32 Path/Directories
//
size_t (char *destPath, const size_t maxDestLen) {
size_t result = 0;
wchar_t modulePath[MAX_PATH];
DWORD written = GetModuleFileNameW(, modulePath, MAX_PATH);
if (written == 0) {
FPL__ERROR(FPL__MODULE_PATHS, "GetModuleFileNameW failed (last error %lu)", GetLastError());
return(result);
}
if (written >= MAX_PATH) {
// Pre-Win10 1607: buffer truncated. We cannot grow without allocating, so report failure.
FPL__ERROR(FPL__MODULE_PATHS, "Executable path exceeds MAX_PATH (%lu); cannot return without truncation", (unsigned long)MAX_PATH);
return(result);
}
modulePath[written] = L'\0';
result = (modulePath, (size_t)written, destPath, maxDestLen);
return(result);
}
size_t (char *destPath, const size_t maxDestLen) {
FPL__CheckPlatform(0);
const fpl__Win32Api *wapi = &fpl__global__AppState->win32.winApi;
size_t result = 0;
wchar_t homePath[MAX_PATH];
HRESULT hr = wapi->shell.SHGetFolderPathW(, CSIDL_PROFILE, , 0, homePath);
if (!SUCCEEDED(hr)) {
FPL__ERROR(FPL__MODULE_PATHS, "SHGetFolderPathW(CSIDL_PROFILE) failed (HRESULT 0x%08lx)", (unsigned long)hr);
return(result);
}
size_t homePathLen = lstrlenW(homePath);
result = (homePath, homePathLen, destPath, maxDestLen);
return(result);
}
size_t (const char *sourcePath, char *destPath, const size_t maxDestLen) {
size_t sourceLen;
if ((sourceLen = (sourcePath)) == 0) {
return 0;
}
wchar_t sourcePathWide[];
size_t wideLen = (sourcePath, sourceLen, sourcePathWide, (sourcePathWide));
if (wideLen == 0) {
return 0;
}
wchar_t targetPath[];
DWORD targetLen = GetFullPathNameW(sourcePathWide, (targetPath), targetPath, NULL);
if (targetLen == 0) {
return 0;
}
size_t result = (targetPath, targetLen, destPath, maxDestLen);
return(result);
}
//
// Win32 Timings
//
(void) {
const fpl__Win32InitState *initState = &fpl__global__InitState.win32;
result = ;
if (initState->qpf.QuadPart > 0) {
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
result.win32.qpc.QuadPart = time.QuadPart;
} else {
result.win32.ticks = GetTickCount64();
}
return(result);
}
(const start, const finish) {
const fpl__Win32InitState *initState = &fpl__global__InitState.win32;
result;
LARGE_INTEGER freq = initState->qpf;
if (freq.QuadPart > 0) {
uint64_t delta = finish.win32.qpc.QuadPart - start.win32.qpc.QuadPart;
result = ()(delta / (double)freq.QuadPart);
} else {
uint64_t delta = finish.win32.ticks - start.win32.ticks;
result = ()(delta / 1000.0);
}
return(result);
}
(void) {
result = ()GetTickCount64();
return(result);
}
(const type) {
const uint64_t EPOCH_DIFFERENCE_FILETIME = 116444736000000000ULL; // difference between 1601 and 1970 in 100-ns intervals
const uint64_t HUNDRED_NANOSECONDS_PER_SECOND = 10000000ULL; // Constants for time conversion
result = ;
// Get current system time in UTC
SYSTEMTIME st = ;
GetSystemTime(&st);
// Convert SYSTEMTIME to FILETIME
FILETIME ft = ;
SystemTimeToFileTime(&st, &ft);
ULARGE_INTEGER ull = ;
ull.LowPart = ft.dwLowDateTime;
ull.HighPart = ft.dwHighDateTime;
// Convert FILETIME (100-ns intervals since 1601) to Unix epoch seconds
uint64_t total100ns = ull.QuadPart;
// Get timezone offset in minutes
TIME_ZONE_INFORMATION tzi = ;
DWORD tzi_status = GetTimeZoneInformation(&tzi);
LONG offsetMinutes = tzi.Bias;
if (tzi_status == TIME_ZONE_ID_DAYLIGHT) {
offsetMinutes += tzi.DaylightBias;
} else if (tzi_status == TIME_ZONE_ID_STANDARD) {
offsetMinutes += tzi.StandardBias;
}
// Subtract the difference between FILETIME epoch and Unix epoch
uint64_t unixTime100ns = total100ns - EPOCH_DIFFERENCE_FILETIME;
if (type == ) {
int64_t sec100Nanos = offsetMinutes * 60ULL * HUNDRED_NANOSECONDS_PER_SECOND;
unixTime100ns -= sec100Nanos;
}
// Calculate seconds and milliseconds
result. = unixTime100ns / HUNDRED_NANOSECONDS_PER_SECOND;
result. = (uint32_t)((unixTime100ns % HUNDRED_NANOSECONDS_PER_SECOND) / 10000);
// Windows Bias is minutes west of UTC, so negate to get offset relative to UTC
if (type == ) {
result. = offsetMinutes;
} else {
result. = 0;
}
return result;
}
(const dateTime, const type) {
const uint64_t EPOCH_DIFFERENCE_FILETIME = 116444736000000000ULL; // difference between 1601 and 1970 in 100-ns intervals
const uint64_t HUNDRED_NANOSECONDS_PER_SECOND = 10000000ULL; // Constants for time conversion
result = ;
// Convert unix epoch + offset (in minutes) + milliseconds to FILETIME
// FILETIME uses 100-nanosecond intervals since 1601
uint64_t total100ns = (dateTime. * HUNDRED_NANOSECONDS_PER_SECOND) +
((uint64_t)dateTime. * 10000);
// Convert back into UTC
if (dateTime. != 0) {
int64_t secs100ns = dateTime. * 60ULL * HUNDRED_NANOSECONDS_PER_SECOND;
total100ns += secs100ns;
}
// Adjust for offset if converting to local time
if (type == ) {
TIME_ZONE_INFORMATION tzi = ;
DWORD tzi_status = GetTimeZoneInformation(&tzi);
LONG offsetMinutes = tzi.Bias;
if (tzi_status == TIME_ZONE_ID_DAYLIGHT) {
offsetMinutes += tzi.DaylightBias;
} else if (tzi_status == TIME_ZONE_ID_STANDARD) {
offsetMinutes += tzi.StandardBias;
}
// offset is in minutes; convert to seconds and add
int64_t offsetInSec = (int64_t)offsetMinutes * 60 * -1;
total100ns += offsetInSec * HUNDRED_NANOSECONDS_PER_SECOND;
}
// Add difference between Unix epoch (1970) and FILETIME epoch (1601)
total100ns += EPOCH_DIFFERENCE_FILETIME;
ULARGE_INTEGER ull = ;
ull.QuadPart = total100ns;
FILETIME ft = ;
ft.dwLowDateTime = ull.LowPart;
ft.dwHighDateTime = ull.HighPart;
SYSTEMTIME st;
BOOL res = FileTimeToSystemTime(&ft, &st);
if (res) {
result. = (uint16_t)st.wYear;
result. = (uint8_t)st.wMonth;
result. = (uint8_t)st.wDay;
result. = (uint8_t)st.wHour;
result. = (uint8_t)st.wMinute;
result. = (uint8_t)st.wSecond;
result. = (uint16_t)st.wMilliseconds;
}
return result;
}
//
// Win32 Strings
//
size_t (const wchar_t *wideSource, const size_t wideSourceLen, char *utf8Dest, const size_t maxUtf8DestLen) {
FPL__CheckArgumentNull(wideSource, 0);
FPL__CheckArgumentZero(wideSourceLen, 0);
if (wideSourceLen > (size_t)INT_MAX) {
FPL__ERROR(FPL__MODULE_STRINGS, "Wide source length %zu exceeds INT_MAX", wideSourceLen);
return(0);
}
int sizeRes = WideCharToMultiByte(CP_UTF8, 0, wideSource, (int)wideSourceLen, , 0, , );
if (sizeRes <= 0) {
FPL__ERROR(FPL__MODULE_STRINGS, "Failed to convert wide-string to UTF-8 (size query)");
return(0);
}
size_t result = (size_t)sizeRes;
if (utf8Dest != ) {
size_t minRequiredLen = result + 1;
FPL__CheckArgumentMin(maxUtf8DestLen, minRequiredLen, 0);
int destClamp = (maxUtf8DestLen > (size_t)INT_MAX) ? INT_MAX : (int)maxUtf8DestLen;
int writeRes = WideCharToMultiByte(CP_UTF8, 0, wideSource, (int)wideSourceLen, utf8Dest, destClamp, , );
if (writeRes <= 0) {
FPL__ERROR(FPL__MODULE_STRINGS, "Failed to convert wide-string to UTF-8 (write)");
return(0);
}
utf8Dest[result] = 0;
}
return(result);
}
size_t (const char *utf8Source, const size_t utf8SourceLen, wchar_t *wideDest, const size_t maxWideDestLen) {
FPL__CheckArgumentNull(utf8Source, 0);
FPL__CheckArgumentZero(utf8SourceLen, 0);
if (utf8SourceLen > (size_t)INT_MAX) {
FPL__ERROR(FPL__MODULE_STRINGS, "UTF-8 source length %zu exceeds INT_MAX", utf8SourceLen);
return(0);
}
int sizeRes = MultiByteToWideChar(CP_UTF8, 0, utf8Source, (int)utf8SourceLen, , 0);
if (sizeRes <= 0) {
FPL__ERROR(FPL__MODULE_STRINGS, "Failed to convert UTF-8 to wide-string (size query)");
return(0);
}
size_t result = (size_t)sizeRes;
if (wideDest != ) {
size_t minRequiredLen = result + 1;
FPL__CheckArgumentMin(maxWideDestLen, minRequiredLen, 0);
int destClamp = (maxWideDestLen > (size_t)INT_MAX) ? INT_MAX : (int)maxWideDestLen;
int writeRes = MultiByteToWideChar(CP_UTF8, 0, utf8Source, (int)utf8SourceLen, wideDest, destClamp);
if (writeRes <= 0) {
FPL__ERROR(FPL__MODULE_STRINGS, "Failed to convert UTF-8 to wide-string (write)");
return(0);
}
wideDest[result] = 0;
}
return(result);
}
//
// Win32 Library
//
bool (const char *libraryFilePath, *outHandle) {
bool result = false;
if (libraryFilePath != && outHandle != ) {
wchar_t libraryFilePathWide[];
(libraryFilePath, (libraryFilePath), libraryFilePathWide, (libraryFilePathWide));
HMODULE libModule = LoadLibraryW(libraryFilePathWide);
if (libModule != ) {
(outHandle);
outHandle->.win32LibraryHandle = libModule;
outHandle-> = true;
result = true;
}
}
return(result);
}
void *(const *handle, const char *name) {
if ((handle != ) && (handle->.win32LibraryHandle != ) && (name != )) {
HMODULE libModule = (HMODULE)handle->.win32LibraryHandle;
return (void *)GetProcAddress(libModule, name);
}
return ;
}
void ( *handle) {
if ((handle != ) && (handle->.win32LibraryHandle != )) {
HMODULE libModule = (HMODULE)handle->.win32LibraryHandle;
FreeLibrary(libModule);
(handle);
}
}
#if defined(FPL__ENABLE_WINDOW)
//
// Win32 Window
//
bool ( *outSize) {
FPL__CheckArgumentNull(outSize, false);
FPL__CheckPlatform(false);
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &appState->winApi;
bool result = false;
RECT windowRect;
if (wapi->user.GetClientRect(windowState->windowHandle, &windowRect)) {
outSize-> = windowRect.right - windowRect.left;
outSize-> = windowRect.bottom - windowRect.top;
result = true;
}
return(result);
}
void (const uint32_t width, const uint32_t height) {
FPL__CheckPlatformNoRet();
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &appState->winApi;
RECT clientRect, windowRect;
if (wapi->user.GetClientRect(windowState->windowHandle, &clientRect) &&
wapi->user.GetWindowRect(windowState->windowHandle, &windowRect)) {
int borderWidth = (windowRect.right - windowRect.left) - (clientRect.right - clientRect.left);
int borderHeight = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
int newWidth = width + borderWidth;
int newHeight = height + borderHeight;
wapi->user.SetWindowPos(windowState->windowHandle, , 0, 0, newWidth, newHeight, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}
}
bool (void) {
FPL__CheckPlatform(false);
const fpl__PlatformAppState *appState = fpl__global__AppState;
bool result = appState->currentSettings.window.isResizable != 0;
return(result);
}
void (const bool value) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32WindowState *windowState = &appState->window.win32;
if (!appState->currentSettings.window.isFullscreen && appState->currentSettings.window.isDecorated) {
DWORD style = fpl__win32_GetWindowLong(windowState->windowHandle, GWL_STYLE);
DWORD exStyle = fpl__win32_GetWindowLong(windowState->windowHandle, GWL_EXSTYLE);
if (value) {
style |= (WS_MAXIMIZEBOX | WS_THICKFRAME);
} else {
style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
}
fpl__win32_SetWindowLong(windowState->windowHandle, GWL_STYLE, style);
appState->currentSettings.window.isResizable = value;
}
}
bool (void) {
FPL__CheckPlatform(false);
const fpl__PlatformAppState *appState = fpl__global__AppState;
bool result = appState->currentSettings.window.isDecorated != 0;
return(result);
}
void (const bool value) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32WindowState *windowState = &appState->window.win32;
const fpl__Win32Api *wapi = &appState->win32.winApi;
if (!appState->currentSettings.window.isFullscreen) {
HWND windowHandle = windowState->windowHandle;
DWORD style = fpl__win32_GetWindowLong(windowHandle, GWL_STYLE);
DWORD exStyle = fpl__win32_GetWindowLong(windowHandle, GWL_EXSTYLE);
if (value) {
style &= ~WS_POPUP;
style |= WS_OVERLAPPEDWINDOW;
if (!appState->currentSettings.window.isResizable) {
style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
}
} else {
style &= ~WS_OVERLAPPEDWINDOW;
style |= WS_POPUP;
}
fpl__win32_SetWindowLong(windowHandle, GWL_STYLE, style);
wapi->user.SetWindowPos(windowHandle, , 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
appState->currentSettings.window.isDecorated = value;
}
}
bool (void) {
FPL__CheckPlatform(false);
const fpl__PlatformAppState *appState = fpl__global__AppState;
bool result = appState->currentSettings.window.isFloating != 0;
return(result);
}
void (const bool value) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32WindowState *windowState = &appState->window.win32;
const fpl__Win32Api *wapi = &appState->win32.winApi;
if (!appState->currentSettings.window.isFullscreen) {
if (value) {
wapi->user.SetWindowPos(windowState->windowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
} else {
wapi->user.SetWindowPos(windowState->windowHandle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
appState->currentSettings.window.isFloating = value;
}
}
bool (void) {
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
bool result = appState->currentSettings.window.isFullscreen != 0;
return(result);
}
bool (const bool value, const uint32_t fullscreenWidth, const uint32_t fullscreenHeight, const uint32_t refreshRate) {
bool result = fpl__Win32SetWindowFullscreen(value, INT32_MAX, INT32_MAX, fullscreenWidth, fullscreenHeight, refreshRate, true);
return(result);
}
bool (const bool value, const int32_t x, const int32_t y, const int32_t width, const int32_t height) {
bool result = fpl__Win32SetWindowFullscreen(value, x, y, width, height, 0, false);
return(result);
}
bool (void) {
bool result = fpl__Win32SetWindowFullscreen(true, INT32_MAX, INT32_MAX, 0, 0, 0, false);
return(result);
}
bool (void) {
bool result = fpl__Win32SetWindowFullscreen(false, 0, 0, 0, 0, 0, false);
return(result);
}
bool ( *outPos) {
FPL__CheckArgumentNull(outPos, false);
FPL__CheckPlatform(false);
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &appState->winApi;
bool result = false;
WINDOWPLACEMENT placement = ;
placement.length = sizeof(WINDOWPLACEMENT);
if (wapi->user.GetWindowPlacement(windowState->windowHandle, &placement) == TRUE) {
switch (placement.showCmd) {
case SW_MAXIMIZE:
{
outPos-> = placement.ptMaxPosition.x;
outPos-> = placement.ptMaxPosition.y;
} break;
case SW_MINIMIZE:
{
outPos-> = placement.ptMinPosition.x;
outPos-> = placement.ptMinPosition.y;
} break;
default:
{
outPos-> = placement.rcNormalPosition.left;
outPos-> = placement.rcNormalPosition.top;
} break;
}
result = true;
}
return(result);
}
void (const char *title) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32AppState *win32AppState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &win32AppState->winApi;
HWND handle = windowState->windowHandle;
(title, appState->currentSettings.window.title, (appState->currentSettings.window.title));
wchar_t titleWide[];
(title, (title), titleWide, (titleWide));
wapi->user.SetWindowTextW(handle, titleWide);
}
void (const int32_t left, const int32_t top) {
FPL__CheckPlatformNoRet();
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &appState->winApi;
WINDOWPLACEMENT placement = ;
placement.length = sizeof(WINDOWPLACEMENT);
RECT windowRect;
if (wapi->user.GetWindowPlacement(windowState->windowHandle, &placement) &&
wapi->user.GetWindowRect(windowState->windowHandle, &windowRect)) {
switch (placement.showCmd) {
case SW_NORMAL:
case SW_SHOW:
{
placement.rcNormalPosition.left = left;
placement.rcNormalPosition.top = top;
placement.rcNormalPosition.right = placement.rcNormalPosition.left + (windowRect.right - windowRect.left);
placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + (windowRect.bottom - windowRect.top);
wapi->user.SetWindowPlacement(windowState->windowHandle, &placement);
} break;
}
}
}
(void) {
FPL__CheckPlatform();
const fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32AppState *win32AppState = &appState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &win32AppState->winApi;
HWND windowHandle = windowState->windowHandle;
result;
if (appState->currentSettings.window.isFullscreen) {
result = ;
} else {
bool isMaximized = !!wapi->user.IsZoomed(windowHandle);
bool isMinimized = !!wapi->user.IsIconic(windowHandle);
if (isMinimized) {
result = ;
} else if (isMaximized) {
result = ;
} else {
result = ;
}
}
return(result);
}
bool (const newState) {
FPL__CheckPlatform(false);
const fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32AppState *win32AppState = &appState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &win32AppState->winApi;
HWND windowHandle = windowState->windowHandle;
bool result = false;
switch (newState) {
case :
{
wapi->user.SendMessageW(windowHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
result = true;
} break;
case :
{
if (!appState->currentSettings.window.isFullscreen && appState->currentSettings.window.isResizable) {
wapi->user.SendMessageW(windowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
result = true;
}
} break;
case :
{
wapi->user.SendMessageW(windowHandle, WM_SYSCOMMAND, SC_RESTORE, 0);
result = true;
} break;
case :
{
if (!appState->currentSettings.window.isFullscreen)
result = fpl__Win32SetWindowFullscreen(true, INT32_MAX, INT32_MAX, 0, 0, 0, false);
else
result = true;
} break;
case :
default:
break;
}
return(result);
}
void (const bool value) {
FPL__CheckPlatformNoRet();
fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
windowState->isCursorActive = value;
}
bool fpl__Win32ProcessNextEvent(const fpl__Win32Api *wapi, fpl__PlatformAppState *appState, fpl__Win32WindowState *windowState) {
bool result = false;
if (windowState->windowHandle != 0) {
MSG msg;
if (wapi->user.PeekMessageW(&msg, windowState->windowHandle, 0, 0, PM_REMOVE) == TRUE) {
fpl__Win32HandleMessage(wapi, appState, windowState, &msg);
result = true;
}
}
return(result);
}
bool ( *ev) {
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__Win32AppState *win32AppState = &appState->win32;
fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32InitState *win32InitState = &fpl__global__InitState.win32;
const fpl__Win32Api *wapi = &win32AppState->winApi;
// Poll next event from the internal queue first
if (fpl__PollInternalEvent(ev)) {
return(true);
}
// Create new event from the OS message queue
if (!fpl__Win32ProcessNextEvent(wapi, appState, windowState)) {
// Queue is empty, we have no events left
if (!fpl__HasInternalEvents()) {
return(false);
}
}
// Poll the first event from the internal queue
if (fpl__PollInternalEvent(ev)) {
return(true);
}
// No events left
return(false);
}
void (void) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__Win32AppState *win32AppState = &appState->win32;
fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32InitState *win32InitState = &fpl__global__InitState.win32;
const fpl__Win32Api *wapi = &win32AppState->winApi;
if (windowState->windowHandle != 0) {
if (windowState->mainFiber != && windowState->messageFiber != ) {
SwitchToFiber(windowState->messageFiber);
} else {
MSG msg;
while (wapi->user.PeekMessageW(&msg, windowState->windowHandle, 0, 0, PM_REMOVE)) {
fpl__Win32HandleMessage(wapi, appState, windowState, &msg);
}
}
}
fpl__ClearInternalEvents();
}
bool (void) {
FPL__CheckPlatform(false);
fpl__PlatformAppState *appState = fpl__global__AppState;
fpl__ClearInternalEvents();
# if defined(FPL__ENABLE_INPUT)
if (!appState->currentSettings.input.disabledEvents) {
fpl__InputSystem_Update(&appState->input);
}
# endif
bool result = appState->window.isRunning != 0;
return(result);
}
bool (void) {
FPL__CheckPlatform(false);
bool result = fpl__global__AppState->window.isRunning != 0;
return(result);
}
void (void) {
FPL__CheckPlatformNoRet();
fpl__PlatformAppState *appState = fpl__global__AppState;
const fpl__Win32AppState *win32AppState = &appState->win32;
if (appState->window.isRunning) {
appState->window.isRunning = false;
const fpl__Win32Api *wapi = &win32AppState->winApi;
wapi->user.PostQuitMessage(0);
}
}
bool (char *dest, const uint32_t maxDestLen) {
FPL__CheckPlatform(false);
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__Win32Api *wapi = &appState->winApi;
bool result = false;
if (wapi->user.OpenClipboard(windowState->windowHandle)) {
if (wapi->user.IsClipboardFormatAvailable(CF_UNICODETEXT)) {
HGLOBAL dataHandle = wapi->user.GetClipboardData(CF_UNICODETEXT);
if (dataHandle != ) {
const wchar_t *stringValue = (const wchar_t *)GlobalLock(dataHandle);
(stringValue, lstrlenW(stringValue), dest, maxDestLen);
GlobalUnlock(dataHandle);
result = true;
}
}
wapi->user.CloseClipboard();
}
return(result);
}
bool (const char *text) {
FPL__CheckPlatform(false);
const fpl__Win32AppState *appState = &fpl__global__AppState->win32;
const fpl__Win32WindowState *windowState = &fpl__global__AppState->window.win32;
const fpl__- Assertion & Debug
- Atomic operations
- Audio functions
- Clipboard functions
- Console functions
- Constants
- Display/Monitor functions
- Dynamic library loading
- Error Handling
- Files/IO functions
- Function macros
- Hardware Infos
- Input types and functions
- Localization functions
- Logging
- Memory Macros
- Memory functions
- Operating system Infos
- Path functions
- Platform functions
- Session Infos
- Settings & Configurations
- Storage class identifiers
- String functions
- Threading and synchronizations routines
- Timing functions
- Video functions
- Window events
- Window functions
- fplARMCPUCapabilities
- fplAudioChannelMap
- fplAudioDeviceID
- fplAudioDeviceInfo
- fplAudioFormat
- fplAudioSettings
- fplColor32
- fplConditionVariable
- fplConsoleSettings
- fplCPUCapabilities
- fplCPUIDLeaf
- fplDateTime
- fplDateTimeCreationResult
- fplDateTimeResult
- fplDisplayInfo
- fplDisplayMode
- fplDynamicLibraryHandle
- fplEndianess
- fplEvent
- fplFileEntry
- fplFileHandle
- fplFilePermissions
- fplFileTimeStamps
- fplGamepadButton
- fplGamepadData
- fplGamepadEvent
- fplGamepadInfo
- fplGamepadInputBinding
- fplGamepadMapping
- fplGamepadSettings
- fplGamepadState
- fplGamepadStates
- fplGraphicsApiSettings
- fplImageSource
- fplInputBackendMask
- fplInputBackendSupport
- fplInputDevice
- fplInputDeviceGuid
- fplInputSettings
- fplInternalConditionVariable
- fplInternalDynamicLibraryHandle
- fplInternalFileEntryHandle
- fplInternalFileHandle
- fplInternalFileRootInfo
- fplInternalMutexHandle
- fplInternalSemaphoreHandle
- fplInternalSignalHandle
- fplInternalThreadHandle
- fplKeyboardEvent
- fplKeyboardState
- fplLogSettings
- fplLogWriter
- fplLogWriterConsole
- fplLogWriterCustom
- fplMemoryAllocationSettings
- fplMemoryBlock
- fplMemoryInfos
- fplMemorySettings
- fplMouseEvent
- fplMouseState
- fplMutexHandle
- fplOpenGLSettings
- fplOSVersionInfos
- fplSemaphoreHandle
- fplSettings
- fplSignalHandle
- fplSpecificAudioSettings
- fplThreadHandle
- fplThreadParameters
- fplTimestamp
- fplVersionInfo
- fplVideoBackBuffer
- fplVideoRect
- fplVideoRequirements
- fplVideoRequirementsVulkan
- fplVideoSettings
- fplVideoSurface
- fplVideoSurfaceOpenGL
- fplVideoSurfaceVulkan
- fplVideoWindow
- fplVulkanSettings
- fplWindowCallbacks
- fplWindowDropFiles
- fplWindowEvent
- fplWindowPosition
- fplWindowSettings
- fplWindowSize
- fplX86CPUCapabilities