We need the CMake stuff for wayland configuration.
Otherwise, we would have to replicate that ourselves.
This is the full 7ef34eb06d
tree except
for tests/ examples/ and docs/
pull/538/head
@ -0,0 +1,23 @@ | |||
branches: | |||
only: | |||
- ci | |||
- master | |||
skip_tags: true | |||
environment: | |||
CFLAGS: /WX | |||
matrix: | |||
- BUILD_SHARED_LIBS: ON | |||
- BUILD_SHARED_LIBS: OFF | |||
matrix: | |||
fast_finish: true | |||
build_script: | |||
- mkdir build | |||
- cd build | |||
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% .. | |||
- cmake --build . | |||
notifications: | |||
- provider: Email | |||
to: | |||
- ci@glfw.org | |||
on_build_failure: true | |||
on_build_success: false |
@ -0,0 +1 @@ | |||
*.m linguist-language=Objective-C |
@ -0,0 +1,84 @@ | |||
# External junk | |||
.DS_Store | |||
_ReSharper* | |||
*.opensdf | |||
*.sdf | |||
*.suo | |||
*.dir | |||
*.vcxproj* | |||
*.sln | |||
Win32 | |||
x64 | |||
Debug | |||
Release | |||
MinSizeRel | |||
RelWithDebInfo | |||
*.xcodeproj | |||
# CMake files | |||
Makefile | |||
CMakeCache.txt | |||
CMakeFiles | |||
CMakeScripts | |||
cmake_install.cmake | |||
cmake_uninstall.cmake | |||
# Generated files | |||
docs/Doxyfile | |||
docs/html | |||
docs/warnings.txt | |||
docs/doxygen_sqlite3.db | |||
src/glfw_config.h | |||
src/glfw3.pc | |||
src/glfw3Config.cmake | |||
src/glfw3ConfigVersion.cmake | |||
src/wayland-pointer-constraints-unstable-v1-client-protocol.h | |||
src/wayland-pointer-constraints-unstable-v1-protocol.c | |||
src/wayland-relative-pointer-unstable-v1-client-protocol.h | |||
src/wayland-relative-pointer-unstable-v1-protocol.c | |||
# Compiled binaries | |||
src/libglfw.so | |||
src/libglfw.so.3 | |||
src/libglfw.so.3.3 | |||
src/libglfw.dylib | |||
src/libglfw.dylib | |||
src/libglfw.3.dylib | |||
src/libglfw.3.3.dylib | |||
src/libglfw3.a | |||
src/glfw3.lib | |||
src/glfw3.dll | |||
src/glfw3dll.lib | |||
src/libglfw3dll.a | |||
examples/*.app | |||
examples/*.exe | |||
examples/boing | |||
examples/gears | |||
examples/heightmap | |||
examples/offscreen | |||
examples/particles | |||
examples/splitview | |||
examples/sharing | |||
examples/simple | |||
examples/wave | |||
tests/*.app | |||
tests/*.exe | |||
tests/clipboard | |||
tests/cursor | |||
tests/empty | |||
tests/events | |||
tests/gamma | |||
tests/glfwinfo | |||
tests/icon | |||
tests/iconify | |||
tests/joysticks | |||
tests/monitors | |||
tests/msaa | |||
tests/reopen | |||
tests/tearing | |||
tests/threads | |||
tests/timeout | |||
tests/title | |||
tests/vulkan | |||
tests/windows | |||
@ -0,0 +1,78 @@ | |||
language: c | |||
compiler: clang | |||
branches: | |||
only: | |||
- ci | |||
- master | |||
sudo: false | |||
dist: trusty | |||
addons: | |||
apt: | |||
packages: | |||
- cmake | |||
- libxrandr-dev | |||
- libxinerama-dev | |||
- libxcursor-dev | |||
- libxi-dev | |||
matrix: | |||
include: | |||
- os: linux | |||
env: | |||
- BUILD_SHARED_LIBS=ON | |||
- CFLAGS=-Werror | |||
- os: linux | |||
env: | |||
- BUILD_SHARED_LIBS=OFF | |||
- CFLAGS=-Werror | |||
- os: linux | |||
sudo: required | |||
addons: | |||
apt: | |||
packages: | |||
- libwayland-dev | |||
- libxkbcommon-dev | |||
- libegl1-mesa-dev | |||
env: | |||
- USE_WAYLAND=ON | |||
- BUILD_SHARED_LIBS=ON | |||
- CFLAGS=-Werror | |||
- os: linux | |||
sudo: required | |||
addons: | |||
apt: | |||
packages: | |||
- libwayland-dev | |||
- libxkbcommon-dev | |||
- libegl1-mesa-dev | |||
env: | |||
- USE_WAYLAND=ON | |||
- BUILD_SHARED_LIBS=OFF | |||
- CFLAGS=-Werror | |||
- os: osx | |||
env: | |||
- BUILD_SHARED_LIBS=ON | |||
- CFLAGS=-Werror | |||
- os: osx | |||
env: | |||
- BUILD_SHARED_LIBS=OFF | |||
- CFLAGS=-Werror | |||
script: | |||
- if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi | |||
- mkdir build | |||
- cd build | |||
- if test -n "${USE_WAYLAND}"; | |||
then wget https://mirrors.kernel.org/ubuntu/pool/universe/e/extra-cmake-modules/extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; | |||
sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; | |||
git clone git://anongit.freedesktop.org/wayland/wayland-protocols; | |||
pushd wayland-protocols; | |||
git checkout 1.12 && ./autogen.sh --prefix=/usr && make && sudo make install; | |||
popd; | |||
fi | |||
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. | |||
- cmake --build . | |||
notifications: | |||
email: | |||
recipients: | |||
- ci@glfw.org | |||
on_success: never | |||
on_failure: always |
@ -0,0 +1,33 @@ | |||
# Usage: | |||
# cmake -P GenerateMappings.cmake <path/to/mappings.h.in> <path/to/mappings.h> | |||
set(source_url "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt") | |||
set(source_path "${CMAKE_CURRENT_BINARY_DIR}/gamecontrollerdb.txt") | |||
set(template_path "${CMAKE_ARGV3}") | |||
set(target_path "${CMAKE_ARGV4}") | |||
if (NOT EXISTS "${template_path}") | |||
message(FATAL_ERROR "Failed to find template file ${template_path}") | |||
endif() | |||
file(DOWNLOAD "${source_url}" "${source_path}" | |||
STATUS download_status | |||
TLS_VERIFY on) | |||
list(GET download_status 0 status_code) | |||
list(GET download_status 1 status_message) | |||
if (status_code) | |||
message(FATAL_ERROR "Failed to download ${source_url}: ${status_message}") | |||
endif() | |||
file(STRINGS "${source_path}" lines) | |||
foreach(line ${lines}) | |||
if ("${line}" MATCHES "^[0-9a-fA-F].*$") | |||
set(GLFW_GAMEPAD_MAPPINGS "${GLFW_GAMEPAD_MAPPINGS}\"${line}\",\n") | |||
endif() | |||
endforeach() | |||
configure_file("${template_path}" "${target_path}" @ONLY NEWLINE_STYLE UNIX) | |||
file(REMOVE "${source_path}") | |||
@ -0,0 +1,38 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
<plist version="1.0"> | |||
<dict> | |||
<key>CFBundleDevelopmentRegion</key> | |||
<string>English</string> | |||
<key>CFBundleExecutable</key> | |||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string> | |||
<key>CFBundleGetInfoString</key> | |||
<string>${MACOSX_BUNDLE_INFO_STRING}</string> | |||
<key>CFBundleIconFile</key> | |||
<string>${MACOSX_BUNDLE_ICON_FILE}</string> | |||
<key>CFBundleIdentifier</key> | |||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string> | |||
<key>CFBundleInfoDictionaryVersion</key> | |||
<string>6.0</string> | |||
<key>CFBundleLongVersionString</key> | |||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string> | |||
<key>CFBundleName</key> | |||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string> | |||
<key>CFBundlePackageType</key> | |||
<string>APPL</string> | |||
<key>CFBundleShortVersionString</key> | |||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> | |||
<key>CFBundleSignature</key> | |||
<string>????</string> | |||
<key>CFBundleVersion</key> | |||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string> | |||
<key>CSResourcesFileMapped</key> | |||
<true/> | |||
<key>LSRequiresCarbon</key> | |||
<true/> | |||
<key>NSHumanReadableCopyright</key> | |||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string> | |||
<key>NSHighResolutionCapable</key> | |||
<true/> | |||
</dict> | |||
</plist> |
@ -0,0 +1,13 @@ | |||
# Define the environment for cross compiling from Linux to Win64 | |||
SET(CMAKE_SYSTEM_NAME Windows) | |||
SET(CMAKE_SYSTEM_VERSION 1) | |||
SET(CMAKE_C_COMPILER "amd64-mingw32msvc-gcc") | |||
SET(CMAKE_CXX_COMPILER "amd64-mingw32msvc-g++") | |||
SET(CMAKE_RC_COMPILER "amd64-mingw32msvc-windres") | |||
SET(CMAKE_RANLIB "amd64-mingw32msvc-ranlib") | |||
# Configure the behaviour of the find commands | |||
SET(CMAKE_FIND_ROOT_PATH "/usr/amd64-mingw32msvc") | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
@ -0,0 +1,13 @@ | |||
# Define the environment for cross compiling from Linux to Win32 | |||
SET(CMAKE_SYSTEM_NAME Windows) | |||
SET(CMAKE_SYSTEM_VERSION 1) | |||
SET(CMAKE_C_COMPILER "i586-mingw32msvc-gcc") | |||
SET(CMAKE_CXX_COMPILER "i586-mingw32msvc-g++") | |||
SET(CMAKE_RC_COMPILER "i586-mingw32msvc-windres") | |||
SET(CMAKE_RANLIB "i586-mingw32msvc-ranlib") | |||
# Configure the behaviour of the find commands | |||
SET(CMAKE_FIND_ROOT_PATH "/usr/i586-mingw32msvc") | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
@ -0,0 +1,13 @@ | |||
# Define the environment for cross compiling from Linux to Win32 | |||
SET(CMAKE_SYSTEM_NAME Windows) # Target system name | |||
SET(CMAKE_SYSTEM_VERSION 1) | |||
SET(CMAKE_C_COMPILER "i686-pc-mingw32-gcc") | |||
SET(CMAKE_CXX_COMPILER "i686-pc-mingw32-g++") | |||
SET(CMAKE_RC_COMPILER "i686-pc-mingw32-windres") | |||
SET(CMAKE_RANLIB "i686-pc-mingw32-ranlib") | |||
#Configure the behaviour of the find commands | |||
SET(CMAKE_FIND_ROOT_PATH "/opt/mingw/usr/i686-pc-mingw32") | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
@ -0,0 +1,13 @@ | |||
# Define the environment for cross compiling from Linux to Win32 | |||
SET(CMAKE_SYSTEM_NAME Windows) # Target system name | |||
SET(CMAKE_SYSTEM_VERSION 1) | |||
SET(CMAKE_C_COMPILER "i686-w64-mingw32-gcc") | |||
SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++") | |||
SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres") | |||
SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib") | |||
# Configure the behaviour of the find commands | |||
SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32") | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
@ -0,0 +1,17 @@ | |||
# Find EpollShim | |||
# Once done, this will define | |||
# | |||
# EPOLLSHIM_FOUND - System has EpollShim | |||
# EPOLLSHIM_INCLUDE_DIRS - The EpollShim include directories | |||
# EPOLLSHIM_LIBRARIES - The libraries needed to use EpollShim | |||
find_path(EPOLLSHIM_INCLUDE_DIRS NAMES sys/epoll.h sys/timerfd.h HINTS /usr/local/include/libepoll-shim) | |||
find_library(EPOLLSHIM_LIBRARIES NAMES epoll-shim libepoll-shim HINTS /usr/local/lib) | |||
if (EPOLLSHIM_INCLUDE_DIRS AND EPOLLSHIM_LIBRARIES) | |||
set(EPOLLSHIM_FOUND TRUE) | |||
endif (EPOLLSHIM_INCLUDE_DIRS AND EPOLLSHIM_LIBRARIES) | |||
include(FindPackageHandleStandardArgs) | |||
find_package_handle_standard_args(EPOLLSHIM DEFAULT_MSG EPOLLSHIM_LIBRARIES EPOLLSHIM_INCLUDE_DIRS) | |||
mark_as_advanced(EPOLLSHIM_INCLUDE_DIRS EPOLLSHIM_LIBRARIES) |
@ -0,0 +1,34 @@ | |||
# FindMir | |||
# ------- | |||
# Finds the Mir library | |||
# | |||
# This will will define the following variables:: | |||
# | |||
# MIR_FOUND - the system has Mir | |||
# MIR_INCLUDE_DIRS - the Mir include directory | |||
# MIR_LIBRARIES - the Mir libraries | |||
# MIR_DEFINITIONS - the Mir definitions | |||
find_package (PkgConfig) | |||
if(PKG_CONFIG_FOUND) | |||
pkg_check_modules (PC_MIR mirclient>=0.26.2 QUIET) | |||
find_path(MIR_INCLUDE_DIR NAMES mir_toolkit/mir_client_library.h | |||
PATHS ${PC_MIR_INCLUDE_DIRS}) | |||
find_library(MIR_LIBRARY NAMES mirclient | |||
PATHS ${PC_MIR_LIBRARIES} ${PC_MIR_LIBRARY_DIRS}) | |||
include (FindPackageHandleStandardArgs) | |||
find_package_handle_standard_args (MIR | |||
REQUIRED_VARS MIR_LIBRARY MIR_INCLUDE_DIR) | |||
if (MIR_FOUND) | |||
set(MIR_LIBRARIES ${MIR_LIBRARY}) | |||
set(MIR_INCLUDE_DIRS ${PC_MIR_INCLUDE_DIRS}) | |||
set(MIR_DEFINITIONS -DHAVE_MIR=1) | |||
endif() | |||
mark_as_advanced (MIR_LIBRARY MIR_INCLUDE_DIR) | |||
endif() |
@ -0,0 +1,18 @@ | |||
# Try to find OSMesa on a Unix system | |||
# | |||
# This will define: | |||
# | |||
# OSMESA_LIBRARIES - Link these to use OSMesa | |||
# OSMESA_INCLUDE_DIR - Include directory for OSMesa | |||
# | |||
# Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com> | |||
if (NOT WIN32) | |||
find_package (PkgConfig) | |||
pkg_check_modules (PKG_OSMESA QUIET osmesa) | |||
set (OSMESA_INCLUDE_DIR ${PKG_OSMESA_INCLUDE_DIRS}) | |||
set (OSMESA_LIBRARIES ${PKG_OSMESA_LIBRARIES}) | |||
endif () |
@ -0,0 +1,46 @@ | |||
# Find Vulkan | |||
# | |||
# VULKAN_INCLUDE_DIR | |||
# VULKAN_LIBRARY | |||
# VULKAN_FOUND | |||
if (WIN32) | |||
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS | |||
"$ENV{VULKAN_SDK}/Include" | |||
"$ENV{VK_SDK_PATH}/Include") | |||
if (CMAKE_SIZEOF_VOID_P EQUAL 8) | |||
find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS | |||
"$ENV{VULKAN_SDK}/Lib" | |||
"$ENV{VULKAN_SDK}/Bin" | |||
"$ENV{VK_SDK_PATH}/Bin") | |||
find_library(VULKAN_STATIC_LIBRARY NAMES vkstatic.1 HINTS | |||
"$ENV{VULKAN_SDK}/Lib" | |||
"$ENV{VULKAN_SDK}/Bin" | |||
"$ENV{VK_SDK_PATH}/Bin") | |||
else() | |||
find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS | |||
"$ENV{VULKAN_SDK}/Lib32" | |||
"$ENV{VULKAN_SDK}/Bin32" | |||
"$ENV{VK_SDK_PATH}/Bin32") | |||
find_library(VULKAN_STATIC_LIBRARY NAMES vkstatic.1 HINTS | |||
"$ENV{VULKAN_SDK}/Lib32" | |||
"$ENV{VULKAN_SDK}/Bin32" | |||
"$ENV{VK_SDK_PATH}/Bin32") | |||
endif() | |||
elseif (APPLE) | |||
find_library(VULKAN_LIBRARY vulkan.1 HINTS | |||
"$ENV{VULKAN_SDK}/macOS/lib") | |||
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS | |||
"$ENV{VULKAN_SDK}/macOS/include") | |||
else() | |||
find_path(VULKAN_INCLUDE_DIR NAMES vulkan/vulkan.h HINTS | |||
"$ENV{VULKAN_SDK}/include") | |||
find_library(VULKAN_LIBRARY NAMES vulkan HINTS | |||
"$ENV{VULKAN_SDK}/lib") | |||
endif() | |||
include(FindPackageHandleStandardArgs) | |||
find_package_handle_standard_args(Vulkan DEFAULT_MSG VULKAN_LIBRARY VULKAN_INCLUDE_DIR) | |||
mark_as_advanced(VULKAN_INCLUDE_DIR VULKAN_LIBRARY VULKAN_STATIC_LIBRARY) | |||
@ -0,0 +1,26 @@ | |||
find_package(PkgConfig) | |||
pkg_check_modules(WaylandProtocols QUIET wayland-protocols>=${WaylandProtocols_FIND_VERSION}) | |||
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir wayland-protocols | |||
OUTPUT_VARIABLE WaylandProtocols_PKGDATADIR | |||
RESULT_VARIABLE _pkgconfig_failed) | |||
if (_pkgconfig_failed) | |||
message(FATAL_ERROR "Missing wayland-protocols pkgdatadir") | |||
endif() | |||
string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}") | |||
find_package_handle_standard_args(WaylandProtocols | |||
FOUND_VAR | |||
WaylandProtocols_FOUND | |||
REQUIRED_VARS | |||
WaylandProtocols_PKGDATADIR | |||
VERSION_VAR | |||
WaylandProtocols_VERSION | |||
HANDLE_COMPONENTS | |||
) | |||
set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND}) | |||
set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR}) | |||
set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION}) |
@ -0,0 +1,34 @@ | |||
# - Try to find XKBCommon | |||
# Once done, this will define | |||
# | |||
# XKBCOMMON_FOUND - System has XKBCommon | |||
# XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories | |||
# XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon | |||
# XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon | |||
find_package(PkgConfig) | |||
pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon) | |||
set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER}) | |||
find_path(XKBCOMMON_INCLUDE_DIR | |||
NAMES xkbcommon/xkbcommon.h | |||
HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS} | |||
) | |||
find_library(XKBCOMMON_LIBRARY | |||
NAMES xkbcommon | |||
HINTS ${PC_XKBCOMMON_LIBRARY} ${PC_XKBCOMMON_LIBRARY_DIRS} | |||
) | |||
set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARY}) | |||
set(XKBCOMMON_LIBRARY_DIRS ${XKBCOMMON_LIBRARY_DIRS}) | |||
set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIR}) | |||
include(FindPackageHandleStandardArgs) | |||
find_package_handle_standard_args(XKBCommon DEFAULT_MSG | |||
XKBCOMMON_LIBRARY | |||
XKBCOMMON_INCLUDE_DIR | |||
) | |||
mark_as_advanced(XKBCOMMON_LIBRARY XKBCOMMON_INCLUDE_DIR) | |||
@ -0,0 +1,13 @@ | |||
# Define the environment for cross compiling from Linux to Win32 | |||
SET(CMAKE_SYSTEM_NAME Windows) # Target system name | |||
SET(CMAKE_SYSTEM_VERSION 1) | |||
SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc") | |||
SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++") | |||
SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres") | |||
SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib") | |||
# Configure the behaviour of the find commands | |||
SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32") | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) | |||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
@ -0,0 +1,402 @@ | |||
cmake_minimum_required(VERSION 3.0) | |||
project(GLFW C) | |||
set(CMAKE_LEGACY_CYGWIN_WIN32 OFF) | |||
if (NOT CMAKE_VERSION VERSION_LESS "3.1") | |||
cmake_policy(SET CMP0054 NEW) | |||
endif() | |||
set(GLFW_VERSION_MAJOR "3") | |||
set(GLFW_VERSION_MINOR "3") | |||
set(GLFW_VERSION_PATCH "0") | |||
set(GLFW_VERSION_EXTRA "") | |||
set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") | |||
set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") | |||
set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64") | |||
set_property(GLOBAL PROPERTY USE_FOLDERS ON) | |||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF) | |||
option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ON) | |||
option(GLFW_BUILD_TESTS "Build the GLFW test programs" ON) | |||
option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON) | |||
option(GLFW_INSTALL "Generate installation target" ON) | |||
option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF) | |||
if (UNIX) | |||
option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF) | |||
endif() | |||
if (WIN32) | |||
option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF) | |||
endif() | |||
if (UNIX AND NOT APPLE) | |||
option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF) | |||
option(GLFW_USE_MIR "Use Mir for window creation" OFF) | |||
endif() | |||
if (MSVC) | |||
option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON) | |||
endif() | |||
if (BUILD_SHARED_LIBS) | |||
set(_GLFW_BUILD_DLL 1) | |||
endif() | |||
if (BUILD_SHARED_LIBS AND UNIX) | |||
# On Unix-like systems, shared libraries can use the soname system. | |||
set(GLFW_LIB_NAME glfw) | |||
else() | |||
set(GLFW_LIB_NAME glfw3) | |||
endif() | |||
if (GLFW_VULKAN_STATIC) | |||
set(_GLFW_VULKAN_STATIC 1) | |||
endif() | |||
list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") | |||
find_package(Threads REQUIRED) | |||
find_package(Vulkan) | |||
if (GLFW_BUILD_DOCS) | |||
set(DOXYGEN_SKIP_DOT TRUE) | |||
find_package(Doxygen) | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Set compiler specific flags | |||
#-------------------------------------------------------------------- | |||
if (MSVC) | |||
if (MSVC90) | |||
# Workaround for VS 2008 not shipping with the DirectX 9 SDK | |||
include(CheckIncludeFile) | |||
check_include_file(dinput.h DINPUT_H_FOUND) | |||
if (NOT DINPUT_H_FOUND) | |||
message(FATAL_ERROR "DirectX 9 SDK not found") | |||
endif() | |||
# Workaround for VS 2008 not shipping with stdint.h | |||
list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/vs2008") | |||
endif() | |||
if (NOT USE_MSVC_RUNTIME_LIBRARY_DLL) | |||
foreach (flag CMAKE_C_FLAGS | |||
CMAKE_C_FLAGS_DEBUG | |||
CMAKE_C_FLAGS_RELEASE | |||
CMAKE_C_FLAGS_MINSIZEREL | |||
CMAKE_C_FLAGS_RELWITHDEBINFO) | |||
if (${flag} MATCHES "/MD") | |||
string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") | |||
endif() | |||
if (${flag} MATCHES "/MDd") | |||
string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") | |||
endif() | |||
endforeach() | |||
endif() | |||
endif() | |||
if (MINGW) | |||
# Workaround for legacy MinGW not providing XInput and DirectInput | |||
include(CheckIncludeFile) | |||
check_include_file(dinput.h DINPUT_H_FOUND) | |||
check_include_file(xinput.h XINPUT_H_FOUND) | |||
if (NOT DINPUT_H_FOUND OR NOT XINPUT_H_FOUND) | |||
list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/mingw") | |||
endif() | |||
# Enable link-time exploit mitigation features enabled by default on MSVC | |||
include(CheckCCompilerFlag) | |||
# Compatibility with data execution prevention (DEP) | |||
set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat") | |||
check_c_compiler_flag("" _GLFW_HAS_DEP) | |||
if (_GLFW_HAS_DEP) | |||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--nxcompat ${CMAKE_SHARED_LINKER_FLAGS}") | |||
endif() | |||
# Compatibility with address space layout randomization (ASLR) | |||
set(CMAKE_REQUIRED_FLAGS "-Wl,--dynamicbase") | |||
check_c_compiler_flag("" _GLFW_HAS_ASLR) | |||
if (_GLFW_HAS_ASLR) | |||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--dynamicbase ${CMAKE_SHARED_LINKER_FLAGS}") | |||
endif() | |||
# Compatibility with 64-bit address space layout randomization (ASLR) | |||
set(CMAKE_REQUIRED_FLAGS "-Wl,--high-entropy-va") | |||
check_c_compiler_flag("" _GLFW_HAS_64ASLR) | |||
if (_GLFW_HAS_64ASLR) | |||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--high-entropy-va ${CMAKE_SHARED_LINKER_FLAGS}") | |||
endif() | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Detect and select backend APIs | |||
#-------------------------------------------------------------------- | |||
if (GLFW_USE_WAYLAND) | |||
set(_GLFW_WAYLAND 1) | |||
message(STATUS "Using Wayland for window creation") | |||
elseif (GLFW_USE_MIR) | |||
set(_GLFW_MIR 1) | |||
message(STATUS "Using Mir for window creation") | |||
elseif (GLFW_USE_OSMESA) | |||
set(_GLFW_OSMESA 1) | |||
message(STATUS "Using OSMesa for headless context creation") | |||
elseif (WIN32) | |||
set(_GLFW_WIN32 1) | |||
message(STATUS "Using Win32 for window creation") | |||
elseif (APPLE) | |||
set(_GLFW_COCOA 1) | |||
message(STATUS "Using Cocoa for window creation") | |||
elseif (UNIX) | |||
set(_GLFW_X11 1) | |||
message(STATUS "Using X11 for window creation") | |||
else() | |||
message(FATAL_ERROR "No supported platform was detected") | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Add Vulkan static library if requested | |||
#-------------------------------------------------------------------- | |||
if (GLFW_VULKAN_STATIC) | |||
if (VULKAN_FOUND AND VULKAN_STATIC_LIBRARY) | |||
list(APPEND glfw_LIBRARIES "${VULKAN_STATIC_LIBRARY}") | |||
if (BUILD_SHARED_LIBS) | |||
message(WARNING "Linking Vulkan loader static library into GLFW") | |||
endif() | |||
else() | |||
if (BUILD_SHARED_LIBS OR GLFW_BUILD_EXAMPLES OR GLFW_BUILD_TESTS) | |||
message(FATAL_ERROR "Vulkan loader static library not found") | |||
else() | |||
message(WARNING "Vulkan loader static library not found") | |||
endif() | |||
endif() | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Find and add Unix math and time libraries | |||
#-------------------------------------------------------------------- | |||
if (UNIX AND NOT APPLE) | |||
find_library(RT_LIBRARY rt) | |||
mark_as_advanced(RT_LIBRARY) | |||
if (RT_LIBRARY) | |||
list(APPEND glfw_LIBRARIES "${RT_LIBRARY}") | |||
list(APPEND glfw_PKG_LIBS "-lrt") | |||
endif() | |||
find_library(MATH_LIBRARY m) | |||
mark_as_advanced(MATH_LIBRARY) | |||
if (MATH_LIBRARY) | |||
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}") | |||
list(APPEND glfw_PKG_LIBS "-lm") | |||
endif() | |||
if (CMAKE_DL_LIBS) | |||
list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}") | |||
list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}") | |||
endif() | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use Win32 for window creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_WIN32) | |||
list(APPEND glfw_PKG_LIBS "-lgdi32") | |||
if (GLFW_USE_HYBRID_HPG) | |||
set(_GLFW_USE_HYBRID_HPG 1) | |||
endif() | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use X11 for window creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_X11) | |||
find_package(X11 REQUIRED) | |||
list(APPEND glfw_PKG_DEPS "x11") | |||
# Set up library and include paths | |||
list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}") | |||
list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}") | |||
# Check for XRandR (modern resolution switching and gamma control) | |||
if (NOT X11_Xrandr_FOUND) | |||
message(FATAL_ERROR "The RandR headers were not found") | |||
endif() | |||
# Check for Xinerama (legacy multi-monitor support) | |||
if (NOT X11_Xinerama_FOUND) | |||
message(FATAL_ERROR "The Xinerama headers were not found") | |||
endif() | |||
# Check for Xkb (X keyboard extension) | |||
if (NOT X11_Xkb_FOUND) | |||
message(FATAL_ERROR "The X keyboard extension headers were not found") | |||
endif() | |||
# Check for Xcursor (cursor creation from RGBA images) | |||
if (NOT X11_Xcursor_FOUND) | |||
message(FATAL_ERROR "The Xcursor headers were not found") | |||
endif() | |||
list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}" | |||
"${X11_Xinerama_INCLUDE_PATH}" | |||
"${X11_Xkb_INCLUDE_PATH}" | |||
"${X11_Xcursor_INCLUDE_PATH}") | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use Wayland for window creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_WAYLAND) | |||
find_package(ECM REQUIRED NO_MODULE) | |||
list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}") | |||
find_package(Wayland REQUIRED Client Cursor Egl) | |||
find_package(WaylandScanner REQUIRED) | |||
find_package(WaylandProtocols 1.12 REQUIRED) | |||
list(APPEND glfw_PKG_DEPS "wayland-egl") | |||
list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}") | |||
list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") | |||
find_package(XKBCommon REQUIRED) | |||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") | |||
include(CheckIncludeFiles) | |||
check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H) | |||
if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")) | |||
find_package(EpollShim) | |||
if (EPOLLSHIM_FOUND) | |||
list(APPEND glfw_INCLUDE_DIRS "${EPOLLSHIM_INCLUDE_DIRS}") | |||
list(APPEND glfw_LIBRARIES "${EPOLLSHIM_LIBRARIES}") | |||
endif() | |||
endif() | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use Mir for window creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_MIR) | |||
find_package(Mir REQUIRED) | |||
list(APPEND glfw_PKG_DEPS "mirclient") | |||
list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIRS}") | |||
list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") | |||
find_package(XKBCommon REQUIRED) | |||
list(APPEND glfw_PKG_DEPS "xkbcommon") | |||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") | |||
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use OSMesa for offscreen context creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_OSMESA) | |||
find_package(OSMesa REQUIRED) | |||
list(APPEND glfw_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Use Cocoa for window creation and NSOpenGL for context creation | |||
#-------------------------------------------------------------------- | |||
if (_GLFW_COCOA) | |||
list(APPEND glfw_LIBRARIES | |||
"-framework Cocoa" | |||
"-framework IOKit" | |||
"-framework CoreFoundation" | |||
"-framework CoreVideo") | |||
set(glfw_PKG_DEPS "") | |||
set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo") | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Export GLFW library dependencies | |||
#-------------------------------------------------------------------- | |||
foreach(arg ${glfw_PKG_DEPS}) | |||
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} ${arg}") | |||
endforeach() | |||
foreach(arg ${glfw_PKG_LIBS}) | |||
set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} ${arg}") | |||
endforeach() | |||
#-------------------------------------------------------------------- | |||
# Create generated files | |||
#-------------------------------------------------------------------- | |||
include(CMakePackageConfigHelpers) | |||
set(GLFW_CONFIG_PATH "lib${LIB_SUFFIX}/cmake/glfw3") | |||
configure_package_config_file(src/glfw3Config.cmake.in | |||
src/glfw3Config.cmake | |||
INSTALL_DESTINATION "${GLFW_CONFIG_PATH}" | |||
NO_CHECK_REQUIRED_COMPONENTS_MACRO) | |||
write_basic_package_version_file(src/glfw3ConfigVersion.cmake | |||
VERSION ${GLFW_VERSION_FULL} | |||
COMPATIBILITY SameMajorVersion) | |||
configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY) | |||
configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY) | |||
#-------------------------------------------------------------------- | |||
# Add subdirectories | |||
#-------------------------------------------------------------------- | |||
add_subdirectory(src) | |||
if (GLFW_BUILD_EXAMPLES) | |||
add_subdirectory(examples) | |||
endif() | |||
if (GLFW_BUILD_TESTS) | |||
add_subdirectory(tests) | |||
endif() | |||
if (DOXYGEN_FOUND AND GLFW_BUILD_DOCS) | |||
add_subdirectory(docs) | |||
endif() | |||
#-------------------------------------------------------------------- | |||
# Install files other than the library | |||
# The library is installed by src/CMakeLists.txt | |||
#-------------------------------------------------------------------- | |||
if (GLFW_INSTALL) | |||
install(DIRECTORY include/GLFW DESTINATION include | |||
FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) | |||
install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" | |||
"${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake" | |||
DESTINATION "${GLFW_CONFIG_PATH}") | |||
install(EXPORT glfwTargets FILE glfw3Targets.cmake | |||
EXPORT_LINK_INTERFACE_LIBRARIES | |||
DESTINATION "${GLFW_CONFIG_PATH}") | |||
install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" | |||
DESTINATION "lib${LIB_SUFFIX}/pkgconfig") | |||
# Only generate this target if no higher-level project already has | |||
if (NOT TARGET uninstall) | |||
configure_file(cmake_uninstall.cmake.in | |||
cmake_uninstall.cmake IMMEDIATE @ONLY) | |||
add_custom_target(uninstall | |||
"${CMAKE_COMMAND}" -P | |||
"${GLFW_BINARY_DIR}/cmake_uninstall.cmake") | |||
set_target_properties(uninstall PROPERTIES FOLDER "GLFW3") | |||
endif() | |||
endif() | |||
@ -0,0 +1,29 @@ | |||
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") | |||
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") | |||
endif() | |||
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) | |||
string(REGEX REPLACE "\n" ";" files "${files}") | |||
foreach (file ${files}) | |||
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") | |||
if (EXISTS "$ENV{DESTDIR}${file}") | |||
exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" | |||
OUTPUT_VARIABLE rm_out | |||
RETURN_VALUE rm_retval) | |||
if (NOT "${rm_retval}" STREQUAL 0) | |||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") | |||
endif() | |||
elseif (IS_SYMLINK "$ENV{DESTDIR}${file}") | |||
EXEC_PROGRAM("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" | |||
OUTPUT_VARIABLE rm_out | |||
RETURN_VALUE rm_retval) | |||
if (NOT "${rm_retval}" STREQUAL 0) | |||
message(FATAL_ERROR "Problem when removing symlink \"$ENV{DESTDIR}${file}\"") | |||
endif() | |||
else() | |||
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") | |||
endif() | |||
endforeach() | |||
@ -0,0 +1,230 @@ | |||
/* Copyright (c) 2012, Kim Gräsman | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright notice, | |||
* this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright notice, | |||
* this list of conditions and the following disclaimer in the documentation | |||
* and/or other materials provided with the distribution. | |||
* * Neither the name of Kim Gräsman nor the names of contributors may be used | |||
* to endorse or promote products derived from this software without specific | |||
* prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, | |||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#include "getopt.h" | |||
#include <stddef.h> | |||
#include <string.h> | |||
const int no_argument = 0; | |||
const int required_argument = 1; | |||
const int optional_argument = 2; | |||
char* optarg; | |||
int optopt; | |||
/* The variable optind [...] shall be initialized to 1 by the system. */ | |||
int optind = 1; | |||
int opterr; | |||
static char* optcursor = NULL; | |||
/* Implemented based on [1] and [2] for optional arguments. | |||
optopt is handled FreeBSD-style, per [3]. | |||
Other GNU and FreeBSD extensions are purely accidental. | |||
[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html | |||
[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html | |||
[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE | |||
*/ | |||
int getopt(int argc, char* const argv[], const char* optstring) { | |||
int optchar = -1; | |||
const char* optdecl = NULL; | |||
optarg = NULL; | |||
opterr = 0; | |||
optopt = 0; | |||
/* Unspecified, but we need it to avoid overrunning the argv bounds. */ | |||
if (optind >= argc) | |||
goto no_more_optchars; | |||
/* If, when getopt() is called argv[optind] is a null pointer, getopt() | |||
shall return -1 without changing optind. */ | |||
if (argv[optind] == NULL) | |||
goto no_more_optchars; | |||
/* If, when getopt() is called *argv[optind] is not the character '-', | |||
getopt() shall return -1 without changing optind. */ | |||
if (*argv[optind] != '-') | |||
goto no_more_optchars; | |||
/* If, when getopt() is called argv[optind] points to the string "-", | |||
getopt() shall return -1 without changing optind. */ | |||
if (strcmp(argv[optind], "-") == 0) | |||
goto no_more_optchars; | |||
/* If, when getopt() is called argv[optind] points to the string "--", | |||
getopt() shall return -1 after incrementing optind. */ | |||
if (strcmp(argv[optind], "--") == 0) { | |||
++optind; | |||
goto no_more_optchars; | |||
} | |||
if (optcursor == NULL || *optcursor == '\0') | |||
optcursor = argv[optind] + 1; | |||
optchar = *optcursor; | |||
/* FreeBSD: The variable optopt saves the last known option character | |||
returned by getopt(). */ | |||
optopt = optchar; | |||
/* The getopt() function shall return the next option character (if one is | |||
found) from argv that matches a character in optstring, if there is | |||
one that matches. */ | |||
optdecl = strchr(optstring, optchar); | |||
if (optdecl) { | |||
/* [I]f a character is followed by a colon, the option takes an | |||
argument. */ | |||
if (optdecl[1] == ':') { | |||
optarg = ++optcursor; | |||
if (*optarg == '\0') { | |||
/* GNU extension: Two colons mean an option takes an | |||
optional arg; if there is text in the current argv-element | |||
(i.e., in the same word as the option name itself, for example, | |||
"-oarg"), then it is returned in optarg, otherwise optarg is set | |||
to zero. */ | |||
if (optdecl[2] != ':') { | |||
/* If the option was the last character in the string pointed to by | |||
an element of argv, then optarg shall contain the next element | |||
of argv, and optind shall be incremented by 2. If the resulting | |||
value of optind is greater than argc, this indicates a missing | |||
option-argument, and getopt() shall return an error indication. | |||
Otherwise, optarg shall point to the string following the | |||
option character in that element of argv, and optind shall be | |||
incremented by 1. | |||
*/ | |||
if (++optind < argc) { | |||
optarg = argv[optind]; | |||
} else { | |||
/* If it detects a missing option-argument, it shall return the | |||
colon character ( ':' ) if the first character of optstring | |||
was a colon, or a question-mark character ( '?' ) otherwise. | |||
*/ | |||
optarg = NULL; | |||
optchar = (optstring[0] == ':') ? ':' : '?'; | |||
} | |||
} else { | |||
optarg = NULL; | |||
} | |||
} | |||
optcursor = NULL; | |||
} | |||
} else { | |||
/* If getopt() encounters an option character that is not contained in | |||
optstring, it shall return the question-mark ( '?' ) character. */ | |||
optchar = '?'; | |||
} | |||
if (optcursor == NULL || *++optcursor == '\0') | |||
++optind; | |||
return optchar; | |||
no_more_optchars: | |||
optcursor = NULL; | |||
return -1; | |||
} | |||
/* Implementation based on [1]. | |||
[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html | |||
*/ | |||
int getopt_long(int argc, char* const argv[], const char* optstring, | |||
const struct option* longopts, int* longindex) { | |||
const struct option* o = longopts; | |||
const struct option* match = NULL; | |||
int num_matches = 0; | |||
size_t argument_name_length = 0; | |||
const char* current_argument = NULL; | |||
int retval = -1; | |||
optarg = NULL; | |||
optopt = 0; | |||
if (optind >= argc) | |||
return -1; | |||
if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) | |||
return getopt(argc, argv, optstring); | |||
/* It's an option; starts with -- and is longer than two chars. */ | |||
current_argument = argv[optind] + 2; | |||
argument_name_length = strcspn(current_argument, "="); | |||
for (; o->name; ++o) { | |||
if (strncmp(o->name, current_argument, argument_name_length) == 0) { | |||
match = o; | |||
++num_matches; | |||
} | |||
} | |||
if (num_matches == 1) { | |||
/* If longindex is not NULL, it points to a variable which is set to the | |||
index of the long option relative to longopts. */ | |||
if (longindex) | |||
*longindex = (int) (match - longopts); | |||
/* If flag is NULL, then getopt_long() shall return val. | |||
Otherwise, getopt_long() returns 0, and flag shall point to a variable | |||
which shall be set to val if the option is found, but left unchanged if | |||
the option is not found. */ | |||
if (match->flag) | |||
*(match->flag) = match->val; | |||
retval = match->flag ? 0 : match->val; | |||
if (match->has_arg != no_argument) { | |||
optarg = strchr(argv[optind], '='); | |||
if (optarg != NULL) | |||
++optarg; | |||
if (match->has_arg == required_argument) { | |||
/* Only scan the next argv for required arguments. Behavior is not | |||
specified, but has been observed with Ubuntu and Mac OSX. */ | |||
if (optarg == NULL && ++optind < argc) { | |||
optarg = argv[optind]; | |||
} | |||
if (optarg == NULL) | |||
retval = ':'; | |||
} | |||
} else if (strchr(argv[optind], '=')) { | |||
/* An argument was provided to a non-argument option. | |||
I haven't seen this specified explicitly, but both GNU and BSD-based | |||
implementations show this behavior. | |||
*/ | |||
retval = '?'; | |||
} | |||
} else { | |||
/* Unknown option or ambiguous match. */ | |||
retval = '?'; | |||
} | |||
++optind; | |||
return retval; | |||
} |
@ -0,0 +1,57 @@ | |||
/* Copyright (c) 2012, Kim Gräsman | |||
* All rights reserved. | |||
* | |||
* Redistribution and use in source and binary forms, with or without | |||
* modification, are permitted provided that the following conditions are met: | |||
* * Redistributions of source code must retain the above copyright notice, | |||
* this list of conditions and the following disclaimer. | |||
* * Redistributions in binary form must reproduce the above copyright notice, | |||
* this list of conditions and the following disclaimer in the documentation | |||
* and/or other materials provided with the distribution. | |||
* * Neither the name of Kim Gräsman nor the names of contributors may be used | |||
* to endorse or promote products derived from this software without specific | |||
* prior written permission. | |||
* | |||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, | |||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
*/ | |||
#ifndef INCLUDED_GETOPT_PORT_H | |||
#define INCLUDED_GETOPT_PORT_H | |||
#if defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
extern const int no_argument; | |||
extern const int required_argument; | |||
extern const int optional_argument; | |||
extern char* optarg; | |||
extern int optind, opterr, optopt; | |||
struct option { | |||
const char* name; | |||
int has_arg; | |||
int* flag; | |||
int val; | |||
}; | |||
int getopt(int argc, char* const argv[], const char* optstring); | |||
int getopt_long(int argc, char* const argv[], | |||
const char* optstring, const struct option* longopts, int* longindex); | |||
#if defined(__cplusplus) | |||
} | |||
#endif | |||
#endif // INCLUDED_GETOPT_PORT_H |
@ -0,0 +1,574 @@ | |||
#ifndef LINMATH_H | |||
#define LINMATH_H | |||
#include <math.h> | |||
#ifdef _MSC_VER | |||
#define inline __inline | |||
#endif | |||
#define LINMATH_H_DEFINE_VEC(n) \ | |||
typedef float vec##n[n]; \ | |||
static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ | |||
{ \ | |||
int i; \ | |||
for(i=0; i<n; ++i) \ | |||
r[i] = a[i] + b[i]; \ | |||
} \ | |||
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \ | |||
{ \ | |||
int i; \ | |||
for(i=0; i<n; ++i) \ | |||
r[i] = a[i] - b[i]; \ | |||
} \ | |||
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \ | |||
{ \ | |||
int i; \ | |||
for(i=0; i<n; ++i) \ | |||
r[i] = v[i] * s; \ | |||
} \ | |||
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \ | |||
{ \ | |||
float p = 0.; \ | |||
int i; \ | |||
for(i=0; i<n; ++i) \ | |||
p += b[i]*a[i]; \ | |||
return p; \ | |||
} \ | |||
static inline float vec##n##_len(vec##n const v) \ | |||
{ \ | |||
return (float) sqrt(vec##n##_mul_inner(v,v)); \ | |||
} \ | |||
static inline void vec##n##_norm(vec##n r, vec##n const v) \ | |||
{ \ | |||
float k = 1.f / vec##n##_len(v); \ | |||
vec##n##_scale(r, v, k); \ | |||
} | |||
LINMATH_H_DEFINE_VEC(2) | |||
LINMATH_H_DEFINE_VEC(3) | |||
LINMATH_H_DEFINE_VEC(4) | |||
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) | |||
{ | |||
r[0] = a[1]*b[2] - a[2]*b[1]; | |||
r[1] = a[2]*b[0] - a[0]*b[2]; | |||
r[2] = a[0]*b[1] - a[1]*b[0]; | |||
} | |||
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n) | |||
{ | |||
float p = 2.f*vec3_mul_inner(v, n); | |||
int i; | |||
for(i=0;i<3;++i) | |||
r[i] = v[i] - p*n[i]; | |||
} | |||
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b) | |||
{ | |||
r[0] = a[1]*b[2] - a[2]*b[1]; | |||
r[1] = a[2]*b[0] - a[0]*b[2]; | |||
r[2] = a[0]*b[1] - a[1]*b[0]; | |||
r[3] = 1.f; | |||
} | |||
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n) | |||
{ | |||
float p = 2.f*vec4_mul_inner(v, n); | |||
int i; | |||
for(i=0;i<4;++i) | |||
r[i] = v[i] - p*n[i]; | |||
} | |||
typedef vec4 mat4x4[4]; | |||
static inline void mat4x4_identity(mat4x4 M) | |||
{ | |||
int i, j; | |||
for(i=0; i<4; ++i) | |||
for(j=0; j<4; ++j) | |||
M[i][j] = i==j ? 1.f : 0.f; | |||
} | |||
static inline void mat4x4_dup(mat4x4 M, mat4x4 N) | |||
{ | |||
int i, j; | |||
for(i=0; i<4; ++i) | |||
for(j=0; j<4; ++j) | |||
M[i][j] = N[i][j]; | |||
} | |||
static inline void mat4x4_row(vec4 r, mat4x4 M, int i) | |||
{ | |||
int k; | |||
for(k=0; k<4; ++k) | |||
r[k] = M[k][i]; | |||
} | |||
static inline void mat4x4_col(vec4 r, mat4x4 M, int i) | |||
{ | |||
int k; | |||
for(k=0; k<4; ++k) | |||
r[k] = M[i][k]; | |||
} | |||
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N) | |||
{ | |||
int i, j; | |||
for(j=0; j<4; ++j) | |||
for(i=0; i<4; ++i) | |||
M[i][j] = N[j][i]; | |||
} | |||
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
vec4_add(M[i], a[i], b[i]); | |||
} | |||
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
vec4_sub(M[i], a[i], b[i]); | |||
} | |||
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
vec4_scale(M[i], a[i], k); | |||
} | |||
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z) | |||
{ | |||
int i; | |||
vec4_scale(M[0], a[0], x); | |||
vec4_scale(M[1], a[1], y); | |||
vec4_scale(M[2], a[2], z); | |||
for(i = 0; i < 4; ++i) { | |||
M[3][i] = a[3][i]; | |||
} | |||
} | |||
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b) | |||
{ | |||
mat4x4 temp; | |||
int k, r, c; | |||
for(c=0; c<4; ++c) for(r=0; r<4; ++r) { | |||
temp[c][r] = 0.f; | |||
for(k=0; k<4; ++k) | |||
temp[c][r] += a[k][r] * b[c][k]; | |||
} | |||
mat4x4_dup(M, temp); | |||
} | |||
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v) | |||
{ | |||
int i, j; | |||
for(j=0; j<4; ++j) { | |||
r[j] = 0.f; | |||
for(i=0; i<4; ++i) | |||
r[j] += M[i][j] * v[i]; | |||
} | |||
} | |||
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z) | |||
{ | |||
mat4x4_identity(T); | |||
T[3][0] = x; | |||
T[3][1] = y; | |||
T[3][2] = z; | |||
} | |||
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) | |||
{ | |||
vec4 t = {x, y, z, 0}; | |||
vec4 r; | |||
int i; | |||
for (i = 0; i < 4; ++i) { | |||
mat4x4_row(r, M, i); | |||
M[3][i] += vec4_mul_inner(r, t); | |||
} | |||
} | |||
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b) | |||
{ | |||
int i, j; | |||
for(i=0; i<4; ++i) for(j=0; j<4; ++j) | |||
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; | |||
} | |||
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle) | |||
{ | |||
float s = sinf(angle); | |||
float c = cosf(angle); | |||
vec3 u = {x, y, z}; | |||
if(vec3_len(u) > 1e-4) { | |||
mat4x4 T, C, S = {{0}}; | |||
vec3_norm(u, u); | |||
mat4x4_from_vec3_mul_outer(T, u, u); | |||
S[1][2] = u[0]; | |||
S[2][1] = -u[0]; | |||
S[2][0] = u[1]; | |||
S[0][2] = -u[1]; | |||
S[0][1] = u[2]; | |||
S[1][0] = -u[2]; | |||
mat4x4_scale(S, S, s); | |||
mat4x4_identity(C); | |||
mat4x4_sub(C, C, T); | |||
mat4x4_scale(C, C, c); | |||
mat4x4_add(T, T, C); | |||
mat4x4_add(T, T, S); | |||
T[3][3] = 1.; | |||
mat4x4_mul(R, M, T); | |||
} else { | |||
mat4x4_dup(R, M); | |||
} | |||
} | |||
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle) | |||
{ | |||
float s = sinf(angle); | |||
float c = cosf(angle); | |||
mat4x4 R = { | |||
{1.f, 0.f, 0.f, 0.f}, | |||
{0.f, c, s, 0.f}, | |||
{0.f, -s, c, 0.f}, | |||
{0.f, 0.f, 0.f, 1.f} | |||
}; | |||
mat4x4_mul(Q, M, R); | |||
} | |||
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle) | |||
{ | |||
float s = sinf(angle); | |||
float c = cosf(angle); | |||
mat4x4 R = { | |||
{ c, 0.f, s, 0.f}, | |||
{ 0.f, 1.f, 0.f, 0.f}, | |||
{ -s, 0.f, c, 0.f}, | |||
{ 0.f, 0.f, 0.f, 1.f} | |||
}; | |||
mat4x4_mul(Q, M, R); | |||
} | |||
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle) | |||
{ | |||
float s = sinf(angle); | |||
float c = cosf(angle); | |||
mat4x4 R = { | |||
{ c, s, 0.f, 0.f}, | |||
{ -s, c, 0.f, 0.f}, | |||
{ 0.f, 0.f, 1.f, 0.f}, | |||
{ 0.f, 0.f, 0.f, 1.f} | |||
}; | |||
mat4x4_mul(Q, M, R); | |||
} | |||
static inline void mat4x4_invert(mat4x4 T, mat4x4 M) | |||
{ | |||
float idet; | |||
float s[6]; | |||
float c[6]; | |||
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; | |||
s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; | |||
s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; | |||
s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; | |||
s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; | |||
s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; | |||
c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; | |||
c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; | |||
c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; | |||
c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; | |||
c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; | |||
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; | |||
/* Assumes it is invertible */ | |||
idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); | |||
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; | |||
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; | |||
T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; | |||
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; | |||
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; | |||
T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; | |||
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; | |||
T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; | |||
T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; | |||
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; | |||
T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; | |||
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; | |||
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; | |||
T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; | |||
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; | |||
T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; | |||
} | |||
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) | |||
{ | |||
float s = 1.; | |||
vec3 h; | |||
mat4x4_dup(R, M); | |||
vec3_norm(R[2], R[2]); | |||
s = vec3_mul_inner(R[1], R[2]); | |||
vec3_scale(h, R[2], s); | |||
vec3_sub(R[1], R[1], h); | |||
vec3_norm(R[2], R[2]); | |||
s = vec3_mul_inner(R[1], R[2]); | |||
vec3_scale(h, R[2], s); | |||
vec3_sub(R[1], R[1], h); | |||
vec3_norm(R[1], R[1]); | |||
s = vec3_mul_inner(R[0], R[1]); | |||
vec3_scale(h, R[1], s); | |||
vec3_sub(R[0], R[0], h); | |||
vec3_norm(R[0], R[0]); | |||
} | |||
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) | |||
{ | |||
M[0][0] = 2.f*n/(r-l); | |||
M[0][1] = M[0][2] = M[0][3] = 0.f; | |||
M[1][1] = 2.f*n/(t-b); | |||
M[1][0] = M[1][2] = M[1][3] = 0.f; | |||
M[2][0] = (r+l)/(r-l); | |||
M[2][1] = (t+b)/(t-b); | |||
M[2][2] = -(f+n)/(f-n); | |||
M[2][3] = -1.f; | |||
M[3][2] = -2.f*(f*n)/(f-n); | |||
M[3][0] = M[3][1] = M[3][3] = 0.f; | |||
} | |||
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) | |||
{ | |||
M[0][0] = 2.f/(r-l); | |||
M[0][1] = M[0][2] = M[0][3] = 0.f; | |||
M[1][1] = 2.f/(t-b); | |||
M[1][0] = M[1][2] = M[1][3] = 0.f; | |||
M[2][2] = -2.f/(f-n); | |||
M[2][0] = M[2][1] = M[2][3] = 0.f; | |||
M[3][0] = -(r+l)/(r-l); | |||
M[3][1] = -(t+b)/(t-b); | |||
M[3][2] = -(f+n)/(f-n); | |||
M[3][3] = 1.f; | |||
} | |||
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) | |||
{ | |||
/* NOTE: Degrees are an unhandy unit to work with. | |||
* linmath.h uses radians for everything! */ | |||
float const a = 1.f / (float) tan(y_fov / 2.f); | |||
m[0][0] = a / aspect; | |||
m[0][1] = 0.f; | |||
m[0][2] = 0.f; | |||
m[0][3] = 0.f; | |||
m[1][0] = 0.f; | |||
m[1][1] = a; | |||
m[1][2] = 0.f; | |||
m[1][3] = 0.f; | |||
m[2][0] = 0.f; | |||
m[2][1] = 0.f; | |||
m[2][2] = -((f + n) / (f - n)); | |||
m[2][3] = -1.f; | |||
m[3][0] = 0.f; | |||
m[3][1] = 0.f; | |||
m[3][2] = -((2.f * f * n) / (f - n)); | |||
m[3][3] = 0.f; | |||
} | |||
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up) | |||
{ | |||
/* Adapted from Android's OpenGL Matrix.java. */ | |||
/* See the OpenGL GLUT documentation for gluLookAt for a description */ | |||
/* of the algorithm. We implement it in a straightforward way: */ | |||
/* TODO: The negation of of can be spared by swapping the order of | |||
* operands in the following cross products in the right way. */ | |||
vec3 f; | |||
vec3 s; | |||
vec3 t; | |||
vec3_sub(f, center, eye); | |||
vec3_norm(f, f); | |||
vec3_mul_cross(s, f, up); | |||
vec3_norm(s, s); | |||
vec3_mul_cross(t, s, f); | |||
m[0][0] = s[0]; | |||
m[0][1] = t[0]; | |||
m[0][2] = -f[0]; | |||
m[0][3] = 0.f; | |||
m[1][0] = s[1]; | |||
m[1][1] = t[1]; | |||
m[1][2] = -f[1]; | |||
m[1][3] = 0.f; | |||
m[2][0] = s[2]; | |||
m[2][1] = t[2]; | |||
m[2][2] = -f[2]; | |||
m[2][3] = 0.f; | |||
m[3][0] = 0.f; | |||
m[3][1] = 0.f; | |||
m[3][2] = 0.f; | |||
m[3][3] = 1.f; | |||
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); | |||
} | |||
typedef float quat[4]; | |||
static inline void quat_identity(quat q) | |||
{ | |||
q[0] = q[1] = q[2] = 0.f; | |||
q[3] = 1.f; | |||
} | |||
static inline void quat_add(quat r, quat a, quat b) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
r[i] = a[i] + b[i]; | |||
} | |||
static inline void quat_sub(quat r, quat a, quat b) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
r[i] = a[i] - b[i]; | |||
} | |||
static inline void quat_mul(quat r, quat p, quat q) | |||
{ | |||
vec3 w; | |||
vec3_mul_cross(r, p, q); | |||
vec3_scale(w, p, q[3]); | |||
vec3_add(r, r, w); | |||
vec3_scale(w, q, p[3]); | |||
vec3_add(r, r, w); | |||
r[3] = p[3]*q[3] - vec3_mul_inner(p, q); | |||
} | |||
static inline void quat_scale(quat r, quat v, float s) | |||
{ | |||
int i; | |||
for(i=0; i<4; ++i) | |||
r[i] = v[i] * s; | |||
} | |||
static inline float quat_inner_product(quat a, quat b) | |||
{ | |||
float p = 0.f; | |||
int i; | |||
for(i=0; i<4; ++i) | |||
p += b[i]*a[i]; | |||
return p; | |||
} | |||
static inline void quat_conj(quat r, quat q) | |||
{ | |||
int i; | |||
for(i=0; i<3; ++i) | |||
r[i] = -q[i]; | |||
r[3] = q[3]; | |||
} | |||
static inline void quat_rotate(quat r, float angle, vec3 axis) { | |||
int i; | |||
vec3 v; | |||
vec3_scale(v, axis, sinf(angle / 2)); | |||
for(i=0; i<3; ++i) | |||
r[i] = v[i]; | |||
r[3] = cosf(angle / 2); | |||
} | |||
#define quat_norm vec4_norm | |||
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v) | |||
{ | |||
/* | |||
* Method by Fabian 'ryg' Giessen (of Farbrausch) | |||
t = 2 * cross(q.xyz, v) | |||
v' = v + q.w * t + cross(q.xyz, t) | |||
*/ | |||
vec3 t = {q[0], q[1], q[2]}; | |||
vec3 u = {q[0], q[1], q[2]}; | |||
vec3_mul_cross(t, t, v); | |||
vec3_scale(t, t, 2); | |||
vec3_mul_cross(u, u, t); | |||
vec3_scale(t, t, q[3]); | |||
vec3_add(r, v, t); | |||
vec3_add(r, r, u); | |||
} | |||
static inline void mat4x4_from_quat(mat4x4 M, quat q) | |||
{ | |||
float a = q[3]; | |||
float b = q[0]; | |||
float c = q[1]; | |||
float d = q[2]; | |||
float a2 = a*a; | |||
float b2 = b*b; | |||
float c2 = c*c; | |||
float d2 = d*d; | |||
M[0][0] = a2 + b2 - c2 - d2; | |||
M[0][1] = 2.f*(b*c + a*d); | |||
M[0][2] = 2.f*(b*d - a*c); | |||
M[0][3] = 0.f; | |||
M[1][0] = 2*(b*c - a*d); | |||
M[1][1] = a2 - b2 + c2 - d2; | |||
M[1][2] = 2.f*(c*d + a*b); | |||
M[1][3] = 0.f; | |||
M[2][0] = 2.f*(b*d + a*c); | |||
M[2][1] = 2.f*(c*d - a*b); | |||
M[2][2] = a2 - b2 - c2 + d2; | |||
M[2][3] = 0.f; | |||
M[3][0] = M[3][1] = M[3][2] = 0.f; | |||
M[3][3] = 1.f; | |||
} | |||
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q) | |||
{ | |||
/* XXX: The way this is written only works for othogonal matrices. */ | |||
/* TODO: Take care of non-orthogonal case. */ | |||
quat_mul_vec3(R[0], q, M[0]); | |||
quat_mul_vec3(R[1], q, M[1]); | |||
quat_mul_vec3(R[2], q, M[2]); | |||
R[3][0] = R[3][1] = R[3][2] = 0.f; | |||
R[3][3] = 1.f; | |||
} | |||
static inline void quat_from_mat4x4(quat q, mat4x4 M) | |||
{ | |||
float r=0.f; | |||
int i; | |||
int perm[] = { 0, 1, 2, 0, 1 }; | |||
int *p = perm; | |||
for(i = 0; i<3; i++) { | |||
float m = M[i][i]; | |||
if( m < r ) | |||
continue; | |||
m = r; | |||
p = &perm[i]; | |||
} | |||
r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); | |||
if(r < 1e-6) { | |||
q[0] = 1.f; | |||
q[1] = q[2] = q[3] = 0.f; | |||
return; | |||
} | |||
q[0] = r/2.f; | |||
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); | |||
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); | |||
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); | |||
} | |||
#endif |
@ -0,0 +1,381 @@ | |||
/* | |||
* Nuklear - v1.32.0 - public domain | |||
* no warrenty implied; use at your own risk. | |||
* authored from 2015-2017 by Micha Mettke | |||
*/ | |||
/* | |||
* ============================================================== | |||
* | |||
* API | |||
* | |||
* =============================================================== | |||
*/ | |||
#ifndef NK_GLFW_GL2_H_ | |||
#define NK_GLFW_GL2_H_ | |||
#include <GLFW/glfw3.h> | |||
enum nk_glfw_init_state{ | |||
NK_GLFW3_DEFAULT = 0, | |||
NK_GLFW3_INSTALL_CALLBACKS | |||
}; | |||
NK_API struct nk_context* nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state); | |||
NK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas); | |||
NK_API void nk_glfw3_font_stash_end(void); | |||
NK_API void nk_glfw3_new_frame(void); | |||
NK_API void nk_glfw3_render(enum nk_anti_aliasing); | |||
NK_API void nk_glfw3_shutdown(void); | |||
NK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint); | |||
NK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff); | |||
#endif | |||
/* | |||
* ============================================================== | |||
* | |||
* IMPLEMENTATION | |||
* | |||
* =============================================================== | |||
*/ | |||
#ifdef NK_GLFW_GL2_IMPLEMENTATION | |||
#ifndef NK_GLFW_TEXT_MAX | |||
#define NK_GLFW_TEXT_MAX 256 | |||
#endif | |||
#ifndef NK_GLFW_DOUBLE_CLICK_LO | |||
#define NK_GLFW_DOUBLE_CLICK_LO 0.02 | |||
#endif | |||
#ifndef NK_GLFW_DOUBLE_CLICK_HI | |||
#define NK_GLFW_DOUBLE_CLICK_HI 0.2 | |||
#endif | |||
struct nk_glfw_device { | |||
struct nk_buffer cmds; | |||
struct nk_draw_null_texture null; | |||
GLuint font_tex; | |||
}; | |||
struct nk_glfw_vertex { | |||
float position[2]; | |||
float uv[2]; | |||
nk_byte col[4]; | |||
}; | |||
static struct nk_glfw { | |||
GLFWwindow *win; | |||
int width, height; | |||
int display_width, display_height; | |||
struct nk_glfw_device ogl; | |||
struct nk_context ctx; | |||
struct nk_font_atlas atlas; | |||
struct nk_vec2 fb_scale; | |||
unsigned int text[NK_GLFW_TEXT_MAX]; | |||
int text_len; | |||
struct nk_vec2 scroll; | |||
double last_button_click; | |||
int is_double_click_down; | |||
struct nk_vec2 double_click_pos; | |||
} glfw; | |||
NK_INTERN void | |||
nk_glfw3_device_upload_atlas(const void *image, int width, int height) | |||
{ | |||
struct nk_glfw_device *dev = &glfw.ogl; | |||
glGenTextures(1, &dev->font_tex); | |||
glBindTexture(GL_TEXTURE_2D, dev->font_tex); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, | |||
GL_RGBA, GL_UNSIGNED_BYTE, image); | |||
} | |||
NK_API void | |||
nk_glfw3_render(enum nk_anti_aliasing AA) | |||
{ | |||
/* setup global state */ | |||
struct nk_glfw_device *dev = &glfw.ogl; | |||
glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); | |||
glDisable(GL_CULL_FACE); | |||
glDisable(GL_DEPTH_TEST); | |||
glEnable(GL_SCISSOR_TEST); | |||
glEnable(GL_BLEND); | |||
glEnable(GL_TEXTURE_2D); | |||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
/* setup viewport/project */ | |||
glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height); | |||
glMatrixMode(GL_PROJECTION); | |||
glPushMatrix(); | |||
glLoadIdentity(); | |||
glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f); | |||
glMatrixMode(GL_MODELVIEW); | |||
glPushMatrix(); | |||
glLoadIdentity(); | |||
glEnableClientState(GL_VERTEX_ARRAY); | |||
glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |||
glEnableClientState(GL_COLOR_ARRAY); | |||
{ | |||
GLsizei vs = sizeof(struct nk_glfw_vertex); | |||
size_t vp = offsetof(struct nk_glfw_vertex, position); | |||
size_t vt = offsetof(struct nk_glfw_vertex, uv); | |||
size_t vc = offsetof(struct nk_glfw_vertex, col); | |||
/* convert from command queue into draw list and draw to screen */ | |||
const struct nk_draw_command *cmd; | |||
const nk_draw_index *offset = NULL; | |||
struct nk_buffer vbuf, ebuf; | |||
/* fill convert configuration */ | |||
struct nk_convert_config config; | |||
static const struct nk_draw_vertex_layout_element vertex_layout[] = { | |||
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)}, | |||
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)}, | |||
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)}, | |||
{NK_VERTEX_LAYOUT_END} | |||
}; | |||
NK_MEMSET(&config, 0, sizeof(config)); | |||
config.vertex_layout = vertex_layout; | |||
config.vertex_size = sizeof(struct nk_glfw_vertex); | |||
config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex); | |||
config.null = dev->null; | |||
config.circle_segment_count = 22; | |||
config.curve_segment_count = 22; | |||
config.arc_segment_count = 22; | |||
config.global_alpha = 1.0f; | |||
config.shape_AA = AA; | |||
config.line_AA = AA; | |||
/* convert shapes into vertexes */ | |||
nk_buffer_init_default(&vbuf); | |||
nk_buffer_init_default(&ebuf); | |||
nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config); | |||
/* setup vertex buffer pointer */ | |||
{const void *vertices = nk_buffer_memory_const(&vbuf); | |||
glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp)); | |||
glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt)); | |||
glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));} | |||
/* iterate over and execute each draw command */ | |||
offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf); | |||
nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) | |||
{ | |||
if (!cmd->elem_count) continue; | |||
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); | |||
glScissor( | |||
(GLint)(cmd->clip_rect.x * glfw.fb_scale.x), | |||
(GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y), | |||
(GLint)(cmd->clip_rect.w * glfw.fb_scale.x), | |||
(GLint)(cmd->clip_rect.h * glfw.fb_scale.y)); | |||
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); | |||
offset += cmd->elem_count; | |||
} | |||
nk_clear(&glfw.ctx); | |||
nk_buffer_free(&vbuf); | |||
nk_buffer_free(&ebuf); | |||
} | |||
/* default OpenGL state */ | |||
glDisableClientState(GL_VERTEX_ARRAY); | |||
glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |||
glDisableClientState(GL_COLOR_ARRAY); | |||
glDisable(GL_CULL_FACE); | |||
glDisable(GL_DEPTH_TEST); | |||
glDisable(GL_SCISSOR_TEST); | |||
glDisable(GL_BLEND); | |||
glDisable(GL_TEXTURE_2D); | |||
glBindTexture(GL_TEXTURE_2D, 0); | |||
glMatrixMode(GL_MODELVIEW); | |||
glPopMatrix(); | |||
glMatrixMode(GL_PROJECTION); | |||
glPopMatrix(); | |||
glPopAttrib(); | |||
} | |||
NK_API void | |||
nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) | |||
{ | |||
(void)win; | |||
if (glfw.text_len < NK_GLFW_TEXT_MAX) | |||
glfw.text[glfw.text_len++] = codepoint; | |||
} | |||
NK_API void | |||
nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff) | |||
{ | |||
(void)win; (void)xoff; | |||
glfw.scroll.x += (float)xoff; | |||
glfw.scroll.y += (float)yoff; | |||
} | |||
NK_API void | |||
nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) | |||
{ | |||
double x, y; | |||
if (button != GLFW_MOUSE_BUTTON_LEFT) return; | |||
glfwGetCursorPos(window, &x, &y); | |||
if (action == GLFW_PRESS) { | |||
double dt = glfwGetTime() - glfw.last_button_click; | |||
if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) { | |||
glfw.is_double_click_down = nk_true; | |||
glfw.double_click_pos = nk_vec2((float)x, (float)y); | |||
} | |||
glfw.last_button_click = glfwGetTime(); | |||
} else glfw.is_double_click_down = nk_false; | |||
} | |||
NK_INTERN void | |||
nk_glfw3_clipbard_paste(nk_handle usr, struct nk_text_edit *edit) | |||
{ | |||
const char *text = glfwGetClipboardString(glfw.win); | |||
if (text) nk_textedit_paste(edit, text, nk_strlen(text)); | |||
(void)usr; | |||
} | |||
NK_INTERN void | |||
nk_glfw3_clipbard_copy(nk_handle usr, const char *text, int len) | |||
{ | |||
char *str = 0; | |||
(void)usr; | |||
if (!len) return; | |||
str = (char*)malloc((size_t)len+1); | |||
if (!str) return; | |||
NK_MEMCPY(str, text, (size_t)len); | |||
str[len] = '\0'; | |||
glfwSetClipboardString(glfw.win, str); | |||
free(str); | |||
} | |||
NK_API struct nk_context* | |||
nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) | |||
{ | |||
glfw.win = win; | |||
if (init_state == NK_GLFW3_INSTALL_CALLBACKS) { | |||
glfwSetScrollCallback(win, nk_gflw3_scroll_callback); | |||
glfwSetCharCallback(win, nk_glfw3_char_callback); | |||
glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback); | |||
} | |||
nk_init_default(&glfw.ctx, 0); | |||
glfw.ctx.clip.copy = nk_glfw3_clipbard_copy; | |||
glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; | |||
glfw.ctx.clip.userdata = nk_handle_ptr(0); | |||
nk_buffer_init_default(&glfw.ogl.cmds); | |||
glfw.is_double_click_down = nk_false; | |||
glfw.double_click_pos = nk_vec2(0, 0); | |||
return &glfw.ctx; | |||
} | |||
NK_API void | |||
nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) | |||
{ | |||
nk_font_atlas_init_default(&glfw.atlas); | |||
nk_font_atlas_begin(&glfw.atlas); | |||
*atlas = &glfw.atlas; | |||
} | |||
NK_API void | |||
nk_glfw3_font_stash_end(void) | |||
{ | |||
const void *image; int w, h; | |||
image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32); | |||
nk_glfw3_device_upload_atlas(image, w, h); | |||
nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.null); | |||
if (glfw.atlas.default_font) | |||
nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle); | |||
} | |||
NK_API void | |||
nk_glfw3_new_frame(void) | |||
{ | |||
int i; | |||
double x, y; | |||
struct nk_context *ctx = &glfw.ctx; | |||
struct GLFWwindow *win = glfw.win; | |||
glfwGetWindowSize(win, &glfw.width, &glfw.height); | |||
glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height); | |||
glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width; | |||
glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height; | |||
nk_input_begin(ctx); | |||
for (i = 0; i < glfw.text_len; ++i) | |||
nk_input_unicode(ctx, glfw.text[i]); | |||
/* optional grabbing behavior */ | |||
if (ctx->input.mouse.grab) | |||
glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||
else if (ctx->input.mouse.ungrab) | |||
glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||
nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_SCROLL_UP, glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS|| | |||
glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS); | |||
if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || | |||
glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) { | |||
nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_UNDO, glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_REDO, glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS); | |||
} else { | |||
nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS); | |||
nk_input_key(ctx, NK_KEY_COPY, 0); | |||
nk_input_key(ctx, NK_KEY_PASTE, 0); | |||
nk_input_key(ctx, NK_KEY_CUT, 0); | |||
nk_input_key(ctx, NK_KEY_SHIFT, 0); | |||
} | |||
glfwGetCursorPos(win, &x, &y); | |||
nk_input_motion(ctx, (int)x, (int)y); | |||
if (ctx->input.mouse.grabbed) { | |||
glfwSetCursorPos(glfw.win, (double)ctx->input.mouse.prev.x, (double)ctx->input.mouse.prev.y); | |||
ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; | |||
ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; | |||
} | |||
nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); | |||
nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); | |||
nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); | |||
nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down); | |||
nk_input_scroll(ctx, glfw.scroll); | |||
nk_input_end(&glfw.ctx); | |||
glfw.text_len = 0; | |||
glfw.scroll = nk_vec2(0,0); | |||
} | |||
NK_API | |||
void nk_glfw3_shutdown(void) | |||
{ | |||
struct nk_glfw_device *dev = &glfw.ogl; | |||
nk_font_atlas_clear(&glfw.atlas); | |||
nk_free(&glfw.ctx); | |||
glDeleteTextures(1, &dev->font_tex); | |||
nk_buffer_free(&dev->cmds); | |||
NK_MEMSET(&glfw, 0, sizeof(glfw)); | |||
} | |||
#endif |
@ -0,0 +1,594 @@ | |||
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- | |||
Copyright (c) 2012 Marcus Geelnard | |||
This software is provided 'as-is', without any express or implied | |||
warranty. In no event will the authors be held liable for any damages | |||
arising from the use of this software. | |||
Permission is granted to anyone to use this software for any purpose, | |||
including commercial applications, and to alter it and redistribute it | |||
freely, subject to the following restrictions: | |||
1. The origin of this software must not be misrepresented; you must not | |||
claim that you wrote the original software. If you use this software | |||
in a product, an acknowledgment in the product documentation would be | |||
appreciated but is not required. | |||
2. Altered source versions must be plainly marked as such, and must not be | |||
misrepresented as being the original software. | |||
3. This notice may not be removed or altered from any source | |||
distribution. | |||
*/ | |||
/* 2013-01-06 Camilla Löwy <elmindreda@glfw.org> | |||
* | |||
* Added casts from time_t to DWORD to avoid warnings on VC++. | |||
* Fixed time retrieval on POSIX systems. | |||
*/ | |||
#include "tinycthread.h" | |||
#include <stdlib.h> | |||
/* Platform specific includes */ | |||
#if defined(_TTHREAD_POSIX_) | |||
#include <signal.h> | |||
#include <sched.h> | |||
#include <unistd.h> | |||
#include <sys/time.h> | |||
#include <errno.h> | |||
#elif defined(_TTHREAD_WIN32_) | |||
#include <process.h> | |||
#include <sys/timeb.h> | |||
#endif | |||
/* Standard, good-to-have defines */ | |||
#ifndef NULL | |||
#define NULL (void*)0 | |||
#endif | |||
#ifndef TRUE | |||
#define TRUE 1 | |||
#endif | |||
#ifndef FALSE | |||
#define FALSE 0 | |||
#endif | |||
int mtx_init(mtx_t *mtx, int type) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
mtx->mAlreadyLocked = FALSE; | |||
mtx->mRecursive = type & mtx_recursive; | |||
InitializeCriticalSection(&mtx->mHandle); | |||
return thrd_success; | |||
#else | |||
int ret; | |||
pthread_mutexattr_t attr; | |||
pthread_mutexattr_init(&attr); | |||
if (type & mtx_recursive) | |||
{ | |||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); | |||
} | |||
ret = pthread_mutex_init(mtx, &attr); | |||
pthread_mutexattr_destroy(&attr); | |||
return ret == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
void mtx_destroy(mtx_t *mtx) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
DeleteCriticalSection(&mtx->mHandle); | |||
#else | |||
pthread_mutex_destroy(mtx); | |||
#endif | |||
} | |||
int mtx_lock(mtx_t *mtx) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
EnterCriticalSection(&mtx->mHandle); | |||
if (!mtx->mRecursive) | |||
{ | |||
while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ | |||
mtx->mAlreadyLocked = TRUE; | |||
} | |||
return thrd_success; | |||
#else | |||
return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) | |||
{ | |||
/* FIXME! */ | |||
(void)mtx; | |||
(void)ts; | |||
return thrd_error; | |||
} | |||
int mtx_trylock(mtx_t *mtx) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; | |||
if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) | |||
{ | |||
LeaveCriticalSection(&mtx->mHandle); | |||
ret = thrd_busy; | |||
} | |||
return ret; | |||
#else | |||
return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; | |||
#endif | |||
} | |||
int mtx_unlock(mtx_t *mtx) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
mtx->mAlreadyLocked = FALSE; | |||
LeaveCriticalSection(&mtx->mHandle); | |||
return thrd_success; | |||
#else | |||
return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; | |||
#endif | |||
} | |||
#if defined(_TTHREAD_WIN32_) | |||
#define _CONDITION_EVENT_ONE 0 | |||
#define _CONDITION_EVENT_ALL 1 | |||
#endif | |||
int cnd_init(cnd_t *cond) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
cond->mWaitersCount = 0; | |||
/* Init critical section */ | |||
InitializeCriticalSection(&cond->mWaitersCountLock); | |||
/* Init events */ | |||
cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); | |||
if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) | |||
{ | |||
cond->mEvents[_CONDITION_EVENT_ALL] = NULL; | |||
return thrd_error; | |||
} | |||
cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); | |||
if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) | |||
{ | |||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); | |||
cond->mEvents[_CONDITION_EVENT_ONE] = NULL; | |||
return thrd_error; | |||
} | |||
return thrd_success; | |||
#else | |||
return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
void cnd_destroy(cnd_t *cond) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) | |||
{ | |||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); | |||
} | |||
if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) | |||
{ | |||
CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); | |||
} | |||
DeleteCriticalSection(&cond->mWaitersCountLock); | |||
#else | |||
pthread_cond_destroy(cond); | |||
#endif | |||
} | |||
int cnd_signal(cnd_t *cond) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
int haveWaiters; | |||
/* Are there any waiters? */ | |||
EnterCriticalSection(&cond->mWaitersCountLock); | |||
haveWaiters = (cond->mWaitersCount > 0); | |||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||
/* If we have any waiting threads, send them a signal */ | |||
if(haveWaiters) | |||
{ | |||
if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) | |||
{ | |||
return thrd_error; | |||
} | |||
} | |||
return thrd_success; | |||
#else | |||
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
int cnd_broadcast(cnd_t *cond) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
int haveWaiters; | |||
/* Are there any waiters? */ | |||
EnterCriticalSection(&cond->mWaitersCountLock); | |||
haveWaiters = (cond->mWaitersCount > 0); | |||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||
/* If we have any waiting threads, send them a signal */ | |||
if(haveWaiters) | |||
{ | |||
if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) | |||
{ | |||
return thrd_error; | |||
} | |||
} | |||
return thrd_success; | |||
#else | |||
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
#if defined(_TTHREAD_WIN32_) | |||
static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) | |||
{ | |||
int result, lastWaiter; | |||
/* Increment number of waiters */ | |||
EnterCriticalSection(&cond->mWaitersCountLock); | |||
++ cond->mWaitersCount; | |||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||
/* Release the mutex while waiting for the condition (will decrease | |||
the number of waiters when done)... */ | |||
mtx_unlock(mtx); | |||
/* Wait for either event to become signaled due to cnd_signal() or | |||
cnd_broadcast() being called */ | |||
result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); | |||
if (result == WAIT_TIMEOUT) | |||
{ | |||
return thrd_timeout; | |||
} | |||
else if (result == (int)WAIT_FAILED) | |||
{ | |||
return thrd_error; | |||
} | |||
/* Check if we are the last waiter */ | |||
EnterCriticalSection(&cond->mWaitersCountLock); | |||
-- cond->mWaitersCount; | |||
lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && | |||
(cond->mWaitersCount == 0); | |||
LeaveCriticalSection(&cond->mWaitersCountLock); | |||
/* If we are the last waiter to be notified to stop waiting, reset the event */ | |||
if (lastWaiter) | |||
{ | |||
if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) | |||
{ | |||
return thrd_error; | |||
} | |||
} | |||
/* Re-acquire the mutex */ | |||
mtx_lock(mtx); | |||
return thrd_success; | |||
} | |||
#endif | |||
int cnd_wait(cnd_t *cond, mtx_t *mtx) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
return _cnd_timedwait_win32(cond, mtx, INFINITE); | |||
#else | |||
return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
struct timespec now; | |||
if (clock_gettime(CLOCK_REALTIME, &now) == 0) | |||
{ | |||
DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + | |||
(ts->tv_nsec - now.tv_nsec + 500000) / 1000000); | |||
return _cnd_timedwait_win32(cond, mtx, delta); | |||
} | |||
else | |||
return thrd_error; | |||
#else | |||
int ret; | |||
ret = pthread_cond_timedwait(cond, mtx, ts); | |||
if (ret == ETIMEDOUT) | |||
{ | |||
return thrd_timeout; | |||
} | |||
return ret == 0 ? thrd_success : thrd_error; | |||
#endif | |||
} | |||
/** Information to pass to the new thread (what to run). */ | |||
typedef struct { | |||
thrd_start_t mFunction; /**< Pointer to the function to be executed. */ | |||
void * mArg; /**< Function argument for the thread function. */ | |||
} _thread_start_info; | |||
/* Thread wrapper function. */ | |||
#if defined(_TTHREAD_WIN32_) | |||
static unsigned WINAPI _thrd_wrapper_function(void * aArg) | |||
#elif defined(_TTHREAD_POSIX_) | |||
static void * _thrd_wrapper_function(void * aArg) | |||
#endif | |||
{ | |||
thrd_start_t fun; | |||
void *arg; | |||
int res; | |||
#if defined(_TTHREAD_POSIX_) | |||
void *pres; | |||
#endif | |||
/* Get thread startup information */ | |||
_thread_start_info *ti = (_thread_start_info *) aArg; | |||
fun = ti->mFunction; | |||
arg = ti->mArg; | |||
/* The thread is responsible for freeing the startup information */ | |||
free((void *)ti); | |||
/* Call the actual client thread function */ | |||
res = fun(arg); | |||
#if defined(_TTHREAD_WIN32_) | |||
return res; | |||
#else | |||
pres = malloc(sizeof(int)); | |||
if (pres != NULL) | |||
{ | |||
*(int*)pres = res; | |||
} | |||
return pres; | |||
#endif | |||
} | |||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) | |||
{ | |||
/* Fill out the thread startup information (passed to the thread wrapper, | |||
which will eventually free it) */ | |||
_thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); | |||
if (ti == NULL) | |||
{ | |||
return thrd_nomem; | |||
} | |||
ti->mFunction = func; | |||
ti->mArg = arg; | |||
/* Create the thread */ | |||
#if defined(_TTHREAD_WIN32_) | |||
*thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); | |||
#elif defined(_TTHREAD_POSIX_) | |||
if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) | |||
{ | |||
*thr = 0; | |||
} | |||
#endif | |||
/* Did we fail to create the thread? */ | |||
if(!*thr) | |||
{ | |||
free(ti); | |||
return thrd_error; | |||
} | |||
return thrd_success; | |||
} | |||
thrd_t thrd_current(void) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
return GetCurrentThread(); | |||
#else | |||
return pthread_self(); | |||
#endif | |||
} | |||
int thrd_detach(thrd_t thr) | |||
{ | |||
/* FIXME! */ | |||
(void)thr; | |||
return thrd_error; | |||
} | |||
int thrd_equal(thrd_t thr0, thrd_t thr1) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
return thr0 == thr1; | |||
#else | |||
return pthread_equal(thr0, thr1); | |||
#endif | |||
} | |||
void thrd_exit(int res) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
ExitThread(res); | |||
#else | |||
void *pres = malloc(sizeof(int)); | |||
if (pres != NULL) | |||
{ | |||
*(int*)pres = res; | |||
} | |||
pthread_exit(pres); | |||
#endif | |||
} | |||
int thrd_join(thrd_t thr, int *res) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) | |||
{ | |||
return thrd_error; | |||
} | |||
if (res != NULL) | |||
{ | |||
DWORD dwRes; | |||
GetExitCodeThread(thr, &dwRes); | |||
*res = dwRes; | |||
} | |||
#elif defined(_TTHREAD_POSIX_) | |||
void *pres; | |||
int ires = 0; | |||
if (pthread_join(thr, &pres) != 0) | |||
{ | |||
return thrd_error; | |||
} | |||
if (pres != NULL) | |||
{ | |||
ires = *(int*)pres; | |||
free(pres); | |||
} | |||
if (res != NULL) | |||
{ | |||
*res = ires; | |||
} | |||
#endif | |||
return thrd_success; | |||
} | |||
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) | |||
{ | |||
struct timespec now; | |||
#if defined(_TTHREAD_WIN32_) | |||
DWORD delta; | |||
#else | |||
long delta; | |||
#endif | |||
/* Get the current time */ | |||
if (clock_gettime(CLOCK_REALTIME, &now) != 0) | |||
return -2; // FIXME: Some specific error code? | |||
#if defined(_TTHREAD_WIN32_) | |||
/* Delta in milliseconds */ | |||
delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + | |||
(time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); | |||
if (delta > 0) | |||
{ | |||
Sleep(delta); | |||
} | |||
#else | |||
/* Delta in microseconds */ | |||
delta = (time_point->tv_sec - now.tv_sec) * 1000000L + | |||
(time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; | |||
/* On some systems, the usleep argument must be < 1000000 */ | |||
while (delta > 999999L) | |||
{ | |||
usleep(999999); | |||
delta -= 999999L; | |||
} | |||
if (delta > 0L) | |||
{ | |||
usleep((useconds_t)delta); | |||
} | |||
#endif | |||
/* We don't support waking up prematurely (yet) */ | |||
if (remaining) | |||
{ | |||
remaining->tv_sec = 0; | |||
remaining->tv_nsec = 0; | |||
} | |||
return 0; | |||
} | |||
void thrd_yield(void) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
Sleep(0); | |||
#else | |||
sched_yield(); | |||
#endif | |||
} | |||
int tss_create(tss_t *key, tss_dtor_t dtor) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
/* FIXME: The destructor function is not supported yet... */ | |||
if (dtor != NULL) | |||
{ | |||
return thrd_error; | |||
} | |||
*key = TlsAlloc(); | |||
if (*key == TLS_OUT_OF_INDEXES) | |||
{ | |||
return thrd_error; | |||
} | |||
#else | |||
if (pthread_key_create(key, dtor) != 0) | |||
{ | |||
return thrd_error; | |||
} | |||
#endif | |||
return thrd_success; | |||
} | |||
void tss_delete(tss_t key) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
TlsFree(key); | |||
#else | |||
pthread_key_delete(key); | |||
#endif | |||
} | |||
void *tss_get(tss_t key) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
return TlsGetValue(key); | |||
#else | |||
return pthread_getspecific(key); | |||
#endif | |||
} | |||
int tss_set(tss_t key, void *val) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
if (TlsSetValue(key, val) == 0) | |||
{ | |||
return thrd_error; | |||
} | |||
#else | |||
if (pthread_setspecific(key, val) != 0) | |||
{ | |||
return thrd_error; | |||
} | |||
#endif | |||
return thrd_success; | |||
} | |||
#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) | |||
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) | |||
{ | |||
#if defined(_TTHREAD_WIN32_) | |||
struct _timeb tb; | |||
_ftime(&tb); | |||
ts->tv_sec = (time_t)tb.time; | |||
ts->tv_nsec = 1000000L * (long)tb.millitm; | |||
#else | |||
struct timeval tv; | |||
gettimeofday(&tv, NULL); | |||
ts->tv_sec = (time_t)tv.tv_sec; | |||
ts->tv_nsec = 1000L * (long)tv.tv_usec; | |||
#endif | |||
return 0; | |||
} | |||
#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ | |||
@ -0,0 +1,443 @@ | |||
/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- | |||
Copyright (c) 2012 Marcus Geelnard | |||
This software is provided 'as-is', without any express or implied | |||
warranty. In no event will the authors be held liable for any damages | |||
arising from the use of this software. | |||
Permission is granted to anyone to use this software for any purpose, | |||
including commercial applications, and to alter it and redistribute it | |||
freely, subject to the following restrictions: | |||
1. The origin of this software must not be misrepresented; you must not | |||
claim that you wrote the original software. If you use this software | |||
in a product, an acknowledgment in the product documentation would be | |||
appreciated but is not required. | |||
2. Altered source versions must be plainly marked as such, and must not be | |||
misrepresented as being the original software. | |||
3. This notice may not be removed or altered from any source | |||
distribution. | |||
*/ | |||
#ifndef _TINYCTHREAD_H_ | |||
#define _TINYCTHREAD_H_ | |||
/** | |||
* @file | |||
* @mainpage TinyCThread API Reference | |||
* | |||
* @section intro_sec Introduction | |||
* TinyCThread is a minimal, portable implementation of basic threading | |||
* classes for C. | |||
* | |||
* They closely mimic the functionality and naming of the C11 standard, and | |||
* should be easily replaceable with the corresponding standard variants. | |||
* | |||
* @section port_sec Portability | |||
* The Win32 variant uses the native Win32 API for implementing the thread | |||
* classes, while for other systems, the POSIX threads API (pthread) is used. | |||
* | |||
* @section misc_sec Miscellaneous | |||
* The following special keywords are available: #_Thread_local. | |||
* | |||
* For more detailed information, browse the different sections of this | |||
* documentation. A good place to start is: | |||
* tinycthread.h. | |||
*/ | |||
/* Which platform are we on? */ | |||
#if !defined(_TTHREAD_PLATFORM_DEFINED_) | |||
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) | |||
#define _TTHREAD_WIN32_ | |||
#else | |||
#define _TTHREAD_POSIX_ | |||
#endif | |||
#define _TTHREAD_PLATFORM_DEFINED_ | |||
#endif | |||
/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ | |||
#if defined(_TTHREAD_POSIX_) | |||
#undef _FEATURES_H | |||
#if !defined(_GNU_SOURCE) | |||
#define _GNU_SOURCE | |||
#endif | |||
#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) | |||
#undef _POSIX_C_SOURCE | |||
#define _POSIX_C_SOURCE 199309L | |||
#endif | |||
#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) | |||
#undef _XOPEN_SOURCE | |||
#define _XOPEN_SOURCE 500 | |||
#endif | |||
#endif | |||
/* Generic includes */ | |||
#include <time.h> | |||
/* Platform specific includes */ | |||
#if defined(_TTHREAD_POSIX_) | |||
#include <sys/time.h> | |||
#include <pthread.h> | |||
#elif defined(_TTHREAD_WIN32_) | |||
#ifndef WIN32_LEAN_AND_MEAN | |||
#define WIN32_LEAN_AND_MEAN | |||
#define __UNDEF_LEAN_AND_MEAN | |||
#endif | |||
#include <windows.h> | |||
#ifdef __UNDEF_LEAN_AND_MEAN | |||
#undef WIN32_LEAN_AND_MEAN | |||
#undef __UNDEF_LEAN_AND_MEAN | |||
#endif | |||
#endif | |||
/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, | |||
it's quite likely that libc does not support it either. Hence, fall back to | |||
the only other supported time specifier: CLOCK_REALTIME (and if that fails, | |||
we're probably emulating clock_gettime anyway, so anything goes). */ | |||
#ifndef TIME_UTC | |||
#ifdef CLOCK_REALTIME | |||
#define TIME_UTC CLOCK_REALTIME | |||
#else | |||
#define TIME_UTC 0 | |||
#endif | |||
#endif | |||
/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ | |||
#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) | |||
#define _TTHREAD_EMULATE_CLOCK_GETTIME_ | |||
/* Emulate struct timespec */ | |||
#if defined(_TTHREAD_WIN32_) | |||
struct _ttherad_timespec { | |||
time_t tv_sec; | |||
long tv_nsec; | |||
}; | |||
#define timespec _ttherad_timespec | |||
#endif | |||
/* Emulate clockid_t */ | |||
typedef int _tthread_clockid_t; | |||
#define clockid_t _tthread_clockid_t | |||
/* Emulate clock_gettime */ | |||
int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); | |||
#define clock_gettime _tthread_clock_gettime | |||
#ifndef CLOCK_REALTIME | |||
#define CLOCK_REALTIME 0 | |||
#endif | |||
#endif | |||
/** TinyCThread version (major number). */ | |||
#define TINYCTHREAD_VERSION_MAJOR 1 | |||
/** TinyCThread version (minor number). */ | |||
#define TINYCTHREAD_VERSION_MINOR 1 | |||
/** TinyCThread version (full version). */ | |||
#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) | |||
/** | |||
* @def _Thread_local | |||
* Thread local storage keyword. | |||
* A variable that is declared with the @c _Thread_local keyword makes the | |||
* value of the variable local to each thread (known as thread-local storage, | |||
* or TLS). Example usage: | |||
* @code | |||
* // This variable is local to each thread. | |||
* _Thread_local int variable; | |||
* @endcode | |||
* @note The @c _Thread_local keyword is a macro that maps to the corresponding | |||
* compiler directive (e.g. @c __declspec(thread)). | |||
* @note This directive is currently not supported on Mac OS X (it will give | |||
* a compiler error), since compile-time TLS is not supported in the Mac OS X | |||
* executable format. Also, some older versions of MinGW (before GCC 4.x) do | |||
* not support this directive. | |||
* @hideinitializer | |||
*/ | |||
/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ | |||
#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) | |||
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) | |||
#define _Thread_local __thread | |||
#else | |||
#define _Thread_local __declspec(thread) | |||
#endif | |||
#endif | |||
/* Macros */ | |||
#define TSS_DTOR_ITERATIONS 0 | |||
/* Function return values */ | |||
#define thrd_error 0 /**< The requested operation failed */ | |||
#define thrd_success 1 /**< The requested operation succeeded */ | |||
#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ | |||
#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ | |||
#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ | |||
/* Mutex types */ | |||
#define mtx_plain 1 | |||
#define mtx_timed 2 | |||
#define mtx_try 4 | |||
#define mtx_recursive 8 | |||
/* Mutex */ | |||
#if defined(_TTHREAD_WIN32_) | |||
typedef struct { | |||
CRITICAL_SECTION mHandle; /* Critical section handle */ | |||
int mAlreadyLocked; /* TRUE if the mutex is already locked */ | |||
int mRecursive; /* TRUE if the mutex is recursive */ | |||
} mtx_t; | |||
#else | |||
typedef pthread_mutex_t mtx_t; | |||
#endif | |||
/** Create a mutex object. | |||
* @param mtx A mutex object. | |||
* @param type Bit-mask that must have one of the following six values: | |||
* @li @c mtx_plain for a simple non-recursive mutex | |||
* @li @c mtx_timed for a non-recursive mutex that supports timeout | |||
* @li @c mtx_try for a non-recursive mutex that supports test and return | |||
* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) | |||
* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) | |||
* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int mtx_init(mtx_t *mtx, int type); | |||
/** Release any resources used by the given mutex. | |||
* @param mtx A mutex object. | |||
*/ | |||
void mtx_destroy(mtx_t *mtx); | |||
/** Lock the given mutex. | |||
* Blocks until the given mutex can be locked. If the mutex is non-recursive, and | |||
* the calling thread already has a lock on the mutex, this call will block | |||
* forever. | |||
* @param mtx A mutex object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int mtx_lock(mtx_t *mtx); | |||
/** NOT YET IMPLEMENTED. | |||
*/ | |||
int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); | |||
/** Try to lock the given mutex. | |||
* The specified mutex shall support either test and return or timeout. If the | |||
* mutex is already locked, the function returns without blocking. | |||
* @param mtx A mutex object. | |||
* @return @ref thrd_success on success, or @ref thrd_busy if the resource | |||
* requested is already in use, or @ref thrd_error if the request could not be | |||
* honored. | |||
*/ | |||
int mtx_trylock(mtx_t *mtx); | |||
/** Unlock the given mutex. | |||
* @param mtx A mutex object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int mtx_unlock(mtx_t *mtx); | |||
/* Condition variable */ | |||
#if defined(_TTHREAD_WIN32_) | |||
typedef struct { | |||
HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ | |||
unsigned int mWaitersCount; /* Count of the number of waiters. */ | |||
CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ | |||
} cnd_t; | |||
#else | |||
typedef pthread_cond_t cnd_t; | |||
#endif | |||
/** Create a condition variable object. | |||
* @param cond A condition variable object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int cnd_init(cnd_t *cond); | |||
/** Release any resources used by the given condition variable. | |||
* @param cond A condition variable object. | |||
*/ | |||
void cnd_destroy(cnd_t *cond); | |||
/** Signal a condition variable. | |||
* Unblocks one of the threads that are blocked on the given condition variable | |||
* at the time of the call. If no threads are blocked on the condition variable | |||
* at the time of the call, the function does nothing and return success. | |||
* @param cond A condition variable object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int cnd_signal(cnd_t *cond); | |||
/** Broadcast a condition variable. | |||
* Unblocks all of the threads that are blocked on the given condition variable | |||
* at the time of the call. If no threads are blocked on the condition variable | |||
* at the time of the call, the function does nothing and return success. | |||
* @param cond A condition variable object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int cnd_broadcast(cnd_t *cond); | |||
/** Wait for a condition variable to become signaled. | |||
* The function atomically unlocks the given mutex and endeavors to block until | |||
* the given condition variable is signaled by a call to cnd_signal or to | |||
* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex | |||
* before it returns. | |||
* @param cond A condition variable object. | |||
* @param mtx A mutex object. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int cnd_wait(cnd_t *cond, mtx_t *mtx); | |||
/** Wait for a condition variable to become signaled. | |||
* The function atomically unlocks the given mutex and endeavors to block until | |||
* the given condition variable is signaled by a call to cnd_signal or to | |||
* cnd_broadcast, or until after the specified time. When the calling thread | |||
* becomes unblocked it locks the mutex before it returns. | |||
* @param cond A condition variable object. | |||
* @param mtx A mutex object. | |||
* @param xt A point in time at which the request will time out (absolute time). | |||
* @return @ref thrd_success upon success, or @ref thrd_timeout if the time | |||
* specified in the call was reached without acquiring the requested resource, or | |||
* @ref thrd_error if the request could not be honored. | |||
*/ | |||
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); | |||
/* Thread */ | |||
#if defined(_TTHREAD_WIN32_) | |||
typedef HANDLE thrd_t; | |||
#else | |||
typedef pthread_t thrd_t; | |||
#endif | |||
/** Thread start function. | |||
* Any thread that is started with the @ref thrd_create() function must be | |||
* started through a function of this type. | |||
* @param arg The thread argument (the @c arg argument of the corresponding | |||
* @ref thrd_create() call). | |||
* @return The thread return value, which can be obtained by another thread | |||
* by using the @ref thrd_join() function. | |||
*/ | |||
typedef int (*thrd_start_t)(void *arg); | |||
/** Create a new thread. | |||
* @param thr Identifier of the newly created thread. | |||
* @param func A function pointer to the function that will be executed in | |||
* the new thread. | |||
* @param arg An argument to the thread function. | |||
* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could | |||
* be allocated for the thread requested, or @ref thrd_error if the request | |||
* could not be honored. | |||
* @note A thread’s identifier may be reused for a different thread once the | |||
* original thread has exited and either been detached or joined to another | |||
* thread. | |||
*/ | |||
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); | |||
/** Identify the calling thread. | |||
* @return The identifier of the calling thread. | |||
*/ | |||
thrd_t thrd_current(void); | |||
/** NOT YET IMPLEMENTED. | |||
*/ | |||
int thrd_detach(thrd_t thr); | |||
/** Compare two thread identifiers. | |||
* The function determines if two thread identifiers refer to the same thread. | |||
* @return Zero if the two thread identifiers refer to different threads. | |||
* Otherwise a nonzero value is returned. | |||
*/ | |||
int thrd_equal(thrd_t thr0, thrd_t thr1); | |||
/** Terminate execution of the calling thread. | |||
* @param res Result code of the calling thread. | |||
*/ | |||
void thrd_exit(int res); | |||
/** Wait for a thread to terminate. | |||
* The function joins the given thread with the current thread by blocking | |||
* until the other thread has terminated. | |||
* @param thr The thread to join with. | |||
* @param res If this pointer is not NULL, the function will store the result | |||
* code of the given thread in the integer pointed to by @c res. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int thrd_join(thrd_t thr, int *res); | |||
/** Put the calling thread to sleep. | |||
* Suspend execution of the calling thread. | |||
* @param time_point A point in time at which the thread will resume (absolute time). | |||
* @param remaining If non-NULL, this parameter will hold the remaining time until | |||
* time_point upon return. This will typically be zero, but if | |||
* the thread was woken up by a signal that is not ignored before | |||
* time_point was reached @c remaining will hold a positive | |||
* time. | |||
* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. | |||
*/ | |||
int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); | |||
/** Yield execution to another thread. | |||
* Permit other threads to run, even if the current thread would ordinarily | |||
* continue to run. | |||
*/ | |||
void thrd_yield(void); | |||
/* Thread local storage */ | |||
#if defined(_TTHREAD_WIN32_) | |||
typedef DWORD tss_t; | |||
#else | |||
typedef pthread_key_t tss_t; | |||
#endif | |||
/** Destructor function for a thread-specific storage. | |||
* @param val The value of the destructed thread-specific storage. | |||
*/ | |||
typedef void (*tss_dtor_t)(void *val); | |||
/** Create a thread-specific storage. | |||
* @param key The unique key identifier that will be set if the function is | |||
* successful. | |||
* @param dtor Destructor function. This can be NULL. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
* @note The destructor function is not supported under Windows. If @c dtor is | |||
* not NULL when calling this function under Windows, the function will fail | |||
* and return @ref thrd_error. | |||
*/ | |||
int tss_create(tss_t *key, tss_dtor_t dtor); | |||
/** Delete a thread-specific storage. | |||
* The function releases any resources used by the given thread-specific | |||
* storage. | |||
* @param key The key that shall be deleted. | |||
*/ | |||
void tss_delete(tss_t key); | |||
/** Get the value for a thread-specific storage. | |||
* @param key The thread-specific storage identifier. | |||
* @return The value for the current thread held in the given thread-specific | |||
* storage. | |||
*/ | |||
void *tss_get(tss_t key); | |||
/** Set the value for a thread-specific storage. | |||
* @param key The thread-specific storage identifier. | |||
* @param val The value of the thread-specific storage to set for the current | |||
* thread. | |||
* @return @ref thrd_success on success, or @ref thrd_error if the request could | |||
* not be honored. | |||
*/ | |||
int tss_set(tss_t key, void *val); | |||
#endif /* _TINYTHREAD_H_ */ | |||
@ -1,120 +1,92 @@ | |||
// | |||
// File: vk_platform.h | |||
// | |||
/* | |||
** Copyright (c) 2014-2015 The Khronos Group Inc. | |||
** | |||
** Licensed under the Apache License, Version 2.0 (the "License"); | |||
** you may not use this file except in compliance with the License. | |||
** You may obtain a copy of the License at | |||
** | |||
** http://www.apache.org/licenses/LICENSE-2.0 | |||
** | |||
** Unless required by applicable law or agreed to in writing, software | |||
** distributed under the License is distributed on an "AS IS" BASIS, | |||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
** See the License for the specific language governing permissions and | |||
** limitations under the License. | |||
*/ | |||
#ifndef VK_PLATFORM_H_ | |||
#define VK_PLATFORM_H_ | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif // __cplusplus | |||
/* | |||
*************************************************************************************************** | |||
* Platform-specific directives and type declarations | |||
*************************************************************************************************** | |||
*/ | |||
/* Platform-specific calling convention macros. | |||
* | |||
* Platforms should define these so that Vulkan clients call Vulkan commands | |||
* with the same calling conventions that the Vulkan implementation expects. | |||
* | |||
* VKAPI_ATTR - Placed before the return type in function declarations. | |||
* Useful for C++11 and GCC/Clang-style function attribute syntax. | |||
* VKAPI_CALL - Placed after the return type in function declarations. | |||
* Useful for MSVC-style calling convention syntax. | |||
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types. | |||
* | |||
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); | |||
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); | |||
*/ | |||
#if defined(_WIN32) | |||
// On Windows, Vulkan commands use the stdcall convention | |||
#define VKAPI_ATTR | |||
#define VKAPI_CALL __stdcall | |||
#define VKAPI_PTR VKAPI_CALL | |||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 | |||
#error "Vulkan isn't supported for the 'armeabi' NDK ABI" | |||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) | |||
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" | |||
// calling convention, i.e. float parameters are passed in registers. This | |||
// is true even if the rest of the application passes floats on the stack, | |||
// as it does by default when compiling for the armeabi-v7a NDK ABI. | |||
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) | |||
#define VKAPI_CALL | |||
#define VKAPI_PTR VKAPI_ATTR | |||
#else | |||
// On other platforms, use the default calling convention | |||
#define VKAPI_ATTR | |||
#define VKAPI_CALL | |||
#define VKAPI_PTR | |||
#endif | |||
#include <stddef.h> | |||
#if !defined(VK_NO_STDINT_H) | |||
#if defined(_MSC_VER) && (_MSC_VER < 1600) | |||
typedef signed __int8 int8_t; | |||
typedef unsigned __int8 uint8_t; | |||
typedef signed __int16 int16_t; | |||
typedef unsigned __int16 uint16_t; | |||
typedef signed __int32 int32_t; | |||
typedef unsigned __int32 uint32_t; | |||
typedef signed __int64 int64_t; | |||
typedef unsigned __int64 uint64_t; | |||
#else | |||
#include <stdint.h> | |||
#endif | |||
#endif // !defined(VK_NO_STDINT_H) | |||
#ifdef __cplusplus | |||
} // extern "C" | |||
#endif // __cplusplus | |||
// Platform-specific headers required by platform window system extensions. | |||
// These are enabled prior to #including "vulkan.h". The same enable then | |||
// controls inclusion of the extension interfaces in vulkan.h. | |||
#ifdef VK_USE_PLATFORM_ANDROID_KHR | |||
#include <android/native_window.h> | |||
#endif | |||
#ifdef VK_USE_PLATFORM_MIR_KHR | |||
#include <mir_toolkit/client_types.h> | |||
#endif | |||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR | |||
#include <wayland-client.h> | |||
#endif | |||
#ifdef VK_USE_PLATFORM_WIN32_KHR | |||
#include <windows.h> | |||
#endif | |||
#ifdef VK_USE_PLATFORM_XLIB_KHR | |||
#include <X11/Xlib.h> | |||
#endif | |||
#ifdef VK_USE_PLATFORM_XCB_KHR | |||
#include <xcb/xcb.h> | |||
#endif | |||
#endif | |||
// | |||
// File: vk_platform.h | |||
// | |||
/* | |||
** Copyright (c) 2014-2017 The Khronos Group Inc. | |||
** | |||
** Licensed under the Apache License, Version 2.0 (the "License"); | |||
** you may not use this file except in compliance with the License. | |||
** You may obtain a copy of the License at | |||
** | |||
** http://www.apache.org/licenses/LICENSE-2.0 | |||
** | |||
** Unless required by applicable law or agreed to in writing, software | |||
** distributed under the License is distributed on an "AS IS" BASIS, | |||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
** See the License for the specific language governing permissions and | |||
** limitations under the License. | |||
*/ | |||
#ifndef VK_PLATFORM_H_ | |||
#define VK_PLATFORM_H_ | |||
#ifdef __cplusplus | |||
extern "C" | |||
{ | |||
#endif // __cplusplus | |||
/* | |||
*************************************************************************************************** | |||
* Platform-specific directives and type declarations | |||
*************************************************************************************************** | |||
*/ | |||
/* Platform-specific calling convention macros. | |||
* | |||
* Platforms should define these so that Vulkan clients call Vulkan commands | |||
* with the same calling conventions that the Vulkan implementation expects. | |||
* | |||
* VKAPI_ATTR - Placed before the return type in function declarations. | |||
* Useful for C++11 and GCC/Clang-style function attribute syntax. | |||
* VKAPI_CALL - Placed after the return type in function declarations. | |||
* Useful for MSVC-style calling convention syntax. | |||
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types. | |||
* | |||
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void); | |||
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); | |||
*/ | |||
#if defined(_WIN32) | |||
// On Windows, Vulkan commands use the stdcall convention | |||
#define VKAPI_ATTR | |||
#define VKAPI_CALL __stdcall | |||
#define VKAPI_PTR VKAPI_CALL | |||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 | |||
#error "Vulkan isn't supported for the 'armeabi' NDK ABI" | |||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) | |||
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" | |||
// calling convention, i.e. float parameters are passed in registers. This | |||
// is true even if the rest of the application passes floats on the stack, | |||
// as it does by default when compiling for the armeabi-v7a NDK ABI. | |||
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) | |||
#define VKAPI_CALL | |||
#define VKAPI_PTR VKAPI_ATTR | |||
#else | |||
// On other platforms, use the default calling convention | |||
#define VKAPI_ATTR | |||
#define VKAPI_CALL | |||
#define VKAPI_PTR | |||
#endif | |||
#include <stddef.h> | |||
#if !defined(VK_NO_STDINT_H) | |||
#if defined(_MSC_VER) && (_MSC_VER < 1600) | |||
typedef signed __int8 int8_t; | |||
typedef unsigned __int8 uint8_t; | |||
typedef signed __int16 int16_t; | |||
typedef unsigned __int16 uint16_t; | |||
typedef signed __int32 int32_t; | |||
typedef unsigned __int32 uint32_t; | |||
typedef signed __int64 int64_t; | |||
typedef unsigned __int64 uint64_t; | |||
#else | |||
#include <stdint.h> | |||
#endif | |||
#endif // !defined(VK_NO_STDINT_H) | |||
#ifdef __cplusplus | |||
} // extern "C" | |||
#endif // __cplusplus | |||
#endif |