first commit
This commit is contained in:
commit
8f29bc7e21
2
bat/clean.bat
Normal file
2
bat/clean.bat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
cd ..\
|
||||||
|
premake5 clean
|
2
bat/premake_vs2015.bat
Normal file
2
bat/premake_vs2015.bat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
cd ..\
|
||||||
|
premake5 solution
|
14
building.txt
Normal file
14
building.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Bounce uses premake for generating project files in a platform agnostic manner.
|
||||||
|
|
||||||
|
Grab premake from http://industriousone.com/premake.
|
||||||
|
Put premake.exe into bounce/.
|
||||||
|
|
||||||
|
Visual Studio 2015
|
||||||
|
|
||||||
|
Open bounce/bat.
|
||||||
|
Open premake_vs2015.bat. This will run a premake script and open bounce/build/vs2015/bounce.sln.
|
||||||
|
Set testbed as the startup project.
|
||||||
|
Press F5 or Ctrl-F5 to run.
|
||||||
|
|
||||||
|
premake files for building on Mac will be available later because I don't run Mac currently and
|
||||||
|
therefore can't test the build system in this platform.
|
8
documenting.txt
Normal file
8
documenting.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Generating API Documentation
|
||||||
|
|
||||||
|
Grab Doxygen from http://www.doxygen.org
|
||||||
|
Say the following on the command line: doxygen doxyfile
|
||||||
|
Open doc/api/html/index.html
|
||||||
|
|
||||||
|
User manual is a work in progress. Meanwhile, code comments are the best way to learn how to use
|
||||||
|
Bounce.
|
8973
external/glad/glad.c
vendored
Normal file
8973
external/glad/glad.c
vendored
Normal file
File diff suppressed because one or more lines are too long
16287
external/glad/glad.h
vendored
Normal file
16287
external/glad/glad.h
vendored
Normal file
File diff suppressed because one or more lines are too long
285
external/glad/khrplatform.h
vendored
Normal file
285
external/glad/khrplatform.h
vendored
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
#ifndef __khrplatform_h_
|
||||||
|
#define __khrplatform_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2008-2009 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
** the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included
|
||||||
|
** in all copies or substantial portions of the Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Khronos platform-specific types and definitions.
|
||||||
|
*
|
||||||
|
* $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
|
||||||
|
*
|
||||||
|
* Adopters may modify this file to suit their platform. Adopters are
|
||||||
|
* encouraged to submit platform specific modifications to the Khronos
|
||||||
|
* group so that they can be included in future versions of this file.
|
||||||
|
* Please submit changes by sending them to the public Khronos Bugzilla
|
||||||
|
* (http://khronos.org/bugzilla) by filing a bug against product
|
||||||
|
* "Khronos (general)" component "Registry".
|
||||||
|
*
|
||||||
|
* A predefined template which fills in some of the bug fields can be
|
||||||
|
* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
|
||||||
|
* must create a Bugzilla login first.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Implementer's Guidelines for information about where this file
|
||||||
|
* should be located on your system and for more details of its use:
|
||||||
|
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||||
|
*
|
||||||
|
* This file should be included as
|
||||||
|
* #include <KHR/khrplatform.h>
|
||||||
|
* by Khronos client API header files that use its types and defines.
|
||||||
|
*
|
||||||
|
* The types in khrplatform.h should only be used to define API-specific types.
|
||||||
|
*
|
||||||
|
* Types defined in khrplatform.h:
|
||||||
|
* khronos_int8_t signed 8 bit
|
||||||
|
* khronos_uint8_t unsigned 8 bit
|
||||||
|
* khronos_int16_t signed 16 bit
|
||||||
|
* khronos_uint16_t unsigned 16 bit
|
||||||
|
* khronos_int32_t signed 32 bit
|
||||||
|
* khronos_uint32_t unsigned 32 bit
|
||||||
|
* khronos_int64_t signed 64 bit
|
||||||
|
* khronos_uint64_t unsigned 64 bit
|
||||||
|
* khronos_intptr_t signed same number of bits as a pointer
|
||||||
|
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||||
|
* khronos_ssize_t signed size
|
||||||
|
* khronos_usize_t unsigned size
|
||||||
|
* khronos_float_t signed 32 bit floating point
|
||||||
|
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||||
|
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||||
|
* nanoseconds
|
||||||
|
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||||
|
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||||
|
* only be used as a base type when a client API's boolean type is
|
||||||
|
* an enum. Client APIs which use an integer or other type for
|
||||||
|
* booleans cannot use this as the base type for their boolean.
|
||||||
|
*
|
||||||
|
* Tokens defined in khrplatform.h:
|
||||||
|
*
|
||||||
|
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||||
|
*
|
||||||
|
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||||
|
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||||
|
*
|
||||||
|
* Calling convention macros defined in this file:
|
||||||
|
* KHRONOS_APICALL
|
||||||
|
* KHRONOS_APIENTRY
|
||||||
|
* KHRONOS_APIATTRIBUTES
|
||||||
|
*
|
||||||
|
* These may be used in function prototypes as:
|
||||||
|
*
|
||||||
|
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||||
|
* int arg1,
|
||||||
|
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APICALL
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This precedes the return type of the function in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
# define KHRONOS_APICALL __declspec(dllimport)
|
||||||
|
#elif defined (__SYMBIAN32__)
|
||||||
|
# define KHRONOS_APICALL IMPORT_C
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# include <sys/cdefs.h>
|
||||||
|
# define KHRONOS_APICALL __attribute__((visibility("default"))) __NDK_FPABI__
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIENTRY
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the return type of the function and precedes the function
|
||||||
|
* name in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||||
|
/* Win32 but not WinCE */
|
||||||
|
# define KHRONOS_APIENTRY __stdcall
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APIENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIATTRIBUTES
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the closing parenthesis of the function prototype arguments.
|
||||||
|
*/
|
||||||
|
#if defined (__ARMCC_2__)
|
||||||
|
#define KHRONOS_APIATTRIBUTES __softfp
|
||||||
|
#else
|
||||||
|
#define KHRONOS_APIATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* basic type definitions
|
||||||
|
*-----------------------------------------------------------------------*/
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <stdint.h>
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__VMS ) || defined(__sgi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <inttypes.h>
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Win32
|
||||||
|
*/
|
||||||
|
typedef __int32 khronos_int32_t;
|
||||||
|
typedef unsigned __int32 khronos_uint32_t;
|
||||||
|
typedef __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__sun__) || defined(__digital__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun or Digital
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#if defined(__arch64__) || defined(_LP64)
|
||||||
|
typedef long int khronos_int64_t;
|
||||||
|
typedef unsigned long int khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef long long int khronos_int64_t;
|
||||||
|
typedef unsigned long long int khronos_uint64_t;
|
||||||
|
#endif /* __arch64__ */
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypothetical platform with no float or int64 support
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 0
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic fallback
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that are (so far) the same on all platforms
|
||||||
|
*/
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||||
|
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||||
|
* to be the only LLP64 architecture in current use.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef unsigned long long int khronos_uintptr_t;
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
typedef unsigned long long int khronos_usize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef unsigned long int khronos_uintptr_t;
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
typedef unsigned long int khronos_usize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_FLOAT
|
||||||
|
/*
|
||||||
|
* Float type
|
||||||
|
*/
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_INT64
|
||||||
|
/* Time types
|
||||||
|
*
|
||||||
|
* These types can be used to represent a time interval in nanoseconds or
|
||||||
|
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||||
|
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||||
|
* time the system booted). The Unadjusted System Time is an unsigned
|
||||||
|
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||||
|
* may be either signed or unsigned.
|
||||||
|
*/
|
||||||
|
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||||
|
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy value used to pad enum types to 32 bits.
|
||||||
|
*/
|
||||||
|
#ifndef KHRONOS_MAX_ENUM
|
||||||
|
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerated boolean type
|
||||||
|
*
|
||||||
|
* Values other than zero should be considered to be true. Therefore
|
||||||
|
* comparisons should not be made against KHRONOS_TRUE.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
KHRONOS_FALSE = 0,
|
||||||
|
KHRONOS_TRUE = 1,
|
||||||
|
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||||
|
} khronos_boolean_enum_t;
|
||||||
|
|
||||||
|
#endif /* __khrplatform_h_ */
|
121
external/glfw/CMakeLists.txt
vendored
Normal file
121
external/glfw/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
add_definitions(-D_GLFW_USE_CONFIG_H)
|
||||||
|
|
||||||
|
set(common_HEADERS internal.h
|
||||||
|
"${GLFW_BINARY_DIR}/src/glfw_config.h"
|
||||||
|
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
|
||||||
|
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h")
|
||||||
|
set(common_SOURCES context.c init.c input.c monitor.c vulkan.c window.c)
|
||||||
|
|
||||||
|
if (_GLFW_COCOA)
|
||||||
|
set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h cocoa_joystick.h
|
||||||
|
posix_tls.h nsgl_context.h)
|
||||||
|
set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_joystick.m
|
||||||
|
cocoa_monitor.m cocoa_window.m cocoa_time.c posix_tls.c
|
||||||
|
nsgl_context.m)
|
||||||
|
elseif (_GLFW_WIN32)
|
||||||
|
set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_joystick.h
|
||||||
|
wgl_context.h egl_context.h)
|
||||||
|
set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_joystick.c
|
||||||
|
win32_monitor.c win32_time.c win32_tls.c win32_window.c
|
||||||
|
wgl_context.c egl_context.c)
|
||||||
|
elseif (_GLFW_X11)
|
||||||
|
set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h
|
||||||
|
linux_joystick.h posix_time.h posix_tls.h glx_context.h
|
||||||
|
egl_context.h)
|
||||||
|
set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c
|
||||||
|
xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c
|
||||||
|
glx_context.c egl_context.c)
|
||||||
|
elseif (_GLFW_WAYLAND)
|
||||||
|
set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h
|
||||||
|
posix_time.h posix_tls.h xkb_unicode.h egl_context.h)
|
||||||
|
set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c
|
||||||
|
linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c
|
||||||
|
egl_context.c)
|
||||||
|
|
||||||
|
ecm_add_wayland_client_protocol(glfw_SOURCES
|
||||||
|
PROTOCOL
|
||||||
|
${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml
|
||||||
|
BASENAME relative-pointer-unstable-v1)
|
||||||
|
ecm_add_wayland_client_protocol(glfw_SOURCES
|
||||||
|
PROTOCOL
|
||||||
|
${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
|
||||||
|
BASENAME pointer-constraints-unstable-v1)
|
||||||
|
elseif (_GLFW_MIR)
|
||||||
|
set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
|
||||||
|
posix_time.h posix_tls.h xkb_unicode.h egl_context.h)
|
||||||
|
set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c
|
||||||
|
linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c
|
||||||
|
egl_context.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
# For some reason, CMake doesn't know about .m
|
||||||
|
set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS})
|
||||||
|
set_target_properties(glfw PROPERTIES
|
||||||
|
OUTPUT_NAME ${GLFW_LIB_NAME}
|
||||||
|
VERSION ${GLFW_VERSION}
|
||||||
|
SOVERSION ${GLFW_VERSION_MAJOR}
|
||||||
|
POSITION_INDEPENDENT_CODE ON
|
||||||
|
FOLDER "GLFW3")
|
||||||
|
|
||||||
|
target_compile_definitions(glfw PRIVATE -D_GLFW_USE_CONFIG_H)
|
||||||
|
target_include_directories(glfw PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)
|
||||||
|
target_include_directories(glfw PRIVATE
|
||||||
|
"${GLFW_SOURCE_DIR}/src"
|
||||||
|
"${GLFW_BINARY_DIR}/src"
|
||||||
|
${glfw_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# HACK: When building on MinGW, WINVER and UNICODE need to be defined before
|
||||||
|
# the inclusion of stddef.h (by glfw3.h), which is itself included before
|
||||||
|
# win32_platform.h. We define them here until a saner solution can be found
|
||||||
|
# NOTE: MinGW-w64 and Visual C++ do /not/ need this hack.
|
||||||
|
target_compile_definitions(glfw PRIVATE
|
||||||
|
"$<$<BOOL:${MINGW}>:UNICODE;WINVER=0x0501>")
|
||||||
|
|
||||||
|
# Enable a reasonable set of warnings (no, -Wextra is not reasonable)
|
||||||
|
target_compile_options(glfw PRIVATE
|
||||||
|
"$<$<C_COMPILER_ID:Clang>:-Wall>"
|
||||||
|
"$<$<C_COMPILER_ID:GNU>:-Wall>")
|
||||||
|
|
||||||
|
if (BUILD_SHARED_LIBS)
|
||||||
|
if (WIN32)
|
||||||
|
if (MINGW)
|
||||||
|
# Remove the lib prefix on the DLL (but not the import library
|
||||||
|
set_target_properties(glfw PROPERTIES PREFIX "")
|
||||||
|
|
||||||
|
# Add a suffix to the import library to avoid naming conflicts
|
||||||
|
set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a")
|
||||||
|
else()
|
||||||
|
# Add a suffix to the import library to avoid naming conflicts
|
||||||
|
set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib")
|
||||||
|
endif()
|
||||||
|
elseif (APPLE)
|
||||||
|
# Add -fno-common to work around a bug in Apple's GCC
|
||||||
|
target_compile_options(glfw PRIVATE "-fno-common")
|
||||||
|
|
||||||
|
set_target_properties(glfw PROPERTIES
|
||||||
|
INSTALL_NAME_DIR "lib${LIB_SUFFIX}")
|
||||||
|
elseif (UNIX)
|
||||||
|
# Hide symbols not explicitly tagged for export from the shared library
|
||||||
|
target_compile_options(glfw PRIVATE "-fvisibility=hidden")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(glfw INTERFACE -DGLFW_DLL)
|
||||||
|
target_link_libraries(glfw PRIVATE ${glfw_LIBRARIES})
|
||||||
|
else()
|
||||||
|
target_link_libraries(glfw INTERFACE ${glfw_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
target_compile_definitions(glfw PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (GLFW_INSTALL)
|
||||||
|
install(TARGETS glfw EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX})
|
||||||
|
endif()
|
||||||
|
|
398
external/glfw/cocoa_init.m
vendored
Normal file
398
external/glfw/cocoa_init.m
vendored
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include <sys/param.h> // For MAXPATHLEN
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_GLFW_USE_CHDIR)
|
||||||
|
|
||||||
|
// Change to our application bundle's resources directory, if present
|
||||||
|
//
|
||||||
|
static void changeToResourcesDirectory(void)
|
||||||
|
{
|
||||||
|
char resourcesPath[MAXPATHLEN];
|
||||||
|
|
||||||
|
CFBundleRef bundle = CFBundleGetMainBundle();
|
||||||
|
if (!bundle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
|
||||||
|
|
||||||
|
CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
|
||||||
|
if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
|
||||||
|
{
|
||||||
|
CFRelease(last);
|
||||||
|
CFRelease(resourcesURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(last);
|
||||||
|
|
||||||
|
if (!CFURLGetFileSystemRepresentation(resourcesURL,
|
||||||
|
true,
|
||||||
|
(UInt8*) resourcesPath,
|
||||||
|
MAXPATHLEN))
|
||||||
|
{
|
||||||
|
CFRelease(resourcesURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(resourcesURL);
|
||||||
|
|
||||||
|
chdir(resourcesPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _GLFW_USE_CHDIR */
|
||||||
|
|
||||||
|
// Create key code translation tables
|
||||||
|
//
|
||||||
|
static void createKeyTables(void)
|
||||||
|
{
|
||||||
|
int scancode;
|
||||||
|
|
||||||
|
memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys));
|
||||||
|
memset(_glfw.ns.nativeKeys, -1, sizeof(_glfw.ns.nativeKeys));
|
||||||
|
|
||||||
|
_glfw.ns.publicKeys[0x1D] = GLFW_KEY_0;
|
||||||
|
_glfw.ns.publicKeys[0x12] = GLFW_KEY_1;
|
||||||
|
_glfw.ns.publicKeys[0x13] = GLFW_KEY_2;
|
||||||
|
_glfw.ns.publicKeys[0x14] = GLFW_KEY_3;
|
||||||
|
_glfw.ns.publicKeys[0x15] = GLFW_KEY_4;
|
||||||
|
_glfw.ns.publicKeys[0x17] = GLFW_KEY_5;
|
||||||
|
_glfw.ns.publicKeys[0x16] = GLFW_KEY_6;
|
||||||
|
_glfw.ns.publicKeys[0x1A] = GLFW_KEY_7;
|
||||||
|
_glfw.ns.publicKeys[0x1C] = GLFW_KEY_8;
|
||||||
|
_glfw.ns.publicKeys[0x19] = GLFW_KEY_9;
|
||||||
|
_glfw.ns.publicKeys[0x00] = GLFW_KEY_A;
|
||||||
|
_glfw.ns.publicKeys[0x0B] = GLFW_KEY_B;
|
||||||
|
_glfw.ns.publicKeys[0x08] = GLFW_KEY_C;
|
||||||
|
_glfw.ns.publicKeys[0x02] = GLFW_KEY_D;
|
||||||
|
_glfw.ns.publicKeys[0x0E] = GLFW_KEY_E;
|
||||||
|
_glfw.ns.publicKeys[0x03] = GLFW_KEY_F;
|
||||||
|
_glfw.ns.publicKeys[0x05] = GLFW_KEY_G;
|
||||||
|
_glfw.ns.publicKeys[0x04] = GLFW_KEY_H;
|
||||||
|
_glfw.ns.publicKeys[0x22] = GLFW_KEY_I;
|
||||||
|
_glfw.ns.publicKeys[0x26] = GLFW_KEY_J;
|
||||||
|
_glfw.ns.publicKeys[0x28] = GLFW_KEY_K;
|
||||||
|
_glfw.ns.publicKeys[0x25] = GLFW_KEY_L;
|
||||||
|
_glfw.ns.publicKeys[0x2E] = GLFW_KEY_M;
|
||||||
|
_glfw.ns.publicKeys[0x2D] = GLFW_KEY_N;
|
||||||
|
_glfw.ns.publicKeys[0x1F] = GLFW_KEY_O;
|
||||||
|
_glfw.ns.publicKeys[0x23] = GLFW_KEY_P;
|
||||||
|
_glfw.ns.publicKeys[0x0C] = GLFW_KEY_Q;
|
||||||
|
_glfw.ns.publicKeys[0x0F] = GLFW_KEY_R;
|
||||||
|
_glfw.ns.publicKeys[0x01] = GLFW_KEY_S;
|
||||||
|
_glfw.ns.publicKeys[0x11] = GLFW_KEY_T;
|
||||||
|
_glfw.ns.publicKeys[0x20] = GLFW_KEY_U;
|
||||||
|
_glfw.ns.publicKeys[0x09] = GLFW_KEY_V;
|
||||||
|
_glfw.ns.publicKeys[0x0D] = GLFW_KEY_W;
|
||||||
|
_glfw.ns.publicKeys[0x07] = GLFW_KEY_X;
|
||||||
|
_glfw.ns.publicKeys[0x10] = GLFW_KEY_Y;
|
||||||
|
_glfw.ns.publicKeys[0x06] = GLFW_KEY_Z;
|
||||||
|
|
||||||
|
_glfw.ns.publicKeys[0x27] = GLFW_KEY_APOSTROPHE;
|
||||||
|
_glfw.ns.publicKeys[0x2A] = GLFW_KEY_BACKSLASH;
|
||||||
|
_glfw.ns.publicKeys[0x2B] = GLFW_KEY_COMMA;
|
||||||
|
_glfw.ns.publicKeys[0x18] = GLFW_KEY_EQUAL;
|
||||||
|
_glfw.ns.publicKeys[0x32] = GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
_glfw.ns.publicKeys[0x21] = GLFW_KEY_LEFT_BRACKET;
|
||||||
|
_glfw.ns.publicKeys[0x1B] = GLFW_KEY_MINUS;
|
||||||
|
_glfw.ns.publicKeys[0x2F] = GLFW_KEY_PERIOD;
|
||||||
|
_glfw.ns.publicKeys[0x1E] = GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
_glfw.ns.publicKeys[0x29] = GLFW_KEY_SEMICOLON;
|
||||||
|
_glfw.ns.publicKeys[0x2C] = GLFW_KEY_SLASH;
|
||||||
|
_glfw.ns.publicKeys[0x0A] = GLFW_KEY_WORLD_1;
|
||||||
|
|
||||||
|
_glfw.ns.publicKeys[0x33] = GLFW_KEY_BACKSPACE;
|
||||||
|
_glfw.ns.publicKeys[0x39] = GLFW_KEY_CAPS_LOCK;
|
||||||
|
_glfw.ns.publicKeys[0x75] = GLFW_KEY_DELETE;
|
||||||
|
_glfw.ns.publicKeys[0x7D] = GLFW_KEY_DOWN;
|
||||||
|
_glfw.ns.publicKeys[0x77] = GLFW_KEY_END;
|
||||||
|
_glfw.ns.publicKeys[0x24] = GLFW_KEY_ENTER;
|
||||||
|
_glfw.ns.publicKeys[0x35] = GLFW_KEY_ESCAPE;
|
||||||
|
_glfw.ns.publicKeys[0x7A] = GLFW_KEY_F1;
|
||||||
|
_glfw.ns.publicKeys[0x78] = GLFW_KEY_F2;
|
||||||
|
_glfw.ns.publicKeys[0x63] = GLFW_KEY_F3;
|
||||||
|
_glfw.ns.publicKeys[0x76] = GLFW_KEY_F4;
|
||||||
|
_glfw.ns.publicKeys[0x60] = GLFW_KEY_F5;
|
||||||
|
_glfw.ns.publicKeys[0x61] = GLFW_KEY_F6;
|
||||||
|
_glfw.ns.publicKeys[0x62] = GLFW_KEY_F7;
|
||||||
|
_glfw.ns.publicKeys[0x64] = GLFW_KEY_F8;
|
||||||
|
_glfw.ns.publicKeys[0x65] = GLFW_KEY_F9;
|
||||||
|
_glfw.ns.publicKeys[0x6D] = GLFW_KEY_F10;
|
||||||
|
_glfw.ns.publicKeys[0x67] = GLFW_KEY_F11;
|
||||||
|
_glfw.ns.publicKeys[0x6F] = GLFW_KEY_F12;
|
||||||
|
_glfw.ns.publicKeys[0x69] = GLFW_KEY_F13;
|
||||||
|
_glfw.ns.publicKeys[0x6B] = GLFW_KEY_F14;
|
||||||
|
_glfw.ns.publicKeys[0x71] = GLFW_KEY_F15;
|
||||||
|
_glfw.ns.publicKeys[0x6A] = GLFW_KEY_F16;
|
||||||
|
_glfw.ns.publicKeys[0x40] = GLFW_KEY_F17;
|
||||||
|
_glfw.ns.publicKeys[0x4F] = GLFW_KEY_F18;
|
||||||
|
_glfw.ns.publicKeys[0x50] = GLFW_KEY_F19;
|
||||||
|
_glfw.ns.publicKeys[0x5A] = GLFW_KEY_F20;
|
||||||
|
_glfw.ns.publicKeys[0x73] = GLFW_KEY_HOME;
|
||||||
|
_glfw.ns.publicKeys[0x72] = GLFW_KEY_INSERT;
|
||||||
|
_glfw.ns.publicKeys[0x7B] = GLFW_KEY_LEFT;
|
||||||
|
_glfw.ns.publicKeys[0x3A] = GLFW_KEY_LEFT_ALT;
|
||||||
|
_glfw.ns.publicKeys[0x3B] = GLFW_KEY_LEFT_CONTROL;
|
||||||
|
_glfw.ns.publicKeys[0x38] = GLFW_KEY_LEFT_SHIFT;
|
||||||
|
_glfw.ns.publicKeys[0x37] = GLFW_KEY_LEFT_SUPER;
|
||||||
|
_glfw.ns.publicKeys[0x6E] = GLFW_KEY_MENU;
|
||||||
|
_glfw.ns.publicKeys[0x47] = GLFW_KEY_NUM_LOCK;
|
||||||
|
_glfw.ns.publicKeys[0x79] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
_glfw.ns.publicKeys[0x74] = GLFW_KEY_PAGE_UP;
|
||||||
|
_glfw.ns.publicKeys[0x7C] = GLFW_KEY_RIGHT;
|
||||||
|
_glfw.ns.publicKeys[0x3D] = GLFW_KEY_RIGHT_ALT;
|
||||||
|
_glfw.ns.publicKeys[0x3E] = GLFW_KEY_RIGHT_CONTROL;
|
||||||
|
_glfw.ns.publicKeys[0x3C] = GLFW_KEY_RIGHT_SHIFT;
|
||||||
|
_glfw.ns.publicKeys[0x36] = GLFW_KEY_RIGHT_SUPER;
|
||||||
|
_glfw.ns.publicKeys[0x31] = GLFW_KEY_SPACE;
|
||||||
|
_glfw.ns.publicKeys[0x30] = GLFW_KEY_TAB;
|
||||||
|
_glfw.ns.publicKeys[0x7E] = GLFW_KEY_UP;
|
||||||
|
|
||||||
|
_glfw.ns.publicKeys[0x52] = GLFW_KEY_KP_0;
|
||||||
|
_glfw.ns.publicKeys[0x53] = GLFW_KEY_KP_1;
|
||||||
|
_glfw.ns.publicKeys[0x54] = GLFW_KEY_KP_2;
|
||||||
|
_glfw.ns.publicKeys[0x55] = GLFW_KEY_KP_3;
|
||||||
|
_glfw.ns.publicKeys[0x56] = GLFW_KEY_KP_4;
|
||||||
|
_glfw.ns.publicKeys[0x57] = GLFW_KEY_KP_5;
|
||||||
|
_glfw.ns.publicKeys[0x58] = GLFW_KEY_KP_6;
|
||||||
|
_glfw.ns.publicKeys[0x59] = GLFW_KEY_KP_7;
|
||||||
|
_glfw.ns.publicKeys[0x5B] = GLFW_KEY_KP_8;
|
||||||
|
_glfw.ns.publicKeys[0x5C] = GLFW_KEY_KP_9;
|
||||||
|
_glfw.ns.publicKeys[0x45] = GLFW_KEY_KP_ADD;
|
||||||
|
_glfw.ns.publicKeys[0x41] = GLFW_KEY_KP_DECIMAL;
|
||||||
|
_glfw.ns.publicKeys[0x4B] = GLFW_KEY_KP_DIVIDE;
|
||||||
|
_glfw.ns.publicKeys[0x4C] = GLFW_KEY_KP_ENTER;
|
||||||
|
_glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL;
|
||||||
|
_glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY;
|
||||||
|
_glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT;
|
||||||
|
|
||||||
|
for (scancode = 0; scancode < 256; scancode++)
|
||||||
|
{
|
||||||
|
// Store the reverse translation for faster key name lookup
|
||||||
|
if (_glfw.ns.publicKeys[scancode] >= 0)
|
||||||
|
_glfw.ns.nativeKeys[_glfw.ns.publicKeys[scancode]] = scancode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve Unicode data for the current keyboard layout
|
||||||
|
//
|
||||||
|
static GLFWbool updateUnicodeDataNS(void)
|
||||||
|
{
|
||||||
|
if (_glfw.ns.inputSource)
|
||||||
|
{
|
||||||
|
CFRelease(_glfw.ns.inputSource);
|
||||||
|
_glfw.ns.inputSource = NULL;
|
||||||
|
_glfw.ns.unicodeData = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
|
||||||
|
if (!_glfw.ns.inputSource)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to retrieve keyboard layout input source");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.ns.unicodeData = TISGetInputSourceProperty(_glfw.ns.inputSource,
|
||||||
|
kTISPropertyUnicodeKeyLayoutData);
|
||||||
|
if (!_glfw.ns.unicodeData)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to retrieve keyboard layout Unicode data");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load HIToolbox.framework and the TIS symbols we need from it
|
||||||
|
//
|
||||||
|
static GLFWbool initializeTIS(void)
|
||||||
|
{
|
||||||
|
// This works only because Cocoa has already loaded it properly
|
||||||
|
_glfw.ns.tis.bundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
|
||||||
|
if (!_glfw.ns.tis.bundle)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to load HIToolbox.framework");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef* kPropertyUnicodeKeyLayoutData =
|
||||||
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("kTISPropertyUnicodeKeyLayoutData"));
|
||||||
|
CFStringRef* kNotifySelectedKeyboardInputSourceChanged =
|
||||||
|
CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("kTISNotifySelectedKeyboardInputSourceChanged"));
|
||||||
|
_glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
|
||||||
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
|
||||||
|
_glfw.ns.tis.GetInputSourceProperty =
|
||||||
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("TISGetInputSourceProperty"));
|
||||||
|
_glfw.ns.tis.GetKbdType =
|
||||||
|
CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
|
||||||
|
CFSTR("LMGetKbdType"));
|
||||||
|
|
||||||
|
if (!kPropertyUnicodeKeyLayoutData ||
|
||||||
|
!kNotifySelectedKeyboardInputSourceChanged ||
|
||||||
|
!TISCopyCurrentKeyboardLayoutInputSource ||
|
||||||
|
!TISGetInputSourceProperty ||
|
||||||
|
!LMGetKbdType)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to load TIS API symbols");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
|
||||||
|
*kPropertyUnicodeKeyLayoutData;
|
||||||
|
_glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged =
|
||||||
|
*kNotifySelectedKeyboardInputSourceChanged;
|
||||||
|
|
||||||
|
return updateUnicodeDataNS();
|
||||||
|
}
|
||||||
|
|
||||||
|
@interface GLFWLayoutListener : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GLFWLayoutListener
|
||||||
|
|
||||||
|
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||||
|
{
|
||||||
|
updateUnicodeDataNS();
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformInit(void)
|
||||||
|
{
|
||||||
|
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
|
||||||
|
[[NSDistributedNotificationCenter defaultCenter]
|
||||||
|
addObserver:_glfw.ns.listener
|
||||||
|
selector:@selector(selectedKeyboardInputSourceChanged:)
|
||||||
|
name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged
|
||||||
|
object:nil];
|
||||||
|
|
||||||
|
#if defined(_GLFW_USE_CHDIR)
|
||||||
|
changeToResourcesDirectory();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
createKeyTables();
|
||||||
|
|
||||||
|
_glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
|
||||||
|
if (!_glfw.ns.eventSource)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
|
||||||
|
|
||||||
|
if (!initializeTIS())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (!_glfwInitThreadLocalStoragePOSIX())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfwInitTimerNS();
|
||||||
|
_glfwInitJoysticksNS();
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminate(void)
|
||||||
|
{
|
||||||
|
if (_glfw.ns.inputSource)
|
||||||
|
{
|
||||||
|
CFRelease(_glfw.ns.inputSource);
|
||||||
|
_glfw.ns.inputSource = NULL;
|
||||||
|
_glfw.ns.unicodeData = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.ns.eventSource)
|
||||||
|
{
|
||||||
|
CFRelease(_glfw.ns.eventSource);
|
||||||
|
_glfw.ns.eventSource = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.ns.delegate)
|
||||||
|
{
|
||||||
|
[NSApp setDelegate:nil];
|
||||||
|
[_glfw.ns.delegate release];
|
||||||
|
_glfw.ns.delegate = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.ns.listener)
|
||||||
|
{
|
||||||
|
[[NSDistributedNotificationCenter defaultCenter]
|
||||||
|
removeObserver:_glfw.ns.listener
|
||||||
|
name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged
|
||||||
|
object:nil];
|
||||||
|
[[NSDistributedNotificationCenter defaultCenter]
|
||||||
|
removeObserver:_glfw.ns.listener];
|
||||||
|
[_glfw.ns.listener release];
|
||||||
|
_glfw.ns.listener = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
[_glfw.ns.cursor release];
|
||||||
|
_glfw.ns.cursor = nil;
|
||||||
|
|
||||||
|
free(_glfw.ns.clipboardString);
|
||||||
|
|
||||||
|
_glfwTerminateNSGL();
|
||||||
|
_glfwTerminateJoysticksNS();
|
||||||
|
_glfwTerminateThreadLocalStoragePOSIX();
|
||||||
|
|
||||||
|
[_glfw.ns.autoreleasePool release];
|
||||||
|
_glfw.ns.autoreleasePool = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _GLFW_VERSION_NUMBER " Cocoa NSGL"
|
||||||
|
#if defined(_GLFW_USE_CHDIR)
|
||||||
|
" chdir"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_USE_MENUBAR)
|
||||||
|
" menubar"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_USE_RETINA)
|
||||||
|
" retina"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
" dynamic"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
60
external/glfw/cocoa_joystick.h
vendored
Normal file
60
external/glfw/cocoa_joystick.h
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Cocoa - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_cocoa_joystick_h_
|
||||||
|
#define _glfw3_cocoa_joystick_h_
|
||||||
|
|
||||||
|
#include <IOKit/IOKitLib.h>
|
||||||
|
#include <IOKit/IOCFPlugIn.h>
|
||||||
|
#include <IOKit/hid/IOHIDLib.h>
|
||||||
|
#include <IOKit/hid/IOHIDKeys.h>
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||||
|
_GLFWjoystickNS ns_js[GLFW_JOYSTICK_LAST + 1]
|
||||||
|
|
||||||
|
|
||||||
|
// Cocoa-specific per-joystick data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoystickNS
|
||||||
|
{
|
||||||
|
GLFWbool present;
|
||||||
|
char name[256];
|
||||||
|
|
||||||
|
IOHIDDeviceRef deviceRef;
|
||||||
|
|
||||||
|
CFMutableArrayRef axisElements;
|
||||||
|
CFMutableArrayRef buttonElements;
|
||||||
|
CFMutableArrayRef hatElements;
|
||||||
|
|
||||||
|
float* axes;
|
||||||
|
unsigned char* buttons;
|
||||||
|
} _GLFWjoystickNS;
|
||||||
|
|
||||||
|
|
||||||
|
void _glfwInitJoysticksNS(void);
|
||||||
|
void _glfwTerminateJoysticksNS(void);
|
||||||
|
|
||||||
|
#endif // _glfw3_cocoa_joystick_h_
|
511
external/glfw/cocoa_joystick.m
vendored
Normal file
511
external/glfw/cocoa_joystick.m
vendored
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Cocoa - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <mach/mach_error.h>
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Joystick element information
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoyelementNS
|
||||||
|
{
|
||||||
|
IOHIDElementRef elementRef;
|
||||||
|
|
||||||
|
long min;
|
||||||
|
long max;
|
||||||
|
|
||||||
|
long minReport;
|
||||||
|
long maxReport;
|
||||||
|
|
||||||
|
} _GLFWjoyelementNS;
|
||||||
|
|
||||||
|
|
||||||
|
static void getElementsCFArrayHandler(const void* value, void* parameter);
|
||||||
|
|
||||||
|
// Adds an element to the specified joystick
|
||||||
|
//
|
||||||
|
static void addJoystickElement(_GLFWjoystickNS* js,
|
||||||
|
IOHIDElementRef elementRef)
|
||||||
|
{
|
||||||
|
IOHIDElementType elementType;
|
||||||
|
long usagePage, usage;
|
||||||
|
CFMutableArrayRef elementsArray = NULL;
|
||||||
|
|
||||||
|
elementType = IOHIDElementGetType(elementRef);
|
||||||
|
usagePage = IOHIDElementGetUsagePage(elementRef);
|
||||||
|
usage = IOHIDElementGetUsage(elementRef);
|
||||||
|
|
||||||
|
if ((elementType != kIOHIDElementTypeInput_Axis) &&
|
||||||
|
(elementType != kIOHIDElementTypeInput_Button) &&
|
||||||
|
(elementType != kIOHIDElementTypeInput_Misc))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (usagePage)
|
||||||
|
{
|
||||||
|
case kHIDPage_GenericDesktop:
|
||||||
|
{
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case kHIDUsage_GD_X:
|
||||||
|
case kHIDUsage_GD_Y:
|
||||||
|
case kHIDUsage_GD_Z:
|
||||||
|
case kHIDUsage_GD_Rx:
|
||||||
|
case kHIDUsage_GD_Ry:
|
||||||
|
case kHIDUsage_GD_Rz:
|
||||||
|
case kHIDUsage_GD_Slider:
|
||||||
|
case kHIDUsage_GD_Dial:
|
||||||
|
case kHIDUsage_GD_Wheel:
|
||||||
|
elementsArray = js->axisElements;
|
||||||
|
break;
|
||||||
|
case kHIDUsage_GD_Hatswitch:
|
||||||
|
elementsArray = js->hatElements;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kHIDPage_Button:
|
||||||
|
elementsArray = js->buttonElements;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementsArray)
|
||||||
|
{
|
||||||
|
_GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
|
||||||
|
|
||||||
|
CFArrayAppendValue(elementsArray, element);
|
||||||
|
|
||||||
|
element->elementRef = elementRef;
|
||||||
|
|
||||||
|
element->minReport = IOHIDElementGetLogicalMin(elementRef);
|
||||||
|
element->maxReport = IOHIDElementGetLogicalMax(elementRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an element to the specified joystick
|
||||||
|
//
|
||||||
|
static void getElementsCFArrayHandler(const void* value, void* parameter)
|
||||||
|
{
|
||||||
|
if (CFGetTypeID(value) == IOHIDElementGetTypeID())
|
||||||
|
{
|
||||||
|
addJoystickElement((_GLFWjoystickNS*) parameter,
|
||||||
|
(IOHIDElementRef) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the value of the specified element of the specified joystick
|
||||||
|
//
|
||||||
|
static long getElementValue(_GLFWjoystickNS* js, _GLFWjoyelementNS* element)
|
||||||
|
{
|
||||||
|
IOReturn result = kIOReturnSuccess;
|
||||||
|
IOHIDValueRef valueRef;
|
||||||
|
long value = 0;
|
||||||
|
|
||||||
|
if (js && element && js->deviceRef)
|
||||||
|
{
|
||||||
|
result = IOHIDDeviceGetValue(js->deviceRef,
|
||||||
|
element->elementRef,
|
||||||
|
&valueRef);
|
||||||
|
|
||||||
|
if (kIOReturnSuccess == result)
|
||||||
|
{
|
||||||
|
value = IOHIDValueGetIntegerValue(valueRef);
|
||||||
|
|
||||||
|
// Record min and max for auto calibration
|
||||||
|
if (value < element->minReport)
|
||||||
|
element->minReport = value;
|
||||||
|
if (value > element->maxReport)
|
||||||
|
element->maxReport = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto user scale
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes the specified joystick
|
||||||
|
//
|
||||||
|
static void removeJoystick(_GLFWjoystickNS* js)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!js->present)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->axisElements); i++)
|
||||||
|
free((void*) CFArrayGetValueAtIndex(js->axisElements, i));
|
||||||
|
CFArrayRemoveAllValues(js->axisElements);
|
||||||
|
CFRelease(js->axisElements);
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->buttonElements); i++)
|
||||||
|
free((void*) CFArrayGetValueAtIndex(js->buttonElements, i));
|
||||||
|
CFArrayRemoveAllValues(js->buttonElements);
|
||||||
|
CFRelease(js->buttonElements);
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->hatElements); i++)
|
||||||
|
free((void*) CFArrayGetValueAtIndex(js->hatElements, i));
|
||||||
|
CFArrayRemoveAllValues(js->hatElements);
|
||||||
|
CFRelease(js->hatElements);
|
||||||
|
|
||||||
|
free(js->axes);
|
||||||
|
free(js->buttons);
|
||||||
|
|
||||||
|
memset(js, 0, sizeof(_GLFWjoystickNS));
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(js - _glfw.ns_js, GLFW_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polls for joystick axis events and updates GLFW state
|
||||||
|
//
|
||||||
|
static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js)
|
||||||
|
{
|
||||||
|
CFIndex i;
|
||||||
|
|
||||||
|
if (!js->present)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->axisElements); i++)
|
||||||
|
{
|
||||||
|
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
|
||||||
|
CFArrayGetValueAtIndex(js->axisElements, i);
|
||||||
|
|
||||||
|
long value = getElementValue(js, axis);
|
||||||
|
long readScale = axis->maxReport - axis->minReport;
|
||||||
|
|
||||||
|
if (readScale == 0)
|
||||||
|
js->axes[i] = value;
|
||||||
|
else
|
||||||
|
js->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polls for joystick button events and updates GLFW state
|
||||||
|
//
|
||||||
|
static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js)
|
||||||
|
{
|
||||||
|
CFIndex i;
|
||||||
|
int buttonIndex = 0;
|
||||||
|
|
||||||
|
if (!js->present)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->buttonElements); i++)
|
||||||
|
{
|
||||||
|
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
|
||||||
|
CFArrayGetValueAtIndex(js->buttonElements, i);
|
||||||
|
|
||||||
|
if (getElementValue(js, button))
|
||||||
|
js->buttons[buttonIndex++] = GLFW_PRESS;
|
||||||
|
else
|
||||||
|
js->buttons[buttonIndex++] = GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < CFArrayGetCount(js->hatElements); i++)
|
||||||
|
{
|
||||||
|
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
|
||||||
|
CFArrayGetValueAtIndex(js->hatElements, i);
|
||||||
|
|
||||||
|
// Bit fields of button presses for each direction, including nil
|
||||||
|
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
|
||||||
|
|
||||||
|
long j, value = getElementValue(js, hat);
|
||||||
|
if (value < 0 || value > 8)
|
||||||
|
value = 8;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if (directions[value] & (1 << j))
|
||||||
|
js->buttons[buttonIndex++] = GLFW_PRESS;
|
||||||
|
else
|
||||||
|
js->buttons[buttonIndex++] = GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback for user-initiated joystick addition
|
||||||
|
//
|
||||||
|
static void matchCallback(void* context,
|
||||||
|
IOReturn result,
|
||||||
|
void* sender,
|
||||||
|
IOHIDDeviceRef deviceRef)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js;
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (_glfw.ns_js[joy].present && _glfw.ns_js[joy].deviceRef == deviceRef)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (!_glfw.ns_js[joy].present)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joy > GLFW_JOYSTICK_LAST)
|
||||||
|
return;
|
||||||
|
|
||||||
|
js = _glfw.ns_js + joy;
|
||||||
|
js->present = GLFW_TRUE;
|
||||||
|
js->deviceRef = deviceRef;
|
||||||
|
|
||||||
|
CFStringRef name = IOHIDDeviceGetProperty(deviceRef,
|
||||||
|
CFSTR(kIOHIDProductKey));
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
CFStringGetCString(name,
|
||||||
|
js->name,
|
||||||
|
sizeof(js->name),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strncpy(js->name, "Unknown", sizeof(js->name));
|
||||||
|
|
||||||
|
js->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
js->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
js->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
|
||||||
|
CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef,
|
||||||
|
NULL,
|
||||||
|
kIOHIDOptionsTypeNone);
|
||||||
|
CFRange range = { 0, CFArrayGetCount(arrayRef) };
|
||||||
|
CFArrayApplyFunction(arrayRef,
|
||||||
|
range,
|
||||||
|
getElementsCFArrayHandler,
|
||||||
|
(void*) js);
|
||||||
|
|
||||||
|
CFRelease(arrayRef);
|
||||||
|
|
||||||
|
js->axes = calloc(CFArrayGetCount(js->axisElements), sizeof(float));
|
||||||
|
js->buttons = calloc(CFArrayGetCount(js->buttonElements) +
|
||||||
|
CFArrayGetCount(js->hatElements) * 4, 1);
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback for user-initiated joystick removal
|
||||||
|
//
|
||||||
|
static void removeCallback(void* context,
|
||||||
|
IOReturn result,
|
||||||
|
void* sender,
|
||||||
|
IOHIDDeviceRef deviceRef)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (_glfw.ns_js[joy].deviceRef == deviceRef)
|
||||||
|
{
|
||||||
|
removeJoystick(_glfw.ns_js + joy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a dictionary to match against devices with the specified usage page
|
||||||
|
// and usage
|
||||||
|
//
|
||||||
|
static CFMutableDictionaryRef createMatchingDictionary(long usagePage,
|
||||||
|
long usage)
|
||||||
|
{
|
||||||
|
CFMutableDictionaryRef result =
|
||||||
|
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||||
|
0,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks,
|
||||||
|
&kCFTypeDictionaryValueCallBacks);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
|
||||||
|
kCFNumberLongType,
|
||||||
|
&usagePage);
|
||||||
|
if (pageRef)
|
||||||
|
{
|
||||||
|
CFDictionarySetValue(result,
|
||||||
|
CFSTR(kIOHIDDeviceUsagePageKey),
|
||||||
|
pageRef);
|
||||||
|
CFRelease(pageRef);
|
||||||
|
|
||||||
|
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
|
||||||
|
kCFNumberLongType,
|
||||||
|
&usage);
|
||||||
|
if (usageRef)
|
||||||
|
{
|
||||||
|
CFDictionarySetValue(result,
|
||||||
|
CFSTR(kIOHIDDeviceUsageKey),
|
||||||
|
usageRef);
|
||||||
|
CFRelease(usageRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize joystick interface
|
||||||
|
//
|
||||||
|
void _glfwInitJoysticksNS(void)
|
||||||
|
{
|
||||||
|
CFMutableArrayRef matchingCFArrayRef;
|
||||||
|
|
||||||
|
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
|
||||||
|
kIOHIDOptionsTypeNone);
|
||||||
|
|
||||||
|
matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault,
|
||||||
|
0,
|
||||||
|
&kCFTypeArrayCallBacks);
|
||||||
|
if (matchingCFArrayRef)
|
||||||
|
{
|
||||||
|
CFDictionaryRef matchingCFDictRef =
|
||||||
|
createMatchingDictionary(kHIDPage_GenericDesktop,
|
||||||
|
kHIDUsage_GD_Joystick);
|
||||||
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop,
|
||||||
|
kHIDUsage_GD_GamePad);
|
||||||
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingCFDictRef =
|
||||||
|
createMatchingDictionary(kHIDPage_GenericDesktop,
|
||||||
|
kHIDUsage_GD_MultiAxisController);
|
||||||
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager,
|
||||||
|
matchingCFArrayRef);
|
||||||
|
CFRelease(matchingCFArrayRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
|
||||||
|
&matchCallback, NULL);
|
||||||
|
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
|
||||||
|
&removeCallback, NULL);
|
||||||
|
|
||||||
|
IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
|
||||||
|
CFRunLoopGetMain(),
|
||||||
|
kCFRunLoopDefaultMode);
|
||||||
|
|
||||||
|
IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
|
||||||
|
|
||||||
|
// Execute the run loop once in order to register any initially-attached
|
||||||
|
// joysticks
|
||||||
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all opened joystick handles
|
||||||
|
//
|
||||||
|
void _glfwTerminateJoysticksNS(void)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js = _glfw.ns_js + joy;
|
||||||
|
removeJoystick(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(_glfw.ns.hidManager);
|
||||||
|
_glfw.ns.hidManager = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformJoystickPresent(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js = _glfw.ns_js + joy;
|
||||||
|
return js->present;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js = _glfw.ns_js + joy;
|
||||||
|
if (!pollJoystickAxisEvents(js))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = (int) CFArrayGetCount(js->axisElements);
|
||||||
|
return js->axes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js = _glfw.ns_js + joy;
|
||||||
|
if (!pollJoystickButtonEvents(js))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = (int) CFArrayGetCount(js->buttonElements) +
|
||||||
|
(int) CFArrayGetCount(js->hatElements) * 4;
|
||||||
|
return js->buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetJoystickName(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickNS* js = _glfw.ns_js + joy;
|
||||||
|
if (!js->present)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return js->name;
|
||||||
|
}
|
||||||
|
|
413
external/glfw/cocoa_monitor.m
vendored
Normal file
413
external/glfw/cocoa_monitor.m
vendored
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||||
|
#include <CoreVideo/CVBase.h>
|
||||||
|
#include <CoreVideo/CVDisplayLink.h>
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Get the name of the specified display
|
||||||
|
//
|
||||||
|
static char* getDisplayName(CGDirectDisplayID displayID)
|
||||||
|
{
|
||||||
|
char* name;
|
||||||
|
CFDictionaryRef info, names;
|
||||||
|
CFStringRef value;
|
||||||
|
CFIndex size;
|
||||||
|
|
||||||
|
// NOTE: This uses a deprecated function because Apple has
|
||||||
|
// (as of January 2015) not provided any alternative
|
||||||
|
info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID),
|
||||||
|
kIODisplayOnlyPreferredName);
|
||||||
|
names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
|
||||||
|
|
||||||
|
if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"),
|
||||||
|
(const void**) &value))
|
||||||
|
{
|
||||||
|
// This may happen if a desktop Mac is running headless
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Failed to retrieve display name");
|
||||||
|
|
||||||
|
CFRelease(info);
|
||||||
|
return strdup("Unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
name = calloc(size + 1, 1);
|
||||||
|
CFStringGetCString(value, name, size, kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
CFRelease(info);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the display mode should be included in enumeration
|
||||||
|
//
|
||||||
|
static GLFWbool modeIsGood(CGDisplayModeRef mode)
|
||||||
|
{
|
||||||
|
uint32_t flags = CGDisplayModeGetIOFlags(mode);
|
||||||
|
if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (flags & kDisplayModeInterlacedFlag)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (flags & kDisplayModeStretchedFlag)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||||
|
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
|
||||||
|
CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
|
||||||
|
{
|
||||||
|
CFRelease(format);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(format);
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Core Graphics display mode to GLFW video mode
|
||||||
|
//
|
||||||
|
static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
|
||||||
|
CVDisplayLinkRef link)
|
||||||
|
{
|
||||||
|
GLFWvidmode result;
|
||||||
|
result.width = (int) CGDisplayModeGetWidth(mode);
|
||||||
|
result.height = (int) CGDisplayModeGetHeight(mode);
|
||||||
|
result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode);
|
||||||
|
|
||||||
|
if (result.refreshRate == 0)
|
||||||
|
{
|
||||||
|
const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
|
||||||
|
if (!(time.flags & kCVTimeIsIndefinite))
|
||||||
|
result.refreshRate = (int) (time.timeScale / (double) time.timeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
|
||||||
|
|
||||||
|
if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0)
|
||||||
|
{
|
||||||
|
result.redBits = 5;
|
||||||
|
result.greenBits = 5;
|
||||||
|
result.blueBits = 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.redBits = 8;
|
||||||
|
result.greenBits = 8;
|
||||||
|
result.blueBits = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(format);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts reservation for display fading
|
||||||
|
//
|
||||||
|
static CGDisplayFadeReservationToken beginFadeReservation(void)
|
||||||
|
{
|
||||||
|
CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken;
|
||||||
|
|
||||||
|
if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess)
|
||||||
|
CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ends reservation for display fading
|
||||||
|
//
|
||||||
|
static void endFadeReservation(CGDisplayFadeReservationToken token)
|
||||||
|
{
|
||||||
|
if (token != kCGDisplayFadeReservationInvalidToken)
|
||||||
|
{
|
||||||
|
CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
|
||||||
|
CGReleaseDisplayFadeReservation(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Change the current video mode
|
||||||
|
//
|
||||||
|
GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||||
|
{
|
||||||
|
CFArrayRef modes;
|
||||||
|
CFIndex count, i;
|
||||||
|
CVDisplayLinkRef link;
|
||||||
|
CGDisplayModeRef native = NULL;
|
||||||
|
GLFWvidmode current;
|
||||||
|
const GLFWvidmode* best;
|
||||||
|
|
||||||
|
best = _glfwChooseVideoMode(monitor, desired);
|
||||||
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
|
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||||
|
count = CFArrayGetCount(modes);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||||
|
if (!modeIsGood(dm))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||||
|
if (_glfwCompareVideoModes(best, &mode) == 0)
|
||||||
|
{
|
||||||
|
native = dm;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (native)
|
||||||
|
{
|
||||||
|
if (monitor->ns.previousMode == NULL)
|
||||||
|
monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||||
|
|
||||||
|
CGDisplayFadeReservationToken token = beginFadeReservation();
|
||||||
|
CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL);
|
||||||
|
endFadeReservation(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(modes);
|
||||||
|
CVDisplayLinkRelease(link);
|
||||||
|
|
||||||
|
if (!native)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Cocoa: Monitor mode list changed");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the previously saved (original) video mode
|
||||||
|
//
|
||||||
|
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
if (monitor->ns.previousMode)
|
||||||
|
{
|
||||||
|
CGDisplayFadeReservationToken token = beginFadeReservation();
|
||||||
|
CGDisplaySetDisplayMode(monitor->ns.displayID,
|
||||||
|
monitor->ns.previousMode, NULL);
|
||||||
|
endFadeReservation(token);
|
||||||
|
|
||||||
|
CGDisplayModeRelease(monitor->ns.previousMode);
|
||||||
|
monitor->ns.previousMode = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
uint32_t i, found = 0, displayCount;
|
||||||
|
_GLFWmonitor** monitors;
|
||||||
|
CGDirectDisplayID* displays;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||||
|
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||||
|
monitors = calloc(displayCount, sizeof(_GLFWmonitor*));
|
||||||
|
|
||||||
|
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||||
|
|
||||||
|
for (i = 0; i < displayCount; i++)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor;
|
||||||
|
|
||||||
|
if (CGDisplayIsAsleep(displays[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const CGSize size = CGDisplayScreenSize(displays[i]);
|
||||||
|
char* name = getDisplayName(displays[i]);
|
||||||
|
|
||||||
|
monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||||
|
monitor->ns.displayID = displays[i];
|
||||||
|
monitor->ns.unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||||
|
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
found++;
|
||||||
|
monitors[found - 1] = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(displays);
|
||||||
|
|
||||||
|
*count = found;
|
||||||
|
return monitors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||||
|
{
|
||||||
|
// HACK: Compare unit numbers instead of display IDs to work around display
|
||||||
|
// replacement on machines with automatic graphics switching
|
||||||
|
return first->ns.unitNumber == second->ns.unitNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = (int) bounds.origin.x;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = (int) bounds.origin.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||||
|
{
|
||||||
|
CFArrayRef modes;
|
||||||
|
CFIndex found, i, j;
|
||||||
|
GLFWvidmode* result;
|
||||||
|
CVDisplayLinkRef link;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
|
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||||
|
found = CFArrayGetCount(modes);
|
||||||
|
result = calloc(found, sizeof(GLFWvidmode));
|
||||||
|
|
||||||
|
for (i = 0; i < found; i++)
|
||||||
|
{
|
||||||
|
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||||
|
if (!modeIsGood(dm))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||||
|
|
||||||
|
for (j = 0; j < *count; j++)
|
||||||
|
{
|
||||||
|
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip duplicate modes
|
||||||
|
if (i < *count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
result[*count - 1] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(modes);
|
||||||
|
CVDisplayLinkRelease(link);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
||||||
|
{
|
||||||
|
CGDisplayModeRef displayMode;
|
||||||
|
CVDisplayLinkRef link;
|
||||||
|
|
||||||
|
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||||
|
|
||||||
|
displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
|
||||||
|
*mode = vidmodeFromCGDisplayMode(displayMode, link);
|
||||||
|
CGDisplayModeRelease(displayMode);
|
||||||
|
|
||||||
|
CVDisplayLinkRelease(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||||
|
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||||
|
|
||||||
|
CGGetDisplayTransferByTable(monitor->ns.displayID,
|
||||||
|
size,
|
||||||
|
values,
|
||||||
|
values + size,
|
||||||
|
values + size * 2,
|
||||||
|
&size);
|
||||||
|
|
||||||
|
_glfwAllocGammaArrays(ramp, size);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
ramp->red[i] = (unsigned short) (values[i] * 65535);
|
||||||
|
ramp->green[i] = (unsigned short) (values[i + size] * 65535);
|
||||||
|
ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue));
|
||||||
|
|
||||||
|
for (i = 0; i < ramp->size; i++)
|
||||||
|
{
|
||||||
|
values[i] = ramp->red[i] / 65535.f;
|
||||||
|
values[i + ramp->size] = ramp->green[i] / 65535.f;
|
||||||
|
values[i + ramp->size * 2] = ramp->blue[i] / 65535.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGSetDisplayTransferByTable(monitor->ns.displayID,
|
||||||
|
ramp->size,
|
||||||
|
values,
|
||||||
|
values + ramp->size,
|
||||||
|
values + ramp->size * 2);
|
||||||
|
|
||||||
|
free(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
|
||||||
|
return monitor->ns.displayID;
|
||||||
|
}
|
||||||
|
|
150
external/glfw/cocoa_platform.h
vendored
Normal file
150
external/glfw/cocoa_platform.h
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_cocoa_platform_h_
|
||||||
|
#define _glfw3_cocoa_platform_h_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
#import <Carbon/Carbon.h>
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#else
|
||||||
|
#include <Carbon/Carbon.h>
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
typedef void* id;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "posix_tls.h"
|
||||||
|
#include "cocoa_joystick.h"
|
||||||
|
#include "nsgl_context.h"
|
||||||
|
|
||||||
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||||
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns
|
||||||
|
|
||||||
|
#define _GLFW_EGL_CONTEXT_STATE
|
||||||
|
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE
|
||||||
|
|
||||||
|
// HIToolbox.framework pointer typedefs
|
||||||
|
#define kTISPropertyUnicodeKeyLayoutData _glfw.ns.tis.kPropertyUnicodeKeyLayoutData
|
||||||
|
#define kTISNotifySelectedKeyboardInputSourceChanged _glfw.ns.tis.kNotifySelectedKeyboardInputSourceChanged
|
||||||
|
typedef TISInputSourceRef (*PFN_TISCopyCurrentKeyboardLayoutInputSource)(void);
|
||||||
|
#define TISCopyCurrentKeyboardLayoutInputSource _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource
|
||||||
|
typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
||||||
|
#define TISGetInputSourceProperty _glfw.ns.tis.GetInputSourceProperty
|
||||||
|
typedef UInt8 (*PFN_LMGetKbdType)(void);
|
||||||
|
#define LMGetKbdType _glfw.ns.tis.GetKbdType
|
||||||
|
|
||||||
|
|
||||||
|
// Cocoa-specific per-window data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWwindowNS
|
||||||
|
{
|
||||||
|
id object;
|
||||||
|
id delegate;
|
||||||
|
id view;
|
||||||
|
|
||||||
|
// The total sum of the distances the cursor has been warped
|
||||||
|
// since the last cursor motion event was processed
|
||||||
|
// This is kept to counteract Cocoa doing the same internally
|
||||||
|
double cursorWarpDeltaX, cursorWarpDeltaY;
|
||||||
|
|
||||||
|
} _GLFWwindowNS;
|
||||||
|
|
||||||
|
// Cocoa-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryNS
|
||||||
|
{
|
||||||
|
CGEventSourceRef eventSource;
|
||||||
|
id delegate;
|
||||||
|
id autoreleasePool;
|
||||||
|
id cursor;
|
||||||
|
TISInputSourceRef inputSource;
|
||||||
|
IOHIDManagerRef hidManager;
|
||||||
|
id unicodeData;
|
||||||
|
id listener;
|
||||||
|
|
||||||
|
char keyName[64];
|
||||||
|
short int publicKeys[256];
|
||||||
|
short int nativeKeys[GLFW_KEY_LAST + 1];
|
||||||
|
char* clipboardString;
|
||||||
|
// Where to place the cursor when re-enabled
|
||||||
|
double restoreCursorPosX, restoreCursorPosY;
|
||||||
|
// The window whose disabled cursor mode is active
|
||||||
|
_GLFWwindow* disabledCursorWindow;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
CFBundleRef bundle;
|
||||||
|
PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;
|
||||||
|
PFN_TISGetInputSourceProperty GetInputSourceProperty;
|
||||||
|
PFN_LMGetKbdType GetKbdType;
|
||||||
|
CFStringRef kPropertyUnicodeKeyLayoutData;
|
||||||
|
CFStringRef kNotifySelectedKeyboardInputSourceChanged;
|
||||||
|
} tis;
|
||||||
|
|
||||||
|
} _GLFWlibraryNS;
|
||||||
|
|
||||||
|
// Cocoa-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorNS
|
||||||
|
{
|
||||||
|
CGDirectDisplayID displayID;
|
||||||
|
CGDisplayModeRef previousMode;
|
||||||
|
uint32_t unitNumber;
|
||||||
|
|
||||||
|
} _GLFWmonitorNS;
|
||||||
|
|
||||||
|
// Cocoa-specific per-cursor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcursorNS
|
||||||
|
{
|
||||||
|
id object;
|
||||||
|
|
||||||
|
} _GLFWcursorNS;
|
||||||
|
|
||||||
|
// Cocoa-specific global timer data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWtimeNS
|
||||||
|
{
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
|
} _GLFWtimeNS;
|
||||||
|
|
||||||
|
|
||||||
|
void _glfwInitTimerNS(void);
|
||||||
|
|
||||||
|
GLFWbool _glfwSetVideoModeNS(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
|
void _glfwRestoreVideoModeNS(_GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
#endif // _glfw3_cocoa_platform_h_
|
60
external/glfw/cocoa_time.c
vendored
Normal file
60
external/glfw/cocoa_time.c
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialise timer
|
||||||
|
//
|
||||||
|
void _glfwInitTimerNS(void)
|
||||||
|
{
|
||||||
|
mach_timebase_info_data_t info;
|
||||||
|
mach_timebase_info(&info);
|
||||||
|
|
||||||
|
_glfw.ns_time.frequency = (info.denom * 1e9) / info.numer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerValue(void)
|
||||||
|
{
|
||||||
|
return mach_absolute_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||||
|
{
|
||||||
|
return _glfw.ns_time.frequency;
|
||||||
|
}
|
||||||
|
|
1653
external/glfw/cocoa_window.m
vendored
Normal file
1653
external/glfw/cocoa_window.m
vendored
Normal file
File diff suppressed because it is too large
Load Diff
720
external/glfw/context.c
vendored
Normal file
720
external/glfw/context.c
vendored
Normal file
@ -0,0 +1,720 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||||
|
{
|
||||||
|
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
|
||||||
|
ctxconfig->source != GLFW_EGL_CONTEXT_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid context creation API %i",
|
||||||
|
ctxconfig->source);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->client != GLFW_NO_API &&
|
||||||
|
ctxconfig->client != GLFW_OPENGL_API &&
|
||||||
|
ctxconfig->client != GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid client API %i",
|
||||||
|
ctxconfig->client);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
|
||||||
|
(ctxconfig->major == 1 && ctxconfig->minor > 5) ||
|
||||||
|
(ctxconfig->major == 2 && ctxconfig->minor > 1) ||
|
||||||
|
(ctxconfig->major == 3 && ctxconfig->minor > 3))
|
||||||
|
{
|
||||||
|
// OpenGL 1.0 is the smallest valid version
|
||||||
|
// OpenGL 1.x series ended with version 1.5
|
||||||
|
// OpenGL 2.x series ended with version 2.1
|
||||||
|
// OpenGL 3.x series ended with version 3.3
|
||||||
|
// For now, let everything else through
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid OpenGL version %i.%i",
|
||||||
|
ctxconfig->major, ctxconfig->minor);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->profile)
|
||||||
|
{
|
||||||
|
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
|
||||||
|
ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid OpenGL profile %i",
|
||||||
|
ctxconfig->profile);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->major <= 2 ||
|
||||||
|
(ctxconfig->major == 3 && ctxconfig->minor < 2))
|
||||||
|
{
|
||||||
|
// Desktop OpenGL context profiles are only defined for version 3.2
|
||||||
|
// and above
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Context profiles are only defined for OpenGL version 3.2 and above");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->forward && ctxconfig->major <= 2)
|
||||||
|
{
|
||||||
|
// Forward-compatible contexts are only defined for OpenGL version 3.0 and above
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Forward-compatibility is only defined for OpenGL version 3.0 and above");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
|
||||||
|
(ctxconfig->major == 1 && ctxconfig->minor > 1) ||
|
||||||
|
(ctxconfig->major == 2 && ctxconfig->minor > 0))
|
||||||
|
{
|
||||||
|
// OpenGL ES 1.0 is the smallest valid version
|
||||||
|
// OpenGL ES 1.x series ended with version 1.1
|
||||||
|
// OpenGL ES 2.x series ended with version 2.0
|
||||||
|
// For now, let everything else through
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid OpenGL ES version %i.%i",
|
||||||
|
ctxconfig->major, ctxconfig->minor);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->robustness)
|
||||||
|
{
|
||||||
|
if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
|
||||||
|
ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid context robustness mode %i",
|
||||||
|
ctxconfig->robustness);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->release)
|
||||||
|
{
|
||||||
|
if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
|
||||||
|
ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid context release behavior %i",
|
||||||
|
ctxconfig->release);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
|
||||||
|
const _GLFWfbconfig* alternatives,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int missing, leastMissing = UINT_MAX;
|
||||||
|
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
||||||
|
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
|
||||||
|
const _GLFWfbconfig* current;
|
||||||
|
const _GLFWfbconfig* closest = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
current = alternatives + i;
|
||||||
|
|
||||||
|
if (desired->stereo > 0 && current->stereo == 0)
|
||||||
|
{
|
||||||
|
// Stereo is a hard constraint
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->doublebuffer != current->doublebuffer)
|
||||||
|
{
|
||||||
|
// Double buffering is a hard constraint
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count number of missing buffers
|
||||||
|
{
|
||||||
|
missing = 0;
|
||||||
|
|
||||||
|
if (desired->alphaBits > 0 && current->alphaBits == 0)
|
||||||
|
missing++;
|
||||||
|
|
||||||
|
if (desired->depthBits > 0 && current->depthBits == 0)
|
||||||
|
missing++;
|
||||||
|
|
||||||
|
if (desired->stencilBits > 0 && current->stencilBits == 0)
|
||||||
|
missing++;
|
||||||
|
|
||||||
|
if (desired->auxBuffers > 0 &&
|
||||||
|
current->auxBuffers < desired->auxBuffers)
|
||||||
|
{
|
||||||
|
missing += desired->auxBuffers - current->auxBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->samples > 0 && current->samples == 0)
|
||||||
|
{
|
||||||
|
// Technically, several multisampling buffers could be
|
||||||
|
// involved, but that's a lower level implementation detail and
|
||||||
|
// not important to us here, so we count them as one
|
||||||
|
missing++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These polynomials make many small channel size differences matter
|
||||||
|
// less than one large channel size difference
|
||||||
|
|
||||||
|
// Calculate color channel size difference value
|
||||||
|
{
|
||||||
|
colorDiff = 0;
|
||||||
|
|
||||||
|
if (desired->redBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
colorDiff += (desired->redBits - current->redBits) *
|
||||||
|
(desired->redBits - current->redBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->greenBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
colorDiff += (desired->greenBits - current->greenBits) *
|
||||||
|
(desired->greenBits - current->greenBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->blueBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
colorDiff += (desired->blueBits - current->blueBits) *
|
||||||
|
(desired->blueBits - current->blueBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate non-color channel size difference value
|
||||||
|
{
|
||||||
|
extraDiff = 0;
|
||||||
|
|
||||||
|
if (desired->alphaBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->alphaBits - current->alphaBits) *
|
||||||
|
(desired->alphaBits - current->alphaBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->depthBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->depthBits - current->depthBits) *
|
||||||
|
(desired->depthBits - current->depthBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->stencilBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->stencilBits - current->stencilBits) *
|
||||||
|
(desired->stencilBits - current->stencilBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->accumRedBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->accumRedBits - current->accumRedBits) *
|
||||||
|
(desired->accumRedBits - current->accumRedBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->accumGreenBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
|
||||||
|
(desired->accumGreenBits - current->accumGreenBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->accumBlueBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
|
||||||
|
(desired->accumBlueBits - current->accumBlueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->accumAlphaBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
|
||||||
|
(desired->accumAlphaBits - current->accumAlphaBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->samples != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
extraDiff += (desired->samples - current->samples) *
|
||||||
|
(desired->samples - current->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired->sRGB && !current->sRGB)
|
||||||
|
extraDiff++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out if the current one is better than the best one found so far
|
||||||
|
// Least number of missing buffers is the most important heuristic,
|
||||||
|
// then color buffer size match and lastly size match for other buffers
|
||||||
|
|
||||||
|
if (missing < leastMissing)
|
||||||
|
closest = current;
|
||||||
|
else if (missing == leastMissing)
|
||||||
|
{
|
||||||
|
if ((colorDiff < leastColorDiff) ||
|
||||||
|
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
|
||||||
|
{
|
||||||
|
closest = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current == closest)
|
||||||
|
{
|
||||||
|
leastMissing = missing;
|
||||||
|
leastColorDiff = colorDiff;
|
||||||
|
leastExtraDiff = extraDiff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
_GLFWwindow* window;
|
||||||
|
const char* version;
|
||||||
|
const char* prefixes[] =
|
||||||
|
{
|
||||||
|
"OpenGL ES-CM ",
|
||||||
|
"OpenGL ES-CL ",
|
||||||
|
"OpenGL ES ",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
window = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
window->context.source = ctxconfig->source;
|
||||||
|
window->context.client = GLFW_OPENGL_API;
|
||||||
|
|
||||||
|
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
||||||
|
window->context.getProcAddress("glGetIntegerv");
|
||||||
|
window->context.GetString = (PFNGLGETSTRINGPROC)
|
||||||
|
window->context.getProcAddress("glGetString");
|
||||||
|
if (!window->context.GetIntegerv || !window->context.GetString)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = (const char*) window->context.GetString(GL_VERSION);
|
||||||
|
if (!version)
|
||||||
|
{
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"OpenGL version string retrieval is broken");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"OpenGL ES version string retrieval is broken");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; prefixes[i]; i++)
|
||||||
|
{
|
||||||
|
const size_t length = strlen(prefixes[i]);
|
||||||
|
|
||||||
|
if (strncmp(version, prefixes[i], length) == 0)
|
||||||
|
{
|
||||||
|
version += length;
|
||||||
|
window->context.client = GLFW_OPENGL_ES_API;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sscanf(version, "%d.%d.%d",
|
||||||
|
&window->context.major,
|
||||||
|
&window->context.minor,
|
||||||
|
&window->context.revision))
|
||||||
|
{
|
||||||
|
if (window->context.client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"No version found in OpenGL version string");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"No version found in OpenGL ES version string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.major < ctxconfig->major ||
|
||||||
|
(window->context.major == ctxconfig->major &&
|
||||||
|
window->context.minor < ctxconfig->minor))
|
||||||
|
{
|
||||||
|
// The desired OpenGL version is greater than the actual version
|
||||||
|
// This only happens if the machine lacks {GLX|WGL}_ARB_create_context
|
||||||
|
// /and/ the user has requested an OpenGL version greater than 1.0
|
||||||
|
|
||||||
|
// For API consistency, we emulate the behavior of the
|
||||||
|
// {GLX|WGL}_ARB_create_context extension and fail here
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"Requested OpenGL version %i.%i, got version %i.%i",
|
||||||
|
ctxconfig->major, ctxconfig->minor,
|
||||||
|
window->context.major, window->context.minor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"Requested OpenGL ES version %i.%i, got version %i.%i",
|
||||||
|
ctxconfig->major, ctxconfig->minor,
|
||||||
|
window->context.major, window->context.minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.major >= 3)
|
||||||
|
{
|
||||||
|
// OpenGL 3.0+ uses a different function for extension string retrieval
|
||||||
|
// We cache it here instead of in glfwExtensionSupported mostly to alert
|
||||||
|
// users as early as possible that their build may be broken
|
||||||
|
|
||||||
|
window->context.GetStringi = (PFNGLGETSTRINGIPROC)
|
||||||
|
window->context.getProcAddress("glGetStringi");
|
||||||
|
if (!window->context.GetStringi)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Entry point retrieval is broken");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
// Read back context flags (OpenGL 3.0 and above)
|
||||||
|
if (window->context.major >= 3)
|
||||||
|
{
|
||||||
|
GLint flags;
|
||||||
|
window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||||
|
|
||||||
|
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||||
|
window->context.forward = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
|
||||||
|
window->context.debug = GLFW_TRUE;
|
||||||
|
else if (glfwExtensionSupported("GL_ARB_debug_output") &&
|
||||||
|
ctxconfig->debug)
|
||||||
|
{
|
||||||
|
// HACK: This is a workaround for older drivers (pre KHR_debug)
|
||||||
|
// not setting the debug bit in the context flags for
|
||||||
|
// debug contexts
|
||||||
|
window->context.debug = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
|
||||||
|
window->context.noerror = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read back OpenGL context profile (OpenGL 3.2 and above)
|
||||||
|
if (window->context.major >= 4 ||
|
||||||
|
(window->context.major == 3 && window->context.minor >= 2))
|
||||||
|
{
|
||||||
|
GLint mask;
|
||||||
|
window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||||
|
|
||||||
|
if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||||
|
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||||
|
else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
|
||||||
|
window->context.profile = GLFW_OPENGL_CORE_PROFILE;
|
||||||
|
else if (glfwExtensionSupported("GL_ARB_compatibility"))
|
||||||
|
{
|
||||||
|
// HACK: This is a workaround for the compatibility profile bit
|
||||||
|
// not being set in the context flags if an OpenGL 3.2+
|
||||||
|
// context was created without having requested a specific
|
||||||
|
// version
|
||||||
|
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read back robustness strategy
|
||||||
|
if (glfwExtensionSupported("GL_ARB_robustness"))
|
||||||
|
{
|
||||||
|
// NOTE: We avoid using the context flags for detection, as they are
|
||||||
|
// only present from 3.0 while the extension applies from 1.1
|
||||||
|
|
||||||
|
GLint strategy;
|
||||||
|
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
&strategy);
|
||||||
|
|
||||||
|
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||||
|
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||||
|
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||||
|
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Read back robustness strategy
|
||||||
|
if (glfwExtensionSupported("GL_EXT_robustness"))
|
||||||
|
{
|
||||||
|
// NOTE: The values of these constants match those of the OpenGL ARB
|
||||||
|
// one, so we can reuse them here
|
||||||
|
|
||||||
|
GLint strategy;
|
||||||
|
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
&strategy);
|
||||||
|
|
||||||
|
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||||
|
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||||
|
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||||
|
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glfwExtensionSupported("GL_KHR_context_flush_control"))
|
||||||
|
{
|
||||||
|
GLint behavior;
|
||||||
|
window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
|
||||||
|
|
||||||
|
if (behavior == GL_NONE)
|
||||||
|
window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
|
||||||
|
else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
|
||||||
|
window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearing the front buffer to black to avoid garbage pixels left over from
|
||||||
|
// previous uses of our bit of VRAM
|
||||||
|
{
|
||||||
|
PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
|
||||||
|
window->context.getProcAddress("glClear");
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
window->context.swapBuffers(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||||
|
{
|
||||||
|
const char* start = extensions;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const char* where;
|
||||||
|
const char* terminator;
|
||||||
|
|
||||||
|
where = strstr(start, string);
|
||||||
|
if (!where)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
terminator = where + strlen(string);
|
||||||
|
if (where == start || *(where - 1) == ' ')
|
||||||
|
{
|
||||||
|
if (*terminator == ' ' || *terminator == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = terminator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFWwindow* previous = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window && window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous)
|
||||||
|
{
|
||||||
|
if (!window || window->context.source != previous->context.source)
|
||||||
|
previous->context.makeCurrent(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
window->context.makeCurrent(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return (GLFWwindow*) _glfwPlatformGetCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.swapBuffers(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSwapInterval(int interval)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
window = _glfwPlatformGetCurrentContext();
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.swapInterval(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
assert(extension != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||||
|
|
||||||
|
window = _glfwPlatformGetCurrentContext();
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*extension == '\0')
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE, "Extension name is empty string");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.major >= 3)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GLint count;
|
||||||
|
|
||||||
|
// Check if extension is in the modern OpenGL extensions string list
|
||||||
|
|
||||||
|
window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
const char* en = (const char*)
|
||||||
|
window->context.GetStringi(GL_EXTENSIONS, i);
|
||||||
|
if (!en)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Extension string retrieval is broken");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(en, extension) == 0)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check if extension is in the old style OpenGL extensions string
|
||||||
|
|
||||||
|
const char* extensions = (const char*)
|
||||||
|
window->context.GetString(GL_EXTENSIONS);
|
||||||
|
if (!extensions)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Extension string retrieval is broken");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfwStringInExtensionString(extension, extensions))
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if extension is in the platform-specific string
|
||||||
|
return window->context.extensionSupported(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
assert(procname != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
window = _glfwPlatformGetCurrentContext();
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.getProcAddress(procname);
|
||||||
|
}
|
||||||
|
|
746
external/glfw/egl_context.c
vendored
Normal file
746
external/glfw/egl_context.c
vendored
Normal file
@ -0,0 +1,746 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 EGL - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Return a description of the specified EGL error
|
||||||
|
//
|
||||||
|
static const char* getEGLErrorString(EGLint error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case EGL_SUCCESS:
|
||||||
|
return "Success";
|
||||||
|
case EGL_NOT_INITIALIZED:
|
||||||
|
return "EGL is not or could not be initialized";
|
||||||
|
case EGL_BAD_ACCESS:
|
||||||
|
return "EGL cannot access a requested resource";
|
||||||
|
case EGL_BAD_ALLOC:
|
||||||
|
return "EGL failed to allocate resources for the requested operation";
|
||||||
|
case EGL_BAD_ATTRIBUTE:
|
||||||
|
return "An unrecognized attribute or attribute value was passed in the attribute list";
|
||||||
|
case EGL_BAD_CONTEXT:
|
||||||
|
return "An EGLContext argument does not name a valid EGL rendering context";
|
||||||
|
case EGL_BAD_CONFIG:
|
||||||
|
return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
|
||||||
|
case EGL_BAD_CURRENT_SURFACE:
|
||||||
|
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
|
||||||
|
case EGL_BAD_DISPLAY:
|
||||||
|
return "An EGLDisplay argument does not name a valid EGL display connection";
|
||||||
|
case EGL_BAD_SURFACE:
|
||||||
|
return "An EGLSurface argument does not name a valid surface configured for GL rendering";
|
||||||
|
case EGL_BAD_MATCH:
|
||||||
|
return "Arguments are inconsistent";
|
||||||
|
case EGL_BAD_PARAMETER:
|
||||||
|
return "One or more argument values are invalid";
|
||||||
|
case EGL_BAD_NATIVE_PIXMAP:
|
||||||
|
return "A NativePixmapType argument does not refer to a valid native pixmap";
|
||||||
|
case EGL_BAD_NATIVE_WINDOW:
|
||||||
|
return "A NativeWindowType argument does not refer to a valid native window";
|
||||||
|
case EGL_CONTEXT_LOST:
|
||||||
|
return "The application must destroy all contexts and reinitialise";
|
||||||
|
default:
|
||||||
|
return "ERROR: UNKNOWN EGL ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the specified attribute of the specified EGLConfig
|
||||||
|
//
|
||||||
|
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the EGLConfig most closely matching the specified hints
|
||||||
|
//
|
||||||
|
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* desired,
|
||||||
|
EGLConfig* result)
|
||||||
|
{
|
||||||
|
EGLConfig* nativeConfigs;
|
||||||
|
_GLFWfbconfig* usableConfigs;
|
||||||
|
const _GLFWfbconfig* closest;
|
||||||
|
int i, nativeCount, usableCount;
|
||||||
|
|
||||||
|
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||||
|
if (!nativeCount)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
|
||||||
|
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
|
||||||
|
|
||||||
|
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||||
|
usableCount = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nativeCount; i++)
|
||||||
|
{
|
||||||
|
const EGLConfig n = nativeConfigs[i];
|
||||||
|
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||||
|
|
||||||
|
// Only consider RGB(A) EGLConfigs
|
||||||
|
if (!(getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Only consider window EGLConfigs
|
||||||
|
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if defined(_GLFW_X11)
|
||||||
|
// Only consider EGLConfigs with associated Visuals
|
||||||
|
if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
|
||||||
|
continue;
|
||||||
|
#endif // _GLFW_X11
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->major == 1)
|
||||||
|
{
|
||||||
|
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
|
||||||
|
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
|
||||||
|
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
|
||||||
|
|
||||||
|
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
|
||||||
|
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
|
||||||
|
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
||||||
|
|
||||||
|
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
||||||
|
u->doublebuffer = GLFW_TRUE;
|
||||||
|
|
||||||
|
u->handle = (uintptr_t) n;
|
||||||
|
usableCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||||
|
if (closest)
|
||||||
|
*result = (EGLConfig) closest->handle;
|
||||||
|
|
||||||
|
free(nativeConfigs);
|
||||||
|
free(usableConfigs);
|
||||||
|
|
||||||
|
return closest != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
if (!eglMakeCurrent(_glfw.egl.display,
|
||||||
|
window->context.egl.surface,
|
||||||
|
window->context.egl.surface,
|
||||||
|
window->context.egl.handle))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: Failed to make context current: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!eglMakeCurrent(_glfw.egl.display,
|
||||||
|
EGL_NO_SURFACE,
|
||||||
|
EGL_NO_SURFACE,
|
||||||
|
EGL_NO_CONTEXT))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: Failed to clear current context: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformSetCurrentContext(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapBuffersEGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window != _glfwPlatformGetCurrentContext())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: The context must be current on the calling thread when swapping buffers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapIntervalEGL(int interval)
|
||||||
|
{
|
||||||
|
eglSwapInterval(_glfw.egl.display, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extensionSupportedEGL(const char* extension)
|
||||||
|
{
|
||||||
|
const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
if (_glfwStringInExtensionString(extension, extensions))
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
if (window->context.egl.client)
|
||||||
|
{
|
||||||
|
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->context.egl.client,
|
||||||
|
procname);
|
||||||
|
if (proc)
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eglGetProcAddress(procname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroyContextEGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_X11)
|
||||||
|
// NOTE: Do not unload libGL.so.1 while the X11 display is still open,
|
||||||
|
// as it will make XCloseDisplay segfault
|
||||||
|
if (window->context.client != GLFW_OPENGL_API)
|
||||||
|
#endif // _GLFW_X11
|
||||||
|
{
|
||||||
|
if (window->context.egl.client)
|
||||||
|
{
|
||||||
|
_glfw_dlclose(window->context.egl.client);
|
||||||
|
window->context.egl.client = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.egl.surface)
|
||||||
|
{
|
||||||
|
eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
|
||||||
|
window->context.egl.surface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.egl.handle)
|
||||||
|
{
|
||||||
|
eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
|
||||||
|
window->context.egl.handle = EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize EGL
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitEGL(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char* sonames[] =
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_WIN32)
|
||||||
|
"libEGL.dll",
|
||||||
|
"EGL.dll",
|
||||||
|
#elif defined(_GLFW_COCOA)
|
||||||
|
"libEGL.dylib",
|
||||||
|
#else
|
||||||
|
"libEGL.so.1",
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_glfw.egl.handle)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
for (i = 0; sonames[i]; i++)
|
||||||
|
{
|
||||||
|
_glfw.egl.handle = _glfw_dlopen(sonames[i]);
|
||||||
|
if (_glfw.egl.handle)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfw.egl.handle)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
|
||||||
|
|
||||||
|
_glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
|
||||||
|
_glfw.egl.GetConfigs = (PFNEGLGETCONFIGSPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
|
||||||
|
_glfw.egl.GetDisplay = (PFNEGLGETDISPLAYPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
|
||||||
|
_glfw.egl.GetError = (PFNEGLGETERRORPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglGetError");
|
||||||
|
_glfw.egl.Initialize = (PFNEGLINITIALIZEPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglInitialize");
|
||||||
|
_glfw.egl.Terminate = (PFNEGLTERMINATEPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglTerminate");
|
||||||
|
_glfw.egl.BindAPI = (PFNEGLBINDAPIPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
|
||||||
|
_glfw.egl.CreateContext = (PFNEGLCREATECONTEXTPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
|
||||||
|
_glfw.egl.DestroySurface = (PFNEGLDESTROYSURFACEPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
|
||||||
|
_glfw.egl.DestroyContext = (PFNEGLDESTROYCONTEXTPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
|
||||||
|
_glfw.egl.CreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
|
||||||
|
_glfw.egl.MakeCurrent = (PFNEGLMAKECURRENTPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
|
||||||
|
_glfw.egl.SwapBuffers = (PFNEGLSWAPBUFFERSPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
|
||||||
|
_glfw.egl.SwapInterval = (PFNEGLSWAPINTERVALPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
|
||||||
|
_glfw.egl.QueryString = (PFNEGLQUERYSTRINGPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglQueryString");
|
||||||
|
_glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC)
|
||||||
|
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
|
||||||
|
|
||||||
|
if (!_glfw.egl.GetConfigAttrib ||
|
||||||
|
!_glfw.egl.GetConfigs ||
|
||||||
|
!_glfw.egl.GetDisplay ||
|
||||||
|
!_glfw.egl.GetError ||
|
||||||
|
!_glfw.egl.Initialize ||
|
||||||
|
!_glfw.egl.Terminate ||
|
||||||
|
!_glfw.egl.BindAPI ||
|
||||||
|
!_glfw.egl.CreateContext ||
|
||||||
|
!_glfw.egl.DestroySurface ||
|
||||||
|
!_glfw.egl.DestroyContext ||
|
||||||
|
!_glfw.egl.CreateWindowSurface ||
|
||||||
|
!_glfw.egl.MakeCurrent ||
|
||||||
|
!_glfw.egl.SwapBuffers ||
|
||||||
|
!_glfw.egl.SwapInterval ||
|
||||||
|
!_glfw.egl.QueryString ||
|
||||||
|
!_glfw.egl.GetProcAddress)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: Failed to load required entry points");
|
||||||
|
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
|
||||||
|
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to get EGL display: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to initialize EGL: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.egl.KHR_create_context =
|
||||||
|
extensionSupportedEGL("EGL_KHR_create_context");
|
||||||
|
_glfw.egl.KHR_create_context_no_error =
|
||||||
|
extensionSupportedEGL("EGL_KHR_create_context_no_error");
|
||||||
|
_glfw.egl.KHR_gl_colorspace =
|
||||||
|
extensionSupportedEGL("EGL_KHR_gl_colorspace");
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate EGL
|
||||||
|
//
|
||||||
|
void _glfwTerminateEGL(void)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.display)
|
||||||
|
{
|
||||||
|
eglTerminate(_glfw.egl.display);
|
||||||
|
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.handle)
|
||||||
|
{
|
||||||
|
_glfw_dlclose(_glfw.egl.handle);
|
||||||
|
_glfw.egl.handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define setEGLattrib(attribName, attribValue) \
|
||||||
|
{ \
|
||||||
|
attribs[index++] = attribName; \
|
||||||
|
attribs[index++] = attribValue; \
|
||||||
|
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the OpenGL or OpenGL ES context
|
||||||
|
//
|
||||||
|
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
|
{
|
||||||
|
EGLint attribs[40];
|
||||||
|
EGLConfig config;
|
||||||
|
EGLContext share = NULL;
|
||||||
|
|
||||||
|
if (!_glfw.egl.display)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->share)
|
||||||
|
share = ctxconfig->share->context.egl.handle;
|
||||||
|
|
||||||
|
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find a suitable EGLConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to bind OpenGL ES: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!eglBindAPI(EGL_OPENGL_API))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to bind OpenGL: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.egl.KHR_create_context)
|
||||||
|
{
|
||||||
|
int index = 0, mask = 0, flags = 0;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->forward)
|
||||||
|
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||||
|
|
||||||
|
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||||
|
mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
|
||||||
|
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||||
|
mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
|
||||||
|
|
||||||
|
if (_glfw.egl.KHR_create_context_no_error)
|
||||||
|
{
|
||||||
|
if (ctxconfig->noerror)
|
||||||
|
flags |= EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->debug)
|
||||||
|
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||||
|
|
||||||
|
if (ctxconfig->robustness)
|
||||||
|
{
|
||||||
|
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||||
|
{
|
||||||
|
setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||||
|
EGL_NO_RESET_NOTIFICATION_KHR);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||||
|
{
|
||||||
|
setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||||
|
EGL_LOSE_CONTEXT_ON_RESET_KHR);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||||
|
{
|
||||||
|
setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||||
|
setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask)
|
||||||
|
setEGLattrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||||
|
|
||||||
|
setEGLattrib(EGL_NONE, EGL_NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
|
||||||
|
|
||||||
|
setEGLattrib(EGL_NONE, EGL_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context release behaviors (GL_KHR_context_flush_control) are not yet
|
||||||
|
// supported on EGL but are not a hard constraint, so ignore and continue
|
||||||
|
|
||||||
|
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
|
||||||
|
config, share, attribs);
|
||||||
|
|
||||||
|
if (window->context.egl.handle == EGL_NO_CONTEXT)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"EGL: Failed to create context: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up attributes for surface creation
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if (fbconfig->sRGB)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.KHR_gl_colorspace)
|
||||||
|
{
|
||||||
|
setEGLattrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setEGLattrib(EGL_NONE, EGL_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.egl.surface =
|
||||||
|
eglCreateWindowSurface(_glfw.egl.display,
|
||||||
|
config,
|
||||||
|
_GLFW_EGL_NATIVE_WINDOW,
|
||||||
|
attribs);
|
||||||
|
if (window->context.egl.surface == EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: Failed to create window surface: %s",
|
||||||
|
getEGLErrorString(eglGetError()));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.egl.config = config;
|
||||||
|
|
||||||
|
// Load the appropriate client library
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char** sonames;
|
||||||
|
const char* es1sonames[] =
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_WIN32)
|
||||||
|
"GLESv1_CM.dll",
|
||||||
|
"libGLES_CM.dll",
|
||||||
|
#elif defined(_GLFW_COCOA)
|
||||||
|
"libGLESv1_CM.dylib",
|
||||||
|
#else
|
||||||
|
"libGLESv1_CM.so.1",
|
||||||
|
"libGLES_CM.so.1",
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char* es2sonames[] =
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_WIN32)
|
||||||
|
"GLESv2.dll",
|
||||||
|
"libGLESv2.dll",
|
||||||
|
#elif defined(_GLFW_COCOA)
|
||||||
|
"libGLESv2.dylib",
|
||||||
|
#else
|
||||||
|
"libGLESv2.so.2",
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char* glsonames[] =
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_WIN32)
|
||||||
|
#elif defined(_GLFW_COCOA)
|
||||||
|
#else
|
||||||
|
"libGL.so.1",
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->major == 1)
|
||||||
|
sonames = es1sonames;
|
||||||
|
else
|
||||||
|
sonames = es2sonames;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sonames = glsonames;
|
||||||
|
|
||||||
|
for (i = 0; sonames[i]; i++)
|
||||||
|
{
|
||||||
|
// HACK: Match presence of lib prefix to increase chance of finding
|
||||||
|
// a matching pair in the jungle that is Win32 EGL/GLES
|
||||||
|
if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
window->context.egl.client = _glfw_dlopen(sonames[i]);
|
||||||
|
if (window->context.egl.client)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window->context.egl.client)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to load client library");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.makeCurrent = makeContextCurrentEGL;
|
||||||
|
window->context.swapBuffers = swapBuffersEGL;
|
||||||
|
window->context.swapInterval = swapIntervalEGL;
|
||||||
|
window->context.extensionSupported = extensionSupportedEGL;
|
||||||
|
window->context.getProcAddress = getProcAddressEGL;
|
||||||
|
window->context.destroy = destroyContextEGL;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef setEGLattrib
|
||||||
|
|
||||||
|
// Returns the Visual and depth of the chosen EGLConfig
|
||||||
|
//
|
||||||
|
#if defined(_GLFW_X11)
|
||||||
|
GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig,
|
||||||
|
Visual** visual, int* depth)
|
||||||
|
{
|
||||||
|
XVisualInfo* result;
|
||||||
|
XVisualInfo desired;
|
||||||
|
EGLConfig native;
|
||||||
|
EGLint visualID = 0, count = 0;
|
||||||
|
const long vimask = VisualScreenMask | VisualIDMask;
|
||||||
|
|
||||||
|
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find a suitable EGLConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
eglGetConfigAttrib(_glfw.egl.display, native,
|
||||||
|
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||||
|
|
||||||
|
desired.screen = _glfw.x11.screen;
|
||||||
|
desired.visualid = visualID;
|
||||||
|
|
||||||
|
result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"EGL: Failed to retrieve Visual for EGLConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*visual = result->visual;
|
||||||
|
*depth = result->depth;
|
||||||
|
|
||||||
|
XFree(result);
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
#endif // _GLFW_X11
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
|
||||||
|
return _glfw.egl.display;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return EGL_NO_CONTEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.egl.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.egl.surface;
|
||||||
|
}
|
||||||
|
|
213
external/glfw/egl_context.h
vendored
Normal file
213
external/glfw/egl_context.h
vendored
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 EGL - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_egl_context_h_
|
||||||
|
#define _glfw3_egl_context_h_
|
||||||
|
|
||||||
|
#if defined(_GLFW_USE_EGLPLATFORM_H)
|
||||||
|
#include <EGL/eglplatform.h>
|
||||||
|
#elif defined(_GLFW_WIN32)
|
||||||
|
#define EGLAPIENTRY __stdcall
|
||||||
|
typedef HDC EGLNativeDisplayType;
|
||||||
|
typedef HWND EGLNativeWindowType;
|
||||||
|
#elif defined(_GLFW_X11)
|
||||||
|
#define EGLAPIENTRY
|
||||||
|
typedef Display* EGLNativeDisplayType;
|
||||||
|
typedef Window EGLNativeWindowType;
|
||||||
|
#elif defined(_GLFW_WAYLAND)
|
||||||
|
#define EGLAPIENTRY
|
||||||
|
typedef struct wl_display* EGLNativeDisplayType;
|
||||||
|
typedef struct wl_egl_window* EGLNativeWindowType;
|
||||||
|
#elif defined(_GLFW_MIR)
|
||||||
|
#define EGLAPIENTRY
|
||||||
|
typedef MirEGLNativeDisplayType EGLNativeDisplayType;
|
||||||
|
typedef MirEGLNativeWindowType EGLNativeWindowType;
|
||||||
|
#else
|
||||||
|
#error "No supported EGL platform selected"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EGL_SUCCESS 0x3000
|
||||||
|
#define EGL_NOT_INITIALIZED 0x3001
|
||||||
|
#define EGL_BAD_ACCESS 0x3002
|
||||||
|
#define EGL_BAD_ALLOC 0x3003
|
||||||
|
#define EGL_BAD_ATTRIBUTE 0x3004
|
||||||
|
#define EGL_BAD_CONFIG 0x3005
|
||||||
|
#define EGL_BAD_CONTEXT 0x3006
|
||||||
|
#define EGL_BAD_CURRENT_SURFACE 0x3007
|
||||||
|
#define EGL_BAD_DISPLAY 0x3008
|
||||||
|
#define EGL_BAD_MATCH 0x3009
|
||||||
|
#define EGL_BAD_NATIVE_PIXMAP 0x300a
|
||||||
|
#define EGL_BAD_NATIVE_WINDOW 0x300b
|
||||||
|
#define EGL_BAD_PARAMETER 0x300c
|
||||||
|
#define EGL_BAD_SURFACE 0x300d
|
||||||
|
#define EGL_CONTEXT_LOST 0x300e
|
||||||
|
#define EGL_COLOR_BUFFER_TYPE 0x303f
|
||||||
|
#define EGL_RGB_BUFFER 0x308e
|
||||||
|
#define EGL_SURFACE_TYPE 0x3033
|
||||||
|
#define EGL_WINDOW_BIT 0x0004
|
||||||
|
#define EGL_RENDERABLE_TYPE 0x3040
|
||||||
|
#define EGL_OPENGL_ES_BIT 0x0001
|
||||||
|
#define EGL_OPENGL_ES2_BIT 0x0004
|
||||||
|
#define EGL_OPENGL_BIT 0x0008
|
||||||
|
#define EGL_ALPHA_SIZE 0x3021
|
||||||
|
#define EGL_BLUE_SIZE 0x3022
|
||||||
|
#define EGL_GREEN_SIZE 0x3023
|
||||||
|
#define EGL_RED_SIZE 0x3024
|
||||||
|
#define EGL_DEPTH_SIZE 0x3025
|
||||||
|
#define EGL_STENCIL_SIZE 0x3026
|
||||||
|
#define EGL_SAMPLES 0x3031
|
||||||
|
#define EGL_OPENGL_ES_API 0x30a0
|
||||||
|
#define EGL_OPENGL_API 0x30a2
|
||||||
|
#define EGL_NONE 0x3038
|
||||||
|
#define EGL_EXTENSIONS 0x3055
|
||||||
|
#define EGL_CONTEXT_CLIENT_VERSION 0x3098
|
||||||
|
#define EGL_NATIVE_VISUAL_ID 0x302e
|
||||||
|
#define EGL_NO_SURFACE ((EGLSurface) 0)
|
||||||
|
#define EGL_NO_DISPLAY ((EGLDisplay) 0)
|
||||||
|
#define EGL_NO_CONTEXT ((EGLContext) 0)
|
||||||
|
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType) 0)
|
||||||
|
|
||||||
|
#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
|
||||||
|
#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
|
||||||
|
#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
|
||||||
|
#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
|
||||||
|
#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31bd
|
||||||
|
#define EGL_NO_RESET_NOTIFICATION_KHR 0x31be
|
||||||
|
#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31bf
|
||||||
|
#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
|
||||||
|
#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
|
||||||
|
#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30fb
|
||||||
|
#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30fd
|
||||||
|
#define EGL_CONTEXT_FLAGS_KHR 0x30fc
|
||||||
|
#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31b3
|
||||||
|
#define EGL_GL_COLORSPACE_KHR 0x309d
|
||||||
|
#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
|
||||||
|
|
||||||
|
typedef int EGLint;
|
||||||
|
typedef unsigned int EGLBoolean;
|
||||||
|
typedef unsigned int EGLenum;
|
||||||
|
typedef void* EGLConfig;
|
||||||
|
typedef void* EGLContext;
|
||||||
|
typedef void* EGLDisplay;
|
||||||
|
typedef void* EGLSurface;
|
||||||
|
|
||||||
|
// EGL function pointer typedefs
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay,EGLConfig,EGLint,EGLint*);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLGETCONFIGSPROC)(EGLDisplay,EGLConfig*,EGLint,EGLint*);
|
||||||
|
typedef EGLDisplay (EGLAPIENTRY * PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType);
|
||||||
|
typedef EGLint (EGLAPIENTRY * PFNEGLGETERRORPROC)(void);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLINITIALIZEPROC)(EGLDisplay,EGLint*,EGLint*);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLTERMINATEPROC)(EGLDisplay);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLBINDAPIPROC)(EGLenum);
|
||||||
|
typedef EGLContext (EGLAPIENTRY * PFNEGLCREATECONTEXTPROC)(EGLDisplay,EGLConfig,EGLContext,const EGLint*);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYSURFACEPROC)(EGLDisplay,EGLSurface);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLDESTROYCONTEXTPROC)(EGLDisplay,EGLContext);
|
||||||
|
typedef EGLSurface (EGLAPIENTRY * PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay,EGLConfig,EGLNativeWindowType,const EGLint*);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLMAKECURRENTPROC)(EGLDisplay,EGLSurface,EGLSurface,EGLContext);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPBUFFERSPROC)(EGLDisplay,EGLSurface);
|
||||||
|
typedef EGLBoolean (EGLAPIENTRY * PFNEGLSWAPINTERVALPROC)(EGLDisplay,EGLint);
|
||||||
|
typedef const char* (EGLAPIENTRY * PFNEGLQUERYSTRINGPROC)(EGLDisplay,EGLint);
|
||||||
|
typedef GLFWglproc (EGLAPIENTRY * PFNEGLGETPROCADDRESSPROC)(const char*);
|
||||||
|
#define eglGetConfigAttrib _glfw.egl.GetConfigAttrib
|
||||||
|
#define eglGetConfigs _glfw.egl.GetConfigs
|
||||||
|
#define eglGetDisplay _glfw.egl.GetDisplay
|
||||||
|
#define eglGetError _glfw.egl.GetError
|
||||||
|
#define eglInitialize _glfw.egl.Initialize
|
||||||
|
#define eglTerminate _glfw.egl.Terminate
|
||||||
|
#define eglBindAPI _glfw.egl.BindAPI
|
||||||
|
#define eglCreateContext _glfw.egl.CreateContext
|
||||||
|
#define eglDestroySurface _glfw.egl.DestroySurface
|
||||||
|
#define eglDestroyContext _glfw.egl.DestroyContext
|
||||||
|
#define eglCreateWindowSurface _glfw.egl.CreateWindowSurface
|
||||||
|
#define eglMakeCurrent _glfw.egl.MakeCurrent
|
||||||
|
#define eglSwapBuffers _glfw.egl.SwapBuffers
|
||||||
|
#define eglSwapInterval _glfw.egl.SwapInterval
|
||||||
|
#define eglQueryString _glfw.egl.QueryString
|
||||||
|
#define eglGetProcAddress _glfw.egl.GetProcAddress
|
||||||
|
|
||||||
|
#define _GLFW_EGL_CONTEXT_STATE _GLFWcontextEGL egl
|
||||||
|
#define _GLFW_EGL_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl
|
||||||
|
|
||||||
|
|
||||||
|
// EGL-specific per-context data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcontextEGL
|
||||||
|
{
|
||||||
|
EGLConfig config;
|
||||||
|
EGLContext handle;
|
||||||
|
EGLSurface surface;
|
||||||
|
|
||||||
|
void* client;
|
||||||
|
|
||||||
|
} _GLFWcontextEGL;
|
||||||
|
|
||||||
|
// EGL-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryEGL
|
||||||
|
{
|
||||||
|
EGLDisplay display;
|
||||||
|
EGLint major, minor;
|
||||||
|
GLFWbool prefix;
|
||||||
|
|
||||||
|
GLFWbool KHR_create_context;
|
||||||
|
GLFWbool KHR_create_context_no_error;
|
||||||
|
GLFWbool KHR_gl_colorspace;
|
||||||
|
|
||||||
|
void* handle;
|
||||||
|
|
||||||
|
PFNEGLGETCONFIGATTRIBPROC GetConfigAttrib;
|
||||||
|
PFNEGLGETCONFIGSPROC GetConfigs;
|
||||||
|
PFNEGLGETDISPLAYPROC GetDisplay;
|
||||||
|
PFNEGLGETERRORPROC GetError;
|
||||||
|
PFNEGLINITIALIZEPROC Initialize;
|
||||||
|
PFNEGLTERMINATEPROC Terminate;
|
||||||
|
PFNEGLBINDAPIPROC BindAPI;
|
||||||
|
PFNEGLCREATECONTEXTPROC CreateContext;
|
||||||
|
PFNEGLDESTROYSURFACEPROC DestroySurface;
|
||||||
|
PFNEGLDESTROYCONTEXTPROC DestroyContext;
|
||||||
|
PFNEGLCREATEWINDOWSURFACEPROC CreateWindowSurface;
|
||||||
|
PFNEGLMAKECURRENTPROC MakeCurrent;
|
||||||
|
PFNEGLSWAPBUFFERSPROC SwapBuffers;
|
||||||
|
PFNEGLSWAPINTERVALPROC SwapInterval;
|
||||||
|
PFNEGLQUERYSTRINGPROC QueryString;
|
||||||
|
PFNEGLGETPROCADDRESSPROC GetProcAddress;
|
||||||
|
|
||||||
|
} _GLFWlibraryEGL;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitEGL(void);
|
||||||
|
void _glfwTerminateEGL(void);
|
||||||
|
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig);
|
||||||
|
#if defined(_GLFW_X11)
|
||||||
|
GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig,
|
||||||
|
Visual** visual, int* depth);
|
||||||
|
#endif /*_GLFW_X11*/
|
||||||
|
|
||||||
|
#endif // _glfw3_egl_context_h_
|
4248
external/glfw/glfw3.h
vendored
Normal file
4248
external/glfw/glfw3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
13
external/glfw/glfw3.pc.in
vendored
Normal file
13
external/glfw/glfw3.pc.in
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
includedir=${prefix}/include
|
||||||
|
libdir=${exec_prefix}/lib@LIB_SUFFIX@
|
||||||
|
|
||||||
|
Name: GLFW
|
||||||
|
Description: A multi-platform library for OpenGL, window and input
|
||||||
|
Version: @GLFW_VERSION_FULL@
|
||||||
|
URL: http://www.glfw.org/
|
||||||
|
Requires.private: @GLFW_PKG_DEPS@
|
||||||
|
Libs: -L${libdir} -l@GLFW_LIB_NAME@
|
||||||
|
Libs.private: @GLFW_PKG_LIBS@
|
||||||
|
Cflags: -I${includedir}
|
1
external/glfw/glfw3Config.cmake.in
vendored
Normal file
1
external/glfw/glfw3Config.cmake.in
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/glfw3Targets.cmake")
|
456
external/glfw/glfw3native.h
vendored
Normal file
456
external/glfw/glfw3native.h
vendored
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* GLFW 3.3 - www.glfw.org
|
||||||
|
* A library for OpenGL, window and input
|
||||||
|
*------------------------------------------------------------------------
|
||||||
|
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
* Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
*
|
||||||
|
* 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 _glfw3_native_h_
|
||||||
|
#define _glfw3_native_h_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Doxygen documentation
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
/*! @file glfw3native.h
|
||||||
|
* @brief The header of the native access functions.
|
||||||
|
*
|
||||||
|
* This is the header file of the native access functions. See @ref native for
|
||||||
|
* more information.
|
||||||
|
*/
|
||||||
|
/*! @defgroup native Native access
|
||||||
|
*
|
||||||
|
* **By using the native access functions you assert that you know what you're
|
||||||
|
* doing and how to fix problems caused by using them. If you don't, you
|
||||||
|
* shouldn't be using them.**
|
||||||
|
*
|
||||||
|
* Before the inclusion of @ref glfw3native.h, you may define exactly one
|
||||||
|
* window system API macro and zero or more context creation API macros.
|
||||||
|
*
|
||||||
|
* The chosen backends must match those the library was compiled for. Failure
|
||||||
|
* to do this will cause a link-time error.
|
||||||
|
*
|
||||||
|
* The available window API macros are:
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_WIN32`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_MIR`
|
||||||
|
*
|
||||||
|
* The available context API macros are:
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||||
|
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||||
|
*
|
||||||
|
* These macros select which of the native access functions that are declared
|
||||||
|
* and which platform-specific headers to include. It is then up your (by
|
||||||
|
* definition platform-specific) code to handle which of these should be
|
||||||
|
* defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* System headers and types
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||||
|
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||||
|
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||||
|
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||||
|
#undef APIENTRY
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#else
|
||||||
|
typedef void* id;
|
||||||
|
#endif
|
||||||
|
#elif defined(GLFW_EXPOSE_NATIVE_X11)
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||||
|
#include <mir_toolkit/mir_client_library.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||||
|
/* WGL is declared by windows.h */
|
||||||
|
#endif
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||||
|
/* NSGL is declared by Cocoa.h */
|
||||||
|
#endif
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#endif
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Functions
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||||
|
/*! @brief Returns the adapter device name of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
|
||||||
|
* of the specified monitor, or `NULL` if an [error](@ref error_handling)
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.1.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the display device name of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The UTF-8 encoded display device name (for example
|
||||||
|
* `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.1.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the `HWND` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `HWND` of the specified window, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||||
|
/*! @brief Returns the `HGLRC` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `HGLRC` of the specified window, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||||
|
/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The `CGDirectDisplayID` of the specified monitor, or
|
||||||
|
* `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.1.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the `NSWindow` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `NSWindow` of the specified window, or `nil` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||||
|
/*! @brief Returns the `NSOpenGLContext` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `NSOpenGLContext` of the specified window, or `nil` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_X11)
|
||||||
|
/*! @brief Returns the `Display` used by GLFW.
|
||||||
|
*
|
||||||
|
* @return The `Display` used by GLFW, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI Display* glfwGetX11Display(void);
|
||||||
|
|
||||||
|
/*! @brief Returns the `RRCrtc` of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The `RRCrtc` of the specified monitor, or `None` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.1.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the `RROutput` of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The `RROutput` of the specified monitor, or `None` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.1.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the `Window` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `Window` of the specified window, or `None` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||||
|
/*! @brief Returns the `GLXContext` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `GLXContext` of the specified window, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
|
||||||
|
|
||||||
|
/*! @brief Returns the `GLXWindow` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `GLXWindow` of the specified window, or `None` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||||
|
/*! @brief Returns the `struct wl_display*` used by GLFW.
|
||||||
|
*
|
||||||
|
* @return The `struct wl_display*` used by GLFW, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
|
||||||
|
|
||||||
|
/*! @brief Returns the `struct wl_output*` of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The `struct wl_output*` of the specified monitor, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the main `struct wl_surface*` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The main `struct wl_surface*` of the specified window, or `NULL` if
|
||||||
|
* an [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||||
|
/*! @brief Returns the `MirConnection*` used by GLFW.
|
||||||
|
*
|
||||||
|
* @return The `MirConnection*` used by GLFW, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI MirConnection* glfwGetMirDisplay(void);
|
||||||
|
|
||||||
|
/*! @brief Returns the Mir output ID of the specified monitor.
|
||||||
|
*
|
||||||
|
* @return The Mir output ID of the specified monitor, or zero if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
/*! @brief Returns the `MirSurface*` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `MirSurface*` of the specified window, or `NULL` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.2.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||||
|
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||||
|
*
|
||||||
|
* @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
|
||||||
|
|
||||||
|
/*! @brief Returns the `EGLContext` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
|
||||||
|
|
||||||
|
/*! @brief Returns the `EGLSurface` of the specified window.
|
||||||
|
*
|
||||||
|
* @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
|
||||||
|
* [error](@ref error_handling) occurred.
|
||||||
|
*
|
||||||
|
* @thread_safety This function may be called from any thread. Access is not
|
||||||
|
* synchronized.
|
||||||
|
*
|
||||||
|
* @since Added in version 3.0.
|
||||||
|
*
|
||||||
|
* @ingroup native
|
||||||
|
*/
|
||||||
|
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _glfw3_native_h_ */
|
||||||
|
|
65
external/glfw/glfw_config.h
vendored
Normal file
65
external/glfw/glfw_config.h
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2010-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
// As glfw_config.h.in, this file is used by CMake to produce the
|
||||||
|
// glfw_config.h configuration header file. If you are adding a feature
|
||||||
|
// requiring conditional compilation, this is where to add the macro.
|
||||||
|
//========================================================================
|
||||||
|
// As glfw_config.h, this file defines compile-time option macros for a
|
||||||
|
// specific platform and development environment. If you are using the
|
||||||
|
// GLFW CMake files, modify glfw_config.h.in instead of this file. If you
|
||||||
|
// are using your own build system, make this file define the appropriate
|
||||||
|
// macros in whatever way is suitable.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
// Define this to 1 if building GLFW for X11
|
||||||
|
/* #undef _GLFW_X11 */
|
||||||
|
// Define this to 1 if building GLFW for Win32
|
||||||
|
#define _GLFW_WIN32
|
||||||
|
// Define this to 1 if building GLFW for Cocoa
|
||||||
|
/* #undef _GLFW_COCOA */
|
||||||
|
// Define this to 1 if building GLFW for Wayland
|
||||||
|
/* #undef _GLFW_WAYLAND */
|
||||||
|
// Define this to 1 if building GLFW for Mir
|
||||||
|
/* #undef _GLFW_MIR */
|
||||||
|
|
||||||
|
// Define this to 1 if building as a shared library / dynamic library / DLL
|
||||||
|
/* #undef _GLFW_BUILD_DLL */
|
||||||
|
// Define this to 1 to use Vulkan loader linked statically into application
|
||||||
|
/* #undef _GLFW_VULKAN_STATIC */
|
||||||
|
|
||||||
|
// Define this to 1 to force use of high-performance GPU on hybrid systems
|
||||||
|
/* #undef _GLFW_USE_HYBRID_HPG */
|
||||||
|
|
||||||
|
// Define this to 1 if the Xxf86vm X11 extension is available
|
||||||
|
/* #undef _GLFW_HAS_XF86VM */
|
||||||
|
|
||||||
|
// Define this to 1 if glfwInit should change the current directory
|
||||||
|
/* #undef _GLFW_USE_CHDIR */
|
||||||
|
// Define this to 1 if glfwCreateWindow should populate the menu bar
|
||||||
|
/* #undef _GLFW_USE_MENUBAR */
|
||||||
|
// Define this to 1 if windows should use full resolution on Retina displays
|
||||||
|
/* #undef _GLFW_USE_RETINA */
|
||||||
|
|
65
external/glfw/glfw_config.h.in
vendored
Normal file
65
external/glfw/glfw_config.h.in
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2010-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
// As glfw_config.h.in, this file is used by CMake to produce the
|
||||||
|
// glfw_config.h configuration header file. If you are adding a feature
|
||||||
|
// requiring conditional compilation, this is where to add the macro.
|
||||||
|
//========================================================================
|
||||||
|
// As glfw_config.h, this file defines compile-time option macros for a
|
||||||
|
// specific platform and development environment. If you are using the
|
||||||
|
// GLFW CMake files, modify glfw_config.h.in instead of this file. If you
|
||||||
|
// are using your own build system, make this file define the appropriate
|
||||||
|
// macros in whatever way is suitable.
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
// Define this to 1 if building GLFW for X11
|
||||||
|
#cmakedefine _GLFW_X11
|
||||||
|
// Define this to 1 if building GLFW for Win32
|
||||||
|
#cmakedefine _GLFW_WIN32
|
||||||
|
// Define this to 1 if building GLFW for Cocoa
|
||||||
|
#cmakedefine _GLFW_COCOA
|
||||||
|
// Define this to 1 if building GLFW for Wayland
|
||||||
|
#cmakedefine _GLFW_WAYLAND
|
||||||
|
// Define this to 1 if building GLFW for Mir
|
||||||
|
#cmakedefine _GLFW_MIR
|
||||||
|
|
||||||
|
// Define this to 1 if building as a shared library / dynamic library / DLL
|
||||||
|
#cmakedefine _GLFW_BUILD_DLL
|
||||||
|
// Define this to 1 to use Vulkan loader linked statically into application
|
||||||
|
#cmakedefine _GLFW_VULKAN_STATIC
|
||||||
|
|
||||||
|
// Define this to 1 to force use of high-performance GPU on hybrid systems
|
||||||
|
#cmakedefine _GLFW_USE_HYBRID_HPG
|
||||||
|
|
||||||
|
// Define this to 1 if the Xxf86vm X11 extension is available
|
||||||
|
#cmakedefine _GLFW_HAS_XF86VM
|
||||||
|
|
||||||
|
// Define this to 1 if glfwInit should change the current directory
|
||||||
|
#cmakedefine _GLFW_USE_CHDIR
|
||||||
|
// Define this to 1 if glfwCreateWindow should populate the menu bar
|
||||||
|
#cmakedefine _GLFW_USE_MENUBAR
|
||||||
|
// Define this to 1 if windows should use full resolution on Retina displays
|
||||||
|
#cmakedefine _GLFW_USE_RETINA
|
||||||
|
|
677
external/glfw/glx_context.c
vendored
Normal file
677
external/glfw/glx_context.c
vendored
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 GLX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifndef GLXBadProfileARB
|
||||||
|
#define GLXBadProfileARB 13
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the specified attribute of the specified GLXFBConfig
|
||||||
|
//
|
||||||
|
static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the GLXFBConfig most closely matching the specified hints
|
||||||
|
//
|
||||||
|
static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result)
|
||||||
|
{
|
||||||
|
GLXFBConfig* nativeConfigs;
|
||||||
|
_GLFWfbconfig* usableConfigs;
|
||||||
|
const _GLFWfbconfig* closest;
|
||||||
|
int i, nativeCount, usableCount;
|
||||||
|
const char* vendor;
|
||||||
|
GLFWbool trustWindowBit = GLFW_TRUE;
|
||||||
|
|
||||||
|
// HACK: This is a (hopefully temporary) workaround for Chromium
|
||||||
|
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
||||||
|
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
||||||
|
if (strcmp(vendor, "Chromium") == 0)
|
||||||
|
trustWindowBit = GLFW_FALSE;
|
||||||
|
|
||||||
|
nativeConfigs =
|
||||||
|
glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, &nativeCount);
|
||||||
|
if (!nativeCount)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||||
|
usableCount = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nativeCount; i++)
|
||||||
|
{
|
||||||
|
const GLXFBConfig n = nativeConfigs[i];
|
||||||
|
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||||
|
|
||||||
|
// Only consider RGBA GLXFBConfigs
|
||||||
|
if (!(getGLXFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Only consider window GLXFBConfigs
|
||||||
|
if (!(getGLXFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
|
||||||
|
{
|
||||||
|
if (trustWindowBit)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
|
||||||
|
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE);
|
||||||
|
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE);
|
||||||
|
|
||||||
|
u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
|
||||||
|
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE);
|
||||||
|
u->stencilBits = getGLXFBConfigAttrib(n, GLX_STENCIL_SIZE);
|
||||||
|
|
||||||
|
u->accumRedBits = getGLXFBConfigAttrib(n, GLX_ACCUM_RED_SIZE);
|
||||||
|
u->accumGreenBits = getGLXFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE);
|
||||||
|
u->accumBlueBits = getGLXFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE);
|
||||||
|
u->accumAlphaBits = getGLXFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE);
|
||||||
|
|
||||||
|
u->auxBuffers = getGLXFBConfigAttrib(n, GLX_AUX_BUFFERS);
|
||||||
|
|
||||||
|
if (getGLXFBConfigAttrib(n, GLX_STEREO))
|
||||||
|
u->stereo = GLFW_TRUE;
|
||||||
|
if (getGLXFBConfigAttrib(n, GLX_DOUBLEBUFFER))
|
||||||
|
u->doublebuffer = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (_glfw.glx.ARB_multisample)
|
||||||
|
u->samples = getGLXFBConfigAttrib(n, GLX_SAMPLES);
|
||||||
|
|
||||||
|
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
|
||||||
|
u->sRGB = getGLXFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
||||||
|
|
||||||
|
u->handle = (uintptr_t) n;
|
||||||
|
usableCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||||
|
if (closest)
|
||||||
|
*result = (GLXFBConfig) closest->handle;
|
||||||
|
|
||||||
|
XFree(nativeConfigs);
|
||||||
|
free(usableConfigs);
|
||||||
|
|
||||||
|
return closest != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the OpenGL context using legacy API
|
||||||
|
//
|
||||||
|
static GLXContext createLegacyContextGLX(_GLFWwindow* window,
|
||||||
|
GLXFBConfig fbconfig,
|
||||||
|
GLXContext share)
|
||||||
|
{
|
||||||
|
return glXCreateNewContext(_glfw.x11.display,
|
||||||
|
fbconfig,
|
||||||
|
GLX_RGBA_TYPE,
|
||||||
|
share,
|
||||||
|
True);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeContextCurrentGLX(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(_glfw.x11.display,
|
||||||
|
window->context.glx.window,
|
||||||
|
window->context.glx.handle))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"GLX: Failed to make context current");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(_glfw.x11.display, None, NULL))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"GLX: Failed to clear current context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformSetCurrentContext(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapBuffersGLX(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
glXSwapBuffers(_glfw.x11.display, window->context.glx.window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapIntervalGLX(int interval)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
if (_glfw.glx.EXT_swap_control)
|
||||||
|
{
|
||||||
|
_glfw.glx.SwapIntervalEXT(_glfw.x11.display,
|
||||||
|
window->context.glx.window,
|
||||||
|
interval);
|
||||||
|
}
|
||||||
|
else if (_glfw.glx.MESA_swap_control)
|
||||||
|
_glfw.glx.SwapIntervalMESA(interval);
|
||||||
|
else if (_glfw.glx.SGI_swap_control)
|
||||||
|
{
|
||||||
|
if (interval > 0)
|
||||||
|
_glfw.glx.SwapIntervalSGI(interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extensionSupportedGLX(const char* extension)
|
||||||
|
{
|
||||||
|
const char* extensions =
|
||||||
|
glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
if (_glfwStringInExtensionString(extension, extensions))
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWglproc getProcAddressGLX(const char* procname)
|
||||||
|
{
|
||||||
|
if (_glfw.glx.GetProcAddress)
|
||||||
|
return _glfw.glx.GetProcAddress((const GLubyte*) procname);
|
||||||
|
else if (_glfw.glx.GetProcAddressARB)
|
||||||
|
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
||||||
|
else
|
||||||
|
return dlsym(_glfw.glx.handle, procname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the OpenGL context
|
||||||
|
//
|
||||||
|
static void destroyContextGLX(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window->context.glx.window)
|
||||||
|
{
|
||||||
|
glXDestroyWindow(_glfw.x11.display, window->context.glx.window);
|
||||||
|
window->context.glx.window = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.glx.handle)
|
||||||
|
{
|
||||||
|
glXDestroyContext(_glfw.x11.display, window->context.glx.handle);
|
||||||
|
window->context.glx.handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize GLX
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitGLX(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char* sonames[] =
|
||||||
|
{
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
"libGL-1.so",
|
||||||
|
#else
|
||||||
|
"libGL.so.1",
|
||||||
|
"libGL.so",
|
||||||
|
#endif
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_glfw.glx.handle)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
for (i = 0; sonames[i]; i++)
|
||||||
|
{
|
||||||
|
_glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
if (_glfw.glx.handle)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfw.glx.handle)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.glx.GetFBConfigs =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetFBConfigs");
|
||||||
|
_glfw.glx.GetFBConfigAttrib =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetFBConfigAttrib");
|
||||||
|
_glfw.glx.GetClientString =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetClientString");
|
||||||
|
_glfw.glx.QueryExtension =
|
||||||
|
dlsym(_glfw.glx.handle, "glXQueryExtension");
|
||||||
|
_glfw.glx.QueryVersion =
|
||||||
|
dlsym(_glfw.glx.handle, "glXQueryVersion");
|
||||||
|
_glfw.glx.DestroyContext =
|
||||||
|
dlsym(_glfw.glx.handle, "glXDestroyContext");
|
||||||
|
_glfw.glx.MakeCurrent =
|
||||||
|
dlsym(_glfw.glx.handle, "glXMakeCurrent");
|
||||||
|
_glfw.glx.SwapBuffers =
|
||||||
|
dlsym(_glfw.glx.handle, "glXSwapBuffers");
|
||||||
|
_glfw.glx.QueryExtensionsString =
|
||||||
|
dlsym(_glfw.glx.handle, "glXQueryExtensionsString");
|
||||||
|
_glfw.glx.CreateNewContext =
|
||||||
|
dlsym(_glfw.glx.handle, "glXCreateNewContext");
|
||||||
|
_glfw.glx.CreateWindow =
|
||||||
|
dlsym(_glfw.glx.handle, "glXCreateWindow");
|
||||||
|
_glfw.glx.DestroyWindow =
|
||||||
|
dlsym(_glfw.glx.handle, "glXDestroyWindow");
|
||||||
|
_glfw.glx.GetProcAddress =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
||||||
|
_glfw.glx.GetProcAddressARB =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
||||||
|
_glfw.glx.GetVisualFromFBConfig =
|
||||||
|
dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||||
|
|
||||||
|
if (!_glfw.glx.GetFBConfigs ||
|
||||||
|
!_glfw.glx.GetFBConfigAttrib ||
|
||||||
|
!_glfw.glx.GetClientString ||
|
||||||
|
!_glfw.glx.QueryExtension ||
|
||||||
|
!_glfw.glx.QueryVersion ||
|
||||||
|
!_glfw.glx.DestroyContext ||
|
||||||
|
!_glfw.glx.MakeCurrent ||
|
||||||
|
!_glfw.glx.SwapBuffers ||
|
||||||
|
!_glfw.glx.QueryExtensionsString ||
|
||||||
|
!_glfw.glx.CreateNewContext ||
|
||||||
|
!_glfw.glx.CreateWindow ||
|
||||||
|
!_glfw.glx.DestroyWindow ||
|
||||||
|
!_glfw.glx.GetProcAddress ||
|
||||||
|
!_glfw.glx.GetProcAddressARB ||
|
||||||
|
!_glfw.glx.GetVisualFromFBConfig)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"GLX: Failed to load required entry points");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glXQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.glx.errorBase,
|
||||||
|
&_glfw.glx.eventBase))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glXQueryVersion(_glfw.x11.display, &_glfw.glx.major, &_glfw.glx.minor))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"GLX: Failed to query GLX version");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"GLX: GLX version 1.3 is required");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_EXT_swap_control"))
|
||||||
|
{
|
||||||
|
_glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
|
||||||
|
getProcAddressGLX("glXSwapIntervalEXT");
|
||||||
|
|
||||||
|
if (_glfw.glx.SwapIntervalEXT)
|
||||||
|
_glfw.glx.EXT_swap_control = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_SGI_swap_control"))
|
||||||
|
{
|
||||||
|
_glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
|
||||||
|
getProcAddressGLX("glXSwapIntervalSGI");
|
||||||
|
|
||||||
|
if (_glfw.glx.SwapIntervalSGI)
|
||||||
|
_glfw.glx.SGI_swap_control = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_MESA_swap_control"))
|
||||||
|
{
|
||||||
|
_glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
|
||||||
|
getProcAddressGLX("glXSwapIntervalMESA");
|
||||||
|
|
||||||
|
if (_glfw.glx.SwapIntervalMESA)
|
||||||
|
_glfw.glx.MESA_swap_control = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_multisample"))
|
||||||
|
_glfw.glx.ARB_multisample = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_framebuffer_sRGB"))
|
||||||
|
_glfw.glx.ARB_framebuffer_sRGB = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_EXT_framebuffer_sRGB"))
|
||||||
|
_glfw.glx.EXT_framebuffer_sRGB = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_create_context"))
|
||||||
|
{
|
||||||
|
_glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
|
||||||
|
getProcAddressGLX("glXCreateContextAttribsARB");
|
||||||
|
|
||||||
|
if (_glfw.glx.CreateContextAttribsARB)
|
||||||
|
_glfw.glx.ARB_create_context = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_create_context_robustness"))
|
||||||
|
_glfw.glx.ARB_create_context_robustness = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_create_context_profile"))
|
||||||
|
_glfw.glx.ARB_create_context_profile = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_EXT_create_context_es2_profile"))
|
||||||
|
_glfw.glx.EXT_create_context_es2_profile = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (extensionSupportedGLX("GLX_ARB_context_flush_control"))
|
||||||
|
_glfw.glx.ARB_context_flush_control = GLFW_TRUE;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate GLX
|
||||||
|
//
|
||||||
|
void _glfwTerminateGLX(void)
|
||||||
|
{
|
||||||
|
// NOTE: This function must not call any X11 functions, as it is called
|
||||||
|
// after XCloseDisplay (see _glfwPlatformTerminate for details)
|
||||||
|
|
||||||
|
if (_glfw.glx.handle)
|
||||||
|
{
|
||||||
|
dlclose(_glfw.glx.handle);
|
||||||
|
_glfw.glx.handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define setGLXattrib(attribName, attribValue) \
|
||||||
|
{ \
|
||||||
|
attribs[index++] = attribName; \
|
||||||
|
attribs[index++] = attribValue; \
|
||||||
|
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the OpenGL or OpenGL ES context
|
||||||
|
//
|
||||||
|
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
|
{
|
||||||
|
int attribs[40];
|
||||||
|
GLXFBConfig native = NULL;
|
||||||
|
GLXContext share = NULL;
|
||||||
|
|
||||||
|
if (ctxconfig->share)
|
||||||
|
share = ctxconfig->share->context.glx.handle;
|
||||||
|
|
||||||
|
if (!chooseGLXFBConfig(fbconfig, &native))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"GLX: Failed to find a suitable GLXFBConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (!_glfw.glx.ARB_create_context ||
|
||||||
|
!_glfw.glx.ARB_create_context_profile ||
|
||||||
|
!_glfw.glx.EXT_create_context_es2_profile)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"GLX: OpenGL ES requested but GLX_EXT_create_context_es2_profile is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->forward)
|
||||||
|
{
|
||||||
|
if (!_glfw.glx.ARB_create_context)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"GLX: Forward compatibility requested but GLX_ARB_create_context_profile is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->profile)
|
||||||
|
{
|
||||||
|
if (!_glfw.glx.ARB_create_context ||
|
||||||
|
!_glfw.glx.ARB_create_context_profile)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"GLX: An OpenGL profile requested but GLX_ARB_create_context_profile is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
|
||||||
|
if (_glfw.glx.ARB_create_context)
|
||||||
|
{
|
||||||
|
int index = 0, mask = 0, flags = 0;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->forward)
|
||||||
|
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||||
|
|
||||||
|
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||||
|
mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||||
|
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||||
|
mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
|
||||||
|
|
||||||
|
if (ctxconfig->debug)
|
||||||
|
flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||||
|
if (ctxconfig->noerror)
|
||||||
|
flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
|
||||||
|
|
||||||
|
if (ctxconfig->robustness)
|
||||||
|
{
|
||||||
|
if (_glfw.glx.ARB_create_context_robustness)
|
||||||
|
{
|
||||||
|
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||||
|
{
|
||||||
|
setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
GLX_NO_RESET_NOTIFICATION_ARB);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||||
|
{
|
||||||
|
setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
GLX_LOSE_CONTEXT_ON_RESET_ARB);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->release)
|
||||||
|
{
|
||||||
|
if (_glfw.glx.ARB_context_flush_control)
|
||||||
|
{
|
||||||
|
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||||
|
{
|
||||||
|
setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||||
|
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||||
|
{
|
||||||
|
setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||||
|
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Only request an explicitly versioned context when necessary, as
|
||||||
|
// explicitly requesting version 1.0 does not always return the
|
||||||
|
// highest version supported by the driver
|
||||||
|
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||||
|
{
|
||||||
|
setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||||
|
setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask)
|
||||||
|
setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags);
|
||||||
|
|
||||||
|
setGLXattrib(None, None);
|
||||||
|
|
||||||
|
window->context.glx.handle =
|
||||||
|
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
|
||||||
|
native,
|
||||||
|
share,
|
||||||
|
True,
|
||||||
|
attribs);
|
||||||
|
|
||||||
|
// HACK: This is a fallback for broken versions of the Mesa
|
||||||
|
// implementation of GLX_ARB_create_context_profile that fail
|
||||||
|
// default 1.0 context creation with a GLXBadProfileARB error in
|
||||||
|
// violation of the extension spec
|
||||||
|
if (!window->context.glx.handle)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
|
||||||
|
ctxconfig->client == GLFW_OPENGL_API &&
|
||||||
|
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
|
||||||
|
ctxconfig->forward == GLFW_FALSE)
|
||||||
|
{
|
||||||
|
window->context.glx.handle =
|
||||||
|
createLegacyContextGLX(window, native, share);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->context.glx.handle =
|
||||||
|
createLegacyContextGLX(window, native, share);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
|
||||||
|
if (!window->context.glx.handle)
|
||||||
|
{
|
||||||
|
_glfwInputErrorX11(GLFW_VERSION_UNAVAILABLE, "GLX: Failed to create context");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.glx.window =
|
||||||
|
glXCreateWindow(_glfw.x11.display, native, window->x11.handle, NULL);
|
||||||
|
if (!window->context.glx.window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to create window");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.makeCurrent = makeContextCurrentGLX;
|
||||||
|
window->context.swapBuffers = swapBuffersGLX;
|
||||||
|
window->context.swapInterval = swapIntervalGLX;
|
||||||
|
window->context.extensionSupported = extensionSupportedGLX;
|
||||||
|
window->context.getProcAddress = getProcAddressGLX;
|
||||||
|
window->context.destroy = destroyContextGLX;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef setGLXattrib
|
||||||
|
|
||||||
|
// Returns the Visual and depth of the chosen GLXFBConfig
|
||||||
|
//
|
||||||
|
GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig,
|
||||||
|
Visual** visual, int* depth)
|
||||||
|
{
|
||||||
|
GLXFBConfig native;
|
||||||
|
XVisualInfo* result;
|
||||||
|
|
||||||
|
if (!chooseGLXFBConfig(fbconfig, &native))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"GLX: Failed to find a suitable GLXFBConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = glXGetVisualFromFBConfig(_glfw.x11.display, native);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"GLX: Failed to retrieve Visual for GLXFBConfig");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*visual = result->visual;
|
||||||
|
*depth = result->depth;
|
||||||
|
|
||||||
|
XFree(result);
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.glx.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.glx.window;
|
||||||
|
}
|
||||||
|
|
182
external/glfw/glx_context.h
vendored
Normal file
182
external/glfw/glx_context.h
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 GLX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_glx_context_h_
|
||||||
|
#define _glfw3_glx_context_h_
|
||||||
|
|
||||||
|
#define GLX_VENDOR 1
|
||||||
|
#define GLX_RGBA_BIT 0x00000001
|
||||||
|
#define GLX_WINDOW_BIT 0x00000001
|
||||||
|
#define GLX_DRAWABLE_TYPE 0x8010
|
||||||
|
#define GLX_RENDER_TYPE 0x8011
|
||||||
|
#define GLX_RGBA_TYPE 0x8014
|
||||||
|
#define GLX_DOUBLEBUFFER 5
|
||||||
|
#define GLX_STEREO 6
|
||||||
|
#define GLX_AUX_BUFFERS 7
|
||||||
|
#define GLX_RED_SIZE 8
|
||||||
|
#define GLX_GREEN_SIZE 9
|
||||||
|
#define GLX_BLUE_SIZE 10
|
||||||
|
#define GLX_ALPHA_SIZE 11
|
||||||
|
#define GLX_DEPTH_SIZE 12
|
||||||
|
#define GLX_STENCIL_SIZE 13
|
||||||
|
#define GLX_ACCUM_RED_SIZE 14
|
||||||
|
#define GLX_ACCUM_GREEN_SIZE 15
|
||||||
|
#define GLX_ACCUM_BLUE_SIZE 16
|
||||||
|
#define GLX_ACCUM_ALPHA_SIZE 17
|
||||||
|
#define GLX_SAMPLES 0x186a1
|
||||||
|
#define GLX_VISUAL_ID 0x800b
|
||||||
|
|
||||||
|
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
|
||||||
|
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||||
|
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||||
|
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||||
|
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||||
|
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
||||||
|
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||||
|
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||||
|
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
||||||
|
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||||
|
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
||||||
|
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
||||||
|
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
||||||
|
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
|
||||||
|
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
||||||
|
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
||||||
|
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
||||||
|
|
||||||
|
typedef XID GLXWindow;
|
||||||
|
typedef XID GLXDrawable;
|
||||||
|
typedef struct __GLXFBConfig* GLXFBConfig;
|
||||||
|
typedef struct __GLXcontext* GLXContext;
|
||||||
|
typedef void (*__GLXextproc)(void);
|
||||||
|
|
||||||
|
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
|
||||||
|
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
|
||||||
|
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
|
||||||
|
typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
|
||||||
|
typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
|
||||||
|
typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
|
||||||
|
typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
|
||||||
|
typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
|
||||||
|
typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
|
||||||
|
typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
|
||||||
|
typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
|
||||||
|
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
|
||||||
|
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
|
||||||
|
typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
|
||||||
|
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
|
||||||
|
typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
|
||||||
|
typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
|
||||||
|
typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
|
||||||
|
|
||||||
|
// libGL.so function pointer typedefs
|
||||||
|
#define glXGetFBConfigs _glfw.glx.GetFBConfigs
|
||||||
|
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
||||||
|
#define glXGetClientString _glfw.glx.GetClientString
|
||||||
|
#define glXQueryExtension _glfw.glx.QueryExtension
|
||||||
|
#define glXQueryVersion _glfw.glx.QueryVersion
|
||||||
|
#define glXDestroyContext _glfw.glx.DestroyContext
|
||||||
|
#define glXMakeCurrent _glfw.glx.MakeCurrent
|
||||||
|
#define glXSwapBuffers _glfw.glx.SwapBuffers
|
||||||
|
#define glXQueryExtensionsString _glfw.glx.QueryExtensionsString
|
||||||
|
#define glXCreateNewContext _glfw.glx.CreateNewContext
|
||||||
|
#define glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig
|
||||||
|
#define glXCreateWindow _glfw.glx.CreateWindow
|
||||||
|
#define glXDestroyWindow _glfw.glx.DestroyWindow
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx
|
||||||
|
|
||||||
|
|
||||||
|
// GLX-specific per-context data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcontextGLX
|
||||||
|
{
|
||||||
|
GLXContext handle;
|
||||||
|
GLXWindow window;
|
||||||
|
|
||||||
|
} _GLFWcontextGLX;
|
||||||
|
|
||||||
|
// GLX-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryGLX
|
||||||
|
{
|
||||||
|
int major, minor;
|
||||||
|
int eventBase;
|
||||||
|
int errorBase;
|
||||||
|
|
||||||
|
// dlopen handle for libGL.so.1
|
||||||
|
void* handle;
|
||||||
|
|
||||||
|
// GLX 1.3 functions
|
||||||
|
PFNGLXGETFBCONFIGSPROC GetFBConfigs;
|
||||||
|
PFNGLXGETFBCONFIGATTRIBPROC GetFBConfigAttrib;
|
||||||
|
PFNGLXGETCLIENTSTRINGPROC GetClientString;
|
||||||
|
PFNGLXQUERYEXTENSIONPROC QueryExtension;
|
||||||
|
PFNGLXQUERYVERSIONPROC QueryVersion;
|
||||||
|
PFNGLXDESTROYCONTEXTPROC DestroyContext;
|
||||||
|
PFNGLXMAKECURRENTPROC MakeCurrent;
|
||||||
|
PFNGLXSWAPBUFFERSPROC SwapBuffers;
|
||||||
|
PFNGLXQUERYEXTENSIONSSTRINGPROC QueryExtensionsString;
|
||||||
|
PFNGLXCREATENEWCONTEXTPROC CreateNewContext;
|
||||||
|
PFNGLXGETVISUALFROMFBCONFIGPROC GetVisualFromFBConfig;
|
||||||
|
PFNGLXCREATEWINDOWPROC CreateWindow;
|
||||||
|
PFNGLXDESTROYWINDOWPROC DestroyWindow;
|
||||||
|
|
||||||
|
// GLX 1.4 and extension functions
|
||||||
|
PFNGLXGETPROCADDRESSPROC GetProcAddress;
|
||||||
|
PFNGLXGETPROCADDRESSPROC GetProcAddressARB;
|
||||||
|
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI;
|
||||||
|
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||||
|
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
||||||
|
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||||
|
GLFWbool SGI_swap_control;
|
||||||
|
GLFWbool EXT_swap_control;
|
||||||
|
GLFWbool MESA_swap_control;
|
||||||
|
GLFWbool ARB_multisample;
|
||||||
|
GLFWbool ARB_framebuffer_sRGB;
|
||||||
|
GLFWbool EXT_framebuffer_sRGB;
|
||||||
|
GLFWbool ARB_create_context;
|
||||||
|
GLFWbool ARB_create_context_profile;
|
||||||
|
GLFWbool ARB_create_context_robustness;
|
||||||
|
GLFWbool EXT_create_context_es2_profile;
|
||||||
|
GLFWbool ARB_context_flush_control;
|
||||||
|
|
||||||
|
} _GLFWlibraryGLX;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitGLX(void);
|
||||||
|
void _glfwTerminateGLX(void);
|
||||||
|
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig);
|
||||||
|
void _glfwDestroyContextGLX(_GLFWwindow* window);
|
||||||
|
GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig,
|
||||||
|
Visual** visual, int* depth);
|
||||||
|
|
||||||
|
#endif // _glfw3_glx_context_h_
|
200
external/glfw/init.c
vendored
Normal file
200
external/glfw/init.c
vendored
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
|
// The three global variables below comprise all global data in GLFW.
|
||||||
|
// Any other global variable is a bug.
|
||||||
|
|
||||||
|
// Global state shared between compilation units of GLFW
|
||||||
|
// These are documented in internal.h
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitialized = GLFW_FALSE;
|
||||||
|
_GLFWlibrary _glfw;
|
||||||
|
|
||||||
|
// This is outside of _glfw so it can be initialized and usable before
|
||||||
|
// glfwInit is called, which lets that function report errors
|
||||||
|
//
|
||||||
|
static GLFWerrorfun _glfwErrorCallback = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
// Returns a generic string representation of the specified error
|
||||||
|
//
|
||||||
|
static const char* getErrorString(int error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case GLFW_NOT_INITIALIZED:
|
||||||
|
return "The GLFW library is not initialized";
|
||||||
|
case GLFW_NO_CURRENT_CONTEXT:
|
||||||
|
return "There is no current context";
|
||||||
|
case GLFW_INVALID_ENUM:
|
||||||
|
return "Invalid argument for enum parameter";
|
||||||
|
case GLFW_INVALID_VALUE:
|
||||||
|
return "Invalid value for parameter";
|
||||||
|
case GLFW_OUT_OF_MEMORY:
|
||||||
|
return "Out of memory";
|
||||||
|
case GLFW_API_UNAVAILABLE:
|
||||||
|
return "The requested API is unavailable";
|
||||||
|
case GLFW_VERSION_UNAVAILABLE:
|
||||||
|
return "The requested API version is unavailable";
|
||||||
|
case GLFW_PLATFORM_ERROR:
|
||||||
|
return "A platform-specific error occurred";
|
||||||
|
case GLFW_FORMAT_UNAVAILABLE:
|
||||||
|
return "The requested format is unavailable";
|
||||||
|
case GLFW_NO_WINDOW_CONTEXT:
|
||||||
|
return "The specified window has no context";
|
||||||
|
default:
|
||||||
|
return "ERROR: UNKNOWN GLFW ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW event API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwInputError(int error, const char* format, ...)
|
||||||
|
{
|
||||||
|
if (_glfwErrorCallback)
|
||||||
|
{
|
||||||
|
char buffer[8192];
|
||||||
|
const char* description;
|
||||||
|
|
||||||
|
if (format)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
|
va_start(vl, format);
|
||||||
|
count = vsnprintf(buffer, sizeof(buffer), format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0';
|
||||||
|
|
||||||
|
description = buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
description = getErrorString(error);
|
||||||
|
|
||||||
|
_glfwErrorCallback(error, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI int glfwInit(void)
|
||||||
|
{
|
||||||
|
if (_glfwInitialized)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
memset(&_glfw, 0, sizeof(_glfw));
|
||||||
|
|
||||||
|
if (!_glfwPlatformInit())
|
||||||
|
{
|
||||||
|
_glfwPlatformTerminate();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
|
||||||
|
_glfwInitialized = GLFW_TRUE;
|
||||||
|
|
||||||
|
_glfw.timerOffset = _glfwPlatformGetTimerValue();
|
||||||
|
|
||||||
|
// Not all window hints have zero as their default value
|
||||||
|
glfwDefaultWindowHints();
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwTerminate(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!_glfwInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks));
|
||||||
|
|
||||||
|
while (_glfw.windowListHead)
|
||||||
|
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
|
||||||
|
|
||||||
|
while (_glfw.cursorListHead)
|
||||||
|
glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead);
|
||||||
|
|
||||||
|
for (i = 0; i < _glfw.monitorCount; i++)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = _glfw.monitors[i];
|
||||||
|
if (monitor->originalRamp.size)
|
||||||
|
_glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwTerminateVulkan();
|
||||||
|
|
||||||
|
_glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount);
|
||||||
|
_glfw.monitors = NULL;
|
||||||
|
_glfw.monitorCount = 0;
|
||||||
|
|
||||||
|
_glfwPlatformTerminate();
|
||||||
|
|
||||||
|
memset(&_glfw, 0, sizeof(_glfw));
|
||||||
|
_glfwInitialized = GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev)
|
||||||
|
{
|
||||||
|
if (major != NULL)
|
||||||
|
*major = GLFW_VERSION_MAJOR;
|
||||||
|
|
||||||
|
if (minor != NULL)
|
||||||
|
*minor = GLFW_VERSION_MINOR;
|
||||||
|
|
||||||
|
if (rev != NULL)
|
||||||
|
*rev = GLFW_VERSION_REVISION;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _glfwPlatformGetVersionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
659
external/glfw/input.c
vendored
Normal file
659
external/glfw/input.c
vendored
Normal file
@ -0,0 +1,659 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Internal key state used for sticky keys
|
||||||
|
#define _GLFW_STICK 3
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW event API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
if (key >= 0 && key <= GLFW_KEY_LAST)
|
||||||
|
{
|
||||||
|
GLFWbool repeated = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
|
||||||
|
repeated = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (action == GLFW_RELEASE && window->stickyKeys)
|
||||||
|
window->keys[key] = _GLFW_STICK;
|
||||||
|
else
|
||||||
|
window->keys[key] = (char) action;
|
||||||
|
|
||||||
|
if (repeated)
|
||||||
|
action = GLFW_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->callbacks.key)
|
||||||
|
window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
|
||||||
|
{
|
||||||
|
if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window->callbacks.charmods)
|
||||||
|
window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
|
||||||
|
|
||||||
|
if (plain)
|
||||||
|
{
|
||||||
|
if (window->callbacks.character)
|
||||||
|
window->callbacks.character((GLFWwindow*) window, codepoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
|
||||||
|
{
|
||||||
|
if (window->callbacks.scroll)
|
||||||
|
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Register mouse button action
|
||||||
|
if (action == GLFW_RELEASE && window->stickyMouseButtons)
|
||||||
|
window->mouseButtons[button] = _GLFW_STICK;
|
||||||
|
else
|
||||||
|
window->mouseButtons[button] = (char) action;
|
||||||
|
|
||||||
|
if (window->callbacks.mouseButton)
|
||||||
|
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
|
||||||
|
{
|
||||||
|
if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
window->virtualCursorPosX = xpos;
|
||||||
|
window->virtualCursorPosY = ypos;
|
||||||
|
|
||||||
|
if (window->callbacks.cursorPos)
|
||||||
|
window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
|
||||||
|
{
|
||||||
|
if (window->callbacks.cursorEnter)
|
||||||
|
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
|
||||||
|
{
|
||||||
|
if (window->callbacks.drop)
|
||||||
|
window->callbacks.drop((GLFWwindow*) window, count, paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputJoystickChange(int joy, int event)
|
||||||
|
{
|
||||||
|
if (_glfw.callbacks.joystick)
|
||||||
|
_glfw.callbacks.joystick(joy, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWbool _glfwIsPrintable(int key)
|
||||||
|
{
|
||||||
|
return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) ||
|
||||||
|
(key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) ||
|
||||||
|
key == GLFW_KEY_KP_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case GLFW_CURSOR:
|
||||||
|
return window->cursorMode;
|
||||||
|
case GLFW_STICKY_KEYS:
|
||||||
|
return window->stickyKeys;
|
||||||
|
case GLFW_STICKY_MOUSE_BUTTONS:
|
||||||
|
return window->stickyMouseButtons;
|
||||||
|
default:
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case GLFW_CURSOR:
|
||||||
|
{
|
||||||
|
if (value != GLFW_CURSOR_NORMAL &&
|
||||||
|
value != GLFW_CURSOR_HIDDEN &&
|
||||||
|
value != GLFW_CURSOR_DISABLED)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Invalid cursor mode %i",
|
||||||
|
value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->cursorMode == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
window->cursorMode = value;
|
||||||
|
|
||||||
|
_glfwPlatformGetCursorPos(window,
|
||||||
|
&window->virtualCursorPosX,
|
||||||
|
&window->virtualCursorPosY);
|
||||||
|
|
||||||
|
if (_glfwPlatformWindowFocused(window))
|
||||||
|
_glfwPlatformSetCursorMode(window, value);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GLFW_STICKY_KEYS:
|
||||||
|
{
|
||||||
|
if (window->stickyKeys == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Release all sticky keys
|
||||||
|
for (i = 0; i <= GLFW_KEY_LAST; i++)
|
||||||
|
{
|
||||||
|
if (window->keys[i] == _GLFW_STICK)
|
||||||
|
window->keys[i] = GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case GLFW_STICKY_MOUSE_BUTTONS:
|
||||||
|
{
|
||||||
|
if (window->stickyMouseButtons == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Release all sticky mouse buttons
|
||||||
|
for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
|
||||||
|
{
|
||||||
|
if (window->mouseButtons[i] == _GLFW_STICK)
|
||||||
|
window->mouseButtons[i] = GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return _glfwPlatformGetKeyName(key, scancode);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
|
||||||
|
|
||||||
|
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
||||||
|
return GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->keys[key] == _GLFW_STICK)
|
||||||
|
{
|
||||||
|
// Sticky mode: release key now
|
||||||
|
window->keys[key] = GLFW_RELEASE;
|
||||||
|
return GLFW_PRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) window->keys[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
|
||||||
|
|
||||||
|
if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
|
||||||
|
return GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->mouseButtons[button] == _GLFW_STICK)
|
||||||
|
{
|
||||||
|
// Sticky mode: release mouse button now
|
||||||
|
window->mouseButtons[button] = GLFW_RELEASE;
|
||||||
|
return GLFW_PRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) window->mouseButtons[button];
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = 0;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = window->virtualCursorPosX;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = window->virtualCursorPosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_glfwPlatformGetCursorPos(window, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
|
||||||
|
ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid cursor position %f %f",
|
||||||
|
xpos, ypos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfwPlatformWindowFocused(window))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
|
{
|
||||||
|
// Only update the accumulated position if the cursor is disabled
|
||||||
|
window->virtualCursorPosX = xpos;
|
||||||
|
window->virtualCursorPosY = ypos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Update system cursor position
|
||||||
|
_glfwPlatformSetCursorPos(window, xpos, ypos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
|
||||||
|
{
|
||||||
|
_GLFWcursor* cursor;
|
||||||
|
|
||||||
|
assert(image != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
cursor = calloc(1, sizeof(_GLFWcursor));
|
||||||
|
cursor->next = _glfw.cursorListHead;
|
||||||
|
_glfw.cursorListHead = cursor;
|
||||||
|
|
||||||
|
if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot))
|
||||||
|
{
|
||||||
|
glfwDestroyCursor((GLFWcursor*) cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GLFWcursor*) cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
|
||||||
|
{
|
||||||
|
_GLFWcursor* cursor;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (shape != GLFW_ARROW_CURSOR &&
|
||||||
|
shape != GLFW_IBEAM_CURSOR &&
|
||||||
|
shape != GLFW_CROSSHAIR_CURSOR &&
|
||||||
|
shape != GLFW_HAND_CURSOR &&
|
||||||
|
shape != GLFW_HRESIZE_CURSOR &&
|
||||||
|
shape != GLFW_VRESIZE_CURSOR)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = calloc(1, sizeof(_GLFWcursor));
|
||||||
|
cursor->next = _glfw.cursorListHead;
|
||||||
|
_glfw.cursorListHead = cursor;
|
||||||
|
|
||||||
|
if (!_glfwPlatformCreateStandardCursor(cursor, shape))
|
||||||
|
{
|
||||||
|
glfwDestroyCursor((GLFWcursor*) cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GLFWcursor*) cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
|
||||||
|
{
|
||||||
|
_GLFWcursor* cursor = (_GLFWcursor*) handle;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (cursor == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure the cursor is not being used by any window
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
for (window = _glfw.windowListHead; window; window = window->next)
|
||||||
|
{
|
||||||
|
if (window->cursor == cursor)
|
||||||
|
glfwSetCursor((GLFWwindow*) window, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformDestroyCursor(cursor);
|
||||||
|
|
||||||
|
// Unlink cursor from global linked list
|
||||||
|
{
|
||||||
|
_GLFWcursor** prev = &_glfw.cursorListHead;
|
||||||
|
|
||||||
|
while (*prev != cursor)
|
||||||
|
prev = &((*prev)->next);
|
||||||
|
|
||||||
|
*prev = cursor->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) windowHandle;
|
||||||
|
_GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
window->cursor = cursor;
|
||||||
|
|
||||||
|
_glfwPlatformSetCursor(window, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
|
||||||
|
GLFWmousebuttonfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
|
||||||
|
GLFWcursorposfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
|
||||||
|
GLFWcursorenterfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
|
||||||
|
GLFWscrollfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwJoystickPresent(int joy)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
|
||||||
|
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformJoystickPresent(joy);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count)
|
||||||
|
{
|
||||||
|
assert(count != NULL);
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformGetJoystickAxes(joy, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count)
|
||||||
|
{
|
||||||
|
assert(count != NULL);
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformGetJoystickButtons(joy, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetJoystickName(int joy)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformGetJoystickName(joy);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
assert(string != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformSetClipboardString(window, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return _glfwPlatformGetClipboardString(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI double glfwGetTime(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0.0);
|
||||||
|
return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) /
|
||||||
|
_glfwPlatformGetTimerFrequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetTime(double time)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (time != time || time < 0.0 || time > 18446744073.0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.timerOffset = _glfwPlatformGetTimerValue() -
|
||||||
|
(uint64_t) (time * _glfwPlatformGetTimerFrequency());
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI uint64_t glfwGetTimerValue(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
return _glfwPlatformGetTimerValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI uint64_t glfwGetTimerFrequency(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
return _glfwPlatformGetTimerFrequency();
|
||||||
|
}
|
||||||
|
|
1055
external/glfw/internal.h
vendored
Normal file
1055
external/glfw/internal.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
341
external/glfw/linux_joystick.c
vendored
Normal file
341
external/glfw/linux_joystick.c
vendored
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Linux - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <linux/joystick.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
|
||||||
|
// Attempt to open the specified joystick device
|
||||||
|
//
|
||||||
|
#if defined(__linux__)
|
||||||
|
static GLFWbool openJoystickDevice(const char* path)
|
||||||
|
{
|
||||||
|
char axisCount, buttonCount;
|
||||||
|
char name[256] = "";
|
||||||
|
int joy, fd, version;
|
||||||
|
_GLFWjoystickLinux* js;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (!_glfw.linux_js.js[joy].present)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(_glfw.linux_js.js[joy].path, path) == 0)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (!_glfw.linux_js.js[joy].present)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joy > GLFW_JOYSTICK_LAST)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY | O_NONBLOCK);
|
||||||
|
if (fd == -1)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
// Verify that the joystick driver version is at least 1.0
|
||||||
|
ioctl(fd, JSIOCGVERSION, &version);
|
||||||
|
if (version < 0x010000)
|
||||||
|
{
|
||||||
|
// It's an old 0.x interface (we don't support it)
|
||||||
|
close(fd);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
|
||||||
|
strncpy(name, "Unknown", sizeof(name));
|
||||||
|
|
||||||
|
js = _glfw.linux_js.js + joy;
|
||||||
|
js->present = GLFW_TRUE;
|
||||||
|
js->name = strdup(name);
|
||||||
|
js->path = strdup(path);
|
||||||
|
js->fd = fd;
|
||||||
|
|
||||||
|
ioctl(fd, JSIOCGAXES, &axisCount);
|
||||||
|
js->axisCount = (int) axisCount;
|
||||||
|
js->axes = calloc(axisCount, sizeof(float));
|
||||||
|
|
||||||
|
ioctl(fd, JSIOCGBUTTONS, &buttonCount);
|
||||||
|
js->buttonCount = (int) buttonCount;
|
||||||
|
js->buttons = calloc(buttonCount, 1);
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
// Polls for and processes events the specified joystick
|
||||||
|
//
|
||||||
|
static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
_glfwPollJoystickEvents();
|
||||||
|
|
||||||
|
if (!js->present)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
// Read all queued events (non-blocking)
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct js_event e;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (read(js->fd, &e, sizeof(e)) < 0)
|
||||||
|
{
|
||||||
|
// Reset the joystick slot if the device was disconnected
|
||||||
|
if (errno == ENODEV)
|
||||||
|
{
|
||||||
|
free(js->axes);
|
||||||
|
free(js->buttons);
|
||||||
|
free(js->name);
|
||||||
|
free(js->path);
|
||||||
|
|
||||||
|
memset(js, 0, sizeof(_GLFWjoystickLinux));
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(js - _glfw.linux_js.js,
|
||||||
|
GLFW_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the initial-state bit
|
||||||
|
e.type &= ~JS_EVENT_INIT;
|
||||||
|
|
||||||
|
if (e.type == JS_EVENT_AXIS)
|
||||||
|
js->axes[e.number] = (float) e.value / 32767.0f;
|
||||||
|
else if (e.type == JS_EVENT_BUTTON)
|
||||||
|
js->buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
#endif // __linux__
|
||||||
|
return js->present;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexically compare joysticks by name; used by qsort
|
||||||
|
//
|
||||||
|
#if defined(__linux__)
|
||||||
|
static int compareJoysticks(const void* fp, const void* sp)
|
||||||
|
{
|
||||||
|
const _GLFWjoystickLinux* fj = fp;
|
||||||
|
const _GLFWjoystickLinux* sj = sp;
|
||||||
|
return strcmp(fj->path, sj->path);
|
||||||
|
}
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize joystick interface
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitJoysticksLinux(void)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
DIR* dir;
|
||||||
|
int count = 0;
|
||||||
|
const char* dirname = "/dev/input";
|
||||||
|
|
||||||
|
_glfw.linux_js.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||||
|
if (_glfw.linux_js.inotify == -1)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Linux: Failed to initialize inotify: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: Register for IN_ATTRIB as well to get notified when udev is done
|
||||||
|
// This works well in practice but the true way is libudev
|
||||||
|
|
||||||
|
_glfw.linux_js.watch = inotify_add_watch(_glfw.linux_js.inotify,
|
||||||
|
dirname,
|
||||||
|
IN_CREATE | IN_ATTRIB);
|
||||||
|
if (_glfw.linux_js.watch == -1)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Linux: Failed to watch for joystick connections in %s: %s",
|
||||||
|
dirname,
|
||||||
|
strerror(errno));
|
||||||
|
// Continue without device connection notifications
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regcomp(&_glfw.linux_js.regex, "^js[0-9]\\+$", 0) != 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = opendir(dirname);
|
||||||
|
if (dir)
|
||||||
|
{
|
||||||
|
struct dirent* entry;
|
||||||
|
|
||||||
|
while ((entry = readdir(dir)))
|
||||||
|
{
|
||||||
|
char path[20];
|
||||||
|
regmatch_t match;
|
||||||
|
|
||||||
|
if (regexec(&_glfw.linux_js.regex, entry->d_name, 1, &match, 0) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);
|
||||||
|
if (openJoystickDevice(path))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Linux: Failed to open joystick device directory %s: %s",
|
||||||
|
dirname,
|
||||||
|
strerror(errno));
|
||||||
|
// Continue with no joysticks detected
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(_glfw.linux_js.js, count, sizeof(_GLFWjoystickLinux), compareJoysticks);
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all opened joystick handles
|
||||||
|
//
|
||||||
|
void _glfwTerminateJoysticksLinux(void)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i <= GLFW_JOYSTICK_LAST; i++)
|
||||||
|
{
|
||||||
|
if (_glfw.linux_js.js[i].present)
|
||||||
|
{
|
||||||
|
close(_glfw.linux_js.js[i].fd);
|
||||||
|
free(_glfw.linux_js.js[i].axes);
|
||||||
|
free(_glfw.linux_js.js[i].buttons);
|
||||||
|
free(_glfw.linux_js.js[i].name);
|
||||||
|
free(_glfw.linux_js.js[i].path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regfree(&_glfw.linux_js.regex);
|
||||||
|
|
||||||
|
if (_glfw.linux_js.inotify > 0)
|
||||||
|
{
|
||||||
|
if (_glfw.linux_js.watch > 0)
|
||||||
|
inotify_rm_watch(_glfw.linux_js.inotify, _glfw.linux_js.watch);
|
||||||
|
|
||||||
|
close(_glfw.linux_js.inotify);
|
||||||
|
}
|
||||||
|
#endif // __linux__
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPollJoystickEvents(void)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
ssize_t offset = 0;
|
||||||
|
char buffer[16384];
|
||||||
|
|
||||||
|
const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
while (size > offset)
|
||||||
|
{
|
||||||
|
regmatch_t match;
|
||||||
|
const struct inotify_event* e = (struct inotify_event*) (buffer + offset);
|
||||||
|
|
||||||
|
if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0)
|
||||||
|
{
|
||||||
|
char path[20];
|
||||||
|
snprintf(path, sizeof(path), "/dev/input/%s", e->name);
|
||||||
|
openJoystickDevice(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += sizeof(struct inotify_event) + e->len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformJoystickPresent(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
|
||||||
|
return pollJoystickEvents(js);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
|
||||||
|
if (!pollJoystickEvents(js))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = js->axisCount;
|
||||||
|
return js->axes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
|
||||||
|
if (!pollJoystickEvents(js))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = js->buttonCount;
|
||||||
|
return js->buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetJoystickName(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux* js = _glfw.linux_js.js + joy;
|
||||||
|
if (!pollJoystickEvents(js))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return js->name;
|
||||||
|
}
|
||||||
|
|
68
external/glfw/linux_joystick.h
vendored
Normal file
68
external/glfw/linux_joystick.h
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Linux - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_linux_joystick_h_
|
||||||
|
#define _glfw3_linux_joystick_h_
|
||||||
|
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE _GLFWjoylistLinux linux_js
|
||||||
|
|
||||||
|
|
||||||
|
// Linux-specific joystick data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoystickLinux
|
||||||
|
{
|
||||||
|
GLFWbool present;
|
||||||
|
int fd;
|
||||||
|
float* axes;
|
||||||
|
int axisCount;
|
||||||
|
unsigned char* buttons;
|
||||||
|
int buttonCount;
|
||||||
|
char* name;
|
||||||
|
char* path;
|
||||||
|
} _GLFWjoystickLinux;
|
||||||
|
|
||||||
|
// Linux-specific joystick API data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoylistLinux
|
||||||
|
{
|
||||||
|
_GLFWjoystickLinux js[GLFW_JOYSTICK_LAST + 1];
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
int inotify;
|
||||||
|
int watch;
|
||||||
|
regex_t regex;
|
||||||
|
#endif /*__linux__*/
|
||||||
|
} _GLFWjoylistLinux;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitJoysticksLinux(void);
|
||||||
|
void _glfwTerminateJoysticksLinux(void);
|
||||||
|
|
||||||
|
void _glfwPollJoystickEvents(void);
|
||||||
|
|
||||||
|
#endif // _glfw3_linux_joystick_h_
|
238
external/glfw/mir_init.c
vendored
Normal file
238
external/glfw/mir_init.c
vendored
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Mir - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Create key code translation tables
|
||||||
|
//
|
||||||
|
static void createKeyTables(void)
|
||||||
|
{
|
||||||
|
memset(_glfw.mir.publicKeys, -1, sizeof(_glfw.mir.publicKeys));
|
||||||
|
|
||||||
|
_glfw.mir.publicKeys[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
_glfw.mir.publicKeys[KEY_1] = GLFW_KEY_1;
|
||||||
|
_glfw.mir.publicKeys[KEY_2] = GLFW_KEY_2;
|
||||||
|
_glfw.mir.publicKeys[KEY_3] = GLFW_KEY_3;
|
||||||
|
_glfw.mir.publicKeys[KEY_4] = GLFW_KEY_4;
|
||||||
|
_glfw.mir.publicKeys[KEY_5] = GLFW_KEY_5;
|
||||||
|
_glfw.mir.publicKeys[KEY_6] = GLFW_KEY_6;
|
||||||
|
_glfw.mir.publicKeys[KEY_7] = GLFW_KEY_7;
|
||||||
|
_glfw.mir.publicKeys[KEY_8] = GLFW_KEY_8;
|
||||||
|
_glfw.mir.publicKeys[KEY_9] = GLFW_KEY_9;
|
||||||
|
_glfw.mir.publicKeys[KEY_0] = GLFW_KEY_0;
|
||||||
|
_glfw.mir.publicKeys[KEY_MINUS] = GLFW_KEY_MINUS;
|
||||||
|
_glfw.mir.publicKeys[KEY_EQUAL] = GLFW_KEY_EQUAL;
|
||||||
|
_glfw.mir.publicKeys[KEY_Q] = GLFW_KEY_Q;
|
||||||
|
_glfw.mir.publicKeys[KEY_W] = GLFW_KEY_W;
|
||||||
|
_glfw.mir.publicKeys[KEY_E] = GLFW_KEY_E;
|
||||||
|
_glfw.mir.publicKeys[KEY_R] = GLFW_KEY_R;
|
||||||
|
_glfw.mir.publicKeys[KEY_T] = GLFW_KEY_T;
|
||||||
|
_glfw.mir.publicKeys[KEY_Y] = GLFW_KEY_Y;
|
||||||
|
_glfw.mir.publicKeys[KEY_U] = GLFW_KEY_U;
|
||||||
|
_glfw.mir.publicKeys[KEY_I] = GLFW_KEY_I;
|
||||||
|
_glfw.mir.publicKeys[KEY_O] = GLFW_KEY_O;
|
||||||
|
_glfw.mir.publicKeys[KEY_P] = GLFW_KEY_P;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
_glfw.mir.publicKeys[KEY_A] = GLFW_KEY_A;
|
||||||
|
_glfw.mir.publicKeys[KEY_S] = GLFW_KEY_S;
|
||||||
|
_glfw.mir.publicKeys[KEY_D] = GLFW_KEY_D;
|
||||||
|
_glfw.mir.publicKeys[KEY_F] = GLFW_KEY_F;
|
||||||
|
_glfw.mir.publicKeys[KEY_G] = GLFW_KEY_G;
|
||||||
|
_glfw.mir.publicKeys[KEY_H] = GLFW_KEY_H;
|
||||||
|
_glfw.mir.publicKeys[KEY_J] = GLFW_KEY_J;
|
||||||
|
_glfw.mir.publicKeys[KEY_K] = GLFW_KEY_K;
|
||||||
|
_glfw.mir.publicKeys[KEY_L] = GLFW_KEY_L;
|
||||||
|
_glfw.mir.publicKeys[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;
|
||||||
|
_glfw.mir.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
|
||||||
|
_glfw.mir.publicKeys[KEY_Z] = GLFW_KEY_Z;
|
||||||
|
_glfw.mir.publicKeys[KEY_X] = GLFW_KEY_X;
|
||||||
|
_glfw.mir.publicKeys[KEY_C] = GLFW_KEY_C;
|
||||||
|
_glfw.mir.publicKeys[KEY_V] = GLFW_KEY_V;
|
||||||
|
_glfw.mir.publicKeys[KEY_B] = GLFW_KEY_B;
|
||||||
|
_glfw.mir.publicKeys[KEY_N] = GLFW_KEY_N;
|
||||||
|
_glfw.mir.publicKeys[KEY_M] = GLFW_KEY_M;
|
||||||
|
_glfw.mir.publicKeys[KEY_COMMA] = GLFW_KEY_COMMA;
|
||||||
|
_glfw.mir.publicKeys[KEY_DOT] = GLFW_KEY_PERIOD;
|
||||||
|
_glfw.mir.publicKeys[KEY_SLASH] = GLFW_KEY_SLASH;
|
||||||
|
_glfw.mir.publicKeys[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;
|
||||||
|
_glfw.mir.publicKeys[KEY_ESC] = GLFW_KEY_ESCAPE;
|
||||||
|
_glfw.mir.publicKeys[KEY_TAB] = GLFW_KEY_TAB;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;
|
||||||
|
_glfw.mir.publicKeys[KEY_MENU] = GLFW_KEY_MENU;
|
||||||
|
_glfw.mir.publicKeys[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;
|
||||||
|
_glfw.mir.publicKeys[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;
|
||||||
|
_glfw.mir.publicKeys[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;
|
||||||
|
_glfw.mir.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
|
||||||
|
_glfw.mir.publicKeys[KEY_PAUSE] = GLFW_KEY_PAUSE;
|
||||||
|
_glfw.mir.publicKeys[KEY_DELETE] = GLFW_KEY_DELETE;
|
||||||
|
_glfw.mir.publicKeys[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;
|
||||||
|
_glfw.mir.publicKeys[KEY_ENTER] = GLFW_KEY_ENTER;
|
||||||
|
_glfw.mir.publicKeys[KEY_HOME] = GLFW_KEY_HOME;
|
||||||
|
_glfw.mir.publicKeys[KEY_END] = GLFW_KEY_END;
|
||||||
|
_glfw.mir.publicKeys[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;
|
||||||
|
_glfw.mir.publicKeys[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
_glfw.mir.publicKeys[KEY_INSERT] = GLFW_KEY_INSERT;
|
||||||
|
_glfw.mir.publicKeys[KEY_LEFT] = GLFW_KEY_LEFT;
|
||||||
|
_glfw.mir.publicKeys[KEY_RIGHT] = GLFW_KEY_RIGHT;
|
||||||
|
_glfw.mir.publicKeys[KEY_DOWN] = GLFW_KEY_DOWN;
|
||||||
|
_glfw.mir.publicKeys[KEY_UP] = GLFW_KEY_UP;
|
||||||
|
_glfw.mir.publicKeys[KEY_F1] = GLFW_KEY_F1;
|
||||||
|
_glfw.mir.publicKeys[KEY_F2] = GLFW_KEY_F2;
|
||||||
|
_glfw.mir.publicKeys[KEY_F3] = GLFW_KEY_F3;
|
||||||
|
_glfw.mir.publicKeys[KEY_F4] = GLFW_KEY_F4;
|
||||||
|
_glfw.mir.publicKeys[KEY_F5] = GLFW_KEY_F5;
|
||||||
|
_glfw.mir.publicKeys[KEY_F6] = GLFW_KEY_F6;
|
||||||
|
_glfw.mir.publicKeys[KEY_F7] = GLFW_KEY_F7;
|
||||||
|
_glfw.mir.publicKeys[KEY_F8] = GLFW_KEY_F8;
|
||||||
|
_glfw.mir.publicKeys[KEY_F9] = GLFW_KEY_F9;
|
||||||
|
_glfw.mir.publicKeys[KEY_F10] = GLFW_KEY_F10;
|
||||||
|
_glfw.mir.publicKeys[KEY_F11] = GLFW_KEY_F11;
|
||||||
|
_glfw.mir.publicKeys[KEY_F12] = GLFW_KEY_F12;
|
||||||
|
_glfw.mir.publicKeys[KEY_F13] = GLFW_KEY_F13;
|
||||||
|
_glfw.mir.publicKeys[KEY_F14] = GLFW_KEY_F14;
|
||||||
|
_glfw.mir.publicKeys[KEY_F15] = GLFW_KEY_F15;
|
||||||
|
_glfw.mir.publicKeys[KEY_F16] = GLFW_KEY_F16;
|
||||||
|
_glfw.mir.publicKeys[KEY_F17] = GLFW_KEY_F17;
|
||||||
|
_glfw.mir.publicKeys[KEY_F18] = GLFW_KEY_F18;
|
||||||
|
_glfw.mir.publicKeys[KEY_F19] = GLFW_KEY_F19;
|
||||||
|
_glfw.mir.publicKeys[KEY_F20] = GLFW_KEY_F20;
|
||||||
|
_glfw.mir.publicKeys[KEY_F21] = GLFW_KEY_F21;
|
||||||
|
_glfw.mir.publicKeys[KEY_F22] = GLFW_KEY_F22;
|
||||||
|
_glfw.mir.publicKeys[KEY_F23] = GLFW_KEY_F23;
|
||||||
|
_glfw.mir.publicKeys[KEY_F24] = GLFW_KEY_F24;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPPLUS] = GLFW_KEY_KP_ADD;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP0] = GLFW_KEY_KP_0;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP1] = GLFW_KEY_KP_1;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP2] = GLFW_KEY_KP_2;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP3] = GLFW_KEY_KP_3;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP4] = GLFW_KEY_KP_4;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP5] = GLFW_KEY_KP_5;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP6] = GLFW_KEY_KP_6;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP7] = GLFW_KEY_KP_7;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP8] = GLFW_KEY_KP_8;
|
||||||
|
_glfw.mir.publicKeys[KEY_KP9] = GLFW_KEY_KP_9;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;
|
||||||
|
_glfw.mir.publicKeys[KEY_KPENTER] = GLFW_KEY_KP_ENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformInit(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
_glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
if (!mir_connection_is_valid(_glfw.mir.connection))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unable to connect to server: %s",
|
||||||
|
mir_connection_get_error_message(_glfw.mir.connection));
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.mir.display =
|
||||||
|
mir_connection_get_egl_native_display(_glfw.mir.connection);
|
||||||
|
|
||||||
|
createKeyTables();
|
||||||
|
|
||||||
|
if (!_glfwInitThreadLocalStoragePOSIX())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (!_glfwInitJoysticksLinux())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfwInitTimerPOSIX();
|
||||||
|
|
||||||
|
// Need the default conf for when we set a NULL cursor
|
||||||
|
_glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name);
|
||||||
|
|
||||||
|
_glfw.mir.event_queue = calloc(1, sizeof(EventQueue));
|
||||||
|
_glfwInitEventQueueMir(_glfw.mir.event_queue);
|
||||||
|
|
||||||
|
error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Failed to create event mutex: %s",
|
||||||
|
strerror(error));
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminate(void)
|
||||||
|
{
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
_glfwTerminateJoysticksLinux();
|
||||||
|
_glfwTerminateThreadLocalStoragePOSIX();
|
||||||
|
|
||||||
|
_glfwDeleteEventQueueMir(_glfw.mir.event_queue);
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
mir_connection_release(_glfw.mir.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _GLFW_VERSION_NUMBER " Mir EGL"
|
||||||
|
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
|
||||||
|
" clock_gettime"
|
||||||
|
#else
|
||||||
|
" gettimeofday"
|
||||||
|
#endif
|
||||||
|
#if defined(__linux__)
|
||||||
|
" /dev/js"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
" shared"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
182
external/glfw/mir_monitor.c
vendored
Normal file
182
external/glfw/mir_monitor.c
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Mir - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
int i, found = 0;
|
||||||
|
_GLFWmonitor** monitors = NULL;
|
||||||
|
MirDisplayConfiguration* displayConfig =
|
||||||
|
mir_connection_create_display_config(_glfw.mir.connection);
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < displayConfig->num_outputs; i++)
|
||||||
|
{
|
||||||
|
const MirDisplayOutput* out = displayConfig->outputs + i;
|
||||||
|
|
||||||
|
if (out->used &&
|
||||||
|
out->connected &&
|
||||||
|
out->num_modes &&
|
||||||
|
out->current_mode < out->num_modes)
|
||||||
|
{
|
||||||
|
found++;
|
||||||
|
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
|
||||||
|
monitors[i] = _glfwAllocMonitor("Unknown",
|
||||||
|
out->physical_width_mm,
|
||||||
|
out->physical_height_mm);
|
||||||
|
|
||||||
|
monitors[i]->mir.x = out->position_x;
|
||||||
|
monitors[i]->mir.y = out->position_y;
|
||||||
|
monitors[i]->mir.output_id = out->output_id;
|
||||||
|
monitors[i]->mir.cur_mode = out->current_mode;
|
||||||
|
|
||||||
|
monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i],
|
||||||
|
&monitors[i]->modeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mir_display_config_destroy(displayConfig);
|
||||||
|
|
||||||
|
*count = found;
|
||||||
|
return monitors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||||
|
{
|
||||||
|
return first->mir.output_id == second->mir.output_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = monitor->mir.x;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = monitor->mir.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf)
|
||||||
|
{
|
||||||
|
switch (pf)
|
||||||
|
{
|
||||||
|
case mir_pixel_format_rgb_565:
|
||||||
|
mode->redBits = 5;
|
||||||
|
mode->greenBits = 6;
|
||||||
|
mode->blueBits = 5;
|
||||||
|
break;
|
||||||
|
case mir_pixel_format_rgba_5551:
|
||||||
|
mode->redBits = 5;
|
||||||
|
mode->greenBits = 5;
|
||||||
|
mode->blueBits = 5;
|
||||||
|
break;
|
||||||
|
case mir_pixel_format_rgba_4444:
|
||||||
|
mode->redBits = 4;
|
||||||
|
mode->greenBits = 4;
|
||||||
|
mode->blueBits = 4;
|
||||||
|
break;
|
||||||
|
case mir_pixel_format_abgr_8888:
|
||||||
|
case mir_pixel_format_xbgr_8888:
|
||||||
|
case mir_pixel_format_argb_8888:
|
||||||
|
case mir_pixel_format_xrgb_8888:
|
||||||
|
case mir_pixel_format_bgr_888:
|
||||||
|
case mir_pixel_format_rgb_888:
|
||||||
|
default:
|
||||||
|
mode->redBits = 8;
|
||||||
|
mode->greenBits = 8;
|
||||||
|
mode->blueBits = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GLFWvidmode* modes = NULL;
|
||||||
|
MirDisplayConfiguration* displayConfig =
|
||||||
|
mir_connection_create_display_config(_glfw.mir.connection);
|
||||||
|
|
||||||
|
for (i = 0; i < displayConfig->num_outputs; i++)
|
||||||
|
{
|
||||||
|
const MirDisplayOutput* out = displayConfig->outputs + i;
|
||||||
|
if (out->output_id != monitor->mir.output_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
modes = calloc(out->num_modes, sizeof(GLFWvidmode));
|
||||||
|
|
||||||
|
for (*found = 0; *found < out->num_modes; (*found)++)
|
||||||
|
{
|
||||||
|
modes[*found].width = out->modes[*found].horizontal_resolution;
|
||||||
|
modes[*found].height = out->modes[*found].vertical_resolution;
|
||||||
|
modes[*found].refreshRate = out->modes[*found].refresh_rate;
|
||||||
|
|
||||||
|
FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mir_display_config_destroy(displayConfig);
|
||||||
|
|
||||||
|
return modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||||
|
{
|
||||||
|
*mode = monitor->modes[monitor->mir.cur_mode];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
return monitor->mir.output_id;
|
||||||
|
}
|
||||||
|
|
130
external/glfw/mir_platform.h
vendored
Normal file
130
external/glfw/mir_platform.h
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Mir - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_mir_platform_h_
|
||||||
|
#define _glfw3_mir_platform_h_
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <mir_toolkit/mir_client_library.h>
|
||||||
|
|
||||||
|
typedef VkFlags VkMirSurfaceCreateFlagsKHR;
|
||||||
|
|
||||||
|
typedef struct VkMirSurfaceCreateInfoKHR
|
||||||
|
{
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkMirSurfaceCreateFlagsKHR flags;
|
||||||
|
MirConnection* connection;
|
||||||
|
MirSurface* mirSurface;
|
||||||
|
} VkMirSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (APIENTRY *PFN_vkCreateMirSurfaceKHR)(VkInstance,const VkMirSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||||
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*);
|
||||||
|
|
||||||
|
#include "posix_tls.h"
|
||||||
|
#include "posix_time.h"
|
||||||
|
#include "linux_joystick.h"
|
||||||
|
#include "xkb_unicode.h"
|
||||||
|
#include "egl_context.h"
|
||||||
|
|
||||||
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||||
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
|
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.window)
|
||||||
|
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display)
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||||
|
|
||||||
|
|
||||||
|
// Mir-specific Event Queue
|
||||||
|
//
|
||||||
|
typedef struct EventQueue
|
||||||
|
{
|
||||||
|
TAILQ_HEAD(, EventNode) head;
|
||||||
|
} EventQueue;
|
||||||
|
|
||||||
|
// Mir-specific per-window data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWwindowMir
|
||||||
|
{
|
||||||
|
MirSurface* surface;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
MirEGLNativeWindowType window;
|
||||||
|
|
||||||
|
} _GLFWwindowMir;
|
||||||
|
|
||||||
|
// Mir-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorMir
|
||||||
|
{
|
||||||
|
int cur_mode;
|
||||||
|
int output_id;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
} _GLFWmonitorMir;
|
||||||
|
|
||||||
|
// Mir-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryMir
|
||||||
|
{
|
||||||
|
MirConnection* connection;
|
||||||
|
MirEGLNativeDisplayType display;
|
||||||
|
MirCursorConfiguration* default_conf;
|
||||||
|
EventQueue* event_queue;
|
||||||
|
|
||||||
|
short int publicKeys[256];
|
||||||
|
|
||||||
|
pthread_mutex_t event_mutex;
|
||||||
|
pthread_cond_t event_cond;
|
||||||
|
|
||||||
|
} _GLFWlibraryMir;
|
||||||
|
|
||||||
|
// Mir-specific per-cursor data
|
||||||
|
// TODO: Only system cursors are implemented in Mir atm. Need to wait for support.
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcursorMir
|
||||||
|
{
|
||||||
|
MirCursorConfiguration* conf;
|
||||||
|
MirBufferStream* custom_cursor;
|
||||||
|
} _GLFWcursorMir;
|
||||||
|
|
||||||
|
|
||||||
|
extern void _glfwInitEventQueueMir(EventQueue* queue);
|
||||||
|
extern void _glfwDeleteEventQueueMir(EventQueue* queue);
|
||||||
|
|
||||||
|
#endif // _glfw3_mir_platform_h_
|
848
external/glfw/mir_window.c
vendored
Normal file
848
external/glfw/mir_window.c
vendored
Normal file
@ -0,0 +1,848 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Mir - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014-2015 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct EventNode
|
||||||
|
{
|
||||||
|
TAILQ_ENTRY(EventNode) entries;
|
||||||
|
const MirEvent* event;
|
||||||
|
_GLFWwindow* window;
|
||||||
|
} EventNode;
|
||||||
|
|
||||||
|
static void deleteNode(EventQueue* queue, EventNode* node)
|
||||||
|
{
|
||||||
|
mir_event_unref(node->event);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWbool emptyEventQueue(EventQueue* queue)
|
||||||
|
{
|
||||||
|
return queue->head.tqh_first == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO The mir_event_ref is not supposed to be used but ... its needed
|
||||||
|
// in this case. Need to wait until we can read from an FD set up by mir
|
||||||
|
// for single threaded event handling.
|
||||||
|
static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
|
||||||
|
{
|
||||||
|
EventNode* new_node = calloc(1, sizeof(EventNode));
|
||||||
|
new_node->event = mir_event_ref(event);
|
||||||
|
new_node->window = context;
|
||||||
|
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
EventNode* new_node = newEventNode(event, context);
|
||||||
|
TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries);
|
||||||
|
|
||||||
|
pthread_cond_signal(&_glfw.mir.event_cond);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_glfw.mir.event_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EventNode* dequeueEvent(EventQueue* queue)
|
||||||
|
{
|
||||||
|
EventNode* node = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
node = queue->head.tqh_first;
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
TAILQ_REMOVE(&queue->head, node, entries);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME Soon to be changed upstream mir! So we can use an egl config to figure out
|
||||||
|
the best pixel format!
|
||||||
|
*/
|
||||||
|
static MirPixelFormat findValidPixelFormat(void)
|
||||||
|
{
|
||||||
|
unsigned int i, validFormats, mirPixelFormats = 32;
|
||||||
|
MirPixelFormat formats[mir_pixel_formats];
|
||||||
|
|
||||||
|
mir_connection_get_available_surface_formats(_glfw.mir.connection, formats,
|
||||||
|
mirPixelFormats, &validFormats);
|
||||||
|
|
||||||
|
for (i = 0; i < validFormats; i++)
|
||||||
|
{
|
||||||
|
if (formats[i] == mir_pixel_format_abgr_8888 ||
|
||||||
|
formats[i] == mir_pixel_format_xbgr_8888 ||
|
||||||
|
formats[i] == mir_pixel_format_argb_8888 ||
|
||||||
|
formats[i] == mir_pixel_format_xrgb_8888)
|
||||||
|
{
|
||||||
|
return formats[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mir_pixel_format_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mirModToGLFWMod(uint32_t mods)
|
||||||
|
{
|
||||||
|
int publicMods = 0x0;
|
||||||
|
|
||||||
|
if (mods & mir_input_event_modifier_alt)
|
||||||
|
publicMods |= GLFW_MOD_ALT;
|
||||||
|
else if (mods & mir_input_event_modifier_shift)
|
||||||
|
publicMods |= GLFW_MOD_SHIFT;
|
||||||
|
else if (mods & mir_input_event_modifier_ctrl)
|
||||||
|
publicMods |= GLFW_MOD_CONTROL;
|
||||||
|
else if (mods & mir_input_event_modifier_meta)
|
||||||
|
publicMods |= GLFW_MOD_SUPER;
|
||||||
|
|
||||||
|
return publicMods;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int toGLFWKeyCode(uint32_t key)
|
||||||
|
{
|
||||||
|
if (key < sizeof(_glfw.mir.publicKeys) / sizeof(_glfw.mir.publicKeys[0]))
|
||||||
|
return _glfw.mir.publicKeys[key];
|
||||||
|
|
||||||
|
return GLFW_KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
|
||||||
|
{
|
||||||
|
const int action = mir_keyboard_event_action (key_event);
|
||||||
|
const int scan_code = mir_keyboard_event_scan_code(key_event);
|
||||||
|
const int key_code = mir_keyboard_event_key_code (key_event);
|
||||||
|
const int modifiers = mir_keyboard_event_modifiers(key_event);
|
||||||
|
|
||||||
|
const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
|
||||||
|
const int mods = mirModToGLFWMod(modifiers);
|
||||||
|
const long text = _glfwKeySym2Unicode(key_code);
|
||||||
|
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||||
|
|
||||||
|
_glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
|
||||||
|
|
||||||
|
if (text != -1)
|
||||||
|
_glfwInputChar(window, text, mods, plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handlePointerButton(_GLFWwindow* window,
|
||||||
|
int pressed,
|
||||||
|
const MirPointerEvent* pointer_event)
|
||||||
|
{
|
||||||
|
int mods = mir_pointer_event_modifiers(pointer_event);
|
||||||
|
const int publicMods = mirModToGLFWMod(mods);
|
||||||
|
MirPointerButton button = mir_pointer_button_primary;
|
||||||
|
static uint32_t oldButtonStates = 0;
|
||||||
|
uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event);
|
||||||
|
int publicButton = GLFW_MOUSE_BUTTON_LEFT;
|
||||||
|
|
||||||
|
// XOR our old button states our new states to figure out what was added or removed
|
||||||
|
button = newButtonStates ^ oldButtonStates;
|
||||||
|
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case mir_pointer_button_primary:
|
||||||
|
publicButton = GLFW_MOUSE_BUTTON_LEFT;
|
||||||
|
break;
|
||||||
|
case mir_pointer_button_secondary:
|
||||||
|
publicButton = GLFW_MOUSE_BUTTON_RIGHT;
|
||||||
|
break;
|
||||||
|
case mir_pointer_button_tertiary:
|
||||||
|
publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
|
||||||
|
break;
|
||||||
|
case mir_pointer_button_forward:
|
||||||
|
// FIXME What is the forward button?
|
||||||
|
publicButton = GLFW_MOUSE_BUTTON_4;
|
||||||
|
break;
|
||||||
|
case mir_pointer_button_back:
|
||||||
|
// FIXME What is the back button?
|
||||||
|
publicButton = GLFW_MOUSE_BUTTON_5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldButtonStates = newButtonStates;
|
||||||
|
|
||||||
|
_glfwInputMouseClick(window, publicButton, pressed, publicMods);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handlePointerMotion(_GLFWwindow* window,
|
||||||
|
const MirPointerEvent* pointer_event)
|
||||||
|
{
|
||||||
|
int current_x = window->virtualCursorPosX;
|
||||||
|
int current_y = window->virtualCursorPosY;
|
||||||
|
int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
|
||||||
|
int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
|
||||||
|
int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
|
||||||
|
int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
|
||||||
|
|
||||||
|
_glfwInputCursorPos(window, x, y);
|
||||||
|
if (dx != 0 || dy != 0)
|
||||||
|
_glfwInputScroll(window, dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handlePointerEvent(const MirPointerEvent* pointer_event,
|
||||||
|
_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
int action = mir_pointer_event_action(pointer_event);
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case mir_pointer_action_button_down:
|
||||||
|
handlePointerButton(window, GLFW_PRESS, pointer_event);
|
||||||
|
break;
|
||||||
|
case mir_pointer_action_button_up:
|
||||||
|
handlePointerButton(window, GLFW_RELEASE, pointer_event);
|
||||||
|
break;
|
||||||
|
case mir_pointer_action_motion:
|
||||||
|
handlePointerMotion(window, pointer_event);
|
||||||
|
break;
|
||||||
|
case mir_pointer_action_enter:
|
||||||
|
case mir_pointer_action_leave:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
|
||||||
|
{
|
||||||
|
int type = mir_input_event_get_type(input_event);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case mir_input_event_type_key:
|
||||||
|
handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
|
||||||
|
break;
|
||||||
|
case mir_input_event_type_pointer:
|
||||||
|
handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleEvent(const MirEvent* event, _GLFWwindow* window)
|
||||||
|
{
|
||||||
|
int type = mir_event_get_type(event);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case mir_event_type_input:
|
||||||
|
handleInput(mir_event_get_input_event(event), window);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addNewEvent(MirSurface* surface, const MirEvent* event, void* context)
|
||||||
|
{
|
||||||
|
enqueueEvent(event, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWbool createSurface(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
MirSurfaceSpec* spec;
|
||||||
|
MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
|
||||||
|
MirPixelFormat pixel_format = findValidPixelFormat();
|
||||||
|
|
||||||
|
if (pixel_format == mir_pixel_format_invalid)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unable to find a correct pixel format");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
spec = mir_connection_create_spec_for_normal_surface(_glfw.mir.connection,
|
||||||
|
window->mir.width,
|
||||||
|
window->mir.height,
|
||||||
|
pixel_format);
|
||||||
|
|
||||||
|
mir_surface_spec_set_buffer_usage(spec, buffer_usage);
|
||||||
|
mir_surface_spec_set_name(spec, "MirSurface");
|
||||||
|
|
||||||
|
window->mir.surface = mir_surface_create_sync(spec);
|
||||||
|
mir_surface_spec_release(spec);
|
||||||
|
|
||||||
|
if (!mir_surface_is_valid(window->mir.surface))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unable to create surface: %s",
|
||||||
|
mir_surface_get_error_message(window->mir.surface));
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mir_surface_set_event_handler(window->mir.surface, addNewEvent, window);
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwInitEventQueueMir(EventQueue* queue)
|
||||||
|
{
|
||||||
|
TAILQ_INIT(&queue->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwDeleteEventQueueMir(EventQueue* queue)
|
||||||
|
{
|
||||||
|
if (queue)
|
||||||
|
{
|
||||||
|
EventNode* node, *node_next;
|
||||||
|
node = queue->head.tqh_first;
|
||||||
|
|
||||||
|
while (node != NULL)
|
||||||
|
{
|
||||||
|
node_next = node->entries.tqe_next;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&queue->head, node, entries);
|
||||||
|
deleteNode(queue, node);
|
||||||
|
|
||||||
|
node = node_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||||
|
const _GLFWwndconfig* wndconfig,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
|
{
|
||||||
|
if (window->monitor)
|
||||||
|
{
|
||||||
|
GLFWvidmode mode;
|
||||||
|
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||||
|
|
||||||
|
mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen);
|
||||||
|
|
||||||
|
if (wndconfig->width > mode.width || wndconfig->height > mode.height)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Requested surface size too large: %ix%i",
|
||||||
|
wndconfig->width, wndconfig->height);
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->mir.width = wndconfig->width;
|
||||||
|
window->mir.height = wndconfig->height;
|
||||||
|
|
||||||
|
if (!createSurface(window))
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
window->mir.window = mir_buffer_stream_get_egl_native_window(
|
||||||
|
mir_surface_get_buffer_stream(window->mir.surface));
|
||||||
|
|
||||||
|
if (ctxconfig->client != GLFW_NO_API)
|
||||||
|
{
|
||||||
|
if (!_glfwInitEGL())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (mir_surface_is_valid(window->mir.surface))
|
||||||
|
{
|
||||||
|
mir_surface_release_sync(window->mir.surface);
|
||||||
|
window->mir.surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->context.destroy)
|
||||||
|
window->context.destroy(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||||
|
{
|
||||||
|
MirSurfaceSpec* spec;
|
||||||
|
const char* e_title = title ? title : "";
|
||||||
|
|
||||||
|
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
|
||||||
|
mir_surface_spec_set_name(spec, e_title);
|
||||||
|
|
||||||
|
mir_surface_apply_spec(window->mir.surface, spec);
|
||||||
|
mir_surface_spec_release(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||||
|
int count, const GLFWimage* images)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
MirSurfaceSpec* spec;
|
||||||
|
|
||||||
|
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
|
||||||
|
mir_surface_spec_set_width (spec, width);
|
||||||
|
mir_surface_spec_set_height(spec, height);
|
||||||
|
|
||||||
|
mir_surface_apply_spec(window->mir.surface, spec);
|
||||||
|
mir_surface_spec_release(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||||
|
int minwidth, int minheight,
|
||||||
|
int maxwidth, int maxheight)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||||
|
int* left, int* top,
|
||||||
|
int* right, int* bottom)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||||
|
{
|
||||||
|
if (width)
|
||||||
|
*width = window->mir.width;
|
||||||
|
if (height)
|
||||||
|
*height = window->mir.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
mir_surface_set_state(window->mir.surface, mir_surface_state_minimized);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
mir_surface_set_state(window->mir.surface, mir_surface_state_restored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
MirSurfaceSpec* spec;
|
||||||
|
|
||||||
|
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
|
||||||
|
mir_surface_spec_set_state(spec, mir_surface_state_hidden);
|
||||||
|
|
||||||
|
mir_surface_apply_spec(window->mir.surface, spec);
|
||||||
|
mir_surface_spec_release(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
MirSurfaceSpec* spec;
|
||||||
|
|
||||||
|
spec = mir_connection_create_spec_for_changes(_glfw.mir.connection);
|
||||||
|
mir_surface_spec_set_state(spec, mir_surface_state_restored);
|
||||||
|
|
||||||
|
mir_surface_apply_spec(window->mir.surface, spec);
|
||||||
|
mir_surface_spec_release(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||||
|
_GLFWmonitor* monitor,
|
||||||
|
int xpos, int ypos,
|
||||||
|
int width, int height,
|
||||||
|
int refreshRate)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformPollEvents(void)
|
||||||
|
{
|
||||||
|
EventNode* node = NULL;
|
||||||
|
|
||||||
|
while ((node = dequeueEvent(_glfw.mir.event_queue)))
|
||||||
|
{
|
||||||
|
handleEvent(node->event, node->window);
|
||||||
|
deleteNode(_glfw.mir.event_queue, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformWaitEvents(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
if (emptyEventQueue(_glfw.mir.event_queue))
|
||||||
|
pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
_glfwPlatformPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
if (emptyEventQueue(_glfw.mir.event_queue))
|
||||||
|
{
|
||||||
|
struct timespec time;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &time);
|
||||||
|
time.tv_sec += (long) timeout;
|
||||||
|
time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
|
||||||
|
pthread_cond_timedwait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex, &time);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_glfw.mir.event_mutex);
|
||||||
|
|
||||||
|
_glfwPlatformPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformPostEmptyEvent(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
|
||||||
|
{
|
||||||
|
if (width)
|
||||||
|
*width = window->mir.width;
|
||||||
|
if (height)
|
||||||
|
*height = window->mir.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME implement
|
||||||
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||||
|
const GLFWimage* image,
|
||||||
|
int xhot, int yhot)
|
||||||
|
{
|
||||||
|
MirBufferStream* stream;
|
||||||
|
MirPixelFormat pixel_format = findValidPixelFormat();
|
||||||
|
|
||||||
|
int i_w = image->width;
|
||||||
|
int i_h = image->height;
|
||||||
|
|
||||||
|
if (pixel_format == mir_pixel_format_invalid)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unable to find a correct pixel format");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
|
||||||
|
i_w, i_h,
|
||||||
|
pixel_format,
|
||||||
|
mir_buffer_usage_software);
|
||||||
|
|
||||||
|
cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
|
||||||
|
|
||||||
|
char* dest;
|
||||||
|
unsigned char *pixels;
|
||||||
|
int i, r_stride, bytes_per_pixel, bytes_per_row;
|
||||||
|
|
||||||
|
MirGraphicsRegion region;
|
||||||
|
mir_buffer_stream_get_graphics_region(stream, ®ion);
|
||||||
|
|
||||||
|
// FIXME Figure this out based on the current_pf
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
bytes_per_row = bytes_per_pixel * i_w;
|
||||||
|
|
||||||
|
dest = region.vaddr;
|
||||||
|
pixels = image->pixels;
|
||||||
|
|
||||||
|
r_stride = region.stride;
|
||||||
|
|
||||||
|
for (i = 0; i < i_h; i++)
|
||||||
|
{
|
||||||
|
memcpy(dest, pixels, bytes_per_row);
|
||||||
|
dest += r_stride;
|
||||||
|
pixels += r_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->mir.custom_cursor = stream;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getSystemCursorName(int shape)
|
||||||
|
{
|
||||||
|
switch (shape)
|
||||||
|
{
|
||||||
|
case GLFW_ARROW_CURSOR:
|
||||||
|
return mir_arrow_cursor_name;
|
||||||
|
case GLFW_IBEAM_CURSOR:
|
||||||
|
return mir_caret_cursor_name;
|
||||||
|
case GLFW_CROSSHAIR_CURSOR:
|
||||||
|
return mir_crosshair_cursor_name;
|
||||||
|
case GLFW_HAND_CURSOR:
|
||||||
|
return mir_open_hand_cursor_name;
|
||||||
|
case GLFW_HRESIZE_CURSOR:
|
||||||
|
return mir_horizontal_resize_cursor_name;
|
||||||
|
case GLFW_VRESIZE_CURSOR:
|
||||||
|
return mir_vertical_resize_cursor_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||||
|
{
|
||||||
|
const char* cursor_name = getSystemCursorName(shape);
|
||||||
|
|
||||||
|
if (cursor_name)
|
||||||
|
{
|
||||||
|
cursor->mir.conf = mir_cursor_configuration_from_name(cursor_name);
|
||||||
|
cursor->mir.custom_cursor = NULL;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
if (cursor->mir.conf)
|
||||||
|
mir_cursor_configuration_destroy(cursor->mir.conf);
|
||||||
|
if (cursor->mir.custom_cursor)
|
||||||
|
mir_buffer_stream_release_sync(cursor->mir.custom_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
if (cursor && cursor->mir.conf)
|
||||||
|
{
|
||||||
|
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf));
|
||||||
|
if (cursor->mir.custom_cursor)
|
||||||
|
{
|
||||||
|
mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, _glfw.mir.default_conf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetKeyName(int key, int scancode)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
|
||||||
|
{
|
||||||
|
char** extensions;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
if (!_glfw.vk.KHR_mir_surface)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
extensions = calloc(2, sizeof(char*));
|
||||||
|
extensions[0] = strdup("VK_KHR_surface");
|
||||||
|
extensions[1] = strdup("VK_KHR_mir_surface");
|
||||||
|
|
||||||
|
*count = 2;
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||||
|
VkPhysicalDevice device,
|
||||||
|
uint32_t queuefamily)
|
||||||
|
{
|
||||||
|
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR =
|
||||||
|
(PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
|
||||||
|
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
|
||||||
|
if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
|
||||||
|
queuefamily,
|
||||||
|
_glfw.mir.connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||||
|
_GLFWwindow* window,
|
||||||
|
const VkAllocationCallbacks* allocator,
|
||||||
|
VkSurfaceKHR* surface)
|
||||||
|
{
|
||||||
|
VkResult err;
|
||||||
|
VkMirSurfaceCreateInfoKHR sci;
|
||||||
|
PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
|
||||||
|
|
||||||
|
vkCreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR)
|
||||||
|
vkGetInstanceProcAddr(instance, "vkCreateMirSurfaceKHR");
|
||||||
|
if (!vkCreateMirSurfaceKHR)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&sci, 0, sizeof(sci));
|
||||||
|
sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
|
||||||
|
sci.connection = _glfw.mir.connection;
|
||||||
|
sci.mirSurface = window->mir.surface;
|
||||||
|
|
||||||
|
err = vkCreateMirSurfaceKHR(instance, &sci, allocator, surface);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Mir: Failed to create Vulkan surface: %s",
|
||||||
|
_glfwGetVulkanResultString(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI MirConnection* glfwGetMirDisplay(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return _glfw.mir.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return window->mir.surface;
|
||||||
|
}
|
||||||
|
|
477
external/glfw/monitor.c
vendored
Normal file
477
external/glfw/monitor.c
vendored
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Lexically compare video modes, used by qsort
|
||||||
|
//
|
||||||
|
static int compareVideoModes(const void* fp, const void* sp)
|
||||||
|
{
|
||||||
|
const GLFWvidmode* fm = fp;
|
||||||
|
const GLFWvidmode* sm = sp;
|
||||||
|
const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
|
||||||
|
const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
|
||||||
|
const int farea = fm->width * fm->height;
|
||||||
|
const int sarea = sm->width * sm->height;
|
||||||
|
|
||||||
|
// First sort on color bits per pixel
|
||||||
|
if (fbpp != sbpp)
|
||||||
|
return fbpp - sbpp;
|
||||||
|
|
||||||
|
// Then sort on screen area
|
||||||
|
if (farea != sarea)
|
||||||
|
return farea - sarea;
|
||||||
|
|
||||||
|
// Lastly sort on refresh rate
|
||||||
|
return fm->refreshRate - sm->refreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves the available modes for the specified monitor
|
||||||
|
//
|
||||||
|
static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
int modeCount;
|
||||||
|
GLFWvidmode* modes;
|
||||||
|
|
||||||
|
if (monitor->modes)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
modes = _glfwPlatformGetVideoModes(monitor, &modeCount);
|
||||||
|
if (!modes)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
||||||
|
|
||||||
|
free(monitor->modes);
|
||||||
|
monitor->modes = modes;
|
||||||
|
monitor->modeCount = modeCount;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW event API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwInputMonitorChange(void)
|
||||||
|
{
|
||||||
|
int i, j, monitorCount = _glfw.monitorCount;
|
||||||
|
_GLFWmonitor** monitors = _glfw.monitors;
|
||||||
|
|
||||||
|
_glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
|
||||||
|
|
||||||
|
// Re-use still connected monitor objects
|
||||||
|
|
||||||
|
for (i = 0; i < _glfw.monitorCount; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < monitorCount; j++)
|
||||||
|
{
|
||||||
|
if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j]))
|
||||||
|
{
|
||||||
|
_glfwFreeMonitor(_glfw.monitors[i]);
|
||||||
|
_glfw.monitors[i] = monitors[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find and report disconnected monitors (not in the new list)
|
||||||
|
|
||||||
|
for (i = 0; i < monitorCount; i++)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window;
|
||||||
|
|
||||||
|
for (j = 0; j < _glfw.monitorCount; j++)
|
||||||
|
{
|
||||||
|
if (monitors[i] == _glfw.monitors[j])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j < _glfw.monitorCount)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (window = _glfw.windowListHead; window; window = window->next)
|
||||||
|
{
|
||||||
|
if (window->monitor == monitors[i])
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||||
|
_glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.callbacks.monitor)
|
||||||
|
_glfw.callbacks.monitor((GLFWmonitor*) monitors[i], GLFW_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find and report newly connected monitors (not in the old list)
|
||||||
|
// Re-used monitor objects are then removed from the old list to avoid
|
||||||
|
// having them destroyed at the end of this function
|
||||||
|
|
||||||
|
for (i = 0; i < _glfw.monitorCount; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < monitorCount; j++)
|
||||||
|
{
|
||||||
|
if (_glfw.monitors[i] == monitors[j])
|
||||||
|
{
|
||||||
|
monitors[j] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j < monitorCount)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_glfw.callbacks.monitor)
|
||||||
|
_glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwFreeMonitors(monitors, monitorCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputMonitorWindowChange(_GLFWmonitor* monitor, _GLFWwindow* window)
|
||||||
|
{
|
||||||
|
monitor->window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor));
|
||||||
|
monitor->name = strdup(name);
|
||||||
|
monitor->widthMM = widthMM;
|
||||||
|
monitor->heightMM = heightMM;
|
||||||
|
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwFreeMonitor(_GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
if (monitor == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwFreeGammaArrays(&monitor->originalRamp);
|
||||||
|
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||||
|
|
||||||
|
free(monitor->modes);
|
||||||
|
free(monitor->name);
|
||||||
|
free(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
|
||||||
|
{
|
||||||
|
ramp->red = calloc(size, sizeof(unsigned short));
|
||||||
|
ramp->green = calloc(size, sizeof(unsigned short));
|
||||||
|
ramp->blue = calloc(size, sizeof(unsigned short));
|
||||||
|
ramp->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
free(ramp->red);
|
||||||
|
free(ramp->green);
|
||||||
|
free(ramp->blue);
|
||||||
|
|
||||||
|
memset(ramp, 0, sizeof(GLFWgammaramp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwFreeMonitors(_GLFWmonitor** monitors, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
_glfwFreeMonitor(monitors[i]);
|
||||||
|
|
||||||
|
free(monitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
|
||||||
|
const GLFWvidmode* desired)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
|
||||||
|
unsigned int rateDiff, leastRateDiff = UINT_MAX;
|
||||||
|
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
||||||
|
const GLFWvidmode* current;
|
||||||
|
const GLFWvidmode* closest = NULL;
|
||||||
|
|
||||||
|
if (!refreshVideoModes(monitor))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < monitor->modeCount; i++)
|
||||||
|
{
|
||||||
|
current = monitor->modes + i;
|
||||||
|
|
||||||
|
colorDiff = 0;
|
||||||
|
|
||||||
|
if (desired->redBits != GLFW_DONT_CARE)
|
||||||
|
colorDiff += abs(current->redBits - desired->redBits);
|
||||||
|
if (desired->greenBits != GLFW_DONT_CARE)
|
||||||
|
colorDiff += abs(current->greenBits - desired->greenBits);
|
||||||
|
if (desired->blueBits != GLFW_DONT_CARE)
|
||||||
|
colorDiff += abs(current->blueBits - desired->blueBits);
|
||||||
|
|
||||||
|
sizeDiff = abs((current->width - desired->width) *
|
||||||
|
(current->width - desired->width) +
|
||||||
|
(current->height - desired->height) *
|
||||||
|
(current->height - desired->height));
|
||||||
|
|
||||||
|
if (desired->refreshRate != GLFW_DONT_CARE)
|
||||||
|
rateDiff = abs(current->refreshRate - desired->refreshRate);
|
||||||
|
else
|
||||||
|
rateDiff = UINT_MAX - current->refreshRate;
|
||||||
|
|
||||||
|
if ((colorDiff < leastColorDiff) ||
|
||||||
|
(colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
|
||||||
|
(colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
|
||||||
|
{
|
||||||
|
closest = current;
|
||||||
|
leastSizeDiff = sizeDiff;
|
||||||
|
leastRateDiff = rateDiff;
|
||||||
|
leastColorDiff = colorDiff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
|
||||||
|
{
|
||||||
|
return compareVideoModes(fm, sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
|
||||||
|
{
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
// We assume that by 32 the user really meant 24
|
||||||
|
if (bpp == 32)
|
||||||
|
bpp = 24;
|
||||||
|
|
||||||
|
// Convert "bits per pixel" to red, green & blue sizes
|
||||||
|
|
||||||
|
*red = *green = *blue = bpp / 3;
|
||||||
|
delta = bpp - (*red * 3);
|
||||||
|
if (delta >= 1)
|
||||||
|
*green = *green + 1;
|
||||||
|
|
||||||
|
if (delta == 2)
|
||||||
|
*red = *red + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
assert(count != NULL);
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
*count = _glfw.monitorCount;
|
||||||
|
return (GLFWmonitor**) _glfw.monitors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (!_glfw.monitorCount)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (GLFWmonitor*) _glfw.monitors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = 0;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
_glfwPlatformGetMonitorPos(monitor, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
|
||||||
|
if (widthMM)
|
||||||
|
*widthMM = 0;
|
||||||
|
if (heightMM)
|
||||||
|
*heightMM = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (widthMM)
|
||||||
|
*widthMM = monitor->widthMM;
|
||||||
|
if (heightMM)
|
||||||
|
*heightMM = monitor->heightMM;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return monitor->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
assert(count != NULL);
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (!refreshVideoModes(monitor))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = monitor->modeCount;
|
||||||
|
return monitor->modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
_glfwPlatformGetVideoMode(monitor, &monitor->currentMode);
|
||||||
|
return &monitor->currentMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned short values[256];
|
||||||
|
GLFWgammaramp ramp;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
|
||||||
|
// Calculate intensity
|
||||||
|
value = i / 255.0;
|
||||||
|
// Apply gamma curve
|
||||||
|
value = pow(value, 1.0 / gamma) * 65535.0 + 0.5;
|
||||||
|
|
||||||
|
// Clamp to value range
|
||||||
|
if (value > 65535.0)
|
||||||
|
value = 65535.0;
|
||||||
|
|
||||||
|
values[i] = (unsigned short) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ramp.red = values;
|
||||||
|
ramp.green = values;
|
||||||
|
ramp.blue = values;
|
||||||
|
ramp.size = 256;
|
||||||
|
|
||||||
|
glfwSetGammaRamp(handle, &ramp);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||||
|
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
|
||||||
|
|
||||||
|
return &monitor->currentRamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
assert(monitor != NULL);
|
||||||
|
assert(ramp != NULL);
|
||||||
|
assert(ramp->red != NULL);
|
||||||
|
assert(ramp->green != NULL);
|
||||||
|
assert(ramp->blue != NULL);
|
||||||
|
|
||||||
|
if (ramp->size <= 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid gamma ramp size %i",
|
||||||
|
ramp->size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (!monitor->originalRamp.size)
|
||||||
|
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
|
||||||
|
|
||||||
|
_glfwPlatformSetGammaRamp(monitor, ramp);
|
||||||
|
}
|
||||||
|
|
60
external/glfw/nsgl_context.h
vendored
Normal file
60
external/glfw/nsgl_context.h
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_nsgl_context_h_
|
||||||
|
#define _glfw3_nsgl_context_h_
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl
|
||||||
|
|
||||||
|
|
||||||
|
// NSGL-specific per-context data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcontextNSGL
|
||||||
|
{
|
||||||
|
id pixelFormat;
|
||||||
|
id object;
|
||||||
|
|
||||||
|
} _GLFWcontextNSGL;
|
||||||
|
|
||||||
|
// NSGL-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryNSGL
|
||||||
|
{
|
||||||
|
// dlopen handle for OpenGL.framework (for glfwGetProcAddress)
|
||||||
|
CFBundleRef framework;
|
||||||
|
|
||||||
|
} _GLFWlibraryNSGL;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitNSGL(void);
|
||||||
|
void _glfwTerminateNSGL(void);
|
||||||
|
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig);
|
||||||
|
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||||
|
|
||||||
|
#endif // _glfw3_nsgl_context_h_
|
308
external/glfw/nsgl_context.m
vendored
Normal file
308
external/glfw/nsgl_context.m
vendored
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 OS X - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2009-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
[window->context.nsgl.object makeCurrentContext];
|
||||||
|
else
|
||||||
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
|
||||||
|
_glfwPlatformSetCurrentContext(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapBuffersNSGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
// ARP appears to be unnecessary, but this is future-proof
|
||||||
|
[window->context.nsgl.object flushBuffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapIntervalNSGL(int interval)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
GLint sync = interval;
|
||||||
|
[window->context.nsgl.object setValues:&sync
|
||||||
|
forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extensionSupportedNSGL(const char* extension)
|
||||||
|
{
|
||||||
|
// There are no NSGL extensions
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWglproc getProcAddressNSGL(const char* procname)
|
||||||
|
{
|
||||||
|
CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
|
||||||
|
procname,
|
||||||
|
kCFStringEncodingASCII);
|
||||||
|
|
||||||
|
GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
|
||||||
|
symbolName);
|
||||||
|
|
||||||
|
CFRelease(symbolName);
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the OpenGL context
|
||||||
|
//
|
||||||
|
static void destroyContextNSGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
[window->context.nsgl.pixelFormat release];
|
||||||
|
window->context.nsgl.pixelFormat = nil;
|
||||||
|
|
||||||
|
[window->context.nsgl.object release];
|
||||||
|
window->context.nsgl.object = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize OpenGL support
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitNSGL(void)
|
||||||
|
{
|
||||||
|
if (_glfw.nsgl.framework)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
_glfw.nsgl.framework =
|
||||||
|
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||||
|
if (_glfw.nsgl.framework == NULL)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"NSGL: Failed to locate OpenGL framework");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate OpenGL support
|
||||||
|
//
|
||||||
|
void _glfwTerminateNSGL(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the OpenGL context
|
||||||
|
//
|
||||||
|
GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
|
{
|
||||||
|
unsigned int attributeCount = 0;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"NSGL: OpenGL ES is not available on OS X");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->major == 3 && ctxconfig->minor < 2)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"NSGL: The targeted version of OS X does not support OpenGL 3.0 or 3.1");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->major > 2)
|
||||||
|
{
|
||||||
|
if (!ctxconfig->forward)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"NSGL: The targeted version of OS X only supports forward-compatible contexts for OpenGL 3.2 and above");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"NSGL: The targeted version of OS X only supports core profile contexts for OpenGL 3.2 and above");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context robustness modes (GL_KHR_robustness) are not yet supported on
|
||||||
|
// OS X but are not a hard constraint, so ignore and continue
|
||||||
|
|
||||||
|
// Context release behaviors (GL_KHR_context_flush_control) are not yet
|
||||||
|
// supported on OS X but are not a hard constraint, so ignore and continue
|
||||||
|
|
||||||
|
#define ADD_ATTR(x) { attributes[attributeCount++] = x; }
|
||||||
|
#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
|
||||||
|
|
||||||
|
// Arbitrary array size here
|
||||||
|
NSOpenGLPixelFormatAttribute attributes[40];
|
||||||
|
|
||||||
|
ADD_ATTR(NSOpenGLPFAAccelerated);
|
||||||
|
ADD_ATTR(NSOpenGLPFAClosestPolicy);
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
|
||||||
|
if (ctxconfig->major >= 4)
|
||||||
|
{
|
||||||
|
ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||||
|
if (ctxconfig->major >= 3)
|
||||||
|
{
|
||||||
|
ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->major <= 2)
|
||||||
|
{
|
||||||
|
if (fbconfig->auxBuffers != GLFW_DONT_CARE)
|
||||||
|
ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
|
||||||
|
|
||||||
|
if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
|
||||||
|
fbconfig->accumGreenBits != GLFW_DONT_CARE &&
|
||||||
|
fbconfig->accumBlueBits != GLFW_DONT_CARE &&
|
||||||
|
fbconfig->accumAlphaBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
const int accumBits = fbconfig->accumRedBits +
|
||||||
|
fbconfig->accumGreenBits +
|
||||||
|
fbconfig->accumBlueBits +
|
||||||
|
fbconfig->accumAlphaBits;
|
||||||
|
|
||||||
|
ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fbconfig->redBits != GLFW_DONT_CARE &&
|
||||||
|
fbconfig->greenBits != GLFW_DONT_CARE &&
|
||||||
|
fbconfig->blueBits != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
int colorBits = fbconfig->redBits +
|
||||||
|
fbconfig->greenBits +
|
||||||
|
fbconfig->blueBits;
|
||||||
|
|
||||||
|
// OS X needs non-zero color size, so set reasonable values
|
||||||
|
if (colorBits == 0)
|
||||||
|
colorBits = 24;
|
||||||
|
else if (colorBits < 15)
|
||||||
|
colorBits = 15;
|
||||||
|
|
||||||
|
ADD_ATTR2(NSOpenGLPFAColorSize, colorBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fbconfig->alphaBits != GLFW_DONT_CARE)
|
||||||
|
ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
|
||||||
|
|
||||||
|
if (fbconfig->depthBits != GLFW_DONT_CARE)
|
||||||
|
ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits);
|
||||||
|
|
||||||
|
if (fbconfig->stencilBits != GLFW_DONT_CARE)
|
||||||
|
ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
|
||||||
|
|
||||||
|
if (fbconfig->stereo)
|
||||||
|
ADD_ATTR(NSOpenGLPFAStereo);
|
||||||
|
|
||||||
|
if (fbconfig->doublebuffer)
|
||||||
|
ADD_ATTR(NSOpenGLPFADoubleBuffer);
|
||||||
|
|
||||||
|
if (fbconfig->samples != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
if (fbconfig->samples == 0)
|
||||||
|
{
|
||||||
|
ADD_ATTR2(NSOpenGLPFASampleBuffers, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ADD_ATTR2(NSOpenGLPFASampleBuffers, 1);
|
||||||
|
ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
|
||||||
|
// framebuffer, so there's no need (and no way) to request it
|
||||||
|
|
||||||
|
ADD_ATTR(0);
|
||||||
|
|
||||||
|
#undef ADD_ATTR
|
||||||
|
#undef ADD_ATTR2
|
||||||
|
|
||||||
|
window->context.nsgl.pixelFormat =
|
||||||
|
[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||||
|
if (window->context.nsgl.pixelFormat == nil)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"NSGL: Failed to find a suitable pixel format");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSOpenGLContext* share = NULL;
|
||||||
|
|
||||||
|
if (ctxconfig->share)
|
||||||
|
share = ctxconfig->share->context.nsgl.object;
|
||||||
|
|
||||||
|
window->context.nsgl.object =
|
||||||
|
[[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
|
||||||
|
shareContext:share];
|
||||||
|
if (window->context.nsgl.object == nil)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"NSGL: Failed to create OpenGL context");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[window->context.nsgl.object setView:window->ns.view];
|
||||||
|
|
||||||
|
window->context.makeCurrent = makeContextCurrentNSGL;
|
||||||
|
window->context.swapBuffers = swapBuffersNSGL;
|
||||||
|
window->context.swapInterval = swapIntervalNSGL;
|
||||||
|
window->context.extensionSupported = extensionSupportedNSGL;
|
||||||
|
window->context.getProcAddress = getProcAddressNSGL;
|
||||||
|
window->context.destroy = destroyContextNSGL;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.nsgl.object;
|
||||||
|
}
|
||||||
|
|
85
external/glfw/posix_time.c
vendored
Normal file
85
external/glfw/posix_time.c
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialise timer
|
||||||
|
//
|
||||||
|
void _glfwInitTimerPOSIX(void)
|
||||||
|
{
|
||||||
|
#if defined(CLOCK_MONOTONIC)
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
||||||
|
{
|
||||||
|
_glfw.posix_time.monotonic = GLFW_TRUE;
|
||||||
|
_glfw.posix_time.frequency = 1000000000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
_glfw.posix_time.monotonic = GLFW_FALSE;
|
||||||
|
_glfw.posix_time.frequency = 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerValue(void)
|
||||||
|
{
|
||||||
|
#if defined(CLOCK_MONOTONIC)
|
||||||
|
if (_glfw.posix_time.monotonic)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||||
|
{
|
||||||
|
return _glfw.posix_time.frequency;
|
||||||
|
}
|
||||||
|
|
48
external/glfw/posix_time.h
vendored
Normal file
48
external/glfw/posix_time.h
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_posix_time_h_
|
||||||
|
#define _glfw3_posix_time_h_
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
// POSIX-specific global timer data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWtimePOSIX
|
||||||
|
{
|
||||||
|
GLFWbool monotonic;
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
|
} _GLFWtimePOSIX;
|
||||||
|
|
||||||
|
|
||||||
|
void _glfwInitTimerPOSIX(void);
|
||||||
|
|
||||||
|
#endif // _glfw3_posix_time_h_
|
68
external/glfw/posix_tls.c
vendored
Normal file
68
external/glfw/posix_tls.c
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWbool _glfwInitThreadLocalStoragePOSIX(void)
|
||||||
|
{
|
||||||
|
if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"POSIX: Failed to create context TLS");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.posix_tls.allocated = GLFW_TRUE;
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwTerminateThreadLocalStoragePOSIX(void)
|
||||||
|
{
|
||||||
|
if (_glfw.posix_tls.allocated)
|
||||||
|
pthread_key_delete(_glfw.posix_tls.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwPlatformSetCurrentContext(_GLFWwindow* context)
|
||||||
|
{
|
||||||
|
pthread_setspecific(_glfw.posix_tls.context, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
_GLFWwindow* _glfwPlatformGetCurrentContext(void)
|
||||||
|
{
|
||||||
|
return pthread_getspecific(_glfw.posix_tls.context);
|
||||||
|
}
|
||||||
|
|
49
external/glfw/posix_tls.h
vendored
Normal file
49
external/glfw/posix_tls.h
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 POSIX - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_posix_tls_h_
|
||||||
|
#define _glfw3_posix_tls_h_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsPOSIX posix_tls
|
||||||
|
|
||||||
|
|
||||||
|
// POSIX-specific global TLS data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWtlsPOSIX
|
||||||
|
{
|
||||||
|
GLFWbool allocated;
|
||||||
|
pthread_key_t context;
|
||||||
|
|
||||||
|
} _GLFWtlsPOSIX;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitThreadLocalStoragePOSIX(void);
|
||||||
|
void _glfwTerminateThreadLocalStoragePOSIX(void);
|
||||||
|
|
||||||
|
#endif // _glfw3_posix_tls_h_
|
302
external/glfw/vulkan.c
vendored
Normal file
302
external/glfw/vulkan.c
vendored
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWbool _glfwInitVulkan(void)
|
||||||
|
{
|
||||||
|
VkResult err;
|
||||||
|
VkExtensionProperties* ep;
|
||||||
|
uint32_t i, count;
|
||||||
|
|
||||||
|
#if !defined(_GLFW_VULKAN_STATIC)
|
||||||
|
#if defined(_GLFW_WIN32)
|
||||||
|
const char* name = "vulkan-1.dll";
|
||||||
|
#else
|
||||||
|
const char* name = "libvulkan.so.1";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_glfw.vk.available)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
_glfw.vk.handle = _glfw_dlopen(name);
|
||||||
|
if (!_glfw.vk.handle)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
|
||||||
|
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
||||||
|
if (!_glfw.vk.GetInstanceProcAddr)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Vulkan: Loader does not export vkGetInstanceProcAddr");
|
||||||
|
|
||||||
|
_glfwTerminateVulkan();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
|
||||||
|
vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
|
||||||
|
if (!_glfw.vk.EnumerateInstanceExtensionProperties)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
|
||||||
|
|
||||||
|
_glfwTerminateVulkan();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
#endif // _GLFW_VULKAN_STATIC
|
||||||
|
|
||||||
|
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Vulkan: Failed to query instance extension count: %s",
|
||||||
|
_glfwGetVulkanResultString(err));
|
||||||
|
|
||||||
|
_glfwTerminateVulkan();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep = calloc(count, sizeof(VkExtensionProperties));
|
||||||
|
|
||||||
|
err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Vulkan: Failed to query instance extensions: %s",
|
||||||
|
_glfwGetVulkanResultString(err));
|
||||||
|
|
||||||
|
free(ep);
|
||||||
|
_glfwTerminateVulkan();
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
|
||||||
|
_glfw.vk.KHR_surface = GLFW_TRUE;
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
|
||||||
|
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
|
||||||
|
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
|
||||||
|
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
|
||||||
|
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
|
||||||
|
if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
|
||||||
|
_glfw.vk.KHR_mir_surface = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ep);
|
||||||
|
|
||||||
|
_glfw.vk.available = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (_glfw.vk.KHR_surface)
|
||||||
|
{
|
||||||
|
_glfw.vk.extensions =
|
||||||
|
_glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwTerminateVulkan(void)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < _glfw.vk.extensionCount; i++)
|
||||||
|
free(_glfw.vk.extensions[i]);
|
||||||
|
free(_glfw.vk.extensions);
|
||||||
|
|
||||||
|
if (_glfw.vk.handle)
|
||||||
|
_glfw_dlclose(_glfw.vk.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwGetVulkanResultString(VkResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS:
|
||||||
|
return "Success";
|
||||||
|
case VK_NOT_READY:
|
||||||
|
return "A fence or query has not yet completed";
|
||||||
|
case VK_TIMEOUT:
|
||||||
|
return "A wait operation has not completed in the specified time";
|
||||||
|
case VK_EVENT_SET:
|
||||||
|
return "An event is signaled";
|
||||||
|
case VK_EVENT_RESET:
|
||||||
|
return "An event is unsignaled";
|
||||||
|
case VK_INCOMPLETE:
|
||||||
|
return "A return array was too small for the result";
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||||
|
return "A host memory allocation has failed";
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||||
|
return "A device memory allocation has failed";
|
||||||
|
case VK_ERROR_INITIALIZATION_FAILED:
|
||||||
|
return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||||
|
case VK_ERROR_DEVICE_LOST:
|
||||||
|
return "The logical or physical device has been lost";
|
||||||
|
case VK_ERROR_MEMORY_MAP_FAILED:
|
||||||
|
return "Mapping of a memory object has failed";
|
||||||
|
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||||
|
return "A requested layer is not present or could not be loaded";
|
||||||
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||||
|
return "A requested extension is not supported";
|
||||||
|
case VK_ERROR_FEATURE_NOT_PRESENT:
|
||||||
|
return "A requested feature is not supported";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||||
|
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||||
|
case VK_ERROR_TOO_MANY_OBJECTS:
|
||||||
|
return "Too many objects of the type have already been created";
|
||||||
|
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
||||||
|
return "A requested format is not supported on this device";
|
||||||
|
case VK_ERROR_SURFACE_LOST_KHR:
|
||||||
|
return "A surface is no longer available";
|
||||||
|
case VK_SUBOPTIMAL_KHR:
|
||||||
|
return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||||
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||||
|
return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
||||||
|
return "The display used by a swapchain does not use the same presentable image layout";
|
||||||
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||||
|
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||||
|
case VK_ERROR_VALIDATION_FAILED_EXT:
|
||||||
|
return "A validation layer found an error";
|
||||||
|
default:
|
||||||
|
return "ERROR: UNKNOWN VULKAN ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI int glfwVulkanSupported(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||||
|
return _glfwInitVulkan();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
|
||||||
|
{
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (!_glfwInitVulkan())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = _glfw.vk.extensionCount;
|
||||||
|
return (const char**) _glfw.vk.extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
|
||||||
|
const char* procname)
|
||||||
|
{
|
||||||
|
GLFWvkproc proc;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (!_glfwInitVulkan())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
|
||||||
|
if (!proc)
|
||||||
|
proc = (GLFWvkproc) _glfw_dlsym(_glfw.vk.handle, procname);
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||||
|
VkPhysicalDevice device,
|
||||||
|
uint32_t queuefamily)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||||
|
|
||||||
|
if (!_glfwInitVulkan())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfw.vk.extensions)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Vulkan: Window surface creation extensions not found");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformGetPhysicalDevicePresentationSupport(instance,
|
||||||
|
device,
|
||||||
|
queuefamily);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
|
||||||
|
GLFWwindow* handle,
|
||||||
|
const VkAllocationCallbacks* allocator,
|
||||||
|
VkSurfaceKHR* surface)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
assert(surface != NULL);
|
||||||
|
|
||||||
|
*surface = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
|
||||||
|
|
||||||
|
if (!_glfwInitVulkan())
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
|
||||||
|
return VK_ERROR_INITIALIZATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfw.vk.extensions)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"Vulkan: Window surface creation extensions not found");
|
||||||
|
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _glfwPlatformCreateWindowSurface(instance, window, allocator, surface);
|
||||||
|
}
|
||||||
|
|
718
external/glfw/wgl_context.c
vendored
Normal file
718
external/glfw/wgl_context.c
vendored
Normal file
@ -0,0 +1,718 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 WGL - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the specified attribute of the specified pixel format
|
||||||
|
//
|
||||||
|
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
|
||||||
|
assert(_glfw.wgl.ARB_pixel_format);
|
||||||
|
|
||||||
|
if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
|
||||||
|
pixelFormat,
|
||||||
|
0, 1, &attrib, &value))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to retrieve pixel format attribute %i",
|
||||||
|
attrib);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a list of available and usable framebuffer configs
|
||||||
|
//
|
||||||
|
static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired)
|
||||||
|
{
|
||||||
|
_GLFWfbconfig* usableConfigs;
|
||||||
|
const _GLFWfbconfig* closest;
|
||||||
|
int i, pixelFormat, nativeCount, usableCount;
|
||||||
|
|
||||||
|
if (_glfw.wgl.ARB_pixel_format)
|
||||||
|
{
|
||||||
|
nativeCount = getPixelFormatAttrib(window,
|
||||||
|
1,
|
||||||
|
WGL_NUMBER_PIXEL_FORMATS_ARB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nativeCount = DescribePixelFormat(window->context.wgl.dc,
|
||||||
|
1,
|
||||||
|
sizeof(PIXELFORMATDESCRIPTOR),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||||
|
usableCount = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nativeCount; i++)
|
||||||
|
{
|
||||||
|
const int n = i + 1;
|
||||||
|
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||||
|
|
||||||
|
if (_glfw.wgl.ARB_pixel_format)
|
||||||
|
{
|
||||||
|
// Get pixel format attributes through "modern" extension
|
||||||
|
|
||||||
|
if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
|
||||||
|
!getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) !=
|
||||||
|
WGL_TYPE_RGBA_ARB)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) ==
|
||||||
|
WGL_NO_ACCELERATION_ARB)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB);
|
||||||
|
u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB);
|
||||||
|
u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB);
|
||||||
|
u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB);
|
||||||
|
|
||||||
|
u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB);
|
||||||
|
u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB);
|
||||||
|
|
||||||
|
u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB);
|
||||||
|
u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB);
|
||||||
|
u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB);
|
||||||
|
u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB);
|
||||||
|
|
||||||
|
u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
|
||||||
|
|
||||||
|
if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB))
|
||||||
|
u->stereo = GLFW_TRUE;
|
||||||
|
if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
|
||||||
|
u->doublebuffer = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (_glfw.wgl.ARB_multisample)
|
||||||
|
u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
|
||||||
|
|
||||||
|
if (_glfw.wgl.ARB_framebuffer_sRGB ||
|
||||||
|
_glfw.wgl.EXT_framebuffer_sRGB)
|
||||||
|
{
|
||||||
|
if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
|
||||||
|
u->sRGB = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
|
||||||
|
// Get pixel format attributes through legacy PFDs
|
||||||
|
|
||||||
|
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||||
|
n,
|
||||||
|
sizeof(PIXELFORMATDESCRIPTOR),
|
||||||
|
&pfd))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
|
||||||
|
!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
|
||||||
|
(pfd.dwFlags & PFD_GENERIC_FORMAT))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfd.iPixelType != PFD_TYPE_RGBA)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
u->redBits = pfd.cRedBits;
|
||||||
|
u->greenBits = pfd.cGreenBits;
|
||||||
|
u->blueBits = pfd.cBlueBits;
|
||||||
|
u->alphaBits = pfd.cAlphaBits;
|
||||||
|
|
||||||
|
u->depthBits = pfd.cDepthBits;
|
||||||
|
u->stencilBits = pfd.cStencilBits;
|
||||||
|
|
||||||
|
u->accumRedBits = pfd.cAccumRedBits;
|
||||||
|
u->accumGreenBits = pfd.cAccumGreenBits;
|
||||||
|
u->accumBlueBits = pfd.cAccumBlueBits;
|
||||||
|
u->accumAlphaBits = pfd.cAccumAlphaBits;
|
||||||
|
|
||||||
|
u->auxBuffers = pfd.cAuxBuffers;
|
||||||
|
|
||||||
|
if (pfd.dwFlags & PFD_STEREO)
|
||||||
|
u->stereo = GLFW_TRUE;
|
||||||
|
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
|
||||||
|
u->doublebuffer = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->handle = n;
|
||||||
|
usableCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usableCount)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"WGL: The driver does not appear to support OpenGL");
|
||||||
|
|
||||||
|
free(usableConfigs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||||
|
if (!closest)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"WGL: Failed to find a suitable pixel format");
|
||||||
|
|
||||||
|
free(usableConfigs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelFormat = (int) closest->handle;
|
||||||
|
free(usableConfigs);
|
||||||
|
|
||||||
|
return pixelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns whether desktop compositing is enabled
|
||||||
|
//
|
||||||
|
static GLFWbool isCompositionEnabled(void)
|
||||||
|
{
|
||||||
|
BOOL enabled;
|
||||||
|
|
||||||
|
if (!_glfw_DwmIsCompositionEnabled)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void makeContextCurrentWGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
|
||||||
|
_glfwPlatformSetCurrentContext(window);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to make context current");
|
||||||
|
_glfwPlatformSetCurrentContext(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!wglMakeCurrent(NULL, NULL))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to clear current context");
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformSetCurrentContext(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapBuffersWGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
// HACK: Use DwmFlush when desktop composition is enabled
|
||||||
|
if (isCompositionEnabled() && !window->monitor)
|
||||||
|
{
|
||||||
|
int count = abs(window->context.wgl.interval);
|
||||||
|
while (count--)
|
||||||
|
_glfw_DwmFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapBuffers(window->context.wgl.dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapIntervalWGL(int interval)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||||
|
|
||||||
|
window->context.wgl.interval = interval;
|
||||||
|
|
||||||
|
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||||
|
// avoid interfering with DWM vsync
|
||||||
|
if (isCompositionEnabled() && !window->monitor)
|
||||||
|
interval = 0;
|
||||||
|
|
||||||
|
if (_glfw.wgl.EXT_swap_control)
|
||||||
|
_glfw.wgl.SwapIntervalEXT(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int extensionSupportedWGL(const char* extension)
|
||||||
|
{
|
||||||
|
const char* extensions;
|
||||||
|
|
||||||
|
if (_glfw.wgl.GetExtensionsStringEXT)
|
||||||
|
{
|
||||||
|
extensions = _glfw.wgl.GetExtensionsStringEXT();
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
if (_glfwStringInExtensionString(extension, extensions))
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.wgl.GetExtensionsStringARB)
|
||||||
|
{
|
||||||
|
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
|
||||||
|
if (extensions)
|
||||||
|
{
|
||||||
|
if (_glfwStringInExtensionString(extension, extensions))
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWglproc getProcAddressWGL(const char* procname)
|
||||||
|
{
|
||||||
|
const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
|
||||||
|
if (proc)
|
||||||
|
return proc;
|
||||||
|
|
||||||
|
return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the OpenGL context
|
||||||
|
//
|
||||||
|
static void destroyContextWGL(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window->context.wgl.handle)
|
||||||
|
{
|
||||||
|
wglDeleteContext(window->context.wgl.handle);
|
||||||
|
window->context.wgl.handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize WGL-specific extensions
|
||||||
|
//
|
||||||
|
static void loadWGLExtensions(void)
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
HGLRC rc;
|
||||||
|
HDC dc = GetDC(_glfw.win32.helperWindowHandle);;
|
||||||
|
|
||||||
|
_glfw.wgl.extensionsLoaded = GLFW_TRUE;
|
||||||
|
|
||||||
|
// NOTE: A dummy context has to be created for opengl32.dll to load the
|
||||||
|
// OpenGL ICD, from which we can then query WGL extensions
|
||||||
|
// NOTE: This code will accept the Microsoft GDI ICD; accelerated context
|
||||||
|
// creation failure occurs during manual pixel format enumeration
|
||||||
|
|
||||||
|
ZeroMemory(&pfd, sizeof(pfd));
|
||||||
|
pfd.nSize = sizeof(pfd);
|
||||||
|
pfd.nVersion = 1;
|
||||||
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pfd.cColorBits = 24;
|
||||||
|
|
||||||
|
if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to set pixel format for dummy context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = wglCreateContext(dc);
|
||||||
|
if (!rc)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to create dummy context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wglMakeCurrent(dc, rc))
|
||||||
|
{
|
||||||
|
wglDeleteContext(rc);
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to make dummy context current");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Functions must be loaded first as they're needed to retrieve the
|
||||||
|
// extension string that tells us whether the functions are supported
|
||||||
|
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
|
||||||
|
wglGetProcAddress("wglGetExtensionsStringEXT");
|
||||||
|
_glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
|
||||||
|
wglGetProcAddress("wglGetExtensionsStringARB");
|
||||||
|
_glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
||||||
|
wglGetProcAddress("wglCreateContextAttribsARB");
|
||||||
|
_glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
|
||||||
|
wglGetProcAddress("wglSwapIntervalEXT");
|
||||||
|
_glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
|
||||||
|
wglGetProcAddress("wglGetPixelFormatAttribivARB");
|
||||||
|
|
||||||
|
// NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
|
||||||
|
// checked below as we are already using them
|
||||||
|
_glfw.wgl.ARB_multisample =
|
||||||
|
extensionSupportedWGL("WGL_ARB_multisample");
|
||||||
|
_glfw.wgl.ARB_framebuffer_sRGB =
|
||||||
|
extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
|
||||||
|
_glfw.wgl.EXT_framebuffer_sRGB =
|
||||||
|
extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
|
||||||
|
_glfw.wgl.ARB_create_context =
|
||||||
|
extensionSupportedWGL("WGL_ARB_create_context");
|
||||||
|
_glfw.wgl.ARB_create_context_profile =
|
||||||
|
extensionSupportedWGL("WGL_ARB_create_context_profile");
|
||||||
|
_glfw.wgl.EXT_create_context_es2_profile =
|
||||||
|
extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
|
||||||
|
_glfw.wgl.ARB_create_context_robustness =
|
||||||
|
extensionSupportedWGL("WGL_ARB_create_context_robustness");
|
||||||
|
_glfw.wgl.EXT_swap_control =
|
||||||
|
extensionSupportedWGL("WGL_EXT_swap_control");
|
||||||
|
_glfw.wgl.ARB_pixel_format =
|
||||||
|
extensionSupportedWGL("WGL_ARB_pixel_format");
|
||||||
|
_glfw.wgl.ARB_context_flush_control =
|
||||||
|
extensionSupportedWGL("WGL_ARB_context_flush_control");
|
||||||
|
|
||||||
|
wglMakeCurrent(dc, NULL);
|
||||||
|
wglDeleteContext(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize WGL
|
||||||
|
//
|
||||||
|
GLFWbool _glfwInitWGL(void)
|
||||||
|
{
|
||||||
|
if (_glfw.wgl.instance)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
_glfw.wgl.instance = LoadLibraryA("opengl32.dll");
|
||||||
|
if (!_glfw.wgl.instance)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to load opengl32.dll");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.wgl.CreateContext = (WGLCREATECONTEXT_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
|
||||||
|
_glfw.wgl.DeleteContext = (WGLDELETECONTEXT_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
|
||||||
|
_glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
|
||||||
|
_glfw.wgl.GetCurrentDC = (WGLGETCURRENTDC_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
|
||||||
|
_glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
|
||||||
|
_glfw.wgl.ShareLists = (WGLSHARELISTS_T)
|
||||||
|
GetProcAddress(_glfw.wgl.instance, "wglShareLists");
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate WGL
|
||||||
|
//
|
||||||
|
void _glfwTerminateWGL(void)
|
||||||
|
{
|
||||||
|
if (_glfw.wgl.instance)
|
||||||
|
FreeLibrary(_glfw.wgl.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define setWGLattrib(attribName, attribValue) \
|
||||||
|
{ \
|
||||||
|
attribs[index++] = attribName; \
|
||||||
|
attribs[index++] = attribValue; \
|
||||||
|
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the OpenGL or OpenGL ES context
|
||||||
|
//
|
||||||
|
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig)
|
||||||
|
{
|
||||||
|
int attribs[40];
|
||||||
|
int pixelFormat;
|
||||||
|
PIXELFORMATDESCRIPTOR pfd;
|
||||||
|
HGLRC share = NULL;
|
||||||
|
|
||||||
|
if (!_glfw.wgl.extensionsLoaded)
|
||||||
|
loadWGLExtensions();
|
||||||
|
|
||||||
|
if (ctxconfig->share)
|
||||||
|
share = ctxconfig->share->context.wgl.handle;
|
||||||
|
|
||||||
|
window->context.wgl.dc = GetDC(window->win32.handle);
|
||||||
|
if (!window->context.wgl.dc)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to retrieve DC for window");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixelFormat = choosePixelFormat(window, fbconfig);
|
||||||
|
if (!pixelFormat)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||||
|
pixelFormat, sizeof(pfd), &pfd))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to retrieve PFD for selected pixel format");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to set selected pixel format");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->forward)
|
||||||
|
{
|
||||||
|
if (!_glfw.wgl.ARB_create_context)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->profile)
|
||||||
|
{
|
||||||
|
if (!_glfw.wgl.ARB_create_context_profile)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_glfw.wgl.ARB_create_context ||
|
||||||
|
!_glfw.wgl.ARB_create_context_profile ||
|
||||||
|
!_glfw.wgl.EXT_create_context_es2_profile)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.wgl.ARB_create_context)
|
||||||
|
{
|
||||||
|
int index = 0, mask = 0, flags = 0;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->forward)
|
||||||
|
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||||
|
|
||||||
|
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||||
|
mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||||
|
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||||
|
mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
|
||||||
|
|
||||||
|
if (ctxconfig->debug)
|
||||||
|
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||||
|
if (ctxconfig->noerror)
|
||||||
|
flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
|
||||||
|
|
||||||
|
if (ctxconfig->robustness)
|
||||||
|
{
|
||||||
|
if (_glfw.wgl.ARB_create_context_robustness)
|
||||||
|
{
|
||||||
|
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||||
|
{
|
||||||
|
setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
WGL_NO_RESET_NOTIFICATION_ARB);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||||
|
{
|
||||||
|
setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||||
|
WGL_LOSE_CONTEXT_ON_RESET_ARB);
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->release)
|
||||||
|
{
|
||||||
|
if (_glfw.wgl.ARB_context_flush_control)
|
||||||
|
{
|
||||||
|
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||||
|
{
|
||||||
|
setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||||
|
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
||||||
|
}
|
||||||
|
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||||
|
{
|
||||||
|
setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||||
|
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Only request an explicitly versioned context when necessary, as
|
||||||
|
// explicitly requesting version 1.0 does not always return the
|
||||||
|
// highest version supported by the driver
|
||||||
|
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||||
|
{
|
||||||
|
setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||||
|
setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags);
|
||||||
|
|
||||||
|
if (mask)
|
||||||
|
setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||||
|
|
||||||
|
setWGLattrib(0, 0);
|
||||||
|
|
||||||
|
window->context.wgl.handle =
|
||||||
|
_glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
|
||||||
|
share, attribs);
|
||||||
|
if (!window->context.wgl.handle)
|
||||||
|
{
|
||||||
|
const DWORD error = GetLastError();
|
||||||
|
|
||||||
|
if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
|
||||||
|
{
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Driver does not support OpenGL version %i.%i",
|
||||||
|
ctxconfig->major,
|
||||||
|
ctxconfig->minor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Driver does not support OpenGL ES version %i.%i",
|
||||||
|
ctxconfig->major,
|
||||||
|
ctxconfig->minor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Driver does not support the requested OpenGL profile");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Failed to create OpenGL context");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Failed to create OpenGL ES context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
|
||||||
|
if (!window->context.wgl.handle)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||||
|
"WGL: Failed to create OpenGL context");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (share)
|
||||||
|
{
|
||||||
|
if (!wglShareLists(share, window->context.wgl.handle))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"WGL: Failed to enable sharing with specified OpenGL context");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->context.makeCurrent = makeContextCurrentWGL;
|
||||||
|
window->context.swapBuffers = swapBuffersWGL;
|
||||||
|
window->context.swapInterval = swapIntervalWGL;
|
||||||
|
window->context.extensionSupported = extensionSupportedWGL;
|
||||||
|
window->context.getProcAddress = getProcAddressWGL;
|
||||||
|
window->context.destroy = destroyContextWGL;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef setWGLattrib
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (window->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window->context.wgl.handle;
|
||||||
|
}
|
||||||
|
|
157
external/glfw/wgl_context.h
vendored
Normal file
157
external/glfw/wgl_context.h
vendored
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 WGL - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_wgl_context_h_
|
||||||
|
#define _glfw3_wgl_context_h_
|
||||||
|
|
||||||
|
|
||||||
|
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||||
|
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||||
|
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||||
|
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||||
|
#define WGL_TYPE_RGBA_ARB 0x202b
|
||||||
|
#define WGL_ACCELERATION_ARB 0x2003
|
||||||
|
#define WGL_NO_ACCELERATION_ARB 0x2025
|
||||||
|
#define WGL_RED_BITS_ARB 0x2015
|
||||||
|
#define WGL_RED_SHIFT_ARB 0x2016
|
||||||
|
#define WGL_GREEN_BITS_ARB 0x2017
|
||||||
|
#define WGL_GREEN_SHIFT_ARB 0x2018
|
||||||
|
#define WGL_BLUE_BITS_ARB 0x2019
|
||||||
|
#define WGL_BLUE_SHIFT_ARB 0x201a
|
||||||
|
#define WGL_ALPHA_BITS_ARB 0x201b
|
||||||
|
#define WGL_ALPHA_SHIFT_ARB 0x201c
|
||||||
|
#define WGL_ACCUM_BITS_ARB 0x201d
|
||||||
|
#define WGL_ACCUM_RED_BITS_ARB 0x201e
|
||||||
|
#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
|
||||||
|
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
||||||
|
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
||||||
|
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||||
|
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||||
|
#define WGL_AUX_BUFFERS_ARB 0x2024
|
||||||
|
#define WGL_STEREO_ARB 0x2012
|
||||||
|
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||||
|
#define WGL_SAMPLES_ARB 0x2042
|
||||||
|
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
|
||||||
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
||||||
|
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
||||||
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||||
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||||
|
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||||
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||||
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||||
|
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||||
|
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
||||||
|
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
||||||
|
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
||||||
|
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
||||||
|
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
|
||||||
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
||||||
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
||||||
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
||||||
|
|
||||||
|
#define ERROR_INVALID_VERSION_ARB 0x2095
|
||||||
|
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
|
||||||
|
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
|
||||||
|
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
|
||||||
|
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
|
||||||
|
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
|
||||||
|
|
||||||
|
typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC);
|
||||||
|
typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC);
|
||||||
|
typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR);
|
||||||
|
typedef HDC (WINAPI * WGLGETCURRENTDC_T)(void);
|
||||||
|
typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC);
|
||||||
|
typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
|
||||||
|
|
||||||
|
// opengl32.dll function pointer typedefs
|
||||||
|
#define wglCreateContext _glfw.wgl.CreateContext
|
||||||
|
#define wglDeleteContext _glfw.wgl.DeleteContext
|
||||||
|
#define wglGetProcAddress _glfw.wgl.GetProcAddress
|
||||||
|
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
|
||||||
|
#define wglMakeCurrent _glfw.wgl.MakeCurrent
|
||||||
|
#define wglShareLists _glfw.wgl.ShareLists
|
||||||
|
|
||||||
|
#define _GLFW_RECREATION_NOT_NEEDED 0
|
||||||
|
#define _GLFW_RECREATION_REQUIRED 1
|
||||||
|
#define _GLFW_RECREATION_IMPOSSIBLE 2
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl
|
||||||
|
|
||||||
|
|
||||||
|
// WGL-specific per-context data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcontextWGL
|
||||||
|
{
|
||||||
|
HDC dc;
|
||||||
|
HGLRC handle;
|
||||||
|
int interval;
|
||||||
|
|
||||||
|
} _GLFWcontextWGL;
|
||||||
|
|
||||||
|
// WGL-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryWGL
|
||||||
|
{
|
||||||
|
HINSTANCE instance;
|
||||||
|
WGLCREATECONTEXT_T CreateContext;
|
||||||
|
WGLDELETECONTEXT_T DeleteContext;
|
||||||
|
WGLGETPROCADDRESS_T GetProcAddress;
|
||||||
|
WGLGETCURRENTDC_T GetCurrentDC;
|
||||||
|
WGLMAKECURRENT_T MakeCurrent;
|
||||||
|
WGLSHARELISTS_T ShareLists;
|
||||||
|
|
||||||
|
GLFWbool extensionsLoaded;
|
||||||
|
|
||||||
|
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||||
|
PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB;
|
||||||
|
PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT;
|
||||||
|
PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB;
|
||||||
|
PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||||
|
GLFWbool EXT_swap_control;
|
||||||
|
GLFWbool ARB_multisample;
|
||||||
|
GLFWbool ARB_framebuffer_sRGB;
|
||||||
|
GLFWbool EXT_framebuffer_sRGB;
|
||||||
|
GLFWbool ARB_pixel_format;
|
||||||
|
GLFWbool ARB_create_context;
|
||||||
|
GLFWbool ARB_create_context_profile;
|
||||||
|
GLFWbool EXT_create_context_es2_profile;
|
||||||
|
GLFWbool ARB_create_context_robustness;
|
||||||
|
GLFWbool ARB_context_flush_control;
|
||||||
|
|
||||||
|
} _GLFWlibraryWGL;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwInitWGL(void);
|
||||||
|
void _glfwTerminateWGL(void);
|
||||||
|
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||||
|
const _GLFWctxconfig* ctxconfig,
|
||||||
|
const _GLFWfbconfig* fbconfig);
|
||||||
|
|
||||||
|
#endif // _glfw3_wgl_context_h_
|
473
external/glfw/win32_init.c
vendored
Normal file
473
external/glfw/win32_init.c
vendored
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include <initguid.h>
|
||||||
|
DEFINE_GUID(GUID_DEVINTERFACE_HID,0x4d1e55b2,0xf16f,0x11cf,0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30);
|
||||||
|
|
||||||
|
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
|
||||||
|
|
||||||
|
// Applications exporting this symbol with this value will be automatically
|
||||||
|
// directed to the high-performance GPU on Nvidia Optimus systems with
|
||||||
|
// up-to-date drivers
|
||||||
|
//
|
||||||
|
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||||
|
|
||||||
|
// Applications exporting this symbol with this value will be automatically
|
||||||
|
// directed to the high-performance GPU on AMD PowerXpress systems with
|
||||||
|
// up-to-date drivers
|
||||||
|
//
|
||||||
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
|
||||||
|
#endif // _GLFW_USE_HYBRID_HPG
|
||||||
|
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
|
||||||
|
// GLFW DLL entry point
|
||||||
|
//
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // _GLFW_BUILD_DLL
|
||||||
|
|
||||||
|
// Load necessary libraries (DLLs)
|
||||||
|
//
|
||||||
|
static GLFWbool loadLibraries(void)
|
||||||
|
{
|
||||||
|
_glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");
|
||||||
|
if (!_glfw.win32.winmm.instance)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load winmm.dll");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32.winmm.timeGetTime = (TIMEGETTIME_T)
|
||||||
|
GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");
|
||||||
|
|
||||||
|
_glfw.win32.user32.instance = LoadLibraryA("user32.dll");
|
||||||
|
if (!_glfw.win32.user32.instance)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to load user32.dll");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T)
|
||||||
|
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
|
||||||
|
_glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T)
|
||||||
|
GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
|
||||||
|
|
||||||
|
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
|
||||||
|
if (_glfw.win32.dinput8.instance)
|
||||||
|
{
|
||||||
|
_glfw.win32.dinput8.DirectInput8Create = (DIRECTINPUT8CREATE_T)
|
||||||
|
GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char* names[] =
|
||||||
|
{
|
||||||
|
"xinput1_4.dll",
|
||||||
|
"xinput1_3.dll",
|
||||||
|
"xinput9_1_0.dll",
|
||||||
|
"xinput1_2.dll",
|
||||||
|
"xinput1_1.dll",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i = 0; names[i]; i++)
|
||||||
|
{
|
||||||
|
_glfw.win32.xinput.instance = LoadLibraryA(names[i]);
|
||||||
|
if (_glfw.win32.xinput.instance)
|
||||||
|
{
|
||||||
|
_glfw.win32.xinput.XInputGetCapabilities = (XINPUTGETCAPABILITIES_T)
|
||||||
|
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
|
||||||
|
_glfw.win32.xinput.XInputGetState = (XINPUTGETSTATE_T)
|
||||||
|
GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll");
|
||||||
|
if (_glfw.win32.dwmapi.instance)
|
||||||
|
{
|
||||||
|
_glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T)
|
||||||
|
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
|
||||||
|
_glfw.win32.dwmapi.DwmFlush = (DWMFLUSH_T)
|
||||||
|
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");
|
||||||
|
if (_glfw.win32.shcore.instance)
|
||||||
|
{
|
||||||
|
_glfw.win32.shcore.SetProcessDpiAwareness = (SETPROCESSDPIAWARENESS_T)
|
||||||
|
GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unload used libraries (DLLs)
|
||||||
|
//
|
||||||
|
static void freeLibraries(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32.xinput.instance)
|
||||||
|
FreeLibrary(_glfw.win32.xinput.instance);
|
||||||
|
|
||||||
|
if (_glfw.win32.dinput8.instance)
|
||||||
|
FreeLibrary(_glfw.win32.dinput8.instance);
|
||||||
|
|
||||||
|
if (_glfw.win32.winmm.instance)
|
||||||
|
FreeLibrary(_glfw.win32.winmm.instance);
|
||||||
|
|
||||||
|
if (_glfw.win32.user32.instance)
|
||||||
|
FreeLibrary(_glfw.win32.user32.instance);
|
||||||
|
|
||||||
|
if (_glfw.win32.dwmapi.instance)
|
||||||
|
FreeLibrary(_glfw.win32.dwmapi.instance);
|
||||||
|
|
||||||
|
if (_glfw.win32.shcore.instance)
|
||||||
|
FreeLibrary(_glfw.win32.shcore.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create key code translation tables
|
||||||
|
//
|
||||||
|
static void createKeyTables(void)
|
||||||
|
{
|
||||||
|
int scancode;
|
||||||
|
|
||||||
|
memset(_glfw.win32.publicKeys, -1, sizeof(_glfw.win32.publicKeys));
|
||||||
|
memset(_glfw.win32.nativeKeys, -1, sizeof(_glfw.win32.nativeKeys));
|
||||||
|
|
||||||
|
_glfw.win32.publicKeys[0x00B] = GLFW_KEY_0;
|
||||||
|
_glfw.win32.publicKeys[0x002] = GLFW_KEY_1;
|
||||||
|
_glfw.win32.publicKeys[0x003] = GLFW_KEY_2;
|
||||||
|
_glfw.win32.publicKeys[0x004] = GLFW_KEY_3;
|
||||||
|
_glfw.win32.publicKeys[0x005] = GLFW_KEY_4;
|
||||||
|
_glfw.win32.publicKeys[0x006] = GLFW_KEY_5;
|
||||||
|
_glfw.win32.publicKeys[0x007] = GLFW_KEY_6;
|
||||||
|
_glfw.win32.publicKeys[0x008] = GLFW_KEY_7;
|
||||||
|
_glfw.win32.publicKeys[0x009] = GLFW_KEY_8;
|
||||||
|
_glfw.win32.publicKeys[0x00A] = GLFW_KEY_9;
|
||||||
|
_glfw.win32.publicKeys[0x01E] = GLFW_KEY_A;
|
||||||
|
_glfw.win32.publicKeys[0x030] = GLFW_KEY_B;
|
||||||
|
_glfw.win32.publicKeys[0x02E] = GLFW_KEY_C;
|
||||||
|
_glfw.win32.publicKeys[0x020] = GLFW_KEY_D;
|
||||||
|
_glfw.win32.publicKeys[0x012] = GLFW_KEY_E;
|
||||||
|
_glfw.win32.publicKeys[0x021] = GLFW_KEY_F;
|
||||||
|
_glfw.win32.publicKeys[0x022] = GLFW_KEY_G;
|
||||||
|
_glfw.win32.publicKeys[0x023] = GLFW_KEY_H;
|
||||||
|
_glfw.win32.publicKeys[0x017] = GLFW_KEY_I;
|
||||||
|
_glfw.win32.publicKeys[0x024] = GLFW_KEY_J;
|
||||||
|
_glfw.win32.publicKeys[0x025] = GLFW_KEY_K;
|
||||||
|
_glfw.win32.publicKeys[0x026] = GLFW_KEY_L;
|
||||||
|
_glfw.win32.publicKeys[0x032] = GLFW_KEY_M;
|
||||||
|
_glfw.win32.publicKeys[0x031] = GLFW_KEY_N;
|
||||||
|
_glfw.win32.publicKeys[0x018] = GLFW_KEY_O;
|
||||||
|
_glfw.win32.publicKeys[0x019] = GLFW_KEY_P;
|
||||||
|
_glfw.win32.publicKeys[0x010] = GLFW_KEY_Q;
|
||||||
|
_glfw.win32.publicKeys[0x013] = GLFW_KEY_R;
|
||||||
|
_glfw.win32.publicKeys[0x01F] = GLFW_KEY_S;
|
||||||
|
_glfw.win32.publicKeys[0x014] = GLFW_KEY_T;
|
||||||
|
_glfw.win32.publicKeys[0x016] = GLFW_KEY_U;
|
||||||
|
_glfw.win32.publicKeys[0x02F] = GLFW_KEY_V;
|
||||||
|
_glfw.win32.publicKeys[0x011] = GLFW_KEY_W;
|
||||||
|
_glfw.win32.publicKeys[0x02D] = GLFW_KEY_X;
|
||||||
|
_glfw.win32.publicKeys[0x015] = GLFW_KEY_Y;
|
||||||
|
_glfw.win32.publicKeys[0x02C] = GLFW_KEY_Z;
|
||||||
|
|
||||||
|
_glfw.win32.publicKeys[0x028] = GLFW_KEY_APOSTROPHE;
|
||||||
|
_glfw.win32.publicKeys[0x02B] = GLFW_KEY_BACKSLASH;
|
||||||
|
_glfw.win32.publicKeys[0x033] = GLFW_KEY_COMMA;
|
||||||
|
_glfw.win32.publicKeys[0x00D] = GLFW_KEY_EQUAL;
|
||||||
|
_glfw.win32.publicKeys[0x029] = GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
_glfw.win32.publicKeys[0x01A] = GLFW_KEY_LEFT_BRACKET;
|
||||||
|
_glfw.win32.publicKeys[0x00C] = GLFW_KEY_MINUS;
|
||||||
|
_glfw.win32.publicKeys[0x034] = GLFW_KEY_PERIOD;
|
||||||
|
_glfw.win32.publicKeys[0x01B] = GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
_glfw.win32.publicKeys[0x027] = GLFW_KEY_SEMICOLON;
|
||||||
|
_glfw.win32.publicKeys[0x035] = GLFW_KEY_SLASH;
|
||||||
|
_glfw.win32.publicKeys[0x056] = GLFW_KEY_WORLD_2;
|
||||||
|
|
||||||
|
_glfw.win32.publicKeys[0x00E] = GLFW_KEY_BACKSPACE;
|
||||||
|
_glfw.win32.publicKeys[0x153] = GLFW_KEY_DELETE;
|
||||||
|
_glfw.win32.publicKeys[0x14F] = GLFW_KEY_END;
|
||||||
|
_glfw.win32.publicKeys[0x01C] = GLFW_KEY_ENTER;
|
||||||
|
_glfw.win32.publicKeys[0x001] = GLFW_KEY_ESCAPE;
|
||||||
|
_glfw.win32.publicKeys[0x147] = GLFW_KEY_HOME;
|
||||||
|
_glfw.win32.publicKeys[0x152] = GLFW_KEY_INSERT;
|
||||||
|
_glfw.win32.publicKeys[0x15D] = GLFW_KEY_MENU;
|
||||||
|
_glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
_glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP;
|
||||||
|
_glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE;
|
||||||
|
_glfw.win32.publicKeys[0x146] = GLFW_KEY_PAUSE;
|
||||||
|
_glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE;
|
||||||
|
_glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB;
|
||||||
|
_glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK;
|
||||||
|
_glfw.win32.publicKeys[0x145] = GLFW_KEY_NUM_LOCK;
|
||||||
|
_glfw.win32.publicKeys[0x046] = GLFW_KEY_SCROLL_LOCK;
|
||||||
|
_glfw.win32.publicKeys[0x03B] = GLFW_KEY_F1;
|
||||||
|
_glfw.win32.publicKeys[0x03C] = GLFW_KEY_F2;
|
||||||
|
_glfw.win32.publicKeys[0x03D] = GLFW_KEY_F3;
|
||||||
|
_glfw.win32.publicKeys[0x03E] = GLFW_KEY_F4;
|
||||||
|
_glfw.win32.publicKeys[0x03F] = GLFW_KEY_F5;
|
||||||
|
_glfw.win32.publicKeys[0x040] = GLFW_KEY_F6;
|
||||||
|
_glfw.win32.publicKeys[0x041] = GLFW_KEY_F7;
|
||||||
|
_glfw.win32.publicKeys[0x042] = GLFW_KEY_F8;
|
||||||
|
_glfw.win32.publicKeys[0x043] = GLFW_KEY_F9;
|
||||||
|
_glfw.win32.publicKeys[0x044] = GLFW_KEY_F10;
|
||||||
|
_glfw.win32.publicKeys[0x057] = GLFW_KEY_F11;
|
||||||
|
_glfw.win32.publicKeys[0x058] = GLFW_KEY_F12;
|
||||||
|
_glfw.win32.publicKeys[0x064] = GLFW_KEY_F13;
|
||||||
|
_glfw.win32.publicKeys[0x065] = GLFW_KEY_F14;
|
||||||
|
_glfw.win32.publicKeys[0x066] = GLFW_KEY_F15;
|
||||||
|
_glfw.win32.publicKeys[0x067] = GLFW_KEY_F16;
|
||||||
|
_glfw.win32.publicKeys[0x068] = GLFW_KEY_F17;
|
||||||
|
_glfw.win32.publicKeys[0x069] = GLFW_KEY_F18;
|
||||||
|
_glfw.win32.publicKeys[0x06A] = GLFW_KEY_F19;
|
||||||
|
_glfw.win32.publicKeys[0x06B] = GLFW_KEY_F20;
|
||||||
|
_glfw.win32.publicKeys[0x06C] = GLFW_KEY_F21;
|
||||||
|
_glfw.win32.publicKeys[0x06D] = GLFW_KEY_F22;
|
||||||
|
_glfw.win32.publicKeys[0x06E] = GLFW_KEY_F23;
|
||||||
|
_glfw.win32.publicKeys[0x076] = GLFW_KEY_F24;
|
||||||
|
_glfw.win32.publicKeys[0x038] = GLFW_KEY_LEFT_ALT;
|
||||||
|
_glfw.win32.publicKeys[0x01D] = GLFW_KEY_LEFT_CONTROL;
|
||||||
|
_glfw.win32.publicKeys[0x02A] = GLFW_KEY_LEFT_SHIFT;
|
||||||
|
_glfw.win32.publicKeys[0x15B] = GLFW_KEY_LEFT_SUPER;
|
||||||
|
_glfw.win32.publicKeys[0x137] = GLFW_KEY_PRINT_SCREEN;
|
||||||
|
_glfw.win32.publicKeys[0x138] = GLFW_KEY_RIGHT_ALT;
|
||||||
|
_glfw.win32.publicKeys[0x11D] = GLFW_KEY_RIGHT_CONTROL;
|
||||||
|
_glfw.win32.publicKeys[0x036] = GLFW_KEY_RIGHT_SHIFT;
|
||||||
|
_glfw.win32.publicKeys[0x15C] = GLFW_KEY_RIGHT_SUPER;
|
||||||
|
_glfw.win32.publicKeys[0x150] = GLFW_KEY_DOWN;
|
||||||
|
_glfw.win32.publicKeys[0x14B] = GLFW_KEY_LEFT;
|
||||||
|
_glfw.win32.publicKeys[0x14D] = GLFW_KEY_RIGHT;
|
||||||
|
_glfw.win32.publicKeys[0x148] = GLFW_KEY_UP;
|
||||||
|
|
||||||
|
_glfw.win32.publicKeys[0x052] = GLFW_KEY_KP_0;
|
||||||
|
_glfw.win32.publicKeys[0x04F] = GLFW_KEY_KP_1;
|
||||||
|
_glfw.win32.publicKeys[0x050] = GLFW_KEY_KP_2;
|
||||||
|
_glfw.win32.publicKeys[0x051] = GLFW_KEY_KP_3;
|
||||||
|
_glfw.win32.publicKeys[0x04B] = GLFW_KEY_KP_4;
|
||||||
|
_glfw.win32.publicKeys[0x04C] = GLFW_KEY_KP_5;
|
||||||
|
_glfw.win32.publicKeys[0x04D] = GLFW_KEY_KP_6;
|
||||||
|
_glfw.win32.publicKeys[0x047] = GLFW_KEY_KP_7;
|
||||||
|
_glfw.win32.publicKeys[0x048] = GLFW_KEY_KP_8;
|
||||||
|
_glfw.win32.publicKeys[0x049] = GLFW_KEY_KP_9;
|
||||||
|
_glfw.win32.publicKeys[0x04E] = GLFW_KEY_KP_ADD;
|
||||||
|
_glfw.win32.publicKeys[0x053] = GLFW_KEY_KP_DECIMAL;
|
||||||
|
_glfw.win32.publicKeys[0x135] = GLFW_KEY_KP_DIVIDE;
|
||||||
|
_glfw.win32.publicKeys[0x11C] = GLFW_KEY_KP_ENTER;
|
||||||
|
_glfw.win32.publicKeys[0x037] = GLFW_KEY_KP_MULTIPLY;
|
||||||
|
_glfw.win32.publicKeys[0x04A] = GLFW_KEY_KP_SUBTRACT;
|
||||||
|
|
||||||
|
for (scancode = 0; scancode < 512; scancode++)
|
||||||
|
{
|
||||||
|
if (_glfw.win32.publicKeys[scancode] > 0)
|
||||||
|
_glfw.win32.nativeKeys[_glfw.win32.publicKeys[scancode]] = scancode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a dummy window for behind-the-scenes work
|
||||||
|
//
|
||||||
|
static HWND createHelperWindow(void)
|
||||||
|
{
|
||||||
|
HWND window = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
|
||||||
|
_GLFW_WNDCLASSNAME,
|
||||||
|
L"GLFW helper window",
|
||||||
|
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||||
|
0, 0, 1, 1,
|
||||||
|
HWND_MESSAGE, NULL,
|
||||||
|
GetModuleHandleW(NULL),
|
||||||
|
NULL);
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to create helper window");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: The first call to ShowWindow is ignored if the parent process
|
||||||
|
// passed along a STARTUPINFO, so clear that flag with a no-op call
|
||||||
|
ShowWindow(window, SW_HIDE);
|
||||||
|
|
||||||
|
// Register for HID device notifications
|
||||||
|
{
|
||||||
|
DEV_BROADCAST_DEVICEINTERFACE_W dbi;
|
||||||
|
ZeroMemory(&dbi, sizeof(dbi));
|
||||||
|
dbi.dbcc_size = sizeof(dbi);
|
||||||
|
dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||||
|
dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
|
||||||
|
|
||||||
|
RegisterDeviceNotificationW(window,
|
||||||
|
(DEV_BROADCAST_HDR*) &dbi,
|
||||||
|
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Returns a wide string version of the specified UTF-8 string
|
||||||
|
//
|
||||||
|
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source)
|
||||||
|
{
|
||||||
|
WCHAR* target;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0);
|
||||||
|
if (!length)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
target = calloc(length, sizeof(WCHAR));
|
||||||
|
|
||||||
|
if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length))
|
||||||
|
{
|
||||||
|
free(target);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a UTF-8 string version of the specified wide string
|
||||||
|
//
|
||||||
|
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
|
||||||
|
{
|
||||||
|
char* target;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
|
||||||
|
if (!length)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
target = calloc(length, 1);
|
||||||
|
|
||||||
|
if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL))
|
||||||
|
{
|
||||||
|
free(target);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformInit(void)
|
||||||
|
{
|
||||||
|
if (!_glfwInitThreadLocalStorageWin32())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
// To make SetForegroundWindow work as we want, we need to fiddle
|
||||||
|
// with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early
|
||||||
|
// as possible in the hope of still being the foreground process)
|
||||||
|
SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
|
||||||
|
&_glfw.win32.foregroundLockTimeout, 0);
|
||||||
|
SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0),
|
||||||
|
SPIF_SENDCHANGE);
|
||||||
|
|
||||||
|
if (!loadLibraries())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
createKeyTables();
|
||||||
|
|
||||||
|
if (_glfw_SetProcessDpiAwareness)
|
||||||
|
_glfw_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||||
|
else if (_glfw_SetProcessDPIAware)
|
||||||
|
_glfw_SetProcessDPIAware();
|
||||||
|
|
||||||
|
if (!_glfwRegisterWindowClassWin32())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfw.win32.helperWindowHandle = createHelperWindow();
|
||||||
|
if (!_glfw.win32.helperWindowHandle)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfwPlatformPollEvents();
|
||||||
|
|
||||||
|
_glfwInitTimerWin32();
|
||||||
|
_glfwInitJoysticksWin32();
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminate(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32.helperWindowHandle)
|
||||||
|
DestroyWindow(_glfw.win32.helperWindowHandle);
|
||||||
|
|
||||||
|
_glfwUnregisterWindowClassWin32();
|
||||||
|
|
||||||
|
// Restore previous foreground lock timeout system setting
|
||||||
|
SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
|
||||||
|
UIntToPtr(_glfw.win32.foregroundLockTimeout),
|
||||||
|
SPIF_SENDCHANGE);
|
||||||
|
|
||||||
|
free(_glfw.win32.clipboardString);
|
||||||
|
|
||||||
|
_glfwTerminateWGL();
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
|
||||||
|
_glfwTerminateJoysticksWin32();
|
||||||
|
_glfwTerminateThreadLocalStorageWin32();
|
||||||
|
|
||||||
|
freeLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _GLFW_VERSION_NUMBER " Win32 WGL EGL"
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
" MinGW"
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
" VisualC"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
|
||||||
|
" hybrid-GPU"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
" DLL"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
763
external/glfw/win32_joystick.c
vendored
Normal file
763
external/glfw/win32_joystick.c
vendored
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.1 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <initguid.h>
|
||||||
|
|
||||||
|
#define _GLFW_PRESENCE_ONLY 1
|
||||||
|
#define _GLFW_UPDATE_STATE 2
|
||||||
|
|
||||||
|
#define _GLFW_TYPE_AXIS 0
|
||||||
|
#define _GLFW_TYPE_SLIDER 1
|
||||||
|
#define _GLFW_TYPE_BUTTON 2
|
||||||
|
#define _GLFW_TYPE_POV 3
|
||||||
|
|
||||||
|
// Data produced with DirectInput device object enumeration
|
||||||
|
//
|
||||||
|
typedef struct _GLFWobjenumWin32
|
||||||
|
{
|
||||||
|
IDirectInputDevice8W* device;
|
||||||
|
_GLFWjoyobjectWin32* objects;
|
||||||
|
int objectCount;
|
||||||
|
int axisCount;
|
||||||
|
int sliderCount;
|
||||||
|
int buttonCount;
|
||||||
|
int povCount;
|
||||||
|
} _GLFWobjenumWin32;
|
||||||
|
|
||||||
|
// Define only the necessary GUIDs (it's bad enough that we're exporting these)
|
||||||
|
//
|
||||||
|
DEFINE_GUID(IID_IDirectInput8W,0xbf798031,0x483a,0x4da2,0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00);
|
||||||
|
DEFINE_GUID(GUID_XAxis,0xa36d02e0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_YAxis,0xa36d02e1,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_ZAxis,0xa36d02e2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_RxAxis,0xa36d02f4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_RyAxis,0xa36d02f5,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_RzAxis,0xa36d02e3,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_Slider,0xa36d02e4,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_Button,0xa36d02f0,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
DEFINE_GUID(GUID_POV,0xa36d02f2,0xc9f3,0x11cf,0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00);
|
||||||
|
|
||||||
|
// Object data array for our clone of c_dfDIJoystick
|
||||||
|
// Generated with https://github.com/elmindreda/c_dfDIJoystick2
|
||||||
|
//
|
||||||
|
static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
|
||||||
|
{
|
||||||
|
{ &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||||
|
{ &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
{ NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Our clone of c_dfDIJoystick
|
||||||
|
//
|
||||||
|
static const DIDATAFORMAT _glfwDataFormat =
|
||||||
|
{
|
||||||
|
sizeof(DIDATAFORMAT),
|
||||||
|
sizeof(DIOBJECTDATAFORMAT),
|
||||||
|
DIDFT_ABSAXIS,
|
||||||
|
sizeof(DIJOYSTATE),
|
||||||
|
sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
|
||||||
|
_glfwObjectDataFormats
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a description fitting the specified XInput capabilities
|
||||||
|
//
|
||||||
|
static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
|
||||||
|
{
|
||||||
|
switch (xic->SubType)
|
||||||
|
{
|
||||||
|
case XINPUT_DEVSUBTYPE_WHEEL:
|
||||||
|
return "XInput Wheel";
|
||||||
|
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
|
||||||
|
return "XInput Arcade Stick";
|
||||||
|
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
|
||||||
|
return "XInput Flight Stick";
|
||||||
|
case XINPUT_DEVSUBTYPE_DANCE_PAD:
|
||||||
|
return "XInput Dance Pad";
|
||||||
|
case XINPUT_DEVSUBTYPE_GUITAR:
|
||||||
|
return "XInput Guitar";
|
||||||
|
case XINPUT_DEVSUBTYPE_DRUM_KIT:
|
||||||
|
return "XInput Drum Kit";
|
||||||
|
case XINPUT_DEVSUBTYPE_GAMEPAD:
|
||||||
|
{
|
||||||
|
if (xic->Flags & XINPUT_CAPS_WIRELESS)
|
||||||
|
return "Wireless Xbox 360 Controller";
|
||||||
|
else
|
||||||
|
return "Xbox 360 Controller";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown XInput Device";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexically compare device objects
|
||||||
|
//
|
||||||
|
static int compareJoystickObjects(const void* first, const void* second)
|
||||||
|
{
|
||||||
|
const _GLFWjoyobjectWin32* fo = first;
|
||||||
|
const _GLFWjoyobjectWin32* so = second;
|
||||||
|
|
||||||
|
if (fo->type != so->type)
|
||||||
|
return fo->type - so->type;
|
||||||
|
|
||||||
|
return fo->offset - so->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the specified device supports XInput
|
||||||
|
// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
|
||||||
|
//
|
||||||
|
static GLFWbool supportsXInput(const GUID* guid)
|
||||||
|
{
|
||||||
|
UINT i, count = 0;
|
||||||
|
RAWINPUTDEVICELIST* ridl;
|
||||||
|
GLFWbool result = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
|
||||||
|
|
||||||
|
if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
|
||||||
|
{
|
||||||
|
free(ridl);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
RID_DEVICE_INFO rdi;
|
||||||
|
char name[256];
|
||||||
|
UINT size;
|
||||||
|
|
||||||
|
if (ridl[i].dwType != RIM_TYPEHID)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ZeroMemory(&rdi, sizeof(rdi));
|
||||||
|
rdi.cbSize = sizeof(rdi);
|
||||||
|
size = sizeof(rdi);
|
||||||
|
|
||||||
|
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||||
|
RIDI_DEVICEINFO,
|
||||||
|
&rdi, &size) == -1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
|
size = sizeof(name);
|
||||||
|
|
||||||
|
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||||
|
RIDI_DEVICENAME,
|
||||||
|
name, &size) == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
if (strstr(name, "IG_"))
|
||||||
|
{
|
||||||
|
result = GLFW_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ridl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees all resources associated with the specified joystick
|
||||||
|
//
|
||||||
|
static void closeJoystick(_GLFWjoystickWin32* js)
|
||||||
|
{
|
||||||
|
if (js->device)
|
||||||
|
{
|
||||||
|
IDirectInputDevice8_Unacquire(js->device);
|
||||||
|
IDirectInputDevice8_Release(js->device);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(js->name);
|
||||||
|
free(js->axes);
|
||||||
|
free(js->buttons);
|
||||||
|
free(js->objects);
|
||||||
|
memset(js, 0, sizeof(_GLFWjoystickWin32));
|
||||||
|
|
||||||
|
_glfwInputJoystickChange((int) (js - _glfw.win32_js), GLFW_DISCONNECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectInput device object enumeration callback
|
||||||
|
// Insights gleaned from SDL2
|
||||||
|
//
|
||||||
|
static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
|
||||||
|
void* user)
|
||||||
|
{
|
||||||
|
_GLFWobjenumWin32* data = user;
|
||||||
|
_GLFWjoyobjectWin32* object = data->objects + data->objectCount;
|
||||||
|
|
||||||
|
if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
|
||||||
|
{
|
||||||
|
DIPROPRANGE dipr;
|
||||||
|
|
||||||
|
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_SLIDER(data->sliderCount);
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_X;
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_Y;
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_Z;
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_RX;
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_RY;
|
||||||
|
else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
|
||||||
|
object->offset = DIJOFS_RZ;
|
||||||
|
else
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
|
||||||
|
ZeroMemory(&dipr, sizeof(dipr));
|
||||||
|
dipr.diph.dwSize = sizeof(dipr);
|
||||||
|
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
|
||||||
|
dipr.diph.dwObj = doi->dwType;
|
||||||
|
dipr.diph.dwHow = DIPH_BYID;
|
||||||
|
dipr.lMin = -32768;
|
||||||
|
dipr.lMax = 32767;
|
||||||
|
|
||||||
|
if (FAILED(IDirectInputDevice8_SetProperty(data->device,
|
||||||
|
DIPROP_RANGE,
|
||||||
|
&dipr.diph)))
|
||||||
|
{
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||||
|
{
|
||||||
|
object->type = _GLFW_TYPE_SLIDER;
|
||||||
|
data->sliderCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object->type = _GLFW_TYPE_AXIS;
|
||||||
|
data->axisCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
|
||||||
|
{
|
||||||
|
object->offset = DIJOFS_BUTTON(data->buttonCount);
|
||||||
|
object->type = _GLFW_TYPE_BUTTON;
|
||||||
|
data->buttonCount++;
|
||||||
|
}
|
||||||
|
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
|
||||||
|
{
|
||||||
|
object->offset = DIJOFS_POV(data->povCount);
|
||||||
|
object->type = _GLFW_TYPE_POV;
|
||||||
|
data->povCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->objectCount++;
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectInput device enumeration callback
|
||||||
|
//
|
||||||
|
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
|
||||||
|
{
|
||||||
|
int joy = 0;
|
||||||
|
DIDEVCAPS dc;
|
||||||
|
DIPROPDWORD dipd;
|
||||||
|
IDirectInputDevice8* device;
|
||||||
|
_GLFWobjenumWin32 data;
|
||||||
|
_GLFWjoystickWin32* js;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (memcmp(&_glfw.win32_js[joy].guid, &di->guidInstance, sizeof(GUID)) == 0)
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (!_glfw.win32_js[joy].present)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joy > GLFW_JOYSTICK_LAST)
|
||||||
|
return DIENUM_STOP;
|
||||||
|
|
||||||
|
if (supportsXInput(&di->guidProduct))
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
|
||||||
|
if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
|
||||||
|
&di->guidInstance,
|
||||||
|
&device,
|
||||||
|
NULL)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "DI: Failed to create device");
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"DI: Failed to set device data format");
|
||||||
|
|
||||||
|
IDirectInputDevice8_Release(device);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&dc, sizeof(dc));
|
||||||
|
dc.dwSize = sizeof(dc);
|
||||||
|
|
||||||
|
if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"DI: Failed to query device capabilities");
|
||||||
|
|
||||||
|
IDirectInputDevice8_Release(device);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&dipd, sizeof(dipd));
|
||||||
|
dipd.diph.dwSize = sizeof(dipd);
|
||||||
|
dipd.diph.dwHeaderSize = sizeof(dipd.diph);
|
||||||
|
dipd.diph.dwHow = DIPH_DEVICE;
|
||||||
|
dipd.dwData = DIPROPAXISMODE_ABS;
|
||||||
|
|
||||||
|
if (FAILED(IDirectInputDevice8_SetProperty(device,
|
||||||
|
DIPROP_AXISMODE,
|
||||||
|
&dipd.diph)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"DI: Failed to set device axis mode");
|
||||||
|
|
||||||
|
IDirectInputDevice8_Release(device);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.device = device;
|
||||||
|
data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs,
|
||||||
|
sizeof(_GLFWjoyobjectWin32));
|
||||||
|
|
||||||
|
if (FAILED(IDirectInputDevice8_EnumObjects(device,
|
||||||
|
deviceObjectCallback,
|
||||||
|
&data,
|
||||||
|
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"DI: Failed to enumerate device objects");
|
||||||
|
|
||||||
|
IDirectInputDevice8_Release(device);
|
||||||
|
free(data.objects);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(data.objects, data.objectCount,
|
||||||
|
sizeof(_GLFWjoyobjectWin32),
|
||||||
|
compareJoystickObjects);
|
||||||
|
|
||||||
|
js = _glfw.win32_js + joy;
|
||||||
|
js->device = device;
|
||||||
|
js->guid = di->guidInstance;
|
||||||
|
js->axisCount = data.axisCount + data.sliderCount;
|
||||||
|
js->axes = calloc(js->axisCount, sizeof(float));
|
||||||
|
js->buttonCount += data.buttonCount + data.povCount * 4;
|
||||||
|
js->buttons = calloc(js->buttonCount, 1);
|
||||||
|
js->objects = data.objects;
|
||||||
|
js->objectCount = data.objectCount;
|
||||||
|
js->name = _glfwCreateUTF8FromWideStringWin32(di->tszInstanceName);
|
||||||
|
js->present = GLFW_TRUE;
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
|
||||||
|
return DIENUM_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to open the specified joystick device
|
||||||
|
// TODO: Pack state arrays for non-gamepad devices
|
||||||
|
//
|
||||||
|
static GLFWbool openXinputDevice(DWORD index)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
XINPUT_CAPABILITIES xic;
|
||||||
|
_GLFWjoystickWin32* js;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (_glfw.win32_js[joy].present &&
|
||||||
|
_glfw.win32_js[joy].device == NULL &&
|
||||||
|
_glfw.win32_js[joy].index == index)
|
||||||
|
{
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
if (!_glfw.win32_js[joy].present)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joy > GLFW_JOYSTICK_LAST)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (_glfw_XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
js = _glfw.win32_js + joy;
|
||||||
|
js->axisCount = 6;
|
||||||
|
js->axes = calloc(js->axisCount, sizeof(float));
|
||||||
|
js->buttonCount = 14;
|
||||||
|
js->buttons = calloc(js->buttonCount, 1);
|
||||||
|
js->present = GLFW_TRUE;
|
||||||
|
js->name = strdup(getDeviceDescription(&xic));
|
||||||
|
js->index = index;
|
||||||
|
|
||||||
|
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polls for and processes events the specified joystick
|
||||||
|
//
|
||||||
|
static GLFWbool pollJoystickState(_GLFWjoystickWin32* js, int mode)
|
||||||
|
{
|
||||||
|
if (!js->present)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (js->device)
|
||||||
|
{
|
||||||
|
int i, j, ai = 0, bi = 0;
|
||||||
|
HRESULT result;
|
||||||
|
DIJOYSTATE state;
|
||||||
|
|
||||||
|
IDirectInputDevice8_Poll(js->device);
|
||||||
|
result = IDirectInputDevice8_GetDeviceState(js->device,
|
||||||
|
sizeof(state),
|
||||||
|
&state);
|
||||||
|
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
|
||||||
|
{
|
||||||
|
IDirectInputDevice8_Acquire(js->device);
|
||||||
|
IDirectInputDevice8_Poll(js->device);
|
||||||
|
result = IDirectInputDevice8_GetDeviceState(js->device,
|
||||||
|
sizeof(state),
|
||||||
|
&state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
closeJoystick(js);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == _GLFW_PRESENCE_ONLY)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
for (i = 0; i < js->objectCount; i++)
|
||||||
|
{
|
||||||
|
const void* data = (char*) &state + js->objects[i].offset;
|
||||||
|
|
||||||
|
switch (js->objects[i].type)
|
||||||
|
{
|
||||||
|
case _GLFW_TYPE_AXIS:
|
||||||
|
case _GLFW_TYPE_SLIDER:
|
||||||
|
{
|
||||||
|
js->axes[ai++] = (*((LONG*) data) + 0.5f) / 32767.5f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case _GLFW_TYPE_BUTTON:
|
||||||
|
{
|
||||||
|
if (*((BYTE*) data) & 0x80)
|
||||||
|
js->buttons[bi++] = GLFW_PRESS;
|
||||||
|
else
|
||||||
|
js->buttons[bi++] = GLFW_RELEASE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case _GLFW_TYPE_POV:
|
||||||
|
{
|
||||||
|
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
|
||||||
|
// Screams of horror are appropriate at this point
|
||||||
|
int value = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
|
||||||
|
if (value < 0 || value > 8)
|
||||||
|
value = 8;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if (directions[value] & (1 << j))
|
||||||
|
js->buttons[bi++] = GLFW_PRESS;
|
||||||
|
else
|
||||||
|
js->buttons[bi++] = GLFW_RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
DWORD result;
|
||||||
|
XINPUT_STATE xis;
|
||||||
|
const WORD buttons[14] =
|
||||||
|
{
|
||||||
|
XINPUT_GAMEPAD_A,
|
||||||
|
XINPUT_GAMEPAD_B,
|
||||||
|
XINPUT_GAMEPAD_X,
|
||||||
|
XINPUT_GAMEPAD_Y,
|
||||||
|
XINPUT_GAMEPAD_LEFT_SHOULDER,
|
||||||
|
XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||||
|
XINPUT_GAMEPAD_BACK,
|
||||||
|
XINPUT_GAMEPAD_START,
|
||||||
|
XINPUT_GAMEPAD_LEFT_THUMB,
|
||||||
|
XINPUT_GAMEPAD_RIGHT_THUMB,
|
||||||
|
XINPUT_GAMEPAD_DPAD_UP,
|
||||||
|
XINPUT_GAMEPAD_DPAD_RIGHT,
|
||||||
|
XINPUT_GAMEPAD_DPAD_DOWN,
|
||||||
|
XINPUT_GAMEPAD_DPAD_LEFT
|
||||||
|
};
|
||||||
|
|
||||||
|
result = _glfw_XInputGetState(js->index, &xis);
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (result == ERROR_DEVICE_NOT_CONNECTED)
|
||||||
|
closeJoystick(js);
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == _GLFW_PRESENCE_ONLY)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
if (sqrt((double) (xis.Gamepad.sThumbLX * xis.Gamepad.sThumbLX +
|
||||||
|
xis.Gamepad.sThumbLY * xis.Gamepad.sThumbLY)) >
|
||||||
|
(double) XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE)
|
||||||
|
{
|
||||||
|
js->axes[0] = (xis.Gamepad.sThumbLX + 0.5f) / 32767.f;
|
||||||
|
js->axes[1] = (xis.Gamepad.sThumbLY + 0.5f) / 32767.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
js->axes[0] = 0.f;
|
||||||
|
js->axes[1] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqrt((double) (xis.Gamepad.sThumbRX * xis.Gamepad.sThumbRX +
|
||||||
|
xis.Gamepad.sThumbRY * xis.Gamepad.sThumbRY)) >
|
||||||
|
(double) XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE)
|
||||||
|
{
|
||||||
|
js->axes[2] = (xis.Gamepad.sThumbRX + 0.5f) / 32767.f;
|
||||||
|
js->axes[3] = (xis.Gamepad.sThumbRY + 0.5f) / 32767.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
js->axes[2] = 0.f;
|
||||||
|
js->axes[3] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xis.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
|
||||||
|
js->axes[4] = xis.Gamepad.bLeftTrigger / 127.5f - 1.f;
|
||||||
|
else
|
||||||
|
js->axes[4] = -1.f;
|
||||||
|
|
||||||
|
if (xis.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD)
|
||||||
|
js->axes[5] = xis.Gamepad.bRightTrigger / 127.5f - 1.f;
|
||||||
|
else
|
||||||
|
js->axes[5] = -1.f;
|
||||||
|
|
||||||
|
for (i = 0; i < 14; i++)
|
||||||
|
js->buttons[i] = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialize joystick interface
|
||||||
|
//
|
||||||
|
void _glfwInitJoysticksWin32(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32.dinput8.instance)
|
||||||
|
{
|
||||||
|
if (FAILED(_glfw_DirectInput8Create(GetModuleHandle(NULL),
|
||||||
|
DIRECTINPUT_VERSION,
|
||||||
|
&IID_IDirectInput8W,
|
||||||
|
(void**) &_glfw.win32.dinput8.api,
|
||||||
|
NULL)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"DI: Failed to create interface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwDetectJoystickConnectionWin32();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all opened joystick handles
|
||||||
|
//
|
||||||
|
void _glfwTerminateJoysticksWin32(void)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
closeJoystick(_glfw.win32_js + joy);
|
||||||
|
|
||||||
|
if (_glfw.win32.dinput8.api)
|
||||||
|
IDirectInput8_Release(_glfw.win32.dinput8.api);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for new joysticks after DBT_DEVICEARRIVAL
|
||||||
|
//
|
||||||
|
void _glfwDetectJoystickConnectionWin32(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32.xinput.instance)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
for (i = 0; i < XUSER_MAX_COUNT; i++)
|
||||||
|
openXinputDevice(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.win32.dinput8.api)
|
||||||
|
{
|
||||||
|
if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
|
||||||
|
DI8DEVCLASS_GAMECTRL,
|
||||||
|
deviceCallback,
|
||||||
|
NULL,
|
||||||
|
DIEDFL_ALLDEVICES)))
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Failed to enumerate DirectInput8 devices");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
|
||||||
|
//
|
||||||
|
void _glfwDetectJoystickDisconnectionWin32(void)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
pollJoystickState(_glfw.win32_js + joy, _GLFW_PRESENCE_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformJoystickPresent(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||||
|
return pollJoystickState(js, _GLFW_PRESENCE_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||||
|
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = js->axisCount;
|
||||||
|
return js->axes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||||
|
{
|
||||||
|
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||||
|
if (!pollJoystickState(js, _GLFW_UPDATE_STATE))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*count = js->buttonCount;
|
||||||
|
return js->buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetJoystickName(int joy)
|
||||||
|
{
|
||||||
|
_GLFWjoystickWin32* js = _glfw.win32_js + joy;
|
||||||
|
if (!pollJoystickState(js, _GLFW_PRESENCE_ONLY))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return js->name;
|
||||||
|
}
|
||||||
|
|
64
external/glfw/win32_joystick.h
vendored
Normal file
64
external/glfw/win32_joystick.h
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_win32_joystick_h_
|
||||||
|
#define _glfw3_win32_joystick_h_
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||||
|
_GLFWjoystickWin32 win32_js[GLFW_JOYSTICK_LAST + 1]
|
||||||
|
|
||||||
|
// Joystick element (axis, button or slider)
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoyobjectWin32
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
int type;
|
||||||
|
} _GLFWjoyobjectWin32;
|
||||||
|
|
||||||
|
// Win32-specific per-joystick data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoystickWin32
|
||||||
|
{
|
||||||
|
GLFWbool present;
|
||||||
|
float* axes;
|
||||||
|
int axisCount;
|
||||||
|
unsigned char* buttons;
|
||||||
|
int buttonCount;
|
||||||
|
_GLFWjoyobjectWin32* objects;
|
||||||
|
int objectCount;
|
||||||
|
char* name;
|
||||||
|
IDirectInputDevice8W* device;
|
||||||
|
DWORD index;
|
||||||
|
GUID guid;
|
||||||
|
} _GLFWjoystickWin32;
|
||||||
|
|
||||||
|
|
||||||
|
void _glfwInitJoysticksWin32(void);
|
||||||
|
void _glfwTerminateJoysticksWin32(void);
|
||||||
|
void _glfwDetectJoystickConnectionWin32(void);
|
||||||
|
void _glfwDetectJoystickDisconnectionWin32(void);
|
||||||
|
|
||||||
|
#endif // _glfw3_win32_joystick_h_
|
401
external/glfw/win32_monitor.c
vendored
Normal file
401
external/glfw/win32_monitor.c
vendored
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Create monitor from an adapter and (optionally) a display
|
||||||
|
//
|
||||||
|
static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
|
||||||
|
DISPLAY_DEVICEW* display)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor;
|
||||||
|
char* name;
|
||||||
|
HDC dc;
|
||||||
|
|
||||||
|
if (display)
|
||||||
|
name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
|
||||||
|
else
|
||||||
|
name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to convert string to UTF-8");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
|
||||||
|
|
||||||
|
monitor = _glfwAllocMonitor(name,
|
||||||
|
GetDeviceCaps(dc, HORZSIZE),
|
||||||
|
GetDeviceCaps(dc, VERTSIZE));
|
||||||
|
|
||||||
|
DeleteDC(dc);
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
|
||||||
|
monitor->win32.modesPruned = GLFW_TRUE;
|
||||||
|
|
||||||
|
wcscpy(monitor->win32.adapterName, adapter->DeviceName);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0,
|
||||||
|
adapter->DeviceName, -1,
|
||||||
|
monitor->win32.publicAdapterName,
|
||||||
|
sizeof(monitor->win32.publicAdapterName),
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
wcscpy(monitor->win32.displayName, display->DeviceName);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0,
|
||||||
|
display->DeviceName, -1,
|
||||||
|
monitor->win32.publicDisplayName,
|
||||||
|
sizeof(monitor->win32.publicDisplayName),
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Change the current video mode
|
||||||
|
//
|
||||||
|
GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||||
|
{
|
||||||
|
GLFWvidmode current;
|
||||||
|
const GLFWvidmode* best;
|
||||||
|
DEVMODEW dm;
|
||||||
|
|
||||||
|
best = _glfwChooseVideoMode(monitor, desired);
|
||||||
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
ZeroMemory(&dm, sizeof(dm));
|
||||||
|
dm.dmSize = sizeof(DEVMODEW);
|
||||||
|
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
|
||||||
|
DM_DISPLAYFREQUENCY;
|
||||||
|
dm.dmPelsWidth = best->width;
|
||||||
|
dm.dmPelsHeight = best->height;
|
||||||
|
dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
|
||||||
|
dm.dmDisplayFrequency = best->refreshRate;
|
||||||
|
|
||||||
|
if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
|
||||||
|
dm.dmBitsPerPel = 32;
|
||||||
|
|
||||||
|
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||||
|
&dm,
|
||||||
|
NULL,
|
||||||
|
CDS_FULLSCREEN,
|
||||||
|
NULL) != DISP_CHANGE_SUCCESSFUL)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor->win32.modeChanged = GLFW_TRUE;
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the previously saved (original) video mode
|
||||||
|
//
|
||||||
|
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
if (monitor->win32.modeChanged)
|
||||||
|
{
|
||||||
|
ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||||
|
NULL, NULL, CDS_FULLSCREEN, NULL);
|
||||||
|
monitor->win32.modeChanged = GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
int found = 0;
|
||||||
|
DWORD adapterIndex, displayIndex, primaryIndex = 0;
|
||||||
|
DISPLAY_DEVICEW adapter, display;
|
||||||
|
GLFWbool hasDisplays = GLFW_FALSE;
|
||||||
|
_GLFWmonitor** monitors = NULL;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
// HACK: Check if any active adapters have connected displays
|
||||||
|
// If not, this is a headless system or a VMware guest
|
||||||
|
|
||||||
|
for (adapterIndex = 0; ; adapterIndex++)
|
||||||
|
{
|
||||||
|
ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
|
||||||
|
adapter.cb = sizeof(DISPLAY_DEVICEW);
|
||||||
|
|
||||||
|
if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
|
||||||
|
display.cb = sizeof(DISPLAY_DEVICEW);
|
||||||
|
|
||||||
|
if (EnumDisplayDevicesW(adapter.DeviceName, 0, &display, 0))
|
||||||
|
{
|
||||||
|
hasDisplays = GLFW_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (adapterIndex = 0; ; adapterIndex++)
|
||||||
|
{
|
||||||
|
ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW));
|
||||||
|
adapter.cb = sizeof(DISPLAY_DEVICEW);
|
||||||
|
|
||||||
|
if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
|
||||||
|
primaryIndex = found;
|
||||||
|
|
||||||
|
if (hasDisplays)
|
||||||
|
{
|
||||||
|
for (displayIndex = 0; ; displayIndex++)
|
||||||
|
{
|
||||||
|
ZeroMemory(&display, sizeof(DISPLAY_DEVICEW));
|
||||||
|
display.cb = sizeof(DISPLAY_DEVICEW);
|
||||||
|
|
||||||
|
if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
found++;
|
||||||
|
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
|
||||||
|
monitors[found - 1] = createMonitor(&adapter, &display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found++;
|
||||||
|
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
|
||||||
|
monitors[found - 1] = createMonitor(&adapter, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_GLFW_SWAP_POINTERS(monitors[0], monitors[primaryIndex]);
|
||||||
|
|
||||||
|
*count = found;
|
||||||
|
return monitors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||||
|
{
|
||||||
|
if (wcslen(first->win32.displayName))
|
||||||
|
return wcscmp(first->win32.displayName, second->win32.displayName) == 0;
|
||||||
|
else
|
||||||
|
return wcscmp(first->win32.adapterName, second->win32.adapterName) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
DEVMODEW settings;
|
||||||
|
ZeroMemory(&settings, sizeof(DEVMODEW));
|
||||||
|
settings.dmSize = sizeof(DEVMODEW);
|
||||||
|
|
||||||
|
EnumDisplaySettingsExW(monitor->win32.adapterName,
|
||||||
|
ENUM_CURRENT_SETTINGS,
|
||||||
|
&settings,
|
||||||
|
EDS_ROTATEDMODE);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = settings.dmPosition.x;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = settings.dmPosition.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||||
|
{
|
||||||
|
int modeIndex = 0, size = 0;
|
||||||
|
GLFWvidmode* result = NULL;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GLFWvidmode mode;
|
||||||
|
DEVMODEW dm;
|
||||||
|
|
||||||
|
ZeroMemory(&dm, sizeof(DEVMODEW));
|
||||||
|
dm.dmSize = sizeof(DEVMODEW);
|
||||||
|
|
||||||
|
if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
|
||||||
|
break;
|
||||||
|
|
||||||
|
modeIndex++;
|
||||||
|
|
||||||
|
// Skip modes with less than 15 BPP
|
||||||
|
if (dm.dmBitsPerPel < 15)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mode.width = dm.dmPelsWidth;
|
||||||
|
mode.height = dm.dmPelsHeight;
|
||||||
|
mode.refreshRate = dm.dmDisplayFrequency;
|
||||||
|
_glfwSplitBPP(dm.dmBitsPerPel,
|
||||||
|
&mode.redBits,
|
||||||
|
&mode.greenBits,
|
||||||
|
&mode.blueBits);
|
||||||
|
|
||||||
|
for (i = 0; i < *count; i++)
|
||||||
|
{
|
||||||
|
if (_glfwCompareVideoModes(result + i, &mode) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip duplicate modes
|
||||||
|
if (i < *count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (monitor->win32.modesPruned)
|
||||||
|
{
|
||||||
|
// Skip modes not supported by the connected displays
|
||||||
|
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||||
|
&dm,
|
||||||
|
NULL,
|
||||||
|
CDS_TEST,
|
||||||
|
NULL) != DISP_CHANGE_SUCCESSFUL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*count == size)
|
||||||
|
{
|
||||||
|
size += 128;
|
||||||
|
result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
|
||||||
|
}
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
result[*count - 1] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*count)
|
||||||
|
{
|
||||||
|
// HACK: Report the current mode if no valid modes were found
|
||||||
|
result = calloc(1, sizeof(GLFWvidmode));
|
||||||
|
_glfwPlatformGetVideoMode(monitor, result);
|
||||||
|
*count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||||
|
{
|
||||||
|
DEVMODEW dm;
|
||||||
|
|
||||||
|
ZeroMemory(&dm, sizeof(DEVMODEW));
|
||||||
|
dm.dmSize = sizeof(DEVMODEW);
|
||||||
|
|
||||||
|
EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
|
||||||
|
|
||||||
|
mode->width = dm.dmPelsWidth;
|
||||||
|
mode->height = dm.dmPelsHeight;
|
||||||
|
mode->refreshRate = dm.dmDisplayFrequency;
|
||||||
|
_glfwSplitBPP(dm.dmBitsPerPel,
|
||||||
|
&mode->redBits,
|
||||||
|
&mode->greenBits,
|
||||||
|
&mode->blueBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
HDC dc;
|
||||||
|
WORD values[768];
|
||||||
|
|
||||||
|
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
|
||||||
|
GetDeviceGammaRamp(dc, values);
|
||||||
|
DeleteDC(dc);
|
||||||
|
|
||||||
|
_glfwAllocGammaArrays(ramp, 256);
|
||||||
|
|
||||||
|
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
|
||||||
|
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
|
||||||
|
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
HDC dc;
|
||||||
|
WORD values[768];
|
||||||
|
|
||||||
|
if (ramp->size != 256)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Gamma ramp size must be 256");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short));
|
||||||
|
memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short));
|
||||||
|
memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short));
|
||||||
|
|
||||||
|
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
|
||||||
|
SetDeviceGammaRamp(dc, values);
|
||||||
|
DeleteDC(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return monitor->win32.publicAdapterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return monitor->win32.publicDisplayName;
|
||||||
|
}
|
||||||
|
|
350
external/glfw/win32_platform.h
vendored
Normal file
350
external/glfw/win32_platform.h
vendored
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_win32_platform_h_
|
||||||
|
#define _glfw3_win32_platform_h_
|
||||||
|
|
||||||
|
// We don't need all the fancy stuff
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VC_EXTRALEAN
|
||||||
|
#define VC_EXTRALEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||||
|
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||||
|
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||||
|
#undef APIENTRY
|
||||||
|
|
||||||
|
// GLFW on Windows is Unicode only and does not work in MBCS mode
|
||||||
|
#ifndef UNICODE
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GLFW requires Windows XP or later
|
||||||
|
#if WINVER < 0x0501
|
||||||
|
#undef WINVER
|
||||||
|
#define WINVER 0x0501
|
||||||
|
#endif
|
||||||
|
#if _WIN32_WINNT < 0x0501
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GLFW uses DirectInput8 interfaces
|
||||||
|
#define DIRECTINPUT_VERSION 0x0800
|
||||||
|
|
||||||
|
#include <wctype.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <dinput.h>
|
||||||
|
#include <xinput.h>
|
||||||
|
#include <dbt.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <malloc.h>
|
||||||
|
#define strdup _strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// HACK: Define macros that some windows.h variants don't
|
||||||
|
#ifndef WM_MOUSEHWHEEL
|
||||||
|
#define WM_MOUSEHWHEEL 0x020E
|
||||||
|
#endif
|
||||||
|
#ifndef WM_DWMCOMPOSITIONCHANGED
|
||||||
|
#define WM_DWMCOMPOSITIONCHANGED 0x031E
|
||||||
|
#endif
|
||||||
|
#ifndef WM_COPYGLOBALDATA
|
||||||
|
#define WM_COPYGLOBALDATA 0x0049
|
||||||
|
#endif
|
||||||
|
#ifndef WM_UNICHAR
|
||||||
|
#define WM_UNICHAR 0x0109
|
||||||
|
#endif
|
||||||
|
#ifndef UNICODE_NOCHAR
|
||||||
|
#define UNICODE_NOCHAR 0xFFFF
|
||||||
|
#endif
|
||||||
|
#ifndef WM_DPICHANGED
|
||||||
|
#define WM_DPICHANGED 0x02E0
|
||||||
|
#endif
|
||||||
|
#ifndef GET_XBUTTON_WPARAM
|
||||||
|
#define GET_XBUTTON_WPARAM(w) (HIWORD(w))
|
||||||
|
#endif
|
||||||
|
#ifndef EDS_ROTATEDMODE
|
||||||
|
#define EDS_ROTATEDMODE 0x00000004
|
||||||
|
#endif
|
||||||
|
#ifndef DISPLAY_DEVICE_ACTIVE
|
||||||
|
#define DISPLAY_DEVICE_ACTIVE 0x00000001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WINVER < 0x0601
|
||||||
|
typedef struct tagCHANGEFILTERSTRUCT
|
||||||
|
{
|
||||||
|
DWORD cbSize;
|
||||||
|
DWORD ExtStatus;
|
||||||
|
|
||||||
|
} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
|
||||||
|
#ifndef MSGFLT_ALLOW
|
||||||
|
#define MSGFLT_ALLOW 1
|
||||||
|
#endif
|
||||||
|
#endif /*Windows 7*/
|
||||||
|
|
||||||
|
#ifndef DPI_ENUMS_DECLARED
|
||||||
|
typedef enum PROCESS_DPI_AWARENESS
|
||||||
|
{
|
||||||
|
PROCESS_DPI_UNAWARE = 0,
|
||||||
|
PROCESS_SYSTEM_DPI_AWARE = 1,
|
||||||
|
PROCESS_PER_MONITOR_DPI_AWARE = 2
|
||||||
|
} PROCESS_DPI_AWARENESS;
|
||||||
|
#endif /*DPI_ENUMS_DECLARED*/
|
||||||
|
|
||||||
|
// HACK: Define macros that some xinput.h variants don't
|
||||||
|
#ifndef XINPUT_CAPS_WIRELESS
|
||||||
|
#define XINPUT_CAPS_WIRELESS 0x0002
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_WHEEL
|
||||||
|
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK
|
||||||
|
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
|
||||||
|
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD
|
||||||
|
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_GUITAR
|
||||||
|
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT
|
||||||
|
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
|
||||||
|
#endif
|
||||||
|
#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD
|
||||||
|
#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
|
||||||
|
#endif
|
||||||
|
#ifndef XUSER_MAX_COUNT
|
||||||
|
#define XUSER_MAX_COUNT 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// HACK: Define macros that some dinput.h variants don't
|
||||||
|
#ifndef DIDFT_OPTIONAL
|
||||||
|
#define DIDFT_OPTIONAL 0x80000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// winmm.dll function pointer typedefs
|
||||||
|
typedef DWORD (WINAPI * TIMEGETTIME_T)(void);
|
||||||
|
#define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime
|
||||||
|
|
||||||
|
// xinput.dll function pointer typedefs
|
||||||
|
typedef DWORD (WINAPI * XINPUTGETCAPABILITIES_T)(DWORD,DWORD,XINPUT_CAPABILITIES*);
|
||||||
|
typedef DWORD (WINAPI * XINPUTGETSTATE_T)(DWORD,XINPUT_STATE*);
|
||||||
|
#define _glfw_XInputGetCapabilities _glfw.win32.xinput.XInputGetCapabilities
|
||||||
|
#define _glfw_XInputGetState _glfw.win32.xinput.XInputGetState
|
||||||
|
|
||||||
|
// dinput8.dll function pointer typedefs
|
||||||
|
typedef HRESULT (WINAPI * DIRECTINPUT8CREATE_T)(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN);
|
||||||
|
#define _glfw_DirectInput8Create _glfw.win32.dinput8.DirectInput8Create
|
||||||
|
|
||||||
|
// user32.dll function pointer typedefs
|
||||||
|
typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void);
|
||||||
|
typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT);
|
||||||
|
#define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware
|
||||||
|
#define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx
|
||||||
|
|
||||||
|
// dwmapi.dll function pointer typedefs
|
||||||
|
typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
|
||||||
|
typedef HRESULT (WINAPI * DWMFLUSH_T)(VOID);
|
||||||
|
#define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled
|
||||||
|
#define _glfw_DwmFlush _glfw.win32.dwmapi.DwmFlush
|
||||||
|
|
||||||
|
// shcore.dll function pointer typedefs
|
||||||
|
typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
|
||||||
|
#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness
|
||||||
|
|
||||||
|
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
|
||||||
|
|
||||||
|
typedef struct VkWin32SurfaceCreateInfoKHR
|
||||||
|
{
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkWin32SurfaceCreateFlagsKHR flags;
|
||||||
|
HINSTANCE hinstance;
|
||||||
|
HWND hwnd;
|
||||||
|
} VkWin32SurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||||
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
|
||||||
|
|
||||||
|
#include "win32_joystick.h"
|
||||||
|
#include "wgl_context.h"
|
||||||
|
#include "egl_context.h"
|
||||||
|
|
||||||
|
#define _GLFW_WNDCLASSNAME L"GLFW30"
|
||||||
|
|
||||||
|
#define _glfw_dlopen(name) LoadLibraryA(name)
|
||||||
|
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
|
||||||
|
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
|
||||||
|
|
||||||
|
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->win32.handle)
|
||||||
|
#define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
|
||||||
|
|
||||||
|
|
||||||
|
// Win32-specific per-window data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWwindowWin32
|
||||||
|
{
|
||||||
|
HWND handle;
|
||||||
|
HICON bigIcon;
|
||||||
|
HICON smallIcon;
|
||||||
|
|
||||||
|
GLFWbool cursorTracked;
|
||||||
|
GLFWbool iconified;
|
||||||
|
|
||||||
|
// The last received cursor position, regardless of source
|
||||||
|
int lastCursorPosX, lastCursorPosY;
|
||||||
|
|
||||||
|
} _GLFWwindowWin32;
|
||||||
|
|
||||||
|
// Win32-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryWin32
|
||||||
|
{
|
||||||
|
HWND helperWindowHandle;
|
||||||
|
DWORD foregroundLockTimeout;
|
||||||
|
char* clipboardString;
|
||||||
|
char keyName[64];
|
||||||
|
short int publicKeys[512];
|
||||||
|
short int nativeKeys[GLFW_KEY_LAST + 1];
|
||||||
|
// Where to place the cursor when re-enabled
|
||||||
|
double restoreCursorPosX, restoreCursorPosY;
|
||||||
|
// The window whose disabled cursor mode is active
|
||||||
|
_GLFWwindow* disabledCursorWindow;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
TIMEGETTIME_T timeGetTime;
|
||||||
|
} winmm;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
DIRECTINPUT8CREATE_T DirectInput8Create;
|
||||||
|
IDirectInput8W* api;
|
||||||
|
} dinput8;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
XINPUTGETCAPABILITIES_T XInputGetCapabilities;
|
||||||
|
XINPUTGETSTATE_T XInputGetState;
|
||||||
|
} xinput;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
SETPROCESSDPIAWARE_T SetProcessDPIAware;
|
||||||
|
CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx;
|
||||||
|
} user32;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled;
|
||||||
|
DWMFLUSH_T DwmFlush;
|
||||||
|
} dwmapi;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
HINSTANCE instance;
|
||||||
|
SETPROCESSDPIAWARENESS_T SetProcessDpiAwareness;
|
||||||
|
} shcore;
|
||||||
|
|
||||||
|
} _GLFWlibraryWin32;
|
||||||
|
|
||||||
|
// Win32-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorWin32
|
||||||
|
{
|
||||||
|
// This size matches the static size of DISPLAY_DEVICE.DeviceName
|
||||||
|
WCHAR adapterName[32];
|
||||||
|
WCHAR displayName[32];
|
||||||
|
char publicAdapterName[64];
|
||||||
|
char publicDisplayName[64];
|
||||||
|
GLFWbool modesPruned;
|
||||||
|
GLFWbool modeChanged;
|
||||||
|
|
||||||
|
} _GLFWmonitorWin32;
|
||||||
|
|
||||||
|
// Win32-specific per-cursor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcursorWin32
|
||||||
|
{
|
||||||
|
HCURSOR handle;
|
||||||
|
|
||||||
|
} _GLFWcursorWin32;
|
||||||
|
|
||||||
|
// Win32-specific global timer data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWtimeWin32
|
||||||
|
{
|
||||||
|
GLFWbool hasPC;
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
|
} _GLFWtimeWin32;
|
||||||
|
|
||||||
|
// Win32-specific global TLS data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWtlsWin32
|
||||||
|
{
|
||||||
|
GLFWbool allocated;
|
||||||
|
DWORD context;
|
||||||
|
|
||||||
|
} _GLFWtlsWin32;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwRegisterWindowClassWin32(void);
|
||||||
|
void _glfwUnregisterWindowClassWin32(void);
|
||||||
|
|
||||||
|
GLFWbool _glfwInitThreadLocalStorageWin32(void);
|
||||||
|
void _glfwTerminateThreadLocalStorageWin32(void);
|
||||||
|
|
||||||
|
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
|
||||||
|
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
|
||||||
|
|
||||||
|
void _glfwInitTimerWin32(void);
|
||||||
|
|
||||||
|
GLFWbool _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
|
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
#endif // _glfw3_win32_platform_h_
|
74
external/glfw/win32_time.c
vendored
Normal file
74
external/glfw/win32_time.c
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Initialise timer
|
||||||
|
//
|
||||||
|
void _glfwInitTimerWin32(void)
|
||||||
|
{
|
||||||
|
uint64_t frequency;
|
||||||
|
|
||||||
|
if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency))
|
||||||
|
{
|
||||||
|
_glfw.win32_time.hasPC = GLFW_TRUE;
|
||||||
|
_glfw.win32_time.frequency = frequency;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfw.win32_time.hasPC = GLFW_FALSE;
|
||||||
|
_glfw.win32_time.frequency = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerValue(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32_time.hasPC)
|
||||||
|
{
|
||||||
|
uint64_t value;
|
||||||
|
QueryPerformanceCounter((LARGE_INTEGER*) &value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return (uint64_t) _glfw_timeGetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||||
|
{
|
||||||
|
return _glfw.win32_time.frequency;
|
||||||
|
}
|
||||||
|
|
69
external/glfw/win32_tls.c
vendored
Normal file
69
external/glfw/win32_tls.c
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Win32 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWbool _glfwInitThreadLocalStorageWin32(void)
|
||||||
|
{
|
||||||
|
_glfw.win32_tls.context = TlsAlloc();
|
||||||
|
if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Win32: Failed to allocate TLS index");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.win32_tls.allocated = GLFW_TRUE;
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwTerminateThreadLocalStorageWin32(void)
|
||||||
|
{
|
||||||
|
if (_glfw.win32_tls.allocated)
|
||||||
|
TlsFree(_glfw.win32_tls.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwPlatformSetCurrentContext(_GLFWwindow* context)
|
||||||
|
{
|
||||||
|
TlsSetValue(_glfw.win32_tls.context, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
_GLFWwindow* _glfwPlatformGetCurrentContext(void)
|
||||||
|
{
|
||||||
|
return TlsGetValue(_glfw.win32_tls.context);
|
||||||
|
}
|
||||||
|
|
1724
external/glfw/win32_window.c
vendored
Normal file
1724
external/glfw/win32_window.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
908
external/glfw/window.c
vendored
Normal file
908
external/glfw/window.c
vendored
Normal file
@ -0,0 +1,908 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW event API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
|
||||||
|
{
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
if (window->callbacks.focus)
|
||||||
|
window->callbacks.focus((GLFWwindow*) window, focused);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (window->callbacks.focus)
|
||||||
|
window->callbacks.focus((GLFWwindow*) window, focused);
|
||||||
|
|
||||||
|
// Release all pressed keyboard keys
|
||||||
|
for (i = 0; i <= GLFW_KEY_LAST; i++)
|
||||||
|
{
|
||||||
|
if (window->keys[i] == GLFW_PRESS)
|
||||||
|
_glfwInputKey(window, i, 0, GLFW_RELEASE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release all pressed mouse buttons
|
||||||
|
for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
|
||||||
|
{
|
||||||
|
if (window->mouseButtons[i] == GLFW_PRESS)
|
||||||
|
_glfwInputMouseClick(window, i, GLFW_RELEASE, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowPos(_GLFWwindow* window, int x, int y)
|
||||||
|
{
|
||||||
|
if (window->callbacks.pos)
|
||||||
|
window->callbacks.pos((GLFWwindow*) window, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
if (window->callbacks.size)
|
||||||
|
window->callbacks.size((GLFWwindow*) window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
|
||||||
|
{
|
||||||
|
if (window->callbacks.iconify)
|
||||||
|
window->callbacks.iconify((GLFWwindow*) window, iconified);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
if (window->callbacks.fbsize)
|
||||||
|
window->callbacks.fbsize((GLFWwindow*) window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowDamage(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (window->callbacks.refresh)
|
||||||
|
window->callbacks.refresh((GLFWwindow*) window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowCloseRequest(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
window->closed = GLFW_TRUE;
|
||||||
|
|
||||||
|
if (window->callbacks.close)
|
||||||
|
window->callbacks.close((GLFWwindow*) window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
window->monitor = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW public API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||||
|
const char* title,
|
||||||
|
GLFWmonitor* monitor,
|
||||||
|
GLFWwindow* share)
|
||||||
|
{
|
||||||
|
_GLFWfbconfig fbconfig;
|
||||||
|
_GLFWctxconfig ctxconfig;
|
||||||
|
_GLFWwndconfig wndconfig;
|
||||||
|
_GLFWwindow* window;
|
||||||
|
_GLFWwindow* previous;
|
||||||
|
|
||||||
|
assert(title != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid window size %ix%i",
|
||||||
|
width, height);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fbconfig = _glfw.hints.framebuffer;
|
||||||
|
ctxconfig = _glfw.hints.context;
|
||||||
|
wndconfig = _glfw.hints.window;
|
||||||
|
|
||||||
|
wndconfig.width = width;
|
||||||
|
wndconfig.height = height;
|
||||||
|
wndconfig.title = title;
|
||||||
|
ctxconfig.share = (_GLFWwindow*) share;
|
||||||
|
|
||||||
|
if (ctxconfig.share)
|
||||||
|
{
|
||||||
|
if (ctxconfig.client == GLFW_NO_API ||
|
||||||
|
ctxconfig.share->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfwIsValidContextConfig(&ctxconfig))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
window = calloc(1, sizeof(_GLFWwindow));
|
||||||
|
window->next = _glfw.windowListHead;
|
||||||
|
_glfw.windowListHead = window;
|
||||||
|
|
||||||
|
window->videoMode.width = width;
|
||||||
|
window->videoMode.height = height;
|
||||||
|
window->videoMode.redBits = fbconfig.redBits;
|
||||||
|
window->videoMode.greenBits = fbconfig.greenBits;
|
||||||
|
window->videoMode.blueBits = fbconfig.blueBits;
|
||||||
|
window->videoMode.refreshRate = _glfw.hints.refreshRate;
|
||||||
|
|
||||||
|
window->monitor = (_GLFWmonitor*) monitor;
|
||||||
|
window->resizable = wndconfig.resizable;
|
||||||
|
window->decorated = wndconfig.decorated;
|
||||||
|
window->autoIconify = wndconfig.autoIconify;
|
||||||
|
window->floating = wndconfig.floating;
|
||||||
|
window->cursorMode = GLFW_CURSOR_NORMAL;
|
||||||
|
|
||||||
|
window->minwidth = GLFW_DONT_CARE;
|
||||||
|
window->minheight = GLFW_DONT_CARE;
|
||||||
|
window->maxwidth = GLFW_DONT_CARE;
|
||||||
|
window->maxheight = GLFW_DONT_CARE;
|
||||||
|
window->numer = GLFW_DONT_CARE;
|
||||||
|
window->denom = GLFW_DONT_CARE;
|
||||||
|
|
||||||
|
// Save the currently current context so it can be restored later
|
||||||
|
previous = _glfwPlatformGetCurrentContext();
|
||||||
|
if (ctxconfig.client != GLFW_NO_API)
|
||||||
|
glfwMakeContextCurrent(NULL);
|
||||||
|
|
||||||
|
// Open the actual window and create its context
|
||||||
|
if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig))
|
||||||
|
{
|
||||||
|
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||||
|
glfwDestroyWindow((GLFWwindow*) window);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig.client != GLFW_NO_API)
|
||||||
|
{
|
||||||
|
window->context.makeCurrent(window);
|
||||||
|
|
||||||
|
// Retrieve the actual (as opposed to requested) context attributes
|
||||||
|
if (!_glfwRefreshContextAttribs(&ctxconfig))
|
||||||
|
{
|
||||||
|
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||||
|
glfwDestroyWindow((GLFWwindow*) window);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the previously current context (or NULL)
|
||||||
|
glfwMakeContextCurrent((GLFWwindow*) previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window->monitor)
|
||||||
|
{
|
||||||
|
if (wndconfig.visible)
|
||||||
|
{
|
||||||
|
_glfwPlatformShowWindow(window);
|
||||||
|
if (wndconfig.focused)
|
||||||
|
_glfwPlatformFocusWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GLFWwindow*) window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glfwDefaultWindowHints(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
memset(&_glfw.hints, 0, sizeof(_glfw.hints));
|
||||||
|
|
||||||
|
// The default is OpenGL with minimum version 1.0
|
||||||
|
_glfw.hints.context.client = GLFW_OPENGL_API;
|
||||||
|
_glfw.hints.context.source = GLFW_NATIVE_CONTEXT_API;
|
||||||
|
_glfw.hints.context.major = 1;
|
||||||
|
_glfw.hints.context.minor = 0;
|
||||||
|
|
||||||
|
// The default is a focused, visible, resizable window with decorations
|
||||||
|
_glfw.hints.window.resizable = GLFW_TRUE;
|
||||||
|
_glfw.hints.window.visible = GLFW_TRUE;
|
||||||
|
_glfw.hints.window.decorated = GLFW_TRUE;
|
||||||
|
_glfw.hints.window.focused = GLFW_TRUE;
|
||||||
|
_glfw.hints.window.autoIconify = GLFW_TRUE;
|
||||||
|
|
||||||
|
// The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
|
||||||
|
// double buffered
|
||||||
|
_glfw.hints.framebuffer.redBits = 8;
|
||||||
|
_glfw.hints.framebuffer.greenBits = 8;
|
||||||
|
_glfw.hints.framebuffer.blueBits = 8;
|
||||||
|
_glfw.hints.framebuffer.alphaBits = 8;
|
||||||
|
_glfw.hints.framebuffer.depthBits = 24;
|
||||||
|
_glfw.hints.framebuffer.stencilBits = 8;
|
||||||
|
_glfw.hints.framebuffer.doublebuffer = GLFW_TRUE;
|
||||||
|
|
||||||
|
// The default is to select the highest available refresh rate
|
||||||
|
_glfw.hints.refreshRate = GLFW_DONT_CARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwWindowHint(int hint, int value)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
switch (hint)
|
||||||
|
{
|
||||||
|
case GLFW_RED_BITS:
|
||||||
|
_glfw.hints.framebuffer.redBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_GREEN_BITS:
|
||||||
|
_glfw.hints.framebuffer.greenBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_BLUE_BITS:
|
||||||
|
_glfw.hints.framebuffer.blueBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_ALPHA_BITS:
|
||||||
|
_glfw.hints.framebuffer.alphaBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_DEPTH_BITS:
|
||||||
|
_glfw.hints.framebuffer.depthBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_STENCIL_BITS:
|
||||||
|
_glfw.hints.framebuffer.stencilBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_ACCUM_RED_BITS:
|
||||||
|
_glfw.hints.framebuffer.accumRedBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_ACCUM_GREEN_BITS:
|
||||||
|
_glfw.hints.framebuffer.accumGreenBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_ACCUM_BLUE_BITS:
|
||||||
|
_glfw.hints.framebuffer.accumBlueBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_ACCUM_ALPHA_BITS:
|
||||||
|
_glfw.hints.framebuffer.accumAlphaBits = value;
|
||||||
|
break;
|
||||||
|
case GLFW_AUX_BUFFERS:
|
||||||
|
_glfw.hints.framebuffer.auxBuffers = value;
|
||||||
|
break;
|
||||||
|
case GLFW_STEREO:
|
||||||
|
_glfw.hints.framebuffer.stereo = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_DOUBLEBUFFER:
|
||||||
|
_glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_SAMPLES:
|
||||||
|
_glfw.hints.framebuffer.samples = value;
|
||||||
|
break;
|
||||||
|
case GLFW_SRGB_CAPABLE:
|
||||||
|
_glfw.hints.framebuffer.sRGB = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_RESIZABLE:
|
||||||
|
_glfw.hints.window.resizable = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_DECORATED:
|
||||||
|
_glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_FOCUSED:
|
||||||
|
_glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_AUTO_ICONIFY:
|
||||||
|
_glfw.hints.window.autoIconify = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_FLOATING:
|
||||||
|
_glfw.hints.window.floating = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_MAXIMIZED:
|
||||||
|
_glfw.hints.window.maximized = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_VISIBLE:
|
||||||
|
_glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_CLIENT_API:
|
||||||
|
_glfw.hints.context.client = value;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_CREATION_API:
|
||||||
|
_glfw.hints.context.source = value;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_VERSION_MAJOR:
|
||||||
|
_glfw.hints.context.major = value;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_VERSION_MINOR:
|
||||||
|
_glfw.hints.context.minor = value;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_ROBUSTNESS:
|
||||||
|
_glfw.hints.context.robustness = value;
|
||||||
|
break;
|
||||||
|
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||||
|
_glfw.hints.context.forward = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_OPENGL_DEBUG_CONTEXT:
|
||||||
|
_glfw.hints.context.debug = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_NO_ERROR:
|
||||||
|
_glfw.hints.context.noerror = value ? GLFW_TRUE : GLFW_FALSE;
|
||||||
|
break;
|
||||||
|
case GLFW_OPENGL_PROFILE:
|
||||||
|
_glfw.hints.context.profile = value;
|
||||||
|
break;
|
||||||
|
case GLFW_CONTEXT_RELEASE_BEHAVIOR:
|
||||||
|
_glfw.hints.context.release = value;
|
||||||
|
break;
|
||||||
|
case GLFW_REFRESH_RATE:
|
||||||
|
_glfw.hints.refreshRate = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint %i", hint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
// Allow closing of NULL (to match the behavior of free)
|
||||||
|
if (window == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Clear all callbacks to avoid exposing a half torn-down window object
|
||||||
|
memset(&window->callbacks, 0, sizeof(window->callbacks));
|
||||||
|
|
||||||
|
// The window's context must not be current on another thread when the
|
||||||
|
// window is destroyed
|
||||||
|
if (window == _glfwPlatformGetCurrentContext())
|
||||||
|
glfwMakeContextCurrent(NULL);
|
||||||
|
|
||||||
|
_glfwPlatformDestroyWindow(window);
|
||||||
|
|
||||||
|
// Unlink window from global linked list
|
||||||
|
{
|
||||||
|
_GLFWwindow** prev = &_glfw.windowListHead;
|
||||||
|
|
||||||
|
while (*prev != window)
|
||||||
|
prev = &((*prev)->next);
|
||||||
|
|
||||||
|
*prev = window->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
return window->closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
window->closed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
assert(title != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformSetWindowTitle(window, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
|
||||||
|
int count, const GLFWimage* images)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
assert(count >= 0);
|
||||||
|
assert(count == 0 || images != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformSetWindowIcon(window, count, images);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = 0;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformGetWindowPos(window, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformSetWindowPos(window, xpos, ypos);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
if (width)
|
||||||
|
*width = 0;
|
||||||
|
if (height)
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformGetWindowSize(window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
window->videoMode.width = width;
|
||||||
|
window->videoMode.height = height;
|
||||||
|
|
||||||
|
_glfwPlatformSetWindowSize(window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle,
|
||||||
|
int minwidth, int minheight,
|
||||||
|
int maxwidth, int maxheight)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (minwidth != GLFW_DONT_CARE && minheight != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
if (minwidth < 0 || minheight < 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid window minimum size %ix%i",
|
||||||
|
minwidth, minheight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxwidth != GLFW_DONT_CARE && maxheight != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
if (maxwidth < 0 || maxheight < 0 ||
|
||||||
|
maxwidth < minwidth || maxheight < minheight)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid window maximum size %ix%i",
|
||||||
|
maxwidth, maxheight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->minwidth = minwidth;
|
||||||
|
window->minheight = minheight;
|
||||||
|
window->maxwidth = maxwidth;
|
||||||
|
window->maxheight = maxheight;
|
||||||
|
|
||||||
|
if (window->monitor || !window->resizable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformSetWindowSizeLimits(window,
|
||||||
|
minwidth, minheight,
|
||||||
|
maxwidth, maxheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (numer != GLFW_DONT_CARE && denom != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
if (numer <= 0 || denom <= 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid window aspect ratio %i:%i",
|
||||||
|
numer, denom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->numer = numer;
|
||||||
|
window->denom = denom;
|
||||||
|
|
||||||
|
if (window->monitor || !window->resizable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformSetWindowAspectRatio(window, numer, denom);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
if (width)
|
||||||
|
*width = 0;
|
||||||
|
if (height)
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformGetFramebufferSize(window, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle,
|
||||||
|
int* left, int* top,
|
||||||
|
int* right, int* bottom)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
if (left)
|
||||||
|
*left = 0;
|
||||||
|
if (top)
|
||||||
|
*top = 0;
|
||||||
|
if (right)
|
||||||
|
*right = 0;
|
||||||
|
if (bottom)
|
||||||
|
*bottom = 0;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformGetWindowFrameSize(window, left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwIconifyWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformIconifyWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwRestoreWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformRestoreWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformMaximizeWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwShowWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformShowWindow(window);
|
||||||
|
_glfwPlatformFocusWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwHideWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (window->monitor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformHideWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwFocusWindow(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
_glfwPlatformFocusWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
|
||||||
|
switch (attrib)
|
||||||
|
{
|
||||||
|
case GLFW_FOCUSED:
|
||||||
|
return _glfwPlatformWindowFocused(window);
|
||||||
|
case GLFW_ICONIFIED:
|
||||||
|
return _glfwPlatformWindowIconified(window);
|
||||||
|
case GLFW_VISIBLE:
|
||||||
|
return _glfwPlatformWindowVisible(window);
|
||||||
|
case GLFW_MAXIMIZED:
|
||||||
|
return _glfwPlatformWindowMaximized(window);
|
||||||
|
case GLFW_RESIZABLE:
|
||||||
|
return window->resizable;
|
||||||
|
case GLFW_DECORATED:
|
||||||
|
return window->decorated;
|
||||||
|
case GLFW_FLOATING:
|
||||||
|
return window->floating;
|
||||||
|
case GLFW_CLIENT_API:
|
||||||
|
return window->context.client;
|
||||||
|
case GLFW_CONTEXT_CREATION_API:
|
||||||
|
return window->context.source;
|
||||||
|
case GLFW_CONTEXT_VERSION_MAJOR:
|
||||||
|
return window->context.major;
|
||||||
|
case GLFW_CONTEXT_VERSION_MINOR:
|
||||||
|
return window->context.minor;
|
||||||
|
case GLFW_CONTEXT_REVISION:
|
||||||
|
return window->context.revision;
|
||||||
|
case GLFW_CONTEXT_ROBUSTNESS:
|
||||||
|
return window->context.robustness;
|
||||||
|
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||||
|
return window->context.forward;
|
||||||
|
case GLFW_OPENGL_DEBUG_CONTEXT:
|
||||||
|
return window->context.debug;
|
||||||
|
case GLFW_OPENGL_PROFILE:
|
||||||
|
return window->context.profile;
|
||||||
|
case GLFW_CONTEXT_RELEASE_BEHAVIOR:
|
||||||
|
return window->context.release;
|
||||||
|
case GLFW_CONTEXT_NO_ERROR:
|
||||||
|
return window->context.noerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window attribute %i", attrib);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return (GLFWmonitor*) window->monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh,
|
||||||
|
GLFWmonitor* mh,
|
||||||
|
int xpos, int ypos,
|
||||||
|
int width, int height,
|
||||||
|
int refreshRate)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) wh;
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) mh;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid window size %ix%i",
|
||||||
|
width, height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refreshRate < 0 && refreshRate != GLFW_DONT_CARE)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE,
|
||||||
|
"Invalid refresh rate %i",
|
||||||
|
refreshRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->videoMode.width = width;
|
||||||
|
window->videoMode.height = height;
|
||||||
|
window->videoMode.refreshRate = refreshRate;
|
||||||
|
|
||||||
|
_glfwPlatformSetWindowMonitor(window, monitor,
|
||||||
|
xpos, ypos, width, height,
|
||||||
|
refreshRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
window->userPointer = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return window->userPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowposfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowsizefun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.size, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowclosefun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.close, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowrefreshfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowfocusfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle,
|
||||||
|
GLFWwindowiconifyfun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle,
|
||||||
|
GLFWframebuffersizefun cbfun)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
_GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun);
|
||||||
|
return cbfun;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwPollEvents(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
_glfwPlatformPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwWaitEvents(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (!_glfw.windowListHead)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformWaitEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwWaitEventsTimeout(double timeout)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (timeout != timeout || timeout < 0.0 || timeout > DBL_MAX)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", timeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformWaitEventsTimeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwPostEmptyEvent(void)
|
||||||
|
{
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (!_glfw.windowListHead)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfwPlatformPostEmptyEvent();
|
||||||
|
}
|
||||||
|
|
658
external/glfw/wl_init.c
vendored
Normal file
658
external/glfw/wl_init.c
vendored
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Wayland - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <wayland-cursor.h>
|
||||||
|
|
||||||
|
|
||||||
|
static inline int min(int n1, int n2)
|
||||||
|
{
|
||||||
|
return n1 < n2 ? n1 : n2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHandleEnter(void* data,
|
||||||
|
struct wl_pointer* pointer,
|
||||||
|
uint32_t serial,
|
||||||
|
struct wl_surface* surface,
|
||||||
|
wl_fixed_t sx,
|
||||||
|
wl_fixed_t sy)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||||
|
|
||||||
|
_glfw.wl.pointerSerial = serial;
|
||||||
|
_glfw.wl.pointerFocus = window;
|
||||||
|
|
||||||
|
_glfwPlatformSetCursor(window, window->wl.currentCursor);
|
||||||
|
_glfwInputCursorEnter(window, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHandleLeave(void* data,
|
||||||
|
struct wl_pointer* pointer,
|
||||||
|
uint32_t serial,
|
||||||
|
struct wl_surface* surface)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfw.wl.pointerSerial = serial;
|
||||||
|
_glfw.wl.pointerFocus = NULL;
|
||||||
|
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHandleMotion(void* data,
|
||||||
|
struct wl_pointer* pointer,
|
||||||
|
uint32_t time,
|
||||||
|
wl_fixed_t sx,
|
||||||
|
wl_fixed_t sy)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
||||||
|
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputCursorPos(window,
|
||||||
|
wl_fixed_to_double(sx),
|
||||||
|
wl_fixed_to_double(sy));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHandleButton(void* data,
|
||||||
|
struct wl_pointer* wl_pointer,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t time,
|
||||||
|
uint32_t button,
|
||||||
|
uint32_t state)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
int glfwButton;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
||||||
|
* codes. */
|
||||||
|
glfwButton = button - BTN_LEFT;
|
||||||
|
|
||||||
|
_glfwInputMouseClick(window,
|
||||||
|
glfwButton,
|
||||||
|
state == WL_POINTER_BUTTON_STATE_PRESSED
|
||||||
|
? GLFW_PRESS
|
||||||
|
: GLFW_RELEASE,
|
||||||
|
_glfw.wl.xkb.modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHandleAxis(void* data,
|
||||||
|
struct wl_pointer* wl_pointer,
|
||||||
|
uint32_t time,
|
||||||
|
uint32_t axis,
|
||||||
|
wl_fixed_t value)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||||
|
double scroll_factor;
|
||||||
|
double x, y;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Wayland scroll events are in pointer motion coordinate space (think
|
||||||
|
* two finger scroll). The factor 10 is commonly used to convert to
|
||||||
|
* "scroll step means 1.0. */
|
||||||
|
scroll_factor = 1.0/10.0;
|
||||||
|
|
||||||
|
switch (axis)
|
||||||
|
{
|
||||||
|
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||||
|
x = wl_fixed_to_double(value) * scroll_factor;
|
||||||
|
y = 0.0;
|
||||||
|
break;
|
||||||
|
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||||
|
x = 0.0;
|
||||||
|
y = wl_fixed_to_double(value) * scroll_factor;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwInputScroll(window, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_pointer_listener pointerListener = {
|
||||||
|
pointerHandleEnter,
|
||||||
|
pointerHandleLeave,
|
||||||
|
pointerHandleMotion,
|
||||||
|
pointerHandleButton,
|
||||||
|
pointerHandleAxis,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void keyboardHandleKeymap(void* data,
|
||||||
|
struct wl_keyboard* keyboard,
|
||||||
|
uint32_t format,
|
||||||
|
int fd,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
struct xkb_keymap* keymap;
|
||||||
|
struct xkb_state* state;
|
||||||
|
char* mapStr;
|
||||||
|
|
||||||
|
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
if (mapStr == MAP_FAILED) {
|
||||||
|
close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
keymap = xkb_map_new_from_string(_glfw.wl.xkb.context,
|
||||||
|
mapStr,
|
||||||
|
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||||
|
0);
|
||||||
|
munmap(mapStr, size);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (!keymap)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to compile keymap");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = xkb_state_new(keymap);
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to create XKB state");
|
||||||
|
xkb_map_unref(keymap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
xkb_keymap_unref(_glfw.wl.xkb.keymap);
|
||||||
|
xkb_state_unref(_glfw.wl.xkb.state);
|
||||||
|
_glfw.wl.xkb.keymap = keymap;
|
||||||
|
_glfw.wl.xkb.state = state;
|
||||||
|
|
||||||
|
_glfw.wl.xkb.control_mask =
|
||||||
|
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Control");
|
||||||
|
_glfw.wl.xkb.alt_mask =
|
||||||
|
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod1");
|
||||||
|
_glfw.wl.xkb.shift_mask =
|
||||||
|
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
|
||||||
|
_glfw.wl.xkb.super_mask =
|
||||||
|
1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboardHandleEnter(void* data,
|
||||||
|
struct wl_keyboard* keyboard,
|
||||||
|
uint32_t serial,
|
||||||
|
struct wl_surface* surface,
|
||||||
|
struct wl_array* keys)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||||
|
|
||||||
|
_glfw.wl.keyboardFocus = window;
|
||||||
|
_glfwInputWindowFocus(window, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboardHandleLeave(void* data,
|
||||||
|
struct wl_keyboard* keyboard,
|
||||||
|
uint32_t serial,
|
||||||
|
struct wl_surface* surface)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_glfw.wl.keyboardFocus = NULL;
|
||||||
|
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int toGLFWKeyCode(uint32_t key)
|
||||||
|
{
|
||||||
|
if (key < sizeof(_glfw.wl.publicKeys) / sizeof(_glfw.wl.publicKeys[0]))
|
||||||
|
return _glfw.wl.publicKeys[key];
|
||||||
|
|
||||||
|
return GLFW_KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboardHandleKey(void* data,
|
||||||
|
struct wl_keyboard* keyboard,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t time,
|
||||||
|
uint32_t key,
|
||||||
|
uint32_t state)
|
||||||
|
{
|
||||||
|
uint32_t code, num_syms;
|
||||||
|
long cp;
|
||||||
|
int keyCode;
|
||||||
|
int action;
|
||||||
|
const xkb_keysym_t *syms;
|
||||||
|
_GLFWwindow* window = _glfw.wl.keyboardFocus;
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
keyCode = toGLFWKeyCode(key);
|
||||||
|
action = state == WL_KEYBOARD_KEY_STATE_PRESSED
|
||||||
|
? GLFW_PRESS : GLFW_RELEASE;
|
||||||
|
|
||||||
|
_glfwInputKey(window, keyCode, key, action,
|
||||||
|
_glfw.wl.xkb.modifiers);
|
||||||
|
|
||||||
|
code = key + 8;
|
||||||
|
num_syms = xkb_key_get_syms(_glfw.wl.xkb.state, code, &syms);
|
||||||
|
|
||||||
|
if (num_syms == 1)
|
||||||
|
{
|
||||||
|
cp = _glfwKeySym2Unicode(syms[0]);
|
||||||
|
if (cp != -1)
|
||||||
|
{
|
||||||
|
const int mods = _glfw.wl.xkb.modifiers;
|
||||||
|
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||||
|
_glfwInputChar(window, cp, mods, plain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboardHandleModifiers(void* data,
|
||||||
|
struct wl_keyboard* keyboard,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t modsDepressed,
|
||||||
|
uint32_t modsLatched,
|
||||||
|
uint32_t modsLocked,
|
||||||
|
uint32_t group)
|
||||||
|
{
|
||||||
|
xkb_mod_mask_t mask;
|
||||||
|
unsigned int modifiers = 0;
|
||||||
|
|
||||||
|
if (!_glfw.wl.xkb.keymap)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xkb_state_update_mask(_glfw.wl.xkb.state,
|
||||||
|
modsDepressed,
|
||||||
|
modsLatched,
|
||||||
|
modsLocked,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
group);
|
||||||
|
|
||||||
|
mask = xkb_state_serialize_mods(_glfw.wl.xkb.state,
|
||||||
|
XKB_STATE_DEPRESSED |
|
||||||
|
XKB_STATE_LATCHED);
|
||||||
|
if (mask & _glfw.wl.xkb.control_mask)
|
||||||
|
modifiers |= GLFW_MOD_CONTROL;
|
||||||
|
if (mask & _glfw.wl.xkb.alt_mask)
|
||||||
|
modifiers |= GLFW_MOD_ALT;
|
||||||
|
if (mask & _glfw.wl.xkb.shift_mask)
|
||||||
|
modifiers |= GLFW_MOD_SHIFT;
|
||||||
|
if (mask & _glfw.wl.xkb.super_mask)
|
||||||
|
modifiers |= GLFW_MOD_SUPER;
|
||||||
|
_glfw.wl.xkb.modifiers = modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_keyboard_listener keyboardListener = {
|
||||||
|
keyboardHandleKeymap,
|
||||||
|
keyboardHandleEnter,
|
||||||
|
keyboardHandleLeave,
|
||||||
|
keyboardHandleKey,
|
||||||
|
keyboardHandleModifiers,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void seatHandleCapabilities(void* data,
|
||||||
|
struct wl_seat* seat,
|
||||||
|
enum wl_seat_capability caps)
|
||||||
|
{
|
||||||
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
|
||||||
|
{
|
||||||
|
_glfw.wl.pointer = wl_seat_get_pointer(seat);
|
||||||
|
wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
|
||||||
|
}
|
||||||
|
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
|
||||||
|
{
|
||||||
|
wl_pointer_destroy(_glfw.wl.pointer);
|
||||||
|
_glfw.wl.pointer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
|
||||||
|
{
|
||||||
|
_glfw.wl.keyboard = wl_seat_get_keyboard(seat);
|
||||||
|
wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
|
||||||
|
}
|
||||||
|
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
|
||||||
|
{
|
||||||
|
wl_keyboard_destroy(_glfw.wl.keyboard);
|
||||||
|
_glfw.wl.keyboard = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_seat_listener seatListener = {
|
||||||
|
seatHandleCapabilities
|
||||||
|
};
|
||||||
|
|
||||||
|
static void registryHandleGlobal(void* data,
|
||||||
|
struct wl_registry* registry,
|
||||||
|
uint32_t name,
|
||||||
|
const char* interface,
|
||||||
|
uint32_t version)
|
||||||
|
{
|
||||||
|
if (strcmp(interface, "wl_compositor") == 0)
|
||||||
|
{
|
||||||
|
_glfw.wl.wl_compositor_version = min(3, version);
|
||||||
|
_glfw.wl.compositor =
|
||||||
|
wl_registry_bind(registry, name, &wl_compositor_interface,
|
||||||
|
_glfw.wl.wl_compositor_version);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "wl_shm") == 0)
|
||||||
|
{
|
||||||
|
_glfw.wl.shm =
|
||||||
|
wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "wl_shell") == 0)
|
||||||
|
{
|
||||||
|
_glfw.wl.shell =
|
||||||
|
wl_registry_bind(registry, name, &wl_shell_interface, 1);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "wl_output") == 0)
|
||||||
|
{
|
||||||
|
_glfwAddOutputWayland(name, version);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "wl_seat") == 0)
|
||||||
|
{
|
||||||
|
if (!_glfw.wl.seat)
|
||||||
|
{
|
||||||
|
_glfw.wl.seat =
|
||||||
|
wl_registry_bind(registry, name, &wl_seat_interface, 1);
|
||||||
|
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
|
||||||
|
{
|
||||||
|
_glfw.wl.relativePointerManager =
|
||||||
|
wl_registry_bind(registry, name,
|
||||||
|
&zwp_relative_pointer_manager_v1_interface,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
|
||||||
|
{
|
||||||
|
_glfw.wl.pointerConstraints =
|
||||||
|
wl_registry_bind(registry, name,
|
||||||
|
&zwp_pointer_constraints_v1_interface,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registryHandleGlobalRemove(void *data,
|
||||||
|
struct wl_registry *registry,
|
||||||
|
uint32_t name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct wl_registry_listener registryListener = {
|
||||||
|
registryHandleGlobal,
|
||||||
|
registryHandleGlobalRemove
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create key code translation tables
|
||||||
|
//
|
||||||
|
static void createKeyTables(void)
|
||||||
|
{
|
||||||
|
memset(_glfw.wl.publicKeys, -1, sizeof(_glfw.wl.publicKeys));
|
||||||
|
|
||||||
|
_glfw.wl.publicKeys[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
_glfw.wl.publicKeys[KEY_1] = GLFW_KEY_1;
|
||||||
|
_glfw.wl.publicKeys[KEY_2] = GLFW_KEY_2;
|
||||||
|
_glfw.wl.publicKeys[KEY_3] = GLFW_KEY_3;
|
||||||
|
_glfw.wl.publicKeys[KEY_4] = GLFW_KEY_4;
|
||||||
|
_glfw.wl.publicKeys[KEY_5] = GLFW_KEY_5;
|
||||||
|
_glfw.wl.publicKeys[KEY_6] = GLFW_KEY_6;
|
||||||
|
_glfw.wl.publicKeys[KEY_7] = GLFW_KEY_7;
|
||||||
|
_glfw.wl.publicKeys[KEY_8] = GLFW_KEY_8;
|
||||||
|
_glfw.wl.publicKeys[KEY_9] = GLFW_KEY_9;
|
||||||
|
_glfw.wl.publicKeys[KEY_0] = GLFW_KEY_0;
|
||||||
|
_glfw.wl.publicKeys[KEY_MINUS] = GLFW_KEY_MINUS;
|
||||||
|
_glfw.wl.publicKeys[KEY_EQUAL] = GLFW_KEY_EQUAL;
|
||||||
|
_glfw.wl.publicKeys[KEY_Q] = GLFW_KEY_Q;
|
||||||
|
_glfw.wl.publicKeys[KEY_W] = GLFW_KEY_W;
|
||||||
|
_glfw.wl.publicKeys[KEY_E] = GLFW_KEY_E;
|
||||||
|
_glfw.wl.publicKeys[KEY_R] = GLFW_KEY_R;
|
||||||
|
_glfw.wl.publicKeys[KEY_T] = GLFW_KEY_T;
|
||||||
|
_glfw.wl.publicKeys[KEY_Y] = GLFW_KEY_Y;
|
||||||
|
_glfw.wl.publicKeys[KEY_U] = GLFW_KEY_U;
|
||||||
|
_glfw.wl.publicKeys[KEY_I] = GLFW_KEY_I;
|
||||||
|
_glfw.wl.publicKeys[KEY_O] = GLFW_KEY_O;
|
||||||
|
_glfw.wl.publicKeys[KEY_P] = GLFW_KEY_P;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
_glfw.wl.publicKeys[KEY_A] = GLFW_KEY_A;
|
||||||
|
_glfw.wl.publicKeys[KEY_S] = GLFW_KEY_S;
|
||||||
|
_glfw.wl.publicKeys[KEY_D] = GLFW_KEY_D;
|
||||||
|
_glfw.wl.publicKeys[KEY_F] = GLFW_KEY_F;
|
||||||
|
_glfw.wl.publicKeys[KEY_G] = GLFW_KEY_G;
|
||||||
|
_glfw.wl.publicKeys[KEY_H] = GLFW_KEY_H;
|
||||||
|
_glfw.wl.publicKeys[KEY_J] = GLFW_KEY_J;
|
||||||
|
_glfw.wl.publicKeys[KEY_K] = GLFW_KEY_K;
|
||||||
|
_glfw.wl.publicKeys[KEY_L] = GLFW_KEY_L;
|
||||||
|
_glfw.wl.publicKeys[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;
|
||||||
|
_glfw.wl.publicKeys[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
|
||||||
|
_glfw.wl.publicKeys[KEY_Z] = GLFW_KEY_Z;
|
||||||
|
_glfw.wl.publicKeys[KEY_X] = GLFW_KEY_X;
|
||||||
|
_glfw.wl.publicKeys[KEY_C] = GLFW_KEY_C;
|
||||||
|
_glfw.wl.publicKeys[KEY_V] = GLFW_KEY_V;
|
||||||
|
_glfw.wl.publicKeys[KEY_B] = GLFW_KEY_B;
|
||||||
|
_glfw.wl.publicKeys[KEY_N] = GLFW_KEY_N;
|
||||||
|
_glfw.wl.publicKeys[KEY_M] = GLFW_KEY_M;
|
||||||
|
_glfw.wl.publicKeys[KEY_COMMA] = GLFW_KEY_COMMA;
|
||||||
|
_glfw.wl.publicKeys[KEY_DOT] = GLFW_KEY_PERIOD;
|
||||||
|
_glfw.wl.publicKeys[KEY_SLASH] = GLFW_KEY_SLASH;
|
||||||
|
_glfw.wl.publicKeys[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;
|
||||||
|
_glfw.wl.publicKeys[KEY_ESC] = GLFW_KEY_ESCAPE;
|
||||||
|
_glfw.wl.publicKeys[KEY_TAB] = GLFW_KEY_TAB;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;
|
||||||
|
_glfw.wl.publicKeys[KEY_MENU] = GLFW_KEY_MENU;
|
||||||
|
_glfw.wl.publicKeys[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;
|
||||||
|
_glfw.wl.publicKeys[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;
|
||||||
|
_glfw.wl.publicKeys[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;
|
||||||
|
_glfw.wl.publicKeys[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
|
||||||
|
_glfw.wl.publicKeys[KEY_PAUSE] = GLFW_KEY_PAUSE;
|
||||||
|
_glfw.wl.publicKeys[KEY_DELETE] = GLFW_KEY_DELETE;
|
||||||
|
_glfw.wl.publicKeys[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;
|
||||||
|
_glfw.wl.publicKeys[KEY_ENTER] = GLFW_KEY_ENTER;
|
||||||
|
_glfw.wl.publicKeys[KEY_HOME] = GLFW_KEY_HOME;
|
||||||
|
_glfw.wl.publicKeys[KEY_END] = GLFW_KEY_END;
|
||||||
|
_glfw.wl.publicKeys[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;
|
||||||
|
_glfw.wl.publicKeys[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
_glfw.wl.publicKeys[KEY_INSERT] = GLFW_KEY_INSERT;
|
||||||
|
_glfw.wl.publicKeys[KEY_LEFT] = GLFW_KEY_LEFT;
|
||||||
|
_glfw.wl.publicKeys[KEY_RIGHT] = GLFW_KEY_RIGHT;
|
||||||
|
_glfw.wl.publicKeys[KEY_DOWN] = GLFW_KEY_DOWN;
|
||||||
|
_glfw.wl.publicKeys[KEY_UP] = GLFW_KEY_UP;
|
||||||
|
_glfw.wl.publicKeys[KEY_F1] = GLFW_KEY_F1;
|
||||||
|
_glfw.wl.publicKeys[KEY_F2] = GLFW_KEY_F2;
|
||||||
|
_glfw.wl.publicKeys[KEY_F3] = GLFW_KEY_F3;
|
||||||
|
_glfw.wl.publicKeys[KEY_F4] = GLFW_KEY_F4;
|
||||||
|
_glfw.wl.publicKeys[KEY_F5] = GLFW_KEY_F5;
|
||||||
|
_glfw.wl.publicKeys[KEY_F6] = GLFW_KEY_F6;
|
||||||
|
_glfw.wl.publicKeys[KEY_F7] = GLFW_KEY_F7;
|
||||||
|
_glfw.wl.publicKeys[KEY_F8] = GLFW_KEY_F8;
|
||||||
|
_glfw.wl.publicKeys[KEY_F9] = GLFW_KEY_F9;
|
||||||
|
_glfw.wl.publicKeys[KEY_F10] = GLFW_KEY_F10;
|
||||||
|
_glfw.wl.publicKeys[KEY_F11] = GLFW_KEY_F11;
|
||||||
|
_glfw.wl.publicKeys[KEY_F12] = GLFW_KEY_F12;
|
||||||
|
_glfw.wl.publicKeys[KEY_F13] = GLFW_KEY_F13;
|
||||||
|
_glfw.wl.publicKeys[KEY_F14] = GLFW_KEY_F14;
|
||||||
|
_glfw.wl.publicKeys[KEY_F15] = GLFW_KEY_F15;
|
||||||
|
_glfw.wl.publicKeys[KEY_F16] = GLFW_KEY_F16;
|
||||||
|
_glfw.wl.publicKeys[KEY_F17] = GLFW_KEY_F17;
|
||||||
|
_glfw.wl.publicKeys[KEY_F18] = GLFW_KEY_F18;
|
||||||
|
_glfw.wl.publicKeys[KEY_F19] = GLFW_KEY_F19;
|
||||||
|
_glfw.wl.publicKeys[KEY_F20] = GLFW_KEY_F20;
|
||||||
|
_glfw.wl.publicKeys[KEY_F21] = GLFW_KEY_F21;
|
||||||
|
_glfw.wl.publicKeys[KEY_F22] = GLFW_KEY_F22;
|
||||||
|
_glfw.wl.publicKeys[KEY_F23] = GLFW_KEY_F23;
|
||||||
|
_glfw.wl.publicKeys[KEY_F24] = GLFW_KEY_F24;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPPLUS] = GLFW_KEY_KP_ADD;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP0] = GLFW_KEY_KP_0;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP1] = GLFW_KEY_KP_1;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP2] = GLFW_KEY_KP_2;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP3] = GLFW_KEY_KP_3;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP4] = GLFW_KEY_KP_4;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP5] = GLFW_KEY_KP_5;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP6] = GLFW_KEY_KP_6;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP7] = GLFW_KEY_KP_7;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP8] = GLFW_KEY_KP_8;
|
||||||
|
_glfw.wl.publicKeys[KEY_KP9] = GLFW_KEY_KP_9;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;
|
||||||
|
_glfw.wl.publicKeys[KEY_KPENTER] = GLFW_KEY_KP_ENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformInit(void)
|
||||||
|
{
|
||||||
|
_glfw.wl.display = wl_display_connect(NULL);
|
||||||
|
if (!_glfw.wl.display)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to connect to display");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
|
||||||
|
wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL);
|
||||||
|
|
||||||
|
_glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*));
|
||||||
|
_glfw.wl.monitorsSize = 4;
|
||||||
|
|
||||||
|
createKeyTables();
|
||||||
|
|
||||||
|
_glfw.wl.xkb.context = xkb_context_new(0);
|
||||||
|
if (!_glfw.wl.xkb.context)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Failed to initialize xkb context");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync so we got all registry objects
|
||||||
|
wl_display_roundtrip(_glfw.wl.display);
|
||||||
|
|
||||||
|
// Sync so we got all initial output events
|
||||||
|
wl_display_roundtrip(_glfw.wl.display);
|
||||||
|
|
||||||
|
if (!_glfwInitThreadLocalStoragePOSIX())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (!_glfwInitJoysticksLinux())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfwInitTimerPOSIX();
|
||||||
|
|
||||||
|
if (_glfw.wl.pointer && _glfw.wl.shm)
|
||||||
|
{
|
||||||
|
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
|
||||||
|
if (!_glfw.wl.cursorTheme)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Unable to load default cursor theme\n");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
_glfw.wl.cursorSurface =
|
||||||
|
wl_compositor_create_surface(_glfw.wl.compositor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminate(void)
|
||||||
|
{
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
_glfwTerminateJoysticksLinux();
|
||||||
|
_glfwTerminateThreadLocalStoragePOSIX();
|
||||||
|
|
||||||
|
if (_glfw.wl.cursorTheme)
|
||||||
|
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
|
||||||
|
if (_glfw.wl.cursorSurface)
|
||||||
|
wl_surface_destroy(_glfw.wl.cursorSurface);
|
||||||
|
if (_glfw.wl.registry)
|
||||||
|
wl_registry_destroy(_glfw.wl.registry);
|
||||||
|
if (_glfw.wl.display)
|
||||||
|
wl_display_flush(_glfw.wl.display);
|
||||||
|
if (_glfw.wl.display)
|
||||||
|
wl_display_disconnect(_glfw.wl.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _GLFW_VERSION_NUMBER " Wayland EGL"
|
||||||
|
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
|
||||||
|
" clock_gettime"
|
||||||
|
#else
|
||||||
|
" gettimeofday"
|
||||||
|
#endif
|
||||||
|
#if defined(__linux__)
|
||||||
|
" /dev/js"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
" shared"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
269
external/glfw/wl_monitor.c
vendored
Normal file
269
external/glfw/wl_monitor.c
vendored
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Wayland - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct _GLFWvidmodeWayland
|
||||||
|
{
|
||||||
|
GLFWvidmode base;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void geometry(void* data,
|
||||||
|
struct wl_output* output,
|
||||||
|
int32_t x,
|
||||||
|
int32_t y,
|
||||||
|
int32_t physicalWidth,
|
||||||
|
int32_t physicalHeight,
|
||||||
|
int32_t subpixel,
|
||||||
|
const char* make,
|
||||||
|
const char* model,
|
||||||
|
int32_t transform)
|
||||||
|
{
|
||||||
|
struct _GLFWmonitor *monitor = data;
|
||||||
|
|
||||||
|
monitor->wl.x = x;
|
||||||
|
monitor->wl.y = y;
|
||||||
|
monitor->widthMM = physicalWidth;
|
||||||
|
monitor->heightMM = physicalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mode(void* data,
|
||||||
|
struct wl_output* output,
|
||||||
|
uint32_t flags,
|
||||||
|
int32_t width,
|
||||||
|
int32_t height,
|
||||||
|
int32_t refresh)
|
||||||
|
{
|
||||||
|
struct _GLFWmonitor *monitor = data;
|
||||||
|
_GLFWvidmodeWayland mode = { { 0 }, };
|
||||||
|
|
||||||
|
mode.base.width = width;
|
||||||
|
mode.base.height = height;
|
||||||
|
mode.base.refreshRate = refresh / 1000;
|
||||||
|
mode.flags = flags;
|
||||||
|
|
||||||
|
if (monitor->wl.modesCount + 1 >= monitor->wl.modesSize)
|
||||||
|
{
|
||||||
|
int size = monitor->wl.modesSize * 2;
|
||||||
|
_GLFWvidmodeWayland* modes =
|
||||||
|
realloc(monitor->wl.modes,
|
||||||
|
size * sizeof(_GLFWvidmodeWayland));
|
||||||
|
monitor->wl.modes = modes;
|
||||||
|
monitor->wl.modesSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor->wl.modes[monitor->wl.modesCount++] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void done(void* data,
|
||||||
|
struct wl_output* output)
|
||||||
|
{
|
||||||
|
struct _GLFWmonitor *monitor = data;
|
||||||
|
|
||||||
|
monitor->wl.done = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scale(void* data,
|
||||||
|
struct wl_output* output,
|
||||||
|
int32_t factor)
|
||||||
|
{
|
||||||
|
struct _GLFWmonitor *monitor = data;
|
||||||
|
|
||||||
|
monitor->wl.scale = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_output_listener output_listener = {
|
||||||
|
geometry,
|
||||||
|
mode,
|
||||||
|
done,
|
||||||
|
scale,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
|
||||||
|
{
|
||||||
|
_GLFWmonitor *monitor;
|
||||||
|
struct wl_output *output;
|
||||||
|
char name_str[80];
|
||||||
|
|
||||||
|
memset(name_str, 0, sizeof(name_str));
|
||||||
|
snprintf(name_str, 79, "wl_output@%u", name);
|
||||||
|
|
||||||
|
if (version < 2)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Unsupported output interface version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor = _glfwAllocMonitor(name_str, 0, 0);
|
||||||
|
|
||||||
|
output = wl_registry_bind(_glfw.wl.registry,
|
||||||
|
name,
|
||||||
|
&wl_output_interface,
|
||||||
|
2);
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
_glfwFreeMonitor(monitor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland));
|
||||||
|
monitor->wl.modesSize = 4;
|
||||||
|
|
||||||
|
monitor->wl.scale = 1;
|
||||||
|
|
||||||
|
monitor->wl.output = output;
|
||||||
|
wl_output_add_listener(output, &output_listener, monitor);
|
||||||
|
|
||||||
|
if (_glfw.wl.monitorsCount + 1 >= _glfw.wl.monitorsSize)
|
||||||
|
{
|
||||||
|
_GLFWmonitor** monitors = _glfw.wl.monitors;
|
||||||
|
int size = _glfw.wl.monitorsSize * 2;
|
||||||
|
|
||||||
|
monitors = realloc(monitors, size * sizeof(_GLFWmonitor*));
|
||||||
|
|
||||||
|
_glfw.wl.monitors = monitors;
|
||||||
|
_glfw.wl.monitorsSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.wl.monitors[_glfw.wl.monitorsCount++] = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
_GLFWmonitor** monitors;
|
||||||
|
_GLFWmonitor* monitor;
|
||||||
|
int i, monitorsCount = _glfw.wl.monitorsCount;
|
||||||
|
|
||||||
|
if (_glfw.wl.monitorsCount == 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*));
|
||||||
|
|
||||||
|
for (i = 0; i < monitorsCount; i++)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* origMonitor = _glfw.wl.monitors[i];
|
||||||
|
monitor = calloc(1, sizeof(_GLFWmonitor));
|
||||||
|
|
||||||
|
monitor->modes =
|
||||||
|
_glfwPlatformGetVideoModes(origMonitor,
|
||||||
|
&origMonitor->wl.modesCount);
|
||||||
|
*monitor = *_glfw.wl.monitors[i];
|
||||||
|
monitors[i] = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = monitorsCount;
|
||||||
|
return monitors;
|
||||||
|
|
||||||
|
err:
|
||||||
|
*count = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||||
|
{
|
||||||
|
return first->wl.output == second->wl.output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
if (xpos)
|
||||||
|
*xpos = monitor->wl.x;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = monitor->wl.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||||
|
{
|
||||||
|
GLFWvidmode *modes;
|
||||||
|
int i, modesCount = monitor->wl.modesCount;
|
||||||
|
|
||||||
|
modes = calloc(modesCount, sizeof(GLFWvidmode));
|
||||||
|
|
||||||
|
for (i = 0; i < modesCount; i++)
|
||||||
|
modes[i] = monitor->wl.modes[i].base;
|
||||||
|
|
||||||
|
*found = modesCount;
|
||||||
|
return modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < monitor->wl.modesCount; i++)
|
||||||
|
{
|
||||||
|
if (monitor->wl.modes[i].flags & WL_OUTPUT_MODE_CURRENT)
|
||||||
|
{
|
||||||
|
*mode = monitor->wl.modes[i].base;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Gamma ramp getting not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"Wayland: Gamma ramp setting not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
return monitor->wl.output;
|
||||||
|
}
|
||||||
|
|
179
external/glfw/wl_platform.h
vendored
Normal file
179
external/glfw/wl_platform.h
vendored
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Wayland - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_wayland_platform_h_
|
||||||
|
#define _glfw3_wayland_platform_h_
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
|
||||||
|
|
||||||
|
typedef struct VkWaylandSurfaceCreateInfoKHR
|
||||||
|
{
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkWaylandSurfaceCreateFlagsKHR flags;
|
||||||
|
struct wl_display* display;
|
||||||
|
struct wl_surface* surface;
|
||||||
|
} VkWaylandSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWaylandSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||||
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
|
||||||
|
|
||||||
|
#include "posix_tls.h"
|
||||||
|
#include "posix_time.h"
|
||||||
|
#include "linux_joystick.h"
|
||||||
|
#include "xkb_unicode.h"
|
||||||
|
#include "egl_context.h"
|
||||||
|
|
||||||
|
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
||||||
|
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||||
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
|
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->wl.native)
|
||||||
|
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.wl.display)
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||||
|
|
||||||
|
|
||||||
|
// Wayland-specific video mode data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland;
|
||||||
|
|
||||||
|
// Wayland-specific per-window data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWwindowWayland
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
GLFWbool visible;
|
||||||
|
GLFWbool maximized;
|
||||||
|
struct wl_surface* surface;
|
||||||
|
struct wl_egl_window* native;
|
||||||
|
struct wl_shell_surface* shell_surface;
|
||||||
|
struct wl_callback* callback;
|
||||||
|
|
||||||
|
_GLFWcursor* currentCursor;
|
||||||
|
double cursorPosX, cursorPosY;
|
||||||
|
|
||||||
|
char* title;
|
||||||
|
|
||||||
|
// We need to track the monitors the window spans on to calculate the
|
||||||
|
// optimal scaling factor.
|
||||||
|
int scale;
|
||||||
|
_GLFWmonitor** monitors;
|
||||||
|
int monitorsCount;
|
||||||
|
int monitorsSize;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct zwp_relative_pointer_v1* relativePointer;
|
||||||
|
struct zwp_locked_pointer_v1* lockedPointer;
|
||||||
|
} pointerLock;
|
||||||
|
} _GLFWwindowWayland;
|
||||||
|
|
||||||
|
// Wayland-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryWayland
|
||||||
|
{
|
||||||
|
struct wl_display* display;
|
||||||
|
struct wl_registry* registry;
|
||||||
|
struct wl_compositor* compositor;
|
||||||
|
struct wl_shell* shell;
|
||||||
|
struct wl_shm* shm;
|
||||||
|
struct wl_seat* seat;
|
||||||
|
struct wl_pointer* pointer;
|
||||||
|
struct wl_keyboard* keyboard;
|
||||||
|
struct zwp_relative_pointer_manager_v1* relativePointerManager;
|
||||||
|
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||||
|
|
||||||
|
int wl_compositor_version;
|
||||||
|
|
||||||
|
struct wl_cursor_theme* cursorTheme;
|
||||||
|
struct wl_surface* cursorSurface;
|
||||||
|
uint32_t pointerSerial;
|
||||||
|
|
||||||
|
_GLFWmonitor** monitors;
|
||||||
|
int monitorsCount;
|
||||||
|
int monitorsSize;
|
||||||
|
|
||||||
|
short int publicKeys[256];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct xkb_context* context;
|
||||||
|
struct xkb_keymap* keymap;
|
||||||
|
struct xkb_state* state;
|
||||||
|
xkb_mod_mask_t control_mask;
|
||||||
|
xkb_mod_mask_t alt_mask;
|
||||||
|
xkb_mod_mask_t shift_mask;
|
||||||
|
xkb_mod_mask_t super_mask;
|
||||||
|
unsigned int modifiers;
|
||||||
|
} xkb;
|
||||||
|
|
||||||
|
_GLFWwindow* pointerFocus;
|
||||||
|
_GLFWwindow* keyboardFocus;
|
||||||
|
|
||||||
|
} _GLFWlibraryWayland;
|
||||||
|
|
||||||
|
// Wayland-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorWayland
|
||||||
|
{
|
||||||
|
struct wl_output* output;
|
||||||
|
|
||||||
|
_GLFWvidmodeWayland* modes;
|
||||||
|
int modesCount;
|
||||||
|
int modesSize;
|
||||||
|
GLFWbool done;
|
||||||
|
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int scale;
|
||||||
|
} _GLFWmonitorWayland;
|
||||||
|
|
||||||
|
// Wayland-specific per-cursor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcursorWayland
|
||||||
|
{
|
||||||
|
struct wl_cursor_image* image;
|
||||||
|
struct wl_buffer* buffer;
|
||||||
|
int width, height;
|
||||||
|
int xhot, yhot;
|
||||||
|
} _GLFWcursorWayland;
|
||||||
|
|
||||||
|
|
||||||
|
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
|
||||||
|
|
||||||
|
#endif // _glfw3_wayland_platform_h_
|
1050
external/glfw/wl_window.c
vendored
Normal file
1050
external/glfw/wl_window.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
833
external/glfw/x11_init.c
vendored
Normal file
833
external/glfw/x11_init.c
vendored
Normal file
@ -0,0 +1,833 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <X11/Xresource.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Translate an X11 key code to a GLFW key code.
|
||||||
|
//
|
||||||
|
static int translateKeyCode(int scancode)
|
||||||
|
{
|
||||||
|
int keySym;
|
||||||
|
|
||||||
|
// Valid key code range is [8,255], according to the Xlib manual
|
||||||
|
if (scancode < 8 || scancode > 255)
|
||||||
|
return GLFW_KEY_UNKNOWN;
|
||||||
|
|
||||||
|
if (_glfw.x11.xkb.available)
|
||||||
|
{
|
||||||
|
// Try secondary keysym, for numeric keypad keys
|
||||||
|
// Note: This way we always force "NumLock = ON", which is intentional
|
||||||
|
// since the returned key code should correspond to a physical
|
||||||
|
// location.
|
||||||
|
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1);
|
||||||
|
switch (keySym)
|
||||||
|
{
|
||||||
|
case XK_KP_0: return GLFW_KEY_KP_0;
|
||||||
|
case XK_KP_1: return GLFW_KEY_KP_1;
|
||||||
|
case XK_KP_2: return GLFW_KEY_KP_2;
|
||||||
|
case XK_KP_3: return GLFW_KEY_KP_3;
|
||||||
|
case XK_KP_4: return GLFW_KEY_KP_4;
|
||||||
|
case XK_KP_5: return GLFW_KEY_KP_5;
|
||||||
|
case XK_KP_6: return GLFW_KEY_KP_6;
|
||||||
|
case XK_KP_7: return GLFW_KEY_KP_7;
|
||||||
|
case XK_KP_8: return GLFW_KEY_KP_8;
|
||||||
|
case XK_KP_9: return GLFW_KEY_KP_9;
|
||||||
|
case XK_KP_Separator:
|
||||||
|
case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL;
|
||||||
|
case XK_KP_Equal: return GLFW_KEY_KP_EQUAL;
|
||||||
|
case XK_KP_Enter: return GLFW_KEY_KP_ENTER;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try primary keysym for function keys (non-printable keys)
|
||||||
|
// These should not depend on the current keyboard layout
|
||||||
|
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int dummy;
|
||||||
|
KeySym* keySyms;
|
||||||
|
|
||||||
|
keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy);
|
||||||
|
keySym = keySyms[0];
|
||||||
|
XFree(keySyms);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (keySym)
|
||||||
|
{
|
||||||
|
case XK_Escape: return GLFW_KEY_ESCAPE;
|
||||||
|
case XK_Tab: return GLFW_KEY_TAB;
|
||||||
|
case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT;
|
||||||
|
case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT;
|
||||||
|
case XK_Control_L: return GLFW_KEY_LEFT_CONTROL;
|
||||||
|
case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL;
|
||||||
|
case XK_Meta_L:
|
||||||
|
case XK_Alt_L: return GLFW_KEY_LEFT_ALT;
|
||||||
|
case XK_Mode_switch: // Mapped to Alt_R on many keyboards
|
||||||
|
case XK_ISO_Level3_Shift: // AltGr on at least some machines
|
||||||
|
case XK_Meta_R:
|
||||||
|
case XK_Alt_R: return GLFW_KEY_RIGHT_ALT;
|
||||||
|
case XK_Super_L: return GLFW_KEY_LEFT_SUPER;
|
||||||
|
case XK_Super_R: return GLFW_KEY_RIGHT_SUPER;
|
||||||
|
case XK_Menu: return GLFW_KEY_MENU;
|
||||||
|
case XK_Num_Lock: return GLFW_KEY_NUM_LOCK;
|
||||||
|
case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK;
|
||||||
|
case XK_Print: return GLFW_KEY_PRINT_SCREEN;
|
||||||
|
case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK;
|
||||||
|
case XK_Pause: return GLFW_KEY_PAUSE;
|
||||||
|
case XK_Delete: return GLFW_KEY_DELETE;
|
||||||
|
case XK_BackSpace: return GLFW_KEY_BACKSPACE;
|
||||||
|
case XK_Return: return GLFW_KEY_ENTER;
|
||||||
|
case XK_Home: return GLFW_KEY_HOME;
|
||||||
|
case XK_End: return GLFW_KEY_END;
|
||||||
|
case XK_Page_Up: return GLFW_KEY_PAGE_UP;
|
||||||
|
case XK_Page_Down: return GLFW_KEY_PAGE_DOWN;
|
||||||
|
case XK_Insert: return GLFW_KEY_INSERT;
|
||||||
|
case XK_Left: return GLFW_KEY_LEFT;
|
||||||
|
case XK_Right: return GLFW_KEY_RIGHT;
|
||||||
|
case XK_Down: return GLFW_KEY_DOWN;
|
||||||
|
case XK_Up: return GLFW_KEY_UP;
|
||||||
|
case XK_F1: return GLFW_KEY_F1;
|
||||||
|
case XK_F2: return GLFW_KEY_F2;
|
||||||
|
case XK_F3: return GLFW_KEY_F3;
|
||||||
|
case XK_F4: return GLFW_KEY_F4;
|
||||||
|
case XK_F5: return GLFW_KEY_F5;
|
||||||
|
case XK_F6: return GLFW_KEY_F6;
|
||||||
|
case XK_F7: return GLFW_KEY_F7;
|
||||||
|
case XK_F8: return GLFW_KEY_F8;
|
||||||
|
case XK_F9: return GLFW_KEY_F9;
|
||||||
|
case XK_F10: return GLFW_KEY_F10;
|
||||||
|
case XK_F11: return GLFW_KEY_F11;
|
||||||
|
case XK_F12: return GLFW_KEY_F12;
|
||||||
|
case XK_F13: return GLFW_KEY_F13;
|
||||||
|
case XK_F14: return GLFW_KEY_F14;
|
||||||
|
case XK_F15: return GLFW_KEY_F15;
|
||||||
|
case XK_F16: return GLFW_KEY_F16;
|
||||||
|
case XK_F17: return GLFW_KEY_F17;
|
||||||
|
case XK_F18: return GLFW_KEY_F18;
|
||||||
|
case XK_F19: return GLFW_KEY_F19;
|
||||||
|
case XK_F20: return GLFW_KEY_F20;
|
||||||
|
case XK_F21: return GLFW_KEY_F21;
|
||||||
|
case XK_F22: return GLFW_KEY_F22;
|
||||||
|
case XK_F23: return GLFW_KEY_F23;
|
||||||
|
case XK_F24: return GLFW_KEY_F24;
|
||||||
|
case XK_F25: return GLFW_KEY_F25;
|
||||||
|
|
||||||
|
// Numeric keypad
|
||||||
|
case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE;
|
||||||
|
case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY;
|
||||||
|
case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT;
|
||||||
|
case XK_KP_Add: return GLFW_KEY_KP_ADD;
|
||||||
|
|
||||||
|
// These should have been detected in secondary keysym test above!
|
||||||
|
case XK_KP_Insert: return GLFW_KEY_KP_0;
|
||||||
|
case XK_KP_End: return GLFW_KEY_KP_1;
|
||||||
|
case XK_KP_Down: return GLFW_KEY_KP_2;
|
||||||
|
case XK_KP_Page_Down: return GLFW_KEY_KP_3;
|
||||||
|
case XK_KP_Left: return GLFW_KEY_KP_4;
|
||||||
|
case XK_KP_Right: return GLFW_KEY_KP_6;
|
||||||
|
case XK_KP_Home: return GLFW_KEY_KP_7;
|
||||||
|
case XK_KP_Up: return GLFW_KEY_KP_8;
|
||||||
|
case XK_KP_Page_Up: return GLFW_KEY_KP_9;
|
||||||
|
case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL;
|
||||||
|
case XK_KP_Equal: return GLFW_KEY_KP_EQUAL;
|
||||||
|
case XK_KP_Enter: return GLFW_KEY_KP_ENTER;
|
||||||
|
|
||||||
|
// Last resort: Check for printable keys (should not happen if the XKB
|
||||||
|
// extension is available). This will give a layout dependent mapping
|
||||||
|
// (which is wrong, and we may miss some keys, especially on non-US
|
||||||
|
// keyboards), but it's better than nothing...
|
||||||
|
case XK_a: return GLFW_KEY_A;
|
||||||
|
case XK_b: return GLFW_KEY_B;
|
||||||
|
case XK_c: return GLFW_KEY_C;
|
||||||
|
case XK_d: return GLFW_KEY_D;
|
||||||
|
case XK_e: return GLFW_KEY_E;
|
||||||
|
case XK_f: return GLFW_KEY_F;
|
||||||
|
case XK_g: return GLFW_KEY_G;
|
||||||
|
case XK_h: return GLFW_KEY_H;
|
||||||
|
case XK_i: return GLFW_KEY_I;
|
||||||
|
case XK_j: return GLFW_KEY_J;
|
||||||
|
case XK_k: return GLFW_KEY_K;
|
||||||
|
case XK_l: return GLFW_KEY_L;
|
||||||
|
case XK_m: return GLFW_KEY_M;
|
||||||
|
case XK_n: return GLFW_KEY_N;
|
||||||
|
case XK_o: return GLFW_KEY_O;
|
||||||
|
case XK_p: return GLFW_KEY_P;
|
||||||
|
case XK_q: return GLFW_KEY_Q;
|
||||||
|
case XK_r: return GLFW_KEY_R;
|
||||||
|
case XK_s: return GLFW_KEY_S;
|
||||||
|
case XK_t: return GLFW_KEY_T;
|
||||||
|
case XK_u: return GLFW_KEY_U;
|
||||||
|
case XK_v: return GLFW_KEY_V;
|
||||||
|
case XK_w: return GLFW_KEY_W;
|
||||||
|
case XK_x: return GLFW_KEY_X;
|
||||||
|
case XK_y: return GLFW_KEY_Y;
|
||||||
|
case XK_z: return GLFW_KEY_Z;
|
||||||
|
case XK_1: return GLFW_KEY_1;
|
||||||
|
case XK_2: return GLFW_KEY_2;
|
||||||
|
case XK_3: return GLFW_KEY_3;
|
||||||
|
case XK_4: return GLFW_KEY_4;
|
||||||
|
case XK_5: return GLFW_KEY_5;
|
||||||
|
case XK_6: return GLFW_KEY_6;
|
||||||
|
case XK_7: return GLFW_KEY_7;
|
||||||
|
case XK_8: return GLFW_KEY_8;
|
||||||
|
case XK_9: return GLFW_KEY_9;
|
||||||
|
case XK_0: return GLFW_KEY_0;
|
||||||
|
case XK_space: return GLFW_KEY_SPACE;
|
||||||
|
case XK_minus: return GLFW_KEY_MINUS;
|
||||||
|
case XK_equal: return GLFW_KEY_EQUAL;
|
||||||
|
case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET;
|
||||||
|
case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
case XK_backslash: return GLFW_KEY_BACKSLASH;
|
||||||
|
case XK_semicolon: return GLFW_KEY_SEMICOLON;
|
||||||
|
case XK_apostrophe: return GLFW_KEY_APOSTROPHE;
|
||||||
|
case XK_grave: return GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
case XK_comma: return GLFW_KEY_COMMA;
|
||||||
|
case XK_period: return GLFW_KEY_PERIOD;
|
||||||
|
case XK_slash: return GLFW_KEY_SLASH;
|
||||||
|
case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts...
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching translation was found
|
||||||
|
return GLFW_KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create key code translation tables
|
||||||
|
//
|
||||||
|
static void createKeyTables(void)
|
||||||
|
{
|
||||||
|
int scancode, key;
|
||||||
|
|
||||||
|
memset(_glfw.x11.publicKeys, -1, sizeof(_glfw.x11.publicKeys));
|
||||||
|
memset(_glfw.x11.nativeKeys, -1, sizeof(_glfw.x11.nativeKeys));
|
||||||
|
|
||||||
|
if (_glfw.x11.xkb.available)
|
||||||
|
{
|
||||||
|
// Use XKB to determine physical key locations independently of the current
|
||||||
|
// keyboard layout
|
||||||
|
|
||||||
|
char name[XkbKeyNameLength + 1];
|
||||||
|
XkbDescPtr desc = XkbGetMap(_glfw.x11.display, 0, XkbUseCoreKbd);
|
||||||
|
XkbGetNames(_glfw.x11.display, XkbKeyNamesMask, desc);
|
||||||
|
|
||||||
|
// Find the X11 key code -> GLFW key code mapping
|
||||||
|
for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++)
|
||||||
|
{
|
||||||
|
memcpy(name, desc->names->keys[scancode].name, XkbKeyNameLength);
|
||||||
|
name[XkbKeyNameLength] = '\0';
|
||||||
|
|
||||||
|
// Map the key name to a GLFW key code. Note: We only map printable
|
||||||
|
// keys here, and we use the US keyboard layout. The rest of the
|
||||||
|
// keys (function keys) are mapped using traditional KeySym
|
||||||
|
// translations.
|
||||||
|
if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT;
|
||||||
|
else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1;
|
||||||
|
else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2;
|
||||||
|
else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3;
|
||||||
|
else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4;
|
||||||
|
else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5;
|
||||||
|
else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6;
|
||||||
|
else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7;
|
||||||
|
else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8;
|
||||||
|
else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9;
|
||||||
|
else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0;
|
||||||
|
else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS;
|
||||||
|
else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL;
|
||||||
|
else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q;
|
||||||
|
else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W;
|
||||||
|
else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E;
|
||||||
|
else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R;
|
||||||
|
else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T;
|
||||||
|
else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y;
|
||||||
|
else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U;
|
||||||
|
else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I;
|
||||||
|
else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O;
|
||||||
|
else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P;
|
||||||
|
else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET;
|
||||||
|
else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET;
|
||||||
|
else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A;
|
||||||
|
else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S;
|
||||||
|
else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D;
|
||||||
|
else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F;
|
||||||
|
else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G;
|
||||||
|
else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H;
|
||||||
|
else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J;
|
||||||
|
else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K;
|
||||||
|
else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L;
|
||||||
|
else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON;
|
||||||
|
else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE;
|
||||||
|
else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z;
|
||||||
|
else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X;
|
||||||
|
else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C;
|
||||||
|
else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V;
|
||||||
|
else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B;
|
||||||
|
else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N;
|
||||||
|
else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M;
|
||||||
|
else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA;
|
||||||
|
else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD;
|
||||||
|
else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH;
|
||||||
|
else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH;
|
||||||
|
else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1;
|
||||||
|
else key = GLFW_KEY_UNKNOWN;
|
||||||
|
|
||||||
|
if ((scancode >= 0) && (scancode < 256))
|
||||||
|
_glfw.x11.publicKeys[scancode] = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
XkbFreeNames(desc, XkbKeyNamesMask, True);
|
||||||
|
XkbFreeKeyboard(desc, 0, True);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (scancode = 0; scancode < 256; scancode++)
|
||||||
|
{
|
||||||
|
// Translate the un-translated key codes using traditional X11 KeySym
|
||||||
|
// lookups
|
||||||
|
if (_glfw.x11.publicKeys[scancode] < 0)
|
||||||
|
_glfw.x11.publicKeys[scancode] = translateKeyCode(scancode);
|
||||||
|
|
||||||
|
// Store the reverse translation for faster key name lookup
|
||||||
|
if (_glfw.x11.publicKeys[scancode] > 0)
|
||||||
|
_glfw.x11.nativeKeys[_glfw.x11.publicKeys[scancode]] = scancode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the IM has a usable style
|
||||||
|
//
|
||||||
|
static GLFWbool hasUsableInputMethodStyle(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
GLFWbool found = GLFW_FALSE;
|
||||||
|
XIMStyles* styles = NULL;
|
||||||
|
|
||||||
|
if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < styles->count_styles; i++)
|
||||||
|
{
|
||||||
|
if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing))
|
||||||
|
{
|
||||||
|
found = GLFW_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(styles);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the specified atom is supported
|
||||||
|
//
|
||||||
|
static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||||
|
unsigned long atomCount,
|
||||||
|
const char* atomName)
|
||||||
|
{
|
||||||
|
unsigned long i;
|
||||||
|
const Atom atom = XInternAtom(_glfw.x11.display, atomName, False);
|
||||||
|
|
||||||
|
for (i = 0; i < atomCount; i++)
|
||||||
|
{
|
||||||
|
if (supportedAtoms[i] == atom)
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the running window manager is EWMH-compliant
|
||||||
|
//
|
||||||
|
static void detectEWMH(void)
|
||||||
|
{
|
||||||
|
Window* windowFromRoot = NULL;
|
||||||
|
Window* windowFromChild = NULL;
|
||||||
|
|
||||||
|
// First we need a couple of atoms
|
||||||
|
const Atom supportingWmCheck =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", False);
|
||||||
|
const Atom wmSupported =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", False);
|
||||||
|
|
||||||
|
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
||||||
|
if (_glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
|
supportingWmCheck,
|
||||||
|
XA_WINDOW,
|
||||||
|
(unsigned char**) &windowFromRoot) != 1)
|
||||||
|
{
|
||||||
|
if (windowFromRoot)
|
||||||
|
XFree(windowFromRoot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
|
||||||
|
// It should be the ID of a child window (of the root)
|
||||||
|
// Then we look for the same property on the child window
|
||||||
|
if (_glfwGetWindowPropertyX11(*windowFromRoot,
|
||||||
|
supportingWmCheck,
|
||||||
|
XA_WINDOW,
|
||||||
|
(unsigned char**) &windowFromChild) != 1)
|
||||||
|
{
|
||||||
|
XFree(windowFromRoot);
|
||||||
|
if (windowFromChild)
|
||||||
|
XFree(windowFromChild);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
|
||||||
|
// It should be the ID of that same child window
|
||||||
|
if (*windowFromRoot != *windowFromChild)
|
||||||
|
{
|
||||||
|
XFree(windowFromRoot);
|
||||||
|
XFree(windowFromChild);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(windowFromRoot);
|
||||||
|
XFree(windowFromChild);
|
||||||
|
|
||||||
|
// We are now fairly sure that an EWMH-compliant window manager is running
|
||||||
|
|
||||||
|
Atom* supportedAtoms;
|
||||||
|
unsigned long atomCount;
|
||||||
|
|
||||||
|
// Now we need to check the _NET_SUPPORTED property of the root window
|
||||||
|
// It should be a list of supported WM protocol and state atoms
|
||||||
|
atomCount = _glfwGetWindowPropertyX11(_glfw.x11.root,
|
||||||
|
wmSupported,
|
||||||
|
XA_ATOM,
|
||||||
|
(unsigned char**) &supportedAtoms);
|
||||||
|
|
||||||
|
// See which of the atoms we support that are supported by the WM
|
||||||
|
_glfw.x11.NET_WM_STATE =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||||
|
_glfw.x11.NET_WM_STATE_ABOVE =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
|
||||||
|
_glfw.x11.NET_WM_STATE_FULLSCREEN =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
|
||||||
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_VERT");
|
||||||
|
_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||||
|
_glfw.x11.NET_WM_FULLSCREEN_MONITORS =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
|
||||||
|
_glfw.x11.NET_WM_WINDOW_TYPE =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE");
|
||||||
|
_glfw.x11.NET_WM_WINDOW_TYPE_NORMAL =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_WINDOW_TYPE_NORMAL");
|
||||||
|
_glfw.x11.NET_ACTIVE_WINDOW =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
|
||||||
|
_glfw.x11.NET_FRAME_EXTENTS =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS");
|
||||||
|
_glfw.x11.NET_REQUEST_FRAME_EXTENTS =
|
||||||
|
getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS");
|
||||||
|
|
||||||
|
XFree(supportedAtoms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize X11 display and look for supported X11 extensions
|
||||||
|
//
|
||||||
|
static GLFWbool initExtensions(void)
|
||||||
|
{
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
// Check for XF86VidMode extension
|
||||||
|
_glfw.x11.vidmode.available =
|
||||||
|
XF86VidModeQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.x11.vidmode.eventBase,
|
||||||
|
&_glfw.x11.vidmode.errorBase);
|
||||||
|
#endif /*_GLFW_HAS_XF86VM*/
|
||||||
|
|
||||||
|
// Check for RandR extension
|
||||||
|
if (XRRQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.x11.randr.eventBase,
|
||||||
|
&_glfw.x11.randr.errorBase))
|
||||||
|
{
|
||||||
|
if (XRRQueryVersion(_glfw.x11.display,
|
||||||
|
&_glfw.x11.randr.major,
|
||||||
|
&_glfw.x11.randr.minor))
|
||||||
|
{
|
||||||
|
// The GLFW RandR path requires at least version 1.3
|
||||||
|
if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3)
|
||||||
|
_glfw.x11.randr.available = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Failed to query RandR version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.x11.randr.available)
|
||||||
|
{
|
||||||
|
XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display,
|
||||||
|
_glfw.x11.root);
|
||||||
|
|
||||||
|
if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0]))
|
||||||
|
{
|
||||||
|
// This is either a headless system or an older Nvidia binary driver
|
||||||
|
// with broken gamma support
|
||||||
|
// Flag it as useless and fall back to Xf86VidMode gamma, if
|
||||||
|
// available
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: RandR gamma ramp support seems broken");
|
||||||
|
_glfw.x11.randr.gammaBroken = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
|
||||||
|
XRRSelectInput(_glfw.x11.display, _glfw.x11.root,
|
||||||
|
RROutputChangeNotifyMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XineramaQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.x11.xinerama.major,
|
||||||
|
&_glfw.x11.xinerama.minor))
|
||||||
|
{
|
||||||
|
if (XineramaIsActive(_glfw.x11.display))
|
||||||
|
_glfw.x11.xinerama.available = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Xkb is supported on this display
|
||||||
|
_glfw.x11.xkb.major = 1;
|
||||||
|
_glfw.x11.xkb.minor = 0;
|
||||||
|
_glfw.x11.xkb.available =
|
||||||
|
XkbQueryExtension(_glfw.x11.display,
|
||||||
|
&_glfw.x11.xkb.majorOpcode,
|
||||||
|
&_glfw.x11.xkb.eventBase,
|
||||||
|
&_glfw.x11.xkb.errorBase,
|
||||||
|
&_glfw.x11.xkb.major,
|
||||||
|
&_glfw.x11.xkb.minor);
|
||||||
|
|
||||||
|
if (_glfw.x11.xkb.available)
|
||||||
|
{
|
||||||
|
Bool supported;
|
||||||
|
|
||||||
|
if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported))
|
||||||
|
{
|
||||||
|
if (supported)
|
||||||
|
_glfw.x11.xkb.detectable = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.x11.x11xcb.handle = dlopen("libX11-xcb.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
if (_glfw.x11.x11xcb.handle)
|
||||||
|
{
|
||||||
|
_glfw.x11.x11xcb.XGetXCBConnection = (XGETXCBCONNECTION_T)
|
||||||
|
dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the key code LUT
|
||||||
|
// FIXME: We should listen to XkbMapNotify events to track changes to
|
||||||
|
// the keyboard mapping.
|
||||||
|
createKeyTables();
|
||||||
|
|
||||||
|
// Detect whether an EWMH-conformant window manager is running
|
||||||
|
detectEWMH();
|
||||||
|
|
||||||
|
// String format atoms
|
||||||
|
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
|
||||||
|
_glfw.x11.UTF8_STRING =
|
||||||
|
XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
|
||||||
|
_glfw.x11.COMPOUND_STRING =
|
||||||
|
XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False);
|
||||||
|
_glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
|
||||||
|
|
||||||
|
// Custom selection property atom
|
||||||
|
_glfw.x11.GLFW_SELECTION =
|
||||||
|
XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
|
||||||
|
|
||||||
|
// ICCCM standard clipboard atoms
|
||||||
|
_glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
|
||||||
|
_glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
|
||||||
|
_glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
|
||||||
|
|
||||||
|
// Clipboard manager atoms
|
||||||
|
_glfw.x11.CLIPBOARD_MANAGER =
|
||||||
|
XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False);
|
||||||
|
_glfw.x11.SAVE_TARGETS =
|
||||||
|
XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
|
||||||
|
|
||||||
|
// Xdnd (drag and drop) atoms
|
||||||
|
_glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", False);
|
||||||
|
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
|
||||||
|
_glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
|
||||||
|
_glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
|
||||||
|
_glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
|
||||||
|
_glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
|
||||||
|
_glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False);
|
||||||
|
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
|
||||||
|
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
|
||||||
|
|
||||||
|
// ICCCM, EWMH and Motif window property atoms
|
||||||
|
// These can be set safely even without WM support
|
||||||
|
// The EWMH atoms that require WM support are handled in detectEWMH
|
||||||
|
_glfw.x11.WM_PROTOCOLS =
|
||||||
|
XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", False);
|
||||||
|
_glfw.x11.WM_STATE =
|
||||||
|
XInternAtom(_glfw.x11.display, "WM_STATE", False);
|
||||||
|
_glfw.x11.WM_DELETE_WINDOW =
|
||||||
|
XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", False);
|
||||||
|
_glfw.x11.NET_WM_ICON =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_ICON", False);
|
||||||
|
_glfw.x11.NET_WM_PING =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_PING", False);
|
||||||
|
_glfw.x11.NET_WM_PID =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_PID", False);
|
||||||
|
_glfw.x11.NET_WM_NAME =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_NAME", False);
|
||||||
|
_glfw.x11.NET_WM_ICON_NAME =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False);
|
||||||
|
_glfw.x11.NET_WM_BYPASS_COMPOSITOR =
|
||||||
|
XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False);
|
||||||
|
_glfw.x11.MOTIF_WM_HINTS =
|
||||||
|
XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a blank cursor for hidden and disabled cursor modes
|
||||||
|
//
|
||||||
|
static Cursor createHiddenCursor(void)
|
||||||
|
{
|
||||||
|
unsigned char pixels[16 * 16 * 4];
|
||||||
|
GLFWimage image = { 16, 16, pixels };
|
||||||
|
|
||||||
|
memset(pixels, 0, sizeof(pixels));
|
||||||
|
|
||||||
|
return _glfwCreateCursorX11(&image, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// X error handler
|
||||||
|
//
|
||||||
|
static int errorHandler(Display *display, XErrorEvent* event)
|
||||||
|
{
|
||||||
|
_glfw.x11.errorCode = event->error_code;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Sets the X error handler callback
|
||||||
|
//
|
||||||
|
void _glfwGrabErrorHandlerX11(void)
|
||||||
|
{
|
||||||
|
_glfw.x11.errorCode = Success;
|
||||||
|
XSetErrorHandler(errorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears the X error handler callback
|
||||||
|
//
|
||||||
|
void _glfwReleaseErrorHandlerX11(void)
|
||||||
|
{
|
||||||
|
// Synchronize to make sure all commands are processed
|
||||||
|
XSync(_glfw.x11.display, False);
|
||||||
|
XSetErrorHandler(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reports the specified error, appending information about the last X error
|
||||||
|
//
|
||||||
|
void _glfwInputErrorX11(int error, const char* message)
|
||||||
|
{
|
||||||
|
char buffer[8192];
|
||||||
|
XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode,
|
||||||
|
buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
_glfwInputError(error, "%s: %s", message, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a native cursor object from the specified image and hotspot
|
||||||
|
//
|
||||||
|
Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Cursor cursor;
|
||||||
|
|
||||||
|
XcursorImage* native = XcursorImageCreate(image->width, image->height);
|
||||||
|
if (native == NULL)
|
||||||
|
return None;
|
||||||
|
|
||||||
|
native->xhot = xhot;
|
||||||
|
native->yhot = yhot;
|
||||||
|
|
||||||
|
unsigned char* source = (unsigned char*) image->pixels;
|
||||||
|
XcursorPixel* target = native->pixels;
|
||||||
|
|
||||||
|
for (i = 0; i < image->width * image->height; i++, target++, source += 4)
|
||||||
|
{
|
||||||
|
unsigned int alpha = source[3];
|
||||||
|
|
||||||
|
*target = (alpha << 24) |
|
||||||
|
((unsigned char) ((source[0] * alpha) / 255) << 16) |
|
||||||
|
((unsigned char) ((source[1] * alpha) / 255) << 8) |
|
||||||
|
((unsigned char) ((source[2] * alpha) / 255) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = XcursorImageLoadCursor(_glfw.x11.display, native);
|
||||||
|
XcursorImageDestroy(native);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int _glfwPlatformInit(void)
|
||||||
|
{
|
||||||
|
#if !defined(X_HAVE_UTF8_STRING)
|
||||||
|
// HACK: If the current locale is C, apply the environment's locale
|
||||||
|
// This is done because the C locale breaks wide character input
|
||||||
|
if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0)
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
XInitThreads();
|
||||||
|
|
||||||
|
_glfw.x11.display = XOpenDisplay(NULL);
|
||||||
|
if (!_glfw.x11.display)
|
||||||
|
{
|
||||||
|
const char* display = getenv("DISPLAY");
|
||||||
|
if (display)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Failed to open display %s", display);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: The DISPLAY environment variable is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfw.x11.screen = DefaultScreen(_glfw.x11.display);
|
||||||
|
_glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen);
|
||||||
|
_glfw.x11.context = XUniqueContext();
|
||||||
|
|
||||||
|
if (!initExtensions())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfw.x11.cursor = createHiddenCursor();
|
||||||
|
|
||||||
|
if (XSupportsLocale())
|
||||||
|
{
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
|
||||||
|
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
|
||||||
|
if (_glfw.x11.im)
|
||||||
|
{
|
||||||
|
if (!hasUsableInputMethodStyle())
|
||||||
|
{
|
||||||
|
XCloseIM(_glfw.x11.im);
|
||||||
|
_glfw.x11.im = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_glfwInitThreadLocalStoragePOSIX())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
if (!_glfwInitJoysticksLinux())
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
|
_glfwInitTimerPOSIX();
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformTerminate(void)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.x11xcb.handle)
|
||||||
|
{
|
||||||
|
dlclose(_glfw.x11.x11xcb.handle);
|
||||||
|
_glfw.x11.x11xcb.handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_glfw.x11.cursor)
|
||||||
|
{
|
||||||
|
XFreeCursor(_glfw.x11.display, _glfw.x11.cursor);
|
||||||
|
_glfw.x11.cursor = (Cursor) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(_glfw.x11.clipboardString);
|
||||||
|
|
||||||
|
if (_glfw.x11.im)
|
||||||
|
{
|
||||||
|
XCloseIM(_glfw.x11.im);
|
||||||
|
_glfw.x11.im = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwTerminateEGL();
|
||||||
|
|
||||||
|
if (_glfw.x11.display)
|
||||||
|
{
|
||||||
|
XCloseDisplay(_glfw.x11.display);
|
||||||
|
_glfw.x11.display = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This needs to be done after XCloseDisplay, as libGL registers
|
||||||
|
// cleanup callbacks that get called by it
|
||||||
|
_glfwTerminateGLX();
|
||||||
|
|
||||||
|
_glfwTerminateJoysticksLinux();
|
||||||
|
_glfwTerminateThreadLocalStoragePOSIX();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _glfwPlatformGetVersionString(void)
|
||||||
|
{
|
||||||
|
return _GLFW_VERSION_NUMBER " X11 GLX EGL"
|
||||||
|
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
|
||||||
|
" clock_gettime"
|
||||||
|
#else
|
||||||
|
" gettimeofday"
|
||||||
|
#endif
|
||||||
|
#if defined(__linux__)
|
||||||
|
" /dev/js"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
" Xf86vm"
|
||||||
|
#endif
|
||||||
|
#if defined(_GLFW_BUILD_DLL)
|
||||||
|
" shared"
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
491
external/glfw/x11_monitor.c
vendored
Normal file
491
external/glfw/x11_monitor.c
vendored
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Check whether the display mode should be included in enumeration
|
||||||
|
//
|
||||||
|
static GLFWbool modeIsGood(const XRRModeInfo* mi)
|
||||||
|
{
|
||||||
|
return (mi->modeFlags & RR_Interlace) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the refresh rate, in Hz, from the specified RandR mode info
|
||||||
|
//
|
||||||
|
static int calculateRefreshRate(const XRRModeInfo* mi)
|
||||||
|
{
|
||||||
|
if (mi->hTotal && mi->vTotal)
|
||||||
|
return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal));
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the mode info for a RandR mode XID
|
||||||
|
//
|
||||||
|
static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sr->nmode; i++)
|
||||||
|
{
|
||||||
|
if (sr->modes[i].id == id)
|
||||||
|
return sr->modes + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RandR mode info to GLFW video mode
|
||||||
|
//
|
||||||
|
static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi,
|
||||||
|
const XRRCrtcInfo* ci)
|
||||||
|
{
|
||||||
|
GLFWvidmode mode;
|
||||||
|
|
||||||
|
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
|
||||||
|
{
|
||||||
|
mode.width = mi->height;
|
||||||
|
mode.height = mi->width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mode.width = mi->width;
|
||||||
|
mode.height = mi->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode.refreshRate = calculateRefreshRate(mi);
|
||||||
|
|
||||||
|
_glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
|
||||||
|
&mode.redBits, &mode.greenBits, &mode.blueBits);
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Set the current video mode for the specified monitor
|
||||||
|
//
|
||||||
|
GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
|
{
|
||||||
|
XRRScreenResources* sr;
|
||||||
|
XRRCrtcInfo* ci;
|
||||||
|
XRROutputInfo* oi;
|
||||||
|
GLFWvidmode current;
|
||||||
|
const GLFWvidmode* best;
|
||||||
|
RRMode native = None;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
best = _glfwChooseVideoMode(monitor, desired);
|
||||||
|
_glfwPlatformGetVideoMode(monitor, ¤t);
|
||||||
|
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||||
|
return GLFW_TRUE;
|
||||||
|
|
||||||
|
sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
|
||||||
|
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||||
|
|
||||||
|
for (i = 0; i < oi->nmode; i++)
|
||||||
|
{
|
||||||
|
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||||
|
if (!modeIsGood(mi))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
||||||
|
if (_glfwCompareVideoModes(best, &mode) == 0)
|
||||||
|
{
|
||||||
|
native = mi->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (native)
|
||||||
|
{
|
||||||
|
if (monitor->x11.oldMode == None)
|
||||||
|
monitor->x11.oldMode = ci->mode;
|
||||||
|
|
||||||
|
XRRSetCrtcConfig(_glfw.x11.display,
|
||||||
|
sr, monitor->x11.crtc,
|
||||||
|
CurrentTime,
|
||||||
|
ci->x, ci->y,
|
||||||
|
native,
|
||||||
|
ci->rotation,
|
||||||
|
ci->outputs,
|
||||||
|
ci->noutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeOutputInfo(oi);
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
|
||||||
|
if (!native)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: Monitor mode list changed");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GLFW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the saved (original) video mode for the specified monitor
|
||||||
|
//
|
||||||
|
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
|
{
|
||||||
|
XRRScreenResources* sr;
|
||||||
|
XRRCrtcInfo* ci;
|
||||||
|
|
||||||
|
if (monitor->x11.oldMode == None)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
|
||||||
|
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
|
XRRSetCrtcConfig(_glfw.x11.display,
|
||||||
|
sr, monitor->x11.crtc,
|
||||||
|
CurrentTime,
|
||||||
|
ci->x, ci->y,
|
||||||
|
monitor->x11.oldMode,
|
||||||
|
ci->rotation,
|
||||||
|
ci->outputs,
|
||||||
|
ci->noutput);
|
||||||
|
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
|
||||||
|
monitor->x11.oldMode = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW platform API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||||
|
{
|
||||||
|
int i, j, k, found = 0;
|
||||||
|
_GLFWmonitor** monitors = NULL;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
if (_glfw.x11.randr.available)
|
||||||
|
{
|
||||||
|
int screenCount = 0;
|
||||||
|
XineramaScreenInfo* screens = NULL;
|
||||||
|
XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display,
|
||||||
|
_glfw.x11.root);
|
||||||
|
RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
|
||||||
|
_glfw.x11.root);
|
||||||
|
|
||||||
|
monitors = calloc(sr->noutput, sizeof(_GLFWmonitor*));
|
||||||
|
|
||||||
|
if (_glfw.x11.xinerama.available)
|
||||||
|
screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
|
||||||
|
|
||||||
|
for (i = 0; i < sr->ncrtc; i++)
|
||||||
|
{
|
||||||
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display,
|
||||||
|
sr, sr->crtcs[i]);
|
||||||
|
|
||||||
|
for (j = 0; j < ci->noutput; j++)
|
||||||
|
{
|
||||||
|
int widthMM, heightMM;
|
||||||
|
_GLFWmonitor* monitor;
|
||||||
|
XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display,
|
||||||
|
sr, ci->outputs[j]);
|
||||||
|
if (oi->connection != RR_Connected)
|
||||||
|
{
|
||||||
|
XRRFreeOutputInfo(oi);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
|
||||||
|
{
|
||||||
|
widthMM = oi->mm_height;
|
||||||
|
heightMM = oi->mm_width;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
widthMM = oi->mm_width;
|
||||||
|
heightMM = oi->mm_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||||
|
monitor->x11.output = ci->outputs[j];
|
||||||
|
monitor->x11.crtc = oi->crtc;
|
||||||
|
|
||||||
|
for (k = 0; k < screenCount; k++)
|
||||||
|
{
|
||||||
|
if (screens[k].x_org == ci->x &&
|
||||||
|
screens[k].y_org == ci->y &&
|
||||||
|
screens[k].width == ci->width &&
|
||||||
|
screens[k].height == ci->height)
|
||||||
|
{
|
||||||
|
monitor->x11.index = k;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeOutputInfo(oi);
|
||||||
|
|
||||||
|
found++;
|
||||||
|
monitors[found - 1] = monitor;
|
||||||
|
|
||||||
|
if (ci->outputs[j] == primary)
|
||||||
|
_GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
|
||||||
|
if (screens)
|
||||||
|
XFree(screens);
|
||||||
|
|
||||||
|
if (found == 0)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
|
"X11: RandR monitor support seems broken");
|
||||||
|
|
||||||
|
_glfw.x11.randr.monitorBroken = GLFW_TRUE;
|
||||||
|
free(monitors);
|
||||||
|
monitors = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!monitors)
|
||||||
|
{
|
||||||
|
monitors = calloc(1, sizeof(_GLFWmonitor*));
|
||||||
|
monitors[0] = _glfwAllocMonitor("Display",
|
||||||
|
DisplayWidthMM(_glfw.x11.display,
|
||||||
|
_glfw.x11.screen),
|
||||||
|
DisplayHeightMM(_glfw.x11.display,
|
||||||
|
_glfw.x11.screen));
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*count = found;
|
||||||
|
return monitors;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWbool _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||||
|
{
|
||||||
|
return first->x11.crtc == second->x11.crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
|
{
|
||||||
|
XRRScreenResources* sr;
|
||||||
|
XRRCrtcInfo* ci;
|
||||||
|
|
||||||
|
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
|
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
|
if (xpos)
|
||||||
|
*xpos = ci->x;
|
||||||
|
if (ypos)
|
||||||
|
*ypos = ci->y;
|
||||||
|
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||||
|
{
|
||||||
|
GLFWvidmode* result;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
XRRScreenResources* sr;
|
||||||
|
XRRCrtcInfo* ci;
|
||||||
|
XRROutputInfo* oi;
|
||||||
|
|
||||||
|
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
|
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output);
|
||||||
|
|
||||||
|
result = calloc(oi->nmode, sizeof(GLFWvidmode));
|
||||||
|
|
||||||
|
for (i = 0; i < oi->nmode; i++)
|
||||||
|
{
|
||||||
|
const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]);
|
||||||
|
if (!modeIsGood(mi))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
||||||
|
|
||||||
|
for (j = 0; j < *count; j++)
|
||||||
|
{
|
||||||
|
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip duplicate modes
|
||||||
|
if (j < *count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
result[*count - 1] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
XRRFreeOutputInfo(oi);
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*count = 1;
|
||||||
|
result = calloc(1, sizeof(GLFWvidmode));
|
||||||
|
_glfwPlatformGetVideoMode(monitor, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||||
|
{
|
||||||
|
XRRScreenResources* sr;
|
||||||
|
XRRCrtcInfo* ci;
|
||||||
|
|
||||||
|
sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root);
|
||||||
|
ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc);
|
||||||
|
|
||||||
|
*mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci);
|
||||||
|
|
||||||
|
XRRFreeCrtcInfo(ci);
|
||||||
|
XRRFreeScreenResources(sr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen);
|
||||||
|
mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen);
|
||||||
|
mode->refreshRate = 0;
|
||||||
|
|
||||||
|
_glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen),
|
||||||
|
&mode->redBits, &mode->greenBits, &mode->blueBits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
|
||||||
|
{
|
||||||
|
const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display,
|
||||||
|
monitor->x11.crtc);
|
||||||
|
XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display,
|
||||||
|
monitor->x11.crtc);
|
||||||
|
|
||||||
|
_glfwAllocGammaArrays(ramp, size);
|
||||||
|
|
||||||
|
memcpy(ramp->red, gamma->red, size * sizeof(unsigned short));
|
||||||
|
memcpy(ramp->green, gamma->green, size * sizeof(unsigned short));
|
||||||
|
memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short));
|
||||||
|
|
||||||
|
XRRFreeGamma(gamma);
|
||||||
|
}
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
else if (_glfw.x11.vidmode.available)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size);
|
||||||
|
|
||||||
|
_glfwAllocGammaArrays(ramp, size);
|
||||||
|
|
||||||
|
XF86VidModeGetGammaRamp(_glfw.x11.display,
|
||||||
|
_glfw.x11.screen,
|
||||||
|
ramp->size, ramp->red, ramp->green, ramp->blue);
|
||||||
|
}
|
||||||
|
#endif /*_GLFW_HAS_XF86VM*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||||
|
{
|
||||||
|
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
|
||||||
|
{
|
||||||
|
XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size);
|
||||||
|
|
||||||
|
memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short));
|
||||||
|
memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short));
|
||||||
|
memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short));
|
||||||
|
|
||||||
|
XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma);
|
||||||
|
XRRFreeGamma(gamma);
|
||||||
|
}
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
else if (_glfw.x11.vidmode.available)
|
||||||
|
{
|
||||||
|
XF86VidModeSetGammaRamp(_glfw.x11.display,
|
||||||
|
_glfw.x11.screen,
|
||||||
|
ramp->size,
|
||||||
|
(unsigned short*) ramp->red,
|
||||||
|
(unsigned short*) ramp->green,
|
||||||
|
(unsigned short*) ramp->blue);
|
||||||
|
}
|
||||||
|
#endif /*_GLFW_HAS_XF86VM*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW native API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||||
|
return monitor->x11.crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
|
||||||
|
{
|
||||||
|
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||||
|
return monitor->x11.output;
|
||||||
|
}
|
||||||
|
|
296
external/glfw/x11_platform.h
vendored
Normal file
296
external/glfw/x11_platform.h
vendored
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_x11_platform_h_
|
||||||
|
#define _glfw3_x11_platform_h_
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xcursor/Xcursor.h>
|
||||||
|
|
||||||
|
// The XRandR extension provides mode setting and gamma control
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
|
||||||
|
// The Xkb extension provides improved keyboard support
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
|
||||||
|
// The Xinerama extension provides legacy monitor indices
|
||||||
|
#include <X11/extensions/Xinerama.h>
|
||||||
|
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
// The Xf86VidMode extension provides fallback gamma control
|
||||||
|
#include <X11/extensions/xf86vmode.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef XID xcb_window_t;
|
||||||
|
typedef XID xcb_visualid_t;
|
||||||
|
typedef struct xcb_connection_t xcb_connection_t;
|
||||||
|
typedef xcb_connection_t* (* XGETXCBCONNECTION_T)(Display*);
|
||||||
|
|
||||||
|
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
|
||||||
|
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
|
||||||
|
|
||||||
|
typedef struct VkXlibSurfaceCreateInfoKHR
|
||||||
|
{
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkXlibSurfaceCreateFlagsKHR flags;
|
||||||
|
Display* dpy;
|
||||||
|
Window window;
|
||||||
|
} VkXlibSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef struct VkXcbSurfaceCreateInfoKHR
|
||||||
|
{
|
||||||
|
VkStructureType sType;
|
||||||
|
const void* pNext;
|
||||||
|
VkXcbSurfaceCreateFlagsKHR flags;
|
||||||
|
xcb_connection_t* connection;
|
||||||
|
xcb_window_t window;
|
||||||
|
} VkXcbSurfaceCreateInfoKHR;
|
||||||
|
|
||||||
|
typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||||
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID);
|
||||||
|
typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||||
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
|
||||||
|
|
||||||
|
#include "posix_tls.h"
|
||||||
|
#include "posix_time.h"
|
||||||
|
#include "linux_joystick.h"
|
||||||
|
#include "xkb_unicode.h"
|
||||||
|
#include "glx_context.h"
|
||||||
|
#include "egl_context.h"
|
||||||
|
|
||||||
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||||
|
#define _glfw_dlclose(handle) dlclose(handle)
|
||||||
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||||
|
|
||||||
|
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle)
|
||||||
|
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
|
||||||
|
|
||||||
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
||||||
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
||||||
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11
|
||||||
|
|
||||||
|
|
||||||
|
// X11-specific per-window data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWwindowX11
|
||||||
|
{
|
||||||
|
Colormap colormap;
|
||||||
|
Window handle;
|
||||||
|
XIC ic;
|
||||||
|
|
||||||
|
GLFWbool overrideRedirect;
|
||||||
|
|
||||||
|
// Cached position and size used to filter out duplicate events
|
||||||
|
int width, height;
|
||||||
|
int xpos, ypos;
|
||||||
|
|
||||||
|
// The last received cursor position, regardless of source
|
||||||
|
int lastCursorPosX, lastCursorPosY;
|
||||||
|
// The last position the cursor was warped to by GLFW
|
||||||
|
int warpCursorPosX, warpCursorPosY;
|
||||||
|
|
||||||
|
// The information from the last KeyPress event
|
||||||
|
unsigned int lastKeyCode;
|
||||||
|
Time lastKeyTime;
|
||||||
|
|
||||||
|
} _GLFWwindowX11;
|
||||||
|
|
||||||
|
// X11-specific global data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWlibraryX11
|
||||||
|
{
|
||||||
|
Display* display;
|
||||||
|
int screen;
|
||||||
|
Window root;
|
||||||
|
|
||||||
|
// Invisible cursor for hidden cursor mode
|
||||||
|
Cursor cursor;
|
||||||
|
// Context for mapping window XIDs to _GLFWwindow pointers
|
||||||
|
XContext context;
|
||||||
|
// XIM input method
|
||||||
|
XIM im;
|
||||||
|
// Most recent error code received by X error handler
|
||||||
|
int errorCode;
|
||||||
|
// Clipboard string (while the selection is owned)
|
||||||
|
char* clipboardString;
|
||||||
|
// Key name string
|
||||||
|
char keyName[64];
|
||||||
|
// X11 keycode to GLFW key LUT
|
||||||
|
short int publicKeys[256];
|
||||||
|
// GLFW key to X11 keycode LUT
|
||||||
|
short int nativeKeys[GLFW_KEY_LAST + 1];
|
||||||
|
// Where to place the cursor when re-enabled
|
||||||
|
double restoreCursorPosX, restoreCursorPosY;
|
||||||
|
// The window whose disabled cursor mode is active
|
||||||
|
_GLFWwindow* disabledCursorWindow;
|
||||||
|
|
||||||
|
// Window manager atoms
|
||||||
|
Atom WM_PROTOCOLS;
|
||||||
|
Atom WM_STATE;
|
||||||
|
Atom WM_DELETE_WINDOW;
|
||||||
|
Atom NET_WM_NAME;
|
||||||
|
Atom NET_WM_ICON_NAME;
|
||||||
|
Atom NET_WM_ICON;
|
||||||
|
Atom NET_WM_PID;
|
||||||
|
Atom NET_WM_PING;
|
||||||
|
Atom NET_WM_WINDOW_TYPE;
|
||||||
|
Atom NET_WM_WINDOW_TYPE_NORMAL;
|
||||||
|
Atom NET_WM_STATE;
|
||||||
|
Atom NET_WM_STATE_ABOVE;
|
||||||
|
Atom NET_WM_STATE_FULLSCREEN;
|
||||||
|
Atom NET_WM_STATE_MAXIMIZED_VERT;
|
||||||
|
Atom NET_WM_STATE_MAXIMIZED_HORZ;
|
||||||
|
Atom NET_WM_BYPASS_COMPOSITOR;
|
||||||
|
Atom NET_WM_FULLSCREEN_MONITORS;
|
||||||
|
Atom NET_ACTIVE_WINDOW;
|
||||||
|
Atom NET_FRAME_EXTENTS;
|
||||||
|
Atom NET_REQUEST_FRAME_EXTENTS;
|
||||||
|
Atom MOTIF_WM_HINTS;
|
||||||
|
|
||||||
|
// Xdnd (drag and drop) atoms
|
||||||
|
Atom XdndAware;
|
||||||
|
Atom XdndEnter;
|
||||||
|
Atom XdndPosition;
|
||||||
|
Atom XdndStatus;
|
||||||
|
Atom XdndActionCopy;
|
||||||
|
Atom XdndDrop;
|
||||||
|
Atom XdndLeave;
|
||||||
|
Atom XdndFinished;
|
||||||
|
Atom XdndSelection;
|
||||||
|
|
||||||
|
// Selection (clipboard) atoms
|
||||||
|
Atom TARGETS;
|
||||||
|
Atom MULTIPLE;
|
||||||
|
Atom CLIPBOARD;
|
||||||
|
Atom CLIPBOARD_MANAGER;
|
||||||
|
Atom SAVE_TARGETS;
|
||||||
|
Atom NULL_;
|
||||||
|
Atom UTF8_STRING;
|
||||||
|
Atom COMPOUND_STRING;
|
||||||
|
Atom ATOM_PAIR;
|
||||||
|
Atom GLFW_SELECTION;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GLFWbool available;
|
||||||
|
int eventBase;
|
||||||
|
int errorBase;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
GLFWbool gammaBroken;
|
||||||
|
GLFWbool monitorBroken;
|
||||||
|
} randr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GLFWbool available;
|
||||||
|
GLFWbool detectable;
|
||||||
|
int majorOpcode;
|
||||||
|
int eventBase;
|
||||||
|
int errorBase;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
} xkb;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int count;
|
||||||
|
int timeout;
|
||||||
|
int interval;
|
||||||
|
int blanking;
|
||||||
|
int exposure;
|
||||||
|
} saver;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Window source;
|
||||||
|
} xdnd;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
GLFWbool available;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
} xinerama;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
void* handle;
|
||||||
|
XGETXCBCONNECTION_T XGetXCBConnection;
|
||||||
|
} x11xcb;
|
||||||
|
|
||||||
|
#if defined(_GLFW_HAS_XF86VM)
|
||||||
|
struct {
|
||||||
|
GLFWbool available;
|
||||||
|
int eventBase;
|
||||||
|
int errorBase;
|
||||||
|
} vidmode;
|
||||||
|
#endif /*_GLFW_HAS_XF86VM*/
|
||||||
|
|
||||||
|
} _GLFWlibraryX11;
|
||||||
|
|
||||||
|
// X11-specific per-monitor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWmonitorX11
|
||||||
|
{
|
||||||
|
RROutput output;
|
||||||
|
RRCrtc crtc;
|
||||||
|
RRMode oldMode;
|
||||||
|
|
||||||
|
// Index of corresponding Xinerama screen,
|
||||||
|
// for EWMH full screen window placement
|
||||||
|
int index;
|
||||||
|
|
||||||
|
} _GLFWmonitorX11;
|
||||||
|
|
||||||
|
// X11-specific per-cursor data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWcursorX11
|
||||||
|
{
|
||||||
|
Cursor handle;
|
||||||
|
|
||||||
|
} _GLFWcursorX11;
|
||||||
|
|
||||||
|
|
||||||
|
GLFWbool _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||||
|
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
|
||||||
|
|
||||||
|
Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot);
|
||||||
|
|
||||||
|
unsigned long _glfwGetWindowPropertyX11(Window window,
|
||||||
|
Atom property,
|
||||||
|
Atom type,
|
||||||
|
unsigned char** value);
|
||||||
|
|
||||||
|
void _glfwGrabErrorHandlerX11(void);
|
||||||
|
void _glfwReleaseErrorHandlerX11(void);
|
||||||
|
void _glfwInputErrorX11(int error, const char* message);
|
||||||
|
|
||||||
|
#endif // _glfw3_x11_platform_h_
|
2475
external/glfw/x11_window.c
vendored
Normal file
2475
external/glfw/x11_window.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
889
external/glfw/xkb_unicode.c
vendored
Normal file
889
external/glfw/xkb_unicode.c
vendored
Normal file
@ -0,0 +1,889 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 X11 - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Marcus: This code was originally written by Markus G. Kuhn.
|
||||||
|
* I have made some slight changes (trimmed it down a bit from >60 KB to
|
||||||
|
* 20 KB), but the functionality is the same.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This module converts keysym values into the corresponding ISO 10646
|
||||||
|
* (UCS, Unicode) values.
|
||||||
|
*
|
||||||
|
* The array keysymtab[] contains pairs of X11 keysym values for graphical
|
||||||
|
* characters and the corresponding Unicode value. The function
|
||||||
|
* _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary
|
||||||
|
* search, therefore keysymtab[] must remain SORTED by keysym value.
|
||||||
|
*
|
||||||
|
* We allow to represent any UCS character in the range U-00000000 to
|
||||||
|
* U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
|
||||||
|
* This admittedly does not cover the entire 31-bit space of UCS, but
|
||||||
|
* it does cover all of the characters up to U-10FFFF, which can be
|
||||||
|
* represented by UTF-16, and more, and it is very unlikely that higher
|
||||||
|
* UCS codes will ever be assigned by ISO. So to get Unicode character
|
||||||
|
* U+ABCD you can directly use keysym 0x0100abcd.
|
||||||
|
*
|
||||||
|
* Original author: Markus G. Kuhn <mkuhn@acm.org>, University of
|
||||||
|
* Cambridge, April 2001
|
||||||
|
*
|
||||||
|
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
|
||||||
|
* an initial draft of the mapping table.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//************************************************************************
|
||||||
|
//**** KeySym to Unicode mapping table ****
|
||||||
|
//************************************************************************
|
||||||
|
|
||||||
|
static const struct codepair {
|
||||||
|
unsigned short keysym;
|
||||||
|
unsigned short ucs;
|
||||||
|
} keysymtab[] = {
|
||||||
|
{ 0x01a1, 0x0104 },
|
||||||
|
{ 0x01a2, 0x02d8 },
|
||||||
|
{ 0x01a3, 0x0141 },
|
||||||
|
{ 0x01a5, 0x013d },
|
||||||
|
{ 0x01a6, 0x015a },
|
||||||
|
{ 0x01a9, 0x0160 },
|
||||||
|
{ 0x01aa, 0x015e },
|
||||||
|
{ 0x01ab, 0x0164 },
|
||||||
|
{ 0x01ac, 0x0179 },
|
||||||
|
{ 0x01ae, 0x017d },
|
||||||
|
{ 0x01af, 0x017b },
|
||||||
|
{ 0x01b1, 0x0105 },
|
||||||
|
{ 0x01b2, 0x02db },
|
||||||
|
{ 0x01b3, 0x0142 },
|
||||||
|
{ 0x01b5, 0x013e },
|
||||||
|
{ 0x01b6, 0x015b },
|
||||||
|
{ 0x01b7, 0x02c7 },
|
||||||
|
{ 0x01b9, 0x0161 },
|
||||||
|
{ 0x01ba, 0x015f },
|
||||||
|
{ 0x01bb, 0x0165 },
|
||||||
|
{ 0x01bc, 0x017a },
|
||||||
|
{ 0x01bd, 0x02dd },
|
||||||
|
{ 0x01be, 0x017e },
|
||||||
|
{ 0x01bf, 0x017c },
|
||||||
|
{ 0x01c0, 0x0154 },
|
||||||
|
{ 0x01c3, 0x0102 },
|
||||||
|
{ 0x01c5, 0x0139 },
|
||||||
|
{ 0x01c6, 0x0106 },
|
||||||
|
{ 0x01c8, 0x010c },
|
||||||
|
{ 0x01ca, 0x0118 },
|
||||||
|
{ 0x01cc, 0x011a },
|
||||||
|
{ 0x01cf, 0x010e },
|
||||||
|
{ 0x01d0, 0x0110 },
|
||||||
|
{ 0x01d1, 0x0143 },
|
||||||
|
{ 0x01d2, 0x0147 },
|
||||||
|
{ 0x01d5, 0x0150 },
|
||||||
|
{ 0x01d8, 0x0158 },
|
||||||
|
{ 0x01d9, 0x016e },
|
||||||
|
{ 0x01db, 0x0170 },
|
||||||
|
{ 0x01de, 0x0162 },
|
||||||
|
{ 0x01e0, 0x0155 },
|
||||||
|
{ 0x01e3, 0x0103 },
|
||||||
|
{ 0x01e5, 0x013a },
|
||||||
|
{ 0x01e6, 0x0107 },
|
||||||
|
{ 0x01e8, 0x010d },
|
||||||
|
{ 0x01ea, 0x0119 },
|
||||||
|
{ 0x01ec, 0x011b },
|
||||||
|
{ 0x01ef, 0x010f },
|
||||||
|
{ 0x01f0, 0x0111 },
|
||||||
|
{ 0x01f1, 0x0144 },
|
||||||
|
{ 0x01f2, 0x0148 },
|
||||||
|
{ 0x01f5, 0x0151 },
|
||||||
|
{ 0x01f8, 0x0159 },
|
||||||
|
{ 0x01f9, 0x016f },
|
||||||
|
{ 0x01fb, 0x0171 },
|
||||||
|
{ 0x01fe, 0x0163 },
|
||||||
|
{ 0x01ff, 0x02d9 },
|
||||||
|
{ 0x02a1, 0x0126 },
|
||||||
|
{ 0x02a6, 0x0124 },
|
||||||
|
{ 0x02a9, 0x0130 },
|
||||||
|
{ 0x02ab, 0x011e },
|
||||||
|
{ 0x02ac, 0x0134 },
|
||||||
|
{ 0x02b1, 0x0127 },
|
||||||
|
{ 0x02b6, 0x0125 },
|
||||||
|
{ 0x02b9, 0x0131 },
|
||||||
|
{ 0x02bb, 0x011f },
|
||||||
|
{ 0x02bc, 0x0135 },
|
||||||
|
{ 0x02c5, 0x010a },
|
||||||
|
{ 0x02c6, 0x0108 },
|
||||||
|
{ 0x02d5, 0x0120 },
|
||||||
|
{ 0x02d8, 0x011c },
|
||||||
|
{ 0x02dd, 0x016c },
|
||||||
|
{ 0x02de, 0x015c },
|
||||||
|
{ 0x02e5, 0x010b },
|
||||||
|
{ 0x02e6, 0x0109 },
|
||||||
|
{ 0x02f5, 0x0121 },
|
||||||
|
{ 0x02f8, 0x011d },
|
||||||
|
{ 0x02fd, 0x016d },
|
||||||
|
{ 0x02fe, 0x015d },
|
||||||
|
{ 0x03a2, 0x0138 },
|
||||||
|
{ 0x03a3, 0x0156 },
|
||||||
|
{ 0x03a5, 0x0128 },
|
||||||
|
{ 0x03a6, 0x013b },
|
||||||
|
{ 0x03aa, 0x0112 },
|
||||||
|
{ 0x03ab, 0x0122 },
|
||||||
|
{ 0x03ac, 0x0166 },
|
||||||
|
{ 0x03b3, 0x0157 },
|
||||||
|
{ 0x03b5, 0x0129 },
|
||||||
|
{ 0x03b6, 0x013c },
|
||||||
|
{ 0x03ba, 0x0113 },
|
||||||
|
{ 0x03bb, 0x0123 },
|
||||||
|
{ 0x03bc, 0x0167 },
|
||||||
|
{ 0x03bd, 0x014a },
|
||||||
|
{ 0x03bf, 0x014b },
|
||||||
|
{ 0x03c0, 0x0100 },
|
||||||
|
{ 0x03c7, 0x012e },
|
||||||
|
{ 0x03cc, 0x0116 },
|
||||||
|
{ 0x03cf, 0x012a },
|
||||||
|
{ 0x03d1, 0x0145 },
|
||||||
|
{ 0x03d2, 0x014c },
|
||||||
|
{ 0x03d3, 0x0136 },
|
||||||
|
{ 0x03d9, 0x0172 },
|
||||||
|
{ 0x03dd, 0x0168 },
|
||||||
|
{ 0x03de, 0x016a },
|
||||||
|
{ 0x03e0, 0x0101 },
|
||||||
|
{ 0x03e7, 0x012f },
|
||||||
|
{ 0x03ec, 0x0117 },
|
||||||
|
{ 0x03ef, 0x012b },
|
||||||
|
{ 0x03f1, 0x0146 },
|
||||||
|
{ 0x03f2, 0x014d },
|
||||||
|
{ 0x03f3, 0x0137 },
|
||||||
|
{ 0x03f9, 0x0173 },
|
||||||
|
{ 0x03fd, 0x0169 },
|
||||||
|
{ 0x03fe, 0x016b },
|
||||||
|
{ 0x047e, 0x203e },
|
||||||
|
{ 0x04a1, 0x3002 },
|
||||||
|
{ 0x04a2, 0x300c },
|
||||||
|
{ 0x04a3, 0x300d },
|
||||||
|
{ 0x04a4, 0x3001 },
|
||||||
|
{ 0x04a5, 0x30fb },
|
||||||
|
{ 0x04a6, 0x30f2 },
|
||||||
|
{ 0x04a7, 0x30a1 },
|
||||||
|
{ 0x04a8, 0x30a3 },
|
||||||
|
{ 0x04a9, 0x30a5 },
|
||||||
|
{ 0x04aa, 0x30a7 },
|
||||||
|
{ 0x04ab, 0x30a9 },
|
||||||
|
{ 0x04ac, 0x30e3 },
|
||||||
|
{ 0x04ad, 0x30e5 },
|
||||||
|
{ 0x04ae, 0x30e7 },
|
||||||
|
{ 0x04af, 0x30c3 },
|
||||||
|
{ 0x04b0, 0x30fc },
|
||||||
|
{ 0x04b1, 0x30a2 },
|
||||||
|
{ 0x04b2, 0x30a4 },
|
||||||
|
{ 0x04b3, 0x30a6 },
|
||||||
|
{ 0x04b4, 0x30a8 },
|
||||||
|
{ 0x04b5, 0x30aa },
|
||||||
|
{ 0x04b6, 0x30ab },
|
||||||
|
{ 0x04b7, 0x30ad },
|
||||||
|
{ 0x04b8, 0x30af },
|
||||||
|
{ 0x04b9, 0x30b1 },
|
||||||
|
{ 0x04ba, 0x30b3 },
|
||||||
|
{ 0x04bb, 0x30b5 },
|
||||||
|
{ 0x04bc, 0x30b7 },
|
||||||
|
{ 0x04bd, 0x30b9 },
|
||||||
|
{ 0x04be, 0x30bb },
|
||||||
|
{ 0x04bf, 0x30bd },
|
||||||
|
{ 0x04c0, 0x30bf },
|
||||||
|
{ 0x04c1, 0x30c1 },
|
||||||
|
{ 0x04c2, 0x30c4 },
|
||||||
|
{ 0x04c3, 0x30c6 },
|
||||||
|
{ 0x04c4, 0x30c8 },
|
||||||
|
{ 0x04c5, 0x30ca },
|
||||||
|
{ 0x04c6, 0x30cb },
|
||||||
|
{ 0x04c7, 0x30cc },
|
||||||
|
{ 0x04c8, 0x30cd },
|
||||||
|
{ 0x04c9, 0x30ce },
|
||||||
|
{ 0x04ca, 0x30cf },
|
||||||
|
{ 0x04cb, 0x30d2 },
|
||||||
|
{ 0x04cc, 0x30d5 },
|
||||||
|
{ 0x04cd, 0x30d8 },
|
||||||
|
{ 0x04ce, 0x30db },
|
||||||
|
{ 0x04cf, 0x30de },
|
||||||
|
{ 0x04d0, 0x30df },
|
||||||
|
{ 0x04d1, 0x30e0 },
|
||||||
|
{ 0x04d2, 0x30e1 },
|
||||||
|
{ 0x04d3, 0x30e2 },
|
||||||
|
{ 0x04d4, 0x30e4 },
|
||||||
|
{ 0x04d5, 0x30e6 },
|
||||||
|
{ 0x04d6, 0x30e8 },
|
||||||
|
{ 0x04d7, 0x30e9 },
|
||||||
|
{ 0x04d8, 0x30ea },
|
||||||
|
{ 0x04d9, 0x30eb },
|
||||||
|
{ 0x04da, 0x30ec },
|
||||||
|
{ 0x04db, 0x30ed },
|
||||||
|
{ 0x04dc, 0x30ef },
|
||||||
|
{ 0x04dd, 0x30f3 },
|
||||||
|
{ 0x04de, 0x309b },
|
||||||
|
{ 0x04df, 0x309c },
|
||||||
|
{ 0x05ac, 0x060c },
|
||||||
|
{ 0x05bb, 0x061b },
|
||||||
|
{ 0x05bf, 0x061f },
|
||||||
|
{ 0x05c1, 0x0621 },
|
||||||
|
{ 0x05c2, 0x0622 },
|
||||||
|
{ 0x05c3, 0x0623 },
|
||||||
|
{ 0x05c4, 0x0624 },
|
||||||
|
{ 0x05c5, 0x0625 },
|
||||||
|
{ 0x05c6, 0x0626 },
|
||||||
|
{ 0x05c7, 0x0627 },
|
||||||
|
{ 0x05c8, 0x0628 },
|
||||||
|
{ 0x05c9, 0x0629 },
|
||||||
|
{ 0x05ca, 0x062a },
|
||||||
|
{ 0x05cb, 0x062b },
|
||||||
|
{ 0x05cc, 0x062c },
|
||||||
|
{ 0x05cd, 0x062d },
|
||||||
|
{ 0x05ce, 0x062e },
|
||||||
|
{ 0x05cf, 0x062f },
|
||||||
|
{ 0x05d0, 0x0630 },
|
||||||
|
{ 0x05d1, 0x0631 },
|
||||||
|
{ 0x05d2, 0x0632 },
|
||||||
|
{ 0x05d3, 0x0633 },
|
||||||
|
{ 0x05d4, 0x0634 },
|
||||||
|
{ 0x05d5, 0x0635 },
|
||||||
|
{ 0x05d6, 0x0636 },
|
||||||
|
{ 0x05d7, 0x0637 },
|
||||||
|
{ 0x05d8, 0x0638 },
|
||||||
|
{ 0x05d9, 0x0639 },
|
||||||
|
{ 0x05da, 0x063a },
|
||||||
|
{ 0x05e0, 0x0640 },
|
||||||
|
{ 0x05e1, 0x0641 },
|
||||||
|
{ 0x05e2, 0x0642 },
|
||||||
|
{ 0x05e3, 0x0643 },
|
||||||
|
{ 0x05e4, 0x0644 },
|
||||||
|
{ 0x05e5, 0x0645 },
|
||||||
|
{ 0x05e6, 0x0646 },
|
||||||
|
{ 0x05e7, 0x0647 },
|
||||||
|
{ 0x05e8, 0x0648 },
|
||||||
|
{ 0x05e9, 0x0649 },
|
||||||
|
{ 0x05ea, 0x064a },
|
||||||
|
{ 0x05eb, 0x064b },
|
||||||
|
{ 0x05ec, 0x064c },
|
||||||
|
{ 0x05ed, 0x064d },
|
||||||
|
{ 0x05ee, 0x064e },
|
||||||
|
{ 0x05ef, 0x064f },
|
||||||
|
{ 0x05f0, 0x0650 },
|
||||||
|
{ 0x05f1, 0x0651 },
|
||||||
|
{ 0x05f2, 0x0652 },
|
||||||
|
{ 0x06a1, 0x0452 },
|
||||||
|
{ 0x06a2, 0x0453 },
|
||||||
|
{ 0x06a3, 0x0451 },
|
||||||
|
{ 0x06a4, 0x0454 },
|
||||||
|
{ 0x06a5, 0x0455 },
|
||||||
|
{ 0x06a6, 0x0456 },
|
||||||
|
{ 0x06a7, 0x0457 },
|
||||||
|
{ 0x06a8, 0x0458 },
|
||||||
|
{ 0x06a9, 0x0459 },
|
||||||
|
{ 0x06aa, 0x045a },
|
||||||
|
{ 0x06ab, 0x045b },
|
||||||
|
{ 0x06ac, 0x045c },
|
||||||
|
{ 0x06ae, 0x045e },
|
||||||
|
{ 0x06af, 0x045f },
|
||||||
|
{ 0x06b0, 0x2116 },
|
||||||
|
{ 0x06b1, 0x0402 },
|
||||||
|
{ 0x06b2, 0x0403 },
|
||||||
|
{ 0x06b3, 0x0401 },
|
||||||
|
{ 0x06b4, 0x0404 },
|
||||||
|
{ 0x06b5, 0x0405 },
|
||||||
|
{ 0x06b6, 0x0406 },
|
||||||
|
{ 0x06b7, 0x0407 },
|
||||||
|
{ 0x06b8, 0x0408 },
|
||||||
|
{ 0x06b9, 0x0409 },
|
||||||
|
{ 0x06ba, 0x040a },
|
||||||
|
{ 0x06bb, 0x040b },
|
||||||
|
{ 0x06bc, 0x040c },
|
||||||
|
{ 0x06be, 0x040e },
|
||||||
|
{ 0x06bf, 0x040f },
|
||||||
|
{ 0x06c0, 0x044e },
|
||||||
|
{ 0x06c1, 0x0430 },
|
||||||
|
{ 0x06c2, 0x0431 },
|
||||||
|
{ 0x06c3, 0x0446 },
|
||||||
|
{ 0x06c4, 0x0434 },
|
||||||
|
{ 0x06c5, 0x0435 },
|
||||||
|
{ 0x06c6, 0x0444 },
|
||||||
|
{ 0x06c7, 0x0433 },
|
||||||
|
{ 0x06c8, 0x0445 },
|
||||||
|
{ 0x06c9, 0x0438 },
|
||||||
|
{ 0x06ca, 0x0439 },
|
||||||
|
{ 0x06cb, 0x043a },
|
||||||
|
{ 0x06cc, 0x043b },
|
||||||
|
{ 0x06cd, 0x043c },
|
||||||
|
{ 0x06ce, 0x043d },
|
||||||
|
{ 0x06cf, 0x043e },
|
||||||
|
{ 0x06d0, 0x043f },
|
||||||
|
{ 0x06d1, 0x044f },
|
||||||
|
{ 0x06d2, 0x0440 },
|
||||||
|
{ 0x06d3, 0x0441 },
|
||||||
|
{ 0x06d4, 0x0442 },
|
||||||
|
{ 0x06d5, 0x0443 },
|
||||||
|
{ 0x06d6, 0x0436 },
|
||||||
|
{ 0x06d7, 0x0432 },
|
||||||
|
{ 0x06d8, 0x044c },
|
||||||
|
{ 0x06d9, 0x044b },
|
||||||
|
{ 0x06da, 0x0437 },
|
||||||
|
{ 0x06db, 0x0448 },
|
||||||
|
{ 0x06dc, 0x044d },
|
||||||
|
{ 0x06dd, 0x0449 },
|
||||||
|
{ 0x06de, 0x0447 },
|
||||||
|
{ 0x06df, 0x044a },
|
||||||
|
{ 0x06e0, 0x042e },
|
||||||
|
{ 0x06e1, 0x0410 },
|
||||||
|
{ 0x06e2, 0x0411 },
|
||||||
|
{ 0x06e3, 0x0426 },
|
||||||
|
{ 0x06e4, 0x0414 },
|
||||||
|
{ 0x06e5, 0x0415 },
|
||||||
|
{ 0x06e6, 0x0424 },
|
||||||
|
{ 0x06e7, 0x0413 },
|
||||||
|
{ 0x06e8, 0x0425 },
|
||||||
|
{ 0x06e9, 0x0418 },
|
||||||
|
{ 0x06ea, 0x0419 },
|
||||||
|
{ 0x06eb, 0x041a },
|
||||||
|
{ 0x06ec, 0x041b },
|
||||||
|
{ 0x06ed, 0x041c },
|
||||||
|
{ 0x06ee, 0x041d },
|
||||||
|
{ 0x06ef, 0x041e },
|
||||||
|
{ 0x06f0, 0x041f },
|
||||||
|
{ 0x06f1, 0x042f },
|
||||||
|
{ 0x06f2, 0x0420 },
|
||||||
|
{ 0x06f3, 0x0421 },
|
||||||
|
{ 0x06f4, 0x0422 },
|
||||||
|
{ 0x06f5, 0x0423 },
|
||||||
|
{ 0x06f6, 0x0416 },
|
||||||
|
{ 0x06f7, 0x0412 },
|
||||||
|
{ 0x06f8, 0x042c },
|
||||||
|
{ 0x06f9, 0x042b },
|
||||||
|
{ 0x06fa, 0x0417 },
|
||||||
|
{ 0x06fb, 0x0428 },
|
||||||
|
{ 0x06fc, 0x042d },
|
||||||
|
{ 0x06fd, 0x0429 },
|
||||||
|
{ 0x06fe, 0x0427 },
|
||||||
|
{ 0x06ff, 0x042a },
|
||||||
|
{ 0x07a1, 0x0386 },
|
||||||
|
{ 0x07a2, 0x0388 },
|
||||||
|
{ 0x07a3, 0x0389 },
|
||||||
|
{ 0x07a4, 0x038a },
|
||||||
|
{ 0x07a5, 0x03aa },
|
||||||
|
{ 0x07a7, 0x038c },
|
||||||
|
{ 0x07a8, 0x038e },
|
||||||
|
{ 0x07a9, 0x03ab },
|
||||||
|
{ 0x07ab, 0x038f },
|
||||||
|
{ 0x07ae, 0x0385 },
|
||||||
|
{ 0x07af, 0x2015 },
|
||||||
|
{ 0x07b1, 0x03ac },
|
||||||
|
{ 0x07b2, 0x03ad },
|
||||||
|
{ 0x07b3, 0x03ae },
|
||||||
|
{ 0x07b4, 0x03af },
|
||||||
|
{ 0x07b5, 0x03ca },
|
||||||
|
{ 0x07b6, 0x0390 },
|
||||||
|
{ 0x07b7, 0x03cc },
|
||||||
|
{ 0x07b8, 0x03cd },
|
||||||
|
{ 0x07b9, 0x03cb },
|
||||||
|
{ 0x07ba, 0x03b0 },
|
||||||
|
{ 0x07bb, 0x03ce },
|
||||||
|
{ 0x07c1, 0x0391 },
|
||||||
|
{ 0x07c2, 0x0392 },
|
||||||
|
{ 0x07c3, 0x0393 },
|
||||||
|
{ 0x07c4, 0x0394 },
|
||||||
|
{ 0x07c5, 0x0395 },
|
||||||
|
{ 0x07c6, 0x0396 },
|
||||||
|
{ 0x07c7, 0x0397 },
|
||||||
|
{ 0x07c8, 0x0398 },
|
||||||
|
{ 0x07c9, 0x0399 },
|
||||||
|
{ 0x07ca, 0x039a },
|
||||||
|
{ 0x07cb, 0x039b },
|
||||||
|
{ 0x07cc, 0x039c },
|
||||||
|
{ 0x07cd, 0x039d },
|
||||||
|
{ 0x07ce, 0x039e },
|
||||||
|
{ 0x07cf, 0x039f },
|
||||||
|
{ 0x07d0, 0x03a0 },
|
||||||
|
{ 0x07d1, 0x03a1 },
|
||||||
|
{ 0x07d2, 0x03a3 },
|
||||||
|
{ 0x07d4, 0x03a4 },
|
||||||
|
{ 0x07d5, 0x03a5 },
|
||||||
|
{ 0x07d6, 0x03a6 },
|
||||||
|
{ 0x07d7, 0x03a7 },
|
||||||
|
{ 0x07d8, 0x03a8 },
|
||||||
|
{ 0x07d9, 0x03a9 },
|
||||||
|
{ 0x07e1, 0x03b1 },
|
||||||
|
{ 0x07e2, 0x03b2 },
|
||||||
|
{ 0x07e3, 0x03b3 },
|
||||||
|
{ 0x07e4, 0x03b4 },
|
||||||
|
{ 0x07e5, 0x03b5 },
|
||||||
|
{ 0x07e6, 0x03b6 },
|
||||||
|
{ 0x07e7, 0x03b7 },
|
||||||
|
{ 0x07e8, 0x03b8 },
|
||||||
|
{ 0x07e9, 0x03b9 },
|
||||||
|
{ 0x07ea, 0x03ba },
|
||||||
|
{ 0x07eb, 0x03bb },
|
||||||
|
{ 0x07ec, 0x03bc },
|
||||||
|
{ 0x07ed, 0x03bd },
|
||||||
|
{ 0x07ee, 0x03be },
|
||||||
|
{ 0x07ef, 0x03bf },
|
||||||
|
{ 0x07f0, 0x03c0 },
|
||||||
|
{ 0x07f1, 0x03c1 },
|
||||||
|
{ 0x07f2, 0x03c3 },
|
||||||
|
{ 0x07f3, 0x03c2 },
|
||||||
|
{ 0x07f4, 0x03c4 },
|
||||||
|
{ 0x07f5, 0x03c5 },
|
||||||
|
{ 0x07f6, 0x03c6 },
|
||||||
|
{ 0x07f7, 0x03c7 },
|
||||||
|
{ 0x07f8, 0x03c8 },
|
||||||
|
{ 0x07f9, 0x03c9 },
|
||||||
|
{ 0x08a1, 0x23b7 },
|
||||||
|
{ 0x08a2, 0x250c },
|
||||||
|
{ 0x08a3, 0x2500 },
|
||||||
|
{ 0x08a4, 0x2320 },
|
||||||
|
{ 0x08a5, 0x2321 },
|
||||||
|
{ 0x08a6, 0x2502 },
|
||||||
|
{ 0x08a7, 0x23a1 },
|
||||||
|
{ 0x08a8, 0x23a3 },
|
||||||
|
{ 0x08a9, 0x23a4 },
|
||||||
|
{ 0x08aa, 0x23a6 },
|
||||||
|
{ 0x08ab, 0x239b },
|
||||||
|
{ 0x08ac, 0x239d },
|
||||||
|
{ 0x08ad, 0x239e },
|
||||||
|
{ 0x08ae, 0x23a0 },
|
||||||
|
{ 0x08af, 0x23a8 },
|
||||||
|
{ 0x08b0, 0x23ac },
|
||||||
|
{ 0x08bc, 0x2264 },
|
||||||
|
{ 0x08bd, 0x2260 },
|
||||||
|
{ 0x08be, 0x2265 },
|
||||||
|
{ 0x08bf, 0x222b },
|
||||||
|
{ 0x08c0, 0x2234 },
|
||||||
|
{ 0x08c1, 0x221d },
|
||||||
|
{ 0x08c2, 0x221e },
|
||||||
|
{ 0x08c5, 0x2207 },
|
||||||
|
{ 0x08c8, 0x223c },
|
||||||
|
{ 0x08c9, 0x2243 },
|
||||||
|
{ 0x08cd, 0x21d4 },
|
||||||
|
{ 0x08ce, 0x21d2 },
|
||||||
|
{ 0x08cf, 0x2261 },
|
||||||
|
{ 0x08d6, 0x221a },
|
||||||
|
{ 0x08da, 0x2282 },
|
||||||
|
{ 0x08db, 0x2283 },
|
||||||
|
{ 0x08dc, 0x2229 },
|
||||||
|
{ 0x08dd, 0x222a },
|
||||||
|
{ 0x08de, 0x2227 },
|
||||||
|
{ 0x08df, 0x2228 },
|
||||||
|
{ 0x08ef, 0x2202 },
|
||||||
|
{ 0x08f6, 0x0192 },
|
||||||
|
{ 0x08fb, 0x2190 },
|
||||||
|
{ 0x08fc, 0x2191 },
|
||||||
|
{ 0x08fd, 0x2192 },
|
||||||
|
{ 0x08fe, 0x2193 },
|
||||||
|
{ 0x09e0, 0x25c6 },
|
||||||
|
{ 0x09e1, 0x2592 },
|
||||||
|
{ 0x09e2, 0x2409 },
|
||||||
|
{ 0x09e3, 0x240c },
|
||||||
|
{ 0x09e4, 0x240d },
|
||||||
|
{ 0x09e5, 0x240a },
|
||||||
|
{ 0x09e8, 0x2424 },
|
||||||
|
{ 0x09e9, 0x240b },
|
||||||
|
{ 0x09ea, 0x2518 },
|
||||||
|
{ 0x09eb, 0x2510 },
|
||||||
|
{ 0x09ec, 0x250c },
|
||||||
|
{ 0x09ed, 0x2514 },
|
||||||
|
{ 0x09ee, 0x253c },
|
||||||
|
{ 0x09ef, 0x23ba },
|
||||||
|
{ 0x09f0, 0x23bb },
|
||||||
|
{ 0x09f1, 0x2500 },
|
||||||
|
{ 0x09f2, 0x23bc },
|
||||||
|
{ 0x09f3, 0x23bd },
|
||||||
|
{ 0x09f4, 0x251c },
|
||||||
|
{ 0x09f5, 0x2524 },
|
||||||
|
{ 0x09f6, 0x2534 },
|
||||||
|
{ 0x09f7, 0x252c },
|
||||||
|
{ 0x09f8, 0x2502 },
|
||||||
|
{ 0x0aa1, 0x2003 },
|
||||||
|
{ 0x0aa2, 0x2002 },
|
||||||
|
{ 0x0aa3, 0x2004 },
|
||||||
|
{ 0x0aa4, 0x2005 },
|
||||||
|
{ 0x0aa5, 0x2007 },
|
||||||
|
{ 0x0aa6, 0x2008 },
|
||||||
|
{ 0x0aa7, 0x2009 },
|
||||||
|
{ 0x0aa8, 0x200a },
|
||||||
|
{ 0x0aa9, 0x2014 },
|
||||||
|
{ 0x0aaa, 0x2013 },
|
||||||
|
{ 0x0aae, 0x2026 },
|
||||||
|
{ 0x0aaf, 0x2025 },
|
||||||
|
{ 0x0ab0, 0x2153 },
|
||||||
|
{ 0x0ab1, 0x2154 },
|
||||||
|
{ 0x0ab2, 0x2155 },
|
||||||
|
{ 0x0ab3, 0x2156 },
|
||||||
|
{ 0x0ab4, 0x2157 },
|
||||||
|
{ 0x0ab5, 0x2158 },
|
||||||
|
{ 0x0ab6, 0x2159 },
|
||||||
|
{ 0x0ab7, 0x215a },
|
||||||
|
{ 0x0ab8, 0x2105 },
|
||||||
|
{ 0x0abb, 0x2012 },
|
||||||
|
{ 0x0abc, 0x2329 },
|
||||||
|
{ 0x0abe, 0x232a },
|
||||||
|
{ 0x0ac3, 0x215b },
|
||||||
|
{ 0x0ac4, 0x215c },
|
||||||
|
{ 0x0ac5, 0x215d },
|
||||||
|
{ 0x0ac6, 0x215e },
|
||||||
|
{ 0x0ac9, 0x2122 },
|
||||||
|
{ 0x0aca, 0x2613 },
|
||||||
|
{ 0x0acc, 0x25c1 },
|
||||||
|
{ 0x0acd, 0x25b7 },
|
||||||
|
{ 0x0ace, 0x25cb },
|
||||||
|
{ 0x0acf, 0x25af },
|
||||||
|
{ 0x0ad0, 0x2018 },
|
||||||
|
{ 0x0ad1, 0x2019 },
|
||||||
|
{ 0x0ad2, 0x201c },
|
||||||
|
{ 0x0ad3, 0x201d },
|
||||||
|
{ 0x0ad4, 0x211e },
|
||||||
|
{ 0x0ad6, 0x2032 },
|
||||||
|
{ 0x0ad7, 0x2033 },
|
||||||
|
{ 0x0ad9, 0x271d },
|
||||||
|
{ 0x0adb, 0x25ac },
|
||||||
|
{ 0x0adc, 0x25c0 },
|
||||||
|
{ 0x0add, 0x25b6 },
|
||||||
|
{ 0x0ade, 0x25cf },
|
||||||
|
{ 0x0adf, 0x25ae },
|
||||||
|
{ 0x0ae0, 0x25e6 },
|
||||||
|
{ 0x0ae1, 0x25ab },
|
||||||
|
{ 0x0ae2, 0x25ad },
|
||||||
|
{ 0x0ae3, 0x25b3 },
|
||||||
|
{ 0x0ae4, 0x25bd },
|
||||||
|
{ 0x0ae5, 0x2606 },
|
||||||
|
{ 0x0ae6, 0x2022 },
|
||||||
|
{ 0x0ae7, 0x25aa },
|
||||||
|
{ 0x0ae8, 0x25b2 },
|
||||||
|
{ 0x0ae9, 0x25bc },
|
||||||
|
{ 0x0aea, 0x261c },
|
||||||
|
{ 0x0aeb, 0x261e },
|
||||||
|
{ 0x0aec, 0x2663 },
|
||||||
|
{ 0x0aed, 0x2666 },
|
||||||
|
{ 0x0aee, 0x2665 },
|
||||||
|
{ 0x0af0, 0x2720 },
|
||||||
|
{ 0x0af1, 0x2020 },
|
||||||
|
{ 0x0af2, 0x2021 },
|
||||||
|
{ 0x0af3, 0x2713 },
|
||||||
|
{ 0x0af4, 0x2717 },
|
||||||
|
{ 0x0af5, 0x266f },
|
||||||
|
{ 0x0af6, 0x266d },
|
||||||
|
{ 0x0af7, 0x2642 },
|
||||||
|
{ 0x0af8, 0x2640 },
|
||||||
|
{ 0x0af9, 0x260e },
|
||||||
|
{ 0x0afa, 0x2315 },
|
||||||
|
{ 0x0afb, 0x2117 },
|
||||||
|
{ 0x0afc, 0x2038 },
|
||||||
|
{ 0x0afd, 0x201a },
|
||||||
|
{ 0x0afe, 0x201e },
|
||||||
|
{ 0x0ba3, 0x003c },
|
||||||
|
{ 0x0ba6, 0x003e },
|
||||||
|
{ 0x0ba8, 0x2228 },
|
||||||
|
{ 0x0ba9, 0x2227 },
|
||||||
|
{ 0x0bc0, 0x00af },
|
||||||
|
{ 0x0bc2, 0x22a5 },
|
||||||
|
{ 0x0bc3, 0x2229 },
|
||||||
|
{ 0x0bc4, 0x230a },
|
||||||
|
{ 0x0bc6, 0x005f },
|
||||||
|
{ 0x0bca, 0x2218 },
|
||||||
|
{ 0x0bcc, 0x2395 },
|
||||||
|
{ 0x0bce, 0x22a4 },
|
||||||
|
{ 0x0bcf, 0x25cb },
|
||||||
|
{ 0x0bd3, 0x2308 },
|
||||||
|
{ 0x0bd6, 0x222a },
|
||||||
|
{ 0x0bd8, 0x2283 },
|
||||||
|
{ 0x0bda, 0x2282 },
|
||||||
|
{ 0x0bdc, 0x22a2 },
|
||||||
|
{ 0x0bfc, 0x22a3 },
|
||||||
|
{ 0x0cdf, 0x2017 },
|
||||||
|
{ 0x0ce0, 0x05d0 },
|
||||||
|
{ 0x0ce1, 0x05d1 },
|
||||||
|
{ 0x0ce2, 0x05d2 },
|
||||||
|
{ 0x0ce3, 0x05d3 },
|
||||||
|
{ 0x0ce4, 0x05d4 },
|
||||||
|
{ 0x0ce5, 0x05d5 },
|
||||||
|
{ 0x0ce6, 0x05d6 },
|
||||||
|
{ 0x0ce7, 0x05d7 },
|
||||||
|
{ 0x0ce8, 0x05d8 },
|
||||||
|
{ 0x0ce9, 0x05d9 },
|
||||||
|
{ 0x0cea, 0x05da },
|
||||||
|
{ 0x0ceb, 0x05db },
|
||||||
|
{ 0x0cec, 0x05dc },
|
||||||
|
{ 0x0ced, 0x05dd },
|
||||||
|
{ 0x0cee, 0x05de },
|
||||||
|
{ 0x0cef, 0x05df },
|
||||||
|
{ 0x0cf0, 0x05e0 },
|
||||||
|
{ 0x0cf1, 0x05e1 },
|
||||||
|
{ 0x0cf2, 0x05e2 },
|
||||||
|
{ 0x0cf3, 0x05e3 },
|
||||||
|
{ 0x0cf4, 0x05e4 },
|
||||||
|
{ 0x0cf5, 0x05e5 },
|
||||||
|
{ 0x0cf6, 0x05e6 },
|
||||||
|
{ 0x0cf7, 0x05e7 },
|
||||||
|
{ 0x0cf8, 0x05e8 },
|
||||||
|
{ 0x0cf9, 0x05e9 },
|
||||||
|
{ 0x0cfa, 0x05ea },
|
||||||
|
{ 0x0da1, 0x0e01 },
|
||||||
|
{ 0x0da2, 0x0e02 },
|
||||||
|
{ 0x0da3, 0x0e03 },
|
||||||
|
{ 0x0da4, 0x0e04 },
|
||||||
|
{ 0x0da5, 0x0e05 },
|
||||||
|
{ 0x0da6, 0x0e06 },
|
||||||
|
{ 0x0da7, 0x0e07 },
|
||||||
|
{ 0x0da8, 0x0e08 },
|
||||||
|
{ 0x0da9, 0x0e09 },
|
||||||
|
{ 0x0daa, 0x0e0a },
|
||||||
|
{ 0x0dab, 0x0e0b },
|
||||||
|
{ 0x0dac, 0x0e0c },
|
||||||
|
{ 0x0dad, 0x0e0d },
|
||||||
|
{ 0x0dae, 0x0e0e },
|
||||||
|
{ 0x0daf, 0x0e0f },
|
||||||
|
{ 0x0db0, 0x0e10 },
|
||||||
|
{ 0x0db1, 0x0e11 },
|
||||||
|
{ 0x0db2, 0x0e12 },
|
||||||
|
{ 0x0db3, 0x0e13 },
|
||||||
|
{ 0x0db4, 0x0e14 },
|
||||||
|
{ 0x0db5, 0x0e15 },
|
||||||
|
{ 0x0db6, 0x0e16 },
|
||||||
|
{ 0x0db7, 0x0e17 },
|
||||||
|
{ 0x0db8, 0x0e18 },
|
||||||
|
{ 0x0db9, 0x0e19 },
|
||||||
|
{ 0x0dba, 0x0e1a },
|
||||||
|
{ 0x0dbb, 0x0e1b },
|
||||||
|
{ 0x0dbc, 0x0e1c },
|
||||||
|
{ 0x0dbd, 0x0e1d },
|
||||||
|
{ 0x0dbe, 0x0e1e },
|
||||||
|
{ 0x0dbf, 0x0e1f },
|
||||||
|
{ 0x0dc0, 0x0e20 },
|
||||||
|
{ 0x0dc1, 0x0e21 },
|
||||||
|
{ 0x0dc2, 0x0e22 },
|
||||||
|
{ 0x0dc3, 0x0e23 },
|
||||||
|
{ 0x0dc4, 0x0e24 },
|
||||||
|
{ 0x0dc5, 0x0e25 },
|
||||||
|
{ 0x0dc6, 0x0e26 },
|
||||||
|
{ 0x0dc7, 0x0e27 },
|
||||||
|
{ 0x0dc8, 0x0e28 },
|
||||||
|
{ 0x0dc9, 0x0e29 },
|
||||||
|
{ 0x0dca, 0x0e2a },
|
||||||
|
{ 0x0dcb, 0x0e2b },
|
||||||
|
{ 0x0dcc, 0x0e2c },
|
||||||
|
{ 0x0dcd, 0x0e2d },
|
||||||
|
{ 0x0dce, 0x0e2e },
|
||||||
|
{ 0x0dcf, 0x0e2f },
|
||||||
|
{ 0x0dd0, 0x0e30 },
|
||||||
|
{ 0x0dd1, 0x0e31 },
|
||||||
|
{ 0x0dd2, 0x0e32 },
|
||||||
|
{ 0x0dd3, 0x0e33 },
|
||||||
|
{ 0x0dd4, 0x0e34 },
|
||||||
|
{ 0x0dd5, 0x0e35 },
|
||||||
|
{ 0x0dd6, 0x0e36 },
|
||||||
|
{ 0x0dd7, 0x0e37 },
|
||||||
|
{ 0x0dd8, 0x0e38 },
|
||||||
|
{ 0x0dd9, 0x0e39 },
|
||||||
|
{ 0x0dda, 0x0e3a },
|
||||||
|
{ 0x0ddf, 0x0e3f },
|
||||||
|
{ 0x0de0, 0x0e40 },
|
||||||
|
{ 0x0de1, 0x0e41 },
|
||||||
|
{ 0x0de2, 0x0e42 },
|
||||||
|
{ 0x0de3, 0x0e43 },
|
||||||
|
{ 0x0de4, 0x0e44 },
|
||||||
|
{ 0x0de5, 0x0e45 },
|
||||||
|
{ 0x0de6, 0x0e46 },
|
||||||
|
{ 0x0de7, 0x0e47 },
|
||||||
|
{ 0x0de8, 0x0e48 },
|
||||||
|
{ 0x0de9, 0x0e49 },
|
||||||
|
{ 0x0dea, 0x0e4a },
|
||||||
|
{ 0x0deb, 0x0e4b },
|
||||||
|
{ 0x0dec, 0x0e4c },
|
||||||
|
{ 0x0ded, 0x0e4d },
|
||||||
|
{ 0x0df0, 0x0e50 },
|
||||||
|
{ 0x0df1, 0x0e51 },
|
||||||
|
{ 0x0df2, 0x0e52 },
|
||||||
|
{ 0x0df3, 0x0e53 },
|
||||||
|
{ 0x0df4, 0x0e54 },
|
||||||
|
{ 0x0df5, 0x0e55 },
|
||||||
|
{ 0x0df6, 0x0e56 },
|
||||||
|
{ 0x0df7, 0x0e57 },
|
||||||
|
{ 0x0df8, 0x0e58 },
|
||||||
|
{ 0x0df9, 0x0e59 },
|
||||||
|
{ 0x0ea1, 0x3131 },
|
||||||
|
{ 0x0ea2, 0x3132 },
|
||||||
|
{ 0x0ea3, 0x3133 },
|
||||||
|
{ 0x0ea4, 0x3134 },
|
||||||
|
{ 0x0ea5, 0x3135 },
|
||||||
|
{ 0x0ea6, 0x3136 },
|
||||||
|
{ 0x0ea7, 0x3137 },
|
||||||
|
{ 0x0ea8, 0x3138 },
|
||||||
|
{ 0x0ea9, 0x3139 },
|
||||||
|
{ 0x0eaa, 0x313a },
|
||||||
|
{ 0x0eab, 0x313b },
|
||||||
|
{ 0x0eac, 0x313c },
|
||||||
|
{ 0x0ead, 0x313d },
|
||||||
|
{ 0x0eae, 0x313e },
|
||||||
|
{ 0x0eaf, 0x313f },
|
||||||
|
{ 0x0eb0, 0x3140 },
|
||||||
|
{ 0x0eb1, 0x3141 },
|
||||||
|
{ 0x0eb2, 0x3142 },
|
||||||
|
{ 0x0eb3, 0x3143 },
|
||||||
|
{ 0x0eb4, 0x3144 },
|
||||||
|
{ 0x0eb5, 0x3145 },
|
||||||
|
{ 0x0eb6, 0x3146 },
|
||||||
|
{ 0x0eb7, 0x3147 },
|
||||||
|
{ 0x0eb8, 0x3148 },
|
||||||
|
{ 0x0eb9, 0x3149 },
|
||||||
|
{ 0x0eba, 0x314a },
|
||||||
|
{ 0x0ebb, 0x314b },
|
||||||
|
{ 0x0ebc, 0x314c },
|
||||||
|
{ 0x0ebd, 0x314d },
|
||||||
|
{ 0x0ebe, 0x314e },
|
||||||
|
{ 0x0ebf, 0x314f },
|
||||||
|
{ 0x0ec0, 0x3150 },
|
||||||
|
{ 0x0ec1, 0x3151 },
|
||||||
|
{ 0x0ec2, 0x3152 },
|
||||||
|
{ 0x0ec3, 0x3153 },
|
||||||
|
{ 0x0ec4, 0x3154 },
|
||||||
|
{ 0x0ec5, 0x3155 },
|
||||||
|
{ 0x0ec6, 0x3156 },
|
||||||
|
{ 0x0ec7, 0x3157 },
|
||||||
|
{ 0x0ec8, 0x3158 },
|
||||||
|
{ 0x0ec9, 0x3159 },
|
||||||
|
{ 0x0eca, 0x315a },
|
||||||
|
{ 0x0ecb, 0x315b },
|
||||||
|
{ 0x0ecc, 0x315c },
|
||||||
|
{ 0x0ecd, 0x315d },
|
||||||
|
{ 0x0ece, 0x315e },
|
||||||
|
{ 0x0ecf, 0x315f },
|
||||||
|
{ 0x0ed0, 0x3160 },
|
||||||
|
{ 0x0ed1, 0x3161 },
|
||||||
|
{ 0x0ed2, 0x3162 },
|
||||||
|
{ 0x0ed3, 0x3163 },
|
||||||
|
{ 0x0ed4, 0x11a8 },
|
||||||
|
{ 0x0ed5, 0x11a9 },
|
||||||
|
{ 0x0ed6, 0x11aa },
|
||||||
|
{ 0x0ed7, 0x11ab },
|
||||||
|
{ 0x0ed8, 0x11ac },
|
||||||
|
{ 0x0ed9, 0x11ad },
|
||||||
|
{ 0x0eda, 0x11ae },
|
||||||
|
{ 0x0edb, 0x11af },
|
||||||
|
{ 0x0edc, 0x11b0 },
|
||||||
|
{ 0x0edd, 0x11b1 },
|
||||||
|
{ 0x0ede, 0x11b2 },
|
||||||
|
{ 0x0edf, 0x11b3 },
|
||||||
|
{ 0x0ee0, 0x11b4 },
|
||||||
|
{ 0x0ee1, 0x11b5 },
|
||||||
|
{ 0x0ee2, 0x11b6 },
|
||||||
|
{ 0x0ee3, 0x11b7 },
|
||||||
|
{ 0x0ee4, 0x11b8 },
|
||||||
|
{ 0x0ee5, 0x11b9 },
|
||||||
|
{ 0x0ee6, 0x11ba },
|
||||||
|
{ 0x0ee7, 0x11bb },
|
||||||
|
{ 0x0ee8, 0x11bc },
|
||||||
|
{ 0x0ee9, 0x11bd },
|
||||||
|
{ 0x0eea, 0x11be },
|
||||||
|
{ 0x0eeb, 0x11bf },
|
||||||
|
{ 0x0eec, 0x11c0 },
|
||||||
|
{ 0x0eed, 0x11c1 },
|
||||||
|
{ 0x0eee, 0x11c2 },
|
||||||
|
{ 0x0eef, 0x316d },
|
||||||
|
{ 0x0ef0, 0x3171 },
|
||||||
|
{ 0x0ef1, 0x3178 },
|
||||||
|
{ 0x0ef2, 0x317f },
|
||||||
|
{ 0x0ef3, 0x3181 },
|
||||||
|
{ 0x0ef4, 0x3184 },
|
||||||
|
{ 0x0ef5, 0x3186 },
|
||||||
|
{ 0x0ef6, 0x318d },
|
||||||
|
{ 0x0ef7, 0x318e },
|
||||||
|
{ 0x0ef8, 0x11eb },
|
||||||
|
{ 0x0ef9, 0x11f0 },
|
||||||
|
{ 0x0efa, 0x11f9 },
|
||||||
|
{ 0x0eff, 0x20a9 },
|
||||||
|
{ 0x13a4, 0x20ac },
|
||||||
|
{ 0x13bc, 0x0152 },
|
||||||
|
{ 0x13bd, 0x0153 },
|
||||||
|
{ 0x13be, 0x0178 },
|
||||||
|
{ 0x20ac, 0x20ac },
|
||||||
|
// Numeric keypad with numlock on
|
||||||
|
{ 0xff80 /*XKB_KEY_KP_Space*/, ' ' },
|
||||||
|
{ 0xffbd /*XKB_KEY_KP_Equal*/, '=' },
|
||||||
|
{ 0xffaa /*XKB_KEY_KP_Multiply*/, '*' },
|
||||||
|
{ 0xffab /*XKB_KEY_KP_Add*/, '+' },
|
||||||
|
{ 0xffac /*XKB_KEY_KP_Separator*/, ',' },
|
||||||
|
{ 0xffad /*XKB_KEY_KP_Subtract*/, '-' },
|
||||||
|
{ 0xffae /*XKB_KEY_KP_Decimal*/, '.' },
|
||||||
|
{ 0xffaf /*XKB_KEY_KP_Divide*/, '/' },
|
||||||
|
{ 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 },
|
||||||
|
{ 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 },
|
||||||
|
{ 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 },
|
||||||
|
{ 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 },
|
||||||
|
{ 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 },
|
||||||
|
{ 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 },
|
||||||
|
{ 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 },
|
||||||
|
{ 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 },
|
||||||
|
{ 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 },
|
||||||
|
{ 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
////// GLFW internal API //////
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Convert XKB KeySym to Unicode
|
||||||
|
//
|
||||||
|
long _glfwKeySym2Unicode(unsigned int keysym)
|
||||||
|
{
|
||||||
|
int min = 0;
|
||||||
|
int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
|
||||||
|
int mid;
|
||||||
|
|
||||||
|
// First check for Latin-1 characters (1:1 mapping)
|
||||||
|
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
|
||||||
|
(keysym >= 0x00a0 && keysym <= 0x00ff))
|
||||||
|
{
|
||||||
|
return keysym;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check for directly encoded 24-bit UCS characters
|
||||||
|
if ((keysym & 0xff000000) == 0x01000000)
|
||||||
|
return keysym & 0x00ffffff;
|
||||||
|
|
||||||
|
// Binary search in table
|
||||||
|
while (max >= min)
|
||||||
|
{
|
||||||
|
mid = (min + max) / 2;
|
||||||
|
if (keysymtab[mid].keysym < keysym)
|
||||||
|
min = mid + 1;
|
||||||
|
else if (keysymtab[mid].keysym > keysym)
|
||||||
|
max = mid - 1;
|
||||||
|
else
|
||||||
|
return keysymtab[mid].ucs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching Unicode value found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
33
external/glfw/xkb_unicode.h
vendored
Normal file
33
external/glfw/xkb_unicode.h
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//========================================================================
|
||||||
|
// GLFW 3.3 Linux - www.glfw.org
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
|
||||||
|
//
|
||||||
|
// 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 _glfw3_xkb_unicode_h_
|
||||||
|
#define _glfw3_xkb_unicode_h_
|
||||||
|
|
||||||
|
|
||||||
|
long _glfwKeySym2Unicode(unsigned int keysym);
|
||||||
|
|
||||||
|
#endif // _glfw3_xkb_unicode_h_
|
18
external/imgui/CMakeLists.txt
vendored
Normal file
18
external/imgui/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
set(imgui_HEADERS
|
||||||
|
imconfig.h
|
||||||
|
imgui.h
|
||||||
|
imgui_internal.h
|
||||||
|
imgui_impl_glfw_gl3.h
|
||||||
|
stb_rect_pack.h
|
||||||
|
stb_textedit.h
|
||||||
|
stb_truetype.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(imgui_SOURCES
|
||||||
|
imgui.cpp
|
||||||
|
imgui_draw.cpp
|
||||||
|
imgui_impl_glfw_gl3.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(../)
|
||||||
|
add_library(imgui STATIC ${imgui_HEADERS} ${imgui_SOURCES})
|
51
external/imgui/imconfig.h
vendored
Normal file
51
external/imgui/imconfig.h
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// USER IMPLEMENTATION
|
||||||
|
// This file contains compile-time options for ImGui.
|
||||||
|
// Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO().
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
|
|
||||||
|
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
|
||||||
|
//#define IMGUI_API __declspec( dllexport )
|
||||||
|
//#define IMGUI_API __declspec( dllimport )
|
||||||
|
|
||||||
|
//---- Include imgui_user.h at the end of imgui.h
|
||||||
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
|
|
||||||
|
//---- Don't implement default handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions)
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
|
||||||
|
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS
|
||||||
|
|
||||||
|
//---- Don't implement help and test window functionality (ShowUserGuide()/ShowStyleEditor()/ShowTestWindow() methods will be empty)
|
||||||
|
//#define IMGUI_DISABLE_TEST_WINDOWS
|
||||||
|
|
||||||
|
//---- Don't define obsolete functions names
|
||||||
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
|
|
||||||
|
//---- Implement STB libraries in a namespace to avoid conflicts
|
||||||
|
//#define IMGUI_STB_NAMESPACE ImGuiStb
|
||||||
|
|
||||||
|
//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
|
||||||
|
/*
|
||||||
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
|
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||||
|
operator MyVec2() const { return MyVec2(x,y); }
|
||||||
|
|
||||||
|
#define IM_VEC4_CLASS_EXTRA \
|
||||||
|
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||||
|
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||||
|
//---- e.g. create variants of the ImGui::Value() helper for your low-level math types, or your own widgets/helpers.
|
||||||
|
/*
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
void Value(const char* prefix, const MyMatrix44& v, const char* float_format = NULL);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
9584
external/imgui/imgui.cpp
vendored
Normal file
9584
external/imgui/imgui.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1381
external/imgui/imgui.h
vendored
Normal file
1381
external/imgui/imgui.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2376
external/imgui/imgui_draw.cpp
vendored
Normal file
2376
external/imgui/imgui_draw.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
401
external/imgui/imgui_impl_glfw_gl3.cpp
vendored
Normal file
401
external/imgui/imgui_impl_glfw_gl3.cpp
vendored
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
// ImGui GLFW binding with OpenGL3 + shaders
|
||||||
|
// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
|
||||||
|
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_glfw_gl3.h"
|
||||||
|
|
||||||
|
// GL3W/GLFW
|
||||||
|
#if defined(__APPLE_CC__)
|
||||||
|
#include <OpenGL/gl3.h>
|
||||||
|
#else
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#endif
|
||||||
|
#include <glfw/glfw3.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef APIENTRY
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WGL
|
||||||
|
#include <glfw/glfw3native.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Data
|
||||||
|
static GLFWwindow* g_Window = NULL;
|
||||||
|
static double g_Time = 0.0f;
|
||||||
|
static bool g_MousePressed[3] = { false, false, false };
|
||||||
|
static float g_MouseWheel = 0.0f;
|
||||||
|
static GLuint g_FontTexture = 0;
|
||||||
|
static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||||
|
static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
|
||||||
|
static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
|
||||||
|
static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0;
|
||||||
|
|
||||||
|
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
|
||||||
|
// If text or lines are blurry when integrating ImGui in your engine:
|
||||||
|
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
|
||||||
|
void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||||
|
int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||||
|
if (fb_width == 0 || fb_height == 0)
|
||||||
|
return;
|
||||||
|
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
||||||
|
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||||
|
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
GLint last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, &last_active_texture);
|
||||||
|
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||||
|
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
|
GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src);
|
||||||
|
GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst);
|
||||||
|
GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb);
|
||||||
|
GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha);
|
||||||
|
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||||
|
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||||
|
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||||
|
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||||
|
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendEquation(GL_FUNC_ADD);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
// Setup viewport, orthographic projection matrix
|
||||||
|
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||||
|
const float ortho_projection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
|
{-1.0f, 1.0f, 0.0f, 1.0f },
|
||||||
|
};
|
||||||
|
glUseProgram(g_ShaderHandle);
|
||||||
|
glUniform1i(g_AttribLocationTex, 0);
|
||||||
|
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||||
|
glBindVertexArray(g_VaoHandle);
|
||||||
|
|
||||||
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||||
|
const ImDrawIdx* idx_buffer_offset = 0;
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.size() * sizeof(ImDrawVert), (GLvoid*)&cmd_list->VtxBuffer.front(), GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW);
|
||||||
|
|
||||||
|
for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++)
|
||||||
|
{
|
||||||
|
if (pcmd->UserCallback)
|
||||||
|
{
|
||||||
|
pcmd->UserCallback(cmd_list, pcmd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||||
|
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
|
||||||
|
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
|
||||||
|
}
|
||||||
|
idx_buffer_offset += pcmd->ElemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glUseProgram(last_program);
|
||||||
|
glActiveTexture(last_active_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
glBindVertexArray(last_vertex_array);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||||
|
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||||
|
glBlendFunc(last_blend_src, last_blend_dst);
|
||||||
|
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||||
|
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||||
|
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||||
|
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||||
|
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* ImGui_ImplGlfwGL3_GetClipboardText()
|
||||||
|
{
|
||||||
|
return glfwGetClipboardString(g_Window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text)
|
||||||
|
{
|
||||||
|
glfwSetClipboardString(g_Window, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/)
|
||||||
|
{
|
||||||
|
if (action == GLFW_PRESS && button >= 0 && button < 3)
|
||||||
|
g_MousePressed[button] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset)
|
||||||
|
{
|
||||||
|
g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (action == GLFW_PRESS)
|
||||||
|
io.KeysDown[key] = true;
|
||||||
|
if (action == GLFW_RELEASE)
|
||||||
|
io.KeysDown[key] = false;
|
||||||
|
|
||||||
|
(void)mods; // Modifiers are not reliable across systems
|
||||||
|
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||||
|
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||||
|
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||||
|
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c)
|
||||||
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (c > 0 && c < 0x10000)
|
||||||
|
io.AddInputCharacter((unsigned short)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfwGL3_CreateFontsTexture()
|
||||||
|
{
|
||||||
|
// Build texture atlas
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
unsigned char* pixels;
|
||||||
|
int width, height;
|
||||||
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader.
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
GLint last_texture;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGenTextures(1, &g_FontTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||||
|
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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfwGL3_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
// Backup GL state
|
||||||
|
GLint last_texture, last_array_buffer, last_vertex_array;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||||
|
|
||||||
|
const GLchar *vertex_shader =
|
||||||
|
"#version 330\n"
|
||||||
|
"uniform mat4 ProjMtx;\n"
|
||||||
|
"in vec2 Position;\n"
|
||||||
|
"in vec2 UV;\n"
|
||||||
|
"in vec4 Color;\n"
|
||||||
|
"out vec2 Frag_UV;\n"
|
||||||
|
"out vec4 Frag_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Frag_UV = UV;\n"
|
||||||
|
" Frag_Color = Color;\n"
|
||||||
|
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const GLchar* fragment_shader =
|
||||||
|
"#version 330\n"
|
||||||
|
"uniform sampler2D Texture;\n"
|
||||||
|
"in vec2 Frag_UV;\n"
|
||||||
|
"in vec4 Frag_Color;\n"
|
||||||
|
"out vec4 Out_Color;\n"
|
||||||
|
"void main()\n"
|
||||||
|
"{\n"
|
||||||
|
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
g_ShaderHandle = glCreateProgram();
|
||||||
|
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(g_VertHandle, 1, &vertex_shader, 0);
|
||||||
|
glShaderSource(g_FragHandle, 1, &fragment_shader, 0);
|
||||||
|
glCompileShader(g_VertHandle);
|
||||||
|
glCompileShader(g_FragHandle);
|
||||||
|
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||||
|
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||||
|
glLinkProgram(g_ShaderHandle);
|
||||||
|
|
||||||
|
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||||
|
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||||
|
g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position");
|
||||||
|
g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV");
|
||||||
|
g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
|
||||||
|
|
||||||
|
glGenBuffers(1, &g_VboHandle);
|
||||||
|
glGenBuffers(1, &g_ElementsHandle);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &g_VaoHandle);
|
||||||
|
glBindVertexArray(g_VaoHandle);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationPosition);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationUV);
|
||||||
|
glEnableVertexAttribArray(g_AttribLocationColor);
|
||||||
|
|
||||||
|
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
|
||||||
|
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos));
|
||||||
|
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv));
|
||||||
|
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col));
|
||||||
|
#undef OFFSETOF
|
||||||
|
|
||||||
|
ImGui_ImplGlfwGL3_CreateFontsTexture();
|
||||||
|
|
||||||
|
// Restore modified GL state
|
||||||
|
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||||
|
glBindVertexArray(last_vertex_array);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (g_VaoHandle) glDeleteVertexArrays(1, &g_VaoHandle);
|
||||||
|
if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle);
|
||||||
|
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
|
||||||
|
g_VaoHandle = g_VboHandle = g_ElementsHandle = 0;
|
||||||
|
|
||||||
|
glDetachShader(g_ShaderHandle, g_VertHandle);
|
||||||
|
glDeleteShader(g_VertHandle);
|
||||||
|
g_VertHandle = 0;
|
||||||
|
|
||||||
|
glDetachShader(g_ShaderHandle, g_FragHandle);
|
||||||
|
glDeleteShader(g_FragHandle);
|
||||||
|
g_FragHandle = 0;
|
||||||
|
|
||||||
|
glDeleteProgram(g_ShaderHandle);
|
||||||
|
g_ShaderHandle = 0;
|
||||||
|
|
||||||
|
if (g_FontTexture)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, &g_FontTexture);
|
||||||
|
ImGui::GetIO().Fonts->TexID = 0;
|
||||||
|
g_FontTexture = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks)
|
||||||
|
{
|
||||||
|
g_Window = window;
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
|
||||||
|
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||||
|
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||||
|
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||||
|
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||||
|
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||||
|
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||||
|
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||||
|
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||||
|
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||||
|
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||||
|
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||||
|
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||||
|
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||||
|
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||||
|
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||||
|
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||||
|
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||||
|
|
||||||
|
io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
|
||||||
|
io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText;
|
||||||
|
io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText;
|
||||||
|
#ifdef _WIN32
|
||||||
|
io.ImeWindowHandle = glfwGetWin32Window(g_Window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (install_callbacks)
|
||||||
|
{
|
||||||
|
glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL3_MouseButtonCallback);
|
||||||
|
glfwSetScrollCallback(window, ImGui_ImplGlfwGL3_ScrollCallback);
|
||||||
|
glfwSetKeyCallback(window, ImGui_ImplGlfwGL3_KeyCallback);
|
||||||
|
glfwSetCharCallback(window, ImGui_ImplGlfwGL3_CharCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
|
||||||
|
ImGui::Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplGlfwGL3_NewFrame()
|
||||||
|
{
|
||||||
|
if (!g_FontTexture)
|
||||||
|
ImGui_ImplGlfwGL3_CreateDeviceObjects();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
// Setup display size (every frame to accommodate for window resizing)
|
||||||
|
int w, h;
|
||||||
|
int display_w, display_h;
|
||||||
|
glfwGetWindowSize(g_Window, &w, &h);
|
||||||
|
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||||
|
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||||
|
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
|
||||||
|
|
||||||
|
// Setup time step
|
||||||
|
double current_time = glfwGetTime();
|
||||||
|
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
|
||||||
|
g_Time = current_time;
|
||||||
|
|
||||||
|
// Setup inputs
|
||||||
|
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
|
||||||
|
if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
|
||||||
|
{
|
||||||
|
double mouse_x, mouse_y;
|
||||||
|
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||||
|
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
io.MousePos = ImVec2(-1,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
|
g_MousePressed[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.MouseWheel = g_MouseWheel;
|
||||||
|
g_MouseWheel = 0.0f;
|
||||||
|
|
||||||
|
// Hide OS mouse cursor if ImGui is drawing it
|
||||||
|
glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
|
||||||
|
|
||||||
|
// Start the frame
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
25
external/imgui/imgui_impl_glfw_gl3.h
vendored
Normal file
25
external/imgui/imgui_impl_glfw_gl3.h
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// ImGui GLFW binding with OpenGL3 + shaders
|
||||||
|
// In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
|
||||||
|
|
||||||
|
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||||
|
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
|
||||||
|
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
|
||||||
|
// https://github.com/ocornut/imgui
|
||||||
|
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
|
IMGUI_API bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks);
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_Shutdown();
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_NewFrame();
|
||||||
|
|
||||||
|
// Use if you want to reset your rendering device without losing ImGui state.
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
|
||||||
|
IMGUI_API bool ImGui_ImplGlfwGL3_CreateDeviceObjects();
|
||||||
|
|
||||||
|
// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
|
||||||
|
// Provided here if you want to chain callbacks.
|
||||||
|
// You can also handle inputs yourself and use those as a reference.
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||||
|
IMGUI_API void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow* window, unsigned int c);
|
746
external/imgui/imgui_internal.h
vendored
Normal file
746
external/imgui/imgui_internal.h
vendored
Normal file
@ -0,0 +1,746 @@
|
|||||||
|
// dear imgui, v1.49 WIP
|
||||||
|
// (internals)
|
||||||
|
|
||||||
|
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
|
||||||
|
// Implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
|
||||||
|
// #define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef IMGUI_VERSION
|
||||||
|
#error Must include imgui.h before imgui_internal.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h> // FILE*
|
||||||
|
#include <math.h> // sqrtf()
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Forward Declarations
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct ImRect;
|
||||||
|
struct ImGuiColMod;
|
||||||
|
struct ImGuiStyleMod;
|
||||||
|
struct ImGuiGroupData;
|
||||||
|
struct ImGuiSimpleColumns;
|
||||||
|
struct ImGuiDrawContext;
|
||||||
|
struct ImGuiTextEditState;
|
||||||
|
struct ImGuiIniData;
|
||||||
|
struct ImGuiMouseCursorData;
|
||||||
|
struct ImGuiPopupRef;
|
||||||
|
struct ImGuiWindow;
|
||||||
|
|
||||||
|
typedef int ImGuiLayoutType; // enum ImGuiLayoutType_
|
||||||
|
typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_
|
||||||
|
typedef int ImGuiTreeNodeFlags; // enum ImGuiTreeNodeFlags_
|
||||||
|
typedef int ImGuiSliderFlags; // enum ImGuiSliderFlags_
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// STB libraries
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ImGuiStb
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-function"
|
||||||
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef STB_TEXTEDIT_STRING
|
||||||
|
#undef STB_TEXTEDIT_CHARTYPE
|
||||||
|
#define STB_TEXTEDIT_STRING ImGuiTextEditState
|
||||||
|
#define STB_TEXTEDIT_CHARTYPE ImWchar
|
||||||
|
#define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f
|
||||||
|
#include "stb_textedit.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ImGuiStb
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Context
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern IMGUI_API ImGuiContext* GImGui; // current implicit ImGui context pointer
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
|
||||||
|
#define IM_PI 3.14159265358979323846f
|
||||||
|
|
||||||
|
// Helpers: UTF-8 <> wchar
|
||||||
|
IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
|
||||||
|
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
|
||||||
|
IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
|
||||||
|
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
|
||||||
|
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
|
||||||
|
|
||||||
|
// Helpers: Misc
|
||||||
|
IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings
|
||||||
|
IMGUI_API void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0);
|
||||||
|
IMGUI_API bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c);
|
||||||
|
static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; }
|
||||||
|
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
|
||||||
|
|
||||||
|
// Helpers: String
|
||||||
|
IMGUI_API int ImStricmp(const char* str1, const char* str2);
|
||||||
|
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, int count);
|
||||||
|
IMGUI_API char* ImStrdup(const char* str);
|
||||||
|
IMGUI_API int ImStrlenW(const ImWchar* str);
|
||||||
|
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
|
||||||
|
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
|
||||||
|
IMGUI_API int ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_PRINTFARGS(3);
|
||||||
|
IMGUI_API int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args);
|
||||||
|
|
||||||
|
// Helpers: Math
|
||||||
|
// We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined)
|
||||||
|
#ifdef IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); }
|
||||||
|
static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); }
|
||||||
|
static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); }
|
||||||
|
static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); }
|
||||||
|
static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); }
|
||||||
|
static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); }
|
||||||
|
static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; }
|
||||||
|
static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
|
||||||
|
static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
|
||||||
|
static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
|
||||||
|
static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; }
|
||||||
|
static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; }
|
||||||
|
static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
|
||||||
|
static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; }
|
||||||
|
static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMin(lhs.x,rhs.x), ImMin(lhs.y,rhs.y)); }
|
||||||
|
static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(ImMax(lhs.x,rhs.x), ImMax(lhs.y,rhs.y)); }
|
||||||
|
static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
|
||||||
|
static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
|
||||||
|
static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x,mn.x,mx.x), ImClamp(f.y,mn.y,mx.y)); }
|
||||||
|
static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
|
||||||
|
static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; }
|
||||||
|
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
|
||||||
|
static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
|
||||||
|
static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; }
|
||||||
|
static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; }
|
||||||
|
static inline float ImFloor(float f) { return (float)(int)f; }
|
||||||
|
static inline ImVec2 ImFloor(ImVec2 v) { return ImVec2((float)(int)v.x, (float)(int)v.y); }
|
||||||
|
|
||||||
|
// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
|
||||||
|
// Defining a custom placement new() with a dummy parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.
|
||||||
|
#ifdef IMGUI_DEFINE_PLACEMENT_NEW
|
||||||
|
struct ImPlacementNewDummy {};
|
||||||
|
inline void* operator new(size_t, ImPlacementNewDummy, void* ptr) { return ptr; }
|
||||||
|
inline void operator delete(void*, ImPlacementNewDummy, void*) {}
|
||||||
|
#define IM_PLACEMENT_NEW(_PTR) new(ImPlacementNewDummy(), _PTR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum ImGuiButtonFlags_
|
||||||
|
{
|
||||||
|
ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat
|
||||||
|
ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // (default) return pressed on click+release on same item (default if no PressedOn** flag is set)
|
||||||
|
ImGuiButtonFlags_PressedOnClick = 1 << 2, // return pressed on click (default requires click+release)
|
||||||
|
ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return pressed on release (default requires click+release)
|
||||||
|
ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return pressed on double-click (default requires click+release)
|
||||||
|
ImGuiButtonFlags_FlattenChilds = 1 << 5, // allow interaction even if a child window is overlapping
|
||||||
|
ImGuiButtonFlags_DontClosePopups = 1 << 6, // disable automatically closing parent popup on press
|
||||||
|
ImGuiButtonFlags_Disabled = 1 << 7, // disable interaction
|
||||||
|
ImGuiButtonFlags_AlignTextBaseLine = 1 << 8, // vertically align button to match text baseline - ButtonEx() only
|
||||||
|
ImGuiButtonFlags_NoKeyModifiers = 1 << 9, // disable interaction if a key modifier is held
|
||||||
|
ImGuiButtonFlags_AllowOverlapMode = 1 << 10 // require previous frame HoveredId to either match id or be null before being usable
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImGuiSliderFlags_
|
||||||
|
{
|
||||||
|
ImGuiSliderFlags_Vertical = 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImGuiSelectableFlagsPrivate_
|
||||||
|
{
|
||||||
|
// NB: need to be in sync with last value of ImGuiSelectableFlags_
|
||||||
|
ImGuiSelectableFlags_Menu = 1 << 3,
|
||||||
|
ImGuiSelectableFlags_MenuItem = 1 << 4,
|
||||||
|
ImGuiSelectableFlags_Disabled = 1 << 5,
|
||||||
|
ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 6
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: this is in development, not exposed/functional as a generic feature yet.
|
||||||
|
enum ImGuiLayoutType_
|
||||||
|
{
|
||||||
|
ImGuiLayoutType_Vertical,
|
||||||
|
ImGuiLayoutType_Horizontal
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImGuiPlotType
|
||||||
|
{
|
||||||
|
ImGuiPlotType_Lines,
|
||||||
|
ImGuiPlotType_Histogram
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ImGuiDataType
|
||||||
|
{
|
||||||
|
ImGuiDataType_Int,
|
||||||
|
ImGuiDataType_Float
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2D axis aligned bounding-box
|
||||||
|
// NB: we can't rely on ImVec2 math operators being available here
|
||||||
|
struct IMGUI_API ImRect
|
||||||
|
{
|
||||||
|
ImVec2 Min; // Upper-left
|
||||||
|
ImVec2 Max; // Lower-right
|
||||||
|
|
||||||
|
ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {}
|
||||||
|
ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {}
|
||||||
|
ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {}
|
||||||
|
ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {}
|
||||||
|
|
||||||
|
ImVec2 GetCenter() const { return ImVec2((Min.x+Max.x)*0.5f, (Min.y+Max.y)*0.5f); }
|
||||||
|
ImVec2 GetSize() const { return ImVec2(Max.x-Min.x, Max.y-Min.y); }
|
||||||
|
float GetWidth() const { return Max.x-Min.x; }
|
||||||
|
float GetHeight() const { return Max.y-Min.y; }
|
||||||
|
ImVec2 GetTL() const { return Min; } // Top-left
|
||||||
|
ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right
|
||||||
|
ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left
|
||||||
|
ImVec2 GetBR() const { return Max; } // Bottom-right
|
||||||
|
bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; }
|
||||||
|
bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; }
|
||||||
|
bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; }
|
||||||
|
void Add(const ImVec2& rhs) { if (Min.x > rhs.x) Min.x = rhs.x; if (Min.y > rhs.y) Min.y = rhs.y; if (Max.x < rhs.x) Max.x = rhs.x; if (Max.y < rhs.y) Max.y = rhs.y; }
|
||||||
|
void Add(const ImRect& rhs) { if (Min.x > rhs.Min.x) Min.x = rhs.Min.x; if (Min.y > rhs.Min.y) Min.y = rhs.Min.y; if (Max.x < rhs.Max.x) Max.x = rhs.Max.x; if (Max.y < rhs.Max.y) Max.y = rhs.Max.y; }
|
||||||
|
void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; }
|
||||||
|
void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; }
|
||||||
|
void Reduce(const ImVec2& amount) { Min.x += amount.x; Min.y += amount.y; Max.x -= amount.x; Max.y -= amount.y; }
|
||||||
|
void Clip(const ImRect& clip) { if (Min.x < clip.Min.x) Min.x = clip.Min.x; if (Min.y < clip.Min.y) Min.y = clip.Min.y; if (Max.x > clip.Max.x) Max.x = clip.Max.x; if (Max.y > clip.Max.y) Max.y = clip.Max.y; }
|
||||||
|
void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; }
|
||||||
|
ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const
|
||||||
|
{
|
||||||
|
if (!on_edge && Contains(p))
|
||||||
|
return p;
|
||||||
|
if (p.x > Max.x) p.x = Max.x;
|
||||||
|
else if (p.x < Min.x) p.x = Min.x;
|
||||||
|
if (p.y > Max.y) p.y = Max.y;
|
||||||
|
else if (p.y < Min.y) p.y = Min.y;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stacked color modifier, backup of modified data so we can restore it
|
||||||
|
struct ImGuiColMod
|
||||||
|
{
|
||||||
|
ImGuiCol Col;
|
||||||
|
ImVec4 PreviousValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stacked style modifier, backup of modified data so we can restore it
|
||||||
|
struct ImGuiStyleMod
|
||||||
|
{
|
||||||
|
ImGuiStyleVar Var;
|
||||||
|
ImVec2 PreviousValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stacked data for BeginGroup()/EndGroup()
|
||||||
|
struct ImGuiGroupData
|
||||||
|
{
|
||||||
|
ImVec2 BackupCursorPos;
|
||||||
|
ImVec2 BackupCursorMaxPos;
|
||||||
|
float BackupIndentX;
|
||||||
|
float BackupCurrentLineHeight;
|
||||||
|
float BackupCurrentLineTextBaseOffset;
|
||||||
|
float BackupLogLinePosY;
|
||||||
|
bool AdvanceCursor;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Per column data for Columns()
|
||||||
|
struct ImGuiColumnData
|
||||||
|
{
|
||||||
|
float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right)
|
||||||
|
//float IndentX;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simple column measurement currently used for MenuItem() only. This is very short-sighted/throw-away code and NOT a generic helper.
|
||||||
|
struct IMGUI_API ImGuiSimpleColumns
|
||||||
|
{
|
||||||
|
int Count;
|
||||||
|
float Spacing;
|
||||||
|
float Width, NextWidth;
|
||||||
|
float Pos[8], NextWidths[8];
|
||||||
|
|
||||||
|
ImGuiSimpleColumns();
|
||||||
|
void Update(int count, float spacing, bool clear);
|
||||||
|
float DeclColumns(float w0, float w1, float w2);
|
||||||
|
float CalcExtraSpace(float avail_w);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal state of the currently focused/edited text input box
|
||||||
|
struct IMGUI_API ImGuiTextEditState
|
||||||
|
{
|
||||||
|
ImGuiID Id; // widget id owning the text state
|
||||||
|
ImVector<ImWchar> Text; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
|
||||||
|
ImVector<char> InitialText; // backup of end-user buffer at the time of focus (in UTF-8, unaltered)
|
||||||
|
ImVector<char> TempTextBuffer;
|
||||||
|
int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format.
|
||||||
|
int BufSizeA; // end-user buffer size
|
||||||
|
float ScrollX;
|
||||||
|
ImGuiStb::STB_TexteditState StbState;
|
||||||
|
float CursorAnim;
|
||||||
|
bool CursorFollow;
|
||||||
|
bool SelectedAllMouseLock;
|
||||||
|
|
||||||
|
ImGuiTextEditState() { memset(this, 0, sizeof(*this)); }
|
||||||
|
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
|
||||||
|
void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); }
|
||||||
|
bool HasSelection() const { return StbState.select_start != StbState.select_end; }
|
||||||
|
void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; }
|
||||||
|
void SelectAll() { StbState.select_start = 0; StbState.select_end = CurLenW; StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; }
|
||||||
|
void OnKeyPressed(int key);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data saved in imgui.ini file
|
||||||
|
struct ImGuiIniData
|
||||||
|
{
|
||||||
|
char* Name;
|
||||||
|
ImGuiID ID;
|
||||||
|
ImVec2 Pos;
|
||||||
|
ImVec2 Size;
|
||||||
|
bool Collapsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mouse cursor data (used when io.MouseDrawCursor is set)
|
||||||
|
struct ImGuiMouseCursorData
|
||||||
|
{
|
||||||
|
ImGuiMouseCursor Type;
|
||||||
|
ImVec2 HotOffset;
|
||||||
|
ImVec2 Size;
|
||||||
|
ImVec2 TexUvMin[2];
|
||||||
|
ImVec2 TexUvMax[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage for current popup stack
|
||||||
|
struct ImGuiPopupRef
|
||||||
|
{
|
||||||
|
ImGuiID PopupID; // Set on OpenPopup()
|
||||||
|
ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()
|
||||||
|
ImGuiWindow* ParentWindow; // Set on OpenPopup()
|
||||||
|
ImGuiID ParentMenuSet; // Set on OpenPopup()
|
||||||
|
ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup
|
||||||
|
|
||||||
|
ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main state for ImGui
|
||||||
|
struct ImGuiContext
|
||||||
|
{
|
||||||
|
bool Initialized;
|
||||||
|
ImGuiIO IO;
|
||||||
|
ImGuiStyle Style;
|
||||||
|
ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
|
||||||
|
float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize()
|
||||||
|
float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Size of characters.
|
||||||
|
ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvWhitePixel
|
||||||
|
|
||||||
|
float Time;
|
||||||
|
int FrameCount;
|
||||||
|
int FrameCountEnded;
|
||||||
|
int FrameCountRendered;
|
||||||
|
ImVector<ImGuiWindow*> Windows;
|
||||||
|
ImVector<ImGuiWindow*> WindowsSortBuffer;
|
||||||
|
ImGuiWindow* CurrentWindow; // Being drawn into
|
||||||
|
ImVector<ImGuiWindow*> CurrentWindowStack;
|
||||||
|
ImGuiWindow* FocusedWindow; // Will catch keyboard inputs
|
||||||
|
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
|
||||||
|
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
|
||||||
|
ImGuiID HoveredId; // Hovered widget
|
||||||
|
bool HoveredIdAllowOverlap;
|
||||||
|
ImGuiID HoveredIdPreviousFrame;
|
||||||
|
ImGuiID ActiveId; // Active widget
|
||||||
|
ImGuiID ActiveIdPreviousFrame;
|
||||||
|
bool ActiveIdIsAlive;
|
||||||
|
bool ActiveIdIsJustActivated; // Set at the time of activation for one frame
|
||||||
|
bool ActiveIdAllowOverlap; // Set only by active widget
|
||||||
|
ImGuiWindow* ActiveIdWindow;
|
||||||
|
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window.
|
||||||
|
ImGuiID MovedWindowMoveId; // == MovedWindow->RootWindow->MoveId
|
||||||
|
ImVector<ImGuiIniData> Settings; // .ini Settings
|
||||||
|
float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero
|
||||||
|
ImVector<ImGuiColMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
|
||||||
|
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
|
||||||
|
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
|
||||||
|
ImVector<ImGuiPopupRef> OpenPopupStack; // Which popups are open (persistent)
|
||||||
|
ImVector<ImGuiPopupRef> CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame)
|
||||||
|
|
||||||
|
// Storage for SetNexWindow** and SetNextTreeNode*** functions
|
||||||
|
ImVec2 SetNextWindowPosVal;
|
||||||
|
ImVec2 SetNextWindowSizeVal;
|
||||||
|
ImVec2 SetNextWindowContentSizeVal;
|
||||||
|
bool SetNextWindowCollapsedVal;
|
||||||
|
ImGuiSetCond SetNextWindowPosCond;
|
||||||
|
ImGuiSetCond SetNextWindowSizeCond;
|
||||||
|
ImGuiSetCond SetNextWindowContentSizeCond;
|
||||||
|
ImGuiSetCond SetNextWindowCollapsedCond;
|
||||||
|
bool SetNextWindowFocus;
|
||||||
|
bool SetNextTreeNodeOpenVal;
|
||||||
|
ImGuiSetCond SetNextTreeNodeOpenCond;
|
||||||
|
|
||||||
|
// Render
|
||||||
|
ImDrawData RenderDrawData; // Main ImDrawData instance to pass render information to the user
|
||||||
|
ImVector<ImDrawList*> RenderDrawLists[3];
|
||||||
|
float ModalWindowDarkeningRatio;
|
||||||
|
ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays
|
||||||
|
ImGuiMouseCursor MouseCursor;
|
||||||
|
ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_];
|
||||||
|
|
||||||
|
// Widget state
|
||||||
|
ImGuiTextEditState InputTextState;
|
||||||
|
ImFont InputTextPasswordFont;
|
||||||
|
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
|
||||||
|
ImGuiStorage ColorEditModeStorage; // Store user selection of color edit mode
|
||||||
|
ImVec2 ActiveClickDeltaToCenter;
|
||||||
|
float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings
|
||||||
|
ImVec2 DragLastMouseDelta;
|
||||||
|
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
|
||||||
|
float DragSpeedScaleSlow;
|
||||||
|
float DragSpeedScaleFast;
|
||||||
|
ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
|
||||||
|
char Tooltip[1024];
|
||||||
|
char* PrivateClipboard; // If no custom clipboard handler is defined
|
||||||
|
ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
bool LogEnabled;
|
||||||
|
FILE* LogFile; // If != NULL log to stdout/ file
|
||||||
|
ImGuiTextBuffer* LogClipboard; // Else log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.
|
||||||
|
int LogStartDepth;
|
||||||
|
int LogAutoExpandMaxDepth;
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
float FramerateSecPerFrame[120]; // calculate estimate of framerate for user
|
||||||
|
int FramerateSecPerFrameIdx;
|
||||||
|
float FramerateSecPerFrameAccum;
|
||||||
|
int CaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags
|
||||||
|
int CaptureKeyboardNextFrame;
|
||||||
|
char TempBuffer[1024*3+1]; // temporary text buffer
|
||||||
|
|
||||||
|
ImGuiContext()
|
||||||
|
{
|
||||||
|
Initialized = false;
|
||||||
|
Font = NULL;
|
||||||
|
FontSize = FontBaseSize = 0.0f;
|
||||||
|
FontTexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
||||||
|
|
||||||
|
Time = 0.0f;
|
||||||
|
FrameCount = 0;
|
||||||
|
FrameCountEnded = FrameCountRendered = -1;
|
||||||
|
CurrentWindow = NULL;
|
||||||
|
FocusedWindow = NULL;
|
||||||
|
HoveredWindow = NULL;
|
||||||
|
HoveredRootWindow = NULL;
|
||||||
|
HoveredId = 0;
|
||||||
|
HoveredIdAllowOverlap = false;
|
||||||
|
HoveredIdPreviousFrame = 0;
|
||||||
|
ActiveId = 0;
|
||||||
|
ActiveIdPreviousFrame = 0;
|
||||||
|
ActiveIdIsAlive = false;
|
||||||
|
ActiveIdIsJustActivated = false;
|
||||||
|
ActiveIdAllowOverlap = false;
|
||||||
|
ActiveIdWindow = NULL;
|
||||||
|
MovedWindow = NULL;
|
||||||
|
MovedWindowMoveId = 0;
|
||||||
|
SettingsDirtyTimer = 0.0f;
|
||||||
|
|
||||||
|
SetNextWindowPosVal = ImVec2(0.0f, 0.0f);
|
||||||
|
SetNextWindowSizeVal = ImVec2(0.0f, 0.0f);
|
||||||
|
SetNextWindowCollapsedVal = false;
|
||||||
|
SetNextWindowPosCond = 0;
|
||||||
|
SetNextWindowSizeCond = 0;
|
||||||
|
SetNextWindowContentSizeCond = 0;
|
||||||
|
SetNextWindowCollapsedCond = 0;
|
||||||
|
SetNextWindowFocus = false;
|
||||||
|
SetNextTreeNodeOpenVal = false;
|
||||||
|
SetNextTreeNodeOpenCond = 0;
|
||||||
|
|
||||||
|
ScalarAsInputTextId = 0;
|
||||||
|
ActiveClickDeltaToCenter = ImVec2(0.0f, 0.0f);
|
||||||
|
DragCurrentValue = 0.0f;
|
||||||
|
DragLastMouseDelta = ImVec2(0.0f, 0.0f);
|
||||||
|
DragSpeedDefaultRatio = 0.01f;
|
||||||
|
DragSpeedScaleSlow = 0.01f;
|
||||||
|
DragSpeedScaleFast = 10.0f;
|
||||||
|
ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
|
||||||
|
memset(Tooltip, 0, sizeof(Tooltip));
|
||||||
|
PrivateClipboard = NULL;
|
||||||
|
OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f);
|
||||||
|
|
||||||
|
ModalWindowDarkeningRatio = 0.0f;
|
||||||
|
OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging
|
||||||
|
MouseCursor = ImGuiMouseCursor_Arrow;
|
||||||
|
memset(MouseCursorData, 0, sizeof(MouseCursorData));
|
||||||
|
|
||||||
|
LogEnabled = false;
|
||||||
|
LogFile = NULL;
|
||||||
|
LogClipboard = NULL;
|
||||||
|
LogStartDepth = 0;
|
||||||
|
LogAutoExpandMaxDepth = 2;
|
||||||
|
|
||||||
|
memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
|
||||||
|
FramerateSecPerFrameIdx = 0;
|
||||||
|
FramerateSecPerFrameAccum = 0.0f;
|
||||||
|
CaptureMouseNextFrame = CaptureKeyboardNextFrame = -1;
|
||||||
|
memset(TempBuffer, 0, sizeof(TempBuffer));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transient per-window data, reset at the beginning of the frame
|
||||||
|
// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered.
|
||||||
|
struct IMGUI_API ImGuiDrawContext
|
||||||
|
{
|
||||||
|
ImVec2 CursorPos;
|
||||||
|
ImVec2 CursorPosPrevLine;
|
||||||
|
ImVec2 CursorStartPos;
|
||||||
|
ImVec2 CursorMaxPos; // Implicitly calculate the size of our contents, always extending. Saved into window->SizeContents at the end of the frame
|
||||||
|
float CurrentLineHeight;
|
||||||
|
float CurrentLineTextBaseOffset;
|
||||||
|
float PrevLineHeight;
|
||||||
|
float PrevLineTextBaseOffset;
|
||||||
|
float LogLinePosY;
|
||||||
|
int TreeDepth;
|
||||||
|
ImGuiID LastItemID;
|
||||||
|
ImRect LastItemRect;
|
||||||
|
bool LastItemHoveredAndUsable; // Item rectangle is hovered, and its window is currently interactable with (not blocked by a popup preventing access to the window)
|
||||||
|
bool LastItemHoveredRect; // Item rectangle is hovered, but its window may or not be currently interactable with (might be blocked by a popup preventing access to the window)
|
||||||
|
bool MenuBarAppending;
|
||||||
|
float MenuBarOffsetX;
|
||||||
|
ImVector<ImGuiWindow*> ChildWindows;
|
||||||
|
ImGuiStorage* StateStorage;
|
||||||
|
ImGuiLayoutType LayoutType;
|
||||||
|
|
||||||
|
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
|
||||||
|
float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
|
||||||
|
float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f]
|
||||||
|
bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true]
|
||||||
|
bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false]
|
||||||
|
ImVector<float> ItemWidthStack;
|
||||||
|
ImVector<float> TextWrapPosStack;
|
||||||
|
ImVector<bool> AllowKeyboardFocusStack;
|
||||||
|
ImVector<bool> ButtonRepeatStack;
|
||||||
|
ImVector<ImGuiGroupData>GroupStack;
|
||||||
|
ImGuiColorEditMode ColorEditMode;
|
||||||
|
int StackSizesBackup[6]; // Store size of various stacks for asserting
|
||||||
|
|
||||||
|
float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
|
||||||
|
float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
|
||||||
|
int ColumnsCurrent;
|
||||||
|
int ColumnsCount;
|
||||||
|
float ColumnsMinX;
|
||||||
|
float ColumnsMaxX;
|
||||||
|
float ColumnsStartPosY;
|
||||||
|
float ColumnsCellMinY;
|
||||||
|
float ColumnsCellMaxY;
|
||||||
|
bool ColumnsShowBorders;
|
||||||
|
ImGuiID ColumnsSetID;
|
||||||
|
ImVector<ImGuiColumnData> ColumnsData;
|
||||||
|
|
||||||
|
ImGuiDrawContext()
|
||||||
|
{
|
||||||
|
CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f);
|
||||||
|
CurrentLineHeight = PrevLineHeight = 0.0f;
|
||||||
|
CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
|
||||||
|
LogLinePosY = -1.0f;
|
||||||
|
TreeDepth = 0;
|
||||||
|
LastItemID = 0;
|
||||||
|
LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f);
|
||||||
|
LastItemHoveredAndUsable = LastItemHoveredRect = false;
|
||||||
|
MenuBarAppending = false;
|
||||||
|
MenuBarOffsetX = 0.0f;
|
||||||
|
StateStorage = NULL;
|
||||||
|
LayoutType = ImGuiLayoutType_Vertical;
|
||||||
|
ItemWidth = 0.0f;
|
||||||
|
ButtonRepeat = false;
|
||||||
|
AllowKeyboardFocus = true;
|
||||||
|
TextWrapPos = -1.0f;
|
||||||
|
ColorEditMode = ImGuiColorEditMode_RGB;
|
||||||
|
memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
|
||||||
|
|
||||||
|
IndentX = 0.0f;
|
||||||
|
ColumnsOffsetX = 0.0f;
|
||||||
|
ColumnsCurrent = 0;
|
||||||
|
ColumnsCount = 1;
|
||||||
|
ColumnsMinX = ColumnsMaxX = 0.0f;
|
||||||
|
ColumnsStartPosY = 0.0f;
|
||||||
|
ColumnsCellMinY = ColumnsCellMaxY = 0.0f;
|
||||||
|
ColumnsShowBorders = true;
|
||||||
|
ColumnsSetID = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Windows data
|
||||||
|
struct IMGUI_API ImGuiWindow
|
||||||
|
{
|
||||||
|
char* Name;
|
||||||
|
ImGuiID ID; // == ImHash(Name)
|
||||||
|
ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_
|
||||||
|
int IndexWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
|
||||||
|
ImVec2 PosFloat;
|
||||||
|
ImVec2 Pos; // Position rounded-up to nearest pixel
|
||||||
|
ImVec2 Size; // Current size (==SizeFull or collapsed title bar size)
|
||||||
|
ImVec2 SizeFull; // Size when non collapsed
|
||||||
|
ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame
|
||||||
|
ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize()
|
||||||
|
ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect
|
||||||
|
ImGuiID MoveID; // == window->GetID("#MOVE")
|
||||||
|
ImVec2 Scroll;
|
||||||
|
ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
|
||||||
|
ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
|
||||||
|
bool ScrollbarX, ScrollbarY;
|
||||||
|
ImVec2 ScrollbarSizes;
|
||||||
|
float BorderSize;
|
||||||
|
bool Active; // Set to true on Begin()
|
||||||
|
bool WasActive;
|
||||||
|
bool Accessed; // Set to true when any widget access the current window
|
||||||
|
bool Collapsed; // Set when collapsing window to become only title-bar
|
||||||
|
bool SkipItems; // == Visible && !Collapsed
|
||||||
|
int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
|
||||||
|
ImGuiID PopupID; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
|
||||||
|
int AutoFitFramesX, AutoFitFramesY;
|
||||||
|
bool AutoFitOnlyGrows;
|
||||||
|
int AutoPosLastDirection;
|
||||||
|
int HiddenFrames;
|
||||||
|
int SetWindowPosAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowPos() call will succeed with this particular flag.
|
||||||
|
int SetWindowSizeAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowSize() call will succeed with this particular flag.
|
||||||
|
int SetWindowCollapsedAllowFlags; // bit ImGuiSetCond_*** specify if SetWindowCollapsed() call will succeed with this particular flag.
|
||||||
|
bool SetWindowPosCenterWanted;
|
||||||
|
|
||||||
|
ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame
|
||||||
|
ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack
|
||||||
|
ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2.
|
||||||
|
ImRect WindowRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window.
|
||||||
|
int LastFrameActive;
|
||||||
|
float ItemWidthDefault;
|
||||||
|
ImGuiSimpleColumns MenuColumns; // Simplified columns storage for menu items
|
||||||
|
ImGuiStorage StateStorage;
|
||||||
|
float FontWindowScale; // Scale multiplier per-window
|
||||||
|
ImDrawList* DrawList;
|
||||||
|
ImGuiWindow* RootWindow; // If we are a child window, this is pointing to the first non-child parent window. Else point to ourself.
|
||||||
|
ImGuiWindow* RootNonPopupWindow; // If we are a child window, this is pointing to the first non-child non-popup parent window. Else point to ourself.
|
||||||
|
ImGuiWindow* ParentWindow; // If we are a child window, this is pointing to our parent window. Else point to NULL.
|
||||||
|
|
||||||
|
// Focus
|
||||||
|
int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister()
|
||||||
|
int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through)
|
||||||
|
int FocusIdxAllRequestCurrent; // Item being requested for focus
|
||||||
|
int FocusIdxTabRequestCurrent; // Tab-able item being requested for focus
|
||||||
|
int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame)
|
||||||
|
int FocusIdxTabRequestNext; // "
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImGuiWindow(const char* name);
|
||||||
|
~ImGuiWindow();
|
||||||
|
|
||||||
|
ImGuiID GetID(const char* str, const char* str_end = NULL);
|
||||||
|
ImGuiID GetID(const void* ptr);
|
||||||
|
|
||||||
|
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
|
||||||
|
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
|
||||||
|
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
|
||||||
|
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
|
||||||
|
float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; }
|
||||||
|
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Internal API
|
||||||
|
// No guarantee of forward compatibility here.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ImGui
|
||||||
|
{
|
||||||
|
// We should always have a CurrentWindow in the stack (there is an implicit "Debug" window)
|
||||||
|
// If this ever crash because g.CurrentWindow is NULL it means that either
|
||||||
|
// - ImGui::NewFrame() has never been called, which is illegal.
|
||||||
|
// - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
||||||
|
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
||||||
|
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->Accessed = true; return g.CurrentWindow; }
|
||||||
|
IMGUI_API ImGuiWindow* GetParentWindow();
|
||||||
|
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
|
||||||
|
IMGUI_API void FocusWindow(ImGuiWindow* window);
|
||||||
|
|
||||||
|
IMGUI_API void EndFrame(); // Ends the ImGui frame. Automatically called by Render()! you most likely don't need to ever call that yourself directly. If you don't need to render you can call EndFrame() but you'll have wasted CPU already. If you don't need to render, don't create any windows instead!
|
||||||
|
|
||||||
|
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window);
|
||||||
|
IMGUI_API void SetHoveredID(ImGuiID id);
|
||||||
|
IMGUI_API void KeepAliveID(ImGuiID id);
|
||||||
|
|
||||||
|
IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f);
|
||||||
|
IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
|
||||||
|
IMGUI_API bool ItemAdd(const ImRect& bb, const ImGuiID* id);
|
||||||
|
IMGUI_API bool IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged);
|
||||||
|
IMGUI_API bool IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs = false);
|
||||||
|
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, bool is_active, bool tab_stop = true); // Return true if focus is requested
|
||||||
|
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
|
||||||
|
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y);
|
||||||
|
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
||||||
|
|
||||||
|
IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing);
|
||||||
|
|
||||||
|
inline IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; return ImGui::ColorConvertFloat4ToU32(c); }
|
||||||
|
inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
|
||||||
|
|
||||||
|
// NB: All position are in absolute pixels coordinates (not window coordinates)
|
||||||
|
// FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp!
|
||||||
|
// We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers.
|
||||||
|
IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
|
||||||
|
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
|
||||||
|
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align = ImGuiAlign_Default, const ImVec2* clip_min = NULL, const ImVec2* clip_max = NULL);
|
||||||
|
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
|
||||||
|
IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale = 1.0f, bool shadow = false);
|
||||||
|
IMGUI_API void RenderBullet(ImVec2 pos);
|
||||||
|
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col);
|
||||||
|
IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text.
|
||||||
|
|
||||||
|
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
|
||||||
|
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
|
||||||
|
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius);
|
||||||
|
|
||||||
|
IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags = 0);
|
||||||
|
IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power);
|
||||||
|
IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format);
|
||||||
|
|
||||||
|
IMGUI_API bool DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power);
|
||||||
|
IMGUI_API bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power);
|
||||||
|
IMGUI_API bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format);
|
||||||
|
|
||||||
|
IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
|
||||||
|
IMGUI_API bool InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags);
|
||||||
|
IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags);
|
||||||
|
IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags);
|
||||||
|
IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision);
|
||||||
|
|
||||||
|
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
|
||||||
|
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging
|
||||||
|
IMGUI_API void TreePushRawID(ImGuiID id);
|
||||||
|
|
||||||
|
IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size);
|
||||||
|
|
||||||
|
IMGUI_API int ParseFormatPrecision(const char* fmt, int default_value);
|
||||||
|
IMGUI_API float RoundScalar(float value, int decimal_precision);
|
||||||
|
|
||||||
|
} // namespace ImGuiP
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
573
external/imgui/stb_rect_pack.h
vendored
Normal file
573
external/imgui/stb_rect_pack.h
vendored
Normal file
@ -0,0 +1,573 @@
|
|||||||
|
// stb_rect_pack.h - v0.08 - public domain - rectangle packing
|
||||||
|
// Sean Barrett 2014
|
||||||
|
//
|
||||||
|
// Useful for e.g. packing rectangular textures into an atlas.
|
||||||
|
// Does not do rotation.
|
||||||
|
//
|
||||||
|
// Not necessarily the awesomest packing method, but better than
|
||||||
|
// the totally naive one in stb_truetype (which is primarily what
|
||||||
|
// this is meant to replace).
|
||||||
|
//
|
||||||
|
// Has only had a few tests run, may have issues.
|
||||||
|
//
|
||||||
|
// More docs to come.
|
||||||
|
//
|
||||||
|
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||||
|
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||||
|
//
|
||||||
|
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||||
|
//
|
||||||
|
// Please note: better rectangle packers are welcome! Please
|
||||||
|
// implement them to the same API, but with a different init
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// Credits
|
||||||
|
//
|
||||||
|
// Library
|
||||||
|
// Sean Barrett
|
||||||
|
// Minor features
|
||||||
|
// Martins Mozeiko
|
||||||
|
// Bugfixes / warning fixes
|
||||||
|
// Jeremy Jaussaud
|
||||||
|
//
|
||||||
|
// Version history:
|
||||||
|
//
|
||||||
|
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||||
|
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||||
|
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||||
|
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||||
|
// 0.01: initial release
|
||||||
|
//
|
||||||
|
// LICENSE
|
||||||
|
//
|
||||||
|
// This software is in the public domain. Where that dedication is not
|
||||||
|
// recognized, you are granted a perpetual, irrevocable license to copy,
|
||||||
|
// distribute, and modify this file as you see fit.
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INCLUDE SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_VERSION 1
|
||||||
|
|
||||||
|
#ifdef STBRP_STATIC
|
||||||
|
#define STBRP_DEF static
|
||||||
|
#else
|
||||||
|
#define STBRP_DEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct stbrp_context stbrp_context;
|
||||||
|
typedef struct stbrp_node stbrp_node;
|
||||||
|
typedef struct stbrp_rect stbrp_rect;
|
||||||
|
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
typedef int stbrp_coord;
|
||||||
|
#else
|
||||||
|
typedef unsigned short stbrp_coord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||||
|
// Assign packed locations to rectangles. The rectangles are of type
|
||||||
|
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||||
|
// are 'num_rects' many of them.
|
||||||
|
//
|
||||||
|
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||||
|
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||||
|
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||||
|
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||||
|
// have the 'was_packed' flag set to 0.
|
||||||
|
//
|
||||||
|
// You should not try to access the 'rects' array from another thread
|
||||||
|
// while this function is running, as the function temporarily reorders
|
||||||
|
// the array while it executes.
|
||||||
|
//
|
||||||
|
// To pack into another rectangle, you need to call stbrp_init_target
|
||||||
|
// again. To continue packing into the same rectangle, you can call
|
||||||
|
// this function again. Calling this multiple times with multiple rect
|
||||||
|
// arrays will probably produce worse packing results than calling it
|
||||||
|
// a single time with the full rectangle array, but the option is
|
||||||
|
// available.
|
||||||
|
|
||||||
|
struct stbrp_rect
|
||||||
|
{
|
||||||
|
// reserved for your use:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
// input:
|
||||||
|
stbrp_coord w, h;
|
||||||
|
|
||||||
|
// output:
|
||||||
|
stbrp_coord x, y;
|
||||||
|
int was_packed; // non-zero if valid packing
|
||||||
|
|
||||||
|
}; // 16 bytes, nominally
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||||
|
// Initialize a rectangle packer to:
|
||||||
|
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||||
|
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||||
|
//
|
||||||
|
// You must call this function every time you start packing into a new target.
|
||||||
|
//
|
||||||
|
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||||
|
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||||
|
// the call (or calls) finish.
|
||||||
|
//
|
||||||
|
// Note: to guarantee best results, either:
|
||||||
|
// 1. make sure 'num_nodes' >= 'width'
|
||||||
|
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||||
|
//
|
||||||
|
// If you don't do either of the above things, widths will be quantized to multiples
|
||||||
|
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||||
|
//
|
||||||
|
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||||
|
// may run out of temporary storage and be unable to pack some rectangles.
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||||
|
// Optionally call this function after init but before doing any packing to
|
||||||
|
// change the handling of the out-of-temp-memory scenario, described above.
|
||||||
|
// If you call init again, this will be reset to the default (false).
|
||||||
|
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||||
|
// Optionally select which packing heuristic the library should use. Different
|
||||||
|
// heuristics will produce better/worse results for different data sets.
|
||||||
|
// If you call init again, this will be reset to the default.
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP_HEURISTIC_Skyline_default=0,
|
||||||
|
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||||
|
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// the details of the following structures don't matter to you, but they must
|
||||||
|
// be visible so you can handle the memory allocations for them
|
||||||
|
|
||||||
|
struct stbrp_node
|
||||||
|
{
|
||||||
|
stbrp_coord x,y;
|
||||||
|
stbrp_node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stbrp_context
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int align;
|
||||||
|
int init_mode;
|
||||||
|
int heuristic;
|
||||||
|
int num_nodes;
|
||||||
|
stbrp_node *active_head;
|
||||||
|
stbrp_node *free_head;
|
||||||
|
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// IMPLEMENTATION SECTION
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#ifndef STBRP_SORT
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define STBRP_SORT qsort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STBRP_ASSERT
|
||||||
|
#include <assert.h>
|
||||||
|
#define STBRP_ASSERT assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STBRP__INIT_skyline = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||||
|
{
|
||||||
|
switch (context->init_mode) {
|
||||||
|
case STBRP__INIT_skyline:
|
||||||
|
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||||
|
context->heuristic = heuristic;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
STBRP_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||||
|
{
|
||||||
|
if (allow_out_of_mem)
|
||||||
|
// if it's ok to run out of memory, then don't bother aligning them;
|
||||||
|
// this gives better packing, but may fail due to OOM (even though
|
||||||
|
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||||
|
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||||
|
context->align = 1;
|
||||||
|
else {
|
||||||
|
// if it's not ok to run out of memory, then quantize the widths
|
||||||
|
// so that num_nodes is always enough nodes.
|
||||||
|
//
|
||||||
|
// I.e. num_nodes * align >= width
|
||||||
|
// align >= width / num_nodes
|
||||||
|
// align = ceil(width/num_nodes)
|
||||||
|
|
||||||
|
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#ifndef STBRP_LARGE_RECTS
|
||||||
|
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i=0; i < num_nodes-1; ++i)
|
||||||
|
nodes[i].next = &nodes[i+1];
|
||||||
|
nodes[i].next = NULL;
|
||||||
|
context->init_mode = STBRP__INIT_skyline;
|
||||||
|
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||||
|
context->free_head = &nodes[0];
|
||||||
|
context->active_head = &context->extra[0];
|
||||||
|
context->width = width;
|
||||||
|
context->height = height;
|
||||||
|
context->num_nodes = num_nodes;
|
||||||
|
stbrp_setup_allow_out_of_mem(context, 0);
|
||||||
|
|
||||||
|
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||||
|
context->extra[0].x = 0;
|
||||||
|
context->extra[0].y = 0;
|
||||||
|
context->extra[0].next = &context->extra[1];
|
||||||
|
context->extra[1].x = (stbrp_coord) width;
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
context->extra[1].y = (1<<30);
|
||||||
|
#else
|
||||||
|
context->extra[1].y = 65535;
|
||||||
|
#endif
|
||||||
|
context->extra[1].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find minimum y position if it starts at x1
|
||||||
|
static int stbrp__skyline_find_min_y(stbrp_context *, stbrp_node *first, int x0, int width, int *pwaste)
|
||||||
|
{
|
||||||
|
//(void)c;
|
||||||
|
stbrp_node *node = first;
|
||||||
|
int x1 = x0 + width;
|
||||||
|
int min_y, visited_width, waste_area;
|
||||||
|
STBRP_ASSERT(first->x <= x0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// skip in case we're past the node
|
||||||
|
while (node->next->x <= x0)
|
||||||
|
++node;
|
||||||
|
#else
|
||||||
|
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_ASSERT(node->x <= x0);
|
||||||
|
|
||||||
|
min_y = 0;
|
||||||
|
waste_area = 0;
|
||||||
|
visited_width = 0;
|
||||||
|
while (node->x < x1) {
|
||||||
|
if (node->y > min_y) {
|
||||||
|
// raise min_y higher.
|
||||||
|
// we've accounted for all waste up to min_y,
|
||||||
|
// but we'll now add more waste for everything we've visted
|
||||||
|
waste_area += visited_width * (node->y - min_y);
|
||||||
|
min_y = node->y;
|
||||||
|
// the first time through, visited_width might be reduced
|
||||||
|
if (node->x < x0)
|
||||||
|
visited_width += node->next->x - x0;
|
||||||
|
else
|
||||||
|
visited_width += node->next->x - node->x;
|
||||||
|
} else {
|
||||||
|
// add waste area
|
||||||
|
int under_width = node->next->x - node->x;
|
||||||
|
if (under_width + visited_width > width)
|
||||||
|
under_width = width - visited_width;
|
||||||
|
waste_area += under_width * (min_y - node->y);
|
||||||
|
visited_width += under_width;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pwaste = waste_area;
|
||||||
|
return min_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x,y;
|
||||||
|
stbrp_node **prev_link;
|
||||||
|
} stbrp__findresult;
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||||
|
{
|
||||||
|
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||||
|
stbrp__findresult fr;
|
||||||
|
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||||
|
|
||||||
|
// align to multiple of c->align
|
||||||
|
width = (width + c->align - 1);
|
||||||
|
width -= width % c->align;
|
||||||
|
STBRP_ASSERT(width % c->align == 0);
|
||||||
|
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
while (node->x + width <= c->width) {
|
||||||
|
int y,waste;
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||||
|
// bottom left
|
||||||
|
if (y < best_y) {
|
||||||
|
best_y = y;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// best-fit
|
||||||
|
if (y + height <= c->height) {
|
||||||
|
// can only use it if it first vertically
|
||||||
|
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||||
|
|
||||||
|
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||||
|
//
|
||||||
|
// e.g, if fitting
|
||||||
|
//
|
||||||
|
// ____________________
|
||||||
|
// |____________________|
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | ____________|
|
||||||
|
// |____________|
|
||||||
|
//
|
||||||
|
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||||
|
//
|
||||||
|
// This makes BF take about 2x the time
|
||||||
|
|
||||||
|
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||||
|
tail = c->active_head;
|
||||||
|
node = c->active_head;
|
||||||
|
prev = &c->active_head;
|
||||||
|
// find first node that's admissible
|
||||||
|
while (tail->x < width)
|
||||||
|
tail = tail->next;
|
||||||
|
while (tail) {
|
||||||
|
int xpos = tail->x - width;
|
||||||
|
int y,waste;
|
||||||
|
STBRP_ASSERT(xpos >= 0);
|
||||||
|
// find the left position that matches this
|
||||||
|
while (node->next->x <= xpos) {
|
||||||
|
prev = &node->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||||
|
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||||
|
if (y + height < c->height) {
|
||||||
|
if (y <= best_y) {
|
||||||
|
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||||
|
best_x = xpos;
|
||||||
|
STBRP_ASSERT(y <= best_y);
|
||||||
|
best_y = y;
|
||||||
|
best_waste = waste;
|
||||||
|
best = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tail = tail->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.prev_link = best;
|
||||||
|
fr.x = best_x;
|
||||||
|
fr.y = best_y;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||||
|
{
|
||||||
|
// find best position according to heuristic
|
||||||
|
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||||
|
stbrp_node *node, *cur;
|
||||||
|
|
||||||
|
// bail if:
|
||||||
|
// 1. it failed
|
||||||
|
// 2. the best node doesn't fit (we don't always check this)
|
||||||
|
// 3. we're out of memory
|
||||||
|
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||||
|
res.prev_link = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on success, create new node
|
||||||
|
node = context->free_head;
|
||||||
|
node->x = (stbrp_coord) res.x;
|
||||||
|
node->y = (stbrp_coord) (res.y + height);
|
||||||
|
|
||||||
|
context->free_head = node->next;
|
||||||
|
|
||||||
|
// insert the new node into the right starting point, and
|
||||||
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
|
// stiched back in
|
||||||
|
|
||||||
|
cur = *res.prev_link;
|
||||||
|
if (cur->x < res.x) {
|
||||||
|
// preserve the existing one, so start testing with the next one
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
cur->next = node;
|
||||||
|
cur = next;
|
||||||
|
} else {
|
||||||
|
*res.prev_link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from here, traverse cur and free the nodes, until we get to one
|
||||||
|
// that shouldn't be freed
|
||||||
|
while (cur->next && cur->next->x <= res.x + width) {
|
||||||
|
stbrp_node *next = cur->next;
|
||||||
|
// move the current node to the free list
|
||||||
|
cur->next = context->free_head;
|
||||||
|
context->free_head = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stitch the list back in
|
||||||
|
node->next = cur;
|
||||||
|
|
||||||
|
if (cur->x < res.x + width)
|
||||||
|
cur->x = (stbrp_coord) (res.x + width);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur->x < context->width) {
|
||||||
|
STBRP_ASSERT(cur->x < cur->next->x);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(cur->next == NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
stbrp_node *L1 = NULL, *L2 = NULL;
|
||||||
|
int count=0;
|
||||||
|
cur = context->active_head;
|
||||||
|
while (cur) {
|
||||||
|
L1 = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
cur = context->free_head;
|
||||||
|
while (cur) {
|
||||||
|
L2 = cur;
|
||||||
|
cur = cur->next;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
STBRP_ASSERT(count == context->num_nodes+2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rect_height_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
stbrp_rect *p = (stbrp_rect *) a;
|
||||||
|
stbrp_rect *q = (stbrp_rect *) b;
|
||||||
|
if (p->h > q->h)
|
||||||
|
return -1;
|
||||||
|
if (p->h < q->h)
|
||||||
|
return 1;
|
||||||
|
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rect_width_compare(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
stbrp_rect *p = (stbrp_rect *) a;
|
||||||
|
stbrp_rect *q = (stbrp_rect *) b;
|
||||||
|
if (p->w > q->w)
|
||||||
|
return -1;
|
||||||
|
if (p->w < q->w)
|
||||||
|
return 1;
|
||||||
|
return (p->h > q->h) ? -1 : (p->h < q->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rect_original_order(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
stbrp_rect *p = (stbrp_rect *) a;
|
||||||
|
stbrp_rect *q = (stbrp_rect *) b;
|
||||||
|
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STBRP_LARGE_RECTS
|
||||||
|
#define STBRP__MAXVAL 0xffffffff
|
||||||
|
#else
|
||||||
|
#define STBRP__MAXVAL 0xffff
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
rects[i].was_packed = i;
|
||||||
|
#ifndef STBRP_LARGE_RECTS
|
||||||
|
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort according to heuristic
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||||
|
|
||||||
|
for (i=0; i < num_rects; ++i) {
|
||||||
|
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||||
|
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||||
|
} else {
|
||||||
|
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||||
|
if (fr.prev_link) {
|
||||||
|
rects[i].x = (stbrp_coord) fr.x;
|
||||||
|
rects[i].y = (stbrp_coord) fr.y;
|
||||||
|
} else {
|
||||||
|
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsort
|
||||||
|
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||||
|
|
||||||
|
// set was_packed flags
|
||||||
|
for (i=0; i < num_rects; ++i)
|
||||||
|
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||||
|
}
|
||||||
|
#endif
|
1317
external/imgui/stb_textedit.h
vendored
Normal file
1317
external/imgui/stb_textedit.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3263
external/imgui/stb_truetype.h
vendored
Normal file
3263
external/imgui/stb_truetype.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
60
include/bounce/bounce.h
Normal file
60
include/bounce/bounce.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 BOUNCE_H
|
||||||
|
#define BOUNCE_H
|
||||||
|
|
||||||
|
// Include this file header in your project to directly access Bounce objects.
|
||||||
|
|
||||||
|
#include <bounce\common\settings.h>
|
||||||
|
#include <bounce\common\math\math.h>
|
||||||
|
#include <bounce\common\time.h>
|
||||||
|
#include <bounce\common\draw.h>
|
||||||
|
|
||||||
|
#include <bounce\collision\broad_phase.h>
|
||||||
|
#include <bounce\collision\gjk\gjk.h>
|
||||||
|
#include <bounce\collision\gjk\gjk_cache.h>
|
||||||
|
#include <bounce\collision\sat\sat.h>
|
||||||
|
|
||||||
|
#include <bounce\collision\shapes\sphere.h>
|
||||||
|
#include <bounce\collision\shapes\capsule.h>
|
||||||
|
#include <bounce\collision\shapes\hull.h>
|
||||||
|
#include <bounce\collision\shapes\triangle_hull.h>
|
||||||
|
#include <bounce\collision\shapes\box_hull.h>
|
||||||
|
#include <bounce\collision\shapes\mesh.h>
|
||||||
|
|
||||||
|
#include <bounce\dynamics\joints\mouse_joint.h>
|
||||||
|
#include <bounce\dynamics\joints\spring_joint.h>
|
||||||
|
#include <bounce\dynamics\joints\sphere_joint.h>
|
||||||
|
#include <bounce\dynamics\joints\revolute_joint.h>
|
||||||
|
#include <bounce\dynamics\joints\cone_joint.h>
|
||||||
|
|
||||||
|
#include <bounce\dynamics\shapes\sphere_shape.h>
|
||||||
|
#include <bounce\dynamics\shapes\capsule_shape.h>
|
||||||
|
#include <bounce\dynamics\shapes\hull_shape.h>
|
||||||
|
#include <bounce\dynamics\shapes\mesh_shape.h>
|
||||||
|
|
||||||
|
#include <bounce\dynamics\contacts\contact.h>
|
||||||
|
#include <bounce\dynamics\contacts\convex_contact.h>
|
||||||
|
#include <bounce\dynamics\contacts\mesh_contact.h>
|
||||||
|
|
||||||
|
#include <bounce\dynamics\body.h>
|
||||||
|
#include <bounce\dynamics\world.h>
|
||||||
|
#include <bounce\dynamics\world_listeners.h>
|
||||||
|
|
||||||
|
#endif
|
197
include/bounce/collision/broad_phase.h
Normal file
197
include/bounce/collision/broad_phase.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_BROAD_PHASE_H
|
||||||
|
#define B3_BROAD_PHASE_H
|
||||||
|
|
||||||
|
#include <bounce\collision\trees\dynamic_tree.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// A pair of broad-phase proxies.
|
||||||
|
struct b3Pair
|
||||||
|
{
|
||||||
|
i32 proxy1;
|
||||||
|
i32 proxy2;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The broad-phase collision interface.
|
||||||
|
// It is used to perform ray, AABB, and overlapping-pair queries
|
||||||
|
// against AABBs.
|
||||||
|
class b3BroadPhase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
b3BroadPhase();
|
||||||
|
~b3BroadPhase();
|
||||||
|
|
||||||
|
// Create a broad-phase proxy and return a proxy.
|
||||||
|
i32 CreateProxy(const b3AABB3& aabb, void* userData);
|
||||||
|
|
||||||
|
// Destroy an existing proxy.
|
||||||
|
void DestroyProxy(i32 proxyId);
|
||||||
|
|
||||||
|
// Update an existing proxy with a given AABB and a displacement.
|
||||||
|
// displacement = int[a, b](dv/dt) dt = F(b) - F(a) = x(b) - x(a) ~= v * dt
|
||||||
|
// Return true if the proxy has moved.
|
||||||
|
bool MoveProxy(i32 proxyId, const b3AABB3& aabb, const b3Vec3& displacement);
|
||||||
|
|
||||||
|
// Get the AABB of a given proxy.
|
||||||
|
const b3AABB3& GetAABB(i32 proxyId) const;
|
||||||
|
|
||||||
|
// Get the user data attached to a proxy.
|
||||||
|
void* GetUserData(i32 proxyId) const;
|
||||||
|
|
||||||
|
// Test if two proxy AABBs are overlapping.
|
||||||
|
bool TestOverlap(i32 proxy1, i32 proxy2) const;
|
||||||
|
|
||||||
|
// Notify the client callback the AABBs that are overlapping with the passed AABB.
|
||||||
|
template<class T>
|
||||||
|
void QueryAABB(T* callback, const b3AABB3& aabb) const;
|
||||||
|
|
||||||
|
// Notify the client callback the AABBs that are overlapping the
|
||||||
|
// passed ray.
|
||||||
|
template<class T>
|
||||||
|
void QueryRay(T* callback, const b3RayCastInput& input) const;
|
||||||
|
|
||||||
|
// Notify the client callback the AABB pairs that are overlapping.
|
||||||
|
// The client must store the notified pairs.
|
||||||
|
template<class T>
|
||||||
|
void FindNewPairs(T* callback);
|
||||||
|
|
||||||
|
// Debug b3Draw the AABB proxies.
|
||||||
|
void Draw(b3Draw* b3Draw) const;
|
||||||
|
private :
|
||||||
|
friend class b3DynamicTree;
|
||||||
|
|
||||||
|
// Add a proxy to the list of moved proxies.
|
||||||
|
// Only moved proxies will be used as an AABB query reference object.
|
||||||
|
void BufferMove(i32 proxyId);
|
||||||
|
|
||||||
|
// The client callback used to add a overlapping pair
|
||||||
|
// to the overlapping pair buffer.
|
||||||
|
bool Report(i32 proxyId);
|
||||||
|
|
||||||
|
// The dynamic tree.
|
||||||
|
b3DynamicTree m_tree;
|
||||||
|
|
||||||
|
// The current proxy being queried for
|
||||||
|
// overlap witha another proxies. Is used to avoid a proxy overlap with itself.
|
||||||
|
i32 m_queryProxyId;
|
||||||
|
|
||||||
|
// Keep a buffer of the objects that have moved in a step.
|
||||||
|
i32* m_moveBuffer;
|
||||||
|
u32 m_moveBufferCount;
|
||||||
|
u32 m_moveBufferCapacity;
|
||||||
|
|
||||||
|
// The buffer holding the unique overlapping AABB pairs.
|
||||||
|
b3Pair* m_pairBuffer;
|
||||||
|
u32 m_pairBufferCapacity;
|
||||||
|
u32 m_pairBufferCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const b3AABB3& b3BroadPhase::GetAABB(i32 proxyId) const
|
||||||
|
{
|
||||||
|
return m_tree.GetAABB(proxyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* b3BroadPhase::GetUserData(i32 proxyId) const
|
||||||
|
{
|
||||||
|
return m_tree.GetUserData(proxyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3BroadPhase::QueryAABB(T* callback, const b3AABB3& aabb) const
|
||||||
|
{
|
||||||
|
return m_tree.QueryAABB(callback, aabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3BroadPhase::QueryRay(T* callback, const b3RayCastInput& input) const
|
||||||
|
{
|
||||||
|
return m_tree.QueryRay(callback, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator<(const b3Pair& pair1, const b3Pair& pair2)
|
||||||
|
{
|
||||||
|
if (pair1.proxy1 < pair2.proxy1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair1.proxy1 == pair2.proxy1)
|
||||||
|
{
|
||||||
|
return pair1.proxy2 < pair2.proxy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3BroadPhase::FindNewPairs(T* callback)
|
||||||
|
{
|
||||||
|
// Reset the overlapping pairs buffer count for the current step.
|
||||||
|
m_pairBufferCount = 0;
|
||||||
|
|
||||||
|
// Notifying this class with QueryCallback(), gets the (duplicated) overlapping pair buffer.
|
||||||
|
for (u32 i = 0; i < m_moveBufferCount; ++i)
|
||||||
|
{
|
||||||
|
// Keep the current queried proxy ID to avoid self overlapping.
|
||||||
|
m_queryProxyId = m_moveBuffer[i];
|
||||||
|
if (m_queryProxyId == NULL_NODE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b3AABB3& aabb = m_tree.GetAABB(m_queryProxyId);
|
||||||
|
m_tree.QueryAABB(this, aabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the move buffer for the next step.
|
||||||
|
m_moveBufferCount = 0;
|
||||||
|
|
||||||
|
// Sort the (duplicated) overlapping pair buffer to prune duplicated pairs.
|
||||||
|
std::sort(m_pairBuffer, m_pairBuffer + m_pairBufferCount);
|
||||||
|
|
||||||
|
// Skip duplicated overlapping pairs.
|
||||||
|
u32 index = 0;
|
||||||
|
while (index < m_pairBufferCount)
|
||||||
|
{
|
||||||
|
const b3Pair* primaryPair = m_pairBuffer + index;
|
||||||
|
|
||||||
|
// Report an unique overlapping pair to the client.
|
||||||
|
callback->AddPair(m_tree.GetUserData(primaryPair->proxy1), m_tree.GetUserData(primaryPair->proxy2));
|
||||||
|
|
||||||
|
// Skip all duplicated pairs until an unique pair is found.
|
||||||
|
++index;
|
||||||
|
while (index < m_pairBufferCount)
|
||||||
|
{
|
||||||
|
const b3Pair* secondaryPair = m_pairBuffer + index;
|
||||||
|
if (secondaryPair->proxy1 != primaryPair->proxy1 || secondaryPair->proxy2 != primaryPair->proxy2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void b3BroadPhase::Draw(b3Draw* b3Draw) const
|
||||||
|
{
|
||||||
|
m_tree.Draw(b3Draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
67
include/bounce/collision/distance.h
Normal file
67
include/bounce/collision/distance.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_COLLISION_H
|
||||||
|
#define B3_COLLISION_H
|
||||||
|
|
||||||
|
#include <bounce\common\geometry.h>
|
||||||
|
#include <bounce\collision\shapes\aabb3.h>
|
||||||
|
#include <bounce\collision\shapes\capsule.h>
|
||||||
|
|
||||||
|
// Input for a ray cast query.
|
||||||
|
struct b3RayCastInput
|
||||||
|
{
|
||||||
|
b3Vec3 p1; // first point on segment
|
||||||
|
b3Vec3 p2; // second point on segment
|
||||||
|
float32 maxFraction; // maximum intersection
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output of ray cast query.
|
||||||
|
struct b3RayCastOutput
|
||||||
|
{
|
||||||
|
float32 fraction; // time of intersection
|
||||||
|
b3Vec3 normal; // surface normal of intersection
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find the closest point for a point P to a normalized plane.
|
||||||
|
b3Vec3 b3ClosestPointOnPlane(const b3Vec3& P, const b3Plane& plane);
|
||||||
|
|
||||||
|
// Find the closest point for a point P to a segment AB.
|
||||||
|
b3Vec3 b3ClosestPointOnSegment(const b3Vec3& P,
|
||||||
|
const b3Vec3& A, const b3Vec3& B);
|
||||||
|
|
||||||
|
// Find the closest point for a point P to a triangle ABC.
|
||||||
|
b3Vec3 b3ClosestPointOnTriangle(const b3Vec3& P,
|
||||||
|
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C);
|
||||||
|
|
||||||
|
// Find the closest points of two lines.
|
||||||
|
void b3ClosestPointsOnLines(b3Vec3* C1, b3Vec3* C2,
|
||||||
|
const b3Vec3& P1, const b3Vec3& E1,
|
||||||
|
const b3Vec3& P2, const b3Vec3& E2);
|
||||||
|
|
||||||
|
// Find the closest points of two normalized lines.
|
||||||
|
void b3ClosestPointsOnNormalizedLines(b3Vec3* C1, b3Vec3* C2,
|
||||||
|
const b3Vec3& P1, const b3Vec3& N1,
|
||||||
|
const b3Vec3& P2, const b3Vec3& N2);
|
||||||
|
|
||||||
|
// Find the closest points of two segments P1-Q1 to a segment P2-Q2.
|
||||||
|
void b3ClosestPointsOnSegments(b3Vec3* C1, b3Vec3* C2,
|
||||||
|
const b3Vec3& P1, const b3Vec3& Q1,
|
||||||
|
const b3Vec3& P2, const b3Vec3& Q2);
|
||||||
|
|
||||||
|
#endif
|
74
include/bounce/collision/gjk/gjk.h
Normal file
74
include/bounce/collision/gjk/gjk.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_GJK_H
|
||||||
|
#define B3_GJK_H
|
||||||
|
|
||||||
|
#include <bounce\common\geometry.h>
|
||||||
|
|
||||||
|
class b3GJKProxy;
|
||||||
|
struct b3SimplexCache;
|
||||||
|
|
||||||
|
struct b3SimplexVertex
|
||||||
|
{
|
||||||
|
b3Vec3 pointA; // support vertex on proxy A
|
||||||
|
b3Vec3 pointB; // support vertex on proxy B
|
||||||
|
b3Vec3 point; // minkowski vertex
|
||||||
|
float32 weight; // barycentric coordinate for point
|
||||||
|
u32 indexA; // support A index
|
||||||
|
u32 indexB; // support B index
|
||||||
|
};
|
||||||
|
|
||||||
|
struct b3Simplex
|
||||||
|
{
|
||||||
|
b3SimplexVertex m_vertices[4];
|
||||||
|
u32 m_count;
|
||||||
|
|
||||||
|
b3Vec3 GetSearchDirection(const b3Vec3& Q) const;
|
||||||
|
b3Vec3 GetClosestPoint() const;
|
||||||
|
void GetClosestPoints(b3Vec3* pA, b3Vec3* pB) const;
|
||||||
|
|
||||||
|
void Solve2(const b3Vec3& Q);
|
||||||
|
void Solve3(const b3Vec3& Q);
|
||||||
|
void Solve4(const b3Vec3& Q);
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
void ReadCache(const b3SimplexCache* cache,
|
||||||
|
const b3Transform& xfA, const b3GJKProxy& proxyA,
|
||||||
|
const b3Transform& xfB, const b3GJKProxy& proxyB);
|
||||||
|
void WriteCache(b3SimplexCache* cache) const;
|
||||||
|
float32 GetMetric() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The output of the GJK algorithm.
|
||||||
|
// It contains the closest points between two proxies
|
||||||
|
// and their euclidean distance.
|
||||||
|
struct b3GJKOutput
|
||||||
|
{
|
||||||
|
b3Vec3 pointA; // closest point on proxy A
|
||||||
|
b3Vec3 pointB; // closest point on proxy B
|
||||||
|
float32 distance; // euclidean distance between the closest points
|
||||||
|
u32 iterations; // number of GJK iterations
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find the closest points and distance between two proxies.
|
||||||
|
// If the distance is zero then the proxies are overlapping.
|
||||||
|
b3GJKOutput b3GJK(const b3Transform& xfA, const b3GJKProxy& proxyA,
|
||||||
|
const b3Transform& xfB, const b3GJKProxy& proxyB);
|
||||||
|
|
||||||
|
#endif
|
66
include/bounce/collision/gjk/gjk_cache.h
Normal file
66
include/bounce/collision/gjk/gjk_cache.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_GJK_CACHE_H
|
||||||
|
#define B3_GJK_CACHE_H
|
||||||
|
|
||||||
|
#include <bounce\collision\gjk\gjk.h>
|
||||||
|
|
||||||
|
// A simplex used to improve the performance
|
||||||
|
// of the GJK when called more than once.
|
||||||
|
// Make sure to set cache.count to zero before
|
||||||
|
// calling the GJK for the first time.
|
||||||
|
struct b3SimplexCache
|
||||||
|
{
|
||||||
|
float32 metric; // length or area or volume
|
||||||
|
u32 iterations; // number of GJK iterations
|
||||||
|
u16 count; // number of support vertices
|
||||||
|
u8 indexA[4]; // support vertices on proxy A
|
||||||
|
u8 indexB[4]; // support vertices on proxy B
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find the closest points and distance between two proxies.
|
||||||
|
// Assumes a simplex is given for increasing the performance of
|
||||||
|
// the GJK when called more than once.
|
||||||
|
b3GJKOutput b3GJK(const b3Transform& xfA, const b3GJKProxy& proxyA,
|
||||||
|
const b3Transform& xfB, const b3GJKProxy& proxyB,
|
||||||
|
bool applyRadius, b3SimplexCache* cache);
|
||||||
|
|
||||||
|
struct b3GJKFeaturePair
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
e_unknown = 0,
|
||||||
|
e_vertex = 1,
|
||||||
|
e_edge = 2,
|
||||||
|
e_face = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
Type typeA; // number of vertices on proxy A
|
||||||
|
Type typeB; // number of vertices on proxy B
|
||||||
|
u32 indexA[3]; // vertices on proxy A
|
||||||
|
u32 indexB[3]; // vertices on proxy B
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the vertices of the features that the closest points between two
|
||||||
|
// GJK proxies are contained on given a cached simplex.
|
||||||
|
// The GJK must have been called using the pair of proxies and
|
||||||
|
// cache.count must be < 4, that is, the proxies must not be overlapping.
|
||||||
|
b3GJKFeaturePair b3GetFeaturePair(const b3SimplexCache& cache);
|
||||||
|
|
||||||
|
#endif
|
82
include/bounce/collision/gjk/gjk_proxy.h
Normal file
82
include/bounce/collision/gjk/gjk_proxy.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_GJK_PROXY_H
|
||||||
|
#define B3_GJK_PROXY_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\vec3.h>
|
||||||
|
|
||||||
|
// A GJK proxy encapsulates any convex hull to be used by the GJK.
|
||||||
|
class b3GJKProxy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
b3GJKProxy() : m_vertices(nullptr), m_count(0), m_radius(0.0f) { }
|
||||||
|
|
||||||
|
// Get the number of vertices of this proxy.
|
||||||
|
u32 GetVertexCount() const;
|
||||||
|
|
||||||
|
// Read an indexed vertex from this proxy.
|
||||||
|
const b3Vec3& GetVertex(u32 index) const;
|
||||||
|
|
||||||
|
// Get the support vertex index in a given direction.
|
||||||
|
u32 GetSupportIndex(const b3Vec3& d) const;
|
||||||
|
|
||||||
|
// Convenience function.
|
||||||
|
// Get the support vertex in a given direction.
|
||||||
|
const b3Vec3& GetSupportVertex(const b3Vec3& d) const;
|
||||||
|
|
||||||
|
b3Vec3 m_buffer[3]; // for childs
|
||||||
|
const b3Vec3* m_vertices;
|
||||||
|
u32 m_count;
|
||||||
|
float32 m_radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline u32 b3GJKProxy::GetVertexCount() const
|
||||||
|
{
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Vec3& b3GJKProxy::GetVertex(u32 index) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(0 <= index && index < m_count);
|
||||||
|
return m_vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3GJKProxy::GetSupportIndex(const b3Vec3& d) const
|
||||||
|
{
|
||||||
|
u32 maxIndex = 0;
|
||||||
|
float32 maxProjection = b3Dot(d, m_vertices[maxIndex]);
|
||||||
|
for (u32 i = 1; i < m_count; ++i)
|
||||||
|
{
|
||||||
|
float32 projection = b3Dot(d, m_vertices[i]);
|
||||||
|
if (projection > maxProjection)
|
||||||
|
{
|
||||||
|
maxIndex = i;
|
||||||
|
maxProjection = projection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Vec3& b3GJKProxy::GetSupportVertex(const b3Vec3& d) const
|
||||||
|
{
|
||||||
|
u32 index = GetSupportIndex(d);
|
||||||
|
return m_vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
55
include/bounce/collision/sat/sat.h
Normal file
55
include/bounce/collision/sat/sat.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_SAT_H
|
||||||
|
#define B3_SAT_H
|
||||||
|
|
||||||
|
#include <bounce\common\geometry.h>
|
||||||
|
|
||||||
|
struct b3Hull;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct b3FaceQuery
|
||||||
|
{
|
||||||
|
u32 index;
|
||||||
|
float32 separation;
|
||||||
|
};
|
||||||
|
|
||||||
|
float32 b3Project(const b3Hull* hull, const b3Plane& plane);
|
||||||
|
|
||||||
|
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xfA, const b3Hull* hullA,
|
||||||
|
const b3Transform& xfB, const b3Hull* hullB);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct b3EdgeQuery
|
||||||
|
{
|
||||||
|
u32 indexA;
|
||||||
|
u32 indexB;
|
||||||
|
float32 separation;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool b3IsMinkowskiFace(const b3Vec3& A, const b3Vec3& B, const b3Vec3& B_x_A, const b3Vec3& C, const b3Vec3& D, const b3Vec3& D_x_C);
|
||||||
|
|
||||||
|
float32 b3Project(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C1);
|
||||||
|
|
||||||
|
b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xfA, const b3Hull* hullA,
|
||||||
|
const b3Transform& xfB, const b3Hull* hullB);
|
||||||
|
|
||||||
|
#endif
|
40
include/bounce/collision/sat/sat_edge_and_hull.h
Normal file
40
include/bounce/collision/sat/sat_edge_and_hull.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_EDGE_SAT_H
|
||||||
|
#define B3_EDGE_SAT_H
|
||||||
|
|
||||||
|
#include <bounce\collision\sat\sat.h>
|
||||||
|
|
||||||
|
struct b3Capsule;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float32 b3ProjectEdge(const b3Capsule* hull, const b3Plane& plane);
|
||||||
|
|
||||||
|
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xfA, const b3Capsule* hullA,
|
||||||
|
const b3Transform& xfB, const b3Hull* hullB);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float32 b3ProjectEdge(const b3Vec3& P1, const b3Vec3& E1, const b3Vec3& P2, const b3Vec3& E2, const b3Vec3& C2);
|
||||||
|
|
||||||
|
b3EdgeQuery b3QueryEdgeSeparation(const b3Transform& xfA, const b3Capsule* hullA,
|
||||||
|
const b3Transform& xfB, const b3Hull* hullB);
|
||||||
|
|
||||||
|
#endif
|
33
include/bounce/collision/sat/sat_vertex_and_hull.h
Normal file
33
include/bounce/collision/sat/sat_vertex_and_hull.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_VERTEX_SAT_H
|
||||||
|
#define B3_VERTEX_SAT_H
|
||||||
|
|
||||||
|
#include <bounce\collision\sat\sat.h>
|
||||||
|
|
||||||
|
struct b3Sphere;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
float32 b3ProjectVertex(const b3Sphere* hull, const b3Plane& plane);
|
||||||
|
|
||||||
|
b3FaceQuery b3QueryFaceSeparation(const b3Transform& xfA, const b3Sphere* hullA,
|
||||||
|
const b3Transform& xfB, const b3Hull* hullB);
|
||||||
|
|
||||||
|
#endif
|
239
include/bounce/collision/shapes/aabb3.h
Normal file
239
include/bounce/collision/shapes/aabb3.h
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_AABB_3_H
|
||||||
|
#define B3_AABB_3_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\transform.h>
|
||||||
|
|
||||||
|
// A min-max representation of a three-dimensional AABB.
|
||||||
|
struct b3AABB3
|
||||||
|
{
|
||||||
|
b3Vec3 GetSupportVertex(const b3Vec3& direction) const
|
||||||
|
{
|
||||||
|
b3Vec3 support;
|
||||||
|
support.x = direction.x < 0.0f ? m_lower.x : m_upper.x;
|
||||||
|
support.y = direction.y < 0.0f ? m_lower.y : m_upper.y;
|
||||||
|
support.z = direction.z < 0.0f ? m_lower.z : m_upper.z;
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute this AABB from a list of points.
|
||||||
|
void Compute(const b3Vec3* points, u32 count)
|
||||||
|
{
|
||||||
|
m_lower = m_upper = points[0];
|
||||||
|
for (u32 i = 1; i < count; ++i)
|
||||||
|
{
|
||||||
|
m_lower = b3Min(m_lower, points[i]);
|
||||||
|
m_upper = b3Max(m_upper, points[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute this AABB from a list of points and a transform.
|
||||||
|
void Compute(const b3Vec3* points, u32 count, const b3Transform& xf)
|
||||||
|
{
|
||||||
|
m_lower = m_upper = b3Mul(xf, points[0]);
|
||||||
|
for (u32 i = 1; i < count; ++i)
|
||||||
|
{
|
||||||
|
b3Vec3 v = b3Mul(xf, points[i]);
|
||||||
|
m_lower = b3Min(m_lower, v);
|
||||||
|
m_upper = b3Max(m_upper, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend this AABB by a scalar.
|
||||||
|
void Extend(float32 s)
|
||||||
|
{
|
||||||
|
b3Vec3 r(s, s, s);
|
||||||
|
m_lower -= r;
|
||||||
|
m_upper += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend this AABB by a radius vector.
|
||||||
|
void Extend(const b3Vec3& r)
|
||||||
|
{
|
||||||
|
m_lower -= r;
|
||||||
|
m_upper += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the centroid of this AABB.
|
||||||
|
b3Vec3 Centroid() const
|
||||||
|
{
|
||||||
|
return 0.5f * (m_lower + m_upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the width of this AABB.
|
||||||
|
float32 Width() const
|
||||||
|
{
|
||||||
|
return m_upper.x - m_lower.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the height of this AABB.
|
||||||
|
float32 Height() const
|
||||||
|
{
|
||||||
|
return m_upper.y - m_lower.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the depth of this AABB.
|
||||||
|
float32 Depth() const
|
||||||
|
{
|
||||||
|
return m_upper.z - m_lower.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the total of cubic units contained in this AABB.
|
||||||
|
float32 Volume() const
|
||||||
|
{
|
||||||
|
return Width() * Height() * Depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the surface area of this AABB.
|
||||||
|
float32 SurfaceArea() const
|
||||||
|
{
|
||||||
|
return 2.0f * (Width() * Depth() + Width() * Height() + Depth() * Height());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the index of the longest axis of this AABB.
|
||||||
|
u32 GetLongestAxisIndex() const
|
||||||
|
{
|
||||||
|
b3Vec3 c = Centroid();
|
||||||
|
b3Vec3 r = m_upper - c;
|
||||||
|
float32 max = r[0];
|
||||||
|
u32 i = 0;
|
||||||
|
if (r[1] > max)
|
||||||
|
{
|
||||||
|
max = r[1];
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
if (r[2] > max)
|
||||||
|
{
|
||||||
|
max = r[2];
|
||||||
|
i = 2;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if this AABB contains a point.
|
||||||
|
bool TestPoint(const b3Vec3& point) const
|
||||||
|
{
|
||||||
|
return m_lower.x <= point.x && point.x <= m_upper.x &&
|
||||||
|
m_lower.y <= point.y && point.y <= m_upper.y &&
|
||||||
|
m_lower.z <= point.z && point.z <= m_upper.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if this AABB contains another AABB.
|
||||||
|
bool Contains(const b3AABB3& aabb) const
|
||||||
|
{
|
||||||
|
return TestPoint(aabb.m_lower) && TestPoint(aabb.m_upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if a ray intersect this AABB.
|
||||||
|
// Output the minimum fraction to derive the intersection point.
|
||||||
|
bool TestRay(const b3Vec3& p1, const b3Vec3& p2, float32 maxFraction, float32& minFraction) const
|
||||||
|
{
|
||||||
|
// Solve segment to slab plane.
|
||||||
|
// S = p1 + w * d
|
||||||
|
// dot(S, n) = offset[i]
|
||||||
|
// Solution:
|
||||||
|
// dot(p1 + w * d, n) = offset[i]
|
||||||
|
// dot(p1, n) + w * dot(d, n) = offset[i]
|
||||||
|
// w * dot(d, n) = offset[i] - dot(p1, n)
|
||||||
|
// w = (offset[i] - dot(p1, n)) / dot(d, n)
|
||||||
|
b3Vec3 d = p2 - p1;
|
||||||
|
float32 lower = 0.0f;
|
||||||
|
float32 upper = maxFraction;
|
||||||
|
for (u32 i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
float32 numerators[2], denominators[2];
|
||||||
|
//numerators[0] = (-m_lower[i]) - (-p1[i]);
|
||||||
|
numerators[0] = p1[i] - m_lower[i];
|
||||||
|
numerators[1] = m_upper[i] - p1[i];
|
||||||
|
denominators[0] = -d[i];
|
||||||
|
denominators[1] = d[i];
|
||||||
|
|
||||||
|
// For each orthogonal plane...
|
||||||
|
for (u32 j = 0; j < 2; ++j)
|
||||||
|
{
|
||||||
|
float32 numerator = numerators[j];
|
||||||
|
float32 denominator = denominators[j];
|
||||||
|
|
||||||
|
if (denominator == 0.0f)
|
||||||
|
{
|
||||||
|
// s is parallel to this half-space.
|
||||||
|
if (numerator < 0.0f)
|
||||||
|
{
|
||||||
|
// s is outside of this half-space.
|
||||||
|
// dot(n, p1) and dot(n, p2) < 0.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (denominator < 0.0f)
|
||||||
|
{
|
||||||
|
// s enters this half-space.
|
||||||
|
if (numerator < lower * denominator)
|
||||||
|
{
|
||||||
|
// Increase lower.
|
||||||
|
lower = numerator / denominator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// s exits the half-space.
|
||||||
|
if (numerator < upper * denominator)
|
||||||
|
{
|
||||||
|
// Decrease upper.
|
||||||
|
upper = numerator / denominator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit if intersection becomes empty.
|
||||||
|
if (upper < lower)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
B3_ASSERT(lower >= 0.0f && lower <= maxFraction);
|
||||||
|
minFraction = lower;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 m_lower; // lower vertex
|
||||||
|
b3Vec3 m_upper; // upper vertex
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compute an AABB that encloses two AABBs.
|
||||||
|
inline b3AABB3 b3Combine(const b3AABB3& a, const b3AABB3& b)
|
||||||
|
{
|
||||||
|
b3AABB3 aabb;
|
||||||
|
aabb.m_lower = b3Min(a.m_lower, b.m_lower);
|
||||||
|
aabb.m_upper = b3Max(a.m_upper, b.m_upper);
|
||||||
|
return aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if two AABBs are overlapping.
|
||||||
|
inline bool b3TestOverlap(const b3AABB3& a, const b3AABB3& b)
|
||||||
|
{
|
||||||
|
return (a.m_lower.x <= b.m_upper.x) && (a.m_lower.y <= b.m_upper.y) && (a.m_lower.z <= b.m_upper.z) &&
|
||||||
|
(a.m_upper.x >= b.m_lower.x) && (a.m_upper.y >= b.m_lower.y) && (a.m_upper.z >= b.m_lower.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
165
include/bounce/collision/shapes/box_hull.h
Normal file
165
include/bounce/collision/shapes/box_hull.h
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_BOX_HULL_H
|
||||||
|
#define B3_BOX_HULL_H
|
||||||
|
|
||||||
|
#include <bounce\collision\shapes\hull.h>
|
||||||
|
|
||||||
|
struct b3BoxHull : public b3Hull
|
||||||
|
{
|
||||||
|
b3Vec3 boxVertices[8];
|
||||||
|
b3HalfEdge boxEdges[24];
|
||||||
|
b3Face boxFaces[6];
|
||||||
|
b3Plane boxPlanes[6];
|
||||||
|
|
||||||
|
b3BoxHull() { }
|
||||||
|
|
||||||
|
// Set this box to the unit box.
|
||||||
|
void SetIdentity()
|
||||||
|
{
|
||||||
|
boxVertices[0] = b3Vec3(1.0f, 1.0f, -1.0f);
|
||||||
|
boxVertices[1] = b3Vec3(-1.0f, 1.0f, -1.0f);
|
||||||
|
boxVertices[2] = b3Vec3(-1.0f, -1.0f, -1.0f);
|
||||||
|
boxVertices[3] = b3Vec3(1.0f, -1.0f, -1.0f);
|
||||||
|
boxVertices[4] = b3Vec3(1.0f, 1.0f, 1.0f);
|
||||||
|
boxVertices[5] = b3Vec3(-1.0f, 1.0f, 1.0f);
|
||||||
|
boxVertices[6] = b3Vec3(-1.0f, -1.0f, 1.0f);
|
||||||
|
boxVertices[7] = b3Vec3(1.0f, -1.0f, 1.0f);
|
||||||
|
|
||||||
|
boxEdges[0] = b3MakeEdge(1, 1, 0, 2);
|
||||||
|
boxEdges[1] = b3MakeEdge(2, 0, 5, 21);
|
||||||
|
boxEdges[2] = b3MakeEdge(2, 3, 0, 4);
|
||||||
|
boxEdges[3] = b3MakeEdge(6, 2, 2, 18);
|
||||||
|
boxEdges[4] = b3MakeEdge(6, 5, 0, 6);
|
||||||
|
boxEdges[5] = b3MakeEdge(5, 4, 4, 17);
|
||||||
|
boxEdges[6] = b3MakeEdge(5, 7, 0, 0);
|
||||||
|
boxEdges[7] = b3MakeEdge(1, 6, 3, 22);
|
||||||
|
boxEdges[8] = b3MakeEdge(4, 9, 1, 10);
|
||||||
|
boxEdges[9] = b3MakeEdge(7, 8, 4, 23);
|
||||||
|
boxEdges[10] = b3MakeEdge(7, 11, 1, 12);
|
||||||
|
boxEdges[11] = b3MakeEdge(3, 10, 2, 16);
|
||||||
|
boxEdges[12] = b3MakeEdge(3, 13, 1, 14);
|
||||||
|
boxEdges[13] = b3MakeEdge(0, 12, 5, 19);
|
||||||
|
boxEdges[14] = b3MakeEdge(0, 15, 1, 8);
|
||||||
|
boxEdges[15] = b3MakeEdge(4, 14, 3, 20);
|
||||||
|
boxEdges[16] = b3MakeEdge(7, 17, 2, 3);
|
||||||
|
boxEdges[17] = b3MakeEdge(6, 16, 4, 9);
|
||||||
|
boxEdges[18] = b3MakeEdge(2, 19, 2, 11);
|
||||||
|
boxEdges[19] = b3MakeEdge(3, 18, 5, 1);
|
||||||
|
boxEdges[20] = b3MakeEdge(0, 21, 3, 7);
|
||||||
|
boxEdges[21] = b3MakeEdge(1, 20, 5, 13);
|
||||||
|
boxEdges[22] = b3MakeEdge(5, 23, 3, 15);
|
||||||
|
boxEdges[23] = b3MakeEdge(4, 22, 4, 5);
|
||||||
|
|
||||||
|
boxFaces[0].edge = 6;
|
||||||
|
boxFaces[1].edge = 14;
|
||||||
|
boxFaces[2].edge = 18;
|
||||||
|
boxFaces[3].edge = 15;
|
||||||
|
boxFaces[4].edge = 9;
|
||||||
|
boxFaces[5].edge = 21;
|
||||||
|
|
||||||
|
boxPlanes[0] = b3Plane(b3Vec3(-1.0f, 0.0f, 0.0f), boxVertices[1]);
|
||||||
|
boxPlanes[1] = b3Plane(b3Vec3(1.0f, 0.0f, 0.0f), boxVertices[0]);
|
||||||
|
boxPlanes[2] = b3Plane(b3Vec3(0.0f, -1.0f, 0.0f), boxVertices[2]);
|
||||||
|
boxPlanes[3] = b3Plane(b3Vec3(0.0f, 1.0f, 0.0f), boxVertices[1]);
|
||||||
|
boxPlanes[4] = b3Plane(b3Vec3(0.0f, 0.0f, 1.0f), boxVertices[4]);
|
||||||
|
boxPlanes[5] = b3Plane(b3Vec3(0.0f, 0.0f, -1.0f), boxVertices[0]);
|
||||||
|
|
||||||
|
centroid = b3Vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
vertices = boxVertices;
|
||||||
|
vertexCount = 8;
|
||||||
|
edges = boxEdges;
|
||||||
|
edgeCount = 24;
|
||||||
|
faces = boxFaces;
|
||||||
|
planes = boxPlanes;
|
||||||
|
faceCount = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this box to the unit box and transform
|
||||||
|
// it. The transform must not contain non-uniform
|
||||||
|
// scaling!
|
||||||
|
void SetTransform(const b3Transform& T)
|
||||||
|
{
|
||||||
|
boxVertices[0] = b3Vec3(1.0f, 1.0f, -1.0f);
|
||||||
|
boxVertices[1] = b3Vec3(-1.0f, 1.0f, -1.0f);
|
||||||
|
boxVertices[2] = b3Vec3(-1.0f, -1.0f, -1.0f);
|
||||||
|
boxVertices[3] = b3Vec3(1.0f, -1.0f, -1.0f);
|
||||||
|
boxVertices[4] = b3Vec3(1.0f, 1.0f, 1.0f);
|
||||||
|
boxVertices[5] = b3Vec3(-1.0f, 1.0f, 1.0f);
|
||||||
|
boxVertices[6] = b3Vec3(-1.0f, -1.0f, 1.0f);
|
||||||
|
boxVertices[7] = b3Vec3(1.0f, -1.0f, 1.0f);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
boxVertices[i] = T * boxVertices[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
boxEdges[0] = b3MakeEdge(1, 1, 0, 2);
|
||||||
|
boxEdges[1] = b3MakeEdge(2, 0, 5, 21);
|
||||||
|
boxEdges[2] = b3MakeEdge(2, 3, 0, 4);
|
||||||
|
boxEdges[3] = b3MakeEdge(6, 2, 2, 18);
|
||||||
|
boxEdges[4] = b3MakeEdge(6, 5, 0, 6);
|
||||||
|
boxEdges[5] = b3MakeEdge(5, 4, 4, 17);
|
||||||
|
boxEdges[6] = b3MakeEdge(5, 7, 0, 0);
|
||||||
|
boxEdges[7] = b3MakeEdge(1, 6, 3, 22);
|
||||||
|
boxEdges[8] = b3MakeEdge(4, 9, 1, 10);
|
||||||
|
boxEdges[9] = b3MakeEdge(7, 8, 4, 23);
|
||||||
|
boxEdges[10] = b3MakeEdge(7, 11, 1, 12);
|
||||||
|
boxEdges[11] = b3MakeEdge(3, 10, 2, 16);
|
||||||
|
boxEdges[12] = b3MakeEdge(3, 13, 1, 14);
|
||||||
|
boxEdges[13] = b3MakeEdge(0, 12, 5, 19);
|
||||||
|
boxEdges[14] = b3MakeEdge(0, 15, 1, 8);
|
||||||
|
boxEdges[15] = b3MakeEdge(4, 14, 3, 20);
|
||||||
|
boxEdges[16] = b3MakeEdge(7, 17, 2, 3);
|
||||||
|
boxEdges[17] = b3MakeEdge(6, 16, 4, 9);
|
||||||
|
boxEdges[18] = b3MakeEdge(2, 19, 2, 11);
|
||||||
|
boxEdges[19] = b3MakeEdge(3, 18, 5, 1);
|
||||||
|
boxEdges[20] = b3MakeEdge(0, 21, 3, 7);
|
||||||
|
boxEdges[21] = b3MakeEdge(1, 20, 5, 13);
|
||||||
|
boxEdges[22] = b3MakeEdge(5, 23, 3, 15);
|
||||||
|
boxEdges[23] = b3MakeEdge(4, 22, 4, 5);
|
||||||
|
|
||||||
|
boxFaces[0].edge = 6;
|
||||||
|
boxFaces[1].edge = 14;
|
||||||
|
boxFaces[2].edge = 18;
|
||||||
|
boxFaces[3].edge = 15;
|
||||||
|
boxFaces[4].edge = 9;
|
||||||
|
boxFaces[5].edge = 21;
|
||||||
|
|
||||||
|
boxPlanes[0] = b3Plane(b3Vec3(-1.0f, 0.0f, 0.0f), boxVertices[1]);
|
||||||
|
boxPlanes[1] = b3Plane(b3Vec3(1.0f, 0.0f, 0.0f), boxVertices[0]);
|
||||||
|
boxPlanes[2] = b3Plane(b3Vec3(0.0f, -1.0f, 0.0f), boxVertices[2]);
|
||||||
|
boxPlanes[3] = b3Plane(b3Vec3(0.0f, 1.0f, 0.0f), boxVertices[1]);
|
||||||
|
boxPlanes[4] = b3Plane(b3Vec3(0.0f, 0.0f, 1.0f), boxVertices[4]);
|
||||||
|
boxPlanes[5] = b3Plane(b3Vec3(0.0f, 0.0f, -1.0f), boxVertices[0]);
|
||||||
|
|
||||||
|
centroid = b3Vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
vertices = boxVertices;
|
||||||
|
vertexCount = 8;
|
||||||
|
edges = boxEdges;
|
||||||
|
edgeCount = 24;
|
||||||
|
faces = boxFaces;
|
||||||
|
planes = boxPlanes;
|
||||||
|
faceCount = 6;
|
||||||
|
|
||||||
|
centroid = T * centroid;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
48
include/bounce/collision/shapes/capsule.h
Normal file
48
include/bounce/collision/shapes/capsule.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_CAPSULE_H
|
||||||
|
#define B3_CAPSULE_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\vec3.h>
|
||||||
|
|
||||||
|
struct b3Capsule
|
||||||
|
{
|
||||||
|
b3Vec3 vertices[2];
|
||||||
|
float32 radius;
|
||||||
|
|
||||||
|
const b3Vec3& GetVertex(u32 index) const;
|
||||||
|
|
||||||
|
u32 GetSupportVertex(const b3Vec3& direction) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const b3Vec3& b3Capsule::GetVertex(u32 index) const
|
||||||
|
{
|
||||||
|
return vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Capsule::GetSupportVertex(const b3Vec3& direction) const
|
||||||
|
{
|
||||||
|
if (b3Dot(direction, vertices[0]) > b3Dot(direction, vertices[1]))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
65
include/bounce/collision/shapes/hull.h
Normal file
65
include/bounce/collision/shapes/hull.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_HULL_H
|
||||||
|
#define B3_HULL_H
|
||||||
|
|
||||||
|
#include <bounce\common\geometry.h>
|
||||||
|
|
||||||
|
struct b3Face
|
||||||
|
{
|
||||||
|
u8 edge;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct b3HalfEdge
|
||||||
|
{
|
||||||
|
u8 origin;
|
||||||
|
u8 twin;
|
||||||
|
u8 face;
|
||||||
|
u8 next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct b3Hull
|
||||||
|
{
|
||||||
|
b3Vec3 centroid;
|
||||||
|
u32 vertexCount;
|
||||||
|
b3Vec3* vertices;
|
||||||
|
u32 edgeCount;
|
||||||
|
b3HalfEdge* edges;
|
||||||
|
u32 faceCount;
|
||||||
|
b3Face* faces;
|
||||||
|
b3Plane* planes;
|
||||||
|
|
||||||
|
const b3Vec3& GetVertex(u32 index) const;
|
||||||
|
const b3HalfEdge* GetEdge(u32 index) const;
|
||||||
|
const b3Face* GetFace(u32 index) const;
|
||||||
|
const b3Plane& GetPlane(u32 index) const;
|
||||||
|
|
||||||
|
u32 GetSupportVertex(const b3Vec3& direction) const;
|
||||||
|
u32 GetSupportFace(const b3Vec3& direction) const;
|
||||||
|
|
||||||
|
b3Plane GetEdgeSidePlane(u32 index) const;
|
||||||
|
u32 GetSize() const;
|
||||||
|
void Validate() const;
|
||||||
|
void Validate(const b3Face* face) const;
|
||||||
|
void Validate(const b3HalfEdge* edge) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <bounce\collision\shapes\hull.inl>
|
||||||
|
|
||||||
|
#endif
|
89
include/bounce/collision/shapes/hull.inl
Normal file
89
include/bounce/collision/shapes/hull.inl
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
inline b3HalfEdge b3MakeEdge(u32 origin, u32 twin, u32 face, u32 next)
|
||||||
|
{
|
||||||
|
b3HalfEdge edge;
|
||||||
|
edge.origin = u8(origin);
|
||||||
|
edge.twin = u8(twin);
|
||||||
|
edge.face = u8(face);
|
||||||
|
edge.next = u8(next);
|
||||||
|
return edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Vec3& b3Hull::GetVertex(u32 index) const
|
||||||
|
{
|
||||||
|
return vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3HalfEdge* b3Hull::GetEdge(u32 index) const
|
||||||
|
{
|
||||||
|
return edges + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Face* b3Hull::GetFace(u32 index) const
|
||||||
|
{
|
||||||
|
return faces + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Plane& b3Hull::GetPlane(u32 index) const
|
||||||
|
{
|
||||||
|
return planes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Hull::GetSupportVertex(const b3Vec3& direction) const
|
||||||
|
{
|
||||||
|
u32 maxIndex = 0;
|
||||||
|
float32 maxProjection = b3Dot(direction, vertices[maxIndex]);
|
||||||
|
for (u32 i = 1; i < vertexCount; ++i)
|
||||||
|
{
|
||||||
|
float32 projection = b3Dot(direction, vertices[i]);
|
||||||
|
if (projection > maxProjection)
|
||||||
|
{
|
||||||
|
maxIndex = i;
|
||||||
|
maxProjection = projection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Hull::GetSupportFace(const b3Vec3& direction) const
|
||||||
|
{
|
||||||
|
u32 maxIndex = 0;
|
||||||
|
float32 maxProjection = b3Dot(direction, planes[maxIndex].normal);
|
||||||
|
for (u32 i = 1; i < faceCount; ++i)
|
||||||
|
{
|
||||||
|
float32 projection = b3Dot(direction, planes[i].normal);
|
||||||
|
if (projection > maxProjection)
|
||||||
|
{
|
||||||
|
maxIndex = i;
|
||||||
|
maxProjection = projection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b3Plane b3Hull::GetEdgeSidePlane(u32 index) const
|
||||||
|
{
|
||||||
|
const b3HalfEdge* edge = edges + index;
|
||||||
|
const b3HalfEdge* twin = edges + edge->twin;
|
||||||
|
const b3Plane* facePlane = planes + edge->face;
|
||||||
|
|
||||||
|
b3Vec3 P = vertices[edge->origin];
|
||||||
|
b3Vec3 Q = vertices[twin->origin];
|
||||||
|
b3Vec3 E = Q - P;
|
||||||
|
b3Vec3 D = b3Cross(E, facePlane->normal);
|
||||||
|
|
||||||
|
b3Plane plane;
|
||||||
|
plane.normal = b3Normalize(D);
|
||||||
|
plane.offset = b3Dot(plane.normal, P);
|
||||||
|
return plane;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Hull::GetSize() const
|
||||||
|
{
|
||||||
|
u32 size = 0;
|
||||||
|
size += sizeof(b3Hull);
|
||||||
|
size += vertexCount * sizeof(b3Vec3);
|
||||||
|
size += edgeCount * sizeof(b3HalfEdge);
|
||||||
|
size += faceCount * sizeof(b3Face);
|
||||||
|
size += faceCount * sizeof(b3Plane);
|
||||||
|
return size;
|
||||||
|
}
|
114
include/bounce/collision/shapes/mesh.h
Normal file
114
include/bounce/collision/shapes/mesh.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_MESH_H
|
||||||
|
#define B3_MESH_H
|
||||||
|
|
||||||
|
#include <bounce\common\geometry.h>
|
||||||
|
#include <bounce\collision\trees\static_tree.h>
|
||||||
|
|
||||||
|
struct b3Mesh
|
||||||
|
{
|
||||||
|
u32 vertexCount;
|
||||||
|
b3Vec3* vertices;
|
||||||
|
u32 triangleCount;
|
||||||
|
b3Triangle* triangles;
|
||||||
|
b3StaticTree tree;
|
||||||
|
|
||||||
|
void BuildTree();
|
||||||
|
|
||||||
|
const b3Vec3& GetVertex(u32 index) const;
|
||||||
|
const b3Triangle& GetTriangle(u32 index) const;
|
||||||
|
|
||||||
|
void GetTriangleVertices(b3Vec3 out[3], u32 index) const;
|
||||||
|
b3Plane GetTrianglePlane(u32 index) const;
|
||||||
|
b3AABB3 GetTriangleAABB(u32 index) const;
|
||||||
|
u32 GetSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void b3Mesh::BuildTree()
|
||||||
|
{
|
||||||
|
b3AABB3* aabbs = (b3AABB3*)b3Alloc(triangleCount * sizeof(b3AABB3));
|
||||||
|
u32* indices = (u32*)b3Alloc(triangleCount * sizeof(u32));
|
||||||
|
for (u32 i = 0; i < triangleCount; ++i)
|
||||||
|
{
|
||||||
|
aabbs[i] = GetTriangleAABB(i);
|
||||||
|
indices[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.Build(indices, aabbs, triangleCount);
|
||||||
|
|
||||||
|
b3Free(indices);
|
||||||
|
b3Free(aabbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Vec3& b3Mesh::GetVertex(u32 index) const
|
||||||
|
{
|
||||||
|
return vertices[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3Triangle& b3Mesh::GetTriangle(u32 index) const
|
||||||
|
{
|
||||||
|
return triangles[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void b3Mesh::GetTriangleVertices(b3Vec3 out[3], u32 index) const
|
||||||
|
{
|
||||||
|
const b3Triangle* triangle = triangles + index;
|
||||||
|
u32 i1 = triangle->v1;
|
||||||
|
u32 i2 = triangle->v2;
|
||||||
|
u32 i3 = triangle->v3;
|
||||||
|
out[0] = vertices[i1];
|
||||||
|
out[1] = vertices[i2];
|
||||||
|
out[2] = vertices[i3];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b3Plane b3Mesh::GetTrianglePlane(u32 index) const
|
||||||
|
{
|
||||||
|
b3Vec3 vs[3];
|
||||||
|
GetTriangleVertices(vs, index);
|
||||||
|
return b3Plane(vs[0], vs[1], vs[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline b3AABB3 b3Mesh::GetTriangleAABB(u32 index) const
|
||||||
|
{
|
||||||
|
const b3Triangle* triangle = triangles + index;
|
||||||
|
|
||||||
|
u32 i1 = triangle->v1;
|
||||||
|
u32 i2 = triangle->v2;
|
||||||
|
u32 i3 = triangle->v3;
|
||||||
|
|
||||||
|
b3AABB3 aabb;
|
||||||
|
aabb.m_lower = b3Min(b3Min(vertices[i1], vertices[i2]), vertices[i3]);
|
||||||
|
aabb.m_upper = b3Max(b3Max(vertices[i1], vertices[i2]), vertices[i3]);
|
||||||
|
|
||||||
|
return aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Mesh::GetSize() const
|
||||||
|
{
|
||||||
|
u32 memory = 0;
|
||||||
|
memory += sizeof(b3Mesh);
|
||||||
|
memory += sizeof(b3Vec3) * vertexCount;
|
||||||
|
memory += sizeof(b3Triangle) * triangleCount;
|
||||||
|
memory += sizeof(b3Plane) * triangleCount;
|
||||||
|
memory += sizeof(b3StaticTree);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
44
include/bounce/collision/shapes/sphere.h
Normal file
44
include/bounce/collision/shapes/sphere.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_SPHERE_H
|
||||||
|
#define B3_SPHERE_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\vec3.h>
|
||||||
|
|
||||||
|
struct b3Sphere
|
||||||
|
{
|
||||||
|
b3Vec3 vertex;
|
||||||
|
float32 radius;
|
||||||
|
|
||||||
|
const b3Vec3& GetVertex(u32 index) const;
|
||||||
|
|
||||||
|
u32 GetSupportVertex(const b3Vec3& direction) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const b3Vec3& b3Sphere::GetVertex(u32 index) const
|
||||||
|
{
|
||||||
|
return vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3Sphere::GetSupportVertex(const b3Vec3& direction) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
76
include/bounce/collision/shapes/triangle_hull.h
Normal file
76
include/bounce/collision/shapes/triangle_hull.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_TRIANGLE_HULL_H
|
||||||
|
#define B3_TRIANGLE_HULL_H
|
||||||
|
|
||||||
|
#include <bounce\collision\shapes\hull.h>
|
||||||
|
|
||||||
|
struct b3TriangleHull : public b3Hull
|
||||||
|
{
|
||||||
|
b3Vec3 triangleVertices[3];
|
||||||
|
b3HalfEdge triangleEdges[6];
|
||||||
|
b3Face triangleFaces[2];
|
||||||
|
b3Plane trianglePlanes[2];
|
||||||
|
|
||||||
|
b3TriangleHull() { }
|
||||||
|
|
||||||
|
b3TriangleHull(const b3Vec3& A, const b3Vec3& B, const b3Vec3& C)
|
||||||
|
{
|
||||||
|
Set(A, B, C);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const b3Vec3& A, const b3Vec3& B, const b3Vec3& C)
|
||||||
|
{
|
||||||
|
const float32 kInv3 = 1.0f / 3.0f;
|
||||||
|
|
||||||
|
centroid = kInv3 * (A + B + C);
|
||||||
|
|
||||||
|
triangleVertices[0] = A;
|
||||||
|
triangleVertices[1] = B;
|
||||||
|
triangleVertices[2] = C;
|
||||||
|
|
||||||
|
// Each edge must be followed by its twin.
|
||||||
|
triangleEdges[0] = b3MakeEdge(0, 1, 0, 2); // Face 0 - Edge 0
|
||||||
|
triangleEdges[2] = b3MakeEdge(1, 3, 0, 4); // Face 0 - Edge 1
|
||||||
|
triangleEdges[4] = b3MakeEdge(2, 5, 0, 0); // Face 0 - Edge 2
|
||||||
|
|
||||||
|
triangleEdges[1] = b3MakeEdge(1, 0, 1, 3); // Face 1 - Edge 0
|
||||||
|
triangleEdges[3] = b3MakeEdge(2, 2, 1, 5); // Face 1 - Edge 1
|
||||||
|
triangleEdges[5] = b3MakeEdge(0, 4, 1, 1); // Face 1 - Edge 2
|
||||||
|
|
||||||
|
triangleFaces[0].edge = 0;
|
||||||
|
triangleFaces[1].edge = 1;
|
||||||
|
|
||||||
|
b3Vec3 N = b3Cross(B - A, C - A);
|
||||||
|
N = b3Normalize(N);
|
||||||
|
|
||||||
|
trianglePlanes[0] = b3Plane(N, centroid);
|
||||||
|
trianglePlanes[1] = b3Plane(-N, centroid);
|
||||||
|
|
||||||
|
vertices = triangleVertices;
|
||||||
|
vertexCount = 3;
|
||||||
|
edges = triangleEdges;
|
||||||
|
edgeCount = 6;
|
||||||
|
faces = triangleFaces;
|
||||||
|
planes = trianglePlanes;
|
||||||
|
faceCount = 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
240
include/bounce/collision/trees/dynamic_tree.h
Normal file
240
include/bounce/collision/trees/dynamic_tree.h
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_DYNAMIC_TREE_H
|
||||||
|
#define B3_DYNAMIC_TREE_H
|
||||||
|
|
||||||
|
#include <bounce\common\draw.h>
|
||||||
|
#include <bounce\common\template\stack.h>
|
||||||
|
#include <bounce\collision\shapes\aabb3.h>
|
||||||
|
#include <bounce\collision\distance.h>
|
||||||
|
|
||||||
|
#define NULL_NODE (-1)
|
||||||
|
|
||||||
|
// An AABB tree for dynamic AABBs.
|
||||||
|
class b3DynamicTree
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
b3DynamicTree();
|
||||||
|
~b3DynamicTree();
|
||||||
|
|
||||||
|
// Insert a node to the tree and return its ID.
|
||||||
|
i32 InsertNode(const b3AABB3& aabb, void* userData);
|
||||||
|
|
||||||
|
// Remove a node from the tree.
|
||||||
|
void RemoveNode(i32 proxyId);
|
||||||
|
|
||||||
|
// Update a node AABB.
|
||||||
|
void UpdateNode(i32 proxyId, const b3AABB3& aabb);
|
||||||
|
|
||||||
|
// Get the (fat) AABB of a given proxy.
|
||||||
|
const b3AABB3& GetAABB(i32 proxyId) const;
|
||||||
|
|
||||||
|
// Get the data associated with a given proxy.
|
||||||
|
void* GetUserData(i32 proxyId) const;
|
||||||
|
|
||||||
|
// Check if two aabbs of this tree are overlapping.
|
||||||
|
bool TestOverlap(i32 proxy1, i32 proxy2) const;
|
||||||
|
|
||||||
|
// Keep reporting the client callback the AABBs that are overlapping with
|
||||||
|
// the given AABB. The client callback must return true if the query
|
||||||
|
// must be stopped or false to continue looking for more overlapping pairs.
|
||||||
|
template<class T>
|
||||||
|
void QueryAABB(T* callback, const b3AABB3& aabb) const;
|
||||||
|
|
||||||
|
// Keep reporting the client callback all AABBs that are overlapping with
|
||||||
|
// the given ray. The client callback must return the new intersection fraction.
|
||||||
|
// If the fraction == 0 then the query is cancelled immediately.
|
||||||
|
template<class T>
|
||||||
|
void QueryRay(T* callback, const b3RayCastInput& input) const;
|
||||||
|
|
||||||
|
// Validate a given node of this tree.
|
||||||
|
void Validate(i32 node) const;
|
||||||
|
|
||||||
|
// Draw this tree.
|
||||||
|
void Draw(b3Draw* b3Draw) const;
|
||||||
|
private :
|
||||||
|
struct b3Node
|
||||||
|
{
|
||||||
|
bool IsLeaf() const
|
||||||
|
{
|
||||||
|
return child1 == NULL_NODE; //or child 2 == NULL_NODE, or height == 0.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The (enlarged) AABB of this node.
|
||||||
|
b3AABB3 aabb;
|
||||||
|
|
||||||
|
// The associated user data.
|
||||||
|
void* userData;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
i32 parent;
|
||||||
|
i32 next;
|
||||||
|
};
|
||||||
|
|
||||||
|
i32 child1;
|
||||||
|
i32 child2;
|
||||||
|
|
||||||
|
// leaf = 0, free node = -1
|
||||||
|
i32 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Insert a allocated (leaf) node into the tree.
|
||||||
|
void InsertLeaf(i32 node);
|
||||||
|
|
||||||
|
// Remove a allocated node from the tree.
|
||||||
|
void RemoveLeaf(i32 node);
|
||||||
|
|
||||||
|
// Rebuild the tree hierarchy starting from the given node.
|
||||||
|
void WalkBackNodeAndCombineVolumes(i32 node);
|
||||||
|
|
||||||
|
// Perform a basic surface area heuristic search to find the best
|
||||||
|
// node that can be merged with a given AABB.
|
||||||
|
i32 HeuristicSearch(const b3AABB3& leafAABB) const;
|
||||||
|
|
||||||
|
// Peel a node from the free list and insert into the node array.
|
||||||
|
// Allocate a new node if necessary. The function returns the new node index.
|
||||||
|
i32 AllocateNode();
|
||||||
|
|
||||||
|
// Free a node (not destroy) from the node pool and add it to the free list.
|
||||||
|
void FreeNode(i32 node);
|
||||||
|
|
||||||
|
// Make a node available for the next allocation request.
|
||||||
|
void AddToFreeList(i32 node);
|
||||||
|
|
||||||
|
// The root of this tree.
|
||||||
|
i32 m_root;
|
||||||
|
|
||||||
|
// The nodes of this tree stored in an array.
|
||||||
|
b3Node* m_nodes;
|
||||||
|
i32 m_nodeCount;
|
||||||
|
i32 m_nodeCapacity;
|
||||||
|
i32 m_freeList;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool b3DynamicTree::TestOverlap(i32 proxy1, i32 proxy2) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(proxy1 < m_nodeCount);
|
||||||
|
B3_ASSERT(proxy2 < m_nodeCount);
|
||||||
|
return b3TestOverlap(m_nodes[proxy1].aabb, m_nodes[proxy2].aabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const b3AABB3& b3DynamicTree::GetAABB(i32 proxyId) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(proxyId < m_nodeCount);
|
||||||
|
return m_nodes[proxyId].aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void* b3DynamicTree::GetUserData(i32 proxyId) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(proxyId < m_nodeCount);
|
||||||
|
return m_nodes[proxyId].userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3DynamicTree::QueryAABB(T* callback, const b3AABB3& aabb) const
|
||||||
|
{
|
||||||
|
b3Stack<i32, 256> stack;
|
||||||
|
stack.Push(m_root);
|
||||||
|
|
||||||
|
while (stack.IsEmpty() == false)
|
||||||
|
{
|
||||||
|
i32 nodeIndex = stack.Top();
|
||||||
|
stack.Pop();
|
||||||
|
|
||||||
|
if (nodeIndex == NULL_NODE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b3Node* node = m_nodes + nodeIndex;
|
||||||
|
|
||||||
|
if (b3TestOverlap(node->aabb, aabb) == true)
|
||||||
|
{
|
||||||
|
if (node->IsLeaf() == true)
|
||||||
|
{
|
||||||
|
if (callback->Report(nodeIndex) == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.Push(node->child1);
|
||||||
|
stack.Push(node->child2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3DynamicTree::QueryRay(T* callback, const b3RayCastInput& input) const
|
||||||
|
{
|
||||||
|
b3Vec3 p1 = input.p1;
|
||||||
|
b3Vec3 p2 = input.p2;
|
||||||
|
b3Vec3 d = p2 - p1;
|
||||||
|
float32 maxFraction = input.maxFraction;
|
||||||
|
|
||||||
|
// Ensure non-degeneracy.
|
||||||
|
B3_ASSERT(b3Dot(d, d) > B3_EPSILON * B3_EPSILON);
|
||||||
|
|
||||||
|
b3Stack<i32, 256> stack;
|
||||||
|
stack.Push(m_root);
|
||||||
|
|
||||||
|
while (stack.IsEmpty() == false)
|
||||||
|
{
|
||||||
|
i32 nodeIndex = stack.Top();
|
||||||
|
|
||||||
|
stack.Pop();
|
||||||
|
|
||||||
|
if (nodeIndex == NULL_NODE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b3Node* node = m_nodes + nodeIndex;
|
||||||
|
|
||||||
|
float32 minFraction = 0.0f;
|
||||||
|
if (node->aabb.TestRay(p1, p2, maxFraction, minFraction) == true)
|
||||||
|
{
|
||||||
|
if (node->IsLeaf() == true)
|
||||||
|
{
|
||||||
|
b3RayCastInput subInput;
|
||||||
|
subInput.p1 = input.p1;
|
||||||
|
subInput.p2 = input.p2;
|
||||||
|
subInput.maxFraction = maxFraction;
|
||||||
|
|
||||||
|
float32 newFraction = callback->Report(subInput, nodeIndex);
|
||||||
|
|
||||||
|
if (newFraction == 0.0f)
|
||||||
|
{
|
||||||
|
// The client has stopped the query.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.Push(node->child1);
|
||||||
|
stack.Push(node->child2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
195
include/bounce/collision/trees/static_tree.h
Normal file
195
include/bounce/collision/trees/static_tree.h
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_STATIC_TREE_H
|
||||||
|
#define B3_STATIC_TREE_H
|
||||||
|
|
||||||
|
#include <bounce\common\draw.h>
|
||||||
|
#include <bounce\common\template\stack.h>
|
||||||
|
#include <bounce\collision\shapes\aabb3.h>
|
||||||
|
#include <bounce\collision\distance.h>
|
||||||
|
|
||||||
|
#define NULL_NODE_S (0xFFFFFFFF)
|
||||||
|
|
||||||
|
// An AABB tree for static AABBs.
|
||||||
|
class b3StaticTree
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
b3StaticTree();
|
||||||
|
~b3StaticTree();
|
||||||
|
|
||||||
|
// Build the tree.
|
||||||
|
// Output a sorted index array.
|
||||||
|
void Build(u32* indices, const b3AABB3* aabbs, u32 count);
|
||||||
|
|
||||||
|
// Get the AABB of a given proxy.
|
||||||
|
const b3AABB3& GetAABB(u32 proxyId) const;
|
||||||
|
|
||||||
|
// Get the index associated of a given proxy.
|
||||||
|
u32 GetUserData(u32 proxyId) const;
|
||||||
|
|
||||||
|
// Report the client callback all AABBs that are overlapping with
|
||||||
|
// the given AABB. The client callback must return true if the query
|
||||||
|
// must be stopped or false to continue looking for more overlapping pairs.
|
||||||
|
template<class T>
|
||||||
|
void QueryAABB(T* callback, const b3AABB3& aabb) const;
|
||||||
|
|
||||||
|
// Report the client callback all AABBs that are overlapping with
|
||||||
|
// the given ray. The client callback must return the new intersection fraction
|
||||||
|
// (real). If the fraction == 0 then the query is cancelled immediatly.
|
||||||
|
template<class T>
|
||||||
|
void QueryRay(T* callback, const b3RayCastInput& input) const;
|
||||||
|
|
||||||
|
// Draw the hierarchy.
|
||||||
|
void Draw(b3Draw* b3Draw) const;
|
||||||
|
private :
|
||||||
|
// A node in a static tree.
|
||||||
|
struct b3Node
|
||||||
|
{
|
||||||
|
b3AABB3 aabb;
|
||||||
|
u32 child1;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
u32 child2;
|
||||||
|
u32 index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if a node is a leaf node
|
||||||
|
bool IsLeaf() const
|
||||||
|
{
|
||||||
|
return child1 == NULL_NODE_S;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 m_nodeCount;
|
||||||
|
b3Node* m_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const b3AABB3& b3StaticTree::GetAABB(u32 proxyId) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(proxyId < m_nodeCount);
|
||||||
|
return m_nodes[proxyId].aabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 b3StaticTree::GetUserData(u32 proxyId) const
|
||||||
|
{
|
||||||
|
B3_ASSERT(proxyId < m_nodeCount);
|
||||||
|
B3_ASSERT(m_nodes[proxyId].IsLeaf());
|
||||||
|
return m_nodes[proxyId].index;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3StaticTree::QueryAABB(T* callback, const b3AABB3& aabb) const
|
||||||
|
{
|
||||||
|
if (m_nodeCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 root = 0;
|
||||||
|
|
||||||
|
b3Stack<u32, 256> stack;
|
||||||
|
stack.Push(root);
|
||||||
|
|
||||||
|
while (stack.IsEmpty() == false)
|
||||||
|
{
|
||||||
|
u32 nodeIndex = stack.Top();
|
||||||
|
|
||||||
|
stack.Pop();
|
||||||
|
|
||||||
|
const b3Node* node = m_nodes + nodeIndex;
|
||||||
|
|
||||||
|
if (b3TestOverlap(node->aabb, aabb) == true)
|
||||||
|
{
|
||||||
|
if (node->IsLeaf() == true)
|
||||||
|
{
|
||||||
|
if (callback->Report(nodeIndex) == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.Push(node->child1);
|
||||||
|
stack.Push(node->child2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void b3StaticTree::QueryRay(T* callback, const b3RayCastInput& input) const
|
||||||
|
{
|
||||||
|
if (m_nodeCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 p1 = input.p1;
|
||||||
|
b3Vec3 p2 = input.p2;
|
||||||
|
b3Vec3 d = p2 - p1;
|
||||||
|
float32 maxFraction = input.maxFraction;
|
||||||
|
|
||||||
|
// Ensure non-degeneracy.
|
||||||
|
B3_ASSERT(b3Dot(d, d) > B3_EPSILON * B3_EPSILON);
|
||||||
|
|
||||||
|
u32 root = 0;
|
||||||
|
|
||||||
|
b3Stack<u32, 256> stack;
|
||||||
|
stack.Push(root);
|
||||||
|
|
||||||
|
while (stack.IsEmpty() == false)
|
||||||
|
{
|
||||||
|
i32 nodeIndex = stack.Top();
|
||||||
|
stack.Pop();
|
||||||
|
|
||||||
|
if (nodeIndex == NULL_NODE_S)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const b3Node* node = m_nodes + nodeIndex;
|
||||||
|
|
||||||
|
float32 minFraction = 0.0f;
|
||||||
|
if (node->aabb.TestRay(p1, p2, maxFraction, minFraction) == true)
|
||||||
|
{
|
||||||
|
if (node->IsLeaf() == true)
|
||||||
|
{
|
||||||
|
b3RayCastInput subInput;
|
||||||
|
subInput.p1 = input.p1;
|
||||||
|
subInput.p2 = input.p2;
|
||||||
|
subInput.maxFraction = maxFraction;
|
||||||
|
|
||||||
|
float32 newFraction = callback->Report(subInput, nodeIndex);
|
||||||
|
|
||||||
|
if (newFraction == 0.0f)
|
||||||
|
{
|
||||||
|
// The client has stopped the query.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack.Push(node->child1);
|
||||||
|
stack.Push(node->child2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
108
include/bounce/common/draw.h
Normal file
108
include/bounce/common/draw.h
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_DRAW_H
|
||||||
|
#define B3_DRAW_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\math.h>
|
||||||
|
#include <bounce\collision\shapes\aabb3.h>
|
||||||
|
|
||||||
|
// Color channels used by the debug b3Draw interface.
|
||||||
|
struct b3Color
|
||||||
|
{
|
||||||
|
b3Color() { }
|
||||||
|
|
||||||
|
b3Color(float32 R, float32 G, float32 B, float32 A = 1.0f) : r(R), g(G), b(B), a(A) { }
|
||||||
|
|
||||||
|
float32 r, g, b, a;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implement this interface and set to a world so it can b3Draw the physics entities.
|
||||||
|
class b3Draw
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
// Bit flags to tell the world what needs to be b3Draw.
|
||||||
|
enum b3Flags
|
||||||
|
{
|
||||||
|
e_shapesFlag = 0x0001,
|
||||||
|
e_centerOfMassesFlag = 0x0002,
|
||||||
|
e_jointsFlag = 0x0004,
|
||||||
|
e_contactPointsFlag = 0x0008,
|
||||||
|
e_contactNormalsFlag = 0x0010,
|
||||||
|
e_contactTangentsFlag = 0x0020,
|
||||||
|
e_aabbsFlag = 0x0040,
|
||||||
|
};
|
||||||
|
|
||||||
|
b3Draw()
|
||||||
|
{
|
||||||
|
m_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~b3Draw()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFlags(u32 flags);
|
||||||
|
void AppendFlags(u32 flags);
|
||||||
|
|
||||||
|
// Draw a point.
|
||||||
|
virtual void DrawPoint(const b3Vec3& point, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a line segment.
|
||||||
|
virtual void DrawSegment(const b3Vec3& a, const b3Vec3& b, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a polygon with vertices ordered CCW.
|
||||||
|
virtual void DrawPolygon(const b3Vec3* vertices, u32 count, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a solid polygon with vertices ordered CCW.
|
||||||
|
virtual void DrawSolidPolygon(const b3Vec3* vertices, u32 count, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a circle with center, normal, and radius.
|
||||||
|
virtual void DrawCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a solid circle with center, normal, and radius.
|
||||||
|
virtual void DrawSolidCircle(const b3Vec3& normal, const b3Vec3& center, float32 radius, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a sphere with center and radius.
|
||||||
|
virtual void DrawSphere(const b3Vec3& center, float32 radius, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a solid sphere with center and radius.
|
||||||
|
virtual void DrawSolidSphere(const b3Vec3& center, float32 radius, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a AABB.
|
||||||
|
virtual void DrawAABB(const b3AABB3& aabb, const b3Color& color) = 0;
|
||||||
|
|
||||||
|
// Draw a b3Transform.
|
||||||
|
virtual void DrawTransform(const b3Transform& xf) = 0;
|
||||||
|
|
||||||
|
// Debug b3Draw flags.
|
||||||
|
u32 m_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void b3Draw::SetFlags(u32 flags)
|
||||||
|
{
|
||||||
|
m_flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void b3Draw::AppendFlags(u32 flags)
|
||||||
|
{
|
||||||
|
m_flags |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
190
include/bounce/common/geometry.h
Normal file
190
include/bounce/common/geometry.h
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_GEOMETRY_H
|
||||||
|
#define B3_GEOMETRY_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\math.h>
|
||||||
|
#include <bounce\common\math\transform.h>
|
||||||
|
|
||||||
|
// A triangle in indexed form.
|
||||||
|
struct b3Triangle
|
||||||
|
{
|
||||||
|
// Does nothing for performance.
|
||||||
|
b3Triangle() { }
|
||||||
|
|
||||||
|
// Set this triangle from three vertices.
|
||||||
|
b3Triangle(u32 _v1, u32 _v2, u32 _v3)
|
||||||
|
{
|
||||||
|
v1 = _v1;
|
||||||
|
v2 = _v2;
|
||||||
|
v3 = _v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this triangle from three vertices.
|
||||||
|
void Set(u32 _v1, u32 _v2, u32 _v3)
|
||||||
|
{
|
||||||
|
v1 = _v1;
|
||||||
|
v2 = _v2;
|
||||||
|
v3 = _v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if this triangle contains a given vertex.
|
||||||
|
bool TestVertex(u32 v) const
|
||||||
|
{
|
||||||
|
return v == v1 || v == v2 || v == v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if this triangle contains two vertices.
|
||||||
|
bool TestEdge(u32 _v1, u32 _v2) const
|
||||||
|
{
|
||||||
|
return TestVertex(_v1) && TestVertex(_v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 v1, v2, v3;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A plane in constant normal form.
|
||||||
|
// dot(n, p) - d = 0.
|
||||||
|
struct b3Plane
|
||||||
|
{
|
||||||
|
// Does nothing for performance.
|
||||||
|
b3Plane() { }
|
||||||
|
|
||||||
|
// Set this plane from a normal and a signed distance from its origin.
|
||||||
|
b3Plane(const b3Vec3& _normal, float32 _offset)
|
||||||
|
{
|
||||||
|
normal = _normal;
|
||||||
|
offset = _offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this plane from a normal and a point on the plane.
|
||||||
|
b3Plane(const b3Vec3& _normal, const b3Vec3& _point)
|
||||||
|
{
|
||||||
|
normal = _normal;
|
||||||
|
offset = b3Dot(_normal, _point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute this plane from three non-colinear points.
|
||||||
|
b3Plane(const b3Vec3& A, const b3Vec3& B, const b3Vec3& C)
|
||||||
|
{
|
||||||
|
b3Vec3 N = b3Cross(B - A, C - A);
|
||||||
|
normal = b3Normalize(N);
|
||||||
|
offset = b3Dot(normal, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 normal;
|
||||||
|
float32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transform a plane by a given frame.
|
||||||
|
inline b3Plane operator*(const b3Transform& T, const b3Plane& plane)
|
||||||
|
{
|
||||||
|
b3Vec3 normal = b3Mul(T.rotation, plane.normal);
|
||||||
|
return b3Plane(normal, plane.offset + b3Dot(normal, T.position));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform a plane by a given frame.
|
||||||
|
inline b3Plane b3Mul(const b3Transform& T, const b3Plane& plane)
|
||||||
|
{
|
||||||
|
b3Vec3 normal = b3Mul(T.rotation, plane.normal);
|
||||||
|
return b3Plane(normal, plane.offset + b3Dot(normal, T.position));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float32 b3Distance(const b3Vec3& P, const b3Plane& plane)
|
||||||
|
{
|
||||||
|
return b3Dot(plane.normal, P) - plane.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project a point onto a plane.
|
||||||
|
// The plane must be normalized.
|
||||||
|
inline b3Vec3 b3Project(const b3Vec3& P, const b3Plane& plane)
|
||||||
|
{
|
||||||
|
float32 fraction = b3Distance(P, plane);
|
||||||
|
return P - fraction * plane.normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute barycentric coordinates (u, v) for point Q to segment AB.
|
||||||
|
// The last output value is the divisor.
|
||||||
|
inline void b3Barycentric(float32 out[3],
|
||||||
|
const b3Vec3& A, const b3Vec3& B,
|
||||||
|
const b3Vec3& Q)
|
||||||
|
{
|
||||||
|
b3Vec3 AB = B - A;
|
||||||
|
b3Vec3 QA = A - Q;
|
||||||
|
b3Vec3 QB = B - Q;
|
||||||
|
//float32 divisor = b3Dot(AB, AB);
|
||||||
|
out[0] = b3Dot(QB, AB);
|
||||||
|
out[1] = -b3Dot(QA, AB);
|
||||||
|
out[2] = out[0] + out[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute barycentric coordinates (u, v, w) for point Q to triangle ABC.
|
||||||
|
// The last output value is the divisor.
|
||||||
|
inline void b3Barycentric(float32 out[4],
|
||||||
|
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C,
|
||||||
|
const b3Vec3& Q)
|
||||||
|
{
|
||||||
|
// RTCD, 140.
|
||||||
|
b3Vec3 AB = B - A;
|
||||||
|
b3Vec3 AC = C - A;
|
||||||
|
|
||||||
|
b3Vec3 QA = A - Q;
|
||||||
|
b3Vec3 QB = B - Q;
|
||||||
|
b3Vec3 QC = C - Q;
|
||||||
|
|
||||||
|
b3Vec3 QB_x_QC = b3Cross(QB, QC);
|
||||||
|
b3Vec3 QC_x_QA = b3Cross(QC, QA);
|
||||||
|
b3Vec3 QA_x_QB = b3Cross(QA, QB);
|
||||||
|
|
||||||
|
b3Vec3 AB_x_AC = b3Cross(AB, AC);
|
||||||
|
//float32 divisor = b3Dot(AB_x_AC, AB_x_AC);
|
||||||
|
|
||||||
|
out[0] = b3Dot(QB_x_QC, AB_x_AC);
|
||||||
|
out[1] = b3Dot(QC_x_QA, AB_x_AC);
|
||||||
|
out[2] = b3Dot(QA_x_QB, AB_x_AC);
|
||||||
|
out[3] = out[0] + out[1] + out[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute barycentric coordinates (u, v, w, x) for point Q to tetrahedron ABCD.
|
||||||
|
// The last output value is the (positive) divisor.
|
||||||
|
inline void b3Barycentric(float32 out[5],
|
||||||
|
const b3Vec3& A, const b3Vec3& B, const b3Vec3& C, const b3Vec3& D,
|
||||||
|
const b3Vec3& Q)
|
||||||
|
{
|
||||||
|
// RTCD, 48, 49.
|
||||||
|
b3Vec3 AB = B - A;
|
||||||
|
b3Vec3 AC = C - A;
|
||||||
|
b3Vec3 AD = D - A;
|
||||||
|
|
||||||
|
b3Vec3 QA = A - Q;
|
||||||
|
b3Vec3 QB = B - Q;
|
||||||
|
b3Vec3 QC = C - Q;
|
||||||
|
b3Vec3 QD = D - Q;
|
||||||
|
|
||||||
|
float32 divisor = b3Det(AB, AC, AD);
|
||||||
|
float32 sign = b3Sign(divisor);
|
||||||
|
|
||||||
|
out[0] = sign * b3Det(QB, QC, QD);
|
||||||
|
out[1] = sign * b3Det(QA, QD, QC);
|
||||||
|
out[2] = sign * b3Det(QA, QB, QD);
|
||||||
|
out[3] = sign * b3Det(QA, QC, QB);
|
||||||
|
out[4] = sign * divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
85
include/bounce/common/math/mat.h
Normal file
85
include/bounce/common/math/mat.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_MAT_H
|
||||||
|
#define B3_MAT_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\math.h>
|
||||||
|
|
||||||
|
// A vector stored in column-major order.
|
||||||
|
template<u32 n>
|
||||||
|
struct b3Vec
|
||||||
|
{
|
||||||
|
b3Vec() { }
|
||||||
|
|
||||||
|
const float32& operator[](u32 i) const
|
||||||
|
{
|
||||||
|
return e[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float32& operator[](u32 i)
|
||||||
|
{
|
||||||
|
return e[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator+=(const b3Vec<n>& v)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
e[i] += v[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float32 e[n];
|
||||||
|
};
|
||||||
|
|
||||||
|
template<u32 n>
|
||||||
|
inline b3Vec<n> operator-(const b3Vec<n>& v)
|
||||||
|
{
|
||||||
|
b3Vec<n> result;
|
||||||
|
for (u32 i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
result[i] = -v[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A matrix stored in column-major order.
|
||||||
|
template<u32 n, u32 m>
|
||||||
|
struct b3Mat
|
||||||
|
{
|
||||||
|
b3Mat() { }
|
||||||
|
|
||||||
|
const float32& operator()(u32 i, u32 j) const
|
||||||
|
{
|
||||||
|
return e[i + n * j];
|
||||||
|
}
|
||||||
|
|
||||||
|
float32& operator()(u32 i, u32 j)
|
||||||
|
{
|
||||||
|
return e[i + n * j];
|
||||||
|
}
|
||||||
|
|
||||||
|
float32 e[n * m];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Solve Ax = b.
|
||||||
|
// Warning: Make sure to pass a copy of A to the function. It will be invalidated.
|
||||||
|
bool b3Solve(float32* b, float32* A, u32 n);
|
||||||
|
|
||||||
|
#endif
|
59
include/bounce/common/math/mat22.h
Normal file
59
include/bounce/common/math/mat22.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_MAT_22_H
|
||||||
|
#define B3_MAT_22_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\vec2.h>
|
||||||
|
|
||||||
|
// A 2-by-2 matrix stored in column-major order.
|
||||||
|
struct b3Mat22
|
||||||
|
{
|
||||||
|
// Does nothing for performance.
|
||||||
|
b3Mat22() { }
|
||||||
|
|
||||||
|
// Set this matrix from two vector elements.
|
||||||
|
b3Mat22(const b3Vec2& _x, const b3Vec2& _y) : x(_x), y(_y) { }
|
||||||
|
|
||||||
|
// Solve Ax = b.
|
||||||
|
// It doesn't compute the inverse.
|
||||||
|
// Therefore, is more efficient.
|
||||||
|
// Returns the zero vector if the matrix is singular.
|
||||||
|
b3Vec2 Solve(const b3Vec2& b) const;
|
||||||
|
|
||||||
|
b3Vec2 x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Multiply a matrix times a vector.
|
||||||
|
inline b3Vec2 operator*(const b3Mat22& A, const b3Vec2& v)
|
||||||
|
{
|
||||||
|
return v.x * A.x + v.y * A.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply a matrix times a vector.
|
||||||
|
inline b3Vec2 b3Mul(const b3Mat22& A, const b3Vec2& v)
|
||||||
|
{
|
||||||
|
return v.x * A.x + v.y * A.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert a matrix.
|
||||||
|
// If the matrix determinant is zero this returns
|
||||||
|
// the zero matrix.
|
||||||
|
inline b3Mat22 b3Inverse(const b3Mat22& A);
|
||||||
|
|
||||||
|
#endif
|
257
include/bounce/common/math/mat33.h
Normal file
257
include/bounce/common/math/mat33.h
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net
|
||||||
|
*
|
||||||
|
* 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 B3_MAT_33_H
|
||||||
|
#define B3_MAT_33_H
|
||||||
|
|
||||||
|
#include <bounce\common\math\vec3.h>
|
||||||
|
|
||||||
|
// A 3-by-3 matrix stored in column-major order.
|
||||||
|
struct b3Mat33
|
||||||
|
{
|
||||||
|
// Does nothing for performance.
|
||||||
|
b3Mat33() { }
|
||||||
|
|
||||||
|
// Set this matrix from three elements.
|
||||||
|
b3Mat33(const b3Vec3& _x, const b3Vec3& _y, const b3Vec3& _z) : x(_x), y(_y), z(_z) { }
|
||||||
|
|
||||||
|
// Read an indexed column vector from this matrix.
|
||||||
|
const b3Vec3& operator[](u32 i) const
|
||||||
|
{
|
||||||
|
return (&x)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write an indexed column vector to this matrix.
|
||||||
|
b3Vec3& operator[](u32 i)
|
||||||
|
{
|
||||||
|
return (&x)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a matrix to this matrix.
|
||||||
|
void operator+=(const b3Mat33& B)
|
||||||
|
{
|
||||||
|
x += B.x;
|
||||||
|
y += B.y;
|
||||||
|
z += B.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this matrix to the zero matrix.
|
||||||
|
void SetZero()
|
||||||
|
{
|
||||||
|
x.SetZero();
|
||||||
|
y.SetZero();
|
||||||
|
z.SetZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set this matrix to the identity matrix.
|
||||||
|
void SetIdentity()
|
||||||
|
{
|
||||||
|
x.Set(1.0f, 0.0f, 0.0f);
|
||||||
|
y.Set(0.0f, 1.0f, 0.0f);
|
||||||
|
z.Set(0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solve Ax = b.
|
||||||
|
// It doesn't compute the inverse.
|
||||||
|
// Therefore, is more efficient.
|
||||||
|
// Returns the zero vector if the matrix is singular.
|
||||||
|
b3Vec3 Solve(const b3Vec3& b) const;
|
||||||
|
|
||||||
|
float32 operator()(u32 i, u32 j) const
|
||||||
|
{
|
||||||
|
return (&x.x)[i + 3 * j];
|
||||||
|
}
|
||||||
|
|
||||||
|
b3Vec3 x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add two matrices.
|
||||||
|
inline b3Mat33 operator+(const b3Mat33& A, const b3Mat33& B)
|
||||||
|
{
|
||||||
|
return b3Mat33(A.x + B.x, A.y + B.y, A.z + B.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract two matrices.
|
||||||
|
inline b3Mat33 operator-(const b3Mat33& A, const b3Mat33& B)
|
||||||
|
{
|
||||||
|
return b3Mat33(A.x - B.x, A.y - B.y, A.z - B.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply a scalar times a matrix.
|
||||||
|
inline b3Mat33 operator*(float32 s, const b3Mat33& A)
|
||||||
|
{
|
||||||
|
return b3Mat33(s * A.x, s * A.y, s * A.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negate a matrix.
|
||||||
|
inline b3Mat33 operator-(const b3Mat33& A)
|
||||||
|
{
|
||||||
|
return -1.0f * A;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply a matrix times a vector. If the matrix
|
||||||
|
// represents a rotation this transforms the vector
|
||||||
|
// from one frame to another.
|
||||||
|
inline b3Vec3 operator*(const b3Mat33& A, const b3Vec3& v)
|
||||||
|
{
|
||||||
|
return v.x * A.x + v.y * A.y + v.z * A.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply two matrices.
|
||||||
|
inline b3Mat33 operator*(const b3Mat33& A, const b3Mat33& B)
|
||||||
|
{
|
||||||
|
return b3Mat33(A * B.x, A * B.y, A * B.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply a matrix times a vector. If the matrix
|
||||||
|
// represents a rotation this transforms the vector
|
||||||
|
// from one frame to another.
|
||||||
|
inline b3Vec3 b3Mul(const b3Mat33& A, const b3Vec3& v)
|
||||||
|
{
|
||||||
|
return v.x * A.x + v.y * A.y + v.z * A.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply two matrices.
|
||||||
|
inline b3Mat33 b3Mul(const b3Mat33& A, const b3Mat33& B)
|
||||||
|
{
|
||||||
|
return b3Mat33( b3Mul(A, B.x), b3Mul(A, B.y), b3Mul(A, B.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply the transpose of a matrix times a vector. If
|
||||||
|
// the matrix represents a rotation frame this transforms the
|
||||||
|
// vector from one frame to another (inverse b3Transform).
|
||||||
|
inline b3Vec3 b3MulT(const b3Mat33& A, const b3Vec3& v)
|
||||||
|
{
|
||||||
|
return b3Vec3(b3Dot(A.x, v), b3Dot(A.y, v), b3Dot(A.z, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply the transpose of a matrix times another.
|
||||||
|
inline b3Mat33 b3MulT(const b3Mat33& A, const b3Mat33& B)
|
||||||
|
{
|
||||||
|
return b3Mat33(
|
||||||
|
b3Vec3(b3Dot(A.x, B.x), b3Dot(A.y, B.x), b3Dot(A.z, B.x)),
|
||||||
|
b3Vec3(b3Dot(A.x, B.y), b3Dot(A.y, B.y), b3Dot(A.z, B.y)),
|
||||||
|
b3Vec3(b3Dot(A.x, B.z), b3Dot(A.y, B.z), b3Dot(A.z, B.z)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transpose a matrix.
|
||||||
|
inline b3Mat33 b3Transpose(const b3Mat33& A)
|
||||||
|
{
|
||||||
|
return b3Mat33(
|
||||||
|
b3Vec3(A.x.x, A.y.x, A.z.x),
|
||||||
|
b3Vec3(A.x.y, A.y.y, A.z.y),
|
||||||
|
b3Vec3(A.x.z, A.y.z, A.z.z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniform scale matrix.
|
||||||
|
inline b3Mat33 b3Diagonal(float32 s)
|
||||||
|
{
|
||||||
|
return b3Mat33(
|
||||||
|
b3Vec3(s, 0.0f, 0.0f),
|
||||||
|
b3Vec3(0.0f, s, 0.0f),
|
||||||
|
b3Vec3(0.0f, 0.0f, s)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uniform or non-uniform scale matrix.
|
||||||
|
inline b3Mat33 b3Diagonal(float32 x, float32 y, float32 z)
|
||||||
|
{
|
||||||
|
return b3Mat33(
|
||||||
|
b3Vec3(x, 0.0f, 0.0f),
|
||||||
|
b3Vec3(0.0f, y, 0.0f),
|
||||||
|
b3Vec3(0.0f, 0.0f, z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert a matrix.
|
||||||
|
// If the matrix is singular this
|
||||||
|
// returns the zero matrix.
|
||||||
|
b3Mat33 b3Inverse(const b3Mat33& A);
|
||||||
|
|
||||||
|
// Return a skew (anti-symmetric) matrix for a vector.
|
||||||
|
inline b3Mat33 b3Skew(const b3Vec3& v)
|
||||||
|
{
|
||||||
|
return b3Mat33(
|
||||||
|
b3Vec3(0.0f, v.z, -v.y),
|
||||||
|
b3Vec3(-v.z, 0.0f, v.x),
|
||||||
|
b3Vec3(v.y, -v.x, 0.0f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the dot product of two vectors.
|
||||||
|
inline float32 b3Inner(const b3Vec3& a, const b3Vec3& b)
|
||||||
|
{
|
||||||
|
return b3Dot(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the outer product of two vectors.
|
||||||
|
// The result is a matrix A = a * b^T.
|
||||||
|
inline b3Mat33 b3Outer(const b3Vec3& a, const b3Vec3& b)
|
||||||
|
{
|
||||||
|
return b3Mat33(b.x * a, b.y * a, b.z * a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move an inertia tensor from the its current center
|
||||||
|
// to another.
|
||||||
|
inline b3Mat33 b3MoveToCOM(const b3Mat33& inertia, float32 mass, const b3Vec3& center)
|
||||||
|
{
|
||||||
|
// Paralell Axis Theorem
|
||||||
|
// J = I + m * dot(r, r) * E - outer(r, r)
|
||||||
|
// where
|
||||||
|
// I - inertia about the center of mass
|
||||||
|
// m - mass
|
||||||
|
// E - identity 3x3
|
||||||
|
// r - displacement vector from the current com to the new com
|
||||||
|
// J - inertia tensor at the new center of rotation
|
||||||
|
float32 dd = b3Dot(center, center);
|
||||||
|
b3Mat33 A = b3Diagonal(mass * dd);
|
||||||
|
b3Mat33 B = b3Outer(center, center);
|
||||||
|
return inertia + A - B;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the inertia matrix of a body measured in
|
||||||
|
// inertial frame (variable over time) given the
|
||||||
|
// inertia matrix in body-fixed frame (constant)
|
||||||
|
// and a rotation matrix representing the orientation
|
||||||
|
// of the body frame relative to the inertial frame.
|
||||||
|
inline b3Mat33 b3RotateToFrame(const b3Mat33& inertia, const b3Mat33& rotation)
|
||||||
|
{
|
||||||
|
return rotation * inertia * b3Transpose(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute an orthogonal basis given one of its vectors.
|
||||||
|
// The vector must be normalized.
|
||||||
|
inline b3Mat33 b3Basis(const b3Vec3& a)
|
||||||
|
{
|
||||||
|
// Box2D
|
||||||
|
b3Mat33 A;
|
||||||
|
if (b3Abs(a.x) >= float32(0.57735027))
|
||||||
|
{
|
||||||
|
A.y.Set(a.y, -a.x, 0.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
A.y.Set(0.0f, a.z, -a.y);
|
||||||
|
}
|
||||||
|
A.y = b3Normalize(A.y);
|
||||||
|
A.z = b3Cross(a, A.y);
|
||||||
|
return A;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user