mirror of
https://github.com/glfw/glfw.git
synced 2026-09-19 23:43:15 +00:00
Compare commits
195 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30306e5470 | |||
| 755f913b02 | |||
| fb6fbcf700 | |||
| adf130965c | |||
| be65829055 | |||
| e0084617d5 | |||
| 8b2da399ee | |||
| e163d21f23 | |||
| 0d759c8c1a | |||
| 87ad8c0561 | |||
| 842aeb8c47 | |||
| 3dc53e21e5 | |||
| f5cbdbab4f | |||
| cf9079c783 | |||
| 0b65053ffd | |||
| 7c6a8775eb | |||
| 40da56fbf7 | |||
| c8e068712b | |||
| f6f0771770 | |||
| 4ad00fa388 | |||
| 4b4cb9ce66 | |||
| 67eadf1e97 | |||
| 6123937bde | |||
| da3a77b4e3 | |||
| 255f9f0234 | |||
| ba4504a9c7 | |||
| 7e13a4909e | |||
| afe4aadade | |||
| 8db7528ac7 | |||
| 2d39dff84a | |||
| b69b4a9f2a | |||
| 85a01bfd9b | |||
| 352a4f2757 | |||
| 41287694cb | |||
| 04a439a0a0 | |||
| e528a8c7a4 | |||
| 362751e4ef | |||
| 0db3940cc4 | |||
| e2bb5e1726 | |||
| 572ac09660 | |||
| 9f5a483256 | |||
| cc752ad6a0 | |||
| ce2ec035f4 | |||
| 20ed0a15a4 | |||
| a02aeaf972 | |||
| ca8912375c | |||
| 6b8d490249 | |||
| 84b512c62c | |||
| 1343ef5915 | |||
| 65f3bb01be | |||
| 10805cb6ec | |||
| dd01dd7bef | |||
| 1057bd38cf | |||
| fcd6ec99d3 | |||
| d2113dc9f5 | |||
| 3d62ff0e07 | |||
| 90adbe0451 | |||
| f6defeff5d | |||
| 0a1225d0df | |||
| 527952102a | |||
| 8a4e939a10 | |||
| f8395886d3 | |||
| 9527c93a1c | |||
| 37e13361f5 | |||
| bb6db74167 | |||
| 1f95fac699 | |||
| 24e4e674a5 | |||
| 460e5d792d | |||
| 02d821c0ab | |||
| d12b34388d | |||
| e686f5a249 | |||
| 33c7c28dde | |||
| 04c057238b | |||
| bfe55118dd | |||
| f825af06f0 | |||
| 2205bdd469 | |||
| 0f3b69c79d | |||
| cf10e318d6 | |||
| 1ab9dbab60 | |||
| 4f0fc55385 | |||
| 23195693ed | |||
| a7fa41612c | |||
| 5f91ea34de | |||
| ea9c186e36 | |||
| a97477337d | |||
| fec6f187d1 | |||
| 1a96c294ee | |||
| 19a28e2c9f | |||
| 1984d40e33 | |||
| cf4206d987 | |||
| cc4c232956 | |||
| 226f85efcb | |||
| 2aa8e17c88 | |||
| 3365139a6c | |||
| 2cc3c16ab1 | |||
| 3a0b397054 | |||
| b15eaeda16 | |||
| e049190ff1 | |||
| dba59cf903 | |||
| 56122cbe2f | |||
| c77edaee34 | |||
| 21ce21cc07 | |||
| 6cf15615e8 | |||
| a1399426c3 | |||
| 81249724e3 | |||
| bdcffa90eb | |||
| 1ee4c4ba62 | |||
| 7935a366f4 | |||
| 08b3af4387 | |||
| 8e96402819 | |||
| 1c104a385d | |||
| ec6f0811a0 | |||
| a257e7a3ee | |||
| acaddf9cd9 | |||
| bb50368d55 | |||
| 8503d53018 | |||
| 8d4ba0aa83 | |||
| 5abf7841f8 | |||
| ff67e06844 | |||
| 5f74c2afdf | |||
| 96b3f17d02 | |||
| 58c2c10cdb | |||
| e6cc3c4752 | |||
| 9f0e359d73 | |||
| 82c5dfc30a | |||
| ee2d036bbf | |||
| cf363103d2 | |||
| 41af5aaae2 | |||
| f0212f3f15 | |||
| 81144bb969 | |||
| b00a7d0619 | |||
| ef6dec17ba | |||
| b067bb6304 | |||
| ed18c145cd | |||
| 8247e6069d | |||
| 38ca109766 | |||
| 6d5753c548 | |||
| 0fa909a889 | |||
| 38ae319bea | |||
| 287e30239c | |||
| 530fc5a431 | |||
| d3e25db395 | |||
| f3cd42887d | |||
| 3c52cb1790 | |||
| 8309e0ecb0 | |||
| 22e9451192 | |||
| a1641cdec9 | |||
| 8f0fd7ecf5 | |||
| c7f564e866 | |||
| c9ae3f4efe | |||
| 6d0698ba0e | |||
| 155da0cd09 | |||
| b4f3adb6ee | |||
| 6b232bd8f6 | |||
| 323d4a484d | |||
| 6af25fb423 | |||
| 35b6c72634 | |||
| 5f7f6319eb | |||
| 47592fbf42 | |||
| 80a38c1e45 | |||
| c599ea0737 | |||
| 9040c64e5b | |||
| 905073a506 | |||
| 656666e722 | |||
| 460c34df4b | |||
| d1ea1ec21b | |||
| e253beaa2b | |||
| 9021e52a6f | |||
| 5b6e67119f | |||
| ad1739c63f | |||
| b415b9aacf | |||
| dc9d287e33 | |||
| 135be952fe | |||
| c21a8573b4 | |||
| 5733b0e4cb | |||
| 5c3f8efd23 | |||
| 076d9311fa | |||
| c5099ff407 | |||
| 4277e9f5d6 | |||
| 882b770ecb | |||
| a21f586c3b | |||
| 2fbd948a67 | |||
| 49cf82a0ac | |||
| 6412dcb896 | |||
| 16e80258b8 | |||
| b875bbcdf1 | |||
| 6b21c4f6c9 | |||
| e8bceaa284 | |||
| 59abeeb097 | |||
| d95b79f9eb | |||
| 1861cf4975 | |||
| 427c79b24b | |||
| f3270d4ce8 | |||
| 4974585d04 | |||
| 5268914b3f |
+6
-5
@@ -3,12 +3,16 @@
|
||||
_ReSharper*
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.suo
|
||||
*.dir
|
||||
*.vcxproj*
|
||||
*.sln
|
||||
Win32
|
||||
x64
|
||||
Debug
|
||||
Release
|
||||
MinSizeRel
|
||||
RelWithDebInfo
|
||||
|
||||
# CMake files
|
||||
Makefile
|
||||
@@ -21,6 +25,7 @@ cmake_uninstall.cmake
|
||||
docs/Doxyfile
|
||||
docs/html
|
||||
docs/warnings.txt
|
||||
docs/doxygen_sqlite3.db
|
||||
src/glfw_config.h
|
||||
src/glfw3.pc
|
||||
src/glfw3Config.cmake
|
||||
@@ -50,20 +55,16 @@ examples/simple
|
||||
examples/wave
|
||||
tests/*.app
|
||||
tests/*.exe
|
||||
tests/accuracy
|
||||
tests/clipboard
|
||||
tests/cursor
|
||||
tests/cursoranim
|
||||
tests/defaults
|
||||
tests/empty
|
||||
tests/events
|
||||
tests/fsaa
|
||||
tests/gamma
|
||||
tests/glfwinfo
|
||||
tests/iconify
|
||||
tests/joysticks
|
||||
tests/monitors
|
||||
tests/peter
|
||||
tests/msaa
|
||||
tests/reopen
|
||||
tests/sharing
|
||||
tests/tearing
|
||||
|
||||
@@ -5,34 +5,34 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${APPLE_GUI_EXECUTABLE}</string>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${APPLE_GUI_INFO_STRING}</string>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${APPLE_GUI_ICON}</string>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${APPLE_GUI_IDENTIFIER}</string>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${APPLE_GUI_LONG_VERSION_STRING}</string>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${APPLE_GUI_BUNDLE_NAME}</string>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${APPLE_GUI_SHORT_VERSION_STRING}</string>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${APPLE_GUI_BUNDLE_VERSION}</string>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${APPLE_GUI_COPYRIGHT}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
find_path(EGL_INCLUDE_DIR NAMES EGL/egl.h PATHS /opt/vc/include)
|
||||
|
||||
set(EGL_NAMES ${EGL_NAMES} egl EGL)
|
||||
set(EGL_NAMES ${EGL_NAMES} egl EGL libEGL)
|
||||
find_library(EGL_LIBRARY NAMES ${EGL_NAMES} PATHS /opt/vc/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
find_path(GLESv1_INCLUDE_DIR NAMES GLES/gl.h PATHS /opt/vc/include)
|
||||
|
||||
set(GLESv1_NAMES ${GLESv1_NAMES} GLESv1_CM)
|
||||
set(GLESv1_NAMES ${GLESv1_NAMES} GLESv1_CM libGLES_CM)
|
||||
find_library(GLESv1_LIBRARY NAMES ${GLESv1_NAMES} PATHS /opt/vc/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
find_path(GLESv2_INCLUDE_DIR NAMES GLES2/gl2.h PATHS /opt/vc/include)
|
||||
|
||||
set(GLESv2_NAMES ${GLESv2_NAMES} GLESv2)
|
||||
set(GLESv2_NAMES ${GLESv2_NAMES} GLESv2 libGLESv2)
|
||||
find_library(GLESv2_LIBRARY NAMES ${GLESv2_NAMES} PATHS /opt/vc/lib)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
+41
-76
@@ -1,8 +1,8 @@
|
||||
project(GLFW C)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
if (CMAKE_VERSION VERSION_EQUAL "3.0" OR CMAKE_VERSION VERSION_GREATER "3.0")
|
||||
if (NOT CMAKE_VERSION VERSION_LESS "3.0")
|
||||
# Until all major package systems have moved to CMake 3,
|
||||
# we stick with the older INSTALL_NAME_DIR mechanism
|
||||
cmake_policy(SET CMP0042 OLD)
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
|
||||
set(GLFW_VERSION_MAJOR "3")
|
||||
set(GLFW_VERSION_MINOR "1")
|
||||
set(GLFW_VERSION_PATCH "1")
|
||||
set(GLFW_VERSION_PATCH "2")
|
||||
set(GLFW_VERSION_EXTRA "")
|
||||
set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}")
|
||||
set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}")
|
||||
@@ -26,8 +26,7 @@ option(GLFW_INSTALL "Generate installation target" ON)
|
||||
option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF)
|
||||
|
||||
if (WIN32)
|
||||
option(GLFW_USE_DWM_SWAP_INTERVAL "Set swap interval even when DWM compositing is enabled" OFF)
|
||||
option(GLFW_USE_OPTIMUS_HPG "Force use of high-performance GPU on Optimus systems" OFF)
|
||||
option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
@@ -58,6 +57,8 @@ elseif (GLFW_USE_MIR)
|
||||
set(GLFW_USE_EGL ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
|
||||
|
||||
if (GLFW_USE_EGL)
|
||||
set(GLFW_CLIENT_LIBRARY "opengl" CACHE STRING
|
||||
"The client library to use; one of opengl, glesv1 or glesv2")
|
||||
@@ -72,7 +73,6 @@ if (GLFW_USE_EGL)
|
||||
message(FATAL_ERROR "Unsupported client library")
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMake/modules")
|
||||
find_package(EGL REQUIRED)
|
||||
|
||||
if (NOT _GLFW_USE_OPENGL)
|
||||
@@ -137,7 +137,6 @@ endif()
|
||||
|
||||
if (MINGW)
|
||||
# Enable link-time exploit mitigation features enabled by default on MSVC
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
# Compatibility with data execution prevention (DEP)
|
||||
@@ -160,6 +159,12 @@ if (MINGW)
|
||||
if (_GLFW_HAS_64ASLR)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--high-entropy-va ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
endif()
|
||||
|
||||
# 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.
|
||||
add_definitions(-DUNICODE -DWINVER=0x0501)
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
@@ -204,6 +209,25 @@ else()
|
||||
message(FATAL_ERROR "No supported platform was detected")
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Find and add Unix math and time libraries
|
||||
#--------------------------------------------------------------------
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_library(RT_LIBRARY rt)
|
||||
mark_as_advanced(RT_LIBRARY)
|
||||
if (RT_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${RT_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lrt")
|
||||
endif()
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
mark_as_advanced(MATH_LIBRARY)
|
||||
if (MATH_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Use Win32 for window creation
|
||||
#--------------------------------------------------------------------
|
||||
@@ -211,19 +235,8 @@ if (_GLFW_WIN32)
|
||||
|
||||
list(APPEND glfw_PKG_LIBS "-lgdi32")
|
||||
|
||||
if (GLFW_USE_DWM_SWAP_INTERVAL)
|
||||
set(_GLFW_USE_DWM_SWAP_INTERVAL 1)
|
||||
endif()
|
||||
if (GLFW_USE_OPTIMUS_HPG)
|
||||
set(_GLFW_USE_OPTIMUS_HPG 1)
|
||||
endif()
|
||||
|
||||
# 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.
|
||||
if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
|
||||
add_definitions(-DUNICODE -DWINVER=0x0501)
|
||||
if (GLFW_USE_HYBRID_HPG)
|
||||
set(_GLFW_USE_HYBRID_HPG 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -250,9 +263,6 @@ if (_GLFW_X11)
|
||||
# Set up library and include paths
|
||||
list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}")
|
||||
list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}")
|
||||
if (UNIX AND NOT APPLE)
|
||||
list(APPEND glfw_LIBRARIES "${RT_LIBRARY}")
|
||||
endif()
|
||||
|
||||
# Check for XRandR (modern resolution switching and gamma control)
|
||||
if (NOT X11_Xrandr_FOUND)
|
||||
@@ -309,20 +319,6 @@ if (_GLFW_X11)
|
||||
|
||||
list(APPEND glfw_INCLUDE_DIR "${X11_Xkb_INCLUDE_PATH}")
|
||||
|
||||
find_library(RT_LIBRARY rt)
|
||||
mark_as_advanced(RT_LIBRARY)
|
||||
if (RT_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${RT_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lrt")
|
||||
endif()
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
mark_as_advanced(MATH_LIBRARY)
|
||||
if (MATH_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lm")
|
||||
endif()
|
||||
|
||||
# Check for Xcursor
|
||||
if (NOT X11_Xcursor_FOUND)
|
||||
message(FATAL_ERROR "The Xcursor libraries and headers were not found")
|
||||
@@ -348,13 +344,6 @@ if (_GLFW_WAYLAND)
|
||||
list(APPEND glfw_PKG_DEPS "xkbcommon")
|
||||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
|
||||
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}")
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
mark_as_advanced(MATH_LIBRARY)
|
||||
if (MATH_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
@@ -371,13 +360,6 @@ if (_GLFW_MIR)
|
||||
list(APPEND glfw_PKG_DEPS "xkbcommon")
|
||||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
|
||||
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}")
|
||||
|
||||
find_library(MATH_LIBRARY m)
|
||||
mark_as_advanced(MATH_LIBRARY)
|
||||
if (MATH_LIBRARY)
|
||||
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}")
|
||||
list(APPEND glfw_PKG_LIBS "-lm")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
@@ -390,32 +372,10 @@ if (_GLFW_GLX)
|
||||
|
||||
list(APPEND glfw_PKG_DEPS "gl")
|
||||
|
||||
include(CheckFunctionExists)
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${OPENGL_gl_LIBRARY}")
|
||||
check_function_exists(glXGetProcAddress _GLFW_HAS_GLXGETPROCADDRESS)
|
||||
check_function_exists(glXGetProcAddressARB _GLFW_HAS_GLXGETPROCADDRESSARB)
|
||||
check_function_exists(glXGetProcAddressEXT _GLFW_HAS_GLXGETPROCADDRESSEXT)
|
||||
|
||||
if (NOT _GLFW_HAS_GLXGETPROCADDRESS AND
|
||||
NOT _GLFW_HAS_GLXGETPROCADDRESSARB AND
|
||||
NOT _GLFW_HAS_GLXGETPROCADDRESSEXT)
|
||||
message(WARNING "No glXGetProcAddressXXX variant found")
|
||||
|
||||
# Check for dlopen support as a fallback
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_DL_LIBS}")
|
||||
check_function_exists(dlopen _GLFW_HAS_DLOPEN)
|
||||
if (NOT _GLFW_HAS_DLOPEN)
|
||||
message(FATAL_ERROR "No entry point retrieval mechanism found")
|
||||
endif()
|
||||
|
||||
if (CMAKE_DL_LIBS)
|
||||
list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}")
|
||||
list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}")
|
||||
endif()
|
||||
if (CMAKE_DL_LIBS)
|
||||
list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}")
|
||||
list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
@@ -442,6 +402,11 @@ if (_GLFW_EGL)
|
||||
list(APPEND glfw_PKG_DEPS "glesv2")
|
||||
endif()
|
||||
|
||||
if (CMAKE_DL_LIBS)
|
||||
list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}")
|
||||
list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -6,8 +6,9 @@ GLFW is a free, Open Source, multi-platform library for OpenGL and OpenGL ES
|
||||
application development. It provides a simple, platform-independent API for
|
||||
creating windows and contexts, reading input, handling events, etc.
|
||||
|
||||
Version 3.1.1 adds fixes for a number of bugs that together affect all supported
|
||||
platforms, most notably workarounds for bugs in some popular window managers.
|
||||
Version 3.1.2 adds fixes for a large number of bugs that together affect all
|
||||
supported platforms, as well as dynamic loading work that simplifies compilation
|
||||
and linking.
|
||||
|
||||
If you are new to GLFW, you may find the
|
||||
[introductory tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW
|
||||
@@ -59,30 +60,69 @@ GLFW bundles a number of dependencies in the `deps/` directory.
|
||||
examples
|
||||
- An OpenGL 3.2 core loader generated by
|
||||
[glad](https://github.com/Dav1dde/glad) for examples using modern OpenGL
|
||||
- [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in
|
||||
examples
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
- Made library compilation fail if any header option macros are defined
|
||||
- Removed support for LCC and Borland C++
|
||||
- Bugfix: `glfwSetTime` silently accepted invalid values
|
||||
- [Cocoa] Bugfix: `NSHighResolutionCapable` was not enabled for test and
|
||||
example programs
|
||||
- [Cocoa] Bugfix: Sleeping monitors were not included in the monitor list
|
||||
- [Cocoa] Bugfix: `glfwSetWindowSize` did not change the video mode for full
|
||||
screen windows
|
||||
- [X11] Added support for Cygwin-X
|
||||
- [X11] Made XInput2 optional at compile-time
|
||||
- [X11] Made Xxf86vm optional at compile-time
|
||||
- [X11] Bugfix: Moved `_NET_REQUEST_FRAME_EXTENTS` request to
|
||||
`glfwGetWindowFrameSize` and added protocol-breaking timeout
|
||||
as a workaround for broken support in Unity, Fluxbox and Xfwm
|
||||
- [X11] Bugfix: Mouse button `GLFW_MOUSE_BUTTON_4` was never used
|
||||
- [X11] Bugfix: `glfwTerminate` could close an unrelated file descriptor
|
||||
- [X11] Bugfix: Some WMs (KWM, Fluxbox) did not respect cursor redefinition
|
||||
- [WGL] Bugfix: The context flags debug bit was not set for OpenGL ES
|
||||
- [GLX] Bugfix: The context flags debug bit was not set for OpenGL ES
|
||||
- [EGL] Bugfix: The context flags debug bit was not set for OpenGL ES
|
||||
- Made all client API functions dynamically loaded
|
||||
- Changed minimum required CMake version to 2.8.12
|
||||
- Replaced GLU with [linmath.h](https://github.com/datenwolf/linmath.h) in
|
||||
example programs
|
||||
- Merged all cursor test programs into the `cursor` program
|
||||
- Removed all mention of GLU in examples, build files and package dependencies
|
||||
- Bugfix: Initialization failed on headless systems
|
||||
- Bugfix: The cached current context could get out of sync
|
||||
- Bugfix: `glfwIconifyWindow` did not restore the original video mode for full
|
||||
screen windows created with `GLFW_AUTO_ICONIFY`
|
||||
- [Win32] Renamed hybrid GPU override compile-time option to
|
||||
`_GLFW_USE_HYBRID_HPG` and added support for AMD PowerXpress systems
|
||||
- [Win32] Bugfix: `glfwGetVideoModes` included unusable modes on some systems
|
||||
- [Win32] Bugfix: `glfwWaitEvents` would return directly for focused windows in
|
||||
disabled cursor mode
|
||||
- [Cocoa] Bugfix: The cached `NSScreen` for a monitor could get out of sync
|
||||
- [Cocoa] Bugfix: The `GLFW_AUTO_ICONIFY` window hint was ignored
|
||||
- [Cocoa] Bugfix: Resizing a window to its minimum size would segfault
|
||||
- [Cocoa] Bugfix: Creating or showing a window would make its context current
|
||||
- [Cocoa] Bugfix: Joysticks connected after `glfwInit` were not detected
|
||||
- [Cocoa] Bugfix: Cursor creation failed unless a window had been created.
|
||||
- [Cocoa] Bugfix: Window refresh events were not generated by iconification or
|
||||
restoration
|
||||
- [Cocoa] Bugfix: The primary monitor would get reported as disconnected when
|
||||
entering full screen on a dual-GPU machine with automatic
|
||||
graphics switching
|
||||
- [Cocoa] Bugfix: The original video modes were not restored when the
|
||||
application was hidden
|
||||
- [X11] Bugfix: `glfwInit` would segfault on systems without RandR
|
||||
- [X11] Bugfix: The response to `_NET_WM_PING` was sent to the wrong window
|
||||
- [X11] Bugfix: Character input via XIM did not work in many cases
|
||||
- [X11] Bugfix: No fallback existed for missing `_NET_ACTIVE_WINDOW` support
|
||||
- [X11] Bugfix: Some significant window focus events were ignored
|
||||
- [X11] Bugfix: The `GLFW_AUTO_ICONIFY` window hint was ignored
|
||||
- [X11] Bugfix: The original video mode was not restored on iconification of
|
||||
full screen windows
|
||||
- [X11] Bugfix: `GLFW_ARROW_CURSOR` selected the wrong cursor image
|
||||
- [X11] Bugfix: The `GLFW_DECORATED` hint was not ignored for full screen
|
||||
- [X11] Bugfix: `glfwWaitEvents` did not handle `EINTR` for `select`
|
||||
- [X11] Bugfix: `glfwWaitEvents` could return when no events were available
|
||||
- [X11] Bugfix: `XkbGetKeyboard` fails on XWayland
|
||||
- [X11] Bugfix: Character input did not work correctly for non-UTF-8 locales
|
||||
- [X11] Bugfix: Long input sequences generated by IMEs were discarded
|
||||
- [WGL] Made all WGL functions dynamically loaded
|
||||
- [WGL] Removed `GLFW_USE_DWM_SWAP_INTERVAL` compile-time option
|
||||
- [WGL] Bugfix: Swap interval was ignored when DWM was enabled
|
||||
- [WGL] Bugfix: Failure to find a pixel format was reported incorrectly
|
||||
- [GLX] Added dependency on `libdl` on systems where it provides `dlopen`
|
||||
- [GLX] Made all GLX functions dynamically loaded
|
||||
- [GLX] Removed `_GLFW_HAS_GLXGETPROCADDRESS*` and `_GLFW_HAS_DLOPEN`
|
||||
compile-time options
|
||||
- [GLX] Bugfix: Failure to find a `GLXFBConfig` was reported incorrectly
|
||||
- [EGL] Made all EGL functions dynamically loaded
|
||||
- [EGL] Bugfix: `glfwGetProcAddress` did not return the addresses of core
|
||||
functions
|
||||
- [EGL] Bugfix: Failure to find an `EGLConfig` was reported incorrectly
|
||||
- [NSGL] Bugfix: Failure to find a pixel format was reported incorrectly
|
||||
|
||||
|
||||
## Contact
|
||||
@@ -100,9 +140,7 @@ request, please file it in the
|
||||
[issue tracker](https://github.com/glfw/glfw/issues) on GitHub.
|
||||
|
||||
Finally, if you're interested in helping out with the development of GLFW or
|
||||
porting it to your favorite platform, we have an occasionally active
|
||||
[developer's mailing list](https://lists.stacken.kth.se/mailman/listinfo/glfw-dev),
|
||||
or you could join us on `#glfw`.
|
||||
porting it to your favorite platform, join us on GitHub or IRC.
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
@@ -121,6 +159,7 @@ skills.
|
||||
- Doug Binks
|
||||
- blanco
|
||||
- Martin Capitanio
|
||||
- Chi-kwan Chan
|
||||
- Lambert Clara
|
||||
- Andrew Corrigan
|
||||
- Noel Cower
|
||||
@@ -142,14 +181,17 @@ skills.
|
||||
- heromyth
|
||||
- Lucas Hinderberger
|
||||
- Paul Holden
|
||||
- Aaron Jacobs
|
||||
- Toni Jovanoski
|
||||
- Arseny Kapoulkine
|
||||
- Osman Keskin
|
||||
- Cameron King
|
||||
- Peter Knut
|
||||
- Eric Larson
|
||||
- Robin Leffmann
|
||||
- Glenn Lewis
|
||||
- Shane Liesegang
|
||||
- Eyal Lotem
|
||||
- Дмитри Малышев
|
||||
- Martins Mozeiko
|
||||
- Tristam MacDonald
|
||||
@@ -173,6 +215,7 @@ skills.
|
||||
- Peoro
|
||||
- Braden Pellett
|
||||
- Arturo J. Pérez
|
||||
- Emmanuel Gil Peyrot
|
||||
- Cyril Pichard
|
||||
- Pieroman
|
||||
- Jorge Rodriguez
|
||||
@@ -191,6 +234,7 @@ skills.
|
||||
- Julian Squires
|
||||
- Johannes Stein
|
||||
- Justin Stoecker
|
||||
- Elviss Strazdins
|
||||
- Nathan Sweet
|
||||
- TTK-Bandit
|
||||
- Sergey Tikhomirov
|
||||
|
||||
Vendored
+571
@@ -0,0 +1,571 @@
|
||||
#ifndef LINMATH_H
|
||||
#define LINMATH_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#define LINMATH_H_DEFINE_VEC(n) \
|
||||
typedef float vec##n[n]; \
|
||||
static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for(i=0; i<n; ++i) \
|
||||
r[i] = a[i] + b[i]; \
|
||||
} \
|
||||
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
int i; \
|
||||
for(i=0; i<n; ++i) \
|
||||
r[i] = a[i] - b[i]; \
|
||||
} \
|
||||
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \
|
||||
{ \
|
||||
int i; \
|
||||
for(i=0; i<n; ++i) \
|
||||
r[i] = v[i] * s; \
|
||||
} \
|
||||
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \
|
||||
{ \
|
||||
float p = 0.; \
|
||||
int i; \
|
||||
for(i=0; i<n; ++i) \
|
||||
p += b[i]*a[i]; \
|
||||
return p; \
|
||||
} \
|
||||
static inline float vec##n##_len(vec##n const v) \
|
||||
{ \
|
||||
return sqrtf(vec##n##_mul_inner(v,v)); \
|
||||
} \
|
||||
static inline void vec##n##_norm(vec##n r, vec##n const v) \
|
||||
{ \
|
||||
float k = 1.f / vec##n##_len(v); \
|
||||
vec##n##_scale(r, v, k); \
|
||||
}
|
||||
|
||||
LINMATH_H_DEFINE_VEC(2)
|
||||
LINMATH_H_DEFINE_VEC(3)
|
||||
LINMATH_H_DEFINE_VEC(4)
|
||||
|
||||
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
|
||||
{
|
||||
r[0] = a[1]*b[2] - a[2]*b[1];
|
||||
r[1] = a[2]*b[0] - a[0]*b[2];
|
||||
r[2] = a[0]*b[1] - a[1]*b[0];
|
||||
}
|
||||
|
||||
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
|
||||
{
|
||||
float p = 2.f*vec3_mul_inner(v, n);
|
||||
int i;
|
||||
for(i=0;i<3;++i)
|
||||
r[i] = v[i] - p*n[i];
|
||||
}
|
||||
|
||||
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b)
|
||||
{
|
||||
r[0] = a[1]*b[2] - a[2]*b[1];
|
||||
r[1] = a[2]*b[0] - a[0]*b[2];
|
||||
r[2] = a[0]*b[1] - a[1]*b[0];
|
||||
r[3] = 1.f;
|
||||
}
|
||||
|
||||
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n)
|
||||
{
|
||||
float p = 2.f*vec4_mul_inner(v, n);
|
||||
int i;
|
||||
for(i=0;i<4;++i)
|
||||
r[i] = v[i] - p*n[i];
|
||||
}
|
||||
|
||||
typedef vec4 mat4x4[4];
|
||||
static inline void mat4x4_identity(mat4x4 M)
|
||||
{
|
||||
int i, j;
|
||||
for(i=0; i<4; ++i)
|
||||
for(j=0; j<4; ++j)
|
||||
M[i][j] = i==j ? 1.f : 0.f;
|
||||
}
|
||||
static inline void mat4x4_dup(mat4x4 M, mat4x4 N)
|
||||
{
|
||||
int i, j;
|
||||
for(i=0; i<4; ++i)
|
||||
for(j=0; j<4; ++j)
|
||||
M[i][j] = N[i][j];
|
||||
}
|
||||
static inline void mat4x4_row(vec4 r, mat4x4 M, int i)
|
||||
{
|
||||
int k;
|
||||
for(k=0; k<4; ++k)
|
||||
r[k] = M[k][i];
|
||||
}
|
||||
static inline void mat4x4_col(vec4 r, mat4x4 M, int i)
|
||||
{
|
||||
int k;
|
||||
for(k=0; k<4; ++k)
|
||||
r[k] = M[i][k];
|
||||
}
|
||||
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N)
|
||||
{
|
||||
int i, j;
|
||||
for(j=0; j<4; ++j)
|
||||
for(i=0; i<4; ++i)
|
||||
M[i][j] = N[j][i];
|
||||
}
|
||||
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
vec4_add(M[i], a[i], b[i]);
|
||||
}
|
||||
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
vec4_sub(M[i], a[i], b[i]);
|
||||
}
|
||||
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
vec4_scale(M[i], a[i], k);
|
||||
}
|
||||
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z)
|
||||
{
|
||||
int i;
|
||||
vec4_scale(M[0], a[0], x);
|
||||
vec4_scale(M[1], a[1], y);
|
||||
vec4_scale(M[2], a[2], z);
|
||||
for(i = 0; i < 4; ++i) {
|
||||
M[3][i] = a[3][i];
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
mat4x4 temp;
|
||||
int k, r, c;
|
||||
for(c=0; c<4; ++c) for(r=0; r<4; ++r) {
|
||||
temp[c][r] = 0.f;
|
||||
for(k=0; k<4; ++k)
|
||||
temp[c][r] += a[k][r] * b[c][k];
|
||||
}
|
||||
mat4x4_dup(M, temp);
|
||||
}
|
||||
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v)
|
||||
{
|
||||
int i, j;
|
||||
for(j=0; j<4; ++j) {
|
||||
r[j] = 0.f;
|
||||
for(i=0; i<4; ++i)
|
||||
r[j] += M[i][j] * v[i];
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z)
|
||||
{
|
||||
mat4x4_identity(T);
|
||||
T[3][0] = x;
|
||||
T[3][1] = y;
|
||||
T[3][2] = z;
|
||||
}
|
||||
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
|
||||
{
|
||||
vec4 t = {x, y, z, 0};
|
||||
vec4 r;
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
mat4x4_row(r, M, i);
|
||||
M[3][i] += vec4_mul_inner(r, t);
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b)
|
||||
{
|
||||
int i, j;
|
||||
for(i=0; i<4; ++i) for(j=0; j<4; ++j)
|
||||
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f;
|
||||
}
|
||||
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
vec3 u = {x, y, z};
|
||||
|
||||
if(vec3_len(u) > 1e-4) {
|
||||
vec3_norm(u, u);
|
||||
mat4x4 T;
|
||||
mat4x4_from_vec3_mul_outer(T, u, u);
|
||||
|
||||
mat4x4 S = {
|
||||
{ 0, u[2], -u[1], 0},
|
||||
{-u[2], 0, u[0], 0},
|
||||
{ u[1], -u[0], 0, 0},
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
mat4x4_scale(S, S, s);
|
||||
|
||||
mat4x4 C;
|
||||
mat4x4_identity(C);
|
||||
mat4x4_sub(C, C, T);
|
||||
|
||||
mat4x4_scale(C, C, c);
|
||||
|
||||
mat4x4_add(T, T, C);
|
||||
mat4x4_add(T, T, S);
|
||||
|
||||
T[3][3] = 1.;
|
||||
mat4x4_mul(R, M, T);
|
||||
} else {
|
||||
mat4x4_dup(R, M);
|
||||
}
|
||||
}
|
||||
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {
|
||||
{1.f, 0.f, 0.f, 0.f},
|
||||
{0.f, c, s, 0.f},
|
||||
{0.f, -s, c, 0.f},
|
||||
{0.f, 0.f, 0.f, 1.f}
|
||||
};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {
|
||||
{ c, 0.f, s, 0.f},
|
||||
{ 0.f, 1.f, 0.f, 0.f},
|
||||
{ -s, 0.f, c, 0.f},
|
||||
{ 0.f, 0.f, 0.f, 1.f}
|
||||
};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
|
||||
{
|
||||
float s = sinf(angle);
|
||||
float c = cosf(angle);
|
||||
mat4x4 R = {
|
||||
{ c, s, 0.f, 0.f},
|
||||
{ -s, c, 0.f, 0.f},
|
||||
{ 0.f, 0.f, 1.f, 0.f},
|
||||
{ 0.f, 0.f, 0.f, 1.f}
|
||||
};
|
||||
mat4x4_mul(Q, M, R);
|
||||
}
|
||||
static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
|
||||
{
|
||||
float s[6];
|
||||
float c[6];
|
||||
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1];
|
||||
s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2];
|
||||
s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3];
|
||||
s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2];
|
||||
s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3];
|
||||
s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3];
|
||||
|
||||
c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1];
|
||||
c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2];
|
||||
c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3];
|
||||
c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2];
|
||||
c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3];
|
||||
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3];
|
||||
|
||||
/* Assumes it is invertible */
|
||||
float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] );
|
||||
|
||||
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
|
||||
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
|
||||
T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
|
||||
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet;
|
||||
|
||||
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet;
|
||||
T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet;
|
||||
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet;
|
||||
T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet;
|
||||
|
||||
T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet;
|
||||
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet;
|
||||
T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet;
|
||||
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet;
|
||||
|
||||
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet;
|
||||
T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet;
|
||||
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
|
||||
T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
|
||||
}
|
||||
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
|
||||
{
|
||||
mat4x4_dup(R, M);
|
||||
float s = 1.;
|
||||
vec3 h;
|
||||
|
||||
vec3_norm(R[2], R[2]);
|
||||
|
||||
s = vec3_mul_inner(R[1], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[1], R[1], h);
|
||||
vec3_norm(R[2], R[2]);
|
||||
|
||||
s = vec3_mul_inner(R[1], R[2]);
|
||||
vec3_scale(h, R[2], s);
|
||||
vec3_sub(R[1], R[1], h);
|
||||
vec3_norm(R[1], R[1]);
|
||||
|
||||
s = vec3_mul_inner(R[0], R[1]);
|
||||
vec3_scale(h, R[1], s);
|
||||
vec3_sub(R[0], R[0], h);
|
||||
vec3_norm(R[0], R[0]);
|
||||
}
|
||||
|
||||
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f*n/(r-l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f*n/(t-b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = (r+l)/(r-l);
|
||||
M[2][1] = (t+b)/(t-b);
|
||||
M[2][2] = -(f+n)/(f-n);
|
||||
M[2][3] = -1.f;
|
||||
|
||||
M[3][2] = -2.f*(f*n)/(f-n);
|
||||
M[3][0] = M[3][1] = M[3][3] = 0.f;
|
||||
}
|
||||
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||
{
|
||||
M[0][0] = 2.f/(r-l);
|
||||
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||
|
||||
M[1][1] = 2.f/(t-b);
|
||||
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||
|
||||
M[2][2] = -2.f/(f-n);
|
||||
M[2][0] = M[2][1] = M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = -(r+l)/(r-l);
|
||||
M[3][1] = -(t+b)/(t-b);
|
||||
M[3][2] = -(f+n)/(f-n);
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
|
||||
{
|
||||
/* NOTE: Degrees are an unhandy unit to work with.
|
||||
* linmath.h uses radians for everything! */
|
||||
float const a = 1.f / (float) tan(y_fov / 2.f);
|
||||
|
||||
m[0][0] = a / aspect;
|
||||
m[0][1] = 0.f;
|
||||
m[0][2] = 0.f;
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = 0.f;
|
||||
m[1][1] = a;
|
||||
m[1][2] = 0.f;
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = 0.f;
|
||||
m[2][1] = 0.f;
|
||||
m[2][2] = -((f + n) / (f - n));
|
||||
m[2][3] = -1.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = -((2.f * f * n) / (f - n));
|
||||
m[3][3] = 0.f;
|
||||
}
|
||||
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
|
||||
{
|
||||
/* Adapted from Android's OpenGL Matrix.java. */
|
||||
/* See the OpenGL GLUT documentation for gluLookAt for a description */
|
||||
/* of the algorithm. We implement it in a straightforward way: */
|
||||
|
||||
/* TODO: The negation of of can be spared by swapping the order of
|
||||
* operands in the following cross products in the right way. */
|
||||
vec3 f;
|
||||
vec3_sub(f, center, eye);
|
||||
vec3_norm(f, f);
|
||||
|
||||
vec3 s;
|
||||
vec3_mul_cross(s, f, up);
|
||||
vec3_norm(s, s);
|
||||
|
||||
vec3 t;
|
||||
vec3_mul_cross(t, s, f);
|
||||
|
||||
m[0][0] = s[0];
|
||||
m[0][1] = t[0];
|
||||
m[0][2] = -f[0];
|
||||
m[0][3] = 0.f;
|
||||
|
||||
m[1][0] = s[1];
|
||||
m[1][1] = t[1];
|
||||
m[1][2] = -f[1];
|
||||
m[1][3] = 0.f;
|
||||
|
||||
m[2][0] = s[2];
|
||||
m[2][1] = t[2];
|
||||
m[2][2] = -f[2];
|
||||
m[2][3] = 0.f;
|
||||
|
||||
m[3][0] = 0.f;
|
||||
m[3][1] = 0.f;
|
||||
m[3][2] = 0.f;
|
||||
m[3][3] = 1.f;
|
||||
|
||||
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
|
||||
}
|
||||
|
||||
typedef float quat[4];
|
||||
static inline void quat_identity(quat q)
|
||||
{
|
||||
q[0] = q[1] = q[2] = 0.f;
|
||||
q[3] = 1.f;
|
||||
}
|
||||
static inline void quat_add(quat r, quat a, quat b)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
r[i] = a[i] + b[i];
|
||||
}
|
||||
static inline void quat_sub(quat r, quat a, quat b)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
r[i] = a[i] - b[i];
|
||||
}
|
||||
static inline void quat_mul(quat r, quat p, quat q)
|
||||
{
|
||||
vec3 w;
|
||||
vec3_mul_cross(r, p, q);
|
||||
vec3_scale(w, p, q[3]);
|
||||
vec3_add(r, r, w);
|
||||
vec3_scale(w, q, p[3]);
|
||||
vec3_add(r, r, w);
|
||||
r[3] = p[3]*q[3] - vec3_mul_inner(p, q);
|
||||
}
|
||||
static inline void quat_scale(quat r, quat v, float s)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
r[i] = v[i] * s;
|
||||
}
|
||||
static inline float quat_inner_product(quat a, quat b)
|
||||
{
|
||||
float p = 0.f;
|
||||
int i;
|
||||
for(i=0; i<4; ++i)
|
||||
p += b[i]*a[i];
|
||||
return p;
|
||||
}
|
||||
static inline void quat_conj(quat r, quat q)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<3; ++i)
|
||||
r[i] = -q[i];
|
||||
r[3] = q[3];
|
||||
}
|
||||
static inline void quat_rotate(quat r, float angle, vec3 axis) {
|
||||
vec3 v;
|
||||
vec3_scale(v, axis, sinf(angle / 2));
|
||||
int i;
|
||||
for(i=0; i<3; ++i)
|
||||
r[i] = v[i];
|
||||
r[3] = cosf(angle / 2);
|
||||
}
|
||||
#define quat_norm vec4_norm
|
||||
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v)
|
||||
{
|
||||
/*
|
||||
* Method by Fabian 'ryg' Giessen (of Farbrausch)
|
||||
t = 2 * cross(q.xyz, v)
|
||||
v' = v + q.w * t + cross(q.xyz, t)
|
||||
*/
|
||||
vec3 t = {q[0], q[1], q[2]};
|
||||
vec3 u = {q[0], q[1], q[2]};
|
||||
|
||||
vec3_mul_cross(t, t, v);
|
||||
vec3_scale(t, t, 2);
|
||||
|
||||
vec3_mul_cross(u, u, t);
|
||||
vec3_scale(t, t, q[3]);
|
||||
|
||||
vec3_add(r, v, t);
|
||||
vec3_add(r, r, u);
|
||||
}
|
||||
static inline void mat4x4_from_quat(mat4x4 M, quat q)
|
||||
{
|
||||
float a = q[3];
|
||||
float b = q[0];
|
||||
float c = q[1];
|
||||
float d = q[2];
|
||||
float a2 = a*a;
|
||||
float b2 = b*b;
|
||||
float c2 = c*c;
|
||||
float d2 = d*d;
|
||||
|
||||
M[0][0] = a2 + b2 - c2 - d2;
|
||||
M[0][1] = 2.f*(b*c + a*d);
|
||||
M[0][2] = 2.f*(b*d - a*c);
|
||||
M[0][3] = 0.f;
|
||||
|
||||
M[1][0] = 2*(b*c - a*d);
|
||||
M[1][1] = a2 - b2 + c2 - d2;
|
||||
M[1][2] = 2.f*(c*d + a*b);
|
||||
M[1][3] = 0.f;
|
||||
|
||||
M[2][0] = 2.f*(b*d + a*c);
|
||||
M[2][1] = 2.f*(c*d - a*b);
|
||||
M[2][2] = a2 - b2 - c2 + d2;
|
||||
M[2][3] = 0.f;
|
||||
|
||||
M[3][0] = M[3][1] = M[3][2] = 0.f;
|
||||
M[3][3] = 1.f;
|
||||
}
|
||||
|
||||
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q)
|
||||
{
|
||||
/* XXX: The way this is written only works for othogonal matrices. */
|
||||
/* TODO: Take care of non-orthogonal case. */
|
||||
quat_mul_vec3(R[0], q, M[0]);
|
||||
quat_mul_vec3(R[1], q, M[1]);
|
||||
quat_mul_vec3(R[2], q, M[2]);
|
||||
|
||||
R[3][0] = R[3][1] = R[3][2] = 0.f;
|
||||
R[3][3] = 1.f;
|
||||
}
|
||||
static inline void quat_from_mat4x4(quat q, mat4x4 M)
|
||||
{
|
||||
float r=0.f;
|
||||
int i;
|
||||
|
||||
int perm[] = { 0, 1, 2, 0, 1 };
|
||||
int *p = perm;
|
||||
|
||||
for(i = 0; i<3; i++) {
|
||||
float m = M[i][i];
|
||||
if( m < r )
|
||||
continue;
|
||||
m = r;
|
||||
p = &perm[i];
|
||||
}
|
||||
|
||||
r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] );
|
||||
|
||||
if(r < 1e-6) {
|
||||
q[0] = 1.f;
|
||||
q[1] = q[2] = q[3] = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
q[0] = r/2.f;
|
||||
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r);
|
||||
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r);
|
||||
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r);
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+4
-3
@@ -22,8 +22,9 @@ freely, subject to the following restrictions:
|
||||
*/
|
||||
|
||||
/* 2013-01-06 Camilla Berglund <elmindreda@elmindreda.org>
|
||||
*
|
||||
*
|
||||
* Added casts from time_t to DWORD to avoid warnings on VC++.
|
||||
* Fixed time retrieval on POSIX systems.
|
||||
*/
|
||||
|
||||
#include "tinycthread.h"
|
||||
@@ -294,7 +295,7 @@ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
struct timespec now;
|
||||
if (clock_gettime(TIME_UTC, &now) == 0)
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) == 0)
|
||||
{
|
||||
DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 +
|
||||
(ts->tv_nsec - now.tv_nsec + 500000) / 1000000);
|
||||
@@ -471,7 +472,7 @@ int thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
#endif
|
||||
|
||||
/* Get the current time */
|
||||
if (clock_gettime(TIME_UTC, &now) != 0)
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) != 0)
|
||||
return -2; // FIXME: Some specific error code?
|
||||
|
||||
#if defined(_TTHREAD_WIN32_)
|
||||
|
||||
+5
-4
@@ -96,8 +96,8 @@ to that header.
|
||||
|
||||
`GLFW_INCLUDE_GLU` makes the header include the GLU header in addition to the
|
||||
header selected above. This should only be used with the standard OpenGL header
|
||||
and only for legacy code. GLU has been deprecated and should not be used in new
|
||||
code.
|
||||
and only for compatibility with legacy code. GLU has been deprecated and should
|
||||
not be used in new code.
|
||||
|
||||
@note GLFW does not provide any of the API headers mentioned above. They must
|
||||
be provided by your development environment or your OpenGL or OpenGL ES SDK.
|
||||
@@ -254,7 +254,7 @@ You can also use the `glfw3.pc` file without installing it first, by using the
|
||||
env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3`
|
||||
@endcode
|
||||
|
||||
The dependencies do not include GLU, as GLFW does not need it. On OS X, GLU is
|
||||
The dependencies do not include GLU, as GLFW does not use it. On OS X, GLU is
|
||||
built into the OpenGL framework, so if you need GLU you don't need to do
|
||||
anything extra. If you need GLU and are using Linux or BSD, you should add the
|
||||
`glu` pkg-config module.
|
||||
@@ -263,7 +263,8 @@ anything extra. If you need GLU and are using Linux or BSD, you should add the
|
||||
cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --libs glfw3 glu`
|
||||
@endcode
|
||||
|
||||
If you are using the static version of the GLFW library, make sure you don't link statically against GLU.
|
||||
If you are using the static version of the GLFW library, make sure you don't
|
||||
link statically against GLU.
|
||||
|
||||
@code{.sh}
|
||||
cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --static --libs glfw3` `pkg-config --libs glu`
|
||||
|
||||
@@ -117,6 +117,11 @@ whether a context is flushed when it is released (made non-current). Where this
|
||||
extension is unavailable, the `GLFW_CONTEXT_RELEASE_BEHAVIOR` hint will have no
|
||||
effect and the context will always be flushed when released.
|
||||
|
||||
GLFW uses the `GLX_ARB_framebuffer_sRGB` and `GLX_EXT_framebuffer_sRGB`
|
||||
extensions to provide support for sRGB framebuffers. Where both of these
|
||||
extensions are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect.
|
||||
|
||||
|
||||
@section compat_wgl WGL extensions
|
||||
|
||||
The WGL API is used to create OpenGL contexts on Microsoft Windows and other
|
||||
@@ -154,6 +159,11 @@ whether a context is flushed when it is released (made non-current). Where this
|
||||
extension is unavailable, the `GLFW_CONTEXT_RELEASE_BEHAVIOR` hint will have no
|
||||
effect and the context will always be flushed when released.
|
||||
|
||||
GLFW uses the `WGL_ARB_framebuffer_sRGB` and `WGL_EXT_framebuffer_sRGB`
|
||||
extensions to provide support for sRGB framebuffers. Where both of these
|
||||
extension are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect.
|
||||
|
||||
|
||||
@section compat_osx OpenGL 3.2 and later on OS X
|
||||
|
||||
Support for OpenGL 3.2 and above was introduced with OS X 10.7 and even then
|
||||
|
||||
+22
-33
@@ -17,8 +17,9 @@ Homebrew, you can simply install its CMake package. If not, you can download
|
||||
installers for Windows and OS X from the [CMake website](http://www.cmake.org/).
|
||||
|
||||
@note CMake only generates project files or makefiles. It does not compile the
|
||||
actual GLFW library. To compile GLFW, first generate these files and then use
|
||||
them in your chosen development environment to compile the actual GLFW library.
|
||||
actual GLFW library. To compile GLFW, first generate these files for your
|
||||
chosen development environment and then use them to compile the actual GLFW
|
||||
library.
|
||||
|
||||
|
||||
@subsection compile_deps Dependencies
|
||||
@@ -89,11 +90,10 @@ Once you have Xcode installed, move on to @ref compile_generate.
|
||||
To compile GLFW for X11, you need to have the X11 and OpenGL header packages
|
||||
installed, as well as the basic development tools like GCC and make. For
|
||||
example, on Ubuntu and other distributions based on Debian GNU/Linux, you need
|
||||
to install the `xorg-dev` and `libglu1-mesa-dev` packages. The former pulls in
|
||||
all X.org header packages and the latter pulls in the Mesa OpenGL and GLU
|
||||
packages. GLFW itself doesn't need or use GLU, but some of the examples do.
|
||||
Note that using header files and libraries from Mesa during compilation
|
||||
_will not_ tie your binaries to the Mesa implementation of OpenGL.
|
||||
to install the `xorg-dev` and `libgl1-mesa-dev` packages. The former pulls in
|
||||
all X.org header packages and the latter pulls in the Mesa OpenGL development
|
||||
packages. Note that using header files and libraries from Mesa during
|
||||
compilation _will not_ tie your binaries to the Mesa implementation of OpenGL.
|
||||
|
||||
Once you have installed the necessary packages, move on to @ref
|
||||
compile_generate.
|
||||
@@ -127,15 +127,14 @@ cd <glfw-root-dir>
|
||||
cmake .
|
||||
@endcode
|
||||
|
||||
To make an out-of-tree build, make another directory, enter it and run CMake
|
||||
with the (relative or absolute) path to the root of the source tree as an
|
||||
argument.
|
||||
To make an out-of-tree build, make a directory outside of the source tree, enter
|
||||
it and run CMake with the (relative or absolute) path to the root of the source
|
||||
tree as an argument.
|
||||
|
||||
@code{.sh}
|
||||
cd <glfw-root-dir>
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
mkdir glfw-build
|
||||
cd glfw-build
|
||||
cmake <glfw-root-dir>
|
||||
@endcode
|
||||
|
||||
Once you have generated the project files or makefiles for your chosen
|
||||
@@ -222,16 +221,11 @@ DLL version of the Visual C++ library is used. It is recommended to set this to
|
||||
`ON`, as this keeps the executable smaller and benefits from security and bug
|
||||
fix updates of the Visual C++ runtime.
|
||||
|
||||
`GLFW_USE_DWM_SWAP_INTERVAL` determines whether the swap interval is set even
|
||||
when DWM compositing is enabled. If this is `ON`, the swap interval is set even
|
||||
if DWM is enabled. It is recommended to set this to `OFF`, as doing otherwise
|
||||
can lead to severe jitter.
|
||||
|
||||
`GLFW_USE_OPTIMUS_HPG` determines whether to export the `NvOptimusEnablement`
|
||||
symbol, which forces the use of the high-performance GPU on Nvidia Optimus
|
||||
systems. This symbol needs to be exported by the EXE to be detected by the
|
||||
driver, so the override will not work if GLFW is built as a DLL. See _Enabling
|
||||
High Performance Graphics Rendering on Optimus Systems_ for more details.
|
||||
`GLFW_USE_HYBRID_HPG` determines whether to export the `NvOptimusEnablement` and
|
||||
`AmdPowerXpressRequestHighPerformance` symbols, which force the use of the
|
||||
high-performance GPU on Nvidia Optimus and AMD PowerXpress systems. These symbols
|
||||
need to be exported by the EXE to be detected by the driver, so the override
|
||||
will not work if GLFW is built as a DLL.
|
||||
|
||||
|
||||
@subsubsection compile_options_egl EGL specific CMake options
|
||||
@@ -294,18 +288,13 @@ libraries.
|
||||
If you are building GLFW as a shared library / dynamic library / DLL then you
|
||||
must also define `_GLFW_BUILD_DLL`. Otherwise, you may not define it.
|
||||
|
||||
If you are using the X11 window creation API then you _must_ also select an entry
|
||||
point retrieval mechanism.
|
||||
|
||||
- `_GLFW_HAS_GLXGETPROCADDRESS` to use `glXGetProcAddress` (recommended)
|
||||
- `_GLFW_HAS_GLXGETPROCADDRESSARB` to use `glXGetProcAddressARB` (legacy)
|
||||
- `_GLFW_HAS_GLXGETPROCADDRESSEXT` to use `glXGetProcAddressEXT` (legacy)
|
||||
- `_GLFW_HAS_DLOPEN` to do manual retrieval with `dlopen` (fallback)
|
||||
|
||||
In addition, support for the following X11 extensions can be enabled:
|
||||
If you are using the X11 window creation API, support for the following X11
|
||||
extensions can be enabled:
|
||||
|
||||
- `_GLFW_HAS_XINPUT` to use XInput2 for high-resolution cursor motion
|
||||
(recommended)
|
||||
- `_GLFW_HAS_XF86VM` to use Xxf86vm as a fallback when RandR gamma is broken
|
||||
(recommended)
|
||||
|
||||
If you are using the Cocoa window creation API, the following options are
|
||||
available:
|
||||
|
||||
+3
-6
@@ -307,12 +307,9 @@ void load_extensions(void)
|
||||
{
|
||||
if (glfwExtensionSupported("GL_ARB_debug_output"))
|
||||
{
|
||||
pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARBPROC) glfwGetProcAddress("glGetDebugMessageLogARB");
|
||||
if (pfnGetDebugMessageLog)
|
||||
{
|
||||
// Both the extension name and the function pointer are present
|
||||
has_ARB_debug_output = 1;
|
||||
}
|
||||
pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARBPROC)
|
||||
glfwGetProcAddress("glGetDebugMessageLogARB");
|
||||
has_ARB_debug_output = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-11
@@ -104,15 +104,12 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
|
||||
@endcode
|
||||
|
||||
The action is one of `GLFW_PRESS`, `GLFW_REPEAT` or `GLFW_RELEASE`. The key
|
||||
will be `GLFW_KEY_UNKNOWN` if GLFW lacks a key token for it. These keys still
|
||||
have unique, if platform-specific scancodes.
|
||||
will be `GLFW_KEY_UNKNOWN` if GLFW lacks a key token for it, for example
|
||||
_E-mail_ and _Play_ keys.
|
||||
|
||||
The scancode is unique for every key but is platform-specific, so a scancode
|
||||
will map to different keys on different platforms.
|
||||
|
||||
The key will be `GLFW_KEY_UNKNOWN` for special keys like _E-mail_ or _Play_ that
|
||||
don't have a key token. Those keys will still have unique, if platform-specific
|
||||
scancodes.
|
||||
The scancode is unique for every key, regardless of whether it has a key token.
|
||||
Scancodes are platform-specific but consistent over time, so keys will have
|
||||
different scancodes depending on the platform but they are safe to save to disk.
|
||||
|
||||
Key states for [named keys](@ref keys) are also saved in per-window state arrays
|
||||
that can be polled with @ref glfwGetKey.
|
||||
@@ -299,8 +296,9 @@ GLFWcursor* cursor = glfwCreateCursor(&image, 0, 0);
|
||||
If cursor creation fails, `NULL` will be returned, so it is necessary to check
|
||||
the return value.
|
||||
|
||||
The image data is 32-bit RGBA, i.e. eight bits per channel. The pixels are
|
||||
arranged canonically as sequential rows, starting from the top-left corner.
|
||||
The image data is 32-bit, little-endian, non-premultiplied RGBA, i.e. eight bits
|
||||
per channel. The pixels are arranged canonically as sequential rows, starting
|
||||
from the top-left corner.
|
||||
|
||||
|
||||
@subsubsection cursor_standard Standard cursor creation
|
||||
@@ -546,9 +544,14 @@ converted to one, you can retrieve it with @ref glfwGetClipboardString. See the
|
||||
reference documentation for the lifetime of the returned string.
|
||||
|
||||
@code
|
||||
const char* clipboard = glfwGetClipboardString(window);
|
||||
const char* text = glfwGetClipboardString(window);
|
||||
if (text)
|
||||
insert_text(text);
|
||||
@endcode
|
||||
|
||||
If the clipboard is empty or if its contents could not be converted, `NULL` is
|
||||
returned.
|
||||
|
||||
The contents of the system clipboard can be set to a UTF-8 encoded string with
|
||||
@ref glfwSetClipboardString.
|
||||
|
||||
|
||||
+3
-6
@@ -210,12 +210,9 @@ including functions that may called before initialization.
|
||||
The reference documentation for every GLFW function states whether it is limited
|
||||
to the main thread.
|
||||
|
||||
The following categories of functions are and will remain limited to the main
|
||||
thread due to the limitations of one or several platforms:
|
||||
|
||||
- Initialization and termination
|
||||
- Event processing
|
||||
- Creation and destruction of window, context and cursor objects
|
||||
Initialization and termination, event processing and the creation and
|
||||
destruction of windows, contexts and cursors are all limited to the main thread
|
||||
due to limitations of one or several platforms.
|
||||
|
||||
Because event processing must be performed on the main thread, all callbacks
|
||||
except for the error callback will only be called on that thread. The error
|
||||
|
||||
+1
-1
@@ -429,7 +429,7 @@ invalidating any window handles you may still have.
|
||||
|
||||
GLFW 3 does not by default include the GLU header and GLU itself has been
|
||||
deprecated by [Khronos](https://en.wikipedia.org/wiki/Khronos_Group). __New
|
||||
projects should avoid using GLU__, but if you need to compile legacy code that
|
||||
projects should not use GLU__, but if you need it for legacy code that
|
||||
has been moved to GLFW 3, you can request that the GLFW header includes it by
|
||||
defining `GLFW_INCLUDE_GLU` before the inclusion of the GLFW header.
|
||||
|
||||
|
||||
+3
-2
@@ -47,8 +47,9 @@ In other words:
|
||||
GLFW one and it will detect this
|
||||
|
||||
Starting with version 3.0, the GLU header `glu.h` is no longer included by
|
||||
default. If you wish to include it, define `GLFW_INCLUDE_GLU` before the
|
||||
inclusion of the GLFW header.
|
||||
default. GLU is deprecated and should not be used in new code. If you need to
|
||||
include it for legacy code, define `GLFW_INCLUDE_GLU` before the inclusion of
|
||||
the GLFW header.
|
||||
|
||||
@code
|
||||
#define GLFW_INCLUDE_GLU
|
||||
|
||||
+48
-19
@@ -134,9 +134,7 @@ you wish to have the specified attributes.
|
||||
Some window hints are hard constraints. These must match the available
|
||||
capabilities _exactly_ for window and context creation to succeed. Hints
|
||||
that are not hard constraints are matched as closely as possible, but the
|
||||
resulting window and context may differ from what these hints requested. To
|
||||
find out the actual attributes of the created window and context, use the
|
||||
@ref glfwGetWindowAttrib function.
|
||||
resulting context and framebuffer may differ from what these hints requested.
|
||||
|
||||
The following hints are always hard constraints:
|
||||
- `GLFW_STEREO`
|
||||
@@ -151,30 +149,30 @@ context, but are ignored when requesting an OpenGL ES context:
|
||||
|
||||
@subsubsection window_hints_wnd Window related hints
|
||||
|
||||
`GLFW_RESIZABLE` specifies whether the (windowed mode) window will be resizable
|
||||
`GLFW_RESIZABLE` specifies whether the windowed mode window will be resizable
|
||||
_by the user_. The window will still be resizable using the @ref
|
||||
glfwSetWindowSize function. This hint is ignored for full screen windows.
|
||||
|
||||
`GLFW_VISIBLE` specifies whether the (windowed mode) window will be initially
|
||||
`GLFW_VISIBLE` specifies whether the windowed mode window will be initially
|
||||
visible. This hint is ignored for full screen windows.
|
||||
|
||||
`GLFW_DECORATED` specifies whether the (windowed mode) window will have window
|
||||
decorations such as a border, a close widget, etc. This hint is ignored for
|
||||
full screen windows. Note that even though a window may lack a close widget, it
|
||||
is usually still possible for the user to generate close events.
|
||||
`GLFW_DECORATED` specifies whether the windowed mode window will have window
|
||||
decorations such as a border, a close widget, etc. An undecorated window may
|
||||
still allow the user to generate close events on some platforms. This hint is
|
||||
ignored for full screen windows.
|
||||
|
||||
`GLFW_FOCUSED` specifies whether the (windowed mode) window will be given input
|
||||
`GLFW_FOCUSED` specifies whether the windowed mode window will be given input
|
||||
focus when created. This hint is ignored for full screen and initially hidden
|
||||
windows.
|
||||
|
||||
`GLFW_AUTO_ICONIFY` specifies whether the (full screen) window will
|
||||
`GLFW_AUTO_ICONIFY` specifies whether the full screen window will
|
||||
automatically iconify and restore the previous video mode on input focus loss.
|
||||
This hint is ignored for windowed mode windows.
|
||||
|
||||
`GLFW_FLOATING` specifies whether the window will be floating above other
|
||||
regular windows, also called topmost or always-on-top. This is intended
|
||||
primarily for debugging purposes and cannot be used to implement proper full
|
||||
screen windows. This hint is ignored for full screen windows.
|
||||
`GLFW_FLOATING` specifies whether the windowed mode window will be floating
|
||||
above other regular windows, also called topmost or always-on-top. This is
|
||||
intended primarily for debugging purposes and cannot be used to implement proper
|
||||
full screen windows. This hint is ignored for full screen windows.
|
||||
|
||||
|
||||
@subsubsection window_hints_fb Framebuffer related hints
|
||||
@@ -208,6 +206,8 @@ Zero disables multisampling. `GLFW_DONT_CARE` means the application has no
|
||||
preference.
|
||||
|
||||
`GLFW_SRGB_CAPABLE` specifies whether the framebuffer should be sRGB capable.
|
||||
If supported, the created context will provide `GL_ARB_framebuffer_sRGB` or
|
||||
`GL_EXT_framebuffer_sRGB`.
|
||||
|
||||
`GLFW_DOUBLEBUFFER` specifies whether the framebuffer should be double buffered.
|
||||
You nearly always want to use double buffering. This is a hard constraint.
|
||||
@@ -538,7 +538,7 @@ As long as your source file is encoded as UTF-8, you can use any Unicode
|
||||
characters directly in the source.
|
||||
|
||||
@code
|
||||
glfwSetWindowTitle(window, "おもひでぽろぽろ");
|
||||
glfwSetWindowTitle(window, "プラネテス");
|
||||
@endcode
|
||||
|
||||
|
||||
@@ -764,6 +764,37 @@ This is `GLFW_LOSE_CONTEXT_ON_RESET` or `GLFW_NO_RESET_NOTIFICATION` if the
|
||||
window's context supports robustness, or `GLFW_NO_ROBUSTNESS` otherwise.
|
||||
|
||||
|
||||
@subsubsection window_attribs_fb Framebuffer related attributes
|
||||
|
||||
The attributes of the default framebuffer (i.e. the framebuffer attached to the
|
||||
window) are not provided by this function but can be queried with both OpenGL
|
||||
and OpenGL ES.
|
||||
|
||||
If you are using version 3.0 or later of OpenGL or OpenGL ES, the
|
||||
`glGetFramebufferAttachmentParameteriv` function can be used to retrieve the
|
||||
number of bits for the red, green, blue, alpha, depth and stencil buffer
|
||||
channels. Otherwise, the `glGetIntegerv` function can be used.
|
||||
|
||||
The number of MSAA samples are always retrieved with `glGetIntegerv`. For
|
||||
contexts supporting framebuffer objects, the number of samples of the currently
|
||||
bound framebuffer is returned.
|
||||
|
||||
Attribute | glGetIntegerv | glGetFramebufferAttachmentParameteriv
|
||||
------------ | ----------------- | -------------------------------------
|
||||
Red bits | `GL_RED_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE`
|
||||
Green bits | `GL_GREEN_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE`
|
||||
Blue bits | `GL_BLUE_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE`
|
||||
Alpha bits | `GL_ALPHA_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE`
|
||||
Depth bits | `GL_DEPTH_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE`
|
||||
Stencil bits | `GL_STENCIL_BITS` | `GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE`
|
||||
MSAA samples | `GL_SAMPLES` | _Not provided by this function_
|
||||
|
||||
When calling `glGetFramebufferAttachmentParameteriv`, the red, green, blue and
|
||||
alpha sizes can be queried from the `GL_BACK_LEFT`, while the depth and stencil
|
||||
sizes can be queried from the `GL_DEPTH` and `GL_STENCIL` attachments,
|
||||
respectively.
|
||||
|
||||
|
||||
@section buffer_swap Buffer swapping
|
||||
|
||||
GLFW windows are by default double buffered. That means that you have two
|
||||
@@ -796,8 +827,6 @@ interval of one lets you avoid tearing.
|
||||
|
||||
Note that this may not work on all machines, as some drivers have
|
||||
user-controlled settings that override any swap interval the application
|
||||
requests. It is also by default disabled on Windows Vista and later when using
|
||||
DWM (Aero), as using it there sometimes leads to severe jitter. You can
|
||||
forcibly enable it for machines using DWM using @ref compile_options_win32.
|
||||
requests.
|
||||
|
||||
*/
|
||||
|
||||
+21
-44
@@ -1,5 +1,5 @@
|
||||
|
||||
link_libraries(glfw "${OPENGL_glu_LIBRARY}")
|
||||
link_libraries(glfw)
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DGLFW_DLL)
|
||||
@@ -22,61 +22,38 @@ set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h"
|
||||
set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h"
|
||||
"${GLFW_SOURCE_DIR}/deps/tinycthread.c")
|
||||
|
||||
if (APPLE)
|
||||
# Set fancy names for bundles
|
||||
add_executable(Boing MACOSX_BUNDLE boing.c)
|
||||
add_executable(Gears MACOSX_BUNDLE gears.c)
|
||||
add_executable(Heightmap MACOSX_BUNDLE heightmap.c ${GLAD})
|
||||
add_executable(Particles MACOSX_BUNDLE particles.c ${TINYCTHREAD})
|
||||
add_executable(Simple MACOSX_BUNDLE simple.c)
|
||||
add_executable(SplitView MACOSX_BUNDLE splitview.c)
|
||||
add_executable(Wave MACOSX_BUNDLE wave.c)
|
||||
add_executable(boing WIN32 MACOSX_BUNDLE boing.c)
|
||||
add_executable(gears WIN32 MACOSX_BUNDLE gears.c)
|
||||
add_executable(heightmap WIN32 MACOSX_BUNDLE heightmap.c ${GLAD})
|
||||
add_executable(particles WIN32 MACOSX_BUNDLE particles.c ${TINYCTHREAD} ${GETOPT})
|
||||
add_executable(simple WIN32 MACOSX_BUNDLE simple.c)
|
||||
add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c)
|
||||
add_executable(wave WIN32 MACOSX_BUNDLE wave.c)
|
||||
|
||||
set_target_properties(Boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing")
|
||||
set_target_properties(Gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears")
|
||||
set_target_properties(Heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap")
|
||||
set_target_properties(Particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles")
|
||||
set_target_properties(Simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple")
|
||||
set_target_properties(SplitView PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View")
|
||||
set_target_properties(Wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave")
|
||||
target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
|
||||
set_target_properties(Boing Gears Heightmap Particles Simple SplitView Wave PROPERTIES
|
||||
FOLDER "GLFW3/Examples"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/AppleInfo.plist")
|
||||
set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave)
|
||||
|
||||
else()
|
||||
# Set boring names for executables
|
||||
add_executable(boing WIN32 boing.c)
|
||||
add_executable(gears WIN32 gears.c)
|
||||
add_executable(heightmap WIN32 heightmap.c ${GLAD})
|
||||
add_executable(particles WIN32 particles.c ${TINYCTHREAD} ${GETOPT})
|
||||
add_executable(simple WIN32 simple.c)
|
||||
add_executable(splitview WIN32 splitview.c)
|
||||
add_executable(wave WIN32 wave.c)
|
||||
|
||||
set_target_properties(boing gears heightmap particles simple splitview wave PROPERTIES
|
||||
FOLDER "GLFW3/Examples")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries(Particles "${CMAKE_THREAD_LIBS_INIT}")
|
||||
elseif (UNIX)
|
||||
target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
endif()
|
||||
set_target_properties(${WINDOWS_BINARIES} PROPERTIES FOLDER "GLFW3/Examples")
|
||||
|
||||
if (MSVC)
|
||||
set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave)
|
||||
|
||||
# Tell MSVC to use main instead of WinMain for Windows subsystem executables
|
||||
set_target_properties(${WINDOWS_BINARIES} PROPERTIES
|
||||
LINK_FLAGS "/ENTRY:mainCRTStartup")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(BUNDLE_BINARIES Boing Gears Heightmap Particles Simple SplitView Wave)
|
||||
set_target_properties(boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing")
|
||||
set_target_properties(gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears")
|
||||
set_target_properties(heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap")
|
||||
set_target_properties(particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles")
|
||||
set_target_properties(simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple")
|
||||
set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View")
|
||||
set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave")
|
||||
|
||||
set_target_properties(${BUNDLE_BINARIES} PROPERTIES
|
||||
set_target_properties(${WINDOWS_BINARIES} PROPERTIES
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL})
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL}
|
||||
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in")
|
||||
endif()
|
||||
|
||||
|
||||
+21
-39
@@ -27,13 +27,19 @@
|
||||
* a hidden computer or VCR.
|
||||
*****************************************************************************/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <linmath.h>
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Various declarations and macros
|
||||
@@ -102,11 +108,6 @@ double dt;
|
||||
#define RAND_MAX 4095
|
||||
#endif
|
||||
|
||||
/* PI */
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Truncate a degree.
|
||||
@@ -167,28 +168,6 @@ void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n )
|
||||
n->z = u1 * v2 - v1 * u2;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Calculate the angle to be passed to gluPerspective() so that a scene
|
||||
* is visible. This function originates from the OpenGL Red Book.
|
||||
*
|
||||
* Parms : size
|
||||
* The size of the segment when the angle is intersected at "dist"
|
||||
* (ie at the outermost edge of the angle of vision).
|
||||
*
|
||||
* dist
|
||||
* Distance from viewpoint to scene.
|
||||
*****************************************************************************/
|
||||
GLfloat PerspectiveAngle( GLfloat size,
|
||||
GLfloat dist )
|
||||
{
|
||||
GLfloat radTheta, degTheta;
|
||||
|
||||
radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist );
|
||||
degTheta = (180.f * radTheta) / (GLfloat) M_PI;
|
||||
return degTheta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define BOING_DEBUG 0
|
||||
|
||||
@@ -233,22 +212,25 @@ void display(void)
|
||||
*****************************************************************************/
|
||||
void reshape( GLFWwindow* window, int w, int h )
|
||||
{
|
||||
mat4x4 projection, view;
|
||||
|
||||
glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
|
||||
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity();
|
||||
|
||||
gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ),
|
||||
(GLfloat)w / (GLfloat)h,
|
||||
1.0,
|
||||
VIEW_SCENE_DIST );
|
||||
mat4x4_perspective( projection,
|
||||
2.f * (float) atan2( RADIUS, 200.f ),
|
||||
(float)w / (float)h,
|
||||
1.f, VIEW_SCENE_DIST );
|
||||
glLoadMatrixf((const GLfloat*) projection);
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */
|
||||
0.0, 0.0, 0.0, /* center of vision */
|
||||
0.0, -1.0, 0.0 ); /* up vector */
|
||||
{
|
||||
vec3 eye = { 0.f, 0.f, VIEW_SCENE_DIST };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, -1.f, 0.f };
|
||||
mat4x4_look_at( view, eye, center, up );
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
}
|
||||
|
||||
void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods )
|
||||
|
||||
+6
-24
@@ -21,6 +21,10 @@
|
||||
* - Enabled vsync
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@@ -28,14 +32,6 @@
|
||||
#include <string.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592654
|
||||
#endif
|
||||
|
||||
/* If non-zero, the program exits after that many seconds
|
||||
*/
|
||||
static int autoexit = 0;
|
||||
|
||||
/**
|
||||
|
||||
Draw a gear wheel. You'll probably want to call this function when
|
||||
@@ -264,13 +260,12 @@ void reshape( GLFWwindow* window, int width, int height )
|
||||
|
||||
|
||||
/* program & OpenGL initialization */
|
||||
static void init(int argc, char *argv[])
|
||||
static void init(void)
|
||||
{
|
||||
static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f};
|
||||
static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f};
|
||||
static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f};
|
||||
static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f};
|
||||
GLint i;
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||
glEnable(GL_CULL_FACE);
|
||||
@@ -298,19 +293,6 @@ static void init(int argc, char *argv[])
|
||||
glEndList();
|
||||
|
||||
glEnable(GL_NORMALIZE);
|
||||
|
||||
for ( i=1; i<argc; i++ ) {
|
||||
if (strcmp(argv[i], "-info")==0) {
|
||||
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
|
||||
printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
|
||||
printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
|
||||
printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
|
||||
}
|
||||
else if ( strcmp(argv[i], "-exit")==0) {
|
||||
autoexit = 30;
|
||||
printf("Auto Exit after %i seconds.\n", autoexit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +329,7 @@ int main(int argc, char *argv[])
|
||||
reshape(window, width, height);
|
||||
|
||||
// Parse command-line options
|
||||
init(argc, argv);
|
||||
init();
|
||||
|
||||
// Main loop
|
||||
while( !glfwWindowShouldClose(window) )
|
||||
|
||||
+15
-10
@@ -24,6 +24,11 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -32,8 +37,8 @@
|
||||
|
||||
#include <tinycthread.h>
|
||||
#include <getopt.h>
|
||||
#include <linmath.h>
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
// Define tokens for GL_EXT_separate_specular_color if not already defined
|
||||
@@ -43,11 +48,6 @@
|
||||
#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
|
||||
#endif // GL_EXT_separate_specular_color
|
||||
|
||||
// Some <math.h>'s do not define M_PI
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592654
|
||||
#endif
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Type definitions
|
||||
@@ -785,17 +785,22 @@ static void draw_scene(GLFWwindow* window, double t)
|
||||
double xpos, ypos, zpos, angle_x, angle_y, angle_z;
|
||||
static double t_old = 0.0;
|
||||
float dt;
|
||||
mat4x4 projection;
|
||||
|
||||
// Calculate frame-to-frame delta time
|
||||
dt = (float) (t - t_old);
|
||||
t_old = t;
|
||||
|
||||
mat4x4_perspective(projection,
|
||||
65.f * (float) M_PI / 180.f,
|
||||
aspect_ratio,
|
||||
1.0, 60.0);
|
||||
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(65.0, aspect_ratio, 1.0, 60.0);
|
||||
glLoadMatrixf((const GLfloat*) projection);
|
||||
|
||||
// Setup camera
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
@@ -986,11 +991,11 @@ int main(int argc, char** argv)
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
glfwSetWindowSizeCallback(window, resize_callback);
|
||||
glfwSetFramebufferSizeCallback(window, resize_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
// Set initial aspect ratio
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
resize_callback(window, width, height);
|
||||
|
||||
// Upload particle texture
|
||||
|
||||
+72
-29
@@ -10,16 +10,19 @@
|
||||
// because I am not a friend of orthogonal projections)
|
||||
//========================================================================
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#define GLFW_INCLUDE_GLEXT
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#include <linmath.h>
|
||||
|
||||
|
||||
//========================================================================
|
||||
@@ -149,6 +152,7 @@ static void drawGrid(float scale, int steps)
|
||||
{
|
||||
int i;
|
||||
float x, y;
|
||||
mat4x4 view;
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
@@ -157,10 +161,13 @@ static void drawGrid(float scale, int steps)
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Setup modelview matrix (flat XY view)
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0, 0.0, 1.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0);
|
||||
{
|
||||
vec3 eye = { 0.f, 0.f, 1.f };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, 1.f, 0.f };
|
||||
mat4x4_look_at(view, eye, center, up);
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
|
||||
// We don't want to update the Z-buffer
|
||||
glDepthMask(GL_FALSE);
|
||||
@@ -209,13 +216,14 @@ static void drawAllViews(void)
|
||||
const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f};
|
||||
double aspect;
|
||||
float aspect;
|
||||
mat4x4 view, projection;
|
||||
|
||||
// Calculate aspect of window
|
||||
if (height > 0)
|
||||
aspect = (double) width / (double) height;
|
||||
aspect = (float) width / (float) height;
|
||||
else
|
||||
aspect = 1.0;
|
||||
aspect = 1.f;
|
||||
|
||||
// Clear screen
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
@@ -247,10 +255,13 @@ static void drawAllViews(void)
|
||||
glViewport(0, height / 2, width / 2, height / 2);
|
||||
glScissor(0, height / 2, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0f, 10.0f, 1e-3f, // Eye-position (above)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
{
|
||||
vec3 eye = { 0.f, 10.f, 1e-3f };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, 1.f, 0.f };
|
||||
mat4x4_look_at( view, eye, center, up );
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
@@ -258,10 +269,13 @@ static void drawAllViews(void)
|
||||
glViewport(0, 0, width / 2, height / 2);
|
||||
glScissor(0, 0, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(0.0f, 0.0f, 10.0f, // Eye-position (in front of)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
{
|
||||
vec3 eye = { 0.f, 0.f, 10.f };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, 1.f, 0.f };
|
||||
mat4x4_look_at( view, eye, center, up );
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
@@ -269,10 +283,13 @@ static void drawAllViews(void)
|
||||
glViewport(width / 2, 0, width / 2, height / 2);
|
||||
glScissor(width / 2, 0, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(10.0f, 0.0f, 0.0f, // Eye-position (to the right)
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
{
|
||||
vec3 eye = { 10.f, 0.f, 0.f };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, 1.f, 0.f };
|
||||
mat4x4_look_at( view, eye, center, up );
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
drawGrid(0.5, 12);
|
||||
drawScene();
|
||||
|
||||
@@ -292,17 +309,23 @@ static void drawAllViews(void)
|
||||
|
||||
// Setup perspective projection matrix
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(65.0f, aspect, 1.0f, 50.0f);
|
||||
mat4x4_perspective(projection,
|
||||
65.f * (float) M_PI / 180.f,
|
||||
aspect,
|
||||
1.f, 50.f);
|
||||
glLoadMatrixf((const GLfloat*) projection);
|
||||
|
||||
// Upper right view (PERSPECTIVE VIEW)
|
||||
glViewport(width / 2, height / 2, width / 2, height / 2);
|
||||
glScissor(width / 2, height / 2, width / 2, height / 2);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
gluLookAt(3.0f, 1.5f, 3.0f, // Eye-position
|
||||
0.0f, 0.0f, 0.0f, // View-point
|
||||
0.0f, 1.0f, 0.0f); // Up-vector
|
||||
{
|
||||
vec3 eye = { 3.f, 1.5f, 3.f };
|
||||
vec3 center = { 0.f, 0.f, 0.f };
|
||||
vec3 up = { 0.f, 1.f, 0.f };
|
||||
mat4x4_look_at( view, eye, center, up );
|
||||
}
|
||||
glLoadMatrixf((const GLfloat*) view);
|
||||
|
||||
// Configure and enable light source 1
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, light_position);
|
||||
@@ -383,6 +406,17 @@ static void windowRefreshFun(GLFWwindow* window)
|
||||
|
||||
static void cursorPosFun(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
int wnd_width, wnd_height, fb_width, fb_height;
|
||||
double scale;
|
||||
|
||||
glfwGetWindowSize(window, &wnd_width, &wnd_height);
|
||||
glfwGetFramebufferSize(window, &fb_width, &fb_height);
|
||||
|
||||
scale = (double) fb_width / (double) wnd_width;
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
|
||||
// Depending on which view was selected, rotate around different axes
|
||||
switch (active_view)
|
||||
{
|
||||
@@ -458,6 +492,8 @@ int main(void)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_SAMPLES, 4);
|
||||
|
||||
// Open OpenGL window
|
||||
window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL);
|
||||
if (!window)
|
||||
@@ -479,6 +515,13 @@ int main(void)
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
if (glfwExtensionSupported("GL_ARB_multisample") ||
|
||||
glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR) >= 2 ||
|
||||
glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR) >= 3)
|
||||
{
|
||||
glEnable(GL_MULTISAMPLE_ARB);
|
||||
}
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
framebufferSizeFun(window, width, height);
|
||||
|
||||
|
||||
+12
-6
@@ -8,16 +8,18 @@
|
||||
* 2010-10-24: Formatting and cleanup - Camilla Berglund
|
||||
*****************************************************************************/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define GLFW_INCLUDE_GLU
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
#include <linmath.h>
|
||||
|
||||
// Maximum delta T to allow for differential calculations
|
||||
#define MAX_DELTA_T 0.01
|
||||
@@ -362,6 +364,7 @@ void scroll_callback(GLFWwindow* window, double x, double y)
|
||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
float ratio = 1.f;
|
||||
mat4x4 projection;
|
||||
|
||||
if (height > 0)
|
||||
ratio = (float) width / (float) height;
|
||||
@@ -371,8 +374,11 @@ void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
|
||||
// Change to the projection matrix and set our viewing volume
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective(60.0, ratio, 1.0, 1024.0);
|
||||
mat4x4_perspective(projection,
|
||||
60.f * (float) M_PI / 180.f,
|
||||
ratio,
|
||||
1.f, 1024.f);
|
||||
glLoadMatrixf((const GLfloat*) projection);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+46
-28
@@ -211,7 +211,7 @@ extern "C" {
|
||||
* API changes.
|
||||
* @ingroup init
|
||||
*/
|
||||
#define GLFW_VERSION_REVISION 1
|
||||
#define GLFW_VERSION_REVISION 2
|
||||
/*! @} */
|
||||
|
||||
/*! @name Key and button actions
|
||||
@@ -531,7 +531,7 @@ extern "C" {
|
||||
*
|
||||
* @par
|
||||
* Some pre-installed Windows graphics drivers do not support OpenGL. AMD only
|
||||
* supports OpenGL ES via EGL, while Nvidia and Intel only supports it via
|
||||
* supports OpenGL ES via EGL, while Nvidia and Intel only support it via
|
||||
* a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa
|
||||
* EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary
|
||||
* driver.
|
||||
@@ -1067,12 +1067,6 @@ typedef struct GLFWimage
|
||||
* bundle, if present. This can be disabled with a
|
||||
* [compile-time option](@ref compile_options_osx).
|
||||
*
|
||||
* @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to
|
||||
* `"C"` then the environment's locale will be applied to that category. This
|
||||
* is done because character input will not function when `LC_CTYPE` is set to
|
||||
* `"C"`. If another locale was set before this function was called, it will
|
||||
* be left untouched.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
@@ -1212,12 +1206,13 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun);
|
||||
/*! @brief Returns the currently connected monitors.
|
||||
*
|
||||
* This function returns an array of handles for all currently connected
|
||||
* monitors.
|
||||
* monitors. The primary monitor is always first in the returned array. If no
|
||||
* monitors were found, this function returns `NULL`.
|
||||
*
|
||||
* @param[out] count Where to store the number of monitors in the returned
|
||||
* array. This is set to zero if an error occurred.
|
||||
* @return An array of monitor handles, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
* @return An array of monitor handles, or `NULL` if no monitors were found or
|
||||
* if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @par Pointer Lifetime
|
||||
* The returned array is allocated and freed by GLFW. You should not free it
|
||||
@@ -1240,14 +1235,17 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count);
|
||||
/*! @brief Returns the primary monitor.
|
||||
*
|
||||
* This function returns the primary monitor. This is usually the monitor
|
||||
* where elements like the Windows task bar or the OS X menu bar is located.
|
||||
* where elements like the task bar or global menu bar are located.
|
||||
*
|
||||
* @return The primary monitor, or `NULL` if an [error](@ref error_handling)
|
||||
* occurred.
|
||||
* @return The primary monitor, or `NULL` if no monitors were found or if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
* @remarks The primary monitor is always first in the array returned by @ref
|
||||
* glfwGetMonitors.
|
||||
*
|
||||
* @sa @ref monitor_monitors
|
||||
* @sa glfwGetMonitors
|
||||
*
|
||||
@@ -1551,8 +1549,8 @@ GLFWAPI void glfwWindowHint(int target, int hint);
|
||||
* requested, as not all parameters and hints are
|
||||
* [hard constraints](@ref window_hints_hard). This includes the size of the
|
||||
* window, especially for full screen windows. To query the actual attributes
|
||||
* of the created window, framebuffer and context, use queries like @ref
|
||||
* glfwGetWindowAttrib and @ref glfwGetWindowSize.
|
||||
* of the created window, framebuffer and context, see @ref
|
||||
* glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize.
|
||||
*
|
||||
* To create a full screen window, you need to specify the monitor the window
|
||||
* will cover. If no monitor is specified, windowed mode will be used. Unless
|
||||
@@ -1622,13 +1620,20 @@ GLFWAPI void glfwWindowHint(int target, int hint);
|
||||
* `NSHighResolutionCapable` key is enabled in the application bundle's
|
||||
* `Info.plist`. For more information, see
|
||||
* [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html)
|
||||
* in the Mac Developer Library.
|
||||
* in the Mac Developer Library. The GLFW test and example programs use
|
||||
* a custom `Info.plist` template for this, which can be found as
|
||||
* `CMake/MacOSXBundleInfo.plist.in` in the source tree.
|
||||
*
|
||||
* @remarks __X11:__ There is no mechanism for setting the window icon yet.
|
||||
*
|
||||
* @remarks __X11:__ Some window managers will not respect the placement of
|
||||
* initially hidden windows.
|
||||
*
|
||||
* @remarks __X11:__ Due to the asynchronous nature of X11, it may take
|
||||
* a moment for a window to reach its requested state. This means you may not
|
||||
* be able to query the final size, position or other attributes directly after
|
||||
* window creation.
|
||||
*
|
||||
* @par Reentrancy
|
||||
* This function may not be called from a callback.
|
||||
*
|
||||
@@ -1718,6 +1723,9 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value);
|
||||
* @param[in] window The window whose title to change.
|
||||
* @param[in] title The UTF-8 encoded window title.
|
||||
*
|
||||
* @remarks __OS X:__ The window title will not be updated until the next time
|
||||
* you process events.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
@@ -2035,6 +2043,14 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
|
||||
* @return The value of the attribute, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @remarks Framebuffer related hints are not window attributes. See @ref
|
||||
* window_attribs_fb for more information.
|
||||
*
|
||||
* @remarks Zero is a valid value for many window and context related
|
||||
* attributes so you cannot use a return value of zero as an indication of
|
||||
* errors. However, this function should not fail as long as it is passed
|
||||
* valid arguments and the library has been [initialized](@ref intro_init).
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
*
|
||||
@@ -2561,9 +2577,9 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
|
||||
* @param[in] ypos The desired y-coordinate, relative to the top edge of the
|
||||
* client area.
|
||||
*
|
||||
* @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it
|
||||
* may take a moment for the window focus event to arrive. This means you will
|
||||
* not be able to set the cursor position directly after window creation.
|
||||
* @remarks __X11:__ Due to the asynchronous nature of X11, it may take
|
||||
* a moment for the window focus event to arrive. This means you may not be
|
||||
* able to set the cursor position directly after window creation.
|
||||
*
|
||||
* @par Thread Safety
|
||||
* This function may only be called from the main thread.
|
||||
@@ -2583,9 +2599,9 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
|
||||
* glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor.
|
||||
* Any remaining cursors are destroyed by @ref glfwTerminate.
|
||||
*
|
||||
* The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel. They
|
||||
* are arranged canonically as packed sequential rows, starting from the
|
||||
* top-left corner.
|
||||
* The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight
|
||||
* bits per channel. They are arranged canonically as packed sequential rows,
|
||||
* starting from the top-left corner.
|
||||
*
|
||||
* The cursor hotspot is specified in pixels, relative to the upper-left corner
|
||||
* of the cursor image. Like all other coordinate systems in GLFW, the X-axis
|
||||
@@ -3061,7 +3077,9 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
||||
/*! @brief Returns the contents of the clipboard as a string.
|
||||
*
|
||||
* This function returns the contents of the system clipboard, if it contains
|
||||
* or is convertible to a UTF-8 encoded string.
|
||||
* or is convertible to a UTF-8 encoded string. If the clipboard is empty or
|
||||
* if its contents cannot be converted, `NULL` is returned and a @ref
|
||||
* GLFW_FORMAT_UNAVAILABLE error is generated.
|
||||
*
|
||||
* @param[in] window The window that will request the clipboard contents.
|
||||
* @return The contents of the clipboard as a UTF-8 encoded string, or `NULL`
|
||||
@@ -3286,15 +3304,15 @@ GLFWAPI int glfwExtensionSupported(const char* extension);
|
||||
* without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error.
|
||||
*
|
||||
* @param[in] procname The ASCII encoded name of the function.
|
||||
* @return The address of the function, or `NULL` if the function is
|
||||
* unavailable or an [error](@ref error_handling) occurred.
|
||||
* @return The address of the function, or `NULL` if an [error](@ref
|
||||
* error_handling) occurred.
|
||||
*
|
||||
* @remarks The addresses of a given function is not guaranteed to be the same
|
||||
* @remarks The address of a given function is not guaranteed to be the same
|
||||
* between contexts.
|
||||
*
|
||||
* @remarks This function may return a non-`NULL` address despite the
|
||||
* associated version or extension not being available. Always check the
|
||||
* context version or extension string presence first.
|
||||
* context version or extension string first.
|
||||
*
|
||||
* @par Pointer Lifetime
|
||||
* The returned function pointer is valid until the context is destroyed or the
|
||||
|
||||
+1
-3
@@ -249,7 +249,7 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
const char* version = _GLFW_VERSION_NUMBER " Cocoa"
|
||||
return _GLFW_VERSION_NUMBER " Cocoa"
|
||||
#if defined(_GLFW_NSGL)
|
||||
" NSGL"
|
||||
#endif
|
||||
@@ -266,7 +266,5 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
" dynamic"
|
||||
#endif
|
||||
;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
+23
-45
@@ -252,50 +252,29 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
*count = 0;
|
||||
|
||||
CGGetOnlineDisplayList(0, NULL, &displayCount);
|
||||
|
||||
displays = calloc(displayCount, sizeof(CGDirectDisplayID));
|
||||
monitors = calloc(displayCount, sizeof(_GLFWmonitor*));
|
||||
|
||||
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
|
||||
|
||||
NSArray* screens = [NSScreen screens];
|
||||
|
||||
for (i = 0; i < displayCount; i++)
|
||||
{
|
||||
int j;
|
||||
_GLFWmonitor* monitor;
|
||||
|
||||
CGDirectDisplayID screenDisplayID = CGDisplayMirrorsDisplay(displays[i]);
|
||||
if (screenDisplayID == kCGNullDirectDisplay)
|
||||
screenDisplayID = displays[i];
|
||||
if (CGDisplayIsAsleep(displays[i]))
|
||||
continue;
|
||||
|
||||
const CGSize size = CGDisplayScreenSize(displays[i]);
|
||||
char* name = getDisplayName(displays[i]);
|
||||
|
||||
monitors[found] = _glfwAllocMonitor(name, size.width, size.height);
|
||||
monitors[found]->ns.displayID = displays[i];
|
||||
monitor = _glfwAllocMonitor(name, size.width, size.height);
|
||||
monitor->ns.displayID = displays[i];
|
||||
monitor->ns.unitNumber = CGDisplayUnitNumber(displays[i]);
|
||||
|
||||
free(name);
|
||||
|
||||
for (j = 0; j < [screens count]; j++)
|
||||
{
|
||||
NSScreen* screen = [screens objectAtIndex:j];
|
||||
NSDictionary* dictionary = [screen deviceDescription];
|
||||
NSNumber* number = [dictionary objectForKey:@"NSScreenNumber"];
|
||||
|
||||
if ([number unsignedIntegerValue] == screenDisplayID)
|
||||
{
|
||||
monitors[found]->ns.screen = screen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (monitors[found]->ns.screen)
|
||||
found++;
|
||||
else
|
||||
{
|
||||
_glfwFreeMonitor(monitors[found]);
|
||||
monitors[found] = NULL;
|
||||
}
|
||||
found++;
|
||||
monitors[found - 1] = monitor;
|
||||
}
|
||||
|
||||
free(displays);
|
||||
@@ -306,7 +285,9 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
|
||||
GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second)
|
||||
{
|
||||
return first->ns.displayID == second->ns.displayID;
|
||||
// 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)
|
||||
@@ -319,22 +300,22 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
*ypos = (int) bounds.origin.y;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
CFArrayRef modes;
|
||||
CFIndex count, i, j;
|
||||
CFIndex found, i, j;
|
||||
GLFWvidmode* result;
|
||||
CVDisplayLinkRef link;
|
||||
|
||||
*count = 0;
|
||||
|
||||
CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link);
|
||||
|
||||
modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL);
|
||||
count = CFArrayGetCount(modes);
|
||||
found = CFArrayGetCount(modes);
|
||||
result = calloc(found, sizeof(GLFWvidmode));
|
||||
|
||||
result = calloc(count, sizeof(GLFWvidmode));
|
||||
*found = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (i = 0; i < found; i++)
|
||||
{
|
||||
CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
|
||||
if (!modeIsGood(dm))
|
||||
@@ -342,24 +323,21 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link);
|
||||
|
||||
for (j = 0; j < *found; j++)
|
||||
for (j = 0; j < *count; j++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < *found)
|
||||
{
|
||||
// This is a duplicate, so skip it
|
||||
// Skip duplicate modes
|
||||
if (i < *count)
|
||||
continue;
|
||||
}
|
||||
|
||||
result[*found] = mode;
|
||||
(*found)++;
|
||||
(*count)++;
|
||||
result[*count - 1] = mode;
|
||||
}
|
||||
|
||||
CFRelease(modes);
|
||||
|
||||
CVDisplayLinkRelease(link);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -24,9 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _cocoa_platform_h_
|
||||
#define _cocoa_platform_h_
|
||||
|
||||
#ifndef _glfw3_cocoa_platform_h_
|
||||
#define _glfw3_cocoa_platform_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -38,15 +37,14 @@ typedef void* id;
|
||||
#endif
|
||||
|
||||
#include "posix_tls.h"
|
||||
#include "iokit_joystick.h"
|
||||
|
||||
#if defined(_GLFW_NSGL)
|
||||
#include "nsgl_context.h"
|
||||
#else
|
||||
#error "No supported context creation API selected"
|
||||
#error "The Cocoa backend depends on NSGL platform support"
|
||||
#endif
|
||||
|
||||
#include "iokit_joystick.h"
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
||||
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time
|
||||
@@ -59,7 +57,7 @@ typedef void* id;
|
||||
typedef struct _GLFWwindowNS
|
||||
{
|
||||
id object;
|
||||
id delegate;
|
||||
id delegate;
|
||||
id view;
|
||||
unsigned int modifierFlags;
|
||||
|
||||
@@ -92,7 +90,7 @@ typedef struct _GLFWmonitorNS
|
||||
{
|
||||
CGDirectDisplayID displayID;
|
||||
CGDisplayModeRef previousMode;
|
||||
id screen;
|
||||
uint32_t unitNumber;
|
||||
|
||||
} _GLFWmonitorNS;
|
||||
|
||||
@@ -121,4 +119,4 @@ void _glfwInitTimer(void);
|
||||
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
|
||||
|
||||
#endif // _cocoa_platform_h_
|
||||
#endif // _glfw3_cocoa_platform_h_
|
||||
|
||||
+96
-61
@@ -83,13 +83,16 @@ static void updateModeCursor(_GLFWwindow* window)
|
||||
//
|
||||
static GLboolean enterFullscreenMode(_GLFWwindow* window)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
GLboolean status;
|
||||
int xpos, ypos;
|
||||
|
||||
status = _glfwSetVideoMode(window->monitor, &window->videoMode);
|
||||
|
||||
// NOTE: The window is resized despite mode setting failure to make
|
||||
// glfwSetWindowSize more robust
|
||||
[window->ns.object setFrame:[window->monitor->ns.screen frame]
|
||||
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
|
||||
|
||||
[window->ns.object setFrame:NSMakeRect(xpos, ypos, mode.width, mode.height)
|
||||
display:YES];
|
||||
|
||||
return status;
|
||||
@@ -123,6 +126,34 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
// Translates OS X key modifiers into GLFW ones
|
||||
//
|
||||
static int translateFlags(NSUInteger flags)
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
if (flags & NSShiftKeyMask)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (flags & NSControlKeyMask)
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
if (flags & NSAlternateKeyMask)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if (flags & NSCommandKeyMask)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
// Translates a OS X keycode to a GLFW keycode
|
||||
//
|
||||
static int translateKey(unsigned int key)
|
||||
{
|
||||
if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0]))
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
|
||||
return _glfw.ns.publicKeys[key];
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Delegate for window related notifications
|
||||
@@ -156,7 +187,9 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
if (_glfw.focusedWindow == window &&
|
||||
[window->nsgl.context update];
|
||||
|
||||
if (_glfw.cursorWindow == window &&
|
||||
window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
centerCursor(window);
|
||||
@@ -167,12 +200,13 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
|
||||
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
|
||||
_glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
|
||||
_glfwInputWindowDamage(window);
|
||||
}
|
||||
|
||||
- (void)windowDidMove:(NSNotification *)notification
|
||||
{
|
||||
if (_glfw.focusedWindow == window &&
|
||||
[window->nsgl.context update];
|
||||
|
||||
if (_glfw.cursorWindow == window &&
|
||||
window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
centerCursor(window);
|
||||
@@ -185,20 +219,23 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification *)notification
|
||||
{
|
||||
if (window->monitor)
|
||||
leaveFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_TRUE);
|
||||
}
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification *)notification
|
||||
{
|
||||
if (window->monitor)
|
||||
enterFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_FALSE);
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
if (window->monitor)
|
||||
enterFullscreenMode(window);
|
||||
|
||||
if (_glfw.focusedWindow == window &&
|
||||
if (_glfw.cursorWindow == window &&
|
||||
window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
centerCursor(window);
|
||||
@@ -210,8 +247,8 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
if (window->monitor)
|
||||
leaveFullscreenMode(window);
|
||||
if (window->monitor && window->autoIconify)
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
|
||||
_glfwInputWindowFocus(window, GL_FALSE);
|
||||
}
|
||||
@@ -250,42 +287,22 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect)
|
||||
_glfwPlatformPostEmptyEvent();
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)notification
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
_glfwRestoreVideoMode(_glfw.monitors[i]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Translates OS X key modifiers into GLFW ones
|
||||
//
|
||||
static int translateFlags(NSUInteger flags)
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
if (flags & NSShiftKeyMask)
|
||||
mods |= GLFW_MOD_SHIFT;
|
||||
if (flags & NSControlKeyMask)
|
||||
mods |= GLFW_MOD_CONTROL;
|
||||
if (flags & NSAlternateKeyMask)
|
||||
mods |= GLFW_MOD_ALT;
|
||||
if (flags & NSCommandKeyMask)
|
||||
mods |= GLFW_MOD_SUPER;
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
// Translates a OS X keycode to a GLFW keycode
|
||||
//
|
||||
static int translateKey(unsigned int key)
|
||||
{
|
||||
if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0]))
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
|
||||
return _glfw.ns.publicKeys[key];
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Content view class for the GLFW window
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
@interface GLFWContentView : NSOpenGLView
|
||||
@interface GLFWContentView : NSView
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
NSTrackingArea* trackingArea;
|
||||
@@ -313,8 +330,7 @@ static int translateKey(unsigned int key)
|
||||
|
||||
- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow
|
||||
{
|
||||
self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)
|
||||
pixelFormat:nil];
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
window = initWindow;
|
||||
@@ -453,6 +469,10 @@ static int translateKey(unsigned int key)
|
||||
const NSRect fbRect = convertRectToBacking(window, contentRect);
|
||||
|
||||
_glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)rect
|
||||
{
|
||||
_glfwInputWindowDamage(window);
|
||||
}
|
||||
|
||||
@@ -719,6 +739,7 @@ static void createMenuBar(void)
|
||||
[[appMenu addItemWithTitle:@"Services"
|
||||
action:NULL
|
||||
keyEquivalent:@""] setSubmenu:servicesMenu];
|
||||
[servicesMenu release];
|
||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||
[appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
|
||||
action:@selector(hide:)
|
||||
@@ -737,6 +758,7 @@ static void createMenuBar(void)
|
||||
|
||||
NSMenuItem* windowMenuItem =
|
||||
[bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
|
||||
[bar release];
|
||||
NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
[NSApp setWindowsMenu:windowMenu];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
@@ -838,7 +860,15 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
NSRect contentRect;
|
||||
|
||||
if (wndconfig->monitor)
|
||||
contentRect = [wndconfig->monitor->ns.screen frame];
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
int xpos, ypos;
|
||||
|
||||
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
|
||||
|
||||
contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height);
|
||||
}
|
||||
else
|
||||
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
|
||||
|
||||
@@ -865,7 +895,6 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
if (wndconfig->monitor)
|
||||
{
|
||||
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
|
||||
[window->ns.object setHidesOnDeactivate:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -875,9 +904,19 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
[window->ns.object setLevel:NSFloatingWindowLevel];
|
||||
}
|
||||
|
||||
window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
|
||||
|
||||
#if defined(_GLFW_USE_RETINA)
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
#endif /*_GLFW_USE_RETINA*/
|
||||
|
||||
[window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]];
|
||||
[window->ns.object setDelegate:window->ns.delegate];
|
||||
[window->ns.object setAcceptsMouseMovedEvents:YES];
|
||||
[window->ns.object setContentView:window->ns.view];
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||
@@ -906,22 +945,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
if (!_glfwCreateContext(window, ctxconfig, fbconfig))
|
||||
return GL_FALSE;
|
||||
|
||||
window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
|
||||
|
||||
#if defined(_GLFW_USE_RETINA)
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
|
||||
[window->ns.view setWantsBestResolutionOpenGLSurface:YES];
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
#endif /*_GLFW_USE_RETINA*/
|
||||
|
||||
[window->ns.object setContentView:window->ns.view];
|
||||
// NOTE: If you set the pixel format before the context it creates another
|
||||
// context, only to have it destroyed by the next line
|
||||
// We cannot use the view to create the context because that interface
|
||||
// does not support context resource sharing
|
||||
[window->ns.view setOpenGLContext:window->nsgl.context];
|
||||
[window->ns.view setPixelFormat:window->nsgl.pixelFormat];
|
||||
[window->nsgl.context setView:window->ns.view];
|
||||
|
||||
if (wndconfig->monitor)
|
||||
@@ -1148,8 +1171,14 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0);
|
||||
const NSRect globalRect = [window->ns.object convertRectToScreen:localRect];
|
||||
const NSPoint globalPoint = globalRect.origin;
|
||||
#else
|
||||
const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1);
|
||||
const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint];
|
||||
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
|
||||
|
||||
CGWarpMouseCursorPosition(CGPointMake(globalPoint.x,
|
||||
transformY(globalPoint.y)));
|
||||
@@ -1173,6 +1202,9 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
NSImage* native;
|
||||
NSBitmapImageRep* rep;
|
||||
|
||||
if (!initializeAppKit())
|
||||
return GL_FALSE;
|
||||
|
||||
rep = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:image->width
|
||||
@@ -1208,6 +1240,9 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
if (!initializeAppKit())
|
||||
return GL_FALSE;
|
||||
|
||||
cursor->ns.object = getStandardCursor(shape);
|
||||
if (!cursor->ns.object)
|
||||
{
|
||||
|
||||
+21
-22
@@ -38,6 +38,7 @@
|
||||
static GLboolean parseVersionString(int* api, int* major, int* minor, int* rev)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* window;
|
||||
const char* version;
|
||||
const char* prefixes[] =
|
||||
{
|
||||
@@ -49,7 +50,9 @@ static GLboolean parseVersionString(int* api, int* major, int* minor, int* rev)
|
||||
|
||||
*api = GLFW_OPENGL_API;
|
||||
|
||||
version = (const char*) glGetString(GL_VERSION);
|
||||
window = _glfwPlatformGetCurrentContext();
|
||||
|
||||
version = (const char*) window->GetString(GL_VERSION);
|
||||
if (!version)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -352,6 +355,10 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||
|
||||
window->GetIntegerv = (PFNGLGETINTEGERVPROC) glfwGetProcAddress("glGetIntegerv");
|
||||
window->GetString = (PFNGLGETSTRINGPROC) glfwGetProcAddress("glGetString");
|
||||
window->Clear = (PFNGLCLEARPROC) glfwGetProcAddress("glClear");
|
||||
|
||||
if (!parseVersionString(&window->context.api,
|
||||
&window->context.major,
|
||||
&window->context.minor,
|
||||
@@ -382,7 +389,7 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
GLint flags;
|
||||
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
window->GetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||
window->context.forward = GL_TRUE;
|
||||
@@ -404,7 +411,7 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
(window->context.major == 3 && window->context.minor >= 2))
|
||||
{
|
||||
GLint mask;
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
window->GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
|
||||
if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
@@ -427,7 +434,7 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
// only present from 3.0 while the extension applies from 1.1
|
||||
|
||||
GLint strategy;
|
||||
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
|
||||
window->GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
@@ -444,7 +451,7 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
// one, so we can reuse them here
|
||||
|
||||
GLint strategy;
|
||||
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
|
||||
window->GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
@@ -456,7 +463,7 @@ GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
|
||||
if (glfwExtensionSupported("GL_KHR_context_flush_control"))
|
||||
{
|
||||
GLint behavior;
|
||||
glGetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
|
||||
window->GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
|
||||
|
||||
if (behavior == GL_NONE)
|
||||
window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
|
||||
@@ -490,19 +497,16 @@ GLboolean _glfwIsValidContext(const _GLFWctxconfig* ctxconfig)
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
int _glfwStringInExtensionString(const char* string, const GLubyte* extensions)
|
||||
int _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||
{
|
||||
const GLubyte* start;
|
||||
GLubyte* where;
|
||||
GLubyte* terminator;
|
||||
const char* start = extensions;
|
||||
|
||||
// It takes a bit of care to be fool-proof about parsing the
|
||||
// OpenGL extensions string. Don't be fooled by sub-strings,
|
||||
// etc.
|
||||
start = extensions;
|
||||
for (;;)
|
||||
{
|
||||
where = (GLubyte*) strstr((const char*) start, string);
|
||||
const char* where;
|
||||
const char* terminator;
|
||||
|
||||
where = strstr(start, string);
|
||||
if (!where)
|
||||
return GL_FALSE;
|
||||
|
||||
@@ -527,12 +531,7 @@ int _glfwStringInExtensionString(const char* string, const GLubyte* extensions)
|
||||
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (_glfwPlatformGetCurrentContext() == window)
|
||||
return;
|
||||
|
||||
_glfwPlatformMakeContextCurrent(window);
|
||||
}
|
||||
|
||||
@@ -589,7 +588,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
|
||||
// Check if extension is in the modern OpenGL extensions string list
|
||||
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||
window->GetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
@@ -610,7 +609,7 @@ GLFWAPI int glfwExtensionSupported(const char* extension)
|
||||
{
|
||||
// Check if extension is in the old style OpenGL extensions string
|
||||
|
||||
const GLubyte* extensions = glGetString(GL_EXTENSIONS);
|
||||
const char* extensions = (const char*) window->GetString(GL_EXTENSIONS);
|
||||
if (!extensions)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
|
||||
+228
-74
@@ -78,7 +78,7 @@ static const char* getErrorString(EGLint error)
|
||||
static int getConfigAttrib(EGLConfig config, int attrib)
|
||||
{
|
||||
int value;
|
||||
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount;
|
||||
|
||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||
_glfw_eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||
if (!nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||
@@ -101,7 +101,8 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
|
||||
}
|
||||
|
||||
nativeConfigs = calloc(nativeCount, sizeof(EGLConfig));
|
||||
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
|
||||
_glfw_eglGetConfigs(_glfw.egl.display, nativeConfigs,
|
||||
nativeCount, &nativeCount);
|
||||
|
||||
usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||
usableCount = 0;
|
||||
@@ -112,24 +113,18 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
#if defined(_GLFW_X11)
|
||||
// Only consider EGLConfigs with associated visuals
|
||||
if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
|
||||
{
|
||||
// Only consider EGLConfigs with associated visuals
|
||||
continue;
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
// Only consider RGB(A) EGLConfigs
|
||||
if (!(getConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER))
|
||||
{
|
||||
// Only consider RGB(A) EGLConfigs
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only consider window EGLConfigs
|
||||
if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
|
||||
{
|
||||
// Only consider window EGLConfigs
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctxconfig->api == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
@@ -184,30 +179,91 @@ static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig,
|
||||
//
|
||||
int _glfwInitContextAPI(void)
|
||||
{
|
||||
if (!_glfwInitTLS())
|
||||
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 (!_glfwCreateContextTLS())
|
||||
return GL_FALSE;
|
||||
|
||||
_glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY);
|
||||
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: Failed to load EGL");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
_glfw.egl.GetConfigAttrib =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
|
||||
_glfw.egl.GetConfigs =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigs");
|
||||
_glfw.egl.GetDisplay =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetDisplay");
|
||||
_glfw.egl.GetError =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetError");
|
||||
_glfw.egl.Initialize =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglInitialize");
|
||||
_glfw.egl.Terminate =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglTerminate");
|
||||
_glfw.egl.BindAPI =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglBindAPI");
|
||||
_glfw.egl.CreateContext =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateContext");
|
||||
_glfw.egl.DestroySurface =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroySurface");
|
||||
_glfw.egl.DestroyContext =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglDestroyContext");
|
||||
_glfw.egl.CreateWindowSurface =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglCreateWindowSurface");
|
||||
_glfw.egl.MakeCurrent =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglMakeCurrent");
|
||||
_glfw.egl.SwapBuffers =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapBuffers");
|
||||
_glfw.egl.SwapInterval =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglSwapInterval");
|
||||
_glfw.egl.QueryString =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglQueryString");
|
||||
_glfw.egl.GetProcAddress =
|
||||
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
|
||||
|
||||
_glfw.egl.display =
|
||||
_glfw_eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY);
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to get EGL display: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
if (!eglInitialize(_glfw.egl.display,
|
||||
&_glfw.egl.versionMajor,
|
||||
&_glfw.egl.versionMinor))
|
||||
if (!_glfw_eglInitialize(_glfw.egl.display,
|
||||
&_glfw.egl.major,
|
||||
&_glfw.egl.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to initialize EGL: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
if (_glfwPlatformExtensionSupported("EGL_KHR_create_context"))
|
||||
_glfw.egl.KHR_create_context = GL_TRUE;
|
||||
_glfw.egl.KHR_create_context =
|
||||
_glfwPlatformExtensionSupported("EGL_KHR_create_context");
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
@@ -216,9 +272,16 @@ int _glfwInitContextAPI(void)
|
||||
//
|
||||
void _glfwTerminateContextAPI(void)
|
||||
{
|
||||
eglTerminate(_glfw.egl.display);
|
||||
if (_glfw_eglTerminate)
|
||||
_glfw_eglTerminate(_glfw.egl.display);
|
||||
|
||||
_glfwTerminateTLS();
|
||||
if (_glfw.egl.handle)
|
||||
{
|
||||
_glfw_dlclose(_glfw.egl.handle);
|
||||
_glfw.egl.handle = NULL;
|
||||
}
|
||||
|
||||
_glfwDestroyContextTLS();
|
||||
}
|
||||
|
||||
#define setEGLattrib(attribName, attribValue) \
|
||||
@@ -243,7 +306,7 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (!chooseFBConfigs(ctxconfig, fbconfig, &config))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
return GL_FALSE;
|
||||
}
|
||||
@@ -256,8 +319,8 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
EGLint redBits, greenBits, blueBits, alphaBits, visualID = 0;
|
||||
XVisualInfo info;
|
||||
|
||||
eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||
|
||||
info.screen = _glfw.x11.screen;
|
||||
mask = VisualScreenMask;
|
||||
@@ -270,17 +333,17 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
}
|
||||
else
|
||||
{
|
||||
// some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID
|
||||
// attribute, so attempt to find the closest match.
|
||||
// Some EGL drivers do not implement the EGL_NATIVE_VISUAL_ID
|
||||
// attribute, so attempt to find the closest match
|
||||
|
||||
eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_RED_SIZE, &redBits);
|
||||
eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_GREEN_SIZE, &greenBits);
|
||||
eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_BLUE_SIZE, &blueBits);
|
||||
eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_ALPHA_SIZE, &alphaBits);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_RED_SIZE, &redBits);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_GREEN_SIZE, &greenBits);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_BLUE_SIZE, &blueBits);
|
||||
_glfw_eglGetConfigAttrib(_glfw.egl.display, config,
|
||||
EGL_ALPHA_SIZE, &alphaBits);
|
||||
|
||||
info.depth = redBits + greenBits + blueBits + alphaBits;
|
||||
mask |= VisualDepthMask;
|
||||
@@ -299,38 +362,38 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (ctxconfig->api == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
if (!_glfw_eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL ES: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
return GL_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_API))
|
||||
if (!_glfw_eglBindAPI(EGL_OPENGL_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
return GL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.egl.KHR_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0, strategy = 0;
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->api == 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 (ctxconfig->forward)
|
||||
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->debug)
|
||||
@@ -339,9 +402,15 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
strategy = EGL_NO_RESET_NOTIFICATION_KHR;
|
||||
{
|
||||
setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_NO_RESET_NOTIFICATION_KHR);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
strategy = EGL_LOSE_CONTEXT_ON_RESET_KHR;
|
||||
{
|
||||
setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_LOSE_CONTEXT_ON_RESET_KHR);
|
||||
}
|
||||
|
||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||
}
|
||||
@@ -358,9 +427,6 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (flags)
|
||||
setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||
|
||||
if (strategy)
|
||||
setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, strategy);
|
||||
|
||||
setEGLattrib(EGL_NONE, EGL_NONE);
|
||||
}
|
||||
else
|
||||
@@ -376,19 +442,83 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
// 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->egl.context = eglCreateContext(_glfw.egl.display,
|
||||
config, share, attribs);
|
||||
window->egl.context = _glfw_eglCreateContext(_glfw.egl.display,
|
||||
config, share, attribs);
|
||||
|
||||
if (window->egl.context == EGL_NO_CONTEXT)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"EGL: Failed to create context: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
window->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->api == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
sonames = es1sonames;
|
||||
else
|
||||
sonames = es2sonames;
|
||||
}
|
||||
else
|
||||
sonames = glsonames;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
window->egl.client = _glfw_dlopen(sonames[i]);
|
||||
if (window->egl.client)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!window->egl.client)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to load client library");
|
||||
return GL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
@@ -398,6 +528,19 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
//
|
||||
void _glfwDestroyContext(_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.api != GLFW_OPENGL_API)
|
||||
#endif // _GLFW_X11
|
||||
{
|
||||
if (window->egl.client)
|
||||
{
|
||||
_glfw_dlclose(window->egl.client);
|
||||
window->egl.client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_GLFW_X11)
|
||||
if (window->egl.visual)
|
||||
{
|
||||
@@ -408,13 +551,13 @@ void _glfwDestroyContext(_GLFWwindow* window)
|
||||
|
||||
if (window->egl.surface)
|
||||
{
|
||||
eglDestroySurface(_glfw.egl.display, window->egl.surface);
|
||||
_glfw_eglDestroySurface(_glfw.egl.display, window->egl.surface);
|
||||
window->egl.surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (window->egl.context)
|
||||
{
|
||||
eglDestroyContext(_glfw.egl.display, window->egl.context);
|
||||
_glfw_eglDestroyContext(_glfw.egl.display, window->egl.context);
|
||||
window->egl.context = EGL_NO_CONTEXT;
|
||||
}
|
||||
}
|
||||
@@ -443,50 +586,52 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
|
||||
{
|
||||
if (window->egl.surface == EGL_NO_SURFACE)
|
||||
{
|
||||
window->egl.surface = eglCreateWindowSurface(_glfw.egl.display,
|
||||
window->egl.config,
|
||||
(EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW,
|
||||
NULL);
|
||||
window->egl.surface =
|
||||
_glfw_eglCreateWindowSurface(_glfw.egl.display,
|
||||
window->egl.config,
|
||||
(EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW,
|
||||
NULL);
|
||||
if (window->egl.surface == EGL_NO_SURFACE)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to create window surface: %s",
|
||||
getErrorString(eglGetError()));
|
||||
getErrorString(_glfw_eglGetError()));
|
||||
}
|
||||
}
|
||||
|
||||
eglMakeCurrent(_glfw.egl.display,
|
||||
window->egl.surface,
|
||||
window->egl.surface,
|
||||
window->egl.context);
|
||||
_glfw_eglMakeCurrent(_glfw.egl.display,
|
||||
window->egl.surface,
|
||||
window->egl.surface,
|
||||
window->egl.context);
|
||||
}
|
||||
else
|
||||
{
|
||||
eglMakeCurrent(_glfw.egl.display,
|
||||
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
_glfw_eglMakeCurrent(_glfw.egl.display,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
_glfwSetCurrentContext(window);
|
||||
_glfwSetContextTLS(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapBuffers(_GLFWwindow* window)
|
||||
{
|
||||
eglSwapBuffers(_glfw.egl.display, window->egl.surface);
|
||||
_glfw_eglSwapBuffers(_glfw.egl.display, window->egl.surface);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapInterval(int interval)
|
||||
{
|
||||
eglSwapInterval(_glfw.egl.display, interval);
|
||||
_glfw_eglSwapInterval(_glfw.egl.display, interval);
|
||||
}
|
||||
|
||||
int _glfwPlatformExtensionSupported(const char* extension)
|
||||
{
|
||||
const char* extensions;
|
||||
|
||||
extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
|
||||
if (extensions != NULL)
|
||||
const char* extensions = _glfw_eglQueryString(_glfw.egl.display,
|
||||
EGL_EXTENSIONS);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, (unsigned char*) extensions))
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
@@ -495,7 +640,16 @@ int _glfwPlatformExtensionSupported(const char* extension)
|
||||
|
||||
GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
|
||||
{
|
||||
return eglGetProcAddress(procname);
|
||||
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||
|
||||
if (window->egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc) _glfw_dlsym(window->egl.client, procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
}
|
||||
|
||||
return _glfw_eglGetProcAddress(procname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+73
-12
@@ -25,8 +25,19 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _egl_context_h_
|
||||
#define _egl_context_h_
|
||||
#ifndef _glfw3_egl_context_h_
|
||||
#define _glfw3_egl_context_h_
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
#define _glfw_dlopen(name) LoadLibraryA(name)
|
||||
#define _glfw_dlclose(handle) FreeLibrary((HMODULE) handle)
|
||||
#define _glfw_dlsym(handle, name) GetProcAddress((HMODULE) handle, name)
|
||||
#else
|
||||
#include <dlfcn.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)
|
||||
#endif
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
@@ -35,10 +46,39 @@
|
||||
// extensions and not all operating systems come with an up-to-date version
|
||||
#include "../deps/EGL/eglext.h"
|
||||
|
||||
// Do we have support for dlopen/dlsym?
|
||||
#if defined(_GLFW_HAS_DLOPEN)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
// 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 _glfw_eglGetConfigAttrib _glfw.egl.GetConfigAttrib
|
||||
#define _glfw_eglGetConfigs _glfw.egl.GetConfigs
|
||||
#define _glfw_eglGetDisplay _glfw.egl.GetDisplay
|
||||
#define _glfw_eglGetError _glfw.egl.GetError
|
||||
#define _glfw_eglInitialize _glfw.egl.Initialize
|
||||
#define _glfw_eglTerminate _glfw.egl.Terminate
|
||||
#define _glfw_eglBindAPI _glfw.egl.BindAPI
|
||||
#define _glfw_eglCreateContext _glfw.egl.CreateContext
|
||||
#define _glfw_eglDestroySurface _glfw.egl.DestroySurface
|
||||
#define _glfw_eglDestroyContext _glfw.egl.DestroyContext
|
||||
#define _glfw_eglCreateWindowSurface _glfw.egl.CreateWindowSurface
|
||||
#define _glfw_eglMakeCurrent _glfw.egl.MakeCurrent
|
||||
#define _glfw_eglSwapBuffers _glfw.egl.SwapBuffers
|
||||
#define _glfw_eglSwapInterval _glfw.egl.SwapInterval
|
||||
#define _glfw_eglQueryString _glfw.egl.QueryString
|
||||
#define _glfw_eglGetProcAddress _glfw.egl.GetProcAddress
|
||||
|
||||
#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl
|
||||
@@ -49,14 +89,16 @@
|
||||
//
|
||||
typedef struct _GLFWcontextEGL
|
||||
{
|
||||
EGLConfig config;
|
||||
EGLContext context;
|
||||
EGLSurface surface;
|
||||
EGLConfig config;
|
||||
EGLContext context;
|
||||
EGLSurface surface;
|
||||
|
||||
#if defined(_GLFW_X11)
|
||||
XVisualInfo* visual;
|
||||
XVisualInfo* visual;
|
||||
#endif
|
||||
|
||||
void* client;
|
||||
|
||||
} _GLFWcontextEGL;
|
||||
|
||||
|
||||
@@ -65,10 +107,29 @@ typedef struct _GLFWcontextEGL
|
||||
typedef struct _GLFWlibraryEGL
|
||||
{
|
||||
EGLDisplay display;
|
||||
EGLint versionMajor, versionMinor;
|
||||
EGLint major, minor;
|
||||
|
||||
GLboolean KHR_create_context;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -82,4 +143,4 @@ int _glfwAnalyzeContext(const _GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
#endif // _egl_context_h_
|
||||
#endif // _glfw3_egl_context_h_
|
||||
|
||||
+2
-12
@@ -57,23 +57,13 @@
|
||||
// Define this to 1 if building as a shared library / dynamic library / DLL
|
||||
#cmakedefine _GLFW_BUILD_DLL
|
||||
|
||||
// Define this to 1 if glfwSwapInterval should ignore DWM compositing status
|
||||
#cmakedefine _GLFW_USE_DWM_SWAP_INTERVAL
|
||||
// Define this to 1 to force use of high-performance GPU on Optimus systems
|
||||
#cmakedefine _GLFW_USE_OPTIMUS_HPG
|
||||
// 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 XInput X11 extension is available
|
||||
#cmakedefine _GLFW_HAS_XINPUT
|
||||
// Define this to 1 if the Xxf86vm X11 extension is available
|
||||
#cmakedefine _GLFW_HAS_XF86VM
|
||||
// Define this to 1 if glXGetProcAddress is available
|
||||
#cmakedefine _GLFW_HAS_GLXGETPROCADDRESS
|
||||
// Define this to 1 if glXGetProcAddressARB is available
|
||||
#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSARB
|
||||
// Define this to 1 if glXGetProcAddressEXT is available
|
||||
#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT
|
||||
// Define this to 1 if dlopen is available
|
||||
#cmakedefine _GLFW_HAS_DLOPEN
|
||||
|
||||
// Define this to 1 if glfwInit should change the current directory
|
||||
#cmakedefine _GLFW_USE_CHDIR
|
||||
|
||||
+116
-93
@@ -30,11 +30,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// This is the only glXGetProcAddress variant not declared by glxext.h
|
||||
void (*glXGetProcAddressEXT(const GLubyte* procName))();
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifndef GLXBadProfileARB
|
||||
#define GLXBadProfileARB 13
|
||||
@@ -46,7 +42,7 @@ void (*glXGetProcAddressEXT(const GLubyte* procName))();
|
||||
static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
|
||||
{
|
||||
int value;
|
||||
glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
|
||||
_glfw_glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -61,16 +57,14 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul
|
||||
const char* vendor;
|
||||
GLboolean trustWindowBit = GL_TRUE;
|
||||
|
||||
vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
||||
// HACK: This is a (hopefully temporary) workaround for Chromium
|
||||
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
||||
vendor = _glfw_glXGetClientString(_glfw.x11.display, GLX_VENDOR);
|
||||
if (strcmp(vendor, "Chromium") == 0)
|
||||
{
|
||||
// HACK: This is a (hopefully temporary) workaround for Chromium
|
||||
// (VirtualBox GL) not setting the window bit on any GLXFBConfigs
|
||||
trustWindowBit = GL_FALSE;
|
||||
}
|
||||
|
||||
nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen,
|
||||
&nativeCount);
|
||||
nativeConfigs = _glfw_glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen,
|
||||
&nativeCount);
|
||||
if (!nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned");
|
||||
@@ -85,25 +79,19 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul
|
||||
const GLXFBConfig n = nativeConfigs[i];
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
// Only consider GLXFBConfigs with associated visuals
|
||||
if (!getFBConfigAttrib(n, GLX_VISUAL_ID))
|
||||
{
|
||||
// Only consider GLXFBConfigs with associated visuals
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only consider RGBA GLXFBConfigs
|
||||
if (!(getFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT))
|
||||
{
|
||||
// Only consider RGBA GLXFBConfigs
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only consider window GLXFBConfigs
|
||||
if (!(getFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT))
|
||||
{
|
||||
if (trustWindowBit)
|
||||
{
|
||||
// Only consider window GLXFBConfigs
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE);
|
||||
@@ -129,7 +117,7 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul
|
||||
if (_glfw.glx.ARB_multisample)
|
||||
u->samples = getFBConfigAttrib(n, GLX_SAMPLES);
|
||||
|
||||
if (_glfw.glx.ARB_framebuffer_sRGB)
|
||||
if (_glfw.glx.ARB_framebuffer_sRGB || _glfw.glx.EXT_framebuffer_sRGB)
|
||||
u->sRGB = getFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
||||
|
||||
u->glx = n;
|
||||
@@ -152,11 +140,11 @@ static GLXContext createLegacyContext(_GLFWwindow* window,
|
||||
GLXFBConfig fbconfig,
|
||||
GLXContext share)
|
||||
{
|
||||
return glXCreateNewContext(_glfw.x11.display,
|
||||
fbconfig,
|
||||
GLX_RGBA_TYPE,
|
||||
share,
|
||||
True);
|
||||
return _glfw_glXCreateNewContext(_glfw.x11.display,
|
||||
fbconfig,
|
||||
GLX_RGBA_TYPE,
|
||||
share,
|
||||
True);
|
||||
}
|
||||
|
||||
|
||||
@@ -168,36 +156,67 @@ static GLXContext createLegacyContext(_GLFWwindow* window,
|
||||
//
|
||||
int _glfwInitContextAPI(void)
|
||||
{
|
||||
if (!_glfwInitTLS())
|
||||
return GL_FALSE;
|
||||
|
||||
#ifdef _GLFW_DLOPEN_LIBGL
|
||||
_glfw.glx.libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!_glfw.glx.libGL)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to find libGL");
|
||||
return GL_FALSE;
|
||||
}
|
||||
#if defined(__CYGWIN__)
|
||||
const char* soname = "libGL-1.so";
|
||||
#else
|
||||
const char* soname = "libGL.so.1";
|
||||
#endif
|
||||
|
||||
if (!glXQueryExtension(_glfw.x11.display,
|
||||
&_glfw.glx.errorBase,
|
||||
&_glfw.glx.eventBase))
|
||||
if (!_glfwCreateContextTLS())
|
||||
return GL_FALSE;
|
||||
|
||||
_glfw.glx.handle = dlopen(soname, RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (!_glfw.glx.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: %s", dlerror());
|
||||
return GL_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.GetVisualFromFBConfig =
|
||||
dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
_glfw.glx.GetProcAddress =
|
||||
dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
||||
_glfw.glx.GetProcAddressARB =
|
||||
dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
||||
|
||||
if (!_glfw_glXQueryExtension(_glfw.x11.display,
|
||||
&_glfw.glx.errorBase,
|
||||
&_glfw.glx.eventBase))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
if (!glXQueryVersion(_glfw.x11.display,
|
||||
&_glfw.glx.versionMajor,
|
||||
&_glfw.glx.versionMinor))
|
||||
if (!_glfw_glXQueryVersion(_glfw.x11.display,
|
||||
&_glfw.glx.major,
|
||||
&_glfw.glx.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: Failed to query GLX version");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
if (_glfw.glx.versionMajor == 1 && _glfw.glx.versionMinor < 3)
|
||||
if (_glfw.glx.major == 1 && _glfw.glx.minor < 3)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"GLX: GLX version 1.3 is required");
|
||||
@@ -237,6 +256,9 @@ int _glfwInitContextAPI(void)
|
||||
if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB"))
|
||||
_glfw.glx.ARB_framebuffer_sRGB = GL_TRUE;
|
||||
|
||||
if (_glfwPlatformExtensionSupported("GLX_EXT_framebuffer_sRGB"))
|
||||
_glfw.glx.EXT_framebuffer_sRGB = GL_TRUE;
|
||||
|
||||
if (_glfwPlatformExtensionSupported("GLX_ARB_create_context"))
|
||||
{
|
||||
_glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
|
||||
@@ -265,16 +287,16 @@ int _glfwInitContextAPI(void)
|
||||
//
|
||||
void _glfwTerminateContextAPI(void)
|
||||
{
|
||||
// Unload libGL.so if necessary
|
||||
#ifdef _GLFW_DLOPEN_LIBGL
|
||||
if (_glfw.glx.libGL != NULL)
|
||||
{
|
||||
dlclose(_glfw.glx.libGL);
|
||||
_glfw.glx.libGL = NULL;
|
||||
}
|
||||
#endif
|
||||
// NOTE: This function may not call any X11 functions, as it is called after
|
||||
// XCloseDisplay (see _glfwPlatformTerminate for details)
|
||||
|
||||
_glfwTerminateTLS();
|
||||
if (_glfw.glx.handle)
|
||||
{
|
||||
dlclose(_glfw.glx.handle);
|
||||
_glfw.glx.handle = NULL;
|
||||
}
|
||||
|
||||
_glfwDestroyContextTLS();
|
||||
}
|
||||
|
||||
#define setGLXattrib(attribName, attribValue) \
|
||||
@@ -291,7 +313,7 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
int attribs[40];
|
||||
GLXFBConfig native;
|
||||
GLXFBConfig native = NULL;
|
||||
GLXContext share = NULL;
|
||||
|
||||
if (ctxconfig->share)
|
||||
@@ -299,13 +321,13 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (!chooseFBConfig(fbconfig, &native))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"GLX: Failed to find a suitable GLXFBConfig");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
// Retrieve the corresponding visual
|
||||
window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native);
|
||||
window->glx.visual = _glfw_glXGetVisualFromFBConfig(_glfw.x11.display,
|
||||
native);
|
||||
if (!window->glx.visual)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -350,20 +372,17 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (_glfw.glx.ARB_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0, strategy = 0;
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->api == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
@@ -376,9 +395,15 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (_glfw.glx.ARB_create_context_robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
strategy = GLX_NO_RESET_NOTIFICATION_ARB;
|
||||
{
|
||||
setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
GLX_NO_RESET_NOTIFICATION_ARB);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB;
|
||||
{
|
||||
setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
GLX_LOSE_CONTEXT_ON_RESET_ARB);
|
||||
}
|
||||
|
||||
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
@@ -401,12 +426,11 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// NOTE: Only request an explicitly versioned context when
|
||||
// necessary, as explicitly requesting version 1.0 does not
|
||||
// always return the highest available version
|
||||
|
||||
setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
@@ -417,9 +441,6 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (flags)
|
||||
setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags);
|
||||
|
||||
if (strategy)
|
||||
setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy);
|
||||
|
||||
setGLXattrib(None, None);
|
||||
|
||||
window->glx.context =
|
||||
@@ -429,12 +450,12 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
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->glx.context)
|
||||
{
|
||||
// HACK: This is a fallback for the broken Mesa implementation of
|
||||
// GLX_ARB_create_context_profile, which fails default 1.0
|
||||
// context creation with a GLXBadProfileARB error in violation
|
||||
// of the extension spec
|
||||
if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB &&
|
||||
ctxconfig->api == GLFW_OPENGL_API &&
|
||||
ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE &&
|
||||
@@ -472,7 +493,7 @@ void _glfwDestroyContext(_GLFWwindow* window)
|
||||
|
||||
if (window->glx.context)
|
||||
{
|
||||
glXDestroyContext(_glfw.x11.display, window->glx.context);
|
||||
_glfw_glXDestroyContext(_glfw.x11.display, window->glx.context);
|
||||
window->glx.context = NULL;
|
||||
}
|
||||
}
|
||||
@@ -486,19 +507,19 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
glXMakeCurrent(_glfw.x11.display,
|
||||
window->x11.handle,
|
||||
window->glx.context);
|
||||
_glfw_glXMakeCurrent(_glfw.x11.display,
|
||||
window->x11.handle,
|
||||
window->glx.context);
|
||||
}
|
||||
else
|
||||
glXMakeCurrent(_glfw.x11.display, None, NULL);
|
||||
_glfw_glXMakeCurrent(_glfw.x11.display, None, NULL);
|
||||
|
||||
_glfwSetCurrentContext(window);
|
||||
_glfwSetContextTLS(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapBuffers(_GLFWwindow* window)
|
||||
{
|
||||
glXSwapBuffers(_glfw.x11.display, window->x11.handle);
|
||||
_glfw_glXSwapBuffers(_glfw.x11.display, window->x11.handle);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapInterval(int interval)
|
||||
@@ -522,12 +543,9 @@ void _glfwPlatformSwapInterval(int interval)
|
||||
|
||||
int _glfwPlatformExtensionSupported(const char* extension)
|
||||
{
|
||||
const GLubyte* extensions;
|
||||
|
||||
// Get list of GLX extensions
|
||||
extensions = (const GLubyte*) glXQueryExtensionsString(_glfw.x11.display,
|
||||
_glfw.x11.screen);
|
||||
if (extensions != NULL)
|
||||
const char* extensions =
|
||||
_glfw_glXQueryExtensionsString(_glfw.x11.display, _glfw.x11.screen);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GL_TRUE;
|
||||
@@ -538,7 +556,12 @@ int _glfwPlatformExtensionSupported(const char* extension)
|
||||
|
||||
GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
|
||||
{
|
||||
return _glfw_glXGetProcAddress((const GLubyte*) 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+49
-34
@@ -25,8 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _glx_context_h_
|
||||
#define _glx_context_h_
|
||||
#ifndef _glfw3_glx_context_h_
|
||||
#define _glfw3_glx_context_h_
|
||||
|
||||
#define GLX_GLXEXT_LEGACY
|
||||
#include <GL/glx.h>
|
||||
@@ -34,28 +34,29 @@
|
||||
// This path may need to be changed if you build GLFW using your own setup
|
||||
// We ship and use our own copy of glxext.h since GLFW uses fairly new
|
||||
// extensions and not all operating systems come with an up-to-date version
|
||||
#define GLX_GLXEXT_PROTOTYPES
|
||||
#include "../deps/GL/glxext.h"
|
||||
|
||||
// Do we have support for dlopen/dlsym?
|
||||
#if defined(_GLFW_HAS_DLOPEN)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
// We support four different ways for getting addresses for GL/GLX
|
||||
// extension functions: glXGetProcAddress, glXGetProcAddressARB,
|
||||
// glXGetProcAddressEXT, and dlsym
|
||||
#if defined(_GLFW_HAS_GLXGETPROCADDRESSARB)
|
||||
#define _glfw_glXGetProcAddress(x) glXGetProcAddressARB(x)
|
||||
#elif defined(_GLFW_HAS_GLXGETPROCADDRESS)
|
||||
#define _glfw_glXGetProcAddress(x) glXGetProcAddress(x)
|
||||
#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT)
|
||||
#define _glfw_glXGetProcAddress(x) glXGetProcAddressEXT(x)
|
||||
#elif defined(_GLFW_HAS_DLOPEN)
|
||||
#define _glfw_glXGetProcAddress(x) dlsym(_glfw.glx.libGL, x)
|
||||
#define _GLFW_DLOPEN_LIBGL
|
||||
#else
|
||||
#error "No OpenGL entry point retrieval mechanism was enabled"
|
||||
#endif
|
||||
// libGL.so function pointer typedefs
|
||||
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);
|
||||
#define _glfw_glXGetFBConfigs _glfw.glx.GetFBConfigs
|
||||
#define _glfw_glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
|
||||
#define _glfw_glXGetClientString _glfw.glx.GetClientString
|
||||
#define _glfw_glXQueryExtension _glfw.glx.QueryExtension
|
||||
#define _glfw_glXQueryVersion _glfw.glx.QueryVersion
|
||||
#define _glfw_glXDestroyContext _glfw.glx.DestroyContext
|
||||
#define _glfw_glXMakeCurrent _glfw.glx.MakeCurrent
|
||||
#define _glfw_glXSwapBuffers _glfw.glx.SwapBuffers
|
||||
#define _glfw_glXQueryExtensionsString _glfw.glx.QueryExtensionsString
|
||||
#define _glfw_glXCreateNewContext _glfw.glx.CreateNewContext
|
||||
#define _glfw_glXGetVisualFromFBConfig _glfw.glx.GetVisualFromFBConfig
|
||||
|
||||
#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx
|
||||
@@ -82,31 +83,45 @@ typedef struct _GLFWcontextGLX
|
||||
//
|
||||
typedef struct _GLFWlibraryGLX
|
||||
{
|
||||
int versionMajor, versionMinor;
|
||||
int major, minor;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
|
||||
// GLX extensions
|
||||
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI;
|
||||
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||
// 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;
|
||||
|
||||
// GLX 1.4 and extension functions
|
||||
PFNGLXGETPROCADDRESSPROC GetProcAddress;
|
||||
PFNGLXGETPROCADDRESSPROC GetProcAddressARB;
|
||||
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI;
|
||||
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||
PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA;
|
||||
PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB;
|
||||
GLboolean SGI_swap_control;
|
||||
GLboolean EXT_swap_control;
|
||||
GLboolean MESA_swap_control;
|
||||
GLboolean ARB_multisample;
|
||||
GLboolean ARB_framebuffer_sRGB;
|
||||
GLboolean EXT_framebuffer_sRGB;
|
||||
GLboolean ARB_create_context;
|
||||
GLboolean ARB_create_context_profile;
|
||||
GLboolean ARB_create_context_robustness;
|
||||
GLboolean EXT_create_context_es2_profile;
|
||||
GLboolean ARB_context_flush_control;
|
||||
|
||||
#if defined(_GLFW_DLOPEN_LIBGL)
|
||||
// dlopen handle for libGL.so (for glfwGetProcAddress)
|
||||
void* libGL;
|
||||
#endif
|
||||
|
||||
} _GLFWlibraryGLX;
|
||||
|
||||
|
||||
@@ -117,4 +132,4 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContext(_GLFWwindow* window);
|
||||
|
||||
#endif // _glx_context_h_
|
||||
#endif // _glfw3_glx_context_h_
|
||||
|
||||
+3
-10
@@ -33,8 +33,8 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// The three global variables below comprise all global data in GLFW, except for
|
||||
// various static const translation tables. Any other global variable is a bug.
|
||||
// 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
|
||||
@@ -86,7 +86,7 @@ void _glfwInputError(int error, const char* format, ...)
|
||||
{
|
||||
if (_glfwErrorCallback)
|
||||
{
|
||||
char buffer[16384];
|
||||
char buffer[8192];
|
||||
const char* description;
|
||||
|
||||
if (format)
|
||||
@@ -129,13 +129,6 @@ GLFWAPI int glfwInit(void)
|
||||
}
|
||||
|
||||
_glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
|
||||
if (!_glfw.monitorCount)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "No monitors found");
|
||||
_glfwPlatformTerminate();
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
_glfwInitialized = GL_TRUE;
|
||||
|
||||
// Not all window hints have zero as their default value
|
||||
|
||||
+2
-2
@@ -55,7 +55,7 @@ static void setCursorMode(_GLFWwindow* window, int newMode)
|
||||
|
||||
window->cursorMode = newMode;
|
||||
|
||||
if (_glfw.focusedWindow == window)
|
||||
if (_glfw.cursorWindow == window)
|
||||
{
|
||||
if (oldMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
@@ -343,7 +343,7 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (_glfw.focusedWindow != window)
|
||||
if (_glfw.cursorWindow != window)
|
||||
return;
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
|
||||
+22
-41
@@ -25,15 +25,15 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _internal_h_
|
||||
#define _internal_h_
|
||||
#ifndef _glfw3_internal_h_
|
||||
#define _glfw3_internal_h_
|
||||
|
||||
|
||||
#if defined(_GLFW_USE_CONFIG_H)
|
||||
#include "glfw_config.h"
|
||||
#endif
|
||||
|
||||
#define _GLFW_VERSION_NUMBER "3.1.1"
|
||||
#define _GLFW_VERSION_NUMBER "3.1.2"
|
||||
|
||||
#if defined(GLFW_INCLUDE_GLCOREARB) || \
|
||||
defined(GLFW_INCLUDE_ES1) || \
|
||||
@@ -69,6 +69,10 @@
|
||||
#include "../deps/GL/glext.h"
|
||||
#endif
|
||||
|
||||
typedef void (APIENTRY * PFNGLCLEARPROC)(GLbitfield);
|
||||
typedef const GLubyte* (APIENTRY * PFNGLGETSTRINGPROC)(GLenum);
|
||||
typedef void (APIENTRY * PFNGLGETINTEGERVPROC)(GLenum,GLint*);
|
||||
|
||||
typedef struct _GLFWwndconfig _GLFWwndconfig;
|
||||
typedef struct _GLFWctxconfig _GLFWctxconfig;
|
||||
typedef struct _GLFWfbconfig _GLFWfbconfig;
|
||||
@@ -261,6 +265,9 @@ struct _GLFWwindow
|
||||
#if defined(_GLFW_USE_OPENGL)
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
#endif
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
PFNGLCLEARPROC Clear;
|
||||
|
||||
struct {
|
||||
GLFWwindowposfun pos;
|
||||
@@ -323,47 +330,21 @@ struct _GLFWcursor
|
||||
struct _GLFWlibrary
|
||||
{
|
||||
struct {
|
||||
int redBits;
|
||||
int greenBits;
|
||||
int blueBits;
|
||||
int alphaBits;
|
||||
int depthBits;
|
||||
int stencilBits;
|
||||
int accumRedBits;
|
||||
int accumGreenBits;
|
||||
int accumBlueBits;
|
||||
int accumAlphaBits;
|
||||
int auxBuffers;
|
||||
int stereo;
|
||||
int resizable;
|
||||
int visible;
|
||||
int decorated;
|
||||
int focused;
|
||||
int autoIconify;
|
||||
int floating;
|
||||
int samples;
|
||||
int sRGB;
|
||||
int refreshRate;
|
||||
int doublebuffer;
|
||||
int api;
|
||||
int major;
|
||||
int minor;
|
||||
int forward;
|
||||
int debug;
|
||||
int profile;
|
||||
int robustness;
|
||||
int release;
|
||||
_GLFWfbconfig framebuffer;
|
||||
_GLFWwndconfig window;
|
||||
_GLFWctxconfig context;
|
||||
int refreshRate;
|
||||
} hints;
|
||||
|
||||
double cursorPosX, cursorPosY;
|
||||
double cursorPosX, cursorPosY;
|
||||
|
||||
_GLFWcursor* cursorListHead;
|
||||
_GLFWcursor* cursorListHead;
|
||||
|
||||
_GLFWwindow* windowListHead;
|
||||
_GLFWwindow* focusedWindow;
|
||||
_GLFWwindow* windowListHead;
|
||||
_GLFWwindow* cursorWindow;
|
||||
|
||||
_GLFWmonitor** monitors;
|
||||
int monitorCount;
|
||||
_GLFWmonitor** monitors;
|
||||
int monitorCount;
|
||||
|
||||
struct {
|
||||
GLFWmonitorfun monitor;
|
||||
@@ -825,7 +806,7 @@ void _glfwSplitBPP(int bpp, int* red, int* green, int* blue);
|
||||
* @return `GL_TRUE` if the extension was found, or `GL_FALSE` otherwise.
|
||||
* @ingroup utility
|
||||
*/
|
||||
int _glfwStringInExtensionString(const char* string, const GLubyte* extensions);
|
||||
int _glfwStringInExtensionString(const char* string, const char* extensions);
|
||||
|
||||
/*! @brief Chooses the framebuffer config that best matches the desired one.
|
||||
* @param[in] desired The desired framebuffer config.
|
||||
@@ -894,4 +875,4 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor);
|
||||
*/
|
||||
void _glfwFreeMonitors(_GLFWmonitor** monitors, int count);
|
||||
|
||||
#endif // _internal_h_
|
||||
#endif // _glfw3_internal_h_
|
||||
|
||||
+14
-7
@@ -24,8 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _iokit_joystick_h_
|
||||
#define _iokit_joystick_h_
|
||||
#ifndef _glfw3_iokit_joystick_h_
|
||||
#define _glfw3_iokit_joystick_h_
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
@@ -33,17 +33,17 @@
|
||||
#include <IOKit/hid/IOHIDKeys.h>
|
||||
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||
_GLFWjoystickIOKit iokit_js[GLFW_JOYSTICK_LAST + 1]
|
||||
_GLFWjoystickIOKit iokit_js
|
||||
|
||||
|
||||
// IOKit-specific per-joystick data
|
||||
//
|
||||
typedef struct _GLFWjoystickIOKit
|
||||
typedef struct _GLFWjoydevice
|
||||
{
|
||||
int present;
|
||||
char name[256];
|
||||
|
||||
IOHIDDeviceInterface** interface;
|
||||
IOHIDDeviceRef deviceRef;
|
||||
|
||||
CFMutableArrayRef axisElements;
|
||||
CFMutableArrayRef buttonElements;
|
||||
@@ -51,11 +51,18 @@ typedef struct _GLFWjoystickIOKit
|
||||
|
||||
float* axes;
|
||||
unsigned char* buttons;
|
||||
} _GLFWjoydevice;
|
||||
|
||||
// IOKit-specific joystick API data
|
||||
//
|
||||
typedef struct _GLFWjoystickIOKit
|
||||
{
|
||||
_GLFWjoydevice devices[GLFW_JOYSTICK_LAST + 1];
|
||||
|
||||
IOHIDManagerRef managerRef;
|
||||
} _GLFWjoystickIOKit;
|
||||
|
||||
|
||||
void _glfwInitJoysticks(void);
|
||||
void _glfwTerminateJoysticks(void);
|
||||
|
||||
#endif // _iokit_joystick_h_
|
||||
#endif // _glfw3_iokit_joystick_h_
|
||||
|
||||
+262
-261
@@ -42,7 +42,7 @@
|
||||
//------------------------------------------------------------------------
|
||||
typedef struct
|
||||
{
|
||||
IOHIDElementCookie cookie;
|
||||
IOHIDElementRef elementRef;
|
||||
|
||||
long min;
|
||||
long max;
|
||||
@@ -55,89 +55,68 @@ typedef struct
|
||||
|
||||
static void getElementsCFArrayHandler(const void* value, void* parameter);
|
||||
|
||||
|
||||
// Adds an element to the specified joystick
|
||||
//
|
||||
static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRef)
|
||||
static void addJoystickElement(_GLFWjoydevice* joystick,
|
||||
IOHIDElementRef elementRef)
|
||||
{
|
||||
long elementType, usagePage, usage;
|
||||
IOHIDElementType elementType;
|
||||
long usagePage, usage;
|
||||
CFMutableArrayRef elementsArray = NULL;
|
||||
|
||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)),
|
||||
kCFNumberLongType, &elementType);
|
||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)),
|
||||
kCFNumberLongType, &usagePage);
|
||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)),
|
||||
kCFNumberLongType, &usage);
|
||||
elementType = IOHIDElementGetType(elementRef);
|
||||
usagePage = IOHIDElementGetUsagePage(elementRef);
|
||||
usage = IOHIDElementGetUsage(elementRef);
|
||||
|
||||
if ((elementType == kIOHIDElementTypeInput_Axis) ||
|
||||
(elementType == kIOHIDElementTypeInput_Button) ||
|
||||
(elementType == kIOHIDElementTypeInput_Misc))
|
||||
if ((elementType != kIOHIDElementTypeInput_Axis) &&
|
||||
(elementType != kIOHIDElementTypeInput_Button) &&
|
||||
(elementType != kIOHIDElementTypeInput_Misc))
|
||||
{
|
||||
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 = joystick->axisElements;
|
||||
break;
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
elementsArray = joystick->hatElements;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case kHIDPage_Button:
|
||||
elementsArray = joystick->buttonElements;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementsArray)
|
||||
{
|
||||
long number;
|
||||
CFTypeRef numberRef;
|
||||
_GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement));
|
||||
|
||||
CFArrayAppendValue(elementsArray, element);
|
||||
|
||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey));
|
||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
||||
element->cookie = (IOHIDElementCookie) number;
|
||||
|
||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey));
|
||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
||||
element->minReport = element->min = number;
|
||||
|
||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey));
|
||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
||||
element->maxReport = element->max = number;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
switch (usagePage)
|
||||
{
|
||||
CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey));
|
||||
if (array)
|
||||
case kHIDPage_GenericDesktop:
|
||||
{
|
||||
if (CFGetTypeID(array) == CFArrayGetTypeID())
|
||||
switch (usage)
|
||||
{
|
||||
CFRange range = { 0, CFArrayGetCount(array) };
|
||||
CFArrayApplyFunction(array, range, getElementsCFArrayHandler, joystick);
|
||||
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 = joystick->axisElements;
|
||||
break;
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
elementsArray = joystick->hatElements;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case kHIDPage_Button:
|
||||
elementsArray = joystick->buttonElements;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementsArray)
|
||||
{
|
||||
_GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement));
|
||||
|
||||
CFArrayAppendValue(elementsArray, element);
|
||||
|
||||
element->elementRef = elementRef;
|
||||
|
||||
element->minReport = IOHIDElementGetLogicalMin(elementRef);
|
||||
element->maxReport = IOHIDElementGetLogicalMax(elementRef);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,40 +124,46 @@ static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRe
|
||||
//
|
||||
static void getElementsCFArrayHandler(const void* value, void* parameter)
|
||||
{
|
||||
if (CFGetTypeID(value) == CFDictionaryGetTypeID())
|
||||
addJoystickElement((_GLFWjoystickIOKit*) parameter, (CFTypeRef) value);
|
||||
if (CFGetTypeID(value) == IOHIDElementGetTypeID())
|
||||
{
|
||||
addJoystickElement((_GLFWjoydevice*) parameter,
|
||||
(IOHIDElementRef) value);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the value of the specified element of the specified joystick
|
||||
//
|
||||
static long getElementValue(_GLFWjoystickIOKit* joystick, _GLFWjoyelement* element)
|
||||
static long getElementValue(_GLFWjoydevice* joystick, _GLFWjoyelement* element)
|
||||
{
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
IOHIDEventStruct hidEvent;
|
||||
hidEvent.value = 0;
|
||||
IOHIDValueRef valueRef;
|
||||
long value = 0;
|
||||
|
||||
if (joystick && element && joystick->interface)
|
||||
if (joystick && element && joystick->deviceRef)
|
||||
{
|
||||
result = (*(joystick->interface))->getElementValue(joystick->interface,
|
||||
element->cookie,
|
||||
&hidEvent);
|
||||
result = IOHIDDeviceGetValue(joystick->deviceRef,
|
||||
element->elementRef,
|
||||
&valueRef);
|
||||
|
||||
if (kIOReturnSuccess == result)
|
||||
{
|
||||
value = IOHIDValueGetIntegerValue(valueRef);
|
||||
|
||||
// Record min and max for auto calibration
|
||||
if (hidEvent.value < element->minReport)
|
||||
element->minReport = hidEvent.value;
|
||||
if (hidEvent.value > element->maxReport)
|
||||
element->maxReport = hidEvent.value;
|
||||
if (value < element->minReport)
|
||||
element->minReport = value;
|
||||
if (value > element->maxReport)
|
||||
element->maxReport = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto user scale
|
||||
return (long) hidEvent.value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Removes the specified joystick
|
||||
//
|
||||
static void removeJoystick(_GLFWjoystickIOKit* joystick)
|
||||
static void removeJoystick(_GLFWjoydevice* joystick)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -188,29 +173,22 @@ static void removeJoystick(_GLFWjoystickIOKit* joystick)
|
||||
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
|
||||
CFArrayRemoveAllValues(joystick->axisElements);
|
||||
CFRelease(joystick->axisElements);
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
|
||||
CFArrayRemoveAllValues(joystick->buttonElements);
|
||||
CFRelease(joystick->buttonElements);
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
|
||||
free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
|
||||
CFArrayRemoveAllValues(joystick->hatElements);
|
||||
CFRelease(joystick->hatElements);
|
||||
|
||||
free(joystick->axes);
|
||||
free(joystick->buttons);
|
||||
|
||||
(*(joystick->interface))->close(joystick->interface);
|
||||
(*(joystick->interface))->Release(joystick->interface);
|
||||
|
||||
memset(joystick, 0, sizeof(_GLFWjoystickIOKit));
|
||||
}
|
||||
|
||||
// Callback for user-initiated joystick removal
|
||||
//
|
||||
static void removalCallback(void* target, IOReturn result, void* refcon, void* sender)
|
||||
{
|
||||
removeJoystick((_GLFWjoystickIOKit*) refcon);
|
||||
memset(joystick, 0, sizeof(_GLFWjoydevice));
|
||||
}
|
||||
|
||||
// Polls for joystick events and updates GLFW state
|
||||
@@ -223,15 +201,15 @@ static void pollJoystickEvents(void)
|
||||
{
|
||||
CFIndex i;
|
||||
int buttonIndex = 0;
|
||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
||||
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||
|
||||
if (!joystick->present)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
|
||||
{
|
||||
_GLFWjoyelement* button =
|
||||
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttonElements, i);
|
||||
_GLFWjoyelement* button = (_GLFWjoyelement*)
|
||||
CFArrayGetValueAtIndex(joystick->buttonElements, i);
|
||||
|
||||
if (getElementValue(joystick, button))
|
||||
joystick->buttons[buttonIndex++] = GLFW_PRESS;
|
||||
@@ -241,8 +219,8 @@ static void pollJoystickEvents(void)
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
|
||||
{
|
||||
_GLFWjoyelement* axis =
|
||||
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axisElements, i);
|
||||
_GLFWjoyelement* axis = (_GLFWjoyelement*)
|
||||
CFArrayGetValueAtIndex(joystick->axisElements, i);
|
||||
|
||||
long value = getElementValue(joystick, axis);
|
||||
long readScale = axis->maxReport - axis->minReport;
|
||||
@@ -255,8 +233,8 @@ static void pollJoystickEvents(void)
|
||||
|
||||
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
|
||||
{
|
||||
_GLFWjoyelement* hat =
|
||||
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hatElements, i);
|
||||
_GLFWjoyelement* hat = (_GLFWjoyelement*)
|
||||
CFArrayGetValueAtIndex(joystick->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 };
|
||||
@@ -276,6 +254,129 @@ static void pollJoystickEvents(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for user-initiated joystick addition
|
||||
//
|
||||
static void matchCallback(void* context,
|
||||
IOReturn result,
|
||||
void* sender,
|
||||
IOHIDDeviceRef deviceRef)
|
||||
{
|
||||
_GLFWjoydevice* joystick;
|
||||
int joy;
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
joystick = _glfw.iokit_js.devices + joy;
|
||||
|
||||
if (!joystick->present)
|
||||
continue;
|
||||
|
||||
if (joystick->deviceRef == deviceRef)
|
||||
return;
|
||||
}
|
||||
|
||||
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
joystick = _glfw.iokit_js.devices + joy;
|
||||
|
||||
if (!joystick->present)
|
||||
break;
|
||||
}
|
||||
|
||||
if (joy > GLFW_JOYSTICK_LAST)
|
||||
return;
|
||||
|
||||
joystick->present = GL_TRUE;
|
||||
joystick->deviceRef = deviceRef;
|
||||
|
||||
CFStringRef name = IOHIDDeviceGetProperty(deviceRef,
|
||||
CFSTR(kIOHIDProductKey));
|
||||
CFStringGetCString(name,
|
||||
joystick->name,
|
||||
sizeof(joystick->name),
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
|
||||
CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef,
|
||||
NULL,
|
||||
kIOHIDOptionsTypeNone);
|
||||
CFRange range = { 0, CFArrayGetCount(arrayRef) };
|
||||
CFArrayApplyFunction(arrayRef,
|
||||
range,
|
||||
getElementsCFArrayHandler,
|
||||
(void*) joystick);
|
||||
|
||||
CFRelease(arrayRef);
|
||||
|
||||
joystick->axes = calloc(CFArrayGetCount(joystick->axisElements),
|
||||
sizeof(float));
|
||||
joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) +
|
||||
CFArrayGetCount(joystick->hatElements) * 4, 1);
|
||||
}
|
||||
|
||||
// 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++)
|
||||
{
|
||||
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||
if (joystick->deviceRef == deviceRef)
|
||||
{
|
||||
removeJoystick(joystick);
|
||||
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 //////
|
||||
@@ -285,177 +386,77 @@ static void pollJoystickEvents(void)
|
||||
//
|
||||
void _glfwInitJoysticks(void)
|
||||
{
|
||||
int joy = 0;
|
||||
IOReturn result = kIOReturnSuccess;
|
||||
mach_port_t masterPort = 0;
|
||||
io_iterator_t objectIterator = 0;
|
||||
CFMutableDictionaryRef hidMatchDictionary = NULL;
|
||||
io_object_t ioHIDDeviceObject = 0;
|
||||
CFMutableArrayRef matchingCFArrayRef;
|
||||
|
||||
result = IOMasterPort(bootstrap_port, &masterPort);
|
||||
hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
|
||||
if (kIOReturnSuccess != result || !hidMatchDictionary)
|
||||
_glfw.iokit_js.managerRef = IOHIDManagerCreate(kCFAllocatorDefault,
|
||||
kIOHIDOptionsTypeNone);
|
||||
|
||||
matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeArrayCallBacks);
|
||||
if (matchingCFArrayRef)
|
||||
{
|
||||
if (hidMatchDictionary)
|
||||
CFRelease(hidMatchDictionary);
|
||||
CFDictionaryRef matchingCFDictRef =
|
||||
createMatchingDictionary(kHIDPage_GenericDesktop,
|
||||
kHIDUsage_GD_Joystick);
|
||||
if (matchingCFDictRef)
|
||||
{
|
||||
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||
CFRelease(matchingCFDictRef);
|
||||
}
|
||||
|
||||
return;
|
||||
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.iokit_js.managerRef,
|
||||
matchingCFArrayRef);
|
||||
CFRelease(matchingCFArrayRef);
|
||||
}
|
||||
|
||||
result = IOServiceGetMatchingServices(masterPort,
|
||||
hidMatchDictionary,
|
||||
&objectIterator);
|
||||
if (result != kIOReturnSuccess)
|
||||
return;
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.iokit_js.managerRef,
|
||||
&matchCallback, NULL);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.iokit_js.managerRef,
|
||||
&removeCallback, NULL);
|
||||
|
||||
if (!objectIterator)
|
||||
{
|
||||
// There are no joysticks
|
||||
return;
|
||||
}
|
||||
IOHIDManagerScheduleWithRunLoop(_glfw.iokit_js.managerRef,
|
||||
CFRunLoopGetMain(),
|
||||
kCFRunLoopDefaultMode);
|
||||
|
||||
while ((ioHIDDeviceObject = IOIteratorNext(objectIterator)))
|
||||
{
|
||||
CFMutableDictionaryRef propsRef = NULL;
|
||||
CFTypeRef valueRef = NULL;
|
||||
kern_return_t result;
|
||||
IOHIDManagerOpen(_glfw.iokit_js.managerRef, kIOHIDOptionsTypeNone);
|
||||
|
||||
IOCFPlugInInterface** ppPlugInInterface = NULL;
|
||||
HRESULT plugInResult = S_OK;
|
||||
SInt32 score = 0;
|
||||
|
||||
long usagePage = 0;
|
||||
long usage = 0;
|
||||
|
||||
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
|
||||
CFSTR(kIOHIDPrimaryUsagePageKey),
|
||||
kCFAllocatorDefault, kNilOptions);
|
||||
if (valueRef)
|
||||
{
|
||||
CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage);
|
||||
CFRelease(valueRef);
|
||||
}
|
||||
|
||||
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
|
||||
CFSTR(kIOHIDPrimaryUsageKey),
|
||||
kCFAllocatorDefault, kNilOptions);
|
||||
if (valueRef)
|
||||
{
|
||||
CFNumberGetValue(valueRef, kCFNumberLongType, &usage);
|
||||
CFRelease(valueRef);
|
||||
}
|
||||
|
||||
if (usagePage != kHIDPage_GenericDesktop)
|
||||
{
|
||||
// This device is not relevant to GLFW
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((usage != kHIDUsage_GD_Joystick &&
|
||||
usage != kHIDUsage_GD_GamePad &&
|
||||
usage != kHIDUsage_GD_MultiAxisController))
|
||||
{
|
||||
// This device is not relevant to GLFW
|
||||
continue;
|
||||
}
|
||||
|
||||
result = IORegistryEntryCreateCFProperties(ioHIDDeviceObject,
|
||||
&propsRef,
|
||||
kCFAllocatorDefault,
|
||||
kNilOptions);
|
||||
|
||||
if (result != kIOReturnSuccess)
|
||||
continue;
|
||||
|
||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
||||
joystick->present = GL_TRUE;
|
||||
|
||||
result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject,
|
||||
kIOHIDDeviceUserClientTypeID,
|
||||
kIOCFPlugInInterfaceID,
|
||||
&ppPlugInInterface,
|
||||
&score);
|
||||
|
||||
if (kIOReturnSuccess != result)
|
||||
{
|
||||
CFRelease(propsRef);
|
||||
return;
|
||||
}
|
||||
|
||||
plugInResult = (*ppPlugInInterface)->QueryInterface(
|
||||
ppPlugInInterface,
|
||||
CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
|
||||
(void *) &(joystick->interface));
|
||||
|
||||
if (plugInResult != S_OK)
|
||||
{
|
||||
CFRelease(propsRef);
|
||||
return;
|
||||
}
|
||||
|
||||
(*ppPlugInInterface)->Release(ppPlugInInterface);
|
||||
|
||||
(*(joystick->interface))->open(joystick->interface, 0);
|
||||
(*(joystick->interface))->setRemovalCallback(joystick->interface,
|
||||
removalCallback,
|
||||
joystick,
|
||||
joystick);
|
||||
|
||||
// Get product string
|
||||
valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDProductKey));
|
||||
if (valueRef)
|
||||
{
|
||||
CFStringGetCString(valueRef,
|
||||
joystick->name,
|
||||
sizeof(joystick->name),
|
||||
kCFStringEncodingUTF8);
|
||||
}
|
||||
|
||||
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||
|
||||
valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDElementKey));
|
||||
if (CFGetTypeID(valueRef) == CFArrayGetTypeID())
|
||||
{
|
||||
CFRange range = { 0, CFArrayGetCount(valueRef) };
|
||||
CFArrayApplyFunction(valueRef,
|
||||
range,
|
||||
getElementsCFArrayHandler,
|
||||
(void*) joystick);
|
||||
}
|
||||
|
||||
CFRelease(propsRef);
|
||||
|
||||
joystick->axes = calloc(CFArrayGetCount(joystick->axisElements),
|
||||
sizeof(float));
|
||||
joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) +
|
||||
CFArrayGetCount(joystick->hatElements) * 4, 1);
|
||||
|
||||
joy++;
|
||||
if (joy > GLFW_JOYSTICK_LAST)
|
||||
break;
|
||||
}
|
||||
// Execute the run loop once in order to register any initially-attached
|
||||
// joysticks
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
}
|
||||
|
||||
// Close all opened joystick handles
|
||||
//
|
||||
void _glfwTerminateJoysticks(void)
|
||||
{
|
||||
int i;
|
||||
int joy;
|
||||
|
||||
for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++)
|
||||
for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||
{
|
||||
_GLFWjoystickIOKit* joystick = &_glfw.iokit_js[i];
|
||||
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||
removeJoystick(joystick);
|
||||
|
||||
if (joystick->axisElements)
|
||||
CFRelease(joystick->axisElements);
|
||||
if (joystick->buttonElements)
|
||||
CFRelease(joystick->buttonElements);
|
||||
if (joystick->hatElements)
|
||||
CFRelease(joystick->hatElements);
|
||||
}
|
||||
|
||||
CFRelease(_glfw.iokit_js.managerRef);
|
||||
_glfw.iokit_js.managerRef = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -467,12 +468,12 @@ int _glfwPlatformJoystickPresent(int joy)
|
||||
{
|
||||
pollJoystickEvents();
|
||||
|
||||
return _glfw.iokit_js[joy].present;
|
||||
return _glfw.iokit_js.devices[joy].present;
|
||||
}
|
||||
|
||||
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||
{
|
||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
||||
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||
|
||||
pollJoystickEvents();
|
||||
|
||||
@@ -485,7 +486,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||
|
||||
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||
{
|
||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
||||
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||
|
||||
pollJoystickEvents();
|
||||
|
||||
@@ -501,6 +502,6 @@ const char* _glfwPlatformGetJoystickName(int joy)
|
||||
{
|
||||
pollJoystickEvents();
|
||||
|
||||
return _glfw.iokit_js[joy].name;
|
||||
return _glfw.iokit_js.devices[joy].name;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _linux_joystick_h_
|
||||
#define _linux_joystick_h_
|
||||
#ifndef _glfw3_linux_joystick_h_
|
||||
#define _glfw3_linux_joystick_h_
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
@@ -60,4 +60,4 @@ typedef struct _GLFWjoystickLinux
|
||||
int _glfwInitJoysticks(void);
|
||||
void _glfwTerminateJoysticks(void);
|
||||
|
||||
#endif // _linux_joystick_h_
|
||||
#endif // _glfw3_linux_joystick_h_
|
||||
|
||||
+10
-4
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.1 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
// 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
|
||||
@@ -55,6 +55,9 @@ int _glfwPlatformInit(void)
|
||||
if (!_glfwInitContextAPI())
|
||||
return GL_FALSE;
|
||||
|
||||
// Need the default conf for when we set a NULL cursor
|
||||
_glfw.mir.default_conf = mir_cursor_configuration_from_name(mir_arrow_cursor_name);
|
||||
|
||||
_glfwInitTimer();
|
||||
_glfwInitJoysticks();
|
||||
|
||||
@@ -87,15 +90,18 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
const char* version = _GLFW_VERSION_NUMBER " Mir EGL"
|
||||
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
|
||||
;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
+36
-4
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.1 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
// 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
|
||||
@@ -86,6 +86,39 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* 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;
|
||||
@@ -106,9 +139,8 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* 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;
|
||||
modes[*found].redBits = 8;
|
||||
modes[*found].greenBits = 8;
|
||||
modes[*found].blueBits = 8;
|
||||
|
||||
FillInRGBBitsFromPixelFormat(&modes[*found], out->output_formats[*found]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
+12
-8
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.1 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
// 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
|
||||
@@ -24,18 +24,18 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _mir_platform_h_
|
||||
#define _mir_platform_h_
|
||||
#ifndef _glfw3_mir_platform_h_
|
||||
#define _glfw3_mir_platform_h_
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
#include "posix_tls.h"
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
#if defined(_GLFW_EGL)
|
||||
#include "egl_context.h"
|
||||
@@ -51,6 +51,7 @@
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir
|
||||
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir
|
||||
|
||||
|
||||
// Mir-specific Event Queue
|
||||
//
|
||||
typedef struct EventQueue
|
||||
@@ -88,6 +89,7 @@ typedef struct _GLFWlibraryMir
|
||||
{
|
||||
MirConnection* connection;
|
||||
MirEGLNativeDisplayType display;
|
||||
MirCursorConfiguration* default_conf;
|
||||
EventQueue* event_queue;
|
||||
|
||||
pthread_mutex_t event_mutex;
|
||||
@@ -101,10 +103,12 @@ typedef struct _GLFWlibraryMir
|
||||
//
|
||||
typedef struct _GLFWcursorMir
|
||||
{
|
||||
MirCursorConfiguration* conf;
|
||||
MirBufferStream* custom_cursor;
|
||||
} _GLFWcursorMir;
|
||||
|
||||
|
||||
extern void _glfwInitEventQueue(EventQueue* queue);
|
||||
extern void _glfwDeleteEventQueue(EventQueue* queue);
|
||||
|
||||
#endif // _mir_platform_h_
|
||||
#endif // _glfw3_mir_platform_h_
|
||||
|
||||
+237
-123
@@ -1,7 +1,7 @@
|
||||
//========================================================================
|
||||
// GLFW 3.1 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
// 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
|
||||
@@ -25,7 +25,6 @@
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
@@ -35,13 +34,13 @@
|
||||
typedef struct EventNode
|
||||
{
|
||||
TAILQ_ENTRY(EventNode) entries;
|
||||
MirEvent* event;
|
||||
const MirEvent* event;
|
||||
_GLFWwindow* window;
|
||||
} EventNode;
|
||||
|
||||
static void deleteNode(EventQueue* queue, EventNode* node)
|
||||
{
|
||||
free(node->event);
|
||||
mir_event_unref(node->event);
|
||||
free(node);
|
||||
}
|
||||
|
||||
@@ -50,17 +49,19 @@ static int emptyEventQueue(EventQueue* queue)
|
||||
return queue->head.tqh_first == NULL ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
|
||||
static EventNode* newEventNode(MirEvent const* event, _GLFWwindow* context)
|
||||
// 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 = calloc(1, sizeof(MirEvent));
|
||||
new_node->event = mir_event_ref(event);
|
||||
new_node->window = context;
|
||||
|
||||
memcpy(new_node->event, event, sizeof(MirEvent));
|
||||
return new_node;
|
||||
}
|
||||
|
||||
static void enqueueEvent(MirEvent const* event, _GLFWwindow* context)
|
||||
static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
|
||||
{
|
||||
pthread_mutex_lock(&_glfw.mir.event_mutex);
|
||||
|
||||
@@ -88,6 +89,9 @@ static EventNode* dequeueEvent(EventQueue* queue)
|
||||
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;
|
||||
@@ -114,13 +118,13 @@ static int mirModToGLFWMod(uint32_t mods)
|
||||
{
|
||||
int publicMods = 0x0;
|
||||
|
||||
if (mods & mir_key_modifier_alt)
|
||||
if (mods & mir_input_event_modifier_alt)
|
||||
publicMods |= GLFW_MOD_ALT;
|
||||
else if (mods & mir_key_modifier_shift)
|
||||
else if (mods & mir_input_event_modifier_shift)
|
||||
publicMods |= GLFW_MOD_SHIFT;
|
||||
else if (mods & mir_key_modifier_ctrl)
|
||||
else if (mods & mir_input_event_modifier_ctrl)
|
||||
publicMods |= GLFW_MOD_CONTROL;
|
||||
else if (mods & mir_key_modifier_meta)
|
||||
else if (mods & mir_input_event_modifier_meta)
|
||||
publicMods |= GLFW_MOD_SUPER;
|
||||
|
||||
return publicMods;
|
||||
@@ -251,97 +255,93 @@ static int toGLFWKeyCode(uint32_t key)
|
||||
}
|
||||
}
|
||||
|
||||
static void handleKeyEvent(const MirKeyEvent key, _GLFWwindow* window)
|
||||
static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
|
||||
{
|
||||
const int pressed = key.action == mir_key_action_up ? GLFW_RELEASE : GLFW_PRESS;
|
||||
const int mods = mirModToGLFWMod(key.modifiers);
|
||||
const long text = _glfwKeySym2Unicode(key.key_code);
|
||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
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);
|
||||
|
||||
_glfwInputKey(window, toGLFWKeyCode(key.scan_code), key.scan_code, pressed, mods);
|
||||
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 handleMouseButton(_GLFWwindow* window,
|
||||
int pressed, int mods, MirMotionButton button)
|
||||
static void handlePointerButton(_GLFWwindow* window,
|
||||
int pressed,
|
||||
const MirPointerEvent* pointer_event)
|
||||
{
|
||||
static int lastButton;
|
||||
MirPointerButton button = mir_pointer_event_buttons (pointer_event);
|
||||
int mods = mir_pointer_event_modifiers(pointer_event);
|
||||
const int publicMods = mirModToGLFWMod(mods);
|
||||
int publicButton;
|
||||
const int publicMods = mirModToGLFWMod(mods);
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case mir_motion_button_primary:
|
||||
case mir_pointer_button_primary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_LEFT;
|
||||
break;
|
||||
case mir_motion_button_secondary:
|
||||
case mir_pointer_button_secondary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_RIGHT;
|
||||
break;
|
||||
case mir_motion_button_tertiary:
|
||||
case mir_pointer_button_tertiary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
break;
|
||||
case mir_motion_button_forward:
|
||||
case mir_pointer_button_forward:
|
||||
// FIXME What is the forward button?
|
||||
publicButton = GLFW_MOUSE_BUTTON_4;
|
||||
break;
|
||||
case mir_motion_button_back:
|
||||
case mir_pointer_button_back:
|
||||
// FIXME What is the back button?
|
||||
publicButton = GLFW_MOUSE_BUTTON_5;
|
||||
break;
|
||||
default:
|
||||
publicButton = lastButton;
|
||||
break;
|
||||
}
|
||||
|
||||
lastButton = publicButton;
|
||||
|
||||
_glfwInputMouseClick(window, publicButton, pressed, publicMods);
|
||||
}
|
||||
|
||||
static void handleMouseMotion(_GLFWwindow* window, int x, int y)
|
||||
static void handlePointerMotion(_GLFWwindow* window,
|
||||
const MirPointerEvent* pointer_event)
|
||||
{
|
||||
_glfwInputCursorMotion(window, x, y);
|
||||
int current_x = window->cursorPosX;
|
||||
int current_y = window->cursorPosY;
|
||||
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);
|
||||
|
||||
if (current_x != x || current_y != y)
|
||||
_glfwInputCursorMotion(window, x, y);
|
||||
if (dx != 0 || dy != 0)
|
||||
_glfwInputScroll(window, dx, dy);
|
||||
}
|
||||
|
||||
static void handleMouseScroll(_GLFWwindow* window, int dx, int dy)
|
||||
{
|
||||
_glfwInputScroll(window, dx, dy);
|
||||
}
|
||||
|
||||
static void handleMouseEvent(const MirMotionEvent motion,
|
||||
int cord_index,
|
||||
static void handlePointerEvent(const MirPointerEvent* pointer_event,
|
||||
_GLFWwindow* window)
|
||||
{
|
||||
switch (motion.action)
|
||||
int action = mir_pointer_event_action(pointer_event);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case mir_motion_action_down:
|
||||
case mir_motion_action_pointer_down:
|
||||
handleMouseButton(window, GLFW_PRESS,
|
||||
motion.modifiers, motion.button_state);
|
||||
case mir_pointer_action_button_down:
|
||||
handlePointerButton(window, GLFW_PRESS, pointer_event);
|
||||
break;
|
||||
case mir_motion_action_up:
|
||||
case mir_motion_action_pointer_up:
|
||||
handleMouseButton(window, GLFW_RELEASE,
|
||||
motion.modifiers, motion.button_state);
|
||||
case mir_pointer_action_button_up:
|
||||
handlePointerButton(window, GLFW_RELEASE, pointer_event);
|
||||
break;
|
||||
case mir_motion_action_hover_move:
|
||||
case mir_motion_action_move:
|
||||
handleMouseMotion(window,
|
||||
motion.pointer_coordinates[cord_index].x,
|
||||
motion.pointer_coordinates[cord_index].y);
|
||||
case mir_pointer_action_motion:
|
||||
handlePointerMotion(window, pointer_event);
|
||||
break;
|
||||
case mir_motion_action_outside:
|
||||
break;
|
||||
case mir_motion_action_scroll:
|
||||
handleMouseScroll(window,
|
||||
motion.pointer_coordinates[cord_index].hscroll,
|
||||
motion.pointer_coordinates[cord_index].vscroll);
|
||||
break;
|
||||
case mir_motion_action_cancel:
|
||||
case mir_motion_action_hover_enter:
|
||||
case mir_motion_action_hover_exit:
|
||||
case mir_pointer_action_enter:
|
||||
case mir_pointer_action_leave:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -349,61 +349,66 @@ static void handleMouseEvent(const MirMotionEvent motion,
|
||||
}
|
||||
}
|
||||
|
||||
static void handleMotionEvent(const MirMotionEvent motion, _GLFWwindow* window)
|
||||
static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < motion.pointer_count; i++)
|
||||
handleMouseEvent(motion, i, window);
|
||||
}
|
||||
int type = mir_input_event_get_type(input_event);
|
||||
|
||||
static void handleInput(MirEvent const* event, _GLFWwindow* window)
|
||||
{
|
||||
switch (event->type)
|
||||
switch (type)
|
||||
{
|
||||
case mir_event_type_key:
|
||||
handleKeyEvent(event->key, window);
|
||||
case mir_input_event_type_key:
|
||||
handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
|
||||
break;
|
||||
case mir_event_type_motion:
|
||||
handleMotionEvent(event->motion, window);
|
||||
case mir_input_event_type_pointer:
|
||||
handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void addNewEvent(MirSurface* surface, MirEvent const* event, void* context)
|
||||
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 int createSurface(_GLFWwindow* window)
|
||||
{
|
||||
MirSurfaceParameters params =
|
||||
{
|
||||
.name = "MirSurface",
|
||||
.width = window->mir.width,
|
||||
.height = window->mir.height,
|
||||
.pixel_format = mir_pixel_format_invalid,
|
||||
.buffer_usage = mir_buffer_usage_hardware,
|
||||
.output_id = mir_display_output_id_invalid
|
||||
};
|
||||
MirSurfaceSpec* spec;
|
||||
MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
|
||||
MirPixelFormat pixel_format = findValidPixelFormat();
|
||||
|
||||
MirEventDelegate delegate =
|
||||
{
|
||||
addNewEvent,
|
||||
window
|
||||
};
|
||||
|
||||
params.pixel_format = findValidPixelFormat();
|
||||
if (params.pixel_format == mir_pixel_format_invalid)
|
||||
if (pixel_format == mir_pixel_format_invalid)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unable to find a correct pixel format");
|
||||
return GL_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);
|
||||
|
||||
window->mir.surface =
|
||||
mir_connection_create_surface_sync(_glfw.mir.connection, ¶ms);
|
||||
if (!mir_surface_is_valid(window->mir.surface))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@@ -413,7 +418,7 @@ static int createSurface(_GLFWwindow* window)
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
mir_surface_set_event_handler(window->mir.surface, &delegate);
|
||||
mir_surface_set_event_handler(window->mir.surface, addNewEvent, window);
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
@@ -471,7 +476,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Requested surface size too large: %ix%i",
|
||||
wndconfig->width, wndconfig->height);
|
||||
wndconfig->width, wndconfig->height);
|
||||
|
||||
return GL_FALSE;
|
||||
}
|
||||
@@ -483,7 +488,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
if (!createSurface(window))
|
||||
return GL_FALSE;
|
||||
|
||||
window->mir.window = mir_surface_get_egl_native_window(window->mir.surface);
|
||||
window->mir.window = mir_buffer_stream_get_egl_native_window(
|
||||
mir_surface_get_buffer_stream(window->mir.surface));
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
@@ -501,8 +507,26 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
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 _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 _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
@@ -525,12 +549,6 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
@@ -551,14 +569,24 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
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 _glfwPlatformUnhideWindow(_GLFWwindow* window)
|
||||
@@ -583,9 +611,7 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||
|
||||
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
return GL_FALSE;
|
||||
return mir_surface_get_visibility(window->mir.surface) == mir_surface_visibility_exposed;
|
||||
}
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
@@ -594,7 +620,7 @@ void _glfwPlatformPollEvents(void)
|
||||
|
||||
while ((node = dequeueEvent(_glfw.mir.event_queue)))
|
||||
{
|
||||
handleInput(node->event, node->window);
|
||||
handleEvent(node->event, node->window);
|
||||
deleteNode(_glfw.mir.event_queue, node);
|
||||
}
|
||||
}
|
||||
@@ -623,34 +649,122 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh
|
||||
*height = window->mir.height;
|
||||
}
|
||||
|
||||
// FIXME implement
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
MirBufferStream* stream;
|
||||
MirPixelFormat pixel_format = findValidPixelFormat();
|
||||
|
||||
return GL_FALSE;
|
||||
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 GL_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 GL_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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
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 GL_TRUE;
|
||||
}
|
||||
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
if (cursor && cursor->mir.conf)
|
||||
{
|
||||
mir_wait_for(mir_surface_configure_cursor(window->mir.surface, cursor->mir.conf));
|
||||
if (cursor->mir.custom_cursor)
|
||||
{
|
||||
/* FIXME Bug https://bugs.launchpad.net/mir/+bug/1477285
|
||||
Requires a triple buffer swap to get the cursor buffer on top! (since mir is tripled buffered)
|
||||
*/
|
||||
mir_buffer_stream_swap_buffers_sync(cursor->mir.custom_cursor);
|
||||
mir_buffer_stream_swap_buffers_sync(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)
|
||||
|
||||
@@ -305,6 +305,10 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count)
|
||||
GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfw.monitorCount)
|
||||
return NULL;
|
||||
|
||||
return (GLFWmonitor*) _glfw.monitors[0];
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -24,8 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _nsgl_context_h_
|
||||
#define _nsgl_context_h_
|
||||
#ifndef _glfw3_nsgl_context_h_
|
||||
#define _glfw3_nsgl_context_h_
|
||||
|
||||
#define _GLFW_PLATFORM_FBCONFIG
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl
|
||||
@@ -59,4 +59,4 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContext(_GLFWwindow* window);
|
||||
|
||||
#endif // _nsgl_context_h_
|
||||
#endif // _glfw3_nsgl_context_h_
|
||||
|
||||
+7
-7
@@ -35,7 +35,7 @@
|
||||
//
|
||||
int _glfwInitContextAPI(void)
|
||||
{
|
||||
if (!_glfwInitTLS())
|
||||
if (!_glfwCreateContextTLS())
|
||||
return GL_FALSE;
|
||||
|
||||
_glfw.nsgl.framework =
|
||||
@@ -54,7 +54,7 @@ int _glfwInitContextAPI(void)
|
||||
//
|
||||
void _glfwTerminateContextAPI(void)
|
||||
{
|
||||
_glfwTerminateTLS();
|
||||
_glfwDestroyContextTLS();
|
||||
}
|
||||
|
||||
// Create the OpenGL context
|
||||
@@ -67,8 +67,8 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (ctxconfig->api == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"NSGL: This API does not support OpenGL ES");
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"NSGL: OpenGL ES is not available on OS X");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
@@ -211,8 +211,8 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
if (window->nsgl.pixelFormat == nil)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"NSGL: Failed to create OpenGL pixel format");
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"NSGL: Failed to find a suitable pixel format");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
|
||||
else
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
_glfwSetCurrentContext(window);
|
||||
_glfwSetContextTLS(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapBuffers(_GLFWwindow* window)
|
||||
|
||||
+3
-3
@@ -25,8 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _posix_time_h_
|
||||
#define _posix_time_h_
|
||||
#ifndef _glfw3_posix_time_h_
|
||||
#define _glfw3_posix_time_h_
|
||||
|
||||
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time
|
||||
|
||||
@@ -46,4 +46,4 @@ typedef struct _GLFWtimePOSIX
|
||||
|
||||
void _glfwInitTimer(void);
|
||||
|
||||
#endif // _posix_time_h_
|
||||
#endif // _glfw3_posix_time_h_
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwInitTLS(void)
|
||||
int _glfwCreateContextTLS(void)
|
||||
{
|
||||
if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0)
|
||||
{
|
||||
@@ -44,12 +44,12 @@ int _glfwInitTLS(void)
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateTLS(void)
|
||||
void _glfwDestroyContextTLS(void)
|
||||
{
|
||||
pthread_key_delete(_glfw.posix_tls.context);
|
||||
}
|
||||
|
||||
void _glfwSetCurrentContext(_GLFWwindow* context)
|
||||
void _glfwSetContextTLS(_GLFWwindow* context)
|
||||
{
|
||||
pthread_setspecific(_glfw.posix_tls.context, context);
|
||||
}
|
||||
|
||||
+6
-6
@@ -25,8 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _posix_tls_h_
|
||||
#define _posix_tls_h_
|
||||
#ifndef _glfw3_posix_tls_h_
|
||||
#define _glfw3_posix_tls_h_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -42,8 +42,8 @@ typedef struct _GLFWtlsPOSIX
|
||||
} _GLFWtlsPOSIX;
|
||||
|
||||
|
||||
int _glfwInitTLS(void);
|
||||
void _glfwTerminateTLS(void);
|
||||
void _glfwSetCurrentContext(_GLFWwindow* context);
|
||||
int _glfwCreateContextTLS(void);
|
||||
void _glfwDestroyContextTLS(void);
|
||||
void _glfwSetContextTLS(_GLFWwindow* context);
|
||||
|
||||
#endif // _posix_tls_h_
|
||||
#endif // _glfw3_posix_tls_h_
|
||||
|
||||
+120
-140
@@ -33,110 +33,67 @@
|
||||
|
||||
|
||||
// Initialize WGL-specific extensions
|
||||
// This function is called once before initial context creation, i.e. before
|
||||
// any WGL extensions could be present. This is done in order to have both
|
||||
// extension variable clearing and loading in the same place, hopefully
|
||||
// decreasing the possibility of forgetting to add one without the other.
|
||||
//
|
||||
static void initWGLExtensions(_GLFWwindow* window)
|
||||
{
|
||||
// This needs to include every function pointer loaded below
|
||||
window->wgl.SwapIntervalEXT = NULL;
|
||||
window->wgl.GetPixelFormatAttribivARB = NULL;
|
||||
window->wgl.GetExtensionsStringARB = NULL;
|
||||
window->wgl.GetExtensionsStringEXT = NULL;
|
||||
window->wgl.CreateContextAttribsARB = NULL;
|
||||
// Functions for WGL_EXT_extension_string
|
||||
// NOTE: These are needed by _glfwPlatformExtensionSupported
|
||||
window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
|
||||
_glfw_wglGetProcAddress("wglGetExtensionsStringEXT");
|
||||
window->wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
|
||||
_glfw_wglGetProcAddress("wglGetExtensionsStringARB");
|
||||
|
||||
// Functions for WGL_ARB_create_context
|
||||
window->wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
||||
_glfw_wglGetProcAddress("wglCreateContextAttribsARB");
|
||||
|
||||
// Functions for WGL_EXT_swap_control
|
||||
window->wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
|
||||
_glfw_wglGetProcAddress("wglSwapIntervalEXT");
|
||||
|
||||
// Functions for WGL_ARB_pixel_format
|
||||
window->wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
|
||||
_glfw_wglGetProcAddress("wglGetPixelFormatAttribivARB");
|
||||
|
||||
// This needs to include every extension used below except for
|
||||
// WGL_ARB_extensions_string and WGL_EXT_extensions_string
|
||||
window->wgl.ARB_multisample = GL_FALSE;
|
||||
window->wgl.ARB_framebuffer_sRGB = GL_FALSE;
|
||||
window->wgl.ARB_create_context = GL_FALSE;
|
||||
window->wgl.ARB_create_context_profile = GL_FALSE;
|
||||
window->wgl.EXT_create_context_es2_profile = GL_FALSE;
|
||||
window->wgl.ARB_create_context_robustness = GL_FALSE;
|
||||
window->wgl.EXT_swap_control = GL_FALSE;
|
||||
window->wgl.ARB_pixel_format = GL_FALSE;
|
||||
window->wgl.ARB_context_flush_control = GL_FALSE;
|
||||
|
||||
window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringEXT");
|
||||
if (!window->wgl.GetExtensionsStringEXT)
|
||||
{
|
||||
window->wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringARB");
|
||||
if (!window->wgl.GetExtensionsStringARB)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_multisample"))
|
||||
window->wgl.ARB_multisample = GL_TRUE;
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB"))
|
||||
window->wgl.ARB_framebuffer_sRGB = GL_TRUE;
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_create_context"))
|
||||
{
|
||||
window->wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
||||
wglGetProcAddress("wglCreateContextAttribsARB");
|
||||
|
||||
if (window->wgl.CreateContextAttribsARB)
|
||||
window->wgl.ARB_create_context = GL_TRUE;
|
||||
}
|
||||
|
||||
if (window->wgl.ARB_create_context)
|
||||
{
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_profile"))
|
||||
window->wgl.ARB_create_context_profile = GL_TRUE;
|
||||
}
|
||||
|
||||
if (window->wgl.ARB_create_context &&
|
||||
window->wgl.ARB_create_context_profile)
|
||||
{
|
||||
if (_glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile"))
|
||||
window->wgl.EXT_create_context_es2_profile = GL_TRUE;
|
||||
}
|
||||
|
||||
if (window->wgl.ARB_create_context)
|
||||
{
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness"))
|
||||
window->wgl.ARB_create_context_robustness = GL_TRUE;
|
||||
}
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_EXT_swap_control"))
|
||||
{
|
||||
window->wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
|
||||
wglGetProcAddress("wglSwapIntervalEXT");
|
||||
|
||||
if (window->wgl.SwapIntervalEXT)
|
||||
window->wgl.EXT_swap_control = GL_TRUE;
|
||||
}
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_pixel_format"))
|
||||
{
|
||||
window->wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
|
||||
wglGetProcAddress("wglGetPixelFormatAttribivARB");
|
||||
|
||||
if (window->wgl.GetPixelFormatAttribivARB)
|
||||
window->wgl.ARB_pixel_format = GL_TRUE;
|
||||
}
|
||||
|
||||
if (_glfwPlatformExtensionSupported("WGL_ARB_context_flush_control"))
|
||||
window->wgl.ARB_context_flush_control = GL_TRUE;
|
||||
window->wgl.ARB_multisample =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_multisample");
|
||||
window->wgl.ARB_framebuffer_sRGB =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB");
|
||||
window->wgl.EXT_framebuffer_sRGB =
|
||||
_glfwPlatformExtensionSupported("WGL_EXT_framebuffer_sRGB");
|
||||
window->wgl.ARB_create_context =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_create_context");
|
||||
window->wgl.ARB_create_context_profile =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_create_context_profile");
|
||||
window->wgl.EXT_create_context_es2_profile =
|
||||
_glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile");
|
||||
window->wgl.ARB_create_context_robustness =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness");
|
||||
window->wgl.EXT_swap_control =
|
||||
_glfwPlatformExtensionSupported("WGL_EXT_swap_control");
|
||||
window->wgl.ARB_pixel_format =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_pixel_format");
|
||||
window->wgl.ARB_context_flush_control =
|
||||
_glfwPlatformExtensionSupported("WGL_ARB_context_flush_control");
|
||||
}
|
||||
|
||||
// Returns the specified attribute of the specified pixel format
|
||||
// NOTE: Do not call this unless we have found WGL_ARB_pixel_format
|
||||
//
|
||||
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
assert(window->wgl.ARB_pixel_format);
|
||||
|
||||
if (!window->wgl.GetPixelFormatAttribivARB(window->wgl.dc,
|
||||
pixelFormat,
|
||||
0, 1, &attrib, &value))
|
||||
{
|
||||
// NOTE: We should probably handle this error somehow
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve pixel format attribute %i",
|
||||
attrib);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -177,7 +134,8 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
|
||||
|
||||
if (window->wgl.ARB_pixel_format)
|
||||
{
|
||||
// Get pixel format attributes through 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))
|
||||
{
|
||||
@@ -219,7 +177,8 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
|
||||
if (window->wgl.ARB_multisample)
|
||||
u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);
|
||||
|
||||
if (window->wgl.ARB_framebuffer_sRGB)
|
||||
if (window->wgl.ARB_framebuffer_sRGB ||
|
||||
window->wgl.EXT_framebuffer_sRGB)
|
||||
{
|
||||
if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
|
||||
u->sRGB = GL_TRUE;
|
||||
@@ -229,7 +188,7 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
// Get pixel format attributes through old-fashioned PFDs
|
||||
// Get pixel format attributes through legacy PFDs
|
||||
|
||||
if (!DescribePixelFormat(window->wgl.dc,
|
||||
n,
|
||||
@@ -291,7 +250,7 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
|
||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
||||
if (!closest)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"WGL: Failed to find a suitable pixel format");
|
||||
|
||||
free(usableConfigs);
|
||||
@@ -313,7 +272,7 @@ static GLboolean choosePixelFormat(_GLFWwindow* window,
|
||||
//
|
||||
int _glfwInitContextAPI(void)
|
||||
{
|
||||
if (!_glfwInitTLS())
|
||||
if (!_glfwCreateContextTLS())
|
||||
return GL_FALSE;
|
||||
|
||||
_glfw.wgl.opengl32.instance = LoadLibraryW(L"opengl32.dll");
|
||||
@@ -323,6 +282,28 @@ int _glfwInitContextAPI(void)
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
_glfw.wgl.opengl32.CreateContext = (WGLCREATECONTEXT_T)
|
||||
GetProcAddress(_glfw.wgl.opengl32.instance, "wglCreateContext");
|
||||
_glfw.wgl.opengl32.DeleteContext = (WGLDELETECONTEXT_T)
|
||||
GetProcAddress(_glfw.wgl.opengl32.instance, "wglDeleteContext");
|
||||
_glfw.wgl.opengl32.GetProcAddress = (WGLGETPROCADDRESS_T)
|
||||
GetProcAddress(_glfw.wgl.opengl32.instance, "wglGetProcAddress");
|
||||
_glfw.wgl.opengl32.MakeCurrent = (WGLMAKECURRENT_T)
|
||||
GetProcAddress(_glfw.wgl.opengl32.instance, "wglMakeCurrent");
|
||||
_glfw.wgl.opengl32.ShareLists = (WGLSHARELISTS_T)
|
||||
GetProcAddress(_glfw.wgl.opengl32.instance, "wglShareLists");
|
||||
|
||||
if (!_glfw.wgl.opengl32.CreateContext ||
|
||||
!_glfw.wgl.opengl32.DeleteContext ||
|
||||
!_glfw.wgl.opengl32.GetProcAddress ||
|
||||
!_glfw.wgl.opengl32.MakeCurrent ||
|
||||
!_glfw.wgl.opengl32.ShareLists)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to load opengl32 functions");
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
@@ -333,7 +314,7 @@ void _glfwTerminateContextAPI(void)
|
||||
if (_glfw.wgl.opengl32.instance)
|
||||
FreeLibrary(_glfw.wgl.opengl32.instance);
|
||||
|
||||
_glfwTerminateTLS();
|
||||
_glfwDestroyContextTLS();
|
||||
}
|
||||
|
||||
#define setWGLattrib(attribName, attribValue) \
|
||||
@@ -384,20 +365,17 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (window->wgl.ARB_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0, strategy = 0;
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->api == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
@@ -410,9 +388,15 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (window->wgl.ARB_create_context_robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
strategy = WGL_NO_RESET_NOTIFICATION_ARB;
|
||||
{
|
||||
setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_NO_RESET_NOTIFICATION_ARB);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB;
|
||||
{
|
||||
setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_LOSE_CONTEXT_ON_RESET_ARB);
|
||||
}
|
||||
|
||||
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
@@ -435,12 +419,11 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// NOTE: Only request an explicitly versioned context when
|
||||
// necessary, as explicitly requesting version 1.0 does not
|
||||
// always return the highest available version
|
||||
|
||||
setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
@@ -451,9 +434,6 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
if (mask)
|
||||
setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
|
||||
if (strategy)
|
||||
setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy);
|
||||
|
||||
setWGLattrib(0, 0);
|
||||
|
||||
window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc,
|
||||
@@ -468,7 +448,7 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
}
|
||||
else
|
||||
{
|
||||
window->wgl.context = wglCreateContext(window->wgl.dc);
|
||||
window->wgl.context = _glfw_wglCreateContext(window->wgl.dc);
|
||||
if (!window->wgl.context)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
@@ -478,7 +458,7 @@ int _glfwCreateContext(_GLFWwindow* window,
|
||||
|
||||
if (share)
|
||||
{
|
||||
if (!wglShareLists(share, window->wgl.context))
|
||||
if (!_glfw_wglShareLists(share, window->wgl.context))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to enable sharing with specified OpenGL context");
|
||||
@@ -501,7 +481,7 @@ void _glfwDestroyContext(_GLFWwindow* window)
|
||||
{
|
||||
if (window->wgl.context)
|
||||
{
|
||||
wglDeleteContext(window->wgl.context);
|
||||
_glfw_wglDeleteContext(window->wgl.context);
|
||||
window->wgl.context = NULL;
|
||||
}
|
||||
|
||||
@@ -580,24 +560,18 @@ int _glfwAnalyzeContext(const _GLFWwindow* window,
|
||||
|
||||
if (fbconfig->samples > 0)
|
||||
{
|
||||
// We want FSAA, but can we get it?
|
||||
// FSAA is not a hard constraint, so otherwise we just don't care
|
||||
|
||||
// MSAA is not a hard constraint, so do nothing if it's not supported
|
||||
if (window->wgl.ARB_multisample && window->wgl.ARB_pixel_format)
|
||||
{
|
||||
// We appear to have both the extension and the means to ask for it
|
||||
required = GL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (fbconfig->sRGB)
|
||||
{
|
||||
// We want sRGB, but can we get it?
|
||||
// sRGB is not a hard constraint, so otherwise we just don't care
|
||||
|
||||
if (window->wgl.ARB_framebuffer_sRGB && window->wgl.ARB_pixel_format)
|
||||
// sRGB is not a hard constraint, so do nothing if it's not supported
|
||||
if ((window->wgl.ARB_framebuffer_sRGB ||
|
||||
window->wgl.EXT_framebuffer_sRGB) &&
|
||||
window->wgl.ARB_pixel_format)
|
||||
{
|
||||
// We appear to have both the extension and the means to ask for it
|
||||
required = GL_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -616,15 +590,23 @@ int _glfwAnalyzeContext(const _GLFWwindow* window,
|
||||
void _glfwPlatformMakeContextCurrent(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
wglMakeCurrent(window->wgl.dc, window->wgl.context);
|
||||
_glfw_wglMakeCurrent(window->wgl.dc, window->wgl.context);
|
||||
else
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
_glfw_wglMakeCurrent(NULL, NULL);
|
||||
|
||||
_glfwSetCurrentContext(window);
|
||||
_glfwSetContextTLS(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSwapBuffers(_GLFWwindow* window)
|
||||
{
|
||||
// HACK: Use DwmFlush when desktop composition is enabled
|
||||
if (_glfwIsCompositionEnabled() && !window->monitor)
|
||||
{
|
||||
int count = abs(window->wgl.interval);
|
||||
while (count--)
|
||||
_glfw_DwmFlush();
|
||||
}
|
||||
|
||||
SwapBuffers(window->wgl.dc);
|
||||
}
|
||||
|
||||
@@ -632,14 +614,12 @@ void _glfwPlatformSwapInterval(int interval)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||
|
||||
#if !defined(_GLFW_USE_DWM_SWAP_INTERVAL)
|
||||
if (_glfwIsCompositionEnabled() && interval)
|
||||
{
|
||||
// Don't enabled vsync when desktop compositing is enabled, as it leads
|
||||
// to frame jitter
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
window->wgl.interval = interval;
|
||||
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||
// avoid interfering with DWM vsync
|
||||
if (_glfwIsCompositionEnabled() && !window->monitor)
|
||||
interval = 0;
|
||||
|
||||
if (window->wgl.EXT_swap_control)
|
||||
window->wgl.SwapIntervalEXT(interval);
|
||||
@@ -647,14 +627,14 @@ void _glfwPlatformSwapInterval(int interval)
|
||||
|
||||
int _glfwPlatformExtensionSupported(const char* extension)
|
||||
{
|
||||
const GLubyte* extensions;
|
||||
const char* extensions;
|
||||
|
||||
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
|
||||
|
||||
if (window->wgl.GetExtensionsStringEXT != NULL)
|
||||
{
|
||||
extensions = (GLubyte*) window->wgl.GetExtensionsStringEXT();
|
||||
if (extensions != NULL)
|
||||
extensions = window->wgl.GetExtensionsStringEXT();
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GL_TRUE;
|
||||
@@ -663,8 +643,8 @@ int _glfwPlatformExtensionSupported(const char* extension)
|
||||
|
||||
if (window->wgl.GetExtensionsStringARB != NULL)
|
||||
{
|
||||
extensions = (GLubyte*) window->wgl.GetExtensionsStringARB(window->wgl.dc);
|
||||
if (extensions != NULL)
|
||||
extensions = window->wgl.GetExtensionsStringARB(window->wgl.dc);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GL_TRUE;
|
||||
@@ -676,7 +656,7 @@ int _glfwPlatformExtensionSupported(const char* extension)
|
||||
|
||||
GLFWglproc _glfwPlatformGetProcAddress(const char* procname)
|
||||
{
|
||||
const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
|
||||
const GLFWglproc proc = (GLFWglproc) _glfw_wglGetProcAddress(procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
|
||||
|
||||
+23
-5
@@ -25,14 +25,26 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _wgl_context_h_
|
||||
#define _wgl_context_h_
|
||||
#ifndef _glfw3_wgl_context_h_
|
||||
#define _glfw3_wgl_context_h_
|
||||
|
||||
// This path may need to be changed if you build GLFW using your own setup
|
||||
// We ship and use our own copy of wglext.h since GLFW uses fairly new
|
||||
// extensions and not all operating systems come with an up-to-date version
|
||||
#include "../deps/GL/wglext.h"
|
||||
|
||||
// opengl32.dll function pointer typedefs
|
||||
typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC);
|
||||
typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC);
|
||||
typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR);
|
||||
typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC);
|
||||
typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
|
||||
#define _glfw_wglCreateContext _glfw.wgl.opengl32.CreateContext
|
||||
#define _glfw_wglDeleteContext _glfw.wgl.opengl32.DeleteContext
|
||||
#define _glfw_wglGetProcAddress _glfw.wgl.opengl32.GetProcAddress
|
||||
#define _glfw_wglMakeCurrent _glfw.wgl.opengl32.MakeCurrent
|
||||
#define _glfw_wglShareLists _glfw.wgl.opengl32.ShareLists
|
||||
|
||||
#define _GLFW_PLATFORM_FBCONFIG int wgl
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl
|
||||
@@ -44,6 +56,7 @@ typedef struct _GLFWcontextWGL
|
||||
{
|
||||
HDC dc; // Private GDI device context
|
||||
HGLRC context; // Permanent rendering context
|
||||
int interval;
|
||||
|
||||
// WGL extensions (context specific)
|
||||
PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT;
|
||||
@@ -54,6 +67,7 @@ typedef struct _GLFWcontextWGL
|
||||
GLboolean EXT_swap_control;
|
||||
GLboolean ARB_multisample;
|
||||
GLboolean ARB_framebuffer_sRGB;
|
||||
GLboolean EXT_framebuffer_sRGB;
|
||||
GLboolean ARB_pixel_format;
|
||||
GLboolean ARB_create_context;
|
||||
GLboolean ARB_create_context_profile;
|
||||
@@ -68,9 +82,13 @@ typedef struct _GLFWcontextWGL
|
||||
//
|
||||
typedef struct _GLFWlibraryWGL
|
||||
{
|
||||
// opengl32.dll (for glfwGetProcAddress)
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
HINSTANCE instance;
|
||||
WGLCREATECONTEXT_T CreateContext;
|
||||
WGLDELETECONTEXT_T DeleteContext;
|
||||
WGLGETPROCADDRESS_T GetProcAddress;
|
||||
WGLMAKECURRENT_T MakeCurrent;
|
||||
WGLSHARELISTS_T ShareLists;
|
||||
} opengl32;
|
||||
|
||||
} _GLFWlibraryWGL;
|
||||
@@ -86,4 +104,4 @@ int _glfwAnalyzeContext(const _GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
#endif // _wgl_context_h_
|
||||
#endif // _glfw3_wgl_context_h_
|
||||
|
||||
+17
-7
@@ -31,14 +31,21 @@
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
#if defined(_GLFW_USE_OPTIMUS_HPG)
|
||||
#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
|
||||
// directed to the high-performance GPU on Nvidia Optimus systems with
|
||||
// up-to-date drivers
|
||||
//
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||
|
||||
#endif // _GLFW_USE_OPTIMUS_HPG
|
||||
// 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)
|
||||
|
||||
@@ -96,6 +103,8 @@ static GLboolean initLibraries(void)
|
||||
{
|
||||
_glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T)
|
||||
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
|
||||
_glfw.win32.dwmapi.DwmFlush = (DWMFLUSH_T)
|
||||
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
|
||||
}
|
||||
|
||||
return GL_TRUE;
|
||||
@@ -360,7 +369,7 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
const char* version = _GLFW_VERSION_NUMBER " Win32"
|
||||
return _GLFW_VERSION_NUMBER " Win32"
|
||||
#if defined(_GLFW_WGL)
|
||||
" WGL"
|
||||
#elif defined(_GLFW_EGL)
|
||||
@@ -371,11 +380,12 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
#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
|
||||
;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
+48
-39
@@ -103,7 +103,7 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
|
||||
|
||||
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
{
|
||||
int size = 0, found = 0;
|
||||
int found = 0;
|
||||
_GLFWmonitor** monitors = NULL;
|
||||
DWORD adapterIndex, displayIndex;
|
||||
|
||||
@@ -125,6 +125,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
for (displayIndex = 0; ; displayIndex++)
|
||||
{
|
||||
DISPLAY_DEVICEW display;
|
||||
_GLFWmonitor* monitor;
|
||||
char* name;
|
||||
HDC dc;
|
||||
|
||||
@@ -134,12 +135,6 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
|
||||
break;
|
||||
|
||||
if (found == size)
|
||||
{
|
||||
size += 4;
|
||||
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size);
|
||||
}
|
||||
|
||||
name = _glfwCreateUTF8FromWideString(display.DeviceString);
|
||||
if (!name)
|
||||
{
|
||||
@@ -150,35 +145,40 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
|
||||
dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL);
|
||||
|
||||
monitors[found] = _glfwAllocMonitor(name,
|
||||
GetDeviceCaps(dc, HORZSIZE),
|
||||
GetDeviceCaps(dc, VERTSIZE));
|
||||
monitor = _glfwAllocMonitor(name,
|
||||
GetDeviceCaps(dc, HORZSIZE),
|
||||
GetDeviceCaps(dc, VERTSIZE));
|
||||
|
||||
DeleteDC(dc);
|
||||
free(name);
|
||||
|
||||
wcscpy(monitors[found]->win32.adapterName, adapter.DeviceName);
|
||||
wcscpy(monitors[found]->win32.displayName, display.DeviceName);
|
||||
if (adapter.StateFlags & DISPLAY_DEVICE_MODESPRUNED)
|
||||
monitor->win32.modesPruned = GL_TRUE;
|
||||
|
||||
wcscpy(monitor->win32.adapterName, adapter.DeviceName);
|
||||
wcscpy(monitor->win32.displayName, display.DeviceName);
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0,
|
||||
adapter.DeviceName, -1,
|
||||
monitors[found]->win32.publicAdapterName,
|
||||
sizeof(monitors[found]->win32.publicAdapterName),
|
||||
monitor->win32.publicAdapterName,
|
||||
sizeof(monitor->win32.publicAdapterName),
|
||||
NULL, NULL);
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0,
|
||||
display.DeviceName, -1,
|
||||
monitors[found]->win32.publicDisplayName,
|
||||
sizeof(monitors[found]->win32.publicDisplayName),
|
||||
monitor->win32.publicDisplayName,
|
||||
sizeof(monitor->win32.publicDisplayName),
|
||||
NULL, NULL);
|
||||
|
||||
found++;
|
||||
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found);
|
||||
monitors[found - 1] = monitor;
|
||||
|
||||
if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE &&
|
||||
displayIndex == 0)
|
||||
{
|
||||
_GLFW_SWAP_POINTERS(monitors[0], monitors[found]);
|
||||
_GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
|
||||
}
|
||||
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,12 +208,12 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
*ypos = settings.dmPosition.y;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
int modeIndex = 0, count = 0;
|
||||
int modeIndex = 0, size = 0;
|
||||
GLFWvidmode* result = NULL;
|
||||
|
||||
*found = 0;
|
||||
*count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -229,11 +229,9 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
|
||||
modeIndex++;
|
||||
|
||||
// Skip modes with less than 15 BPP
|
||||
if (dm.dmBitsPerPel < 15)
|
||||
{
|
||||
// Skip modes with less than 15 BPP
|
||||
continue;
|
||||
}
|
||||
|
||||
mode.width = dm.dmPelsWidth;
|
||||
mode.height = dm.dmPelsHeight;
|
||||
@@ -243,30 +241,41 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
&mode.greenBits,
|
||||
&mode.blueBits);
|
||||
|
||||
for (i = 0; i < *found; i++)
|
||||
for (i = 0; i < *count; i++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + i, &mode) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < *found)
|
||||
{
|
||||
// This is a duplicate, so skip it
|
||||
// Skip duplicate modes
|
||||
if (i < *count)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*found == count)
|
||||
if (monitor->win32.modesPruned)
|
||||
{
|
||||
if (count)
|
||||
count *= 2;
|
||||
else
|
||||
count = 128;
|
||||
|
||||
result = (GLFWvidmode*) realloc(result, count * sizeof(GLFWvidmode));
|
||||
// Skip modes not supported by the connected displays
|
||||
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||
&dm,
|
||||
NULL,
|
||||
CDS_TEST,
|
||||
NULL) != DISP_CHANGE_SUCCESSFUL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
result[*found] = mode;
|
||||
(*found)++;
|
||||
if (*count == size)
|
||||
{
|
||||
if (*count)
|
||||
size *= 2;
|
||||
else
|
||||
size = 128;
|
||||
|
||||
result = (GLFWvidmode*) realloc(result, size * sizeof(GLFWvidmode));
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
result[*count - 1] = mode;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
+9
-14
@@ -25,9 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _win32_platform_h_
|
||||
#define _win32_platform_h_
|
||||
|
||||
#ifndef _glfw3_win32_platform_h_
|
||||
#define _glfw3_win32_platform_h_
|
||||
|
||||
// We don't need all the fancy stuff
|
||||
#ifndef NOMINMAX
|
||||
@@ -71,9 +70,7 @@
|
||||
#define strdup _strdup
|
||||
#endif
|
||||
|
||||
|
||||
// HACK: Define macros that some older windows.h variants don't
|
||||
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#endif
|
||||
@@ -102,7 +99,6 @@ typedef struct tagCHANGEFILTERSTRUCT
|
||||
#endif
|
||||
#endif /*Windows 7*/
|
||||
|
||||
|
||||
// winmm.dll function pointer typedefs
|
||||
typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT);
|
||||
typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO);
|
||||
@@ -121,15 +117,16 @@ typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFIL
|
||||
|
||||
// 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
|
||||
|
||||
#define _GLFW_RECREATION_NOT_NEEDED 0
|
||||
#define _GLFW_RECREATION_REQUIRED 1
|
||||
#define _GLFW_RECREATION_IMPOSSIBLE 2
|
||||
|
||||
|
||||
#include "win32_tls.h"
|
||||
#include "winmm_joystick.h"
|
||||
|
||||
#if defined(_GLFW_WGL)
|
||||
#include "wgl_context.h"
|
||||
@@ -141,8 +138,6 @@ typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
|
||||
#error "No supported context creation API selected"
|
||||
#endif
|
||||
|
||||
#include "winmm_joystick.h"
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
|
||||
#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time
|
||||
@@ -155,10 +150,8 @@ typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
|
||||
typedef struct _GLFWwindowWin32
|
||||
{
|
||||
HWND handle;
|
||||
DWORD dwStyle;
|
||||
DWORD dwExStyle;
|
||||
|
||||
GLboolean cursorInside;
|
||||
GLboolean cursorTracked;
|
||||
GLboolean iconified;
|
||||
|
||||
// The last received cursor position, regardless of source
|
||||
@@ -195,6 +188,7 @@ typedef struct _GLFWlibraryWin32
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled;
|
||||
DWMFLUSH_T DwmFlush;
|
||||
} dwmapi;
|
||||
|
||||
} _GLFWlibraryWin32;
|
||||
@@ -209,6 +203,7 @@ typedef struct _GLFWmonitorWin32
|
||||
WCHAR displayName[32];
|
||||
char publicAdapterName[64];
|
||||
char publicDisplayName[64];
|
||||
GLboolean modesPruned;
|
||||
GLboolean modeChanged;
|
||||
|
||||
} _GLFWmonitorWin32;
|
||||
@@ -247,4 +242,4 @@ void _glfwInitTimer(void);
|
||||
GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
||||
void _glfwRestoreVideoMode(_GLFWmonitor* monitor);
|
||||
|
||||
#endif // _win32_platform_h_
|
||||
#endif // _glfw3_win32_platform_h_
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwInitTLS(void)
|
||||
int _glfwCreateContextTLS(void)
|
||||
{
|
||||
_glfw.win32_tls.context = TlsAlloc();
|
||||
if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES)
|
||||
@@ -46,13 +46,13 @@ int _glfwInitTLS(void)
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateTLS(void)
|
||||
void _glfwDestroyContextTLS(void)
|
||||
{
|
||||
if (_glfw.win32_tls.allocated)
|
||||
TlsFree(_glfw.win32_tls.context);
|
||||
}
|
||||
|
||||
void _glfwSetCurrentContext(_GLFWwindow* context)
|
||||
void _glfwSetContextTLS(_GLFWwindow* context)
|
||||
{
|
||||
TlsSetValue(_glfw.win32_tls.context, context);
|
||||
}
|
||||
|
||||
+6
-6
@@ -25,8 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _win32_tls_h_
|
||||
#define _win32_tls_h_
|
||||
#ifndef _glfw3_win32_tls_h_
|
||||
#define _glfw3_win32_tls_h_
|
||||
|
||||
#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls
|
||||
|
||||
@@ -41,8 +41,8 @@ typedef struct _GLFWtlsWin32
|
||||
} _GLFWtlsWin32;
|
||||
|
||||
|
||||
int _glfwInitTLS(void);
|
||||
void _glfwTerminateTLS(void);
|
||||
void _glfwSetCurrentContext(_GLFWwindow* context);
|
||||
int _glfwCreateContextTLS(void);
|
||||
void _glfwDestroyContextTLS(void);
|
||||
void _glfwSetContextTLS(_GLFWwindow* context);
|
||||
|
||||
#endif // _win32_tls_h_
|
||||
#endif // _glfw3_win32_tls_h_
|
||||
|
||||
+97
-84
@@ -38,6 +38,37 @@
|
||||
#define _GLFW_WNDCLASSNAME L"GLFW30"
|
||||
|
||||
|
||||
// Returns the window style for the specified window
|
||||
//
|
||||
static DWORD getWindowStyle(const _GLFWwindow* window)
|
||||
{
|
||||
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||
|
||||
if (window->decorated && !window->monitor)
|
||||
{
|
||||
style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
|
||||
if (window->resizable)
|
||||
style |= WS_MAXIMIZEBOX | WS_SIZEBOX;
|
||||
}
|
||||
else
|
||||
style |= WS_POPUP;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
// Returns the extended window style for the specified window
|
||||
//
|
||||
static DWORD getWindowExStyle(const _GLFWwindow* window)
|
||||
{
|
||||
DWORD style = WS_EX_APPWINDOW;
|
||||
|
||||
if (window->decorated && !window->monitor)
|
||||
style |= WS_EX_WINDOWEDGE;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
// Updates the cursor clip rect
|
||||
//
|
||||
static void updateClipRect(_GLFWwindow* window)
|
||||
@@ -249,9 +280,6 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
if (window->cursorMode != GLFW_CURSOR_NORMAL)
|
||||
_glfwPlatformApplyCursorMode(window);
|
||||
|
||||
if (window->monitor && window->autoIconify)
|
||||
enterFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowFocus(window, GL_TRUE);
|
||||
return 0;
|
||||
}
|
||||
@@ -262,10 +290,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
restoreCursor(window);
|
||||
|
||||
if (window->monitor && window->autoIconify)
|
||||
{
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
leaveFullscreenMode(window);
|
||||
}
|
||||
|
||||
_glfwInputWindowFocus(window, GL_FALSE);
|
||||
return 0;
|
||||
@@ -431,12 +456,12 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
if (_glfw.focusedWindow != window)
|
||||
if (_glfw.cursorWindow != window)
|
||||
break;
|
||||
|
||||
_glfwInputCursorMotion(window,
|
||||
x - window->win32.cursorPosX,
|
||||
y - window->win32.cursorPosY);
|
||||
x - window->win32.cursorPosX,
|
||||
y - window->win32.cursorPosY);
|
||||
}
|
||||
else
|
||||
_glfwInputCursorMotion(window, x, y);
|
||||
@@ -444,7 +469,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
window->win32.cursorPosX = x;
|
||||
window->win32.cursorPosY = y;
|
||||
|
||||
if (!window->win32.cursorInside)
|
||||
if (!window->win32.cursorTracked)
|
||||
{
|
||||
TRACKMOUSEEVENT tme;
|
||||
ZeroMemory(&tme, sizeof(tme));
|
||||
@@ -453,7 +478,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
tme.hwndTrack = window->win32.handle;
|
||||
TrackMouseEvent(&tme);
|
||||
|
||||
window->win32.cursorInside = GL_TRUE;
|
||||
window->win32.cursorTracked = GL_TRUE;
|
||||
_glfwInputCursorEnter(window, GL_TRUE);
|
||||
}
|
||||
|
||||
@@ -462,7 +487,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
case WM_MOUSELEAVE:
|
||||
{
|
||||
window->win32.cursorInside = GL_FALSE;
|
||||
window->win32.cursorTracked = GL_FALSE;
|
||||
_glfwInputCursorEnter(window, GL_FALSE);
|
||||
return 0;
|
||||
}
|
||||
@@ -483,7 +508,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
case WM_SIZE:
|
||||
{
|
||||
if (_glfw.focusedWindow == window)
|
||||
if (_glfw.cursorWindow == window)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
updateClipRect(window);
|
||||
@@ -492,12 +517,18 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
if (!window->win32.iconified && wParam == SIZE_MINIMIZED)
|
||||
{
|
||||
window->win32.iconified = GL_TRUE;
|
||||
if (window->monitor)
|
||||
leaveFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_TRUE);
|
||||
}
|
||||
else if (window->win32.iconified &&
|
||||
(wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED))
|
||||
{
|
||||
window->win32.iconified = GL_FALSE;
|
||||
if (window->monitor)
|
||||
enterFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_FALSE);
|
||||
}
|
||||
|
||||
@@ -508,7 +539,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
case WM_MOVE:
|
||||
{
|
||||
if (_glfw.focusedWindow == window)
|
||||
if (_glfw.cursorWindow == window)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
updateClipRect(window);
|
||||
@@ -535,7 +566,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
case WM_SETCURSOR:
|
||||
{
|
||||
if (_glfw.focusedWindow == window && LOWORD(lParam) == HTCLIENT)
|
||||
if (_glfw.cursorWindow == window && LOWORD(lParam) == HTCLIENT)
|
||||
{
|
||||
if (window->cursorMode == GLFW_CURSOR_HIDDEN ||
|
||||
window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
@@ -563,39 +594,25 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DWMCOMPOSITIONCHANGED:
|
||||
{
|
||||
if (_glfwIsCompositionEnabled())
|
||||
{
|
||||
_GLFWwindow* previous = _glfwPlatformGetCurrentContext();
|
||||
_glfwPlatformMakeContextCurrent(window);
|
||||
_glfwPlatformSwapInterval(0);
|
||||
_glfwPlatformMakeContextCurrent(previous);
|
||||
}
|
||||
|
||||
// TODO: Restore vsync if compositing was disabled
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DROPFILES:
|
||||
{
|
||||
HDROP hDrop = (HDROP) wParam;
|
||||
HDROP drop = (HDROP) wParam;
|
||||
POINT pt;
|
||||
int i;
|
||||
|
||||
const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0);
|
||||
const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
|
||||
char** paths = calloc(count, sizeof(char*));
|
||||
|
||||
// Move the mouse to the position of the drop
|
||||
DragQueryPoint(hDrop, &pt);
|
||||
DragQueryPoint(drop, &pt);
|
||||
_glfwInputCursorMotion(window, pt.x, pt.y);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
const UINT length = DragQueryFileW(hDrop, i, NULL, 0);
|
||||
const UINT length = DragQueryFileW(drop, i, NULL, 0);
|
||||
WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
|
||||
|
||||
DragQueryFileW(hDrop, i, buffer, length + 1);
|
||||
DragQueryFileW(drop, i, buffer, length + 1);
|
||||
paths[i] = _glfwCreateUTF8FromWideString(buffer);
|
||||
|
||||
free(buffer);
|
||||
@@ -607,7 +624,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
free(paths[i]);
|
||||
free(paths);
|
||||
|
||||
DragFinish(hDrop);
|
||||
DragFinish(drop);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -622,8 +639,8 @@ static void getFullWindowSize(_GLFWwindow* window,
|
||||
int* fullWidth, int* fullHeight)
|
||||
{
|
||||
RECT rect = { 0, 0, clientWidth, clientHeight };
|
||||
AdjustWindowRectEx(&rect, window->win32.dwStyle,
|
||||
FALSE, window->win32.dwExStyle);
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
*fullWidth = rect.right - rect.left;
|
||||
*fullHeight = rect.bottom - rect.top;
|
||||
}
|
||||
@@ -638,35 +655,20 @@ static int createWindow(_GLFWwindow* window,
|
||||
int xpos, ypos, fullWidth, fullHeight;
|
||||
WCHAR* wideTitle;
|
||||
|
||||
window->win32.dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||
window->win32.dwExStyle = WS_EX_APPWINDOW;
|
||||
|
||||
if (window->monitor)
|
||||
if (wndconfig->monitor)
|
||||
{
|
||||
window->win32.dwStyle |= WS_POPUP;
|
||||
GLFWvidmode mode;
|
||||
|
||||
// NOTE: This window placement is temporary and approximate, as the
|
||||
// correct position and size cannot be known until the monitor
|
||||
// video mode has been set
|
||||
_glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos);
|
||||
fullWidth = wndconfig->width;
|
||||
fullHeight = wndconfig->height;
|
||||
_glfwPlatformGetVideoMode(wndconfig->monitor, &mode);
|
||||
fullWidth = mode.width;
|
||||
fullHeight = mode.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->decorated)
|
||||
{
|
||||
window->win32.dwStyle |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
|
||||
if (wndconfig->resizable)
|
||||
{
|
||||
window->win32.dwStyle |= WS_MAXIMIZEBOX | WS_SIZEBOX;
|
||||
window->win32.dwExStyle |= WS_EX_WINDOWEDGE;
|
||||
}
|
||||
}
|
||||
else
|
||||
window->win32.dwStyle |= WS_POPUP;
|
||||
|
||||
xpos = CW_USEDEFAULT;
|
||||
ypos = CW_USEDEFAULT;
|
||||
|
||||
@@ -683,10 +685,10 @@ static int createWindow(_GLFWwindow* window,
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
window->win32.handle = CreateWindowExW(window->win32.dwExStyle,
|
||||
window->win32.handle = CreateWindowExW(getWindowExStyle(window),
|
||||
_GLFW_WNDCLASSNAME,
|
||||
wideTitle,
|
||||
window->win32.dwStyle,
|
||||
getWindowStyle(window),
|
||||
xpos, ypos,
|
||||
fullWidth, fullHeight,
|
||||
NULL, // No parent window
|
||||
@@ -715,9 +717,9 @@ static int createWindow(_GLFWwindow* window,
|
||||
if (wndconfig->floating && !wndconfig->monitor)
|
||||
{
|
||||
SetWindowPos(window->win32.handle,
|
||||
HWND_TOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
HWND_TOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
|
||||
DragAcceptFiles(window->win32.handle, TRUE);
|
||||
@@ -884,8 +886,8 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
RECT rect = { xpos, ypos, xpos, ypos };
|
||||
AdjustWindowRectEx(&rect, window->win32.dwStyle,
|
||||
FALSE, window->win32.dwExStyle);
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
@@ -930,8 +932,8 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
SetRect(&rect, 0, 0, width, height);
|
||||
AdjustWindowRectEx(&rect, window->win32.dwStyle,
|
||||
FALSE, window->win32.dwExStyle);
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
|
||||
if (left)
|
||||
*left = -rect.left;
|
||||
@@ -989,7 +991,6 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
MSG msg;
|
||||
_GLFWwindow* window;
|
||||
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
@@ -999,7 +1000,7 @@ void _glfwPlatformPollEvents(void)
|
||||
// While GLFW does not itself post WM_QUIT, other processes may post
|
||||
// it to this one, for example Task Manager
|
||||
|
||||
window = _glfw.windowListHead;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
@@ -1013,9 +1014,10 @@ void _glfwPlatformPollEvents(void)
|
||||
}
|
||||
}
|
||||
|
||||
window = _glfw.focusedWindow;
|
||||
if (window)
|
||||
if (_glfw.cursorWindow)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.cursorWindow;
|
||||
|
||||
// LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix)
|
||||
// This is the only async event handling in GLFW, but it solves some
|
||||
// nasty problems
|
||||
@@ -1035,12 +1037,18 @@ void _glfwPlatformPollEvents(void)
|
||||
_glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods);
|
||||
}
|
||||
|
||||
// Did the cursor move in an focused window that has disabled the cursor
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
int width, height;
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
_glfwPlatformSetCursorPos(window, width / 2, height / 2);
|
||||
|
||||
// NOTE: Re-center the cursor only if it has moved since the last
|
||||
// call, to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
|
||||
if (window->win32.cursorPosX != width / 2 ||
|
||||
window->win32.cursorPosY != height / 2)
|
||||
{
|
||||
_glfwPlatformSetCursorPos(window, width / 2, height / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1188,19 +1196,24 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
// It should be guaranteed that the cursor is not being used by this window if
|
||||
// the following condition is not met. That way it should be safe to destroy the
|
||||
// cursor after calling glfwSetCursor(window, NULL) on all windows using the cursor.
|
||||
POINT pos;
|
||||
|
||||
if (_glfw.focusedWindow == window &&
|
||||
window->cursorMode == GLFW_CURSOR_NORMAL &&
|
||||
window->win32.cursorInside)
|
||||
{
|
||||
if (cursor)
|
||||
SetCursor(cursor->win32.handle);
|
||||
else
|
||||
SetCursor(LoadCursorW(NULL, IDC_ARROW));
|
||||
}
|
||||
if (_glfw.cursorWindow != window)
|
||||
return;
|
||||
|
||||
if (window->cursorMode != GLFW_CURSOR_NORMAL)
|
||||
return;
|
||||
|
||||
if (!GetCursorPos(&pos))
|
||||
return;
|
||||
|
||||
if (WindowFromPoint(pos) != window->win32.handle)
|
||||
return;
|
||||
|
||||
if (cursor)
|
||||
SetCursor(cursor->win32.handle);
|
||||
else
|
||||
SetCursor(LoadCursorW(NULL, IDC_ARROW));
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||
|
||||
+106
-139
@@ -40,7 +40,7 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused)
|
||||
{
|
||||
if (focused)
|
||||
{
|
||||
_glfw.focusedWindow = window;
|
||||
_glfw.cursorWindow = window;
|
||||
|
||||
if (window->callbacks.focus)
|
||||
window->callbacks.focus((GLFWwindow*) window, focused);
|
||||
@@ -49,7 +49,7 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused)
|
||||
{
|
||||
int i;
|
||||
|
||||
_glfw.focusedWindow = NULL;
|
||||
_glfw.cursorWindow = NULL;
|
||||
|
||||
if (window->callbacks.focus)
|
||||
window->callbacks.focus((GLFWwindow*) window, focused);
|
||||
@@ -132,45 +132,22 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set up desired framebuffer config
|
||||
fbconfig.redBits = _glfw.hints.redBits;
|
||||
fbconfig.greenBits = _glfw.hints.greenBits;
|
||||
fbconfig.blueBits = _glfw.hints.blueBits;
|
||||
fbconfig.alphaBits = _glfw.hints.alphaBits;
|
||||
fbconfig.depthBits = _glfw.hints.depthBits;
|
||||
fbconfig.stencilBits = _glfw.hints.stencilBits;
|
||||
fbconfig.accumRedBits = _glfw.hints.accumRedBits;
|
||||
fbconfig.accumGreenBits = _glfw.hints.accumGreenBits;
|
||||
fbconfig.accumBlueBits = _glfw.hints.accumBlueBits;
|
||||
fbconfig.accumAlphaBits = _glfw.hints.accumAlphaBits;
|
||||
fbconfig.auxBuffers = _glfw.hints.auxBuffers;
|
||||
fbconfig.stereo = _glfw.hints.stereo ? GL_TRUE : GL_FALSE;
|
||||
fbconfig.samples = _glfw.hints.samples;
|
||||
fbconfig.sRGB = _glfw.hints.sRGB;
|
||||
fbconfig.doublebuffer = _glfw.hints.doublebuffer ? GL_TRUE : GL_FALSE;
|
||||
fbconfig = _glfw.hints.framebuffer;
|
||||
ctxconfig = _glfw.hints.context;
|
||||
wndconfig = _glfw.hints.window;
|
||||
|
||||
// Set up desired window config
|
||||
wndconfig.width = width;
|
||||
wndconfig.height = height;
|
||||
wndconfig.title = title;
|
||||
wndconfig.resizable = _glfw.hints.resizable ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.focused = _glfw.hints.focused ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.autoIconify = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.floating = _glfw.hints.floating ? GL_TRUE : GL_FALSE;
|
||||
wndconfig.monitor = (_GLFWmonitor*) monitor;
|
||||
wndconfig.width = width;
|
||||
wndconfig.height = height;
|
||||
wndconfig.title = title;
|
||||
wndconfig.monitor = (_GLFWmonitor*) monitor;
|
||||
ctxconfig.share = (_GLFWwindow*) share;
|
||||
|
||||
// Set up desired context config
|
||||
ctxconfig.api = _glfw.hints.api;
|
||||
ctxconfig.major = _glfw.hints.major;
|
||||
ctxconfig.minor = _glfw.hints.minor;
|
||||
ctxconfig.forward = _glfw.hints.forward ? GL_TRUE : GL_FALSE;
|
||||
ctxconfig.debug = _glfw.hints.debug ? GL_TRUE : GL_FALSE;
|
||||
ctxconfig.profile = _glfw.hints.profile;
|
||||
ctxconfig.robustness = _glfw.hints.robustness;
|
||||
ctxconfig.release = _glfw.hints.release;
|
||||
ctxconfig.share = (_GLFWwindow*) share;
|
||||
if (wndconfig.monitor)
|
||||
{
|
||||
wndconfig.resizable = GL_TRUE;
|
||||
wndconfig.visible = GL_TRUE;
|
||||
wndconfig.focused = GL_TRUE;
|
||||
}
|
||||
|
||||
// Check the OpenGL bits of the window config
|
||||
if (!_glfwIsValidContextConfig(&ctxconfig))
|
||||
@@ -180,23 +157,13 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
window->next = _glfw.windowListHead;
|
||||
_glfw.windowListHead = window;
|
||||
|
||||
if (wndconfig.monitor)
|
||||
{
|
||||
wndconfig.resizable = GL_TRUE;
|
||||
wndconfig.visible = GL_TRUE;
|
||||
wndconfig.focused = GL_TRUE;
|
||||
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;
|
||||
|
||||
// Set up desired video mode
|
||||
window->videoMode.width = width;
|
||||
window->videoMode.height = height;
|
||||
window->videoMode.redBits = _glfw.hints.redBits;
|
||||
window->videoMode.greenBits = _glfw.hints.greenBits;
|
||||
window->videoMode.blueBits = _glfw.hints.blueBits;
|
||||
window->videoMode.refreshRate = _glfw.hints.refreshRate;
|
||||
}
|
||||
|
||||
// Transfer window hints that are persistent settings and not
|
||||
// just initial states
|
||||
window->monitor = wndconfig.monitor;
|
||||
window->resizable = wndconfig.resizable;
|
||||
window->decorated = wndconfig.decorated;
|
||||
@@ -235,7 +202,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
|
||||
// Clearing the front buffer to black to avoid garbage pixels left over
|
||||
// from previous uses of our bit of VRAM
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
window->Clear(GL_COLOR_BUFFER_BIT);
|
||||
_glfwPlatformSwapBuffers(window);
|
||||
|
||||
// Restore the previously current context (or NULL)
|
||||
@@ -272,29 +239,29 @@ void glfwDefaultWindowHints(void)
|
||||
memset(&_glfw.hints, 0, sizeof(_glfw.hints));
|
||||
|
||||
// The default is OpenGL with minimum version 1.0
|
||||
_glfw.hints.api = GLFW_OPENGL_API;
|
||||
_glfw.hints.major = 1;
|
||||
_glfw.hints.minor = 0;
|
||||
_glfw.hints.context.api = GLFW_OPENGL_API;
|
||||
_glfw.hints.context.major = 1;
|
||||
_glfw.hints.context.minor = 0;
|
||||
|
||||
// The default is a focused, visible, resizable window with decorations
|
||||
_glfw.hints.resizable = GL_TRUE;
|
||||
_glfw.hints.visible = GL_TRUE;
|
||||
_glfw.hints.decorated = GL_TRUE;
|
||||
_glfw.hints.focused = GL_TRUE;
|
||||
_glfw.hints.autoIconify = GL_TRUE;
|
||||
|
||||
// The default is to select the highest available refresh rate
|
||||
_glfw.hints.refreshRate = GLFW_DONT_CARE;
|
||||
_glfw.hints.window.resizable = GL_TRUE;
|
||||
_glfw.hints.window.visible = GL_TRUE;
|
||||
_glfw.hints.window.decorated = GL_TRUE;
|
||||
_glfw.hints.window.focused = GL_TRUE;
|
||||
_glfw.hints.window.autoIconify = GL_TRUE;
|
||||
|
||||
// The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
|
||||
// double buffered
|
||||
_glfw.hints.redBits = 8;
|
||||
_glfw.hints.greenBits = 8;
|
||||
_glfw.hints.blueBits = 8;
|
||||
_glfw.hints.alphaBits = 8;
|
||||
_glfw.hints.depthBits = 24;
|
||||
_glfw.hints.stencilBits = 8;
|
||||
_glfw.hints.doublebuffer = GL_TRUE;
|
||||
_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 = GL_TRUE;
|
||||
|
||||
// The default is to select the highest available refresh rate
|
||||
_glfw.hints.refreshRate = GLFW_DONT_CARE;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwWindowHint(int target, int hint)
|
||||
@@ -304,95 +271,95 @@ GLFWAPI void glfwWindowHint(int target, int hint)
|
||||
switch (target)
|
||||
{
|
||||
case GLFW_RED_BITS:
|
||||
_glfw.hints.redBits = hint;
|
||||
_glfw.hints.framebuffer.redBits = hint;
|
||||
break;
|
||||
case GLFW_GREEN_BITS:
|
||||
_glfw.hints.greenBits = hint;
|
||||
_glfw.hints.framebuffer.greenBits = hint;
|
||||
break;
|
||||
case GLFW_BLUE_BITS:
|
||||
_glfw.hints.blueBits = hint;
|
||||
_glfw.hints.framebuffer.blueBits = hint;
|
||||
break;
|
||||
case GLFW_ALPHA_BITS:
|
||||
_glfw.hints.alphaBits = hint;
|
||||
_glfw.hints.framebuffer.alphaBits = hint;
|
||||
break;
|
||||
case GLFW_DEPTH_BITS:
|
||||
_glfw.hints.depthBits = hint;
|
||||
_glfw.hints.framebuffer.depthBits = hint;
|
||||
break;
|
||||
case GLFW_STENCIL_BITS:
|
||||
_glfw.hints.stencilBits = hint;
|
||||
_glfw.hints.framebuffer.stencilBits = hint;
|
||||
break;
|
||||
case GLFW_ACCUM_RED_BITS:
|
||||
_glfw.hints.accumRedBits = hint;
|
||||
_glfw.hints.framebuffer.accumRedBits = hint;
|
||||
break;
|
||||
case GLFW_ACCUM_GREEN_BITS:
|
||||
_glfw.hints.accumGreenBits = hint;
|
||||
_glfw.hints.framebuffer.accumGreenBits = hint;
|
||||
break;
|
||||
case GLFW_ACCUM_BLUE_BITS:
|
||||
_glfw.hints.accumBlueBits = hint;
|
||||
_glfw.hints.framebuffer.accumBlueBits = hint;
|
||||
break;
|
||||
case GLFW_ACCUM_ALPHA_BITS:
|
||||
_glfw.hints.accumAlphaBits = hint;
|
||||
_glfw.hints.framebuffer.accumAlphaBits = hint;
|
||||
break;
|
||||
case GLFW_AUX_BUFFERS:
|
||||
_glfw.hints.auxBuffers = hint;
|
||||
_glfw.hints.framebuffer.auxBuffers = hint;
|
||||
break;
|
||||
case GLFW_STEREO:
|
||||
_glfw.hints.stereo = hint;
|
||||
_glfw.hints.framebuffer.stereo = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_DOUBLEBUFFER:
|
||||
_glfw.hints.framebuffer.doublebuffer = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_SAMPLES:
|
||||
_glfw.hints.framebuffer.samples = hint;
|
||||
break;
|
||||
case GLFW_SRGB_CAPABLE:
|
||||
_glfw.hints.framebuffer.sRGB = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_RESIZABLE:
|
||||
_glfw.hints.window.resizable = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_DECORATED:
|
||||
_glfw.hints.window.decorated = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_FOCUSED:
|
||||
_glfw.hints.window.focused = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_AUTO_ICONIFY:
|
||||
_glfw.hints.window.autoIconify = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_FLOATING:
|
||||
_glfw.hints.window.floating = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_VISIBLE:
|
||||
_glfw.hints.window.visible = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_CLIENT_API:
|
||||
_glfw.hints.context.api = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_VERSION_MAJOR:
|
||||
_glfw.hints.context.major = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_VERSION_MINOR:
|
||||
_glfw.hints.context.minor = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_ROBUSTNESS:
|
||||
_glfw.hints.context.robustness = hint;
|
||||
break;
|
||||
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||
_glfw.hints.context.forward = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_OPENGL_DEBUG_CONTEXT:
|
||||
_glfw.hints.context.debug = hint ? GL_TRUE : GL_FALSE;
|
||||
break;
|
||||
case GLFW_OPENGL_PROFILE:
|
||||
_glfw.hints.context.profile = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_RELEASE_BEHAVIOR:
|
||||
_glfw.hints.context.release = hint;
|
||||
break;
|
||||
case GLFW_REFRESH_RATE:
|
||||
_glfw.hints.refreshRate = hint;
|
||||
break;
|
||||
case GLFW_DOUBLEBUFFER:
|
||||
_glfw.hints.doublebuffer = hint;
|
||||
break;
|
||||
case GLFW_RESIZABLE:
|
||||
_glfw.hints.resizable = hint;
|
||||
break;
|
||||
case GLFW_DECORATED:
|
||||
_glfw.hints.decorated = hint;
|
||||
break;
|
||||
case GLFW_FOCUSED:
|
||||
_glfw.hints.focused = hint;
|
||||
break;
|
||||
case GLFW_AUTO_ICONIFY:
|
||||
_glfw.hints.autoIconify = hint;
|
||||
break;
|
||||
case GLFW_FLOATING:
|
||||
_glfw.hints.floating = hint;
|
||||
break;
|
||||
case GLFW_VISIBLE:
|
||||
_glfw.hints.visible = hint;
|
||||
break;
|
||||
case GLFW_SAMPLES:
|
||||
_glfw.hints.samples = hint;
|
||||
break;
|
||||
case GLFW_SRGB_CAPABLE:
|
||||
_glfw.hints.sRGB = hint;
|
||||
break;
|
||||
case GLFW_CLIENT_API:
|
||||
_glfw.hints.api = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_VERSION_MAJOR:
|
||||
_glfw.hints.major = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_VERSION_MINOR:
|
||||
_glfw.hints.minor = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_ROBUSTNESS:
|
||||
_glfw.hints.robustness = hint;
|
||||
break;
|
||||
case GLFW_OPENGL_FORWARD_COMPAT:
|
||||
_glfw.hints.forward = hint;
|
||||
break;
|
||||
case GLFW_OPENGL_DEBUG_CONTEXT:
|
||||
_glfw.hints.debug = hint;
|
||||
break;
|
||||
case GLFW_OPENGL_PROFILE:
|
||||
_glfw.hints.profile = hint;
|
||||
break;
|
||||
case GLFW_CONTEXT_RELEASE_BEHAVIOR:
|
||||
_glfw.hints.release = hint;
|
||||
break;
|
||||
default:
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint");
|
||||
break;
|
||||
@@ -418,8 +385,8 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle)
|
||||
_glfwPlatformMakeContextCurrent(NULL);
|
||||
|
||||
// Clear the focused window pointer if this is the focused window
|
||||
if (_glfw.focusedWindow == window)
|
||||
_glfw.focusedWindow = NULL;
|
||||
if (_glfw.cursorWindow == window)
|
||||
_glfw.cursorWindow = NULL;
|
||||
|
||||
_glfwPlatformDestroyWindow(window);
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _winmm_joystick_h_
|
||||
#define _winmm_joystick_h_
|
||||
#ifndef _glfw3_winmm_joystick_h_
|
||||
#define _glfw3_winmm_joystick_h_
|
||||
|
||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||
_GLFWjoystickWinMM winmm_js[GLFW_JOYSTICK_LAST + 1]
|
||||
@@ -44,4 +44,4 @@ typedef struct _GLFWjoystickWinMM
|
||||
void _glfwInitJoysticks(void);
|
||||
void _glfwTerminateJoysticks(void);
|
||||
|
||||
#endif // _winmm_joystick_h_
|
||||
#endif // _glfw3_winmm_joystick_h_
|
||||
|
||||
+11
-4
@@ -35,7 +35,6 @@
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-cursor.h>
|
||||
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
static void pointerHandleEnter(void* data,
|
||||
struct wl_pointer* pointer,
|
||||
@@ -86,6 +85,11 @@ static void pointerHandleMotion(void* data,
|
||||
"Wayland: GLFW_CURSOR_DISABLED not supported");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||
}
|
||||
|
||||
_glfwInputCursorMotion(window,
|
||||
wl_fixed_to_double(sx),
|
||||
@@ -616,15 +620,18 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
const char* version = _GLFW_VERSION_NUMBER " Wayland EGL "
|
||||
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
|
||||
;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
+9
-8
@@ -24,23 +24,23 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _wayland_platform_h_
|
||||
#define _wayland_platform_h_
|
||||
|
||||
#ifndef _glfw3_wayland_platform_h_
|
||||
#define _glfw3_wayland_platform_h_
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "posix_tls.h"
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
#if defined(_GLFW_EGL)
|
||||
#include "egl_context.h"
|
||||
#else
|
||||
#error "The Wayland backend depends on EGL platform support"
|
||||
#endif
|
||||
|
||||
#include "posix_tls.h"
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
|
||||
#define _GLFW_EGL_NATIVE_WINDOW window->wl.native
|
||||
#define _GLFW_EGL_NATIVE_DISPLAY _glfw.wl.display
|
||||
|
||||
@@ -66,6 +66,7 @@ typedef struct _GLFWwindowWayland
|
||||
struct wl_shell_surface* shell_surface;
|
||||
struct wl_callback* callback;
|
||||
_GLFWcursor* currentCursor;
|
||||
double cursorPosX, cursorPosY;
|
||||
} _GLFWwindowWayland;
|
||||
|
||||
|
||||
@@ -137,4 +138,4 @@ typedef struct _GLFWcursorWayland
|
||||
|
||||
void _glfwAddOutput(uint32_t name, uint32_t version);
|
||||
|
||||
#endif // _wayland_platform_h_
|
||||
#endif // _glfw3_wayland_platform_h_
|
||||
|
||||
+44
-37
@@ -114,6 +114,43 @@ createTmpfileCloexec(char* tmpname)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void
|
||||
handleEvents(int timeout)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
struct pollfd fds[] = {
|
||||
{ wl_display_get_fd(display), POLLIN },
|
||||
};
|
||||
|
||||
while (wl_display_prepare_read(display) != 0)
|
||||
wl_display_dispatch_pending(display);
|
||||
|
||||
// If an error different from EAGAIN happens, we have likely been
|
||||
// disconnected from the Wayland session, try to handle that the best we
|
||||
// can.
|
||||
if (wl_display_flush(display) < 0 && errno != EAGAIN)
|
||||
{
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
window = window->next;
|
||||
}
|
||||
wl_display_cancel_read(display);
|
||||
return;
|
||||
}
|
||||
|
||||
if (poll(fds, 1, timeout) > 0)
|
||||
{
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new, unique, anonymous file of the given size, and
|
||||
* return the file descriptor for it. The file descriptor is set
|
||||
@@ -150,7 +187,7 @@ createAnonymousFile(off_t size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = malloc(strlen(path) + sizeof(template));
|
||||
name = calloc(strlen(path) + sizeof(template), 1);
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
@@ -327,44 +364,12 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
struct pollfd fds[] = {
|
||||
{ wl_display_get_fd(display), POLLIN },
|
||||
};
|
||||
|
||||
while (wl_display_prepare_read(display) != 0)
|
||||
wl_display_dispatch_pending(display);
|
||||
wl_display_flush(display);
|
||||
if (poll(fds, 1, 0) > 0)
|
||||
{
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
handleEvents(0);
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
struct pollfd fds[] = {
|
||||
{ wl_display_get_fd(display), POLLIN },
|
||||
};
|
||||
|
||||
while (wl_display_prepare_read(display) != 0)
|
||||
wl_display_dispatch_pending(display);
|
||||
wl_display_flush(display);
|
||||
if (poll(fds, 1, -1) > 0)
|
||||
{
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
handleEvents(-1);
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
@@ -374,8 +379,10 @@ void _glfwPlatformPostEmptyEvent(void)
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
// TODO
|
||||
fprintf(stderr, "_glfwPlatformGetCursorPos not implemented yet\n");
|
||||
if (xpos)
|
||||
*xpos = window->wl.cursorPosX;
|
||||
if (ypos)
|
||||
*ypos = window->wl.cursorPosY;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
||||
|
||||
+51
-43
@@ -38,7 +38,7 @@
|
||||
|
||||
// Translate an X11 key code to a GLFW key code.
|
||||
//
|
||||
static int translateKey(int scancode)
|
||||
static int translateKeyCode(int scancode)
|
||||
{
|
||||
int keySym;
|
||||
|
||||
@@ -241,15 +241,14 @@ static void createKeyTables(void)
|
||||
// keyboard layout
|
||||
|
||||
char name[XkbKeyNameLength + 1];
|
||||
XkbDescPtr descr = XkbGetKeyboard(_glfw.x11.display,
|
||||
XkbAllComponentsMask,
|
||||
XkbUseCoreKbd);
|
||||
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 = descr->min_key_code; scancode <= descr->max_key_code; scancode++)
|
||||
for (scancode = desc->min_key_code; scancode <= desc->max_key_code; scancode++)
|
||||
{
|
||||
memcpy(name, descr->names->keys[scancode].name, XkbKeyNameLength);
|
||||
name[XkbKeyNameLength] = 0;
|
||||
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
|
||||
@@ -309,7 +308,8 @@ static void createKeyTables(void)
|
||||
_glfw.x11.publicKeys[scancode] = key;
|
||||
}
|
||||
|
||||
XkbFreeKeyboard(descr, 0, True);
|
||||
XkbFreeNames(desc, XkbKeyNamesMask, True);
|
||||
XkbFreeClientMap(desc, 0, True);
|
||||
}
|
||||
|
||||
// Translate the un-translated key codes using traditional X11 KeySym
|
||||
@@ -317,7 +317,7 @@ static void createKeyTables(void)
|
||||
for (scancode = 0; scancode < 256; scancode++)
|
||||
{
|
||||
if (_glfw.x11.publicKeys[scancode] < 0)
|
||||
_glfw.x11.publicKeys[scancode] = translateKey(scancode);
|
||||
_glfw.x11.publicKeys[scancode] = translateKeyCode(scancode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,8 +459,6 @@ static void detectEWMH(void)
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_BYPASS_COMPOSITOR");
|
||||
|
||||
XFree(supportedAtoms);
|
||||
|
||||
_glfw.x11.hasEWMH = GL_TRUE;
|
||||
}
|
||||
|
||||
// Initialize X11 display and look for supported X11 extensions
|
||||
@@ -498,8 +496,8 @@ static GLboolean initExtensions(void)
|
||||
XRRScreenResources* sr;
|
||||
|
||||
if (!XRRQueryVersion(_glfw.x11.display,
|
||||
&_glfw.x11.randr.versionMajor,
|
||||
&_glfw.x11.randr.versionMinor))
|
||||
&_glfw.x11.randr.major,
|
||||
&_glfw.x11.randr.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to query RandR version");
|
||||
@@ -507,11 +505,8 @@ static GLboolean initExtensions(void)
|
||||
}
|
||||
|
||||
// The GLFW RandR path requires at least version 1.3
|
||||
if (_glfw.x11.randr.versionMajor == 1 &&
|
||||
_glfw.x11.randr.versionMinor < 3)
|
||||
{
|
||||
if (_glfw.x11.randr.major == 1 && _glfw.x11.randr.minor < 3)
|
||||
_glfw.x11.randr.available = GL_FALSE;
|
||||
}
|
||||
|
||||
sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root);
|
||||
|
||||
@@ -530,8 +525,8 @@ static GLboolean initExtensions(void)
|
||||
}
|
||||
|
||||
if (XineramaQueryExtension(_glfw.x11.display,
|
||||
&_glfw.x11.xinerama.versionMajor,
|
||||
&_glfw.x11.xinerama.versionMinor))
|
||||
&_glfw.x11.xinerama.major,
|
||||
&_glfw.x11.xinerama.minor))
|
||||
{
|
||||
if (XineramaIsActive(_glfw.x11.display))
|
||||
_glfw.x11.xinerama.available = GL_TRUE;
|
||||
@@ -544,12 +539,12 @@ static GLboolean initExtensions(void)
|
||||
&_glfw.x11.xi.eventBase,
|
||||
&_glfw.x11.xi.errorBase))
|
||||
{
|
||||
_glfw.x11.xi.versionMajor = 2;
|
||||
_glfw.x11.xi.versionMinor = 0;
|
||||
_glfw.x11.xi.major = 2;
|
||||
_glfw.x11.xi.minor = 0;
|
||||
|
||||
if (XIQueryVersion(_glfw.x11.display,
|
||||
&_glfw.x11.xi.versionMajor,
|
||||
&_glfw.x11.xi.versionMinor) != BadRequest)
|
||||
&_glfw.x11.xi.major,
|
||||
&_glfw.x11.xi.minor) != BadRequest)
|
||||
{
|
||||
_glfw.x11.xi.available = GL_TRUE;
|
||||
}
|
||||
@@ -557,15 +552,15 @@ static GLboolean initExtensions(void)
|
||||
#endif /*_GLFW_HAS_XINPUT*/
|
||||
|
||||
// Check if Xkb is supported on this display
|
||||
_glfw.x11.xkb.versionMajor = 1;
|
||||
_glfw.x11.xkb.versionMinor = 0;
|
||||
_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.versionMajor,
|
||||
&_glfw.x11.xkb.versionMinor);
|
||||
&_glfw.x11.xkb.major,
|
||||
&_glfw.x11.xkb.minor);
|
||||
|
||||
if (_glfw.x11.xkb.available)
|
||||
{
|
||||
@@ -714,17 +709,30 @@ Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
|
||||
|
||||
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 character input
|
||||
// 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)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to open X 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 GL_FALSE;
|
||||
}
|
||||
|
||||
@@ -741,7 +749,7 @@ int _glfwPlatformInit(void)
|
||||
{
|
||||
XSetLocaleModifiers("");
|
||||
|
||||
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0);
|
||||
_glfw.x11.im = XOpenIM(_glfw.x11.display, 0, NULL, NULL);
|
||||
if (_glfw.x11.im)
|
||||
{
|
||||
if (!hasUsableInputMethodStyle())
|
||||
@@ -780,43 +788,43 @@ void _glfwPlatformTerminate(void)
|
||||
}
|
||||
|
||||
_glfwTerminateJoysticks();
|
||||
_glfwTerminateContextAPI();
|
||||
|
||||
if (_glfw.x11.display)
|
||||
{
|
||||
XCloseDisplay(_glfw.x11.display);
|
||||
_glfw.x11.display = NULL;
|
||||
}
|
||||
|
||||
// NOTE: This needs to be done after XCloseDisplay, as libGL registers
|
||||
// internal cleanup callbacks in libX11
|
||||
_glfwTerminateContextAPI();
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
const char* version = _GLFW_VERSION_NUMBER " X11"
|
||||
return _GLFW_VERSION_NUMBER " X11"
|
||||
#if defined(_GLFW_GLX)
|
||||
" GLX"
|
||||
#elif defined(_GLFW_EGL)
|
||||
" EGL"
|
||||
#endif
|
||||
#if defined(_GLFW_HAS_GLXGETPROCADDRESS)
|
||||
" glXGetProcAddress"
|
||||
#elif defined(_GLFW_HAS_GLXGETPROCADDRESSARB)
|
||||
" glXGetProcAddressARB"
|
||||
#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT)
|
||||
" glXGetProcAddressEXT"
|
||||
#elif defined(_GLFW_DLOPEN_LIBGL)
|
||||
" dlsym(libGL)"
|
||||
#endif
|
||||
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
|
||||
" clock_gettime"
|
||||
#else
|
||||
" gettimeofday"
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
" /dev/js"
|
||||
#endif
|
||||
#if defined(_GLFW_HAS_XINPUT)
|
||||
" XI"
|
||||
#endif
|
||||
#if defined(_GLFW_HAS_XF86VM)
|
||||
" Xf86vm"
|
||||
#endif
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
" shared"
|
||||
#endif
|
||||
;
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
+23
-26
@@ -200,7 +200,7 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
|
||||
|
||||
_GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
{
|
||||
int i, j, k, size = 0, found = 0;
|
||||
int i, j, k, found = 0;
|
||||
_GLFWmonitor** monitors = NULL;
|
||||
|
||||
*count = 0;
|
||||
@@ -214,6 +214,8 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
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);
|
||||
|
||||
@@ -225,6 +227,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
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)
|
||||
@@ -233,12 +236,6 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found == size)
|
||||
{
|
||||
size += 4;
|
||||
monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size);
|
||||
}
|
||||
|
||||
if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270)
|
||||
{
|
||||
widthMM = oi->mm_height;
|
||||
@@ -250,9 +247,9 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
heightMM = oi->mm_height;
|
||||
}
|
||||
|
||||
monitors[found] = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||
monitors[found]->x11.output = ci->outputs[j];
|
||||
monitors[found]->x11.crtc = oi->crtc;
|
||||
monitor = _glfwAllocMonitor(oi->name, widthMM, heightMM);
|
||||
monitor->x11.output = ci->outputs[j];
|
||||
monitor->x11.crtc = oi->crtc;
|
||||
|
||||
for (k = 0; k < screenCount; k++)
|
||||
{
|
||||
@@ -261,17 +258,18 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
screens[k].width == ci->width &&
|
||||
screens[k].height == ci->height)
|
||||
{
|
||||
monitors[found]->x11.index = k;
|
||||
monitor->x11.index = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XRRFreeOutputInfo(oi);
|
||||
|
||||
if (ci->outputs[j] == primary)
|
||||
_GLFW_SWAP_POINTERS(monitors[0], monitors[found]);
|
||||
|
||||
found++;
|
||||
monitors[found - 1] = monitor;
|
||||
|
||||
if (ci->outputs[j] == primary)
|
||||
_GLFW_SWAP_POINTERS(monitors[0], monitors[found - 1]);
|
||||
}
|
||||
|
||||
XRRFreeCrtcInfo(ci);
|
||||
@@ -286,7 +284,10 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: RandR monitor support seems broken");
|
||||
|
||||
_glfw.x11.randr.monitorBroken = GL_TRUE;
|
||||
free(monitors);
|
||||
monitors = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,13 +331,11 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
}
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
GLFWvidmode* result;
|
||||
|
||||
*found = 0;
|
||||
|
||||
// Build array of available resolutions
|
||||
*count = 0;
|
||||
|
||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken)
|
||||
{
|
||||
@@ -359,20 +358,18 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
|
||||
const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci);
|
||||
|
||||
for (j = 0; j < *found; j++)
|
||||
for (j = 0; j < *count; j++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + j, &mode) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < *found)
|
||||
{
|
||||
// This is a duplicate, so skip it
|
||||
// Skip duplicate modes
|
||||
if (j < *count)
|
||||
continue;
|
||||
}
|
||||
|
||||
result[*found] = mode;
|
||||
(*found)++;
|
||||
(*count)++;
|
||||
result[*count - 1] = mode;
|
||||
}
|
||||
|
||||
XRRFreeOutputInfo(oi);
|
||||
@@ -381,7 +378,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
}
|
||||
else
|
||||
{
|
||||
*found = 1;
|
||||
*count = 1;
|
||||
result = calloc(1, sizeof(GLFWvidmode));
|
||||
_glfwPlatformGetVideoMode(monitor, result);
|
||||
}
|
||||
|
||||
+20
-19
@@ -25,8 +25,8 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _x11_platform_h_
|
||||
#define _x11_platform_h_
|
||||
#ifndef _glfw3_x11_platform_h_
|
||||
#define _glfw3_x11_platform_h_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
@@ -57,6 +57,9 @@
|
||||
#endif
|
||||
|
||||
#include "posix_tls.h"
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
#if defined(_GLFW_GLX)
|
||||
#define _GLFW_X11_CONTEXT_VISUAL window->glx.visual
|
||||
@@ -70,10 +73,6 @@
|
||||
#error "No supported context creation API selected"
|
||||
#endif
|
||||
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
#include "xkb_unicode.h"
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
||||
@@ -88,8 +87,6 @@ typedef struct _GLFWwindowX11
|
||||
Window handle;
|
||||
XIC ic;
|
||||
|
||||
GLboolean overrideRedirect;
|
||||
|
||||
// Cached position and size used to filter out duplicate events
|
||||
int width, height;
|
||||
int xpos, ypos;
|
||||
@@ -99,6 +96,12 @@ typedef struct _GLFWwindowX11
|
||||
// The last position the cursor was warped to by GLFW
|
||||
int warpPosX, warpPosY;
|
||||
|
||||
// The information from the last KeyPress event
|
||||
struct {
|
||||
unsigned int keycode;
|
||||
Time time;
|
||||
} last;
|
||||
|
||||
} _GLFWwindowX11;
|
||||
|
||||
|
||||
@@ -116,8 +119,6 @@ typedef struct _GLFWlibraryX11
|
||||
XContext context;
|
||||
// XIM input method
|
||||
XIM im;
|
||||
// True if window manager supports EWMH
|
||||
GLboolean hasEWMH;
|
||||
// Most recent error code received by X error handler
|
||||
int errorCode;
|
||||
// Clipboard string (while the selection is owned)
|
||||
@@ -170,8 +171,8 @@ typedef struct _GLFWlibraryX11
|
||||
GLboolean available;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
int versionMajor;
|
||||
int versionMinor;
|
||||
int major;
|
||||
int minor;
|
||||
GLboolean gammaBroken;
|
||||
GLboolean monitorBroken;
|
||||
} randr;
|
||||
@@ -182,8 +183,8 @@ typedef struct _GLFWlibraryX11
|
||||
int majorOpcode;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
int versionMajor;
|
||||
int versionMinor;
|
||||
int major;
|
||||
int minor;
|
||||
} xkb;
|
||||
|
||||
struct {
|
||||
@@ -200,8 +201,8 @@ typedef struct _GLFWlibraryX11
|
||||
|
||||
struct {
|
||||
GLboolean available;
|
||||
int versionMajor;
|
||||
int versionMinor;
|
||||
int major;
|
||||
int minor;
|
||||
} xinerama;
|
||||
|
||||
#if defined(_GLFW_HAS_XINPUT)
|
||||
@@ -210,8 +211,8 @@ typedef struct _GLFWlibraryX11
|
||||
int majorOpcode;
|
||||
int eventBase;
|
||||
int errorBase;
|
||||
int versionMajor;
|
||||
int versionMinor;
|
||||
int major;
|
||||
int minor;
|
||||
} xi;
|
||||
#endif /*_GLFW_HAS_XINPUT*/
|
||||
|
||||
@@ -264,4 +265,4 @@ void _glfwGrabXErrorHandler(void);
|
||||
void _glfwReleaseXErrorHandler(void);
|
||||
void _glfwInputXError(int error, const char* message);
|
||||
|
||||
#endif // _x11_platform_h_
|
||||
#endif // _glfw3_x11_platform_h_
|
||||
|
||||
+338
-273
@@ -36,6 +36,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Action for EWMH client messages
|
||||
#define _NET_WM_STATE_REMOVE 0
|
||||
@@ -46,32 +48,29 @@
|
||||
#define Button6 6
|
||||
#define Button7 7
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long functions;
|
||||
unsigned long decorations;
|
||||
long input_mode;
|
||||
unsigned long status;
|
||||
} MotifWmHints;
|
||||
|
||||
#define MWM_HINTS_DECORATIONS (1L << 1)
|
||||
|
||||
|
||||
// Wait for data to arrive
|
||||
//
|
||||
void selectDisplayConnection(struct timeval* timeout)
|
||||
{
|
||||
fd_set fds;
|
||||
int result;
|
||||
const int fd = ConnectionNumber(_glfw.x11.display);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
// select(1) is used instead of an X function like XNextEvent, as the
|
||||
// wait inside those are guarded by the mutex protecting the display
|
||||
// struct, locking out other threads from using X (including GLX)
|
||||
select(fd + 1, &fds, NULL, NULL, timeout);
|
||||
// NOTE: We use select instead of an X function like XNextEvent, as the
|
||||
// wait inside those are guarded by the mutex protecting the display
|
||||
// struct, locking out other threads from using X (including GLX)
|
||||
// NOTE: Only retry on EINTR if there is no timeout, as select is not
|
||||
// required to update it for the time elapsed
|
||||
// TODO: Update timeout value manually
|
||||
do
|
||||
{
|
||||
result = select(fd + 1, &fds, NULL, NULL, timeout);
|
||||
}
|
||||
while (result == -1 && errno == EINTR && timeout == NULL);
|
||||
}
|
||||
|
||||
// Returns whether the window is iconified
|
||||
@@ -114,7 +113,7 @@ static int translateCursorShape(int shape)
|
||||
switch (shape)
|
||||
{
|
||||
case GLFW_ARROW_CURSOR:
|
||||
return XC_arrow;
|
||||
return XC_left_ptr;
|
||||
case GLFW_IBEAM_CURSOR:
|
||||
return XC_xterm;
|
||||
case GLFW_CROSSHAIR_CURSOR:
|
||||
@@ -148,7 +147,7 @@ static int translateState(int state)
|
||||
return mods;
|
||||
}
|
||||
|
||||
// Translates an X Window key to internal coding
|
||||
// Translates an X11 key code to a GLFW key token
|
||||
//
|
||||
static int translateKey(int scancode)
|
||||
{
|
||||
@@ -176,9 +175,10 @@ static _GLFWwindow* findWindowByHandle(Window handle)
|
||||
return window;
|
||||
}
|
||||
|
||||
// Adds or removes an EWMH state to a window
|
||||
// Sends an EWMH or ICCCM event to the window manager
|
||||
//
|
||||
static void changeWindowState(_GLFWwindow* window, Atom state, int action)
|
||||
static void sendEventToWM(_GLFWwindow* window, Atom type,
|
||||
long a, long b, long c, long d, long e)
|
||||
{
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
@@ -186,14 +186,14 @@ static void changeWindowState(_GLFWwindow* window, Atom state, int action)
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->x11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = _glfw.x11.NET_WM_STATE;
|
||||
event.xclient.data.l[0] = action;
|
||||
event.xclient.data.l[1] = state;
|
||||
event.xclient.data.l[2] = 0; // No secondary property
|
||||
event.xclient.data.l[3] = 1; // Sender is a normal application
|
||||
event.xclient.message_type = type;
|
||||
event.xclient.data.l[0] = a;
|
||||
event.xclient.data.l[1] = b;
|
||||
event.xclient.data.l[2] = c;
|
||||
event.xclient.data.l[3] = d;
|
||||
event.xclient.data.l[4] = e;
|
||||
|
||||
XSendEvent(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
XSendEvent(_glfw.x11.display, _glfw.x11.root,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
&event);
|
||||
@@ -252,7 +252,7 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
{
|
||||
unsigned long wamask;
|
||||
XSetWindowAttributes wa;
|
||||
XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL;
|
||||
XVisualInfo* vi = _GLFW_X11_CONTEXT_VISUAL;
|
||||
|
||||
// Every window needs a colormap
|
||||
// Create one based on the visual used by the current context
|
||||
@@ -260,7 +260,7 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
|
||||
window->x11.colormap = XCreateColormap(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
visual->visual,
|
||||
vi->visual,
|
||||
AllocNone);
|
||||
|
||||
// Create the actual window
|
||||
@@ -280,10 +280,10 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
_glfw.x11.root,
|
||||
0, 0,
|
||||
wndconfig->width, wndconfig->height,
|
||||
0, // Border width
|
||||
visual->depth, // Color depth
|
||||
0, // Border width
|
||||
vi->depth, // Color depth
|
||||
InputOutput,
|
||||
visual->visual,
|
||||
vi->visual,
|
||||
wamask,
|
||||
&wa);
|
||||
|
||||
@@ -296,45 +296,69 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
if (!wndconfig->decorated)
|
||||
{
|
||||
MotifWmHints hints;
|
||||
hints.flags = MWM_HINTS_DECORATIONS;
|
||||
hints.decorations = 0;
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.MOTIF_WM_HINTS,
|
||||
_glfw.x11.MOTIF_WM_HINTS, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char*) &hints,
|
||||
sizeof(MotifWmHints) / sizeof(long));
|
||||
}
|
||||
|
||||
XSaveContext(_glfw.x11.display,
|
||||
window->x11.handle,
|
||||
_glfw.x11.context,
|
||||
(XPointer) window);
|
||||
}
|
||||
|
||||
if (window->monitor && !_glfw.x11.hasEWMH)
|
||||
if (wndconfig->monitor)
|
||||
{
|
||||
// This is the butcher's way of removing window decorations
|
||||
// Setting the override-redirect attribute on a window makes the window
|
||||
// manager ignore the window completely (ICCCM, section 4)
|
||||
// The good thing is that this makes undecorated full screen windows
|
||||
// easy to do; the bad thing is that we have to do everything manually
|
||||
// and some things (like iconify/restore) won't work at all, as those
|
||||
// are tasks usually performed by the window manager
|
||||
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
// This is the butcher's way of removing window decorations
|
||||
// Setting the override-redirect attribute on a window makes the
|
||||
// window manager ignore the window completely (ICCCM, section 4)
|
||||
// The good thing is that this makes undecorated full screen windows
|
||||
// easy to do; the bad thing is that we have to do everything
|
||||
// manually and some things (like iconify/restore) won't work at
|
||||
// all, as those are tasks usually performed by the window manager
|
||||
|
||||
XSetWindowAttributes attributes;
|
||||
attributes.override_redirect = True;
|
||||
XChangeWindowAttributes(_glfw.x11.display,
|
||||
window->x11.handle,
|
||||
CWOverrideRedirect,
|
||||
&attributes);
|
||||
|
||||
window->x11.overrideRedirect = GL_TRUE;
|
||||
XSetWindowAttributes attributes;
|
||||
attributes.override_redirect = True;
|
||||
XChangeWindowAttributes(_glfw.x11.display,
|
||||
window->x11.handle,
|
||||
CWOverrideRedirect,
|
||||
&attributes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wndconfig->decorated)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long functions;
|
||||
unsigned long decorations;
|
||||
long input_mode;
|
||||
unsigned long status;
|
||||
} hints;
|
||||
|
||||
hints.flags = 2; // Set decorations
|
||||
hints.decorations = 0; // No decorations
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.MOTIF_WM_HINTS,
|
||||
_glfw.x11.MOTIF_WM_HINTS, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char*) &hints,
|
||||
sizeof(hints) / sizeof(long));
|
||||
}
|
||||
|
||||
if (wndconfig->floating)
|
||||
{
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
|
||||
{
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
_NET_WM_STATE_ADD,
|
||||
_glfw.x11.NET_WM_STATE_ABOVE,
|
||||
0, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Declare the WM protocols supported by GLFW
|
||||
{
|
||||
@@ -455,16 +479,6 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
PropModeReplace, (unsigned char*) &version, 1);
|
||||
}
|
||||
|
||||
if (wndconfig->floating && !wndconfig->monitor)
|
||||
{
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE)
|
||||
{
|
||||
changeWindowState(window,
|
||||
_glfw.x11.NET_WM_STATE_ABOVE,
|
||||
_NET_WM_STATE_ADD);
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetWindowTitle(window, wndconfig->title);
|
||||
|
||||
XRRSelectInput(_glfw.x11.display, window->x11.handle,
|
||||
@@ -673,18 +687,18 @@ static void handleSelectionRequest(XEvent* event)
|
||||
{
|
||||
const XSelectionRequestEvent* request = &event->xselectionrequest;
|
||||
|
||||
XEvent response;
|
||||
memset(&response, 0, sizeof(response));
|
||||
XEvent reply;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
|
||||
response.xselection.property = writeTargetToProperty(request);
|
||||
response.xselection.type = SelectionNotify;
|
||||
response.xselection.display = request->display;
|
||||
response.xselection.requestor = request->requestor;
|
||||
response.xselection.selection = request->selection;
|
||||
response.xselection.target = request->target;
|
||||
response.xselection.time = request->time;
|
||||
reply.xselection.property = writeTargetToProperty(request);
|
||||
reply.xselection.type = SelectionNotify;
|
||||
reply.xselection.display = request->display;
|
||||
reply.xselection.requestor = request->requestor;
|
||||
reply.xselection.selection = request->selection;
|
||||
reply.xselection.target = request->target;
|
||||
reply.xselection.time = request->time;
|
||||
|
||||
XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response);
|
||||
XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply);
|
||||
}
|
||||
|
||||
static void pushSelectionToManager(_GLFWwindow* window)
|
||||
@@ -763,80 +777,53 @@ static void enterFullscreenMode(_GLFWwindow* window)
|
||||
PropModeReplace, (unsigned char*) &value, 1);
|
||||
}
|
||||
|
||||
if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
|
||||
// Position the window over its monitor
|
||||
{
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->x11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = _glfw.x11.NET_WM_FULLSCREEN_MONITORS;
|
||||
event.xclient.data.l[0] = window->monitor->x11.index;
|
||||
event.xclient.data.l[1] = window->monitor->x11.index;
|
||||
event.xclient.data.l[2] = window->monitor->x11.index;
|
||||
event.xclient.data.l[3] = window->monitor->x11.index;
|
||||
|
||||
XSendEvent(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
&event);
|
||||
}
|
||||
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
int x, y;
|
||||
_glfwPlatformGetMonitorPos(window->monitor, &x, &y);
|
||||
_glfwPlatformSetWindowPos(window, x, y);
|
||||
|
||||
if (_glfw.x11.NET_ACTIVE_WINDOW)
|
||||
{
|
||||
// Ask the window manager to raise and focus the GLFW window
|
||||
// Only focused windows with the _NET_WM_STATE_FULLSCREEN state end
|
||||
// up on top of all other windows ("Stacking order" in EWMH spec)
|
||||
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->x11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = _glfw.x11.NET_ACTIVE_WINDOW;
|
||||
event.xclient.data.l[0] = 1; // Sender is a normal application
|
||||
event.xclient.data.l[1] = 0; // We don't really know the timestamp
|
||||
|
||||
XSendEvent(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
&event);
|
||||
}
|
||||
|
||||
// Ask the window manager to make the GLFW window a full screen window
|
||||
// Full screen windows are undecorated and, when focused, are kept
|
||||
// on top of all other windows
|
||||
|
||||
changeWindowState(window,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
_NET_WM_STATE_ADD);
|
||||
}
|
||||
else if (window->x11.overrideRedirect)
|
||||
{
|
||||
// In override-redirect mode we have divorced ourselves from the
|
||||
// window manager, so we need to do everything manually
|
||||
int xpos, ypos;
|
||||
GLFWvidmode mode;
|
||||
|
||||
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
|
||||
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||
|
||||
XMoveResizeWindow(_glfw.x11.display, window->x11.handle,
|
||||
xpos, ypos, mode.width, mode.height);
|
||||
}
|
||||
|
||||
if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
|
||||
{
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_FULLSCREEN_MONITORS,
|
||||
window->monitor->x11.index,
|
||||
window->monitor->x11.index,
|
||||
window->monitor->x11.index,
|
||||
window->monitor->x11.index,
|
||||
0);
|
||||
}
|
||||
|
||||
if (_glfw.x11.NET_ACTIVE_WINDOW)
|
||||
{
|
||||
// Ask the window manager to raise and focus the GLFW window
|
||||
// Only focused windows with the _NET_WM_STATE_FULLSCREEN state end up
|
||||
// on top of all other windows ("Stacking order" in EWMH spec)
|
||||
sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
XRaiseWindow(_glfw.x11.display, window->x11.handle);
|
||||
XSetInputFocus(_glfw.x11.display, window->x11.handle,
|
||||
RevertToParent, CurrentTime);
|
||||
XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos);
|
||||
XResizeWindow(_glfw.x11.display, window->x11.handle,
|
||||
mode.width, mode.height);
|
||||
}
|
||||
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
// Ask the window manager to make the GLFW window a full screen window
|
||||
// Full screen windows are undecorated and, when focused, are kept
|
||||
// on top of all other windows
|
||||
sendEventToWM(window,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
_NET_WM_STATE_ADD,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,32 +844,47 @@ static void leaveFullscreenMode(_GLFWwindow* window)
|
||||
_glfw.x11.saver.blanking,
|
||||
_glfw.x11.saver.exposure);
|
||||
}
|
||||
|
||||
if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR)
|
||||
{
|
||||
const unsigned long value = 0;
|
||||
|
||||
XChangeProperty(_glfw.x11.display, window->x11.handle,
|
||||
_glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char*) &value, 1);
|
||||
}
|
||||
|
||||
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
// Ask the window manager to make the GLFW window a normal window
|
||||
// Normal windows usually have frames and other decorations
|
||||
|
||||
changeWindowState(window,
|
||||
_glfw.x11.NET_WM_STATE_FULLSCREEN,
|
||||
_NET_WM_STATE_REMOVE);
|
||||
}
|
||||
}
|
||||
|
||||
// Decode a Unicode code point from a UTF-8 stream
|
||||
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
||||
//
|
||||
#if defined(X_HAVE_UTF8_STRING)
|
||||
static unsigned int decodeUTF8(const char** s)
|
||||
{
|
||||
unsigned int ch = 0, count = 0;
|
||||
static const unsigned int offsets[] =
|
||||
{
|
||||
0x00000000u, 0x00003080u, 0x000e2080u,
|
||||
0x03c82080u, 0xfa082080u, 0x82082080u
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
ch = (ch << 6) + (unsigned char) **s;
|
||||
(*s)++;
|
||||
count++;
|
||||
} while ((**s & 0xc0) == 0x80);
|
||||
|
||||
assert(count <= 6);
|
||||
return ch - offsets[count - 1];
|
||||
}
|
||||
#endif /*X_HAVE_UTF8_STRING*/
|
||||
|
||||
// Process the specified X event
|
||||
//
|
||||
static void processEvent(XEvent *event)
|
||||
{
|
||||
_GLFWwindow* window = NULL;
|
||||
int keycode = 0;
|
||||
Bool filtered = False;
|
||||
|
||||
// HACK: Save scancode as some IMs clear the field in XFilterEvent
|
||||
if (event->type == KeyPress || event->type == KeyRelease)
|
||||
keycode = event->xkey.keycode;
|
||||
|
||||
if (_glfw.x11.im)
|
||||
filtered = XFilterEvent(event, None);
|
||||
|
||||
if (event->type != GenericEvent)
|
||||
{
|
||||
@@ -898,53 +900,101 @@ static void processEvent(XEvent *event)
|
||||
{
|
||||
case KeyPress:
|
||||
{
|
||||
const int key = translateKey(event->xkey.keycode);
|
||||
const int key = translateKey(keycode);
|
||||
const int mods = translateState(event->xkey.state);
|
||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
|
||||
if (event->xkey.keycode)
|
||||
_glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
|
||||
|
||||
if (window->x11.ic)
|
||||
{
|
||||
// Translate keys to characters with XIM input context
|
||||
|
||||
int i;
|
||||
Status status;
|
||||
wchar_t buffer[16];
|
||||
|
||||
if (XFilterEvent(event, None))
|
||||
// HACK: Ignore duplicate key press events generated by ibus
|
||||
// Corresponding release events are filtered out by the
|
||||
// GLFW key repeat logic
|
||||
if (window->x11.last.keycode != keycode ||
|
||||
window->x11.last.time != event->xkey.time)
|
||||
{
|
||||
// Discard intermediary (dead key) events for character input
|
||||
break;
|
||||
if (keycode)
|
||||
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
|
||||
}
|
||||
|
||||
const int count = XwcLookupString(window->x11.ic,
|
||||
&event->xkey,
|
||||
buffer, sizeof(buffer),
|
||||
NULL, &status);
|
||||
window->x11.last.keycode = keycode;
|
||||
window->x11.last.time = event->xkey.time;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
_glfwInputChar(window, buffer[i], mods, plain);
|
||||
if (!filtered)
|
||||
{
|
||||
int count;
|
||||
Status status;
|
||||
#if defined(X_HAVE_UTF8_STRING)
|
||||
char buffer[96];
|
||||
char* chars = buffer;
|
||||
|
||||
count = Xutf8LookupString(window->x11.ic,
|
||||
&event->xkey,
|
||||
buffer, sizeof(buffer),
|
||||
NULL, &status);
|
||||
|
||||
if (status == XBufferOverflow)
|
||||
{
|
||||
chars = calloc(count, 1);
|
||||
count = Xutf8LookupString(window->x11.ic,
|
||||
&event->xkey,
|
||||
chars, count,
|
||||
NULL, &status);
|
||||
}
|
||||
|
||||
if (status == XLookupChars || status == XLookupBoth)
|
||||
{
|
||||
const char* c = chars;
|
||||
while (c - chars < count)
|
||||
_glfwInputChar(window, decodeUTF8(&c), mods, plain);
|
||||
}
|
||||
#else
|
||||
wchar_t buffer[16];
|
||||
wchar_t* chars = buffer;
|
||||
|
||||
count = XwcLookupString(window->x11.ic,
|
||||
&event->xkey,
|
||||
buffer, sizeof(buffer) / sizeof(wchar_t),
|
||||
NULL, &status);
|
||||
|
||||
if (status == XBufferOverflow)
|
||||
{
|
||||
chars = calloc(count, sizeof(wchar_t));
|
||||
count = XwcLookupString(window->x11.ic,
|
||||
&event->xkey,
|
||||
chars, count,
|
||||
NULL, &status);
|
||||
}
|
||||
|
||||
if (status == XLookupChars || status == XLookupBoth)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; i++)
|
||||
_glfwInputChar(window, chars[i], mods, plain);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (chars != buffer)
|
||||
free(chars);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Translate keys to characters with fallback lookup table
|
||||
|
||||
KeySym keysym;
|
||||
XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
|
||||
|
||||
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
|
||||
|
||||
const long character = _glfwKeySym2Unicode(keysym);
|
||||
if (character != -1)
|
||||
_glfwInputChar(window, character, mods, plain);
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case KeyRelease:
|
||||
{
|
||||
const int key = translateKey(event->xkey.keycode);
|
||||
const int key = translateKey(keycode);
|
||||
const int mods = translateState(event->xkey.state);
|
||||
|
||||
if (!_glfw.x11.xkb.detectable)
|
||||
@@ -955,12 +1005,12 @@ static void processEvent(XEvent *event)
|
||||
// presses to repeat, so detect and discard release events
|
||||
if (XEventsQueued(_glfw.x11.display, QueuedAfterReading))
|
||||
{
|
||||
XEvent nextEvent;
|
||||
XPeekEvent(_glfw.x11.display, &nextEvent);
|
||||
XEvent next;
|
||||
XPeekEvent(_glfw.x11.display, &next);
|
||||
|
||||
if (nextEvent.type == KeyPress &&
|
||||
nextEvent.xkey.window == event->xkey.window &&
|
||||
nextEvent.xkey.keycode == event->xkey.keycode)
|
||||
if (next.type == KeyPress &&
|
||||
next.xkey.window == event->xkey.window &&
|
||||
next.xkey.keycode == keycode)
|
||||
{
|
||||
// HACK: Repeat events sometimes leak through due to
|
||||
// some sort of time drift, so add an epsilon
|
||||
@@ -968,18 +1018,18 @@ static void processEvent(XEvent *event)
|
||||
// per second so it's fairly safe to assume that
|
||||
// no human is pressing the key 50 times per
|
||||
// second (value is ms)
|
||||
if ((nextEvent.xkey.time - event->xkey.time) < 20)
|
||||
if ((next.xkey.time - event->xkey.time) < 20)
|
||||
{
|
||||
// This is very likely a server-generated key repeat
|
||||
// event, so ignore it
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_glfwInputKey(window, key, event->xkey.keycode, GLFW_RELEASE, mods);
|
||||
break;
|
||||
_glfwInputKey(window, key, keycode, GLFW_RELEASE, mods);
|
||||
return;
|
||||
}
|
||||
|
||||
case ButtonPress:
|
||||
@@ -1013,7 +1063,7 @@ static void processEvent(XEvent *event)
|
||||
mods);
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case ButtonRelease:
|
||||
@@ -1050,7 +1100,8 @@ static void processEvent(XEvent *event)
|
||||
GLFW_RELEASE,
|
||||
mods);
|
||||
}
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case EnterNotify:
|
||||
@@ -1061,13 +1112,13 @@ static void processEvent(XEvent *event)
|
||||
hideCursor(window);
|
||||
|
||||
_glfwInputCursorEnter(window, GL_TRUE);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case LeaveNotify:
|
||||
{
|
||||
_glfwInputCursorEnter(window, GL_FALSE);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case MotionNotify:
|
||||
@@ -1081,8 +1132,8 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
if (_glfw.focusedWindow != window)
|
||||
break;
|
||||
if (_glfw.cursorWindow != window)
|
||||
return;
|
||||
|
||||
_glfwInputCursorMotion(window,
|
||||
x - window->x11.cursorPosX,
|
||||
@@ -1094,7 +1145,7 @@ static void processEvent(XEvent *event)
|
||||
|
||||
window->x11.cursorPosX = x;
|
||||
window->x11.cursorPosY = y;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case ConfigureNotify:
|
||||
@@ -1125,38 +1176,43 @@ static void processEvent(XEvent *event)
|
||||
window->x11.ypos = event->xconfigure.y;
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case ClientMessage:
|
||||
{
|
||||
// Custom client message, probably from the window manager
|
||||
|
||||
if (filtered)
|
||||
return;
|
||||
|
||||
if (event->xclient.message_type == None)
|
||||
break;
|
||||
return;
|
||||
|
||||
if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS)
|
||||
{
|
||||
if (_glfw.x11.WM_DELETE_WINDOW &&
|
||||
(Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW)
|
||||
const Atom protocol = event->xclient.data.l[0];
|
||||
if (protocol == None)
|
||||
return;
|
||||
|
||||
if (protocol == _glfw.x11.WM_DELETE_WINDOW)
|
||||
{
|
||||
// The window manager was asked to close the window, for example by
|
||||
// the user pressing a 'close' window decoration button
|
||||
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
}
|
||||
else if (_glfw.x11.NET_WM_PING &&
|
||||
(Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING)
|
||||
else if (protocol == _glfw.x11.NET_WM_PING)
|
||||
{
|
||||
// The window manager is pinging the application to ensure it's
|
||||
// still responding to events
|
||||
|
||||
event->xclient.window = _glfw.x11.root;
|
||||
XSendEvent(_glfw.x11.display,
|
||||
event->xclient.window,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
event);
|
||||
XEvent reply = *event;
|
||||
reply.xclient.window = _glfw.x11.root;
|
||||
|
||||
XSendEvent(_glfw.x11.display, _glfw.x11.root,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
&reply);
|
||||
}
|
||||
}
|
||||
else if (event->xclient.message_type == _glfw.x11.XdndEnter)
|
||||
@@ -1204,7 +1260,7 @@ static void processEvent(XEvent *event)
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case SelectionNotify:
|
||||
@@ -1250,39 +1306,56 @@ static void processEvent(XEvent *event)
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case FocusIn:
|
||||
{
|
||||
if (event->xfocus.mode == NotifyNormal)
|
||||
if (event->xfocus.mode == NotifyGrab ||
|
||||
event->xfocus.mode == NotifyUngrab)
|
||||
{
|
||||
_glfwInputWindowFocus(window, GL_TRUE);
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
// Ignore focus events from popup indicator windows, window menu
|
||||
// key chords and window dragging
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
if (window->x11.ic)
|
||||
XSetICFocus(window->x11.ic);
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
disableCursor(window);
|
||||
|
||||
_glfwInputWindowFocus(window, GL_TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
case FocusOut:
|
||||
{
|
||||
if (event->xfocus.mode == NotifyNormal)
|
||||
if (event->xfocus.mode == NotifyGrab ||
|
||||
event->xfocus.mode == NotifyUngrab)
|
||||
{
|
||||
_glfwInputWindowFocus(window, GL_FALSE);
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
restoreCursor(window);
|
||||
// Ignore focus events from popup indicator windows, window menu
|
||||
// key chords and window dragging
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
if (window->x11.ic)
|
||||
XUnsetICFocus(window->x11.ic);
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
restoreCursor(window);
|
||||
|
||||
if (window->monitor && window->autoIconify)
|
||||
_glfwPlatformIconifyWindow(window);
|
||||
|
||||
_glfwInputWindowFocus(window, GL_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
case Expose:
|
||||
{
|
||||
_glfwInputWindowDamage(window);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case PropertyNotify:
|
||||
@@ -1292,24 +1365,34 @@ static void processEvent(XEvent *event)
|
||||
{
|
||||
const int state = getWindowState(window);
|
||||
if (state == IconicState)
|
||||
{
|
||||
if (window->monitor)
|
||||
leaveFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_TRUE);
|
||||
}
|
||||
else if (state == NormalState)
|
||||
{
|
||||
if (window->monitor)
|
||||
enterFullscreenMode(window);
|
||||
|
||||
_glfwInputWindowIconify(window, GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case SelectionClear:
|
||||
{
|
||||
handleSelectionClear(event);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case SelectionRequest:
|
||||
{
|
||||
handleSelectionRequest(event);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case DestroyNotify:
|
||||
@@ -1337,8 +1420,8 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
if (_glfw.focusedWindow != window)
|
||||
break;
|
||||
if (_glfw.cursorWindow != window)
|
||||
return;
|
||||
|
||||
x = data->event_x - window->x11.cursorPosX;
|
||||
y = data->event_y - window->x11.cursorPosY;
|
||||
@@ -1359,23 +1442,15 @@ static void processEvent(XEvent *event)
|
||||
}
|
||||
|
||||
XFreeEventData(_glfw.x11.display, &event->xcookie);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
#endif /*_GLFW_HAS_XINPUT*/
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
switch (event->type - _glfw.x11.randr.eventBase)
|
||||
{
|
||||
case RRScreenChangeNotify:
|
||||
{
|
||||
XRRUpdateConfiguration(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if (event->type - _glfw.x11.randr.eventBase == RRScreenChangeNotify)
|
||||
{
|
||||
XRRUpdateConfiguration(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1560,7 +1635,7 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
_glfwSetVideoMode(window->monitor, &window->videoMode);
|
||||
|
||||
if (window->x11.overrideRedirect)
|
||||
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||
@@ -1607,27 +1682,17 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
if (!_glfwPlatformWindowVisible(window) &&
|
||||
_glfw.x11.NET_REQUEST_FRAME_EXTENTS)
|
||||
{
|
||||
// Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
|
||||
// function before the window is mapped
|
||||
|
||||
double base;
|
||||
XEvent event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->x11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = _glfw.x11.NET_REQUEST_FRAME_EXTENTS;
|
||||
// Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
|
||||
// function before the window is mapped
|
||||
sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS,
|
||||
0, 0, 0, 0, 0);
|
||||
|
||||
XSendEvent(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
False,
|
||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||
&event);
|
||||
|
||||
// HACK: Poll with timeout for the required response instead of blocking
|
||||
// HACK: Poll with timeout for the required reply instead of blocking
|
||||
// This is done because some window managers (at least Unity,
|
||||
// Fluxbox and Xfwm) failed to send the required response
|
||||
// Fluxbox and Xfwm) failed to send the required reply
|
||||
// They have been fixed but broken versions are still in the wild
|
||||
// If you are affected by this and your window manager is NOT
|
||||
// listed above, PLEASE report it to their and our issue trackers
|
||||
@@ -1675,12 +1740,12 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->x11.overrideRedirect)
|
||||
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
// Override-redirect windows cannot be iconified or restored, as those
|
||||
// tasks are performed by the window manager
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Iconification of full screen windows requires a WM that supports EWMH");
|
||||
"X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1690,12 +1755,12 @@ void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (window->x11.overrideRedirect)
|
||||
if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
// Override-redirect windows cannot be iconified or restored, as those
|
||||
// tasks are performed by the window manager
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Iconification of full screen windows requires a WM that supports EWMH");
|
||||
"X11: Iconification of full screen windows requires a WM that supports EWMH full screen");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1752,7 +1817,7 @@ void _glfwPlatformPollEvents(void)
|
||||
processEvent(&event);
|
||||
}
|
||||
|
||||
_GLFWwindow* window = _glfw.focusedWindow;
|
||||
_GLFWwindow* window = _glfw.cursorWindow;
|
||||
if (window && window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
int width, height;
|
||||
@@ -1763,7 +1828,7 @@ void _glfwPlatformPollEvents(void)
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
if (!XPending(_glfw.x11.display))
|
||||
while (!XPending(_glfw.x11.display))
|
||||
selectDisplayConnection(NULL);
|
||||
|
||||
_glfwPlatformPollEvents();
|
||||
|
||||
+3
-3
@@ -24,10 +24,10 @@
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#ifndef _xkb_unicode_h_
|
||||
#define _xkb_unicode_h_
|
||||
#ifndef _glfw3_xkb_unicode_h_
|
||||
#define _glfw3_xkb_unicode_h_
|
||||
|
||||
|
||||
long _glfwKeySym2Unicode(unsigned int keysym);
|
||||
|
||||
#endif // _xkb_unicode_h_
|
||||
#endif // _glfw3_xkb_unicode_h_
|
||||
|
||||
+6
-14
@@ -21,31 +21,23 @@ set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h"
|
||||
"${GLFW_SOURCE_DIR}/deps/tinycthread.c")
|
||||
|
||||
add_executable(clipboard clipboard.c ${GETOPT})
|
||||
add_executable(defaults defaults.c)
|
||||
add_executable(events events.c ${GETOPT})
|
||||
add_executable(fsaa fsaa.c ${GETOPT})
|
||||
add_executable(msaa msaa.c ${GETOPT})
|
||||
add_executable(gamma gamma.c ${GETOPT})
|
||||
add_executable(glfwinfo glfwinfo.c ${GETOPT})
|
||||
add_executable(iconify iconify.c ${GETOPT})
|
||||
add_executable(joysticks joysticks.c)
|
||||
add_executable(monitors monitors.c ${GETOPT})
|
||||
add_executable(peter peter.c)
|
||||
add_executable(reopen reopen.c)
|
||||
add_executable(cursor cursor.c)
|
||||
|
||||
add_executable(cursoranim WIN32 MACOSX_BUNDLE cursoranim.c)
|
||||
set_target_properties(cursoranim PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Cursor animation")
|
||||
|
||||
add_executable(accuracy WIN32 MACOSX_BUNDLE accuracy.c)
|
||||
set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy")
|
||||
|
||||
add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD})
|
||||
set_target_properties(empty PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Empty Event")
|
||||
|
||||
add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c)
|
||||
set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing")
|
||||
|
||||
add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c)
|
||||
add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT})
|
||||
set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing")
|
||||
|
||||
add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD})
|
||||
@@ -60,9 +52,9 @@ set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows")
|
||||
target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}")
|
||||
|
||||
set(WINDOWS_BINARIES accuracy empty sharing tearing threads title windows cursoranim)
|
||||
set(CONSOLE_BINARIES clipboard defaults events fsaa gamma glfwinfo
|
||||
iconify joysticks monitors peter reopen cursor)
|
||||
set(WINDOWS_BINARIES empty sharing tearing threads title windows)
|
||||
set(CONSOLE_BINARIES clipboard events msaa gamma glfwinfo
|
||||
iconify joysticks monitors reopen cursor)
|
||||
|
||||
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
|
||||
FOLDER "GLFW3/Tests")
|
||||
@@ -77,6 +69,6 @@ if (APPLE)
|
||||
set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION}
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL}
|
||||
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/AppleInfo.plist")
|
||||
MACOSX_BUNDLE_INFO_PLIST "${GLFW_SOURCE_DIR}/CMake/MacOSXBundleInfo.plist.in")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
//========================================================================
|
||||
// Mouse cursor accuracy test
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.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.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// This test came about as the result of bug #1867804
|
||||
//
|
||||
// No sign of said bug has so far been detected
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static double cursor_x = 0.0, cursor_y = 0.0;
|
||||
static int window_width = 640, window_height = 480;
|
||||
static int swap_interval = 1;
|
||||
|
||||
static void set_swap_interval(GLFWwindow* window, int interval)
|
||||
{
|
||||
char title[256];
|
||||
|
||||
swap_interval = interval;
|
||||
glfwSwapInterval(swap_interval);
|
||||
|
||||
sprintf(title, "Cursor Inaccuracy Detector (interval %i)", swap_interval);
|
||||
|
||||
glfwSetWindowTitle(window, title);
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
|
||||
glViewport(0, 0, window_width, window_height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.f, window_width, 0.f, window_height, 0.f, 1.f);
|
||||
}
|
||||
|
||||
static void cursor_position_callback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
|
||||
set_swap_interval(window, 1 - swap_interval);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
int width, height;
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = glfwCreateWindow(window_width, window_height, "", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
framebuffer_size_callback(window, width, height);
|
||||
|
||||
set_swap_interval(window, swap_interval);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(0.f, (GLfloat) (window_height - cursor_y));
|
||||
glVertex2f((GLfloat) window_width, (GLfloat) (window_height - cursor_y));
|
||||
glVertex2f((GLfloat) cursor_x, 0.f);
|
||||
glVertex2f((GLfloat) cursor_x, (GLfloat) window_height);
|
||||
glEnd();
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
+8
-2
@@ -34,6 +34,12 @@
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define MODIFIER GLFW_MOD_SUPER
|
||||
#else
|
||||
#define MODIFIER GLFW_MOD_CONTROL
|
||||
#endif
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: clipboard [-h]\n");
|
||||
@@ -56,7 +62,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
break;
|
||||
|
||||
case GLFW_KEY_V:
|
||||
if (mods == GLFW_MOD_CONTROL)
|
||||
if (mods == MODIFIER)
|
||||
{
|
||||
const char* string;
|
||||
|
||||
@@ -69,7 +75,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
break;
|
||||
|
||||
case GLFW_KEY_C:
|
||||
if (mods == GLFW_MOD_CONTROL)
|
||||
if (mods == MODIFIER)
|
||||
{
|
||||
const char* string = "Hello GLFW World!";
|
||||
glfwSetClipboardString(window, string);
|
||||
|
||||
+210
-195
@@ -23,158 +23,83 @@
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// System cursors and input modes tests.
|
||||
// This test provides an interface to the cursor image and cursor mode
|
||||
// parts of the API.
|
||||
//
|
||||
// Custom cursor image generation by urraka.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Make MS math.h define M_PI
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int W = 640;
|
||||
static int H = 480;
|
||||
static int delay = 0;
|
||||
#define CURSOR_FRAME_COUNT 60
|
||||
|
||||
static GLFWwindow* windows[2] = { NULL, NULL };
|
||||
static GLFWwindow* activeWindow = NULL;
|
||||
static GLFWcursor* cursor = NULL;
|
||||
|
||||
static struct
|
||||
{
|
||||
int key;
|
||||
double time;
|
||||
} commands[] = {
|
||||
{GLFW_KEY_H, 0},
|
||||
{GLFW_KEY_C, 0},
|
||||
{GLFW_KEY_D, 0},
|
||||
{GLFW_KEY_S, 0},
|
||||
{GLFW_KEY_N, 0},
|
||||
{GLFW_KEY_1, 0},
|
||||
{GLFW_KEY_2, 0},
|
||||
{GLFW_KEY_3, 0}
|
||||
};
|
||||
|
||||
static int CommandCount = sizeof(commands) / sizeof(commands[0]);
|
||||
|
||||
static struct
|
||||
{
|
||||
int w, h;
|
||||
} cursorSize[] = {
|
||||
{ 24, 24 }, { 13, 37 }, { 5, 53 }, { 43, 64 }, { 300, 300 }
|
||||
};
|
||||
|
||||
static int SizeCount = sizeof(cursorSize) / sizeof(cursorSize[0]);
|
||||
static int currentSize = 0;
|
||||
|
||||
static void command_callback(int key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_H:
|
||||
{
|
||||
printf("H: show this help\n");
|
||||
printf("C: call glfwCreateCursor()\n");
|
||||
printf("D: call glfwDestroyCursor()\n");
|
||||
printf("S: call glfwSetCursor()\n");
|
||||
printf("N: call glfwSetCursor() with NULL\n");
|
||||
printf("1: set GLFW_CURSOR_NORMAL\n");
|
||||
printf("2: set GLFW_CURSOR_HIDDEN\n");
|
||||
printf("3: set GLFW_CURSOR_DISABLED\n");
|
||||
printf("T: enable 3s delay for all previous commands\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case GLFW_KEY_C:
|
||||
{
|
||||
int x, y;
|
||||
GLFWimage image;
|
||||
unsigned char* pixels;
|
||||
|
||||
if (cursor)
|
||||
break;
|
||||
|
||||
image.width = cursorSize[currentSize].w;
|
||||
image.height = cursorSize[currentSize].h;
|
||||
|
||||
pixels = malloc(4 * image.width * image.height);
|
||||
image.pixels = pixels;
|
||||
|
||||
for (y = 0; y < image.height; y++)
|
||||
{
|
||||
for (x = 0; x < image.width; x++)
|
||||
{
|
||||
*pixels++ = 0xff;
|
||||
*pixels++ = 0;
|
||||
*pixels++ = 255 * y / image.height;
|
||||
*pixels++ = 255 * x / image.width;
|
||||
}
|
||||
}
|
||||
|
||||
cursor = glfwCreateCursor(&image, image.width / 2, image.height / 2);
|
||||
currentSize = (currentSize + 1) % SizeCount;
|
||||
free(image.pixels);
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_D:
|
||||
{
|
||||
if (cursor != NULL)
|
||||
{
|
||||
glfwDestroyCursor(cursor);
|
||||
cursor = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_S:
|
||||
{
|
||||
if (cursor != NULL)
|
||||
glfwSetCursor(activeWindow, cursor);
|
||||
else
|
||||
printf("The cursor is not created\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_N:
|
||||
glfwSetCursor(activeWindow, NULL);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_1:
|
||||
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_2:
|
||||
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_3:
|
||||
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static double cursor_x;
|
||||
static double cursor_y;
|
||||
static int swap_interval = 1;
|
||||
static GLboolean wait_events = GL_FALSE;
|
||||
static GLboolean animate_cursor = GL_FALSE;
|
||||
static GLboolean track_cursor = GL_FALSE;
|
||||
static GLFWcursor* standard_cursors[6];
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
static float star(int x, int y, float t)
|
||||
{
|
||||
W = width;
|
||||
H = height;
|
||||
const float c = 64 / 2.f;
|
||||
|
||||
glViewport(0, 0, W, H);
|
||||
const float i = (0.25f * (float) sin(2.f * M_PI * t) + 0.75f);
|
||||
const float k = 64 * 0.046875f * i;
|
||||
|
||||
const float dist = (float) sqrt((x - c) * (x - c) + (y - c) * (y - c));
|
||||
|
||||
const float salpha = 1.f - dist / c;
|
||||
const float xalpha = (float) x == c ? c : k / (float) fabs(x - c);
|
||||
const float yalpha = (float) y == c ? c : k / (float) fabs(y - c);
|
||||
|
||||
return (float) fmax(0.f, fmin(1.f, i * salpha * 0.2f + salpha * xalpha * yalpha));
|
||||
}
|
||||
|
||||
static void refresh_callback(GLFWwindow* window)
|
||||
static GLFWcursor* create_cursor_frame(float t)
|
||||
{
|
||||
glfwMakeContextCurrent(window);
|
||||
glClearColor(0.0f, window == activeWindow ? 0.8f : 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glfwSwapBuffers(window);
|
||||
int i = 0, x, y;
|
||||
unsigned char buffer[64 * 64 * 4];
|
||||
const GLFWimage image = { 64, 64, buffer };
|
||||
|
||||
for (y = 0; y < image.width; y++)
|
||||
{
|
||||
for (x = 0; x < image.height; x++)
|
||||
{
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = (unsigned char) (255 * star(x, y, t));
|
||||
}
|
||||
}
|
||||
|
||||
return glfwCreateCursor(&image, image.width / 2, image.height / 2);
|
||||
}
|
||||
|
||||
static void cursor_position_callback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
printf("%0.3f: Cursor position: %f %f (%+f %+f)\n",
|
||||
glfwGetTime(),
|
||||
x, y, x - cursor_x, y - cursor_y);
|
||||
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
@@ -184,104 +109,194 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_A:
|
||||
{
|
||||
animate_cursor = !animate_cursor;
|
||||
if (!animate_cursor)
|
||||
glfwSetCursor(window, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
{
|
||||
if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* FALLTHROUGH */
|
||||
}
|
||||
|
||||
case GLFW_KEY_N:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
printf("(( cursor is normal ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_D:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
printf("(( cursor is disabled ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_H:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
printf("(( cursor is hidden ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_SPACE:
|
||||
swap_interval = 1 - swap_interval;
|
||||
printf("(( swap interval: %i ))\n", swap_interval);
|
||||
glfwSwapInterval(swap_interval);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_W:
|
||||
wait_events = !wait_events;
|
||||
printf("(( %sing for events ))\n", wait_events ? "wait" : "poll");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_T:
|
||||
delay = !delay;
|
||||
printf("Delay %s.\n", delay ? "enabled" : "disabled");
|
||||
track_cursor = !track_cursor;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if (delay)
|
||||
{
|
||||
int i = 0;
|
||||
case GLFW_KEY_0:
|
||||
glfwSetCursor(window, NULL);
|
||||
break;
|
||||
|
||||
while (i < CommandCount && commands[i].key != key)
|
||||
i++;
|
||||
case GLFW_KEY_1:
|
||||
glfwSetCursor(window, standard_cursors[0]);
|
||||
break;
|
||||
|
||||
if (i < CommandCount)
|
||||
commands[i].time = glfwGetTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
command_callback(key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case GLFW_KEY_2:
|
||||
glfwSetCursor(window, standard_cursors[1]);
|
||||
break;
|
||||
|
||||
static void focus_callback(GLFWwindow* window, int focused)
|
||||
{
|
||||
if (focused)
|
||||
{
|
||||
activeWindow = window;
|
||||
refresh_callback(windows[0]);
|
||||
refresh_callback(windows[1]);
|
||||
case GLFW_KEY_3:
|
||||
glfwSetCursor(window, standard_cursors[2]);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_4:
|
||||
glfwSetCursor(window, standard_cursors[3]);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_5:
|
||||
glfwSetCursor(window, standard_cursors[4]);
|
||||
break;
|
||||
|
||||
case GLFW_KEY_6:
|
||||
glfwSetCursor(window, standard_cursors[5]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
GLboolean running = GL_TRUE;
|
||||
GLFWwindow* window;
|
||||
GLFWcursor* star_cursors[CURSOR_FRAME_COUNT];
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
for (i = 0; i < CURSOR_FRAME_COUNT; i++)
|
||||
{
|
||||
windows[i] = glfwCreateWindow(W, H, "Cursor testing", NULL, NULL);
|
||||
|
||||
if (!windows[i])
|
||||
star_cursors[i] = create_cursor_frame(i / (float) CURSOR_FRAME_COUNT);
|
||||
if (!star_cursors[i])
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwSetWindowPos(windows[i], 100 + (i & 1) * (W + 50), 100);
|
||||
|
||||
glfwSetWindowRefreshCallback(windows[i], refresh_callback);
|
||||
glfwSetFramebufferSizeCallback(windows[i], framebuffer_size_callback);
|
||||
glfwSetKeyCallback(windows[i], key_callback);
|
||||
glfwSetWindowFocusCallback(windows[i], focus_callback);
|
||||
|
||||
glfwMakeContextCurrent(windows[i]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glfwSwapBuffers(windows[i]);
|
||||
}
|
||||
|
||||
activeWindow = windows[0];
|
||||
|
||||
key_callback(NULL, GLFW_KEY_H, 0, GLFW_PRESS, 0);
|
||||
|
||||
while (running)
|
||||
for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++)
|
||||
{
|
||||
if (delay)
|
||||
{
|
||||
int i;
|
||||
double t = glfwGetTime();
|
||||
const int shapes[] = {
|
||||
GLFW_ARROW_CURSOR,
|
||||
GLFW_IBEAM_CURSOR,
|
||||
GLFW_CROSSHAIR_CURSOR,
|
||||
GLFW_HAND_CURSOR,
|
||||
GLFW_HRESIZE_CURSOR,
|
||||
GLFW_VRESIZE_CURSOR
|
||||
};
|
||||
|
||||
for (i = 0; i < CommandCount; i++)
|
||||
{
|
||||
if (commands[i].time != 0 && t - commands[i].time >= 3.0)
|
||||
{
|
||||
command_callback(commands[i].key);
|
||||
commands[i].time = 0;
|
||||
}
|
||||
}
|
||||
standard_cursors[i] = glfwCreateStandardCursor(shapes[i]);
|
||||
if (!standard_cursors[i])
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Cursor Test", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
glfwGetCursorPos(window, &cursor_x, &cursor_y);
|
||||
printf("Cursor position: %f %f\n", cursor_x, cursor_y);
|
||||
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (track_cursor)
|
||||
{
|
||||
int wnd_width, wnd_height, fb_width, fb_height;
|
||||
float scale;
|
||||
|
||||
glfwGetWindowSize(window, &wnd_width, &wnd_height);
|
||||
glfwGetFramebufferSize(window, &fb_width, &fb_height);
|
||||
|
||||
scale = (float) fb_width / (float) wnd_width;
|
||||
|
||||
glViewport(0, 0, fb_width, fb_height);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.f, fb_width, 0.f, fb_height, 0.f, 1.f);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(0.f, (GLfloat) (fb_height - cursor_y * scale));
|
||||
glVertex2f((GLfloat) fb_width, (GLfloat) (fb_height - cursor_y * scale));
|
||||
glVertex2f((GLfloat) cursor_x * scale, 0.f);
|
||||
glVertex2f((GLfloat) cursor_x * scale, (GLfloat) fb_height);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
running = !(glfwWindowShouldClose(windows[0]) || glfwWindowShouldClose(windows[1]));
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
glfwPollEvents();
|
||||
if (animate_cursor)
|
||||
{
|
||||
const int i = (int) (glfwGetTime() * 30.0) % CURSOR_FRAME_COUNT;
|
||||
glfwSetCursor(window, star_cursors[i]);
|
||||
}
|
||||
|
||||
if (wait_events)
|
||||
glfwWaitEvents();
|
||||
else
|
||||
glfwPollEvents();
|
||||
|
||||
// Workaround for an issue with msvcrt and mintty
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
|
||||
for (i = 0; i < CURSOR_FRAME_COUNT; i++)
|
||||
glfwDestroyCursor(star_cursors[i]);
|
||||
|
||||
for (i = 0; i < sizeof(standard_cursors) / sizeof(standard_cursors[0]); i++)
|
||||
glfwDestroyCursor(standard_cursors[i]);
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
//========================================================================
|
||||
// Cursor animation
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.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.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// Cursor animation test.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#define SIZE 64 // cursor size (width & height)
|
||||
#define N 60 // number of frames
|
||||
|
||||
unsigned char buffer[4 * SIZE * SIZE];
|
||||
|
||||
static float max(float a, float b) { return a > b ? a : b; }
|
||||
static float min(float a, float b) { return a < b ? a : b; }
|
||||
|
||||
static float star(int x, int y, float t)
|
||||
{
|
||||
float c = SIZE / 2.0f;
|
||||
|
||||
float i = (0.25f * (float)sin(2.0f * 3.1415926f * t) + 0.75f);
|
||||
float k = SIZE * 0.046875f * i;
|
||||
|
||||
float dist = (float)sqrt((x - c) * (x - c) + (y - c) * (y - c));
|
||||
|
||||
float salpha = 1.0f - dist / c;
|
||||
float xalpha = (float)x == c ? c : k / (float)fabs(x - c);
|
||||
float yalpha = (float)y == c ? c : k / (float)fabs(y - c);
|
||||
|
||||
return max(0.0f, min(1.0f, i * salpha * 0.2f + salpha * xalpha * yalpha));
|
||||
}
|
||||
|
||||
static GLFWcursor* load_frame(float t)
|
||||
{
|
||||
int i = 0, x, y;
|
||||
const GLFWimage image = { SIZE, SIZE, buffer };
|
||||
|
||||
for (y = 0; y < image.width; y++)
|
||||
{
|
||||
for (x = 0; x < image.height; x++)
|
||||
{
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = 255;
|
||||
buffer[i++] = (unsigned char)(255 * star(x, y, t));
|
||||
}
|
||||
}
|
||||
|
||||
return glfwCreateCursor(&image, image.width / 2, image.height / 2);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
double t0, t1, frameTime = 0.0;
|
||||
|
||||
GLFWwindow* window;
|
||||
GLFWcursor* frames[N];
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Cursor animation", NULL, NULL);
|
||||
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
frames[i] = load_frame(i / (float)N);
|
||||
|
||||
i = 0;
|
||||
|
||||
t0 = glfwGetTime();
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glfwSetCursor(window, frames[i]);
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
t1 = glfwGetTime();
|
||||
frameTime += t1 - t0;
|
||||
t0 = t1;
|
||||
|
||||
while (frameTime > 1.0 / (double)N)
|
||||
{
|
||||
i = (i + 1) % N;
|
||||
frameTime -= 1.0 / (double)N;
|
||||
}
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
//========================================================================
|
||||
// Default window/context test
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.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.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// This test creates a windowed mode window with all window hints set to
|
||||
// default values and then reports the actual attributes of the created
|
||||
// window and context
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#define GLFW_INCLUDE_GLEXT
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int attrib;
|
||||
const char* ext;
|
||||
const char* name;
|
||||
} AttribGL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int attrib;
|
||||
const char* name;
|
||||
} AttribGLFW;
|
||||
|
||||
static AttribGL gl_attribs[] =
|
||||
{
|
||||
{ GL_RED_BITS, NULL, "red bits" },
|
||||
{ GL_GREEN_BITS, NULL, "green bits" },
|
||||
{ GL_BLUE_BITS, NULL, "blue bits" },
|
||||
{ GL_ALPHA_BITS, NULL, "alpha bits" },
|
||||
{ GL_DEPTH_BITS, NULL, "depth bits" },
|
||||
{ GL_STENCIL_BITS, NULL, "stencil bits" },
|
||||
{ GL_STEREO, NULL, "stereo" },
|
||||
{ GL_SAMPLES_ARB, "GL_ARB_multisample", "FSAA samples" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
static AttribGLFW glfw_attribs[] =
|
||||
{
|
||||
{ GLFW_CONTEXT_VERSION_MAJOR, "Context version major" },
|
||||
{ GLFW_CONTEXT_VERSION_MINOR, "Context version minor" },
|
||||
{ GLFW_OPENGL_FORWARD_COMPAT, "OpenGL forward compatible" },
|
||||
{ GLFW_OPENGL_DEBUG_CONTEXT, "OpenGL debug context" },
|
||||
{ GLFW_OPENGL_PROFILE, "OpenGL profile" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i, width, height;
|
||||
GLFWwindow* window;
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "Defaults", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
|
||||
printf("framebuffer size: %ix%i\n", width, height);
|
||||
|
||||
for (i = 0; glfw_attribs[i].name; i++)
|
||||
{
|
||||
printf("%s: %i\n",
|
||||
glfw_attribs[i].name,
|
||||
glfwGetWindowAttrib(window, glfw_attribs[i].attrib));
|
||||
}
|
||||
|
||||
for (i = 0; gl_attribs[i].name; i++)
|
||||
{
|
||||
GLint value = 0;
|
||||
|
||||
if (gl_attribs[i].ext)
|
||||
{
|
||||
if (!glfwExtensionSupported(gl_attribs[i].ext))
|
||||
continue;
|
||||
}
|
||||
|
||||
glGetIntegerv(gl_attribs[i].attrib, &value);
|
||||
|
||||
printf("%s: %i\n", gl_attribs[i].name, value);
|
||||
}
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
window = NULL;
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
+380
-158
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// Version information dumper
|
||||
// Context creation and information tool
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
@@ -22,14 +22,13 @@
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// This test is a pale imitation of glxinfo(1), except not really
|
||||
//
|
||||
// It dumps GLFW and OpenGL version information
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
/* HACK: Explicitly include the glext.h shipping with GLFW, as this program uses
|
||||
* many modern symbols not provided by the versions in some development
|
||||
* environments (for example on OS X).
|
||||
*/
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -42,8 +41,8 @@
|
||||
#define strcasecmp(x, y) _stricmp(x, y)
|
||||
#endif
|
||||
|
||||
#define API_OPENGL "gl"
|
||||
#define API_OPENGL_ES "es"
|
||||
#define API_NAME_OPENGL "gl"
|
||||
#define API_NAME_OPENGL_ES "es"
|
||||
|
||||
#define PROFILE_NAME_CORE "core"
|
||||
#define PROFILE_NAME_COMPAT "compat"
|
||||
@@ -56,18 +55,44 @@
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: glfwinfo [-h] [-a API] [-m MAJOR] [-n MINOR] [-d] [-l] [-f] [-p PROFILE] [-s STRATEGY] [-b BEHAVIOR]\n");
|
||||
printf("Usage: glfwinfo [OPTION]...\n");
|
||||
printf("Options:\n");
|
||||
printf(" -a the client API to use (" API_OPENGL " or " API_OPENGL_ES ")\n");
|
||||
printf(" -b the release behavior to use (" BEHAVIOR_NAME_NONE " or " BEHAVIOR_NAME_FLUSH ")\n");
|
||||
printf(" -d request a debug context\n");
|
||||
printf(" -f require a forward-compatible context\n");
|
||||
printf(" -h show this help\n");
|
||||
printf(" -l list all client API extensions after context creation\n");
|
||||
printf(" -m the major number of the required client API version\n");
|
||||
printf(" -n the minor number of the required client API version\n");
|
||||
printf(" -p the OpenGL profile to use (" PROFILE_NAME_CORE " or " PROFILE_NAME_COMPAT ")\n");
|
||||
printf(" -s the robustness strategy to use (" STRATEGY_NAME_NONE " or " STRATEGY_NAME_LOSE ")\n");
|
||||
printf(" -a, --client-api=API the client API to use ("
|
||||
API_NAME_OPENGL " or "
|
||||
API_NAME_OPENGL_ES ")\n");
|
||||
printf(" -b, --behavior=BEHAVIOR the release behavior to use ("
|
||||
BEHAVIOR_NAME_NONE " or "
|
||||
BEHAVIOR_NAME_FLUSH ")\n");
|
||||
printf(" -d, --debug request a debug context\n");
|
||||
printf(" -f, --forward require a forward-compatible context\n");
|
||||
printf(" -h, --help show this help\n");
|
||||
printf(" -l, --list-extensions list all client API extensions\n");
|
||||
printf(" -m, --major=MAJOR the major number of the required "
|
||||
"client API version\n");
|
||||
printf(" -n, --minor=MINOR the minor number of the required "
|
||||
"client API version\n");
|
||||
printf(" -p, --profile=PROFILE the OpenGL profile to use ("
|
||||
PROFILE_NAME_CORE " or "
|
||||
PROFILE_NAME_COMPAT ")\n");
|
||||
printf(" -s, --robustness=STRATEGY the robustness strategy to use ("
|
||||
STRATEGY_NAME_NONE " or "
|
||||
STRATEGY_NAME_LOSE ")\n");
|
||||
printf(" -v, --version print version information\n");
|
||||
printf(" --red-bits=N the number of red bits to request\n");
|
||||
printf(" --green-bits=N the number of green bits to request\n");
|
||||
printf(" --blue-bits=N the number of blue bits to request\n");
|
||||
printf(" --alpha-bits=N the number of alpha bits to request\n");
|
||||
printf(" --depth-bits=N the number of depth bits to request\n");
|
||||
printf(" --stencil-bits=N the number of stencil bits to request\n");
|
||||
printf(" --accum-red-bits=N the number of red bits to request\n");
|
||||
printf(" --accum-green-bits=N the number of green bits to request\n");
|
||||
printf(" --accum-blue-bits=N the number of blue bits to request\n");
|
||||
printf(" --accum-alpha-bits=N the number of alpha bits to request\n");
|
||||
printf(" --aux-buffers=N the number of aux buffers to request\n");
|
||||
printf(" --samples=N the number of MSAA samples to request\n");
|
||||
printf(" --stereo request stereo rendering\n");
|
||||
printf(" --srgb request an sRGB capable framebuffer\n");
|
||||
printf(" --singlebuffer request single-buffering\n");
|
||||
}
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
@@ -75,7 +100,7 @@ static void error_callback(int error, const char* description)
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
static const char* get_client_api_name(int api)
|
||||
static const char* get_api_name(int api)
|
||||
{
|
||||
if (api == GLFW_OPENGL_API)
|
||||
return "OpenGL";
|
||||
@@ -131,11 +156,12 @@ static void list_extensions(int api, int major, int minor)
|
||||
GLint count;
|
||||
const GLubyte* extensions;
|
||||
|
||||
printf("%s context supported extensions:\n", get_client_api_name(api));
|
||||
printf("%s context supported extensions:\n", get_api_name(api));
|
||||
|
||||
if (api == GLFW_OPENGL_API && major > 2)
|
||||
{
|
||||
PFNGLGETSTRINGIPROC glGetStringi = (PFNGLGETSTRINGIPROC) glfwGetProcAddress("glGetStringi");
|
||||
PFNGLGETSTRINGIPROC glGetStringi =
|
||||
(PFNGLGETSTRINGIPROC) glfwGetProcAddress("glGetStringi");
|
||||
if (!glGetStringi)
|
||||
{
|
||||
glfwTerminate();
|
||||
@@ -167,16 +193,8 @@ static void list_extensions(int api, int major, int minor)
|
||||
static GLboolean valid_version(void)
|
||||
{
|
||||
int major, minor, revision;
|
||||
|
||||
glfwGetVersion(&major, &minor, &revision);
|
||||
|
||||
printf("GLFW header version: %u.%u.%u\n",
|
||||
GLFW_VERSION_MAJOR,
|
||||
GLFW_VERSION_MINOR,
|
||||
GLFW_VERSION_REVISION);
|
||||
|
||||
printf("GLFW library version: %u.%u.%u\n", major, minor, revision);
|
||||
|
||||
if (major != GLFW_VERSION_MAJOR)
|
||||
{
|
||||
printf("*** ERROR: GLFW major version mismatch! ***\n");
|
||||
@@ -186,88 +204,64 @@ static GLboolean valid_version(void)
|
||||
if (minor != GLFW_VERSION_MINOR || revision != GLFW_VERSION_REVISION)
|
||||
printf("*** WARNING: GLFW version mismatch! ***\n");
|
||||
|
||||
printf("GLFW library version string: \"%s\"\n", glfwGetVersionString());
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
int major, minor, revision;
|
||||
glfwGetVersion(&major, &minor, &revision);
|
||||
|
||||
printf("GLFW header version: %u.%u.%u\n",
|
||||
GLFW_VERSION_MAJOR,
|
||||
GLFW_VERSION_MINOR,
|
||||
GLFW_VERSION_REVISION);
|
||||
printf("GLFW library version: %u.%u.%u\n", major, minor, revision);
|
||||
printf("GLFW library version string: \"%s\"\n", glfwGetVersionString());
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ch, api = 0, profile = 0, strategy = 0, behavior = 0, major = 1, minor = 0, revision;
|
||||
GLboolean debug = GL_FALSE, forward = GL_FALSE, list = GL_FALSE;
|
||||
GLint flags, mask;
|
||||
int ch, api, major, minor, revision, profile;
|
||||
GLint redbits, greenbits, bluebits, alphabits, depthbits, stencilbits;
|
||||
GLboolean list = GL_FALSE;
|
||||
GLFWwindow* window;
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:b:dfhlm:n:p:s:")) != -1)
|
||||
enum { API, BEHAVIOR, DEBUG, FORWARD, HELP, EXTENSIONS,
|
||||
MAJOR, MINOR, PROFILE, ROBUSTNESS, VERSION,
|
||||
REDBITS, GREENBITS, BLUEBITS, ALPHABITS, DEPTHBITS, STENCILBITS,
|
||||
ACCUMREDBITS, ACCUMGREENBITS, ACCUMBLUEBITS, ACCUMALPHABITS,
|
||||
AUXBUFFERS, SAMPLES, STEREO, SRGB, SINGLEBUFFER };
|
||||
const struct option options[] =
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'a':
|
||||
if (strcasecmp(optarg, API_OPENGL) == 0)
|
||||
api = GLFW_OPENGL_API;
|
||||
else if (strcasecmp(optarg, API_OPENGL_ES) == 0)
|
||||
api = GLFW_OPENGL_ES_API;
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (strcasecmp(optarg, BEHAVIOR_NAME_NONE) == 0)
|
||||
behavior = GLFW_RELEASE_BEHAVIOR_NONE;
|
||||
else if (strcasecmp(optarg, BEHAVIOR_NAME_FLUSH) == 0)
|
||||
behavior = GLFW_RELEASE_BEHAVIOR_FLUSH;
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
debug = GL_TRUE;
|
||||
break;
|
||||
case 'f':
|
||||
forward = GL_TRUE;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
list = GL_TRUE;
|
||||
break;
|
||||
case 'm':
|
||||
major = atoi(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
minor = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
if (strcasecmp(optarg, PROFILE_NAME_CORE) == 0)
|
||||
profile = GLFW_OPENGL_CORE_PROFILE;
|
||||
else if (strcasecmp(optarg, PROFILE_NAME_COMPAT) == 0)
|
||||
profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0)
|
||||
strategy = GLFW_NO_RESET_NOTIFICATION;
|
||||
else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0)
|
||||
strategy = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
{ "behavior", 1, NULL, BEHAVIOR },
|
||||
{ "client-api", 1, NULL, API },
|
||||
{ "debug", 0, NULL, DEBUG },
|
||||
{ "forward", 0, NULL, FORWARD },
|
||||
{ "help", 0, NULL, HELP },
|
||||
{ "list-extensions", 0, NULL, EXTENSIONS },
|
||||
{ "major", 1, NULL, MAJOR },
|
||||
{ "minor", 1, NULL, MINOR },
|
||||
{ "profile", 1, NULL, PROFILE },
|
||||
{ "robustness", 1, NULL, ROBUSTNESS },
|
||||
{ "version", 0, NULL, VERSION },
|
||||
{ "red-bits", 1, NULL, REDBITS },
|
||||
{ "green-bits", 1, NULL, GREENBITS },
|
||||
{ "blue-bits", 1, NULL, BLUEBITS },
|
||||
{ "alpha-bits", 1, NULL, ALPHABITS },
|
||||
{ "depth-bits", 1, NULL, DEPTHBITS },
|
||||
{ "stencil-bits", 1, NULL, STENCILBITS },
|
||||
{ "accum-red-bits", 1, NULL, ACCUMREDBITS },
|
||||
{ "accum-green-bits", 1, NULL, ACCUMGREENBITS },
|
||||
{ "accum-blue-bits", 1, NULL, ACCUMBLUEBITS },
|
||||
{ "accum-alpha-bits", 1, NULL, ACCUMALPHABITS },
|
||||
{ "aux-buffers", 1, NULL, AUXBUFFERS },
|
||||
{ "samples", 1, NULL, SAMPLES },
|
||||
{ "stereo", 0, NULL, STEREO },
|
||||
{ "srgb", 0, NULL, SRGB },
|
||||
{ "singlebuffer", 0, NULL, SINGLEBUFFER },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
// Initialize GLFW and create window
|
||||
|
||||
@@ -279,43 +273,192 @@ int main(int argc, char** argv)
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (major != 1 || minor != 0)
|
||||
while ((ch = getopt_long(argc, argv, "a:b:dfhlm:n:p:s:v", options, NULL)) != -1)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor);
|
||||
switch (ch)
|
||||
{
|
||||
case 'a':
|
||||
case API:
|
||||
if (strcasecmp(optarg, API_NAME_OPENGL) == 0)
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
|
||||
else if (strcasecmp(optarg, API_NAME_OPENGL_ES) == 0)
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
case BEHAVIOR:
|
||||
if (strcasecmp(optarg, BEHAVIOR_NAME_NONE) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR,
|
||||
GLFW_RELEASE_BEHAVIOR_NONE);
|
||||
}
|
||||
else if (strcasecmp(optarg, BEHAVIOR_NAME_FLUSH) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR,
|
||||
GLFW_RELEASE_BEHAVIOR_FLUSH);
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
case DEBUG:
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
|
||||
break;
|
||||
case 'f':
|
||||
case FORWARD:
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
break;
|
||||
case 'h':
|
||||
case HELP:
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
case EXTENSIONS:
|
||||
list = GL_TRUE;
|
||||
break;
|
||||
case 'm':
|
||||
case MAJOR:
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, atoi(optarg));
|
||||
break;
|
||||
case 'n':
|
||||
case MINOR:
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, atoi(optarg));
|
||||
break;
|
||||
case 'p':
|
||||
case PROFILE:
|
||||
if (strcasecmp(optarg, PROFILE_NAME_CORE) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE,
|
||||
GLFW_OPENGL_CORE_PROFILE);
|
||||
}
|
||||
else if (strcasecmp(optarg, PROFILE_NAME_COMPAT) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE,
|
||||
GLFW_OPENGL_COMPAT_PROFILE);
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case ROBUSTNESS:
|
||||
if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS,
|
||||
GLFW_NO_RESET_NOTIFICATION);
|
||||
}
|
||||
else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS,
|
||||
GLFW_LOSE_CONTEXT_ON_RESET);
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
case VERSION:
|
||||
print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
case REDBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_RED_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_RED_BITS, atoi(optarg));
|
||||
break;
|
||||
case GREENBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_GREEN_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_GREEN_BITS, atoi(optarg));
|
||||
break;
|
||||
case BLUEBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_BLUE_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_BLUE_BITS, atoi(optarg));
|
||||
break;
|
||||
case ALPHABITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_ALPHA_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_ALPHA_BITS, atoi(optarg));
|
||||
break;
|
||||
case DEPTHBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, atoi(optarg));
|
||||
break;
|
||||
case STENCILBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, atoi(optarg));
|
||||
break;
|
||||
case ACCUMREDBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_ACCUM_RED_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_ACCUM_RED_BITS, atoi(optarg));
|
||||
break;
|
||||
case ACCUMGREENBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_ACCUM_GREEN_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_ACCUM_GREEN_BITS, atoi(optarg));
|
||||
break;
|
||||
case ACCUMBLUEBITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_ACCUM_BLUE_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_ACCUM_BLUE_BITS, atoi(optarg));
|
||||
break;
|
||||
case ACCUMALPHABITS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, atoi(optarg));
|
||||
break;
|
||||
case AUXBUFFERS:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_AUX_BUFFERS, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_AUX_BUFFERS, atoi(optarg));
|
||||
break;
|
||||
case SAMPLES:
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
glfwWindowHint(GLFW_SAMPLES, GLFW_DONT_CARE);
|
||||
else
|
||||
glfwWindowHint(GLFW_SAMPLES, atoi(optarg));
|
||||
break;
|
||||
case STEREO:
|
||||
glfwWindowHint(GLFW_STEREO, GL_TRUE);
|
||||
break;
|
||||
case SRGB:
|
||||
glfwWindowHint(GLFW_SRGB_CAPABLE, GL_TRUE);
|
||||
break;
|
||||
case SINGLEBUFFER:
|
||||
glfwWindowHint(GLFW_DOUBLEBUFFER, GL_FALSE);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (api != 0)
|
||||
glfwWindowHint(GLFW_CLIENT_API, api);
|
||||
|
||||
if (debug)
|
||||
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
|
||||
|
||||
if (forward)
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
if (profile != 0)
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, profile);
|
||||
|
||||
if (strategy)
|
||||
glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, strategy);
|
||||
|
||||
if (behavior)
|
||||
glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR, behavior);
|
||||
|
||||
glfwWindowHint(GLFW_RED_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_GREEN_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_BLUE_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_ALPHA_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_DEPTH_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_ACCUM_RED_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_ACCUM_GREEN_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_ACCUM_BLUE_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_AUX_BUFFERS, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_SAMPLES, GLFW_DONT_CARE);
|
||||
glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_DONT_CARE);
|
||||
print_version();
|
||||
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||||
|
||||
@@ -334,13 +477,14 @@ int main(int argc, char** argv)
|
||||
major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
|
||||
minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
|
||||
revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
|
||||
profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE);
|
||||
|
||||
printf("%s context version string: \"%s\"\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
glGetString(GL_VERSION));
|
||||
|
||||
printf("%s context version parsed by GLFW: %u.%u.%u\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
major, minor, revision);
|
||||
|
||||
// Report client API context properties
|
||||
@@ -349,8 +493,10 @@ int main(int argc, char** argv)
|
||||
{
|
||||
if (major >= 3)
|
||||
{
|
||||
GLint flags;
|
||||
|
||||
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
printf("%s context flags (0x%08x):", get_client_api_name(api), flags);
|
||||
printf("%s context flags (0x%08x):", get_api_name(api), flags);
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||
printf(" forward-compatible");
|
||||
@@ -360,65 +506,141 @@ int main(int argc, char** argv)
|
||||
printf(" robustness");
|
||||
putchar('\n');
|
||||
|
||||
printf("%s context flags parsed by GLFW:", get_client_api_name(api));
|
||||
printf("%s context flags parsed by GLFW:", get_api_name(api));
|
||||
|
||||
if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT))
|
||||
printf(" forward-compatible");
|
||||
if (glfwGetWindowAttrib(window, GLFW_OPENGL_DEBUG_CONTEXT))
|
||||
printf(" debug");
|
||||
if (glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS) != GLFW_NO_ROBUSTNESS)
|
||||
if (glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS) == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
printf(" robustness");
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
if (major > 3 || (major == 3 && minor >= 2))
|
||||
if (major >= 4 || (major == 3 && minor >= 2))
|
||||
{
|
||||
int profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE);
|
||||
|
||||
GLint mask;
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
|
||||
printf("%s profile mask (0x%08x): %s\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
mask,
|
||||
get_profile_name_gl(mask));
|
||||
|
||||
printf("%s profile mask parsed by GLFW: %s\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
get_profile_name_glfw(profile));
|
||||
}
|
||||
|
||||
if (glfwExtensionSupported("GL_ARB_robustness"))
|
||||
{
|
||||
int robustness;
|
||||
const int robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS);
|
||||
GLint strategy;
|
||||
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy);
|
||||
|
||||
printf("%s robustness strategy (0x%08x): %s\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
strategy,
|
||||
get_strategy_name_gl(strategy));
|
||||
|
||||
robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS);
|
||||
|
||||
printf("%s robustness strategy parsed by GLFW: %s\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
get_strategy_name_glfw(robustness));
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s context renderer string: \"%s\"\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
glGetString(GL_RENDERER));
|
||||
printf("%s context vendor string: \"%s\"\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
glGetString(GL_VENDOR));
|
||||
|
||||
if (major > 1)
|
||||
if (major >= 2)
|
||||
{
|
||||
printf("%s context shading language version: \"%s\"\n",
|
||||
get_client_api_name(api),
|
||||
get_api_name(api),
|
||||
glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
}
|
||||
|
||||
printf("Framebuffer:\n");
|
||||
|
||||
if (api == GLFW_OPENGL_API && profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
{
|
||||
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC
|
||||
glGetFramebufferAttachmentParameteriv =
|
||||
(PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)
|
||||
glfwGetProcAddress("glGetFramebufferAttachmentParameteriv");
|
||||
if (!glGetFramebufferAttachmentParameteriv)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
|
||||
&redbits);
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
|
||||
&greenbits);
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
|
||||
&bluebits);
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
|
||||
&alphabits);
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_DEPTH,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
|
||||
&depthbits);
|
||||
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
|
||||
GL_STENCIL,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
|
||||
&stencilbits);
|
||||
}
|
||||
else
|
||||
{
|
||||
glGetIntegerv(GL_RED_BITS, &redbits);
|
||||
glGetIntegerv(GL_GREEN_BITS, &greenbits);
|
||||
glGetIntegerv(GL_BLUE_BITS, &bluebits);
|
||||
glGetIntegerv(GL_ALPHA_BITS, &alphabits);
|
||||
glGetIntegerv(GL_DEPTH_BITS, &depthbits);
|
||||
glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
|
||||
}
|
||||
|
||||
printf(" red: %u green: %u blue: %u alpha: %u depth: %u stencil: %u\n",
|
||||
redbits, greenbits, bluebits, alphabits, depthbits, stencilbits);
|
||||
|
||||
if (api == GLFW_OPENGL_ES_API ||
|
||||
glfwExtensionSupported("GL_ARB_multisample") ||
|
||||
major > 1 || minor >= 3)
|
||||
{
|
||||
GLint samples, samplebuffers;
|
||||
glGetIntegerv(GL_SAMPLES, &samples);
|
||||
glGetIntegerv(GL_SAMPLE_BUFFERS, &samplebuffers);
|
||||
|
||||
printf(" samples: %u sample buffers: %u\n", samples, samplebuffers);
|
||||
}
|
||||
|
||||
if (api == GLFW_OPENGL_API && profile != GLFW_OPENGL_CORE_PROFILE)
|
||||
{
|
||||
GLint accumredbits, accumgreenbits, accumbluebits, accumalphabits;
|
||||
GLint auxbuffers;
|
||||
|
||||
glGetIntegerv(GL_ACCUM_RED_BITS, &accumredbits);
|
||||
glGetIntegerv(GL_ACCUM_GREEN_BITS, &accumgreenbits);
|
||||
glGetIntegerv(GL_ACCUM_BLUE_BITS, &accumbluebits);
|
||||
glGetIntegerv(GL_ACCUM_ALPHA_BITS, &accumalphabits);
|
||||
glGetIntegerv(GL_AUX_BUFFERS, &auxbuffers);
|
||||
|
||||
printf(" accum red: %u accum green: %u accum blue: %u accum alpha: %u aux buffers: %u\n",
|
||||
accumredbits, accumgreenbits, accumbluebits, accumalphabits, auxbuffers);
|
||||
}
|
||||
|
||||
// Report client API extensions
|
||||
if (list)
|
||||
list_extensions(api, major, minor);
|
||||
|
||||
@@ -99,6 +99,9 @@ static void window_iconify_callback(GLFWwindow* window, int iconified)
|
||||
static void window_refresh_callback(GLFWwindow* window)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
printf("%0.2f Window refresh\n", glfwGetTime());
|
||||
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
+3
-3
@@ -83,7 +83,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
static void list_modes(GLFWmonitor* monitor)
|
||||
{
|
||||
int count, x, y, widthMM, heightMM, dpi, i;
|
||||
int count, x, y, widthMM, heightMM, i;
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count);
|
||||
|
||||
@@ -96,8 +96,8 @@ static void list_modes(GLFWmonitor* monitor)
|
||||
printf("Current mode: %s\n", format_mode(mode));
|
||||
printf("Virtual position: %i %i\n", x, y);
|
||||
|
||||
dpi = (int) ((float) mode->width * 25.4f / (float) widthMM);
|
||||
printf("Physical size: %i x %i mm (%i dpi)\n", widthMM, heightMM, dpi);
|
||||
printf("Physical size: %i x %i mm (%0.2f dpi)\n",
|
||||
widthMM, heightMM, mode->width * 25.4f / widthMM);
|
||||
|
||||
printf("Modes:\n");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//========================================================================
|
||||
// Full screen anti-aliasing test
|
||||
// Multisample anti-aliasing test
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
@@ -25,7 +25,7 @@
|
||||
//
|
||||
// This test renders two high contrast, slowly rotating quads, one aliased
|
||||
// and one (hopefully) anti-aliased, thus allowing for visual verification
|
||||
// of whether FSAA is indeed enabled
|
||||
// of whether MSAA is indeed enabled
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
@@ -62,7 +62,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: fsaa [-h] [-s SAMPLES]\n");
|
||||
printf("Usage: msaa [-h] [-s SAMPLES]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@@ -92,9 +92,9 @@ int main(int argc, char** argv)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (samples)
|
||||
printf("Requesting FSAA with %i samples\n", samples);
|
||||
printf("Requesting MSAA with %i samples\n", samples);
|
||||
else
|
||||
printf("Requesting that FSAA not be available\n");
|
||||
printf("Requesting that MSAA not be available\n");
|
||||
|
||||
glfwWindowHint(GLFW_SAMPLES, samples);
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||||
@@ -124,9 +124,9 @@ int main(int argc, char** argv)
|
||||
|
||||
glGetIntegerv(GL_SAMPLES_ARB, &samples);
|
||||
if (samples)
|
||||
printf("Context reports FSAA is available with %i samples\n", samples);
|
||||
printf("Context reports MSAA is available with %i samples\n", samples);
|
||||
else
|
||||
printf("Context reports FSAA is unavailable\n");
|
||||
printf("Context reports MSAA is unavailable\n");
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glOrtho(0.f, 1.f, 0.f, 0.5f, 0.f, 1.f);
|
||||
-151
@@ -1,151 +0,0 @@
|
||||
//========================================================================
|
||||
// Cursor mode test
|
||||
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.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.
|
||||
//
|
||||
//========================================================================
|
||||
//
|
||||
// This test allows you to switch between the various cursor modes
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static GLboolean reopen = GL_FALSE;
|
||||
static double cursor_x;
|
||||
static double cursor_y;
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
static void cursor_position_callback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
printf("%0.3f: Cursor position: %f %f (%f %f)\n",
|
||||
glfwGetTime(),
|
||||
x, y, x - cursor_x, y - cursor_y);
|
||||
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_D:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
printf("(( cursor is disabled ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_H:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
printf("(( cursor is hidden ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_N:
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
printf("(( cursor is normal ))\n");
|
||||
break;
|
||||
|
||||
case GLFW_KEY_R:
|
||||
reopen = GL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
static GLFWwindow* open_window(void)
|
||||
{
|
||||
GLFWwindow* window = glfwCreateWindow(640, 480, "Peter Detector", NULL, NULL);
|
||||
if (!window)
|
||||
return NULL;
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
glfwGetCursorPos(window, &cursor_x, &cursor_y);
|
||||
printf("Cursor position: %f %f\n", cursor_x, cursor_y);
|
||||
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window;
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = open_window();
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwWaitEvents();
|
||||
|
||||
if (reopen)
|
||||
{
|
||||
glfwDestroyWindow(window);
|
||||
window = open_window();
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
reopen = GL_FALSE;
|
||||
}
|
||||
|
||||
// Workaround for an issue with msvcrt and mintty
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
+14
-1
@@ -122,6 +122,7 @@ int main(int argc, char** argv)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int width, height;
|
||||
GLFWmonitor* monitor = NULL;
|
||||
|
||||
if (count % 2 == 0)
|
||||
@@ -131,7 +132,19 @@ int main(int argc, char** argv)
|
||||
monitor = monitors[rand() % monitorCount];
|
||||
}
|
||||
|
||||
window = open_window(640, 480, monitor);
|
||||
if (monitor)
|
||||
{
|
||||
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 640;
|
||||
height = 480;
|
||||
}
|
||||
|
||||
window = open_window(width, height, monitor);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
|
||||
+88
-6
@@ -34,15 +34,28 @@
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
static GLboolean swap_tear;
|
||||
static int swap_interval;
|
||||
static double frame_rate;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: iconify [-h] [-f]\n");
|
||||
printf("Options:\n");
|
||||
printf(" -f create full screen window\n");
|
||||
printf(" -h show this help\n");
|
||||
}
|
||||
|
||||
static void update_window_title(GLFWwindow* window)
|
||||
{
|
||||
char title[256];
|
||||
|
||||
sprintf(title, "Tearing detector (interval %i, %0.1f Hz)",
|
||||
swap_interval, frame_rate);
|
||||
sprintf(title, "Tearing detector (interval %i%s, %0.1f Hz)",
|
||||
swap_interval,
|
||||
(swap_tear && swap_interval < 0) ? " (swap tear)" : "",
|
||||
frame_rate);
|
||||
|
||||
glfwSetWindowTitle(window, title);
|
||||
}
|
||||
@@ -66,23 +79,90 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
|
||||
set_swap_interval(window, 1 - swap_interval);
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_UP:
|
||||
{
|
||||
if (swap_interval + 1 > swap_interval)
|
||||
set_swap_interval(window, swap_interval + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_DOWN:
|
||||
{
|
||||
if (swap_tear)
|
||||
{
|
||||
if (swap_interval - 1 < swap_interval)
|
||||
set_swap_interval(window, swap_interval - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swap_interval - 1 >= 0)
|
||||
set_swap_interval(window, swap_interval - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int ch, width, height;
|
||||
float position;
|
||||
unsigned long frame_count = 0;
|
||||
double last_time, current_time;
|
||||
GLboolean fullscreen = GL_FALSE;
|
||||
GLFWmonitor* monitor = NULL;
|
||||
GLFWwindow* window;
|
||||
|
||||
while ((ch = getopt(argc, argv, "fh")) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'h':
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'f':
|
||||
fullscreen = GL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
window = glfwCreateWindow(640, 480, "", NULL, NULL);
|
||||
if (fullscreen)
|
||||
{
|
||||
const GLFWvidmode* mode;
|
||||
|
||||
monitor = glfwGetPrimaryMonitor();
|
||||
mode = glfwGetVideoMode(monitor);
|
||||
|
||||
glfwWindowHint(GLFW_RED_BITS, mode->redBits);
|
||||
glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
|
||||
glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
|
||||
glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
|
||||
|
||||
width = mode->width;
|
||||
height = mode->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 640;
|
||||
height = 480;
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(width, height, "", monitor, NULL);
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
@@ -94,6 +174,8 @@ int main(void)
|
||||
|
||||
last_time = glfwGetTime();
|
||||
frame_rate = 0.0;
|
||||
swap_tear = (glfwExtensionSupported("WGL_EXT_swap_control_tear") ||
|
||||
glfwExtensionSupported("GLX_EXT_swap_control_tear"));
|
||||
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
|
||||
+34
-14
@@ -32,12 +32,23 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char* titles[4] =
|
||||
static const char* titles[] =
|
||||
{
|
||||
"Foo",
|
||||
"Bar",
|
||||
"Baz",
|
||||
"Quux"
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue",
|
||||
"Yellow"
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
float r, g, b;
|
||||
} colors[] =
|
||||
{
|
||||
{ 0.95f, 0.32f, 0.11f },
|
||||
{ 0.50f, 0.80f, 0.16f },
|
||||
{ 0.f, 0.68f, 0.94f },
|
||||
{ 0.98f, 0.74f, 0.04f }
|
||||
};
|
||||
|
||||
static void error_callback(int error, const char* description)
|
||||
@@ -47,15 +58,26 @@ static void error_callback(int error, const char* description)
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
|
||||
if (action != GLFW_PRESS)
|
||||
return;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
int xpos, ypos;
|
||||
glfwGetWindowPos(window, &xpos, &ypos);
|
||||
glfwSetWindowPos(window, xpos, ypos);
|
||||
case GLFW_KEY_SPACE:
|
||||
{
|
||||
int xpos, ypos;
|
||||
glfwGetWindowPos(window, &xpos, &ypos);
|
||||
glfwSetWindowPos(window, xpos, ypos);
|
||||
break;
|
||||
}
|
||||
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i;
|
||||
GLboolean running = GL_TRUE;
|
||||
@@ -66,6 +88,7 @@ int main(void)
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
glfwWindowHint(GLFW_DECORATED, GL_FALSE);
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
@@ -82,10 +105,7 @@ int main(void)
|
||||
glfwSetKeyCallback(windows[i], key_callback);
|
||||
|
||||
glfwMakeContextCurrent(windows[i]);
|
||||
glClearColor((GLclampf) (i & 1),
|
||||
(GLclampf) (i >> 1),
|
||||
i ? 0.f : 1.f,
|
||||
0.f);
|
||||
glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f);
|
||||
|
||||
glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom);
|
||||
glfwSetWindowPos(windows[i],
|
||||
|
||||
Reference in New Issue
Block a user