daily update on 20231104 by nitload youmu
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glad/gl.h"
|
||||
#include "glad_gl.h"
|
||||
|
||||
#ifndef GLAD_IMPL_UTIL_C_
|
||||
#define GLAD_IMPL_UTIL_C_
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glad/glsc2.h"
|
||||
#include "glad_glsc2.h"
|
||||
|
||||
#ifndef GLAD_IMPL_UTIL_C_
|
||||
#define GLAD_IMPL_UTIL_C_
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "GLAD/wgl.h"
|
||||
#include "GLAD_wgl.h"
|
||||
|
||||
#ifndef GLAD_IMPL_UTIL_C_
|
||||
#define GLAD_IMPL_UTIL_C_
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// StgShqrpGraphic.cpp : 定义 DLL 的导出函数。
|
||||
//
|
||||
|
||||
#include "ssgc_framework.h"
|
||||
#include "glad_gl.h"
|
||||
#include <stdio.h>
|
||||
#include "StgSharpC.h"
|
||||
|
||||
extern char* infolog[512] = { 0 };
|
||||
GladGLContext* currentContext;
|
||||
glfwContext* glfw;
|
||||
|
||||
void printShaderCode(char* const* code)
|
||||
{
|
||||
printf(*code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
SSCAPI void _cdecl initGL(int majorVersion, int minorVersion)
|
||||
{
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, majorVersion);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minorVersion);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
SSCAPI unsigned int loadShaderCode(char* const shaderCode, GLint shadertype)
|
||||
{
|
||||
|
||||
unsigned int shader = currentContext->CreateShader(shadertype);
|
||||
currentContext->ShaderSource(shader, 1, &shaderCode, NULL);
|
||||
currentContext->CompileShader(shader);
|
||||
int success;
|
||||
currentContext->GetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
currentContext->GetShaderInfoLog(shader, 512, NULL, infolog);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
|
||||
SSCAPI unsigned int linkShaderProgram(GLuint shaderProgram)
|
||||
{
|
||||
currentContext->LinkProgram(shaderProgram);
|
||||
|
||||
int success;
|
||||
currentContext->GetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
currentContext->GetProgramInfoLog(shaderProgram, 512, NULL, infolog);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shaderProgram;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char* _cdecl readLog()
|
||||
{
|
||||
infolog[511] = '\0';
|
||||
return &infolog;
|
||||
}
|
||||
|
||||
void setCurrentGLContxt(GladGLContext* contextPtr)
|
||||
{
|
||||
currentContext = contextPtr;
|
||||
}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
// StgShqrpGraphic.cpp : 定义 DLL 的导出函数。
|
||||
//
|
||||
|
||||
#include "framework.h"
|
||||
#include "glad/gl.h"
|
||||
#include <stdio.h>
|
||||
#include "StgSharpGraphic.h"
|
||||
|
||||
extern char* infolog[512] = { 0 };
|
||||
GladGLContext* currentContext;
|
||||
glfwContext* glfw;
|
||||
|
||||
void printShaderCode(char* const* code)
|
||||
{
|
||||
printf(*code);
|
||||
}
|
||||
|
||||
|
||||
|
||||
SSGC_API glfwContext* _cdecl initGL(int majorVersion, int minorVersion, glfwContext* ptr)
|
||||
{
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, majorVersion);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minorVersion);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
#endif
|
||||
|
||||
glfw = ptr;
|
||||
|
||||
#pragma region loadapi
|
||||
|
||||
glfw->Init = glfwInit;
|
||||
glfw->Terminate = glfwTerminate;
|
||||
glfw->InitHint = glfwInitHint;
|
||||
glfw->GetVersion = glfwGetVersion;
|
||||
glfw->GetVersionString = glfwGetVersionString;
|
||||
glfw->GetError = glfwGetError;
|
||||
glfw->SetErrorCallback = glfwSetErrorCallback;
|
||||
glfw->GetMonitors = glfwGetMonitors;
|
||||
glfw->GetPrimaryMonitor = glfwGetPrimaryMonitor;
|
||||
glfw->GetMonitorPos = glfwGetMonitorPos;
|
||||
glfw->GetMonitorWorkarea = glfwGetMonitorWorkarea;
|
||||
glfw->GetMonitorPhysicalSize = glfwGetMonitorPhysicalSize;
|
||||
glfw->GetMonitorContentScale = glfwGetMonitorContentScale;
|
||||
glfw->GetMonitorName = glfwGetMonitorName;
|
||||
glfw->SetMonitorUserPointer = glfwSetMonitorUserPointer;
|
||||
glfw->GetMonitorUserPointer = glfwGetMonitorUserPointer;
|
||||
glfw->SetMonitorCallback = glfwSetMonitorCallback;
|
||||
glfw->GetVideoModes = glfwGetVideoModes;
|
||||
glfw->GetVideoMode = glfwGetVideoMode;
|
||||
glfw->SetGamma = glfwSetGamma;
|
||||
glfw->GetGammaRamp = glfwGetGammaRamp;
|
||||
glfw->SetGammaRamp = glfwSetGammaRamp;
|
||||
glfw->DefaultWindowHints = glfwDefaultWindowHints;
|
||||
glfw->WindowHint = glfwWindowHint;
|
||||
glfw->WindowHintString = glfwWindowHintString;
|
||||
glfw->CreateWindowProc = glfwCreateWindow;
|
||||
glfw->DestroyWindow = glfwDestroyWindow;
|
||||
glfw->WindowShouldClose = glfwWindowShouldClose;
|
||||
glfw->SetWindowShouldClose = glfwSetWindowShouldClose;
|
||||
glfw->SetWindowTitle = glfwSetWindowTitle;
|
||||
glfw->SetWindowIcon = glfwSetWindowIcon;
|
||||
glfw->GetWindowPos = glfwGetWindowPos;
|
||||
glfw->SetWindowPos = glfwSetWindowPos;
|
||||
glfw->GetWindowSize = glfwGetWindowSize;
|
||||
glfw->SetWindowSizeLimits = glfwSetWindowSizeLimits;
|
||||
glfw->SetWindowAspectRatio = glfwSetWindowAspectRatio;
|
||||
glfw->SetWindowSize = glfwSetWindowSize;
|
||||
glfw->GetFramebufferSize = glfwGetFramebufferSize;
|
||||
glfw->GetWindowFrameSize = glfwGetWindowFrameSize;
|
||||
glfw->GetWindowContentScale = glfwGetWindowContentScale;
|
||||
glfw->GetWindowOpacity = glfwGetWindowOpacity;
|
||||
glfw->SetWindowOpacity = glfwSetWindowOpacity;
|
||||
glfw->IconifyWindow = glfwIconifyWindow;
|
||||
glfw->RestoreWindow = glfwRestoreWindow;
|
||||
glfw->MaximizeWindow = glfwMaximizeWindow;
|
||||
glfw->ShowWindow = glfwShowWindow;
|
||||
glfw->HideWindow = glfwHideWindow;
|
||||
glfw->FocusWindow = glfwFocusWindow;
|
||||
glfw->RequestWindowAttention = glfwRequestWindowAttention;
|
||||
glfw->GetWindowMonitor = glfwGetWindowMonitor;
|
||||
glfw->SetWindowMonitor = glfwSetWindowMonitor;
|
||||
glfw->GetWindowAttrib = glfwGetWindowAttrib;
|
||||
glfw->SetWindowAttrib = glfwSetWindowAttrib;
|
||||
glfw->SetWindowUserPointer = glfwSetWindowUserPointer;
|
||||
glfw->GetWindowUserPointer = glfwGetWindowUserPointer;
|
||||
glfw->SetWindowPosCallback = glfwSetWindowPosCallback;
|
||||
glfw->SetWindowSizeCallback = glfwSetWindowSizeCallback;
|
||||
glfw->SetWindowCloseCallback = glfwSetWindowCloseCallback;
|
||||
glfw->SetWindowRefreshCallback = glfwSetWindowRefreshCallback;
|
||||
glfw->SetWindowFocusCallback = glfwSetWindowFocusCallback;
|
||||
glfw->SetWindowIconifyCallback = glfwSetWindowIconifyCallback;
|
||||
glfw->SetWindowMaximizeCallback = glfwSetWindowMaximizeCallback;
|
||||
glfw->SetFramebufferSizeCallback = glfwSetFramebufferSizeCallback;
|
||||
glfw->SetWindowContentScaleCallback = glfwSetWindowContentScaleCallback;
|
||||
glfw->PollEvents = glfwPollEvents;
|
||||
glfw->WaitEvents = glfwWaitEvents;
|
||||
glfw->WaitEventsTimeout = glfwWaitEventsTimeout;
|
||||
glfw->PostEmptyEvent = glfwPostEmptyEvent;
|
||||
glfw->GetInputMode = glfwGetInputMode;
|
||||
glfw->SetInputMode = glfwSetInputMode;
|
||||
glfw->RawMouseMotionSupported = glfwRawMouseMotionSupported;
|
||||
glfw->GetKeyName = glfwGetKeyName;
|
||||
glfw->GetKeyScancode = glfwGetKeyScancode;
|
||||
glfw->GetKey = glfwGetKey;
|
||||
glfw->GetMouseButton = glfwGetMouseButton;
|
||||
glfw->GetCursorPos = glfwGetCursorPos;
|
||||
glfw->SetCursorPos = glfwSetCursorPos;
|
||||
glfw->CreateCursor = glfwCreateCursor;
|
||||
glfw->CreateStandardCursor = glfwCreateStandardCursor;
|
||||
glfw->DestroyCursor = glfwDestroyCursor;
|
||||
glfw->SetCursor = glfwSetCursor;
|
||||
glfw->SetKeyCallback = glfwSetKeyCallback;
|
||||
glfw->SetCharCallback = glfwSetCharCallback;
|
||||
glfw->SetCharModsCallback = glfwSetCharModsCallback;
|
||||
glfw->SetMouseButtonCallback = glfwSetMouseButtonCallback;
|
||||
glfw->SetCursorPosCallback = glfwSetCursorPosCallback;
|
||||
glfw->SetCursorEnterCallback = glfwSetCursorEnterCallback;
|
||||
glfw->SetScrollCallback = glfwSetScrollCallback;
|
||||
glfw->SetDropCallback = glfwSetDropCallback;
|
||||
glfw->JoystickPresent = glfwJoystickPresent;
|
||||
glfw->GetJoystickAxes = glfwGetJoystickAxes;
|
||||
glfw->GetJoystickButtons = glfwGetJoystickButtons;
|
||||
glfw->GetJoystickHats = glfwGetJoystickHats;
|
||||
glfw->GetJoystickName = glfwGetJoystickName;
|
||||
glfw->GetJoystickGUID = glfwGetJoystickGUID;
|
||||
glfw->SetJoystickUserPointer = glfwSetJoystickUserPointer;
|
||||
glfw->GetJoystickUserPointer = glfwGetJoystickUserPointer;
|
||||
glfw->JoystickIsGamepad = glfwJoystickIsGamepad;
|
||||
glfw->SetJoystickCallback = glfwSetJoystickCallback;
|
||||
glfw->UpdateGamepadMappings = glfwUpdateGamepadMappings;
|
||||
glfw->GetGamepadName = glfwGetGamepadName;
|
||||
glfw->GetGamepadState = glfwGetGamepadState;
|
||||
glfw->SetClipboardString = glfwSetClipboardString;
|
||||
glfw->GetClipboardString = glfwGetClipboardString;
|
||||
glfw->GetTime = glfwGetTime;
|
||||
glfw->SetTime = glfwSetTime;
|
||||
glfw->GetTimerValue = glfwGetTimerValue;
|
||||
glfw->GetTimerFrequency = glfwGetTimerFrequency;
|
||||
glfw->MakeContextCurrent = glfwMakeContextCurrent;
|
||||
glfw->GetCurrentContext = glfwGetCurrentContext;
|
||||
glfw->SwapBuffers = glfwSwapBuffers;
|
||||
glfw->SwapInterval = glfwSwapInterval;
|
||||
glfw->ExtensionSupported = glfwExtensionSupported;
|
||||
glfw->GetProcAddress = glfwGetProcAddress;
|
||||
glfw->VulkanSupported = glfwVulkanSupported;
|
||||
glfw->GetRequiredInstanceExtensions = glfwGetRequiredInstanceExtensions;
|
||||
#if defined(VK_VERSION_1_0)
|
||||
glfw->GetInstanceProcAddress = glfwGetInstanceProcAddress;
|
||||
glfw->GetPhysicalDevicePresentationSupport = glfwGetPhysicalDevicePresentationSupport;
|
||||
glfw->CreateWindowSurface = glfwCreateWindowSurface;
|
||||
#endif
|
||||
#pragma endregion
|
||||
|
||||
return glfw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SSGC_API unsigned int loadShaderCode(char* const shaderCode, GLint shadertype)
|
||||
{
|
||||
|
||||
unsigned int shader = currentContext->CreateShader(shadertype);
|
||||
currentContext->ShaderSource(shader, 1, &shaderCode, NULL);
|
||||
currentContext->CompileShader(shader);
|
||||
int success;
|
||||
currentContext->GetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
currentContext->GetShaderInfoLog(shader, 512, NULL, infolog);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
|
||||
SSGC_API unsigned int linkShaderProgram(GLuint shaderProgram)
|
||||
{
|
||||
currentContext->LinkProgram(shaderProgram);
|
||||
|
||||
int success;
|
||||
currentContext->GetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
currentContext->GetProgramInfoLog(shaderProgram, 512, NULL, infolog);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shaderProgram;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char* _cdecl readLog()
|
||||
{
|
||||
infolog[511] = '\0';
|
||||
return &infolog;
|
||||
}
|
||||
|
||||
void setCurrentGLContxt(GladGLContext* contextPtr)
|
||||
{
|
||||
currentContext = contextPtr;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "framework.h"
|
||||
#include "ssgc_framework.h"
|
||||
#endif // __
|
||||
|
||||
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -20,18 +20,18 @@ BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
case DLL_PROCESS_ATTACH:
|
||||
do
|
||||
{
|
||||
defaultVecPtr = _aligned_malloc(sizeof(__m128),16);
|
||||
defaultVecPtr = _aligned_malloc(sizeof(__m128), 16);
|
||||
} while (defaultVecPtr == NULL);
|
||||
|
||||
return 1;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
|
||||
return 1;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
|
||||
return 1;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
break;
|
||||
@@ -41,7 +41,7 @@ BOOL APIENTRY DllMain(HMODULE hModule,
|
||||
#else
|
||||
attribute((constructor)) void DllMain()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -0,0 +1,765 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Checks whether the desired context attributes are valid
|
||||
//
|
||||
// This function checks things like whether the specified client API version
|
||||
// exists and whether all relevant options have supported and non-conflicting
|
||||
// values
|
||||
//
|
||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
|
||||
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
|
||||
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context creation API 0x%08X",
|
||||
ctxconfig->source);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API &&
|
||||
ctxconfig->client != GLFW_OPENGL_API &&
|
||||
ctxconfig->client != GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid client API 0x%08X",
|
||||
ctxconfig->client);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_NO_API ||
|
||||
ctxconfig->share->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->source != ctxconfig->share->context.source)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Context creation APIs do not match between contexts");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
|
||||
(ctxconfig->major == 1 && ctxconfig->minor > 5) ||
|
||||
(ctxconfig->major == 2 && ctxconfig->minor > 1) ||
|
||||
(ctxconfig->major == 3 && ctxconfig->minor > 3))
|
||||
{
|
||||
// OpenGL 1.0 is the smallest valid version
|
||||
// OpenGL 1.x series ended with version 1.5
|
||||
// OpenGL 2.x series ended with version 2.1
|
||||
// OpenGL 3.x series ended with version 3.3
|
||||
// For now, let everything else through
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE &&
|
||||
ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid OpenGL profile 0x%08X",
|
||||
ctxconfig->profile);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->major <= 2 ||
|
||||
(ctxconfig->major == 3 && ctxconfig->minor < 2))
|
||||
{
|
||||
// Desktop OpenGL context profiles are only defined for version 3.2
|
||||
// and above
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Context profiles are only defined for OpenGL version 3.2 and above");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->forward && ctxconfig->major <= 2)
|
||||
{
|
||||
// Forward-compatible contexts are only defined for OpenGL version 3.0 and above
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Forward-compatibility is only defined for OpenGL version 3.0 and above");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
else if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major < 1 || ctxconfig->minor < 0 ||
|
||||
(ctxconfig->major == 1 && ctxconfig->minor > 1) ||
|
||||
(ctxconfig->major == 2 && ctxconfig->minor > 0))
|
||||
{
|
||||
// OpenGL ES 1.0 is the smallest valid version
|
||||
// OpenGL ES 1.x series ended with version 1.1
|
||||
// OpenGL ES 2.x series ended with version 2.0
|
||||
// For now, let everything else through
|
||||
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid OpenGL ES version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION &&
|
||||
ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context robustness mode 0x%08X",
|
||||
ctxconfig->robustness);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->release)
|
||||
{
|
||||
if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE &&
|
||||
ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid context release behavior 0x%08X",
|
||||
ctxconfig->release);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Chooses the framebuffer config that best matches the desired one
|
||||
//
|
||||
const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
|
||||
const _GLFWfbconfig* alternatives,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int missing, leastMissing = UINT_MAX;
|
||||
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
||||
unsigned int extraDiff, leastExtraDiff = UINT_MAX;
|
||||
const _GLFWfbconfig* current;
|
||||
const _GLFWfbconfig* closest = NULL;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
current = alternatives + i;
|
||||
|
||||
if (desired->stereo > 0 && current->stereo == 0)
|
||||
{
|
||||
// Stereo is a hard constraint
|
||||
continue;
|
||||
}
|
||||
|
||||
// Count number of missing buffers
|
||||
{
|
||||
missing = 0;
|
||||
|
||||
if (desired->alphaBits > 0 && current->alphaBits == 0)
|
||||
missing++;
|
||||
|
||||
if (desired->depthBits > 0 && current->depthBits == 0)
|
||||
missing++;
|
||||
|
||||
if (desired->stencilBits > 0 && current->stencilBits == 0)
|
||||
missing++;
|
||||
|
||||
if (desired->auxBuffers > 0 &&
|
||||
current->auxBuffers < desired->auxBuffers)
|
||||
{
|
||||
missing += desired->auxBuffers - current->auxBuffers;
|
||||
}
|
||||
|
||||
if (desired->samples > 0 && current->samples == 0)
|
||||
{
|
||||
// Technically, several multisampling buffers could be
|
||||
// involved, but that's a lower level implementation detail and
|
||||
// not important to us here, so we count them as one
|
||||
missing++;
|
||||
}
|
||||
|
||||
if (desired->transparent != current->transparent)
|
||||
missing++;
|
||||
}
|
||||
|
||||
// These polynomials make many small channel size differences matter
|
||||
// less than one large channel size difference
|
||||
|
||||
// Calculate color channel size difference value
|
||||
{
|
||||
colorDiff = 0;
|
||||
|
||||
if (desired->redBits != GLFW_DONT_CARE)
|
||||
{
|
||||
colorDiff += (desired->redBits - current->redBits) *
|
||||
(desired->redBits - current->redBits);
|
||||
}
|
||||
|
||||
if (desired->greenBits != GLFW_DONT_CARE)
|
||||
{
|
||||
colorDiff += (desired->greenBits - current->greenBits) *
|
||||
(desired->greenBits - current->greenBits);
|
||||
}
|
||||
|
||||
if (desired->blueBits != GLFW_DONT_CARE)
|
||||
{
|
||||
colorDiff += (desired->blueBits - current->blueBits) *
|
||||
(desired->blueBits - current->blueBits);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate non-color channel size difference value
|
||||
{
|
||||
extraDiff = 0;
|
||||
|
||||
if (desired->alphaBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->alphaBits - current->alphaBits) *
|
||||
(desired->alphaBits - current->alphaBits);
|
||||
}
|
||||
|
||||
if (desired->depthBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->depthBits - current->depthBits) *
|
||||
(desired->depthBits - current->depthBits);
|
||||
}
|
||||
|
||||
if (desired->stencilBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->stencilBits - current->stencilBits) *
|
||||
(desired->stencilBits - current->stencilBits);
|
||||
}
|
||||
|
||||
if (desired->accumRedBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->accumRedBits - current->accumRedBits) *
|
||||
(desired->accumRedBits - current->accumRedBits);
|
||||
}
|
||||
|
||||
if (desired->accumGreenBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->accumGreenBits - current->accumGreenBits) *
|
||||
(desired->accumGreenBits - current->accumGreenBits);
|
||||
}
|
||||
|
||||
if (desired->accumBlueBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->accumBlueBits - current->accumBlueBits) *
|
||||
(desired->accumBlueBits - current->accumBlueBits);
|
||||
}
|
||||
|
||||
if (desired->accumAlphaBits != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) *
|
||||
(desired->accumAlphaBits - current->accumAlphaBits);
|
||||
}
|
||||
|
||||
if (desired->samples != GLFW_DONT_CARE)
|
||||
{
|
||||
extraDiff += (desired->samples - current->samples) *
|
||||
(desired->samples - current->samples);
|
||||
}
|
||||
|
||||
if (desired->sRGB && !current->sRGB)
|
||||
extraDiff++;
|
||||
}
|
||||
|
||||
// Figure out if the current one is better than the best one found so far
|
||||
// Least number of missing buffers is the most important heuristic,
|
||||
// then color buffer size match and lastly size match for other buffers
|
||||
|
||||
if (missing < leastMissing)
|
||||
closest = current;
|
||||
else if (missing == leastMissing)
|
||||
{
|
||||
if ((colorDiff < leastColorDiff) ||
|
||||
(colorDiff == leastColorDiff && extraDiff < leastExtraDiff))
|
||||
{
|
||||
closest = current;
|
||||
}
|
||||
}
|
||||
|
||||
if (current == closest)
|
||||
{
|
||||
leastMissing = missing;
|
||||
leastColorDiff = colorDiff;
|
||||
leastExtraDiff = extraDiff;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// Retrieves the attributes of the current context
|
||||
//
|
||||
GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* previous;
|
||||
const char* version;
|
||||
const char* prefixes[] =
|
||||
{
|
||||
"OpenGL ES-CM ",
|
||||
"OpenGL ES-CL ",
|
||||
"OpenGL ES ",
|
||||
NULL
|
||||
};
|
||||
|
||||
window->context.source = ctxconfig->source;
|
||||
window->context.client = GLFW_OPENGL_API;
|
||||
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
glfwMakeContextCurrent((GLFWwindow*)window);
|
||||
|
||||
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
||||
window->context.getProcAddress("glGetIntegerv");
|
||||
window->context.GetString = (PFNGLGETSTRINGPROC)
|
||||
window->context.getProcAddress("glGetString");
|
||||
if (!window->context.GetIntegerv || !window->context.GetString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
version = (const char*)window->context.GetString(GL_VERSION);
|
||||
if (!version)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OpenGL version string retrieval is broken");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OpenGL ES version string retrieval is broken");
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; prefixes[i]; i++)
|
||||
{
|
||||
const size_t length = strlen(prefixes[i]);
|
||||
|
||||
if (strncmp(version, prefixes[i], length) == 0)
|
||||
{
|
||||
version += length;
|
||||
window->context.client = GLFW_OPENGL_ES_API;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sscanf(version, "%d.%d.%d",
|
||||
&window->context.major,
|
||||
&window->context.minor,
|
||||
&window->context.revision))
|
||||
{
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"No version found in OpenGL version string");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"No version found in OpenGL ES version string");
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major < ctxconfig->major ||
|
||||
(window->context.major == ctxconfig->major &&
|
||||
window->context.minor < ctxconfig->minor))
|
||||
{
|
||||
// The desired OpenGL version is greater than the actual version
|
||||
// This only happens if the machine lacks {GLX|WGL}_ARB_create_context
|
||||
// /and/ the user has requested an OpenGL version greater than 1.0
|
||||
|
||||
// For API consistency, we emulate the behavior of the
|
||||
// {GLX|WGL}_ARB_create_context extension and fail here
|
||||
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"Requested OpenGL version %i.%i, got version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor,
|
||||
window->context.major, window->context.minor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"Requested OpenGL ES version %i.%i, got version %i.%i",
|
||||
ctxconfig->major, ctxconfig->minor,
|
||||
window->context.major, window->context.minor);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
// OpenGL 3.0+ uses a different function for extension string retrieval
|
||||
// We cache it here instead of in glfwExtensionSupported mostly to alert
|
||||
// users as early as possible that their build may be broken
|
||||
|
||||
window->context.GetStringi = (PFNGLGETSTRINGIPROC)
|
||||
window->context.getProcAddress("glGetStringi");
|
||||
if (!window->context.GetStringi)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Entry point retrieval is broken");
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->context.client == GLFW_OPENGL_API)
|
||||
{
|
||||
// Read back context flags (OpenGL 3.0 and above)
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
GLint flags;
|
||||
window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags);
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
|
||||
window->context.forward = GLFW_TRUE;
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
|
||||
window->context.debug = GLFW_TRUE;
|
||||
else if (glfwExtensionSupported("GL_ARB_debug_output") &&
|
||||
ctxconfig->debug)
|
||||
{
|
||||
// HACK: This is a workaround for older drivers (pre KHR_debug)
|
||||
// not setting the debug bit in the context flags for
|
||||
// debug contexts
|
||||
window->context.debug = GLFW_TRUE;
|
||||
}
|
||||
|
||||
if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR)
|
||||
window->context.noerror = GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Read back OpenGL context profile (OpenGL 3.2 and above)
|
||||
if (window->context.major >= 4 ||
|
||||
(window->context.major == 3 && window->context.minor >= 2))
|
||||
{
|
||||
GLint mask;
|
||||
window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||
|
||||
if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
|
||||
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
else if (mask & GL_CONTEXT_CORE_PROFILE_BIT)
|
||||
window->context.profile = GLFW_OPENGL_CORE_PROFILE;
|
||||
else if (glfwExtensionSupported("GL_ARB_compatibility"))
|
||||
{
|
||||
// HACK: This is a workaround for the compatibility profile bit
|
||||
// not being set in the context flags if an OpenGL 3.2+
|
||||
// context was created without having requested a specific
|
||||
// version
|
||||
window->context.profile = GLFW_OPENGL_COMPAT_PROFILE;
|
||||
}
|
||||
}
|
||||
|
||||
// Read back robustness strategy
|
||||
if (glfwExtensionSupported("GL_ARB_robustness"))
|
||||
{
|
||||
// NOTE: We avoid using the context flags for detection, as they are
|
||||
// only present from 3.0 while the extension applies from 1.1
|
||||
|
||||
GLint strategy;
|
||||
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
&strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read back robustness strategy
|
||||
if (glfwExtensionSupported("GL_EXT_robustness"))
|
||||
{
|
||||
// NOTE: The values of these constants match those of the OpenGL ARB
|
||||
// one, so we can reuse them here
|
||||
|
||||
GLint strategy;
|
||||
window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
&strategy);
|
||||
|
||||
if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB)
|
||||
window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET;
|
||||
else if (strategy == GL_NO_RESET_NOTIFICATION_ARB)
|
||||
window->context.robustness = GLFW_NO_RESET_NOTIFICATION;
|
||||
}
|
||||
}
|
||||
|
||||
if (glfwExtensionSupported("GL_KHR_context_flush_control"))
|
||||
{
|
||||
GLint behavior;
|
||||
window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior);
|
||||
|
||||
if (behavior == GL_NONE)
|
||||
window->context.release = GLFW_RELEASE_BEHAVIOR_NONE;
|
||||
else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH)
|
||||
window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH;
|
||||
}
|
||||
|
||||
// Clearing the front buffer to black to avoid garbage pixels left over from
|
||||
// previous uses of our bit of VRAM
|
||||
{
|
||||
PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
|
||||
window->context.getProcAddress("glClear");
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (window->doublebuffer)
|
||||
window->context.swapBuffers(window);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent((GLFWwindow*)previous);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Searches an extension string for the specified extension
|
||||
//
|
||||
GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions)
|
||||
{
|
||||
const char* start = extensions;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const char* where;
|
||||
const char* terminator;
|
||||
|
||||
where = strstr(start, string);
|
||||
if (!where)
|
||||
return GLFW_FALSE;
|
||||
|
||||
terminator = where + strlen(string);
|
||||
if (where == start || *(where - 1) == ' ')
|
||||
{
|
||||
if (*terminator == ' ' || *terminator == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
start = terminator;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI void glfwMakeContextCurrent(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*)handle;
|
||||
_GLFWwindow* previous;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
if (window && window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
|
||||
"Cannot make current with a window that has no OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous)
|
||||
{
|
||||
if (!window || window->context.source != previous->context.source)
|
||||
previous->context.makeCurrent(NULL);
|
||||
}
|
||||
|
||||
if (window)
|
||||
window->context.makeCurrent(window);
|
||||
}
|
||||
|
||||
SSCAPI GLFWwindow* glfwGetCurrentContext(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
}
|
||||
|
||||
SSCAPI void glfwSwapBuffers(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*)handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,
|
||||
"Cannot swap buffers of a window that has no OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
window->context.swapBuffers(window);
|
||||
}
|
||||
|
||||
SSCAPI void glfwSwapInterval(int interval)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot set swap interval without a current OpenGL or OpenGL ES context");
|
||||
return;
|
||||
}
|
||||
|
||||
window->context.swapInterval(interval);
|
||||
}
|
||||
|
||||
SSCAPI int glfwExtensionSupported(const char* extension)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
assert(extension != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot query extension without a current OpenGL or OpenGL ES context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (*extension == '\0')
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (window->context.major >= 3)
|
||||
{
|
||||
int i;
|
||||
GLint count;
|
||||
|
||||
// Check if extension is in the modern OpenGL extensions string list
|
||||
|
||||
window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
const char* en = (const char*)
|
||||
window->context.GetStringi(GL_EXTENSIONS, i);
|
||||
if (!en)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (strcmp(en, extension) == 0)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if extension is in the old style OpenGL extensions string
|
||||
|
||||
const char* extensions = (const char*)
|
||||
window->context.GetString(GL_EXTENSIONS);
|
||||
if (!extensions)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Extension string retrieval is broken");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Check if extension is in the platform-specific string
|
||||
return window->context.extensionSupported(extension);
|
||||
}
|
||||
|
||||
SSCAPI GLFWglproc glfwGetProcAddress(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
assert(procname != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
if (!window)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_CURRENT_CONTEXT,
|
||||
"Cannot query entry point without a current OpenGL or OpenGL ES context");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.getProcAddress(procname);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,909 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 EGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
// Return a description of the specified EGL error
|
||||
//
|
||||
static const char* getEGLErrorString(EGLint error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EGL_SUCCESS:
|
||||
return "Success";
|
||||
case EGL_NOT_INITIALIZED:
|
||||
return "EGL is not or could not be initialized";
|
||||
case EGL_BAD_ACCESS:
|
||||
return "EGL cannot access a requested resource";
|
||||
case EGL_BAD_ALLOC:
|
||||
return "EGL failed to allocate resources for the requested operation";
|
||||
case EGL_BAD_ATTRIBUTE:
|
||||
return "An unrecognized attribute or attribute value was passed in the attribute list";
|
||||
case EGL_BAD_CONTEXT:
|
||||
return "An EGLContext argument does not name a valid EGL rendering context";
|
||||
case EGL_BAD_CONFIG:
|
||||
return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
|
||||
case EGL_BAD_CURRENT_SURFACE:
|
||||
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
|
||||
case EGL_BAD_DISPLAY:
|
||||
return "An EGLDisplay argument does not name a valid EGL display connection";
|
||||
case EGL_BAD_SURFACE:
|
||||
return "An EGLSurface argument does not name a valid surface configured for GL rendering";
|
||||
case EGL_BAD_MATCH:
|
||||
return "Arguments are inconsistent";
|
||||
case EGL_BAD_PARAMETER:
|
||||
return "One or more argument values are invalid";
|
||||
case EGL_BAD_NATIVE_PIXMAP:
|
||||
return "A NativePixmapType argument does not refer to a valid native pixmap";
|
||||
case EGL_BAD_NATIVE_WINDOW:
|
||||
return "A NativeWindowType argument does not refer to a valid native window";
|
||||
case EGL_CONTEXT_LOST:
|
||||
return "The application must destroy all contexts and reinitialise";
|
||||
default:
|
||||
return "ERROR: UNKNOWN EGL ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the specified attribute of the specified EGLConfig
|
||||
//
|
||||
static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
||||
{
|
||||
int value;
|
||||
eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Return the EGLConfig most closely matching the specified hints
|
||||
//
|
||||
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
EGLConfig* result)
|
||||
{
|
||||
EGLConfig* nativeConfigs;
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, nativeCount, usableCount, apiBit;
|
||||
GLFWbool wrongApiAvailable = GLFW_FALSE;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
apiBit = EGL_OPENGL_ES_BIT;
|
||||
else
|
||||
apiBit = EGL_OPENGL_ES2_BIT;
|
||||
}
|
||||
else
|
||||
apiBit = EGL_OPENGL_BIT;
|
||||
|
||||
if (fbconfig->stereo)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||
if (!nativeCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
nativeConfigs = _glfw_calloc(nativeCount, sizeof(EGLConfig));
|
||||
eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount);
|
||||
|
||||
usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||
usableCount = 0;
|
||||
|
||||
for (i = 0; i < nativeCount; i++)
|
||||
{
|
||||
const EGLConfig n = nativeConfigs[i];
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
|
||||
// Only consider RGB(A) EGLConfigs
|
||||
if (getEGLConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) != EGL_RGB_BUFFER)
|
||||
continue;
|
||||
|
||||
// Only consider window EGLConfigs
|
||||
if (!(getEGLConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT))
|
||||
continue;
|
||||
|
||||
#if defined(_GLFW_X11)
|
||||
if (_glfw.platform.platformID == GLFW_PLATFORM_X11)
|
||||
{
|
||||
XVisualInfo vi = { 0 };
|
||||
|
||||
// Only consider EGLConfigs with associated Visuals
|
||||
vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
|
||||
if (!vi.visualid)
|
||||
continue;
|
||||
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
int count;
|
||||
XVisualInfo* vis =
|
||||
XGetVisualInfo(_glfw.x11.display, VisualIDMask, &vi, &count);
|
||||
if (vis)
|
||||
{
|
||||
u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
|
||||
XFree(vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit))
|
||||
{
|
||||
wrongApiAvailable = GLFW_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
|
||||
u->greenBits = getEGLConfigAttrib(n, EGL_GREEN_SIZE);
|
||||
u->blueBits = getEGLConfigAttrib(n, EGL_BLUE_SIZE);
|
||||
|
||||
u->alphaBits = getEGLConfigAttrib(n, EGL_ALPHA_SIZE);
|
||||
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
|
||||
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
||||
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
|
||||
{
|
||||
// NOTE: The wl_surface opaque region is no guarantee that its buffer
|
||||
// is presented as opaque, if it also has an alpha channel
|
||||
// HACK: If EGL_EXT_present_opaque is unavailable, ignore any config
|
||||
// with an alpha channel to ensure the buffer is opaque
|
||||
if (!_glfw.egl.EXT_present_opaque)
|
||||
{
|
||||
if (!fbconfig->transparent && u->alphaBits > 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif // _GLFW_WAYLAND
|
||||
|
||||
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
||||
u->doublebuffer = fbconfig->doublebuffer;
|
||||
|
||||
u->handle = (uintptr_t)n;
|
||||
usableCount++;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
|
||||
if (closest)
|
||||
*result = (EGLConfig)closest->handle;
|
||||
else
|
||||
{
|
||||
if (wrongApiAvailable)
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to find support for OpenGL ES 1.x");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to find support for OpenGL ES 2 or later");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to find support for OpenGL");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"EGL: Failed to find a suitable EGLConfig");
|
||||
}
|
||||
}
|
||||
|
||||
_glfw_free(nativeConfigs);
|
||||
_glfw_free(usableConfigs);
|
||||
|
||||
return closest != NULL;
|
||||
}
|
||||
|
||||
static void makeContextCurrentEGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if (!eglMakeCurrent(_glfw.egl.display,
|
||||
window->context.egl.surface,
|
||||
window->context.egl.surface,
|
||||
window->context.egl.handle))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to make context current: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eglMakeCurrent(_glfw.egl.display,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to clear current context: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static void swapBuffersEGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window != _glfwPlatformGetTls(&_glfw.contextSlot))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: The context must be current on the calling thread when swapping buffers");
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
|
||||
{
|
||||
// NOTE: Swapping buffers on a hidden window on Wayland makes it visible
|
||||
if (!window->wl.visible)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
eglSwapBuffers(_glfw.egl.display, window->context.egl.surface);
|
||||
}
|
||||
|
||||
static void swapIntervalEGL(int interval)
|
||||
{
|
||||
eglSwapInterval(_glfw.egl.display, interval);
|
||||
}
|
||||
|
||||
static int extensionSupportedEGL(const char* extension)
|
||||
{
|
||||
const char* extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS);
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
GLFWglproc proc = (GLFWglproc)
|
||||
_glfwPlatformGetModuleSymbol(window->context.egl.client, procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
}
|
||||
|
||||
return eglGetProcAddress(procname);
|
||||
}
|
||||
|
||||
static void destroyContextEGL(_GLFWwindow* window)
|
||||
{
|
||||
// NOTE: Do not unload libGL.so.1 while the X11 display is still open,
|
||||
// as it will make XCloseDisplay segfault
|
||||
if (_glfw.platform.platformID != GLFW_PLATFORM_X11 ||
|
||||
window->context.client != GLFW_OPENGL_API)
|
||||
{
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
_glfwPlatformFreeModule(window->context.egl.client);
|
||||
window->context.egl.client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (window->context.egl.surface)
|
||||
{
|
||||
eglDestroySurface(_glfw.egl.display, window->context.egl.surface);
|
||||
window->context.egl.surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (window->context.egl.handle)
|
||||
{
|
||||
eglDestroyContext(_glfw.egl.display, window->context.egl.handle);
|
||||
window->context.egl.handle = EGL_NO_CONTEXT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize EGL
|
||||
//
|
||||
GLFWbool _glfwInitEGL(void)
|
||||
{
|
||||
int i;
|
||||
EGLint* attribs = NULL;
|
||||
const char* extensions;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_EGL_LIBRARY)
|
||||
_GLFW_EGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"libEGL.dll",
|
||||
"EGL.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libEGL.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libEGL-1.so",
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libEGL.so",
|
||||
#else
|
||||
"libEGL.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
_glfw.egl.handle = _glfwPlatformLoadModule(sonames[i]);
|
||||
if (_glfw.egl.handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_glfw.egl.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
|
||||
|
||||
_glfw.egl.GetConfigAttrib = (PFN_eglGetConfigAttrib)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigAttrib");
|
||||
_glfw.egl.GetConfigs = (PFN_eglGetConfigs)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetConfigs");
|
||||
_glfw.egl.GetDisplay = (PFN_eglGetDisplay)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetDisplay");
|
||||
_glfw.egl.GetError = (PFN_eglGetError)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetError");
|
||||
_glfw.egl.Initialize = (PFN_eglInitialize)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglInitialize");
|
||||
_glfw.egl.Terminate = (PFN_eglTerminate)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglTerminate");
|
||||
_glfw.egl.BindAPI = (PFN_eglBindAPI)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglBindAPI");
|
||||
_glfw.egl.CreateContext = (PFN_eglCreateContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateContext");
|
||||
_glfw.egl.DestroySurface = (PFN_eglDestroySurface)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroySurface");
|
||||
_glfw.egl.DestroyContext = (PFN_eglDestroyContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglDestroyContext");
|
||||
_glfw.egl.CreateWindowSurface = (PFN_eglCreateWindowSurface)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglCreateWindowSurface");
|
||||
_glfw.egl.MakeCurrent = (PFN_eglMakeCurrent)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglMakeCurrent");
|
||||
_glfw.egl.SwapBuffers = (PFN_eglSwapBuffers)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapBuffers");
|
||||
_glfw.egl.SwapInterval = (PFN_eglSwapInterval)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglSwapInterval");
|
||||
_glfw.egl.QueryString = (PFN_eglQueryString)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglQueryString");
|
||||
_glfw.egl.GetProcAddress = (PFN_eglGetProcAddress)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.egl.handle, "eglGetProcAddress");
|
||||
|
||||
if (!_glfw.egl.GetConfigAttrib ||
|
||||
!_glfw.egl.GetConfigs ||
|
||||
!_glfw.egl.GetDisplay ||
|
||||
!_glfw.egl.GetError ||
|
||||
!_glfw.egl.Initialize ||
|
||||
!_glfw.egl.Terminate ||
|
||||
!_glfw.egl.BindAPI ||
|
||||
!_glfw.egl.CreateContext ||
|
||||
!_glfw.egl.DestroySurface ||
|
||||
!_glfw.egl.DestroyContext ||
|
||||
!_glfw.egl.CreateWindowSurface ||
|
||||
!_glfw.egl.MakeCurrent ||
|
||||
!_glfw.egl.SwapBuffers ||
|
||||
!_glfw.egl.SwapInterval ||
|
||||
!_glfw.egl.QueryString ||
|
||||
!_glfw.egl.GetProcAddress)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to load required entry points");
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
if (extensions && eglGetError() == EGL_SUCCESS)
|
||||
_glfw.egl.EXT_client_extensions = GLFW_TRUE;
|
||||
|
||||
if (_glfw.egl.EXT_client_extensions)
|
||||
{
|
||||
_glfw.egl.EXT_platform_base =
|
||||
_glfwStringInExtensionString("EGL_EXT_platform_base", extensions);
|
||||
_glfw.egl.EXT_platform_x11 =
|
||||
_glfwStringInExtensionString("EGL_EXT_platform_x11", extensions);
|
||||
_glfw.egl.EXT_platform_wayland =
|
||||
_glfwStringInExtensionString("EGL_EXT_platform_wayland", extensions);
|
||||
_glfw.egl.ANGLE_platform_angle =
|
||||
_glfwStringInExtensionString("EGL_ANGLE_platform_angle", extensions);
|
||||
_glfw.egl.ANGLE_platform_angle_opengl =
|
||||
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_opengl", extensions);
|
||||
_glfw.egl.ANGLE_platform_angle_d3d =
|
||||
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_d3d", extensions);
|
||||
_glfw.egl.ANGLE_platform_angle_vulkan =
|
||||
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_vulkan", extensions);
|
||||
_glfw.egl.ANGLE_platform_angle_metal =
|
||||
_glfwStringInExtensionString("EGL_ANGLE_platform_angle_metal", extensions);
|
||||
}
|
||||
|
||||
if (_glfw.egl.EXT_platform_base)
|
||||
{
|
||||
_glfw.egl.GetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
|
||||
eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||
_glfw.egl.CreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
|
||||
eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
|
||||
}
|
||||
|
||||
_glfw.egl.platform = _glfw.platform.getEGLPlatform(&attribs);
|
||||
if (_glfw.egl.platform)
|
||||
{
|
||||
_glfw.egl.display =
|
||||
eglGetPlatformDisplayEXT(_glfw.egl.platform,
|
||||
_glfw.platform.getEGLNativeDisplay(),
|
||||
attribs);
|
||||
}
|
||||
else
|
||||
_glfw.egl.display = eglGetDisplay(_glfw.platform.getEGLNativeDisplay());
|
||||
|
||||
_glfw_free(attribs);
|
||||
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to get EGL display: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to initialize EGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.egl.KHR_create_context =
|
||||
extensionSupportedEGL("EGL_KHR_create_context");
|
||||
_glfw.egl.KHR_create_context_no_error =
|
||||
extensionSupportedEGL("EGL_KHR_create_context_no_error");
|
||||
_glfw.egl.KHR_gl_colorspace =
|
||||
extensionSupportedEGL("EGL_KHR_gl_colorspace");
|
||||
_glfw.egl.KHR_get_all_proc_addresses =
|
||||
extensionSupportedEGL("EGL_KHR_get_all_proc_addresses");
|
||||
_glfw.egl.KHR_context_flush_control =
|
||||
extensionSupportedEGL("EGL_KHR_context_flush_control");
|
||||
_glfw.egl.EXT_present_opaque =
|
||||
extensionSupportedEGL("EGL_EXT_present_opaque");
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate EGL
|
||||
//
|
||||
void _glfwTerminateEGL(void)
|
||||
{
|
||||
if (_glfw.egl.display)
|
||||
{
|
||||
eglTerminate(_glfw.egl.display);
|
||||
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
||||
if (_glfw.egl.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.egl.handle);
|
||||
_glfw.egl.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
EGLint attribs[40];
|
||||
EGLConfig config;
|
||||
EGLContext share = NULL;
|
||||
EGLNativeWindowType native;
|
||||
int index = 0;
|
||||
|
||||
if (!_glfw.egl.display)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: API not available");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.egl.handle;
|
||||
|
||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_ES_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL ES: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eglBindAPI(EGL_OPENGL_API))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to bind OpenGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.egl.KHR_create_context)
|
||||
{
|
||||
int mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->debug)
|
||||
flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
{
|
||||
SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_NO_RESET_NOTIFICATION_KHR);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
|
||||
EGL_LOSE_CONTEXT_ON_RESET_KHR);
|
||||
}
|
||||
|
||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.egl.KHR_create_context_no_error)
|
||||
SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
|
||||
if (flags)
|
||||
SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
|
||||
}
|
||||
|
||||
if (_glfw.egl.KHR_context_flush_control)
|
||||
{
|
||||
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||
{
|
||||
SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
|
||||
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
|
||||
}
|
||||
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
|
||||
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
|
||||
}
|
||||
}
|
||||
|
||||
SET_ATTRIB(EGL_NONE, EGL_NONE);
|
||||
|
||||
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
|
||||
config, share, attribs);
|
||||
|
||||
if (window->context.egl.handle == EGL_NO_CONTEXT)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"EGL: Failed to create context: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// Set up attributes for surface creation
|
||||
index = 0;
|
||||
|
||||
if (fbconfig->sRGB)
|
||||
{
|
||||
if (_glfw.egl.KHR_gl_colorspace)
|
||||
SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
|
||||
}
|
||||
|
||||
if (!fbconfig->doublebuffer)
|
||||
SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
|
||||
|
||||
if (_glfw.egl.EXT_present_opaque)
|
||||
SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
|
||||
|
||||
SET_ATTRIB(EGL_NONE, EGL_NONE);
|
||||
|
||||
native = _glfw.platform.getEGLNativeWindow(window);
|
||||
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
|
||||
// despite reporting EGL_EXT_platform_base
|
||||
if (_glfw.egl.platform && _glfw.egl.platform != EGL_PLATFORM_ANGLE_ANGLE)
|
||||
{
|
||||
window->context.egl.surface =
|
||||
eglCreatePlatformWindowSurfaceEXT(_glfw.egl.display, config, native, attribs);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->context.egl.surface =
|
||||
eglCreateWindowSurface(_glfw.egl.display, config, native, attribs);
|
||||
}
|
||||
|
||||
if (window->context.egl.surface == EGL_NO_SURFACE)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to create window surface: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.egl.config = config;
|
||||
|
||||
// Load the appropriate client library
|
||||
if (!_glfw.egl.KHR_get_all_proc_addresses)
|
||||
{
|
||||
int i;
|
||||
const char** sonames;
|
||||
const char* es1sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_GLESV1_LIBRARY)
|
||||
_GLFW_GLESV1_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"GLESv1_CM.dll",
|
||||
"libGLES_CM.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv1_CM.dylib",
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv1_CM.so",
|
||||
#else
|
||||
"libGLESv1_CM.so.1",
|
||||
"libGLES_CM.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
const char* es2sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_GLESV2_LIBRARY)
|
||||
_GLFW_GLESV2_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
"GLESv2.dll",
|
||||
"libGLESv2.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv2.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGLESv2-2.so",
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv2.so",
|
||||
#else
|
||||
"libGLESv2.so.2",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
const char* glsonames[] =
|
||||
{
|
||||
#if defined(_GLFW_OPENGL_LIBRARY)
|
||||
_GLFW_OPENGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
"libOpenGL.so.0",
|
||||
"libGL.so.1",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
if (ctxconfig->major == 1)
|
||||
sonames = es1sonames;
|
||||
else
|
||||
sonames = es2sonames;
|
||||
}
|
||||
else
|
||||
sonames = glsonames;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
// HACK: Match presence of lib prefix to increase chance of finding
|
||||
// a matching pair in the jungle that is Win32 EGL/GLES
|
||||
if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
|
||||
continue;
|
||||
|
||||
window->context.egl.client = _glfwPlatformLoadModule(sonames[i]);
|
||||
if (window->context.egl.client)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!window->context.egl.client)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to load client library");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentEGL;
|
||||
window->context.swapBuffers = swapBuffersEGL;
|
||||
window->context.swapInterval = swapIntervalEGL;
|
||||
window->context.extensionSupported = extensionSupportedEGL;
|
||||
window->context.getProcAddress = getProcAddressEGL;
|
||||
window->context.destroy = destroyContextEGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef SET_ATTRIB
|
||||
|
||||
// Returns the Visual and depth of the chosen EGLConfig
|
||||
//
|
||||
#if defined(_GLFW_X11)
|
||||
GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig,
|
||||
Visual** visual, int* depth)
|
||||
{
|
||||
XVisualInfo* result;
|
||||
XVisualInfo desired;
|
||||
EGLConfig native;
|
||||
EGLint visualID = 0, count = 0;
|
||||
const long vimask = VisualScreenMask | VisualIDMask;
|
||||
|
||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
|
||||
return GLFW_FALSE;
|
||||
|
||||
eglGetConfigAttrib(_glfw.egl.display, native,
|
||||
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||
|
||||
desired.screen = _glfw.x11.screen;
|
||||
desired.visualid = visualID;
|
||||
|
||||
result = XGetVisualInfo(_glfw.x11.display, vimask, &desired, &count);
|
||||
if (!result)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"EGL: Failed to retrieve Visual for EGLConfig");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
*visual = result->visual;
|
||||
*depth = result->depth;
|
||||
|
||||
XFree(result);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
#endif // _GLFW_X11
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI EGLDisplay glfwGetEGLDisplay(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY);
|
||||
return _glfw.egl.display;
|
||||
}
|
||||
|
||||
SSCAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*)handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
|
||||
|
||||
if (window->context.source != GLFW_EGL_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
return window->context.egl.handle;
|
||||
}
|
||||
|
||||
SSCAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*)handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
|
||||
|
||||
if (window->context.source != GLFW_EGL_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
return window->context.egl.surface;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,550 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
// NOTE: The global variables below comprise all mutable global data in GLFW
|
||||
// Any other mutable global variable is a bug
|
||||
|
||||
// This contains all mutable state shared between compilation units of GLFW
|
||||
//
|
||||
_GLFWlibrary _glfw = { GLFW_FALSE };
|
||||
|
||||
// These are outside of _glfw so they can be used before initialization and
|
||||
// after termination without special handling when _glfw is cleared to zero
|
||||
//
|
||||
static _GLFWerror _glfwMainThreadError;
|
||||
static GLFWerrorfun _glfwErrorCallback;
|
||||
static GLFWallocator _glfwInitAllocator;
|
||||
static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
GLFW_TRUE, // hat buttons
|
||||
GLFW_ANGLE_PLATFORM_TYPE_NONE, // ANGLE backend
|
||||
GLFW_ANY_PLATFORM, // preferred platform
|
||||
NULL, // vkGetInstanceProcAddr function
|
||||
{
|
||||
GLFW_TRUE, // macOS menu bar
|
||||
GLFW_TRUE // macOS bundle chdir
|
||||
},
|
||||
{
|
||||
GLFW_TRUE, // X11 XCB Vulkan surface
|
||||
},
|
||||
{
|
||||
GLFW_WAYLAND_PREFER_LIBDECOR // Wayland libdecor mode
|
||||
},
|
||||
};
|
||||
|
||||
// The allocation function used when no custom allocator is set
|
||||
//
|
||||
static void* defaultAllocate(size_t size, void* user)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// The deallocation function used when no custom allocator is set
|
||||
//
|
||||
static void defaultDeallocate(void* block, void* user)
|
||||
{
|
||||
free(block);
|
||||
}
|
||||
|
||||
// The reallocation function used when no custom allocator is set
|
||||
//
|
||||
static void* defaultReallocate(void* block, size_t size, void* user)
|
||||
{
|
||||
return realloc(block, size);
|
||||
}
|
||||
|
||||
// Terminate the library
|
||||
//
|
||||
static void terminate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks));
|
||||
|
||||
while (_glfw.windowListHead)
|
||||
glfwDestroyWindow((GLFWwindow*)_glfw.windowListHead);
|
||||
|
||||
while (_glfw.cursorListHead)
|
||||
glfwDestroyCursor((GLFWcursor*)_glfw.cursorListHead);
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
{
|
||||
_GLFWmonitor* monitor = _glfw.monitors[i];
|
||||
if (monitor->originalRamp.size)
|
||||
_glfw.platform.setGammaRamp(monitor, &monitor->originalRamp);
|
||||
_glfwFreeMonitor(monitor);
|
||||
}
|
||||
|
||||
_glfw_free(_glfw.monitors);
|
||||
_glfw.monitors = NULL;
|
||||
_glfw.monitorCount = 0;
|
||||
|
||||
_glfw_free(_glfw.mappings);
|
||||
_glfw.mappings = NULL;
|
||||
_glfw.mappingCount = 0;
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
_glfw.platform.terminateJoysticks();
|
||||
_glfw.platform.terminate();
|
||||
|
||||
_glfw.initialized = GLFW_FALSE;
|
||||
|
||||
while (_glfw.errorListHead)
|
||||
{
|
||||
_GLFWerror* error = _glfw.errorListHead;
|
||||
_glfw.errorListHead = error->next;
|
||||
_glfw_free(error);
|
||||
}
|
||||
|
||||
_glfwPlatformDestroyTls(&_glfw.contextSlot);
|
||||
_glfwPlatformDestroyTls(&_glfw.errorSlot);
|
||||
_glfwPlatformDestroyMutex(&_glfw.errorLock);
|
||||
|
||||
memset(&_glfw, 0, sizeof(_glfw));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Encode a Unicode code point to a UTF-8 stream
|
||||
// Based on cutef8 by Jeff Bezanson (Public Domain)
|
||||
//
|
||||
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
if (codepoint < 0x80)
|
||||
s[count++] = (char)codepoint;
|
||||
else if (codepoint < 0x800)
|
||||
{
|
||||
s[count++] = (codepoint >> 6) | 0xc0;
|
||||
s[count++] = (codepoint & 0x3f) | 0x80;
|
||||
}
|
||||
else if (codepoint < 0x10000)
|
||||
{
|
||||
s[count++] = (codepoint >> 12) | 0xe0;
|
||||
s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;
|
||||
s[count++] = (codepoint & 0x3f) | 0x80;
|
||||
}
|
||||
else if (codepoint < 0x110000)
|
||||
{
|
||||
s[count++] = (codepoint >> 18) | 0xf0;
|
||||
s[count++] = ((codepoint >> 12) & 0x3f) | 0x80;
|
||||
s[count++] = ((codepoint >> 6) & 0x3f) | 0x80;
|
||||
s[count++] = (codepoint & 0x3f) | 0x80;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Splits and translates a text/uri-list into separate file paths
|
||||
// NOTE: This function destroys the provided string
|
||||
//
|
||||
char** _glfwParseUriList(char* text, int* count)
|
||||
{
|
||||
const char* prefix = "file://";
|
||||
char** paths = NULL;
|
||||
char* line;
|
||||
|
||||
*count = 0;
|
||||
|
||||
while ((line = strtok(text, "\r\n")))
|
||||
{
|
||||
char* path;
|
||||
|
||||
text = NULL;
|
||||
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||
{
|
||||
line += strlen(prefix);
|
||||
// TODO: Validate hostname
|
||||
while (*line != '/')
|
||||
line++;
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
|
||||
path = _glfw_calloc(strlen(line) + 1, 1);
|
||||
paths = _glfw_realloc(paths, *count * sizeof(char*));
|
||||
paths[*count - 1] = path;
|
||||
|
||||
while (*line)
|
||||
{
|
||||
if (line[0] == '%' && line[1] && line[2])
|
||||
{
|
||||
const char digits[3] = { line[1], line[2], '\0' };
|
||||
*path = (char)strtol(digits, NULL, 16);
|
||||
line += 2;
|
||||
}
|
||||
else
|
||||
*path = *line;
|
||||
|
||||
path++;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
char* _glfw_strdup(const char* source)
|
||||
{
|
||||
const size_t length = strlen(source);
|
||||
char* result = _glfw_calloc(length + 1, 1);
|
||||
strcpy(result, source);
|
||||
return result;
|
||||
}
|
||||
|
||||
int _glfw_min(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
int _glfw_max(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
float _glfw_fminf(float a, float b)
|
||||
{
|
||||
if (a != a)
|
||||
return b;
|
||||
else if (b != b)
|
||||
return a;
|
||||
else if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
float _glfw_fmaxf(float a, float b)
|
||||
{
|
||||
if (a != a)
|
||||
return b;
|
||||
else if (b != b)
|
||||
return a;
|
||||
else if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
void* _glfw_calloc(size_t count, size_t size)
|
||||
{
|
||||
if (count && size)
|
||||
{
|
||||
void* block;
|
||||
|
||||
if (count > SIZE_MAX / size)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Allocation size overflow");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block = _glfw.allocator.allocate(count * size, _glfw.allocator.user);
|
||||
if (block)
|
||||
return memset(block, 0, count * size);
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* _glfw_realloc(void* block, size_t size)
|
||||
{
|
||||
if (block && size)
|
||||
{
|
||||
void* resized = _glfw.allocator.reallocate(block, size, _glfw.allocator.user);
|
||||
if (resized)
|
||||
return resized;
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (block)
|
||||
{
|
||||
_glfw_free(block);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return _glfw_calloc(1, size);
|
||||
}
|
||||
|
||||
void _glfw_free(void* block)
|
||||
{
|
||||
if (block)
|
||||
_glfw.allocator.deallocate(block, _glfw.allocator.user);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of an error
|
||||
//
|
||||
void _glfwInputError(int code, const char* format, ...)
|
||||
{
|
||||
_GLFWerror* error;
|
||||
char description[_GLFW_MESSAGE_SIZE];
|
||||
|
||||
if (format)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, format);
|
||||
vsnprintf(description, sizeof(description), format, vl);
|
||||
va_end(vl);
|
||||
|
||||
description[sizeof(description) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (code == GLFW_NOT_INITIALIZED)
|
||||
strcpy(description, "The GLFW library is not initialized");
|
||||
else if (code == GLFW_NO_CURRENT_CONTEXT)
|
||||
strcpy(description, "There is no current context");
|
||||
else if (code == GLFW_INVALID_ENUM)
|
||||
strcpy(description, "Invalid argument for enum parameter");
|
||||
else if (code == GLFW_INVALID_VALUE)
|
||||
strcpy(description, "Invalid value for parameter");
|
||||
else if (code == GLFW_OUT_OF_MEMORY)
|
||||
strcpy(description, "Out of memory");
|
||||
else if (code == GLFW_API_UNAVAILABLE)
|
||||
strcpy(description, "The requested API is unavailable");
|
||||
else if (code == GLFW_VERSION_UNAVAILABLE)
|
||||
strcpy(description, "The requested API version is unavailable");
|
||||
else if (code == GLFW_PLATFORM_ERROR)
|
||||
strcpy(description, "A platform-specific error occurred");
|
||||
else if (code == GLFW_FORMAT_UNAVAILABLE)
|
||||
strcpy(description, "The requested format is unavailable");
|
||||
else if (code == GLFW_NO_WINDOW_CONTEXT)
|
||||
strcpy(description, "The specified window has no context");
|
||||
else if (code == GLFW_CURSOR_UNAVAILABLE)
|
||||
strcpy(description, "The specified cursor shape is unavailable");
|
||||
else if (code == GLFW_FEATURE_UNAVAILABLE)
|
||||
strcpy(description, "The requested feature cannot be implemented for this platform");
|
||||
else if (code == GLFW_FEATURE_UNIMPLEMENTED)
|
||||
strcpy(description, "The requested feature has not yet been implemented for this platform");
|
||||
else if (code == GLFW_PLATFORM_UNAVAILABLE)
|
||||
strcpy(description, "The requested platform is unavailable");
|
||||
else
|
||||
strcpy(description, "ERROR: UNKNOWN GLFW ERROR");
|
||||
}
|
||||
|
||||
if (_glfw.initialized)
|
||||
{
|
||||
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||
if (!error)
|
||||
{
|
||||
error = _glfw_calloc(1, sizeof(_GLFWerror));
|
||||
_glfwPlatformSetTls(&_glfw.errorSlot, error);
|
||||
_glfwPlatformLockMutex(&_glfw.errorLock);
|
||||
error->next = _glfw.errorListHead;
|
||||
_glfw.errorListHead = error;
|
||||
_glfwPlatformUnlockMutex(&_glfw.errorLock);
|
||||
}
|
||||
}
|
||||
else
|
||||
error = &_glfwMainThreadError;
|
||||
|
||||
error->code = code;
|
||||
strcpy(error->description, description);
|
||||
|
||||
if (_glfwErrorCallback)
|
||||
_glfwErrorCallback(code, description);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI int glfwInit(void)
|
||||
{
|
||||
if (_glfw.initialized)
|
||||
return GLFW_TRUE;
|
||||
|
||||
memset(&_glfw, 0, sizeof(_glfw));
|
||||
_glfw.hints.init = _glfwInitHints;
|
||||
|
||||
_glfw.allocator = _glfwInitAllocator;
|
||||
if (!_glfw.allocator.allocate)
|
||||
{
|
||||
_glfw.allocator.allocate = defaultAllocate;
|
||||
_glfw.allocator.reallocate = defaultReallocate;
|
||||
_glfw.allocator.deallocate = defaultDeallocate;
|
||||
}
|
||||
|
||||
if (!_glfwSelectPlatform(_glfw.hints.init.platformID, &_glfw.platform))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!_glfw.platform.init())
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwPlatformCreateMutex(&_glfw.errorLock) ||
|
||||
!_glfwPlatformCreateTls(&_glfw.errorSlot) ||
|
||||
!_glfwPlatformCreateTls(&_glfw.contextSlot))
|
||||
{
|
||||
terminate();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError);
|
||||
|
||||
_glfwInitGamepadMappings();
|
||||
|
||||
_glfwPlatformInitTimer();
|
||||
_glfw.timer.offset = _glfwPlatformGetTimerValue();
|
||||
|
||||
_glfw.initialized = GLFW_TRUE;
|
||||
|
||||
glfwDefaultWindowHints();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
SSCAPI void glfwTerminate(void)
|
||||
{
|
||||
if (!_glfw.initialized)
|
||||
return;
|
||||
|
||||
terminate();
|
||||
}
|
||||
|
||||
SSCAPI void glfwInitHint(int hint, int value)
|
||||
{
|
||||
switch (hint)
|
||||
{
|
||||
case GLFW_JOYSTICK_HAT_BUTTONS:
|
||||
_glfwInitHints.hatButtons = value;
|
||||
return;
|
||||
case GLFW_ANGLE_PLATFORM_TYPE:
|
||||
_glfwInitHints.angleType = value;
|
||||
return;
|
||||
case GLFW_PLATFORM:
|
||||
_glfwInitHints.platformID = value;
|
||||
return;
|
||||
case GLFW_COCOA_CHDIR_RESOURCES:
|
||||
_glfwInitHints.ns.chdir = value;
|
||||
return;
|
||||
case GLFW_COCOA_MENUBAR:
|
||||
_glfwInitHints.ns.menubar = value;
|
||||
return;
|
||||
case GLFW_X11_XCB_VULKAN_SURFACE:
|
||||
_glfwInitHints.x11.xcbVulkanSurface = value;
|
||||
return;
|
||||
case GLFW_WAYLAND_LIBDECOR:
|
||||
_glfwInitHints.wl.libdecorMode = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
"Invalid init hint 0x%08X", hint);
|
||||
}
|
||||
|
||||
SSCAPI void glfwInitAllocator(const GLFWallocator* allocator)
|
||||
{
|
||||
if (allocator)
|
||||
{
|
||||
if (allocator->allocate && allocator->reallocate && allocator->deallocate)
|
||||
_glfwInitAllocator = *allocator;
|
||||
else
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Missing function in allocator");
|
||||
}
|
||||
else
|
||||
memset(&_glfwInitAllocator, 0, sizeof(GLFWallocator));
|
||||
}
|
||||
|
||||
SSCAPI void glfwInitVulkanLoader(PFN_vkGetInstanceProcAddr loader)
|
||||
{
|
||||
_glfwInitHints.vulkanLoader = loader;
|
||||
}
|
||||
|
||||
SSCAPI void glfwGetVersion(int* major, int* minor, int* rev)
|
||||
{
|
||||
if (major != NULL)
|
||||
*major = GLFW_VERSION_MAJOR;
|
||||
if (minor != NULL)
|
||||
*minor = GLFW_VERSION_MINOR;
|
||||
if (rev != NULL)
|
||||
*rev = GLFW_VERSION_REVISION;
|
||||
}
|
||||
|
||||
SSCAPI int glfwGetError(const char** description)
|
||||
{
|
||||
_GLFWerror* error;
|
||||
int code = GLFW_NO_ERROR;
|
||||
|
||||
if (description)
|
||||
*description = NULL;
|
||||
|
||||
if (_glfw.initialized)
|
||||
error = _glfwPlatformGetTls(&_glfw.errorSlot);
|
||||
else
|
||||
error = &_glfwMainThreadError;
|
||||
|
||||
if (error)
|
||||
{
|
||||
code = error->code;
|
||||
error->code = GLFW_NO_ERROR;
|
||||
if (description && code)
|
||||
*description = error->description;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
SSCAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||
{
|
||||
_GLFW_SWAP(GLFWerrorfun, _glfwErrorCallback, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,548 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// Lexically compare video modes, used by qsort
|
||||
//
|
||||
static int compareVideoModes(const void* fp, const void* sp)
|
||||
{
|
||||
const GLFWvidmode* fm = fp;
|
||||
const GLFWvidmode* sm = sp;
|
||||
const int fbpp = fm->redBits + fm->greenBits + fm->blueBits;
|
||||
const int sbpp = sm->redBits + sm->greenBits + sm->blueBits;
|
||||
const int farea = fm->width * fm->height;
|
||||
const int sarea = sm->width * sm->height;
|
||||
|
||||
// First sort on color bits per pixel
|
||||
if (fbpp != sbpp)
|
||||
return fbpp - sbpp;
|
||||
|
||||
// Then sort on screen area
|
||||
if (farea != sarea)
|
||||
return farea - sarea;
|
||||
|
||||
// Then sort on width
|
||||
if (fm->width != sm->width)
|
||||
return fm->width - sm->width;
|
||||
|
||||
// Lastly sort on refresh rate
|
||||
return fm->refreshRate - sm->refreshRate;
|
||||
}
|
||||
|
||||
// Retrieves the available modes for the specified monitor
|
||||
//
|
||||
static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
|
||||
{
|
||||
int modeCount;
|
||||
GLFWvidmode* modes;
|
||||
|
||||
if (monitor->modes)
|
||||
return GLFW_TRUE;
|
||||
|
||||
modes = _glfw.platform.getVideoModes(monitor, &modeCount);
|
||||
if (!modes)
|
||||
return GLFW_FALSE;
|
||||
|
||||
qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes);
|
||||
|
||||
_glfw_free(monitor->modes);
|
||||
monitor->modes = modes;
|
||||
monitor->modeCount = modeCount;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Notifies shared code of a monitor connection or disconnection
|
||||
//
|
||||
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
|
||||
{
|
||||
assert(monitor != NULL);
|
||||
assert(action == GLFW_CONNECTED || action == GLFW_DISCONNECTED);
|
||||
assert(placement == _GLFW_INSERT_FIRST || placement == _GLFW_INSERT_LAST);
|
||||
|
||||
if (action == GLFW_CONNECTED)
|
||||
{
|
||||
_glfw.monitorCount++;
|
||||
_glfw.monitors =
|
||||
_glfw_realloc(_glfw.monitors,
|
||||
sizeof(_GLFWmonitor*) * _glfw.monitorCount);
|
||||
|
||||
if (placement == _GLFW_INSERT_FIRST)
|
||||
{
|
||||
memmove(_glfw.monitors + 1,
|
||||
_glfw.monitors,
|
||||
((size_t) _glfw.monitorCount - 1) * sizeof(_GLFWmonitor*));
|
||||
_glfw.monitors[0] = monitor;
|
||||
}
|
||||
else
|
||||
_glfw.monitors[_glfw.monitorCount - 1] = monitor;
|
||||
}
|
||||
else if (action == GLFW_DISCONNECTED)
|
||||
{
|
||||
int i;
|
||||
_GLFWwindow* window;
|
||||
|
||||
for (window = _glfw.windowListHead; window; window = window->next)
|
||||
{
|
||||
if (window->monitor == monitor)
|
||||
{
|
||||
int width, height, xoff, yoff;
|
||||
_glfw.platform.getWindowSize(window, &width, &height);
|
||||
_glfw.platform.setWindowMonitor(window, NULL, 0, 0, width, height, 0);
|
||||
_glfw.platform.getWindowFrameSize(window, &xoff, &yoff, NULL, NULL);
|
||||
_glfw.platform.setWindowPos(window, xoff, yoff);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _glfw.monitorCount; i++)
|
||||
{
|
||||
if (_glfw.monitors[i] == monitor)
|
||||
{
|
||||
_glfw.monitorCount--;
|
||||
memmove(_glfw.monitors + i,
|
||||
_glfw.monitors + i + 1,
|
||||
((size_t) _glfw.monitorCount - i) * sizeof(_GLFWmonitor*));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.callbacks.monitor)
|
||||
_glfw.callbacks.monitor((GLFWmonitor*) monitor, action);
|
||||
|
||||
if (action == GLFW_DISCONNECTED)
|
||||
_glfwFreeMonitor(monitor);
|
||||
}
|
||||
|
||||
// Notifies shared code that a full screen window has acquired or released
|
||||
// a monitor
|
||||
//
|
||||
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
|
||||
{
|
||||
assert(monitor != NULL);
|
||||
monitor->window = window;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Allocates and returns a monitor object with the specified name and dimensions
|
||||
//
|
||||
_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM)
|
||||
{
|
||||
_GLFWmonitor* monitor = _glfw_calloc(1, sizeof(_GLFWmonitor));
|
||||
monitor->widthMM = widthMM;
|
||||
monitor->heightMM = heightMM;
|
||||
|
||||
strncpy(monitor->name, name, sizeof(monitor->name) - 1);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
// Frees a monitor object and any data associated with it
|
||||
//
|
||||
void _glfwFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor == NULL)
|
||||
return;
|
||||
|
||||
_glfw.platform.freeMonitor(monitor);
|
||||
|
||||
_glfwFreeGammaArrays(&monitor->originalRamp);
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
|
||||
_glfw_free(monitor->modes);
|
||||
_glfw_free(monitor);
|
||||
}
|
||||
|
||||
// Allocates red, green and blue value arrays of the specified size
|
||||
//
|
||||
void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size)
|
||||
{
|
||||
ramp->red = _glfw_calloc(size, sizeof(unsigned short));
|
||||
ramp->green = _glfw_calloc(size, sizeof(unsigned short));
|
||||
ramp->blue = _glfw_calloc(size, sizeof(unsigned short));
|
||||
ramp->size = size;
|
||||
}
|
||||
|
||||
// Frees the red, green and blue value arrays and clears the struct
|
||||
//
|
||||
void _glfwFreeGammaArrays(GLFWgammaramp* ramp)
|
||||
{
|
||||
_glfw_free(ramp->red);
|
||||
_glfw_free(ramp->green);
|
||||
_glfw_free(ramp->blue);
|
||||
|
||||
memset(ramp, 0, sizeof(GLFWgammaramp));
|
||||
}
|
||||
|
||||
// Chooses the video mode most closely matching the desired one
|
||||
//
|
||||
const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor,
|
||||
const GLFWvidmode* desired)
|
||||
{
|
||||
int i;
|
||||
unsigned int sizeDiff, leastSizeDiff = UINT_MAX;
|
||||
unsigned int rateDiff, leastRateDiff = UINT_MAX;
|
||||
unsigned int colorDiff, leastColorDiff = UINT_MAX;
|
||||
const GLFWvidmode* current;
|
||||
const GLFWvidmode* closest = NULL;
|
||||
|
||||
if (!refreshVideoModes(monitor))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < monitor->modeCount; i++)
|
||||
{
|
||||
current = monitor->modes + i;
|
||||
|
||||
colorDiff = 0;
|
||||
|
||||
if (desired->redBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->redBits - desired->redBits);
|
||||
if (desired->greenBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->greenBits - desired->greenBits);
|
||||
if (desired->blueBits != GLFW_DONT_CARE)
|
||||
colorDiff += abs(current->blueBits - desired->blueBits);
|
||||
|
||||
sizeDiff = abs((current->width - desired->width) *
|
||||
(current->width - desired->width) +
|
||||
(current->height - desired->height) *
|
||||
(current->height - desired->height));
|
||||
|
||||
if (desired->refreshRate != GLFW_DONT_CARE)
|
||||
rateDiff = abs(current->refreshRate - desired->refreshRate);
|
||||
else
|
||||
rateDiff = UINT_MAX - current->refreshRate;
|
||||
|
||||
if ((colorDiff < leastColorDiff) ||
|
||||
(colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) ||
|
||||
(colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff))
|
||||
{
|
||||
closest = current;
|
||||
leastSizeDiff = sizeDiff;
|
||||
leastRateDiff = rateDiff;
|
||||
leastColorDiff = colorDiff;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
// Performs lexical comparison between two @ref GLFWvidmode structures
|
||||
//
|
||||
int _glfwCompareVideoModes(const GLFWvidmode* fm, const GLFWvidmode* sm)
|
||||
{
|
||||
return compareVideoModes(fm, sm);
|
||||
}
|
||||
|
||||
// Splits a color depth into red, green and blue bit depths
|
||||
//
|
||||
void _glfwSplitBPP(int bpp, int* red, int* green, int* blue)
|
||||
{
|
||||
int delta;
|
||||
|
||||
// We assume that by 32 the user really meant 24
|
||||
if (bpp == 32)
|
||||
bpp = 24;
|
||||
|
||||
// Convert "bits per pixel" to red, green & blue sizes
|
||||
|
||||
*red = *green = *blue = bpp / 3;
|
||||
delta = bpp - (*red * 3);
|
||||
if (delta >= 1)
|
||||
*green = *green + 1;
|
||||
|
||||
if (delta == 2)
|
||||
*red = *red + 1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI GLFWmonitor** glfwGetMonitors(int* count)
|
||||
{
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
*count = _glfw.monitorCount;
|
||||
return (GLFWmonitor**) _glfw.monitors;
|
||||
}
|
||||
|
||||
SSCAPI GLFWmonitor* glfwGetPrimaryMonitor(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfw.monitorCount)
|
||||
return NULL;
|
||||
|
||||
return (GLFWmonitor*) _glfw.monitors[0];
|
||||
}
|
||||
|
||||
SSCAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_glfw.platform.getMonitorPos(monitor, xpos, ypos);
|
||||
}
|
||||
|
||||
SSCAPI void glfwGetMonitorWorkarea(GLFWmonitor* handle,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
if (width)
|
||||
*width = 0;
|
||||
if (height)
|
||||
*height = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
_glfw.platform.getMonitorWorkarea(monitor, xpos, ypos, width, height);
|
||||
}
|
||||
|
||||
SSCAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (widthMM)
|
||||
*widthMM = 0;
|
||||
if (heightMM)
|
||||
*heightMM = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (widthMM)
|
||||
*widthMM = monitor->widthMM;
|
||||
if (heightMM)
|
||||
*heightMM = monitor->heightMM;
|
||||
}
|
||||
|
||||
SSCAPI void glfwGetMonitorContentScale(GLFWmonitor* handle,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
if (xscale)
|
||||
*xscale = 0.f;
|
||||
if (yscale)
|
||||
*yscale = 0.f;
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfw.platform.getMonitorContentScale(monitor, xscale, yscale);
|
||||
}
|
||||
|
||||
SSCAPI const char* glfwGetMonitorName(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->name;
|
||||
}
|
||||
|
||||
SSCAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
monitor->userPointer = pointer;
|
||||
}
|
||||
|
||||
SSCAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->userPointer;
|
||||
}
|
||||
|
||||
SSCAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
_GLFW_SWAP(GLFWmonitorfun, _glfw.callbacks.monitor, cbfun);
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
SSCAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!refreshVideoModes(monitor))
|
||||
return NULL;
|
||||
|
||||
*count = monitor->modeCount;
|
||||
return monitor->modes;
|
||||
}
|
||||
|
||||
SSCAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
_glfw.platform.getVideoMode(monitor, &monitor->currentMode);
|
||||
return &monitor->currentMode;
|
||||
}
|
||||
|
||||
SSCAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned short* values;
|
||||
GLFWgammaramp ramp;
|
||||
const GLFWgammaramp* original;
|
||||
assert(handle != NULL);
|
||||
assert(gamma > 0.f);
|
||||
assert(gamma <= FLT_MAX);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (gamma != gamma || gamma <= 0.f || gamma > FLT_MAX)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid gamma value %f", gamma);
|
||||
return;
|
||||
}
|
||||
|
||||
original = glfwGetGammaRamp(handle);
|
||||
if (!original)
|
||||
return;
|
||||
|
||||
values = _glfw_calloc(original->size, sizeof(unsigned short));
|
||||
|
||||
for (i = 0; i < original->size; i++)
|
||||
{
|
||||
float value;
|
||||
|
||||
// Calculate intensity
|
||||
value = i / (float) (original->size - 1);
|
||||
// Apply gamma curve
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
// Clamp to value range
|
||||
value = _glfw_fminf(value, 65535.f);
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
|
||||
ramp.red = values;
|
||||
ramp.green = values;
|
||||
ramp.blue = values;
|
||||
ramp.size = original->size;
|
||||
|
||||
glfwSetGammaRamp(handle, &ramp);
|
||||
_glfw_free(values);
|
||||
}
|
||||
|
||||
SSCAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
if (!_glfw.platform.getGammaRamp(monitor, &monitor->currentRamp))
|
||||
return NULL;
|
||||
|
||||
return &monitor->currentRamp;
|
||||
}
|
||||
|
||||
SSCAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
assert(ramp != NULL);
|
||||
assert(ramp->size > 0);
|
||||
assert(ramp->red != NULL);
|
||||
assert(ramp->green != NULL);
|
||||
assert(ramp->blue != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (ramp->size <= 0)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Invalid gamma ramp size %i",
|
||||
ramp->size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!monitor->originalRamp.size)
|
||||
{
|
||||
if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp))
|
||||
return;
|
||||
}
|
||||
|
||||
_glfw.platform.setGammaRamp(monitor, ramp);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwConnectNull(int platformID, _GLFWplatform* platform)
|
||||
{
|
||||
const _GLFWplatform null =
|
||||
{
|
||||
GLFW_PLATFORM_NULL,
|
||||
_glfwInitNull,
|
||||
_glfwTerminateNull,
|
||||
_glfwGetCursorPosNull,
|
||||
_glfwSetCursorPosNull,
|
||||
_glfwSetCursorModeNull,
|
||||
_glfwSetRawMouseMotionNull,
|
||||
_glfwRawMouseMotionSupportedNull,
|
||||
_glfwCreateCursorNull,
|
||||
_glfwCreateStandardCursorNull,
|
||||
_glfwDestroyCursorNull,
|
||||
_glfwSetCursorNull,
|
||||
_glfwGetScancodeNameNull,
|
||||
_glfwGetKeyScancodeNull,
|
||||
_glfwSetClipboardStringNull,
|
||||
_glfwGetClipboardStringNull,
|
||||
_glfwInitJoysticksNull,
|
||||
_glfwTerminateJoysticksNull,
|
||||
_glfwPollJoystickNull,
|
||||
_glfwGetMappingNameNull,
|
||||
_glfwUpdateGamepadGUIDNull,
|
||||
_glfwFreeMonitorNull,
|
||||
_glfwGetMonitorPosNull,
|
||||
_glfwGetMonitorContentScaleNull,
|
||||
_glfwGetMonitorWorkareaNull,
|
||||
_glfwGetVideoModesNull,
|
||||
_glfwGetVideoModeNull,
|
||||
_glfwGetGammaRampNull,
|
||||
_glfwSetGammaRampNull,
|
||||
_glfwCreateWindowNull,
|
||||
_glfwDestroyWindowNull,
|
||||
_glfwSetWindowTitleNull,
|
||||
_glfwSetWindowIconNull,
|
||||
_glfwGetWindowPosNull,
|
||||
_glfwSetWindowPosNull,
|
||||
_glfwGetWindowSizeNull,
|
||||
_glfwSetWindowSizeNull,
|
||||
_glfwSetWindowSizeLimitsNull,
|
||||
_glfwSetWindowAspectRatioNull,
|
||||
_glfwGetFramebufferSizeNull,
|
||||
_glfwGetWindowFrameSizeNull,
|
||||
_glfwGetWindowContentScaleNull,
|
||||
_glfwIconifyWindowNull,
|
||||
_glfwRestoreWindowNull,
|
||||
_glfwMaximizeWindowNull,
|
||||
_glfwShowWindowNull,
|
||||
_glfwHideWindowNull,
|
||||
_glfwRequestWindowAttentionNull,
|
||||
_glfwFocusWindowNull,
|
||||
_glfwSetWindowMonitorNull,
|
||||
_glfwWindowFocusedNull,
|
||||
_glfwWindowIconifiedNull,
|
||||
_glfwWindowVisibleNull,
|
||||
_glfwWindowMaximizedNull,
|
||||
_glfwWindowHoveredNull,
|
||||
_glfwFramebufferTransparentNull,
|
||||
_glfwGetWindowOpacityNull,
|
||||
_glfwSetWindowResizableNull,
|
||||
_glfwSetWindowDecoratedNull,
|
||||
_glfwSetWindowFloatingNull,
|
||||
_glfwSetWindowOpacityNull,
|
||||
_glfwSetWindowMousePassthroughNull,
|
||||
_glfwPollEventsNull,
|
||||
_glfwWaitEventsNull,
|
||||
_glfwWaitEventsTimeoutNull,
|
||||
_glfwPostEmptyEventNull,
|
||||
_glfwGetEGLPlatformNull,
|
||||
_glfwGetEGLNativeDisplayNull,
|
||||
_glfwGetEGLNativeWindowNull,
|
||||
_glfwGetRequiredInstanceExtensionsNull,
|
||||
_glfwGetPhysicalDevicePresentationSupportNull,
|
||||
_glfwCreateWindowSurfaceNull,
|
||||
};
|
||||
|
||||
*platform = null;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
int _glfwInitNull(void)
|
||||
{
|
||||
int scancode;
|
||||
|
||||
memset(_glfw.null.keycodes, -1, sizeof(_glfw.null.keycodes));
|
||||
memset(_glfw.null.scancodes, -1, sizeof(_glfw.null.scancodes));
|
||||
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_SPACE] = GLFW_KEY_SPACE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_COMMA] = GLFW_KEY_COMMA;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_MINUS] = GLFW_KEY_MINUS;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_PERIOD] = GLFW_KEY_PERIOD;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_SLASH] = GLFW_KEY_SLASH;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_0] = GLFW_KEY_0;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_1] = GLFW_KEY_1;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_2] = GLFW_KEY_2;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_3] = GLFW_KEY_3;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_4] = GLFW_KEY_4;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_5] = GLFW_KEY_5;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_6] = GLFW_KEY_6;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_7] = GLFW_KEY_7;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_8] = GLFW_KEY_8;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_9] = GLFW_KEY_9;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_SEMICOLON] = GLFW_KEY_SEMICOLON;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_EQUAL] = GLFW_KEY_EQUAL;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_A] = GLFW_KEY_A;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_B] = GLFW_KEY_B;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_C] = GLFW_KEY_C;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_D] = GLFW_KEY_D;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_E] = GLFW_KEY_E;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F] = GLFW_KEY_F;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_G] = GLFW_KEY_G;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_H] = GLFW_KEY_H;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_I] = GLFW_KEY_I;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_J] = GLFW_KEY_J;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_K] = GLFW_KEY_K;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_L] = GLFW_KEY_L;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_M] = GLFW_KEY_M;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_N] = GLFW_KEY_N;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_O] = GLFW_KEY_O;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_P] = GLFW_KEY_P;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_Q] = GLFW_KEY_Q;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_R] = GLFW_KEY_R;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_S] = GLFW_KEY_S;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_T] = GLFW_KEY_T;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_U] = GLFW_KEY_U;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_V] = GLFW_KEY_V;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_W] = GLFW_KEY_W;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_X] = GLFW_KEY_X;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_Y] = GLFW_KEY_Y;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_Z] = GLFW_KEY_Z;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT_BRACKET] = GLFW_KEY_LEFT_BRACKET;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_BACKSLASH] = GLFW_KEY_BACKSLASH;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT_BRACKET] = GLFW_KEY_RIGHT_BRACKET;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_GRAVE_ACCENT] = GLFW_KEY_GRAVE_ACCENT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_WORLD_1] = GLFW_KEY_WORLD_1;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_WORLD_2] = GLFW_KEY_WORLD_2;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_ESCAPE] = GLFW_KEY_ESCAPE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_ENTER] = GLFW_KEY_ENTER;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_TAB] = GLFW_KEY_TAB;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_BACKSPACE] = GLFW_KEY_BACKSPACE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_INSERT] = GLFW_KEY_INSERT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_DELETE] = GLFW_KEY_DELETE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT] = GLFW_KEY_RIGHT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT] = GLFW_KEY_LEFT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_DOWN] = GLFW_KEY_DOWN;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_UP] = GLFW_KEY_UP;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_PAGE_UP] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_PAGE_DOWN] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_HOME] = GLFW_KEY_HOME;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_END] = GLFW_KEY_END;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_CAPS_LOCK] = GLFW_KEY_CAPS_LOCK;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_SCROLL_LOCK] = GLFW_KEY_SCROLL_LOCK;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_NUM_LOCK] = GLFW_KEY_NUM_LOCK;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_PRINT_SCREEN] = GLFW_KEY_PRINT_SCREEN;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_PAUSE] = GLFW_KEY_PAUSE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F1] = GLFW_KEY_F1;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F2] = GLFW_KEY_F2;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F3] = GLFW_KEY_F3;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F4] = GLFW_KEY_F4;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F5] = GLFW_KEY_F5;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F6] = GLFW_KEY_F6;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F7] = GLFW_KEY_F7;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F8] = GLFW_KEY_F8;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F9] = GLFW_KEY_F9;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F10] = GLFW_KEY_F10;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F11] = GLFW_KEY_F11;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F12] = GLFW_KEY_F12;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F13] = GLFW_KEY_F13;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F14] = GLFW_KEY_F14;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F15] = GLFW_KEY_F15;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F16] = GLFW_KEY_F16;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F17] = GLFW_KEY_F17;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F18] = GLFW_KEY_F18;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F19] = GLFW_KEY_F19;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F20] = GLFW_KEY_F20;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F21] = GLFW_KEY_F21;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F22] = GLFW_KEY_F22;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F23] = GLFW_KEY_F23;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F24] = GLFW_KEY_F24;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_F25] = GLFW_KEY_F25;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_0] = GLFW_KEY_KP_0;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_1] = GLFW_KEY_KP_1;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_2] = GLFW_KEY_KP_2;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_3] = GLFW_KEY_KP_3;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_4] = GLFW_KEY_KP_4;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_5] = GLFW_KEY_KP_5;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_6] = GLFW_KEY_KP_6;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_7] = GLFW_KEY_KP_7;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_8] = GLFW_KEY_KP_8;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_9] = GLFW_KEY_KP_9;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_DECIMAL] = GLFW_KEY_KP_DECIMAL;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_DIVIDE] = GLFW_KEY_KP_DIVIDE;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_MULTIPLY] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_SUBTRACT] = GLFW_KEY_KP_SUBTRACT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_ADD] = GLFW_KEY_KP_ADD;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_ENTER] = GLFW_KEY_KP_ENTER;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_KP_EQUAL] = GLFW_KEY_KP_EQUAL;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT_SHIFT] = GLFW_KEY_LEFT_SHIFT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT_CONTROL] = GLFW_KEY_LEFT_CONTROL;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT_ALT] = GLFW_KEY_LEFT_ALT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_LEFT_SUPER] = GLFW_KEY_LEFT_SUPER;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT_SHIFT] = GLFW_KEY_RIGHT_SHIFT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT_CONTROL] = GLFW_KEY_RIGHT_CONTROL;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT_ALT] = GLFW_KEY_RIGHT_ALT;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_RIGHT_SUPER] = GLFW_KEY_RIGHT_SUPER;
|
||||
_glfw.null.keycodes[GLFW_NULL_SC_MENU] = GLFW_KEY_MENU;
|
||||
|
||||
for (scancode = GLFW_NULL_SC_FIRST; scancode < GLFW_NULL_SC_LAST; scancode++)
|
||||
{
|
||||
if (_glfw.null.keycodes[scancode] > 0)
|
||||
_glfw.null.scancodes[_glfw.null.keycodes[scancode]] = scancode;
|
||||
}
|
||||
|
||||
_glfwPollMonitorsNull();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateNull(void)
|
||||
{
|
||||
free(_glfw.null.clipboardString);
|
||||
_glfwTerminateOSMesa();
|
||||
_glfwTerminateEGL();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitJoysticksNull(void)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateJoysticksNull(void)
|
||||
{
|
||||
}
|
||||
|
||||
GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
const char* _glfwGetMappingNameNull(void)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void _glfwUpdateGamepadGUIDNull(char* guid)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// The the sole (fake) video mode of our (sole) fake monitor
|
||||
//
|
||||
static GLFWvidmode getVideoMode(void)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
mode.width = 1920;
|
||||
mode.height = 1080;
|
||||
mode.redBits = 8;
|
||||
mode.greenBits = 8;
|
||||
mode.blueBits = 8;
|
||||
mode.refreshRate = 60;
|
||||
return mode;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPollMonitorsNull(void)
|
||||
{
|
||||
const float dpi = 141.f;
|
||||
const GLFWvidmode mode = getVideoMode();
|
||||
_GLFWmonitor* monitor = _glfwAllocMonitor("Null SuperNoop 0",
|
||||
(int) (mode.width * 25.4f / dpi),
|
||||
(int) (mode.height * 25.4f / dpi));
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwFreeMonitorNull(_GLFWmonitor* monitor)
|
||||
{
|
||||
_glfwFreeGammaArrays(&monitor->null.ramp);
|
||||
}
|
||||
|
||||
void _glfwGetMonitorPosNull(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 0;
|
||||
}
|
||||
|
||||
void _glfwGetMonitorContentScaleNull(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
void _glfwGetMonitorWorkareaNull(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
const GLFWvidmode mode = getVideoMode();
|
||||
|
||||
if (xpos)
|
||||
*xpos = 0;
|
||||
if (ypos)
|
||||
*ypos = 10;
|
||||
if (width)
|
||||
*width = mode.width;
|
||||
if (height)
|
||||
*height = mode.height - 10;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwGetVideoModesNull(_GLFWmonitor* monitor, int* found)
|
||||
{
|
||||
GLFWvidmode* mode = _glfw_calloc(1, sizeof(GLFWvidmode));
|
||||
*mode = getVideoMode();
|
||||
*found = 1;
|
||||
return mode;
|
||||
}
|
||||
|
||||
void _glfwGetVideoModeNull(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
{
|
||||
*mode = getVideoMode();
|
||||
}
|
||||
|
||||
GLFWbool _glfwGetGammaRampNull(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
if (!monitor->null.ramp.size)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
_glfwAllocGammaArrays(&monitor->null.ramp, 256);
|
||||
|
||||
for (i = 0; i < monitor->null.ramp.size; i++)
|
||||
{
|
||||
const float gamma = 2.2f;
|
||||
float value;
|
||||
value = i / (float) (monitor->null.ramp.size - 1);
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
value = _glfw_fminf(value, 65535.f);
|
||||
|
||||
monitor->null.ramp.red[i] = (unsigned short) value;
|
||||
monitor->null.ramp.green[i] = (unsigned short) value;
|
||||
monitor->null.ramp.blue[i] = (unsigned short) value;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwAllocGammaArrays(ramp, monitor->null.ramp.size);
|
||||
memcpy(ramp->red, monitor->null.ramp.red, sizeof(short) * ramp->size);
|
||||
memcpy(ramp->green, monitor->null.ramp.green, sizeof(short) * ramp->size);
|
||||
memcpy(ramp->blue, monitor->null.ramp.blue, sizeof(short) * ramp->size);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwSetGammaRampNull(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
if (monitor->null.ramp.size != ramp->size)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Null: Gamma ramp size must match current ramp size");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(monitor->null.ramp.red, ramp->red, sizeof(short) * ramp->size);
|
||||
memcpy(monitor->null.ramp.green, ramp->green, sizeof(short) * ramp->size);
|
||||
memcpy(monitor->null.ramp.blue, ramp->blue, sizeof(short) * ramp->size);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,720 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2016-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
|
||||
{
|
||||
const float ratio = (float) window->numer / (float) window->denom;
|
||||
*height = (int) (*width / ratio);
|
||||
}
|
||||
|
||||
if (window->minwidth != GLFW_DONT_CARE)
|
||||
*width = _glfw_max(*width, window->minwidth);
|
||||
else if (window->maxwidth != GLFW_DONT_CARE)
|
||||
*width = _glfw_min(*width, window->maxwidth);
|
||||
|
||||
if (window->minheight != GLFW_DONT_CARE)
|
||||
*height = _glfw_min(*height, window->minheight);
|
||||
else if (window->maxheight != GLFW_DONT_CARE)
|
||||
*height = _glfw_max(*height, window->maxheight);
|
||||
}
|
||||
|
||||
static void fitToMonitor(_GLFWwindow* window)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
_glfwGetVideoModeNull(window->monitor, &mode);
|
||||
_glfwGetMonitorPosNull(window->monitor,
|
||||
&window->null.xpos,
|
||||
&window->null.ypos);
|
||||
window->null.width = mode.width;
|
||||
window->null.height = mode.height;
|
||||
}
|
||||
|
||||
static void acquireMonitor(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputMonitorWindow(window->monitor, window);
|
||||
}
|
||||
|
||||
static void releaseMonitor(_GLFWwindow* window)
|
||||
{
|
||||
if (window->monitor->window != window)
|
||||
return;
|
||||
|
||||
_glfwInputMonitorWindow(window->monitor, NULL);
|
||||
}
|
||||
|
||||
static int createNativeWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
if (window->monitor)
|
||||
fitToMonitor(window);
|
||||
else
|
||||
{
|
||||
if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
|
||||
{
|
||||
window->null.xpos = 17;
|
||||
window->null.ypos = 17;
|
||||
}
|
||||
else
|
||||
{
|
||||
window->null.xpos = wndconfig->xpos;
|
||||
window->null.ypos = wndconfig->ypos;
|
||||
}
|
||||
|
||||
window->null.width = wndconfig->width;
|
||||
window->null.height = wndconfig->height;
|
||||
}
|
||||
|
||||
window->null.visible = wndconfig->visible;
|
||||
window->null.decorated = wndconfig->decorated;
|
||||
window->null.maximized = wndconfig->maximized;
|
||||
window->null.floating = wndconfig->floating;
|
||||
window->null.transparent = fbconfig->transparent;
|
||||
window->null.opacity = 1.f;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwCreateWindowNull(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
if (!createNativeWindow(window, wndconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API)
|
||||
{
|
||||
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API ||
|
||||
ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitOSMesa())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitEGL())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!_glfwRefreshContextAttribs(window, ctxconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (wndconfig->mousePassthrough)
|
||||
_glfwSetWindowMousePassthroughNull(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
_glfwShowWindowNull(window);
|
||||
_glfwFocusWindowNull(window);
|
||||
acquireMonitor(window);
|
||||
|
||||
if (wndconfig->centerCursor)
|
||||
_glfwCenterCursorInContentArea(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wndconfig->visible)
|
||||
{
|
||||
_glfwShowWindowNull(window);
|
||||
if (wndconfig->focused)
|
||||
_glfwFocusWindowNull(window);
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwDestroyWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
if (window->monitor)
|
||||
releaseMonitor(window);
|
||||
|
||||
if (_glfw.null.focusedWindow == window)
|
||||
_glfw.null.focusedWindow = NULL;
|
||||
|
||||
if (window->context.destroy)
|
||||
window->context.destroy(window);
|
||||
}
|
||||
|
||||
void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetWindowMonitorNull(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
{
|
||||
if (window->monitor == monitor)
|
||||
{
|
||||
if (!monitor)
|
||||
{
|
||||
_glfwSetWindowPosNull(window, xpos, ypos);
|
||||
_glfwSetWindowSizeNull(window, width, height);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (window->monitor)
|
||||
releaseMonitor(window);
|
||||
|
||||
_glfwInputWindowMonitor(window, monitor);
|
||||
|
||||
if (window->monitor)
|
||||
{
|
||||
window->null.visible = GLFW_TRUE;
|
||||
acquireMonitor(window);
|
||||
fitToMonitor(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwSetWindowPosNull(window, xpos, ypos);
|
||||
_glfwSetWindowSizeNull(window, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwGetWindowPosNull(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = window->null.xpos;
|
||||
if (ypos)
|
||||
*ypos = window->null.ypos;
|
||||
}
|
||||
|
||||
void _glfwSetWindowPosNull(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
if (window->monitor)
|
||||
return;
|
||||
|
||||
if (window->null.xpos != xpos || window->null.ypos != ypos)
|
||||
{
|
||||
window->null.xpos = xpos;
|
||||
window->null.ypos = ypos;
|
||||
_glfwInputWindowPos(window, xpos, ypos);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwGetWindowSizeNull(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->null.width;
|
||||
if (height)
|
||||
*height = window->null.height;
|
||||
}
|
||||
|
||||
void _glfwSetWindowSizeNull(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
if (window->monitor)
|
||||
return;
|
||||
|
||||
if (window->null.width != width || window->null.height != height)
|
||||
{
|
||||
window->null.width = width;
|
||||
window->null.height = height;
|
||||
_glfwInputWindowSize(window, width, height);
|
||||
_glfwInputFramebufferSize(window, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwSetWindowSizeLimitsNull(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight)
|
||||
{
|
||||
int width = window->null.width;
|
||||
int height = window->null.height;
|
||||
applySizeLimits(window, &width, &height);
|
||||
_glfwSetWindowSizeNull(window, width, height);
|
||||
}
|
||||
|
||||
void _glfwSetWindowAspectRatioNull(_GLFWwindow* window, int n, int d)
|
||||
{
|
||||
int width = window->null.width;
|
||||
int height = window->null.height;
|
||||
applySizeLimits(window, &width, &height);
|
||||
_glfwSetWindowSizeNull(window, width, height);
|
||||
}
|
||||
|
||||
void _glfwGetFramebufferSizeNull(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->null.width;
|
||||
if (height)
|
||||
*height = window->null.height;
|
||||
}
|
||||
|
||||
void _glfwGetWindowFrameSizeNull(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom)
|
||||
{
|
||||
if (window->null.decorated && !window->monitor)
|
||||
{
|
||||
if (left)
|
||||
*left = 1;
|
||||
if (top)
|
||||
*top = 10;
|
||||
if (right)
|
||||
*right = 1;
|
||||
if (bottom)
|
||||
*bottom = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left)
|
||||
*left = 0;
|
||||
if (top)
|
||||
*top = 0;
|
||||
if (right)
|
||||
*right = 0;
|
||||
if (bottom)
|
||||
*bottom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
void _glfwIconifyWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.null.focusedWindow == window)
|
||||
{
|
||||
_glfw.null.focusedWindow = NULL;
|
||||
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||
}
|
||||
|
||||
if (!window->null.iconified)
|
||||
{
|
||||
window->null.iconified = GLFW_TRUE;
|
||||
_glfwInputWindowIconify(window, GLFW_TRUE);
|
||||
|
||||
if (window->monitor)
|
||||
releaseMonitor(window);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwRestoreWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
if (window->null.iconified)
|
||||
{
|
||||
window->null.iconified = GLFW_FALSE;
|
||||
_glfwInputWindowIconify(window, GLFW_FALSE);
|
||||
|
||||
if (window->monitor)
|
||||
acquireMonitor(window);
|
||||
}
|
||||
else if (window->null.maximized)
|
||||
{
|
||||
window->null.maximized = GLFW_FALSE;
|
||||
_glfwInputWindowMaximize(window, GLFW_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwMaximizeWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
if (!window->null.maximized)
|
||||
{
|
||||
window->null.maximized = GLFW_TRUE;
|
||||
_glfwInputWindowMaximize(window, GLFW_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window)
|
||||
{
|
||||
return window->null.maximized;
|
||||
}
|
||||
|
||||
GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window)
|
||||
{
|
||||
return _glfw.null.xcursor >= window->null.xpos &&
|
||||
_glfw.null.ycursor >= window->null.ypos &&
|
||||
_glfw.null.xcursor <= window->null.xpos + window->null.width - 1 &&
|
||||
_glfw.null.ycursor <= window->null.ypos + window->null.height - 1;
|
||||
}
|
||||
|
||||
GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window)
|
||||
{
|
||||
return window->null.transparent;
|
||||
}
|
||||
|
||||
void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
window->null.resizable = enabled;
|
||||
}
|
||||
|
||||
void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
window->null.decorated = enabled;
|
||||
}
|
||||
|
||||
void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
window->null.floating = enabled;
|
||||
}
|
||||
|
||||
void _glfwSetWindowMousePassthroughNull(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
float _glfwGetWindowOpacityNull(_GLFWwindow* window)
|
||||
{
|
||||
return window->null.opacity;
|
||||
}
|
||||
|
||||
void _glfwSetWindowOpacityNull(_GLFWwindow* window, float opacity)
|
||||
{
|
||||
window->null.opacity = opacity;
|
||||
}
|
||||
|
||||
void _glfwSetRawMouseMotionNull(_GLFWwindow *window, GLFWbool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
GLFWbool _glfwRawMouseMotionSupportedNull(void)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwShowWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
window->null.visible = GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwRequestWindowAttentionNull(_GLFWwindow* window)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwHideWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.null.focusedWindow == window)
|
||||
{
|
||||
_glfw.null.focusedWindow = NULL;
|
||||
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||
}
|
||||
|
||||
window->null.visible = GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwFocusWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
_GLFWwindow* previous;
|
||||
|
||||
if (_glfw.null.focusedWindow == window)
|
||||
return;
|
||||
|
||||
if (!window->null.visible)
|
||||
return;
|
||||
|
||||
previous = _glfw.null.focusedWindow;
|
||||
_glfw.null.focusedWindow = window;
|
||||
|
||||
if (previous)
|
||||
{
|
||||
_glfwInputWindowFocus(previous, GLFW_FALSE);
|
||||
if (previous->monitor && previous->autoIconify)
|
||||
_glfwIconifyWindowNull(previous);
|
||||
}
|
||||
|
||||
_glfwInputWindowFocus(window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window)
|
||||
{
|
||||
return _glfw.null.focusedWindow == window;
|
||||
}
|
||||
|
||||
GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window)
|
||||
{
|
||||
return window->null.iconified;
|
||||
}
|
||||
|
||||
GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window)
|
||||
{
|
||||
return window->null.visible;
|
||||
}
|
||||
|
||||
void _glfwPollEventsNull(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwWaitEventsNull(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwWaitEventsTimeoutNull(double timeout)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPostEmptyEventNull(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = _glfw.null.xcursor - window->null.xpos;
|
||||
if (ypos)
|
||||
*ypos = _glfw.null.ycursor - window->null.ypos;
|
||||
}
|
||||
|
||||
void _glfwSetCursorPosNull(_GLFWwindow* window, double x, double y)
|
||||
{
|
||||
_glfw.null.xcursor = window->null.xpos + (int) x;
|
||||
_glfw.null.ycursor = window->null.ypos + (int) y;
|
||||
}
|
||||
|
||||
void _glfwSetCursorModeNull(_GLFWwindow* window, int mode)
|
||||
{
|
||||
}
|
||||
|
||||
GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwDestroyCursorNull(_GLFWcursor* cursor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwSetClipboardStringNull(const char* string)
|
||||
{
|
||||
char* copy = _glfw_strdup(string);
|
||||
_glfw_free(_glfw.null.clipboardString);
|
||||
_glfw.null.clipboardString = copy;
|
||||
}
|
||||
|
||||
const char* _glfwGetClipboardStringNull(void)
|
||||
{
|
||||
return _glfw.null.clipboardString;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformNull(EGLint** attribs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* _glfwGetScancodeNameNull(int scancode)
|
||||
{
|
||||
if (scancode < GLFW_NULL_SC_FIRST || scancode > GLFW_NULL_SC_LAST)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (scancode)
|
||||
{
|
||||
case GLFW_NULL_SC_APOSTROPHE:
|
||||
return "'";
|
||||
case GLFW_NULL_SC_COMMA:
|
||||
return ",";
|
||||
case GLFW_NULL_SC_MINUS:
|
||||
case GLFW_NULL_SC_KP_SUBTRACT:
|
||||
return "-";
|
||||
case GLFW_NULL_SC_PERIOD:
|
||||
case GLFW_NULL_SC_KP_DECIMAL:
|
||||
return ".";
|
||||
case GLFW_NULL_SC_SLASH:
|
||||
case GLFW_NULL_SC_KP_DIVIDE:
|
||||
return "/";
|
||||
case GLFW_NULL_SC_SEMICOLON:
|
||||
return ";";
|
||||
case GLFW_NULL_SC_EQUAL:
|
||||
case GLFW_NULL_SC_KP_EQUAL:
|
||||
return "=";
|
||||
case GLFW_NULL_SC_LEFT_BRACKET:
|
||||
return "[";
|
||||
case GLFW_NULL_SC_RIGHT_BRACKET:
|
||||
return "]";
|
||||
case GLFW_NULL_SC_KP_MULTIPLY:
|
||||
return "*";
|
||||
case GLFW_NULL_SC_KP_ADD:
|
||||
return "+";
|
||||
case GLFW_NULL_SC_BACKSLASH:
|
||||
case GLFW_NULL_SC_WORLD_1:
|
||||
case GLFW_NULL_SC_WORLD_2:
|
||||
return "\\";
|
||||
case GLFW_NULL_SC_0:
|
||||
case GLFW_NULL_SC_KP_0:
|
||||
return "0";
|
||||
case GLFW_NULL_SC_1:
|
||||
case GLFW_NULL_SC_KP_1:
|
||||
return "1";
|
||||
case GLFW_NULL_SC_2:
|
||||
case GLFW_NULL_SC_KP_2:
|
||||
return "2";
|
||||
case GLFW_NULL_SC_3:
|
||||
case GLFW_NULL_SC_KP_3:
|
||||
return "3";
|
||||
case GLFW_NULL_SC_4:
|
||||
case GLFW_NULL_SC_KP_4:
|
||||
return "4";
|
||||
case GLFW_NULL_SC_5:
|
||||
case GLFW_NULL_SC_KP_5:
|
||||
return "5";
|
||||
case GLFW_NULL_SC_6:
|
||||
case GLFW_NULL_SC_KP_6:
|
||||
return "6";
|
||||
case GLFW_NULL_SC_7:
|
||||
case GLFW_NULL_SC_KP_7:
|
||||
return "7";
|
||||
case GLFW_NULL_SC_8:
|
||||
case GLFW_NULL_SC_KP_8:
|
||||
return "8";
|
||||
case GLFW_NULL_SC_9:
|
||||
case GLFW_NULL_SC_KP_9:
|
||||
return "9";
|
||||
case GLFW_NULL_SC_A:
|
||||
return "a";
|
||||
case GLFW_NULL_SC_B:
|
||||
return "b";
|
||||
case GLFW_NULL_SC_C:
|
||||
return "c";
|
||||
case GLFW_NULL_SC_D:
|
||||
return "d";
|
||||
case GLFW_NULL_SC_E:
|
||||
return "e";
|
||||
case GLFW_NULL_SC_F:
|
||||
return "f";
|
||||
case GLFW_NULL_SC_G:
|
||||
return "g";
|
||||
case GLFW_NULL_SC_H:
|
||||
return "h";
|
||||
case GLFW_NULL_SC_I:
|
||||
return "i";
|
||||
case GLFW_NULL_SC_J:
|
||||
return "j";
|
||||
case GLFW_NULL_SC_K:
|
||||
return "k";
|
||||
case GLFW_NULL_SC_L:
|
||||
return "l";
|
||||
case GLFW_NULL_SC_M:
|
||||
return "m";
|
||||
case GLFW_NULL_SC_N:
|
||||
return "n";
|
||||
case GLFW_NULL_SC_O:
|
||||
return "o";
|
||||
case GLFW_NULL_SC_P:
|
||||
return "p";
|
||||
case GLFW_NULL_SC_Q:
|
||||
return "q";
|
||||
case GLFW_NULL_SC_R:
|
||||
return "r";
|
||||
case GLFW_NULL_SC_S:
|
||||
return "s";
|
||||
case GLFW_NULL_SC_T:
|
||||
return "t";
|
||||
case GLFW_NULL_SC_U:
|
||||
return "u";
|
||||
case GLFW_NULL_SC_V:
|
||||
return "v";
|
||||
case GLFW_NULL_SC_W:
|
||||
return "w";
|
||||
case GLFW_NULL_SC_X:
|
||||
return "x";
|
||||
case GLFW_NULL_SC_Y:
|
||||
return "y";
|
||||
case GLFW_NULL_SC_Z:
|
||||
return "z";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int _glfwGetKeyScancodeNull(int key)
|
||||
{
|
||||
return _glfw.null.scancodes[key];
|
||||
}
|
||||
|
||||
void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
|
||||
{
|
||||
}
|
||||
|
||||
GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
VkResult _glfwCreateWindowSurfaceNull(VkInstance instance,
|
||||
_GLFWwindow* window,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface)
|
||||
{
|
||||
// This seems like the most appropriate error to return here
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 OSMesa - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
// Copyright (c) 2016-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
|
||||
static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
int width, height;
|
||||
_glfw.platform.getFramebufferSize(window, &width, &height);
|
||||
|
||||
// Check to see if we need to allocate a new buffer
|
||||
if ((window->context.osmesa.buffer == NULL) ||
|
||||
(width != window->context.osmesa.width) ||
|
||||
(height != window->context.osmesa.height))
|
||||
{
|
||||
_glfw_free(window->context.osmesa.buffer);
|
||||
|
||||
// Allocate the new buffer (width * height * 8-bit RGBA)
|
||||
window->context.osmesa.buffer = _glfw_calloc(4, (size_t) width * height);
|
||||
window->context.osmesa.width = width;
|
||||
window->context.osmesa.height = height;
|
||||
}
|
||||
|
||||
if (!OSMesaMakeCurrent(window->context.osmesa.handle,
|
||||
window->context.osmesa.buffer,
|
||||
GL_UNSIGNED_BYTE,
|
||||
width, height))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to make context current");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressOSMesa(const char* procname)
|
||||
{
|
||||
return (GLFWglproc) OSMesaGetProcAddress(procname);
|
||||
}
|
||||
|
||||
static void destroyContextOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.osmesa.handle)
|
||||
{
|
||||
OSMesaDestroyContext(window->context.osmesa.handle);
|
||||
window->context.osmesa.handle = NULL;
|
||||
}
|
||||
|
||||
if (window->context.osmesa.buffer)
|
||||
{
|
||||
_glfw_free(window->context.osmesa.buffer);
|
||||
window->context.osmesa.width = 0;
|
||||
window->context.osmesa.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffersOSMesa(_GLFWwindow* window)
|
||||
{
|
||||
// No double buffering on OSMesa
|
||||
}
|
||||
|
||||
static void swapIntervalOSMesa(int interval)
|
||||
{
|
||||
// No swap interval on OSMesa
|
||||
}
|
||||
|
||||
static int extensionSupportedOSMesa(const char* extension)
|
||||
{
|
||||
// OSMesa does not have extensions
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitOSMesa(void)
|
||||
{
|
||||
int i;
|
||||
const char* sonames[] =
|
||||
{
|
||||
#if defined(_GLFW_OSMESA_LIBRARY)
|
||||
_GLFW_OSMESA_LIBRARY,
|
||||
#elif defined(_WIN32)
|
||||
"libOSMesa.dll",
|
||||
"OSMesa.dll",
|
||||
#elif defined(__APPLE__)
|
||||
"libOSMesa.8.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libOSMesa-8.so",
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libOSMesa.so",
|
||||
#else
|
||||
"libOSMesa.so.8",
|
||||
"libOSMesa.so.6",
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
if (_glfw.osmesa.handle)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; sonames[i]; i++)
|
||||
{
|
||||
_glfw.osmesa.handle = _glfwPlatformLoadModule(sonames[i]);
|
||||
if (_glfw.osmesa.handle)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_glfw.osmesa.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "OSMesa: Library not found");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.osmesa.CreateContextExt = (PFN_OSMesaCreateContextExt)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextExt");
|
||||
_glfw.osmesa.CreateContextAttribs = (PFN_OSMesaCreateContextAttribs)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaCreateContextAttribs");
|
||||
_glfw.osmesa.DestroyContext = (PFN_OSMesaDestroyContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaDestroyContext");
|
||||
_glfw.osmesa.MakeCurrent = (PFN_OSMesaMakeCurrent)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaMakeCurrent");
|
||||
_glfw.osmesa.GetColorBuffer = (PFN_OSMesaGetColorBuffer)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetColorBuffer");
|
||||
_glfw.osmesa.GetDepthBuffer = (PFN_OSMesaGetDepthBuffer)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetDepthBuffer");
|
||||
_glfw.osmesa.GetProcAddress = (PFN_OSMesaGetProcAddress)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.osmesa.handle, "OSMesaGetProcAddress");
|
||||
|
||||
if (!_glfw.osmesa.CreateContextExt ||
|
||||
!_glfw.osmesa.DestroyContext ||
|
||||
!_glfw.osmesa.MakeCurrent ||
|
||||
!_glfw.osmesa.GetColorBuffer ||
|
||||
!_glfw.osmesa.GetDepthBuffer ||
|
||||
!_glfw.osmesa.GetProcAddress)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to load required entry points");
|
||||
|
||||
_glfwTerminateOSMesa();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateOSMesa(void)
|
||||
{
|
||||
if (_glfw.osmesa.handle)
|
||||
{
|
||||
_glfwPlatformFreeModule(_glfw.osmesa.handle);
|
||||
_glfw.osmesa.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
OSMesaContext share = NULL;
|
||||
const int accumBits = fbconfig->accumRedBits +
|
||||
fbconfig->accumGreenBits +
|
||||
fbconfig->accumBlueBits +
|
||||
fbconfig->accumAlphaBits;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"OSMesa: OpenGL ES is not available on OSMesa");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.osmesa.handle;
|
||||
|
||||
if (OSMesaCreateContextAttribs)
|
||||
{
|
||||
int index = 0, attribs[40];
|
||||
|
||||
SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA);
|
||||
SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits);
|
||||
SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
|
||||
SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits);
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
{
|
||||
SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
|
||||
}
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
{
|
||||
SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
|
||||
SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: Forward-compatible contexts not supported");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
SET_ATTRIB(0, 0);
|
||||
|
||||
window->context.osmesa.handle =
|
||||
OSMesaCreateContextAttribs(attribs, share);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: OpenGL profiles unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.osmesa.handle =
|
||||
OSMesaCreateContextExt(OSMESA_RGBA,
|
||||
fbconfig->depthBits,
|
||||
fbconfig->stencilBits,
|
||||
accumBits,
|
||||
share);
|
||||
}
|
||||
|
||||
if (window->context.osmesa.handle == NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: Failed to create context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentOSMesa;
|
||||
window->context.swapBuffers = swapBuffersOSMesa;
|
||||
window->context.swapInterval = swapIntervalOSMesa;
|
||||
window->context.extensionSupported = extensionSupportedOSMesa;
|
||||
window->context.getProcAddress = getProcAddressOSMesa;
|
||||
window->context.destroy = destroyContextOSMesa;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef SET_ATTRIB
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI int glfwGetOSMesaColorBuffer(GLFWwindow* handle, int* width,
|
||||
int* height, int* format, void** buffer)
|
||||
{
|
||||
void* mesaBuffer;
|
||||
GLint mesaWidth, mesaHeight, mesaFormat;
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (window->context.source != GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!OSMesaGetColorBuffer(window->context.osmesa.handle,
|
||||
&mesaWidth, &mesaHeight,
|
||||
&mesaFormat, &mesaBuffer))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to retrieve color buffer");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = mesaWidth;
|
||||
if (height)
|
||||
*height = mesaHeight;
|
||||
if (format)
|
||||
*format = mesaFormat;
|
||||
if (buffer)
|
||||
*buffer = mesaBuffer;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
SSCAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* handle,
|
||||
int* width, int* height,
|
||||
int* bytesPerValue,
|
||||
void** buffer)
|
||||
{
|
||||
void* mesaBuffer;
|
||||
GLint mesaWidth, mesaHeight, mesaBytes;
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (window->context.source != GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!OSMesaGetDepthBuffer(window->context.osmesa.handle,
|
||||
&mesaWidth, &mesaHeight,
|
||||
&mesaBytes, &mesaBuffer))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"OSMesa: Failed to retrieve depth buffer");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = mesaWidth;
|
||||
if (height)
|
||||
*height = mesaHeight;
|
||||
if (bytesPerValue)
|
||||
*bytesPerValue = mesaBytes;
|
||||
if (buffer)
|
||||
*buffer = mesaBuffer;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
SSCAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.source != GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.osmesa.handle;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
// These construct a string literal from individual numeric constants
|
||||
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
|
||||
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const struct
|
||||
{
|
||||
int ID;
|
||||
GLFWbool (*connect)(int,_GLFWplatform*);
|
||||
} supportedPlatforms[] =
|
||||
{
|
||||
#if defined(_GLFW_WIN32)
|
||||
{ GLFW_PLATFORM_WIN32, _glfwConnectWin32 },
|
||||
#endif
|
||||
#if defined(_GLFW_COCOA)
|
||||
{ GLFW_PLATFORM_COCOA, _glfwConnectCocoa },
|
||||
#endif
|
||||
#if defined(_GLFW_X11)
|
||||
{ GLFW_PLATFORM_X11, _glfwConnectX11 },
|
||||
#endif
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
{ GLFW_PLATFORM_WAYLAND, _glfwConnectWayland },
|
||||
#endif
|
||||
};
|
||||
|
||||
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
|
||||
{
|
||||
const size_t count = sizeof(supportedPlatforms) / sizeof(supportedPlatforms[0]);
|
||||
size_t i;
|
||||
|
||||
if (desiredID != GLFW_ANY_PLATFORM &&
|
||||
desiredID != GLFW_PLATFORM_WIN32 &&
|
||||
desiredID != GLFW_PLATFORM_COCOA &&
|
||||
desiredID != GLFW_PLATFORM_WAYLAND &&
|
||||
desiredID != GLFW_PLATFORM_X11 &&
|
||||
desiredID != GLFW_PLATFORM_NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", desiredID);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// Only allow the Null platform if specifically requested
|
||||
if (desiredID == GLFW_PLATFORM_NULL)
|
||||
return _glfwConnectNull(desiredID, platform);
|
||||
else if (count == 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "This binary only supports the Null platform");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (desiredID == GLFW_ANY_PLATFORM)
|
||||
{
|
||||
// If there is exactly one platform available for auto-selection, let it emit the
|
||||
// error on failure as the platform-specific error description may be more helpful
|
||||
if (count == 1)
|
||||
return supportedPlatforms[0].connect(supportedPlatforms[0].ID, platform);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (supportedPlatforms[i].connect(desiredID, platform))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "Failed to detect any supported platform");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (supportedPlatforms[i].ID == desiredID)
|
||||
return supportedPlatforms[i].connect(desiredID, platform);
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_PLATFORM_UNAVAILABLE, "The requested platform is not supported");
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI int glfwGetPlatform(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||
return _glfw.platform.platformID;
|
||||
}
|
||||
|
||||
SSCAPI int glfwPlatformSupported(int platformID)
|
||||
{
|
||||
const size_t count = sizeof(supportedPlatforms) / sizeof(supportedPlatforms[0]);
|
||||
size_t i;
|
||||
|
||||
if (platformID != GLFW_PLATFORM_WIN32 &&
|
||||
platformID != GLFW_PLATFORM_COCOA &&
|
||||
platformID != GLFW_PLATFORM_WAYLAND &&
|
||||
platformID != GLFW_PLATFORM_X11 &&
|
||||
platformID != GLFW_PLATFORM_NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", platformID);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (platformID == GLFW_PLATFORM_NULL)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (platformID == supportedPlatforms[i].ID)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
SSCAPI const char* glfwGetVersionString(void)
|
||||
{
|
||||
return _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR,
|
||||
GLFW_VERSION_MINOR,
|
||||
GLFW_VERSION_REVISION)
|
||||
#if defined(_GLFW_WIN32)
|
||||
" Win32 WGL"
|
||||
#endif
|
||||
#if defined(_GLFW_COCOA)
|
||||
" Cocoa NSGL"
|
||||
#endif
|
||||
#if defined(_GLFW_WAYLAND)
|
||||
" Wayland"
|
||||
#endif
|
||||
#if defined(_GLFW_X11)
|
||||
" X11 GLX"
|
||||
#endif
|
||||
" Null"
|
||||
" EGL"
|
||||
" OSMesa"
|
||||
#if defined(__MINGW64_VERSION_MAJOR)
|
||||
" MinGW-w64"
|
||||
#elif defined(__MINGW32__)
|
||||
" MinGW"
|
||||
#elif defined(_MSC_VER)
|
||||
" VisualC"
|
||||
#endif
|
||||
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
|
||||
" hybrid-GPU"
|
||||
#endif
|
||||
#if defined(_POSIX_MONOTONIC_CLOCK)
|
||||
" monotonic"
|
||||
#endif
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
#if defined(_WIN32)
|
||||
" DLL"
|
||||
#elif defined(__APPLE__)
|
||||
" dynamic"
|
||||
#else
|
||||
" shared"
|
||||
#endif
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _GLFW_FIND_LOADER 1
|
||||
#define _GLFW_REQUIRE_LOADER 2
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitVulkan(int mode)
|
||||
{
|
||||
VkResult err;
|
||||
VkExtensionProperties* ep;
|
||||
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
|
||||
uint32_t i, count;
|
||||
|
||||
if (_glfw.vk.available)
|
||||
return GLFW_TRUE;
|
||||
|
||||
if (_glfw.hints.init.vulkanLoader)
|
||||
_glfw.vk.GetInstanceProcAddr = _glfw.hints.init.vulkanLoader;
|
||||
else
|
||||
{
|
||||
#if defined(_GLFW_VULKAN_LIBRARY)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY);
|
||||
#elif defined(_GLFW_WIN32)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll");
|
||||
#elif defined(_GLFW_COCOA)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
|
||||
if (!_glfw.vk.handle)
|
||||
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
|
||||
#else
|
||||
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");
|
||||
#endif
|
||||
if (!_glfw.vk.handle)
|
||||
{
|
||||
if (mode == _GLFW_REQUIRE_LOADER)
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found");
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.vk.handle, "vkGetInstanceProcAddr");
|
||||
if (!_glfw.vk.GetInstanceProcAddr)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Loader does not export vkGetInstanceProcAddr");
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
|
||||
vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
|
||||
if (!vkEnumerateInstanceExtensionProperties)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
|
||||
if (err)
|
||||
{
|
||||
// NOTE: This happens on systems with a loader but without any Vulkan ICD
|
||||
if (mode == _GLFW_REQUIRE_LOADER)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to query instance extension count: %s",
|
||||
_glfwGetVulkanResultString(err));
|
||||
}
|
||||
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
ep = _glfw_calloc(count, sizeof(VkExtensionProperties));
|
||||
|
||||
err = vkEnumerateInstanceExtensionProperties(NULL, &count, ep);
|
||||
if (err)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Failed to query instance extensions: %s",
|
||||
_glfwGetVulkanResultString(err));
|
||||
|
||||
_glfw_free(ep);
|
||||
_glfwTerminateVulkan();
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (strcmp(ep[i].extensionName, "VK_KHR_surface") == 0)
|
||||
_glfw.vk.KHR_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_win32_surface") == 0)
|
||||
_glfw.vk.KHR_win32_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_MVK_macos_surface") == 0)
|
||||
_glfw.vk.MVK_macos_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_EXT_metal_surface") == 0)
|
||||
_glfw.vk.EXT_metal_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_xlib_surface") == 0)
|
||||
_glfw.vk.KHR_xlib_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_xcb_surface") == 0)
|
||||
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
|
||||
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
|
||||
}
|
||||
|
||||
_glfw_free(ep);
|
||||
|
||||
_glfw.vk.available = GLFW_TRUE;
|
||||
|
||||
_glfw.platform.getRequiredInstanceExtensions(_glfw.vk.extensions);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateVulkan(void)
|
||||
{
|
||||
if (_glfw.vk.handle)
|
||||
_glfwPlatformFreeModule(_glfw.vk.handle);
|
||||
}
|
||||
|
||||
const char* _glfwGetVulkanResultString(VkResult result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case VK_SUCCESS:
|
||||
return "Success";
|
||||
case VK_NOT_READY:
|
||||
return "A fence or query has not yet completed";
|
||||
case VK_TIMEOUT:
|
||||
return "A wait operation has not completed in the specified time";
|
||||
case VK_EVENT_SET:
|
||||
return "An event is signaled";
|
||||
case VK_EVENT_RESET:
|
||||
return "An event is unsignaled";
|
||||
case VK_INCOMPLETE:
|
||||
return "A return array was too small for the result";
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
return "A host memory allocation has failed";
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||
return "A device memory allocation has failed";
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||
case VK_ERROR_DEVICE_LOST:
|
||||
return "The logical or physical device has been lost";
|
||||
case VK_ERROR_MEMORY_MAP_FAILED:
|
||||
return "Mapping of a memory object has failed";
|
||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||
return "A requested layer is not present or could not be loaded";
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
return "A requested extension is not supported";
|
||||
case VK_ERROR_FEATURE_NOT_PRESENT:
|
||||
return "A requested feature is not supported";
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||
case VK_ERROR_TOO_MANY_OBJECTS:
|
||||
return "Too many objects of the type have already been created";
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
||||
return "A requested format is not supported on this device";
|
||||
case VK_ERROR_SURFACE_LOST_KHR:
|
||||
return "A surface is no longer available";
|
||||
case VK_SUBOPTIMAL_KHR:
|
||||
return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||
return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
||||
return "The display used by a swapchain does not use the same presentable image layout";
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||
case VK_ERROR_VALIDATION_FAILED_EXT:
|
||||
return "A validation layer found an error";
|
||||
default:
|
||||
return "ERROR: UNKNOWN VULKAN ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW public API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI int glfwVulkanSupported(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
return _glfwInitVulkan(_GLFW_FIND_LOADER);
|
||||
}
|
||||
|
||||
SSCAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
|
||||
{
|
||||
assert(count != NULL);
|
||||
|
||||
*count = 0;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return NULL;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
return NULL;
|
||||
|
||||
*count = 2;
|
||||
return (const char**) _glfw.vk.extensions;
|
||||
}
|
||||
|
||||
SSCAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
|
||||
const char* procname)
|
||||
{
|
||||
GLFWvkproc proc;
|
||||
assert(procname != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return NULL;
|
||||
|
||||
// NOTE: Vulkan 1.0 and 1.1 vkGetInstanceProcAddr cannot return itself
|
||||
if (strcmp(procname, "vkGetInstanceProcAddr") == 0)
|
||||
return (GLFWvkproc) vkGetInstanceProcAddr;
|
||||
|
||||
proc = (GLFWvkproc) vkGetInstanceProcAddr(instance, procname);
|
||||
if (!proc)
|
||||
{
|
||||
if (_glfw.vk.handle)
|
||||
proc = (GLFWvkproc) _glfwPlatformGetModuleSymbol(_glfw.vk.handle, procname);
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
SSCAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
{
|
||||
assert(instance != VK_NULL_HANDLE);
|
||||
assert(device != VK_NULL_HANDLE);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Window surface creation extensions not found");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return _glfw.platform.getPhysicalDevicePresentationSupport(instance,
|
||||
device,
|
||||
queuefamily);
|
||||
}
|
||||
|
||||
SSCAPI VkResult glfwCreateWindowSurface(VkInstance instance,
|
||||
GLFWwindow* handle,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(instance != VK_NULL_HANDLE);
|
||||
assert(window != NULL);
|
||||
assert(surface != NULL);
|
||||
|
||||
*surface = VK_NULL_HANDLE;
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
|
||||
|
||||
if (!_glfwInitVulkan(_GLFW_REQUIRE_LOADER))
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
|
||||
if (!_glfw.vk.extensions[0])
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Vulkan: Window surface creation extensions not found");
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API");
|
||||
return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
|
||||
}
|
||||
|
||||
return _glfw.platform.createWindowSurface(instance, window, allocator, surface);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,782 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 WGL - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Return the value corresponding to the specified attribute
|
||||
//
|
||||
static int findPixelFormatAttribValueWGL(const int* attribs,
|
||||
int attribCount,
|
||||
const int* values,
|
||||
int attrib)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < attribCount; i++)
|
||||
{
|
||||
if (attribs[i] == attrib)
|
||||
return values[i];
|
||||
}
|
||||
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Unknown pixel format attribute requested");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ADD_ATTRIB(a) \
|
||||
{ \
|
||||
assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[attribCount++] = a; \
|
||||
}
|
||||
#define FIND_ATTRIB_VALUE(a) \
|
||||
findPixelFormatAttribValueWGL(attribs, attribCount, values, a)
|
||||
|
||||
// Return a list of available and usable framebuffer configs
|
||||
//
|
||||
static int choosePixelFormatWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
_GLFWfbconfig* usableConfigs;
|
||||
const _GLFWfbconfig* closest;
|
||||
int i, pixelFormat, nativeCount, usableCount = 0, attribCount = 0;
|
||||
int attribs[40];
|
||||
int values[sizeof(attribs) / sizeof(attribs[0])];
|
||||
|
||||
nativeCount = DescribePixelFormat(window->context.wgl.dc,
|
||||
1,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
NULL);
|
||||
|
||||
if (_glfw.wgl.ARB_pixel_format)
|
||||
{
|
||||
ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB);
|
||||
ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB);
|
||||
ADD_ATTRIB(WGL_PIXEL_TYPE_ARB);
|
||||
ADD_ATTRIB(WGL_ACCELERATION_ARB);
|
||||
ADD_ATTRIB(WGL_RED_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_RED_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_GREEN_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_GREEN_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_BLUE_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_BLUE_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_ALPHA_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB);
|
||||
ADD_ATTRIB(WGL_DEPTH_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_STENCIL_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
ADD_ATTRIB(WGL_AUX_BUFFERS_ARB);
|
||||
ADD_ATTRIB(WGL_STEREO_ARB);
|
||||
ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB);
|
||||
|
||||
if (_glfw.wgl.ARB_multisample)
|
||||
ADD_ATTRIB(WGL_SAMPLES_ARB);
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
|
||||
ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_glfw.wgl.EXT_colorspace)
|
||||
ADD_ATTRIB(WGL_COLORSPACE_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
|
||||
|
||||
for (i = 0; i < nativeCount; i++)
|
||||
{
|
||||
_GLFWfbconfig* u = usableConfigs + usableCount;
|
||||
pixelFormat = i + 1;
|
||||
|
||||
if (_glfw.wgl.ARB_pixel_format)
|
||||
{
|
||||
// Get pixel format attributes through "modern" extension
|
||||
|
||||
if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
|
||||
pixelFormat, 0,
|
||||
attribCount,
|
||||
attribs, values))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve pixel format attributes");
|
||||
|
||||
_glfw_free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) ||
|
||||
!FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
|
||||
continue;
|
||||
|
||||
if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
|
||||
continue;
|
||||
|
||||
if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
|
||||
continue;
|
||||
|
||||
u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB);
|
||||
u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB);
|
||||
u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB);
|
||||
u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB);
|
||||
|
||||
u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB);
|
||||
u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB);
|
||||
|
||||
u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB);
|
||||
u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB);
|
||||
u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB);
|
||||
u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB);
|
||||
|
||||
u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB);
|
||||
|
||||
if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB))
|
||||
u->stereo = GLFW_TRUE;
|
||||
|
||||
if (_glfw.wgl.ARB_multisample)
|
||||
u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB);
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (_glfw.wgl.ARB_framebuffer_sRGB ||
|
||||
_glfw.wgl.EXT_framebuffer_sRGB)
|
||||
{
|
||||
if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
|
||||
u->sRGB = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_glfw.wgl.EXT_colorspace)
|
||||
{
|
||||
if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
|
||||
u->sRGB = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get pixel format attributes through legacy PFDs
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||
pixelFormat,
|
||||
sizeof(PIXELFORMATDESCRIPTOR),
|
||||
&pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to describe pixel format");
|
||||
|
||||
_glfw_free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
|
||||
!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
|
||||
(pfd.dwFlags & PFD_GENERIC_FORMAT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pfd.iPixelType != PFD_TYPE_RGBA)
|
||||
continue;
|
||||
|
||||
if (!!(pfd.dwFlags & PFD_DOUBLEBUFFER) != fbconfig->doublebuffer)
|
||||
continue;
|
||||
|
||||
u->redBits = pfd.cRedBits;
|
||||
u->greenBits = pfd.cGreenBits;
|
||||
u->blueBits = pfd.cBlueBits;
|
||||
u->alphaBits = pfd.cAlphaBits;
|
||||
|
||||
u->depthBits = pfd.cDepthBits;
|
||||
u->stencilBits = pfd.cStencilBits;
|
||||
|
||||
u->accumRedBits = pfd.cAccumRedBits;
|
||||
u->accumGreenBits = pfd.cAccumGreenBits;
|
||||
u->accumBlueBits = pfd.cAccumBlueBits;
|
||||
u->accumAlphaBits = pfd.cAccumAlphaBits;
|
||||
|
||||
u->auxBuffers = pfd.cAuxBuffers;
|
||||
|
||||
if (pfd.dwFlags & PFD_STEREO)
|
||||
u->stereo = GLFW_TRUE;
|
||||
}
|
||||
|
||||
u->handle = pixelFormat;
|
||||
usableCount++;
|
||||
}
|
||||
|
||||
if (!usableCount)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"WGL: The driver does not appear to support OpenGL");
|
||||
|
||||
_glfw_free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
|
||||
if (!closest)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"WGL: Failed to find a suitable pixel format");
|
||||
|
||||
_glfw_free(usableConfigs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pixelFormat = (int) closest->handle;
|
||||
_glfw_free(usableConfigs);
|
||||
|
||||
return pixelFormat;
|
||||
}
|
||||
|
||||
#undef ADD_ATTRIB
|
||||
#undef FIND_ATTRIB_VALUE
|
||||
|
||||
static void makeContextCurrentWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window)
|
||||
{
|
||||
if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, window);
|
||||
else
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to make context current");
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wglMakeCurrent(NULL, NULL))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to clear current context");
|
||||
}
|
||||
|
||||
_glfwPlatformSetTls(&_glfw.contextSlot, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void swapBuffersWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (!window->monitor)
|
||||
{
|
||||
// HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7
|
||||
if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled = FALSE;
|
||||
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
int count = abs(window->context.wgl.interval);
|
||||
while (count--)
|
||||
DwmFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwapBuffers(window->context.wgl.dc);
|
||||
}
|
||||
|
||||
static void swapIntervalWGL(int interval)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
|
||||
window->context.wgl.interval = interval;
|
||||
|
||||
if (!window->monitor)
|
||||
{
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled on Windows
|
||||
// Vista and 7 to avoid interfering with DWM vsync
|
||||
if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled = FALSE;
|
||||
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.EXT_swap_control)
|
||||
wglSwapIntervalEXT(interval);
|
||||
}
|
||||
|
||||
static int extensionSupportedWGL(const char* extension)
|
||||
{
|
||||
const char* extensions = NULL;
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringARB)
|
||||
extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
|
||||
else if (_glfw.wgl.GetExtensionsStringEXT)
|
||||
extensions = wglGetExtensionsStringEXT();
|
||||
|
||||
if (!extensions)
|
||||
return GLFW_FALSE;
|
||||
|
||||
return _glfwStringInExtensionString(extension, extensions);
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressWGL(const char* procname)
|
||||
{
|
||||
const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
|
||||
if (proc)
|
||||
return proc;
|
||||
|
||||
return (GLFWglproc) _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, procname);
|
||||
}
|
||||
|
||||
static void destroyContextWGL(_GLFWwindow* window)
|
||||
{
|
||||
if (window->context.wgl.handle)
|
||||
{
|
||||
wglDeleteContext(window->context.wgl.handle);
|
||||
window->context.wgl.handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize WGL
|
||||
//
|
||||
GLFWbool _glfwInitWGL(void)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HGLRC prc, rc;
|
||||
HDC pdc, dc;
|
||||
|
||||
if (_glfw.wgl.instance)
|
||||
return GLFW_TRUE;
|
||||
|
||||
_glfw.wgl.instance = _glfwPlatformLoadModule("opengl32.dll");
|
||||
if (!_glfw.wgl.instance)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to load opengl32.dll");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.wgl.CreateContext = (PFN_wglCreateContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglCreateContext");
|
||||
_glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglDeleteContext");
|
||||
_glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetProcAddress");
|
||||
_glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentDC");
|
||||
_glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentContext");
|
||||
_glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglMakeCurrent");
|
||||
_glfw.wgl.ShareLists = (PFN_wglShareLists)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglShareLists");
|
||||
|
||||
// NOTE: A dummy context has to be created for opengl32.dll to load the
|
||||
// OpenGL ICD, from which we can then query WGL extensions
|
||||
// NOTE: This code will accept the Microsoft GDI ICD; accelerated context
|
||||
// creation failure occurs during manual pixel format enumeration
|
||||
|
||||
dc = GetDC(_glfw.win32.helperWindowHandle);
|
||||
|
||||
ZeroMemory(&pfd, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
|
||||
if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to set pixel format for dummy context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
rc = wglCreateContext(dc);
|
||||
if (!rc)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to create dummy context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
pdc = wglGetCurrentDC();
|
||||
prc = wglGetCurrentContext();
|
||||
|
||||
if (!wglMakeCurrent(dc, rc))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to make dummy context current");
|
||||
wglMakeCurrent(pdc, prc);
|
||||
wglDeleteContext(rc);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// NOTE: Functions must be loaded first as they're needed to retrieve the
|
||||
// extension string that tells us whether the functions are supported
|
||||
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringEXT");
|
||||
_glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
|
||||
wglGetProcAddress("wglGetExtensionsStringARB");
|
||||
_glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
||||
wglGetProcAddress("wglCreateContextAttribsARB");
|
||||
_glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
|
||||
wglGetProcAddress("wglSwapIntervalEXT");
|
||||
_glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
|
||||
wglGetProcAddress("wglGetPixelFormatAttribivARB");
|
||||
|
||||
// NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
|
||||
// checked below as we are already using them
|
||||
_glfw.wgl.ARB_multisample =
|
||||
extensionSupportedWGL("WGL_ARB_multisample");
|
||||
_glfw.wgl.ARB_framebuffer_sRGB =
|
||||
extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
|
||||
_glfw.wgl.EXT_framebuffer_sRGB =
|
||||
extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
|
||||
_glfw.wgl.ARB_create_context =
|
||||
extensionSupportedWGL("WGL_ARB_create_context");
|
||||
_glfw.wgl.ARB_create_context_profile =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_profile");
|
||||
_glfw.wgl.EXT_create_context_es2_profile =
|
||||
extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
|
||||
_glfw.wgl.ARB_create_context_robustness =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_robustness");
|
||||
_glfw.wgl.ARB_create_context_no_error =
|
||||
extensionSupportedWGL("WGL_ARB_create_context_no_error");
|
||||
_glfw.wgl.EXT_swap_control =
|
||||
extensionSupportedWGL("WGL_EXT_swap_control");
|
||||
_glfw.wgl.EXT_colorspace =
|
||||
extensionSupportedWGL("WGL_EXT_colorspace");
|
||||
_glfw.wgl.ARB_pixel_format =
|
||||
extensionSupportedWGL("WGL_ARB_pixel_format");
|
||||
_glfw.wgl.ARB_context_flush_control =
|
||||
extensionSupportedWGL("WGL_ARB_context_flush_control");
|
||||
|
||||
wglMakeCurrent(pdc, prc);
|
||||
wglDeleteContext(rc);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Terminate WGL
|
||||
//
|
||||
void _glfwTerminateWGL(void)
|
||||
{
|
||||
if (_glfw.wgl.instance)
|
||||
_glfwPlatformFreeModule(_glfw.wgl.instance);
|
||||
}
|
||||
|
||||
#define SET_ATTRIB(a, v) \
|
||||
{ \
|
||||
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
|
||||
attribs[index++] = a; \
|
||||
attribs[index++] = v; \
|
||||
}
|
||||
|
||||
// Create the OpenGL or OpenGL ES context
|
||||
//
|
||||
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
int attribs[40];
|
||||
int pixelFormat;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HGLRC share = NULL;
|
||||
|
||||
if (ctxconfig->share)
|
||||
share = ctxconfig->share->context.wgl.handle;
|
||||
|
||||
window->context.wgl.dc = GetDC(window->win32.handle);
|
||||
if (!window->context.wgl.dc)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve DC for window");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig);
|
||||
if (!pixelFormat)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!DescribePixelFormat(window->context.wgl.dc,
|
||||
pixelFormat, sizeof(pfd), &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to retrieve PFD for selected pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to set selected pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->profile)
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_glfw.wgl.ARB_create_context ||
|
||||
!_glfw.wgl.ARB_create_context_profile ||
|
||||
!_glfw.wgl.EXT_create_context_es2_profile)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.ARB_create_context)
|
||||
{
|
||||
int index = 0, mask = 0, flags = 0;
|
||||
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
if (ctxconfig->forward)
|
||||
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
|
||||
mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
|
||||
mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
}
|
||||
else
|
||||
mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
|
||||
|
||||
if (ctxconfig->debug)
|
||||
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
if (ctxconfig->robustness)
|
||||
{
|
||||
if (_glfw.wgl.ARB_create_context_robustness)
|
||||
{
|
||||
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
|
||||
{
|
||||
SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_NO_RESET_NOTIFICATION_ARB);
|
||||
}
|
||||
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
|
||||
{
|
||||
SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
WGL_LOSE_CONTEXT_ON_RESET_ARB);
|
||||
}
|
||||
|
||||
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->release)
|
||||
{
|
||||
if (_glfw.wgl.ARB_context_flush_control)
|
||||
{
|
||||
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
|
||||
{
|
||||
SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
||||
}
|
||||
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
|
||||
{
|
||||
SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
|
||||
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.wgl.ARB_create_context_no_error)
|
||||
SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
|
||||
SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (flags)
|
||||
SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags);
|
||||
|
||||
if (mask)
|
||||
SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
|
||||
|
||||
SET_ATTRIB(0, 0);
|
||||
|
||||
window->context.wgl.handle =
|
||||
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
|
||||
if (!window->context.wgl.handle)
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
|
||||
if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support OpenGL version %i.%i",
|
||||
ctxconfig->major,
|
||||
ctxconfig->minor);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support OpenGL ES version %i.%i",
|
||||
ctxconfig->major,
|
||||
ctxconfig->minor);
|
||||
}
|
||||
}
|
||||
else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Driver does not support the requested OpenGL profile");
|
||||
}
|
||||
else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
|
||||
{
|
||||
_glfwInputError(GLFW_INVALID_VALUE,
|
||||
"WGL: The share context is not compatible with the requested context");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL context");
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL ES context");
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
|
||||
if (!window->context.wgl.handle)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
|
||||
"WGL: Failed to create OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (share)
|
||||
{
|
||||
if (!wglShareLists(share, window->context.wgl.handle))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"WGL: Failed to enable sharing with specified OpenGL context");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window->context.makeCurrent = makeContextCurrentWGL;
|
||||
window->context.swapBuffers = swapBuffersWGL;
|
||||
window->context.swapInterval = swapIntervalWGL;
|
||||
window->context.extensionSupported = extensionSupportedWGL;
|
||||
window->context.getProcAddress = getProcAddressWGL;
|
||||
window->context.destroy = destroyContextWGL;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
#undef SET_ATTRIB
|
||||
|
||||
SSCAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
|
||||
"WGL: Platform not initialized");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (window->context.source != GLFW_NATIVE_CONTEXT_API)
|
||||
{
|
||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window->context.wgl.handle;
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
@@ -0,0 +1,725 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static const GUID _glfw_GUID_DEVINTERFACE_HID =
|
||||
{ 0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30} };
|
||||
|
||||
#define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID
|
||||
|
||||
#if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
|
||||
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
#pragma message("These symbols must be exported by the executable and have no effect in a DLL")
|
||||
#endif
|
||||
|
||||
// Executables (but not DLLs) exporting this symbol with this value will be
|
||||
// automatically directed to the high-performance GPU on Nvidia Optimus systems
|
||||
// with up-to-date drivers
|
||||
//
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||
|
||||
// Executables (but not DLLs) 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)
|
||||
|
||||
|
||||
#endif // _GLFW_BUILD_DLL
|
||||
|
||||
// Load necessary libraries (DLLs)
|
||||
//
|
||||
static GLFWbool loadLibraries(void)
|
||||
{
|
||||
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(const WCHAR*)&_glfw,
|
||||
(HMODULE*)&_glfw.win32.instance))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to retrieve own module handle");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll");
|
||||
if (!_glfw.win32.user32.instance)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to load user32.dll");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDPIAware");
|
||||
_glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
|
||||
_glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
|
||||
_glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext");
|
||||
_glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow");
|
||||
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
|
||||
_glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetSystemMetricsForDpi");
|
||||
|
||||
_glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll");
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
_glfw.win32.dinput8.Create = (PFN_DirectInput8Create)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dinput8.instance, "DirectInput8Create");
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
const char* names[] =
|
||||
{
|
||||
"xinput1_4.dll",
|
||||
"xinput1_3.dll",
|
||||
"xinput9_1_0.dll",
|
||||
"xinput1_2.dll",
|
||||
"xinput1_1.dll",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (i = 0; names[i]; i++)
|
||||
{
|
||||
_glfw.win32.xinput.instance = _glfwPlatformLoadModule(names[i]);
|
||||
if (_glfw.win32.xinput.instance)
|
||||
{
|
||||
_glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetCapabilities");
|
||||
_glfw.win32.xinput.GetState = (PFN_XInputGetState)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.xinput.instance, "XInputGetState");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_glfw.win32.dwmapi.instance = _glfwPlatformLoadModule("dwmapi.dll");
|
||||
if (_glfw.win32.dwmapi.instance)
|
||||
{
|
||||
_glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
|
||||
_glfw.win32.dwmapi.Flush = (PFN_DwmFlush)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmFlush");
|
||||
_glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
|
||||
_glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor");
|
||||
}
|
||||
|
||||
_glfw.win32.shcore.instance = _glfwPlatformLoadModule("shcore.dll");
|
||||
if (_glfw.win32.shcore.instance)
|
||||
{
|
||||
_glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
|
||||
_glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.shcore.instance, "GetDpiForMonitor");
|
||||
}
|
||||
|
||||
_glfw.win32.ntdll.instance = _glfwPlatformLoadModule("ntdll.dll");
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
{
|
||||
_glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Unload used libraries (DLLs)
|
||||
//
|
||||
static void freeLibraries(void)
|
||||
{
|
||||
if (_glfw.win32.xinput.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.xinput.instance);
|
||||
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.dinput8.instance);
|
||||
|
||||
if (_glfw.win32.user32.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.user32.instance);
|
||||
|
||||
if (_glfw.win32.dwmapi.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.dwmapi.instance);
|
||||
|
||||
if (_glfw.win32.shcore.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.shcore.instance);
|
||||
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
{
|
||||
int scancode;
|
||||
|
||||
memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes));
|
||||
memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes));
|
||||
|
||||
_glfw.win32.keycodes[0x00B] = GLFW_KEY_0;
|
||||
_glfw.win32.keycodes[0x002] = GLFW_KEY_1;
|
||||
_glfw.win32.keycodes[0x003] = GLFW_KEY_2;
|
||||
_glfw.win32.keycodes[0x004] = GLFW_KEY_3;
|
||||
_glfw.win32.keycodes[0x005] = GLFW_KEY_4;
|
||||
_glfw.win32.keycodes[0x006] = GLFW_KEY_5;
|
||||
_glfw.win32.keycodes[0x007] = GLFW_KEY_6;
|
||||
_glfw.win32.keycodes[0x008] = GLFW_KEY_7;
|
||||
_glfw.win32.keycodes[0x009] = GLFW_KEY_8;
|
||||
_glfw.win32.keycodes[0x00A] = GLFW_KEY_9;
|
||||
_glfw.win32.keycodes[0x01E] = GLFW_KEY_A;
|
||||
_glfw.win32.keycodes[0x030] = GLFW_KEY_B;
|
||||
_glfw.win32.keycodes[0x02E] = GLFW_KEY_C;
|
||||
_glfw.win32.keycodes[0x020] = GLFW_KEY_D;
|
||||
_glfw.win32.keycodes[0x012] = GLFW_KEY_E;
|
||||
_glfw.win32.keycodes[0x021] = GLFW_KEY_F;
|
||||
_glfw.win32.keycodes[0x022] = GLFW_KEY_G;
|
||||
_glfw.win32.keycodes[0x023] = GLFW_KEY_H;
|
||||
_glfw.win32.keycodes[0x017] = GLFW_KEY_I;
|
||||
_glfw.win32.keycodes[0x024] = GLFW_KEY_J;
|
||||
_glfw.win32.keycodes[0x025] = GLFW_KEY_K;
|
||||
_glfw.win32.keycodes[0x026] = GLFW_KEY_L;
|
||||
_glfw.win32.keycodes[0x032] = GLFW_KEY_M;
|
||||
_glfw.win32.keycodes[0x031] = GLFW_KEY_N;
|
||||
_glfw.win32.keycodes[0x018] = GLFW_KEY_O;
|
||||
_glfw.win32.keycodes[0x019] = GLFW_KEY_P;
|
||||
_glfw.win32.keycodes[0x010] = GLFW_KEY_Q;
|
||||
_glfw.win32.keycodes[0x013] = GLFW_KEY_R;
|
||||
_glfw.win32.keycodes[0x01F] = GLFW_KEY_S;
|
||||
_glfw.win32.keycodes[0x014] = GLFW_KEY_T;
|
||||
_glfw.win32.keycodes[0x016] = GLFW_KEY_U;
|
||||
_glfw.win32.keycodes[0x02F] = GLFW_KEY_V;
|
||||
_glfw.win32.keycodes[0x011] = GLFW_KEY_W;
|
||||
_glfw.win32.keycodes[0x02D] = GLFW_KEY_X;
|
||||
_glfw.win32.keycodes[0x015] = GLFW_KEY_Y;
|
||||
_glfw.win32.keycodes[0x02C] = GLFW_KEY_Z;
|
||||
|
||||
_glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE;
|
||||
_glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH;
|
||||
_glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA;
|
||||
_glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL;
|
||||
_glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT;
|
||||
_glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET;
|
||||
_glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS;
|
||||
_glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD;
|
||||
_glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET;
|
||||
_glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON;
|
||||
_glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH;
|
||||
_glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2;
|
||||
|
||||
_glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE;
|
||||
_glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE;
|
||||
_glfw.win32.keycodes[0x14F] = GLFW_KEY_END;
|
||||
_glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER;
|
||||
_glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE;
|
||||
_glfw.win32.keycodes[0x147] = GLFW_KEY_HOME;
|
||||
_glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT;
|
||||
_glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU;
|
||||
_glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
|
||||
_glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
|
||||
_glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
|
||||
_glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
|
||||
_glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK;
|
||||
_glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK;
|
||||
_glfw.win32.keycodes[0x03B] = GLFW_KEY_F1;
|
||||
_glfw.win32.keycodes[0x03C] = GLFW_KEY_F2;
|
||||
_glfw.win32.keycodes[0x03D] = GLFW_KEY_F3;
|
||||
_glfw.win32.keycodes[0x03E] = GLFW_KEY_F4;
|
||||
_glfw.win32.keycodes[0x03F] = GLFW_KEY_F5;
|
||||
_glfw.win32.keycodes[0x040] = GLFW_KEY_F6;
|
||||
_glfw.win32.keycodes[0x041] = GLFW_KEY_F7;
|
||||
_glfw.win32.keycodes[0x042] = GLFW_KEY_F8;
|
||||
_glfw.win32.keycodes[0x043] = GLFW_KEY_F9;
|
||||
_glfw.win32.keycodes[0x044] = GLFW_KEY_F10;
|
||||
_glfw.win32.keycodes[0x057] = GLFW_KEY_F11;
|
||||
_glfw.win32.keycodes[0x058] = GLFW_KEY_F12;
|
||||
_glfw.win32.keycodes[0x064] = GLFW_KEY_F13;
|
||||
_glfw.win32.keycodes[0x065] = GLFW_KEY_F14;
|
||||
_glfw.win32.keycodes[0x066] = GLFW_KEY_F15;
|
||||
_glfw.win32.keycodes[0x067] = GLFW_KEY_F16;
|
||||
_glfw.win32.keycodes[0x068] = GLFW_KEY_F17;
|
||||
_glfw.win32.keycodes[0x069] = GLFW_KEY_F18;
|
||||
_glfw.win32.keycodes[0x06A] = GLFW_KEY_F19;
|
||||
_glfw.win32.keycodes[0x06B] = GLFW_KEY_F20;
|
||||
_glfw.win32.keycodes[0x06C] = GLFW_KEY_F21;
|
||||
_glfw.win32.keycodes[0x06D] = GLFW_KEY_F22;
|
||||
_glfw.win32.keycodes[0x06E] = GLFW_KEY_F23;
|
||||
_glfw.win32.keycodes[0x076] = GLFW_KEY_F24;
|
||||
_glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT;
|
||||
_glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL;
|
||||
_glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT;
|
||||
_glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER;
|
||||
_glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN;
|
||||
_glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT;
|
||||
_glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL;
|
||||
_glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT;
|
||||
_glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER;
|
||||
_glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN;
|
||||
_glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT;
|
||||
_glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT;
|
||||
_glfw.win32.keycodes[0x148] = GLFW_KEY_UP;
|
||||
|
||||
_glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0;
|
||||
_glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1;
|
||||
_glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2;
|
||||
_glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3;
|
||||
_glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4;
|
||||
_glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5;
|
||||
_glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6;
|
||||
_glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7;
|
||||
_glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8;
|
||||
_glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9;
|
||||
_glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD;
|
||||
_glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL;
|
||||
_glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE;
|
||||
_glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER;
|
||||
_glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL;
|
||||
_glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT;
|
||||
|
||||
for (scancode = 0; scancode < 512; scancode++)
|
||||
{
|
||||
if (_glfw.win32.keycodes[scancode] > 0)
|
||||
_glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode;
|
||||
}
|
||||
}
|
||||
|
||||
// Window procedure for the hidden helper window
|
||||
//
|
||||
static LRESULT CALLBACK helperWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_DISPLAYCHANGE:
|
||||
_glfwPollMonitorsWin32();
|
||||
break;
|
||||
|
||||
case WM_DEVICECHANGE:
|
||||
{
|
||||
if (!_glfw.joysticksInitialized)
|
||||
break;
|
||||
|
||||
if (wParam == DBT_DEVICEARRIVAL)
|
||||
{
|
||||
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*)lParam;
|
||||
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||||
_glfwDetectJoystickConnectionWin32();
|
||||
}
|
||||
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
{
|
||||
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*)lParam;
|
||||
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
||||
_glfwDetectJoystickDisconnectionWin32();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Creates a dummy window for behind-the-scenes work
|
||||
//
|
||||
static GLFWbool createHelperWindow(void)
|
||||
{
|
||||
MSG msg;
|
||||
WNDCLASSEXW wc = { sizeof(wc) };
|
||||
|
||||
wc.style = CS_OWNDC;
|
||||
wc.lpfnWndProc = (WNDPROC)helperWindowProc;
|
||||
wc.hInstance = _glfw.win32.instance;
|
||||
wc.lpszClassName = L"GLFW3 Helper";
|
||||
|
||||
_glfw.win32.helperWindowClass = RegisterClassExW(&wc);
|
||||
if (!_glfw.win32.helperWindowClass)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to register helper window class");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.win32.helperWindowHandle =
|
||||
CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
|
||||
MAKEINTATOM(_glfw.win32.helperWindowClass),
|
||||
L"GLFW message window",
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
||||
0, 0, 1, 1,
|
||||
NULL, NULL,
|
||||
_glfw.win32.instance,
|
||||
NULL);
|
||||
|
||||
if (!_glfw.win32.helperWindowHandle)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to create helper window");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// HACK: The command to the first ShowWindow call is ignored if the parent
|
||||
// process passed along a STARTUPINFO, so clear that with a no-op call
|
||||
ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE);
|
||||
|
||||
// Register for HID device notifications
|
||||
{
|
||||
DEV_BROADCAST_DEVICEINTERFACE_W dbi;
|
||||
ZeroMemory(&dbi, sizeof(dbi));
|
||||
dbi.dbcc_size = sizeof(dbi);
|
||||
dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
|
||||
|
||||
_glfw.win32.deviceNotificationHandle =
|
||||
RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle,
|
||||
(DEV_BROADCAST_HDR*)&dbi,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
}
|
||||
|
||||
while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns a wide string version of the specified UTF-8 string
|
||||
//
|
||||
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source)
|
||||
{
|
||||
WCHAR* target;
|
||||
int count;
|
||||
|
||||
count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0);
|
||||
if (!count)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to convert string from UTF-8");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target = _glfw_calloc(count, sizeof(WCHAR));
|
||||
|
||||
if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to convert string from UTF-8");
|
||||
_glfw_free(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Returns a UTF-8 string version of the specified wide string
|
||||
//
|
||||
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
|
||||
{
|
||||
char* target;
|
||||
int size;
|
||||
|
||||
size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
|
||||
if (!size)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to convert string to UTF-8");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
target = _glfw_calloc(size, 1);
|
||||
|
||||
if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL))
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to convert string to UTF-8");
|
||||
_glfw_free(target);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Reports the specified error, appending information about the last Win32 error
|
||||
//
|
||||
void _glfwInputErrorWin32(int error, const char* description)
|
||||
{
|
||||
WCHAR buffer[_GLFW_MESSAGE_SIZE] = L"";
|
||||
char message[_GLFW_MESSAGE_SIZE] = "";
|
||||
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||
NULL,
|
||||
GetLastError() & 0xffff,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
buffer,
|
||||
sizeof(buffer) / sizeof(WCHAR),
|
||||
NULL);
|
||||
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL);
|
||||
|
||||
_glfwInputError(error, "%s: %s", description, message);
|
||||
}
|
||||
|
||||
// Updates key names according to the current keyboard layout
|
||||
//
|
||||
void _glfwUpdateKeyNamesWin32(void)
|
||||
{
|
||||
int key;
|
||||
BYTE state[256] = { 0 };
|
||||
|
||||
memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames));
|
||||
|
||||
for (key = GLFW_KEY_SPACE; key <= GLFW_KEY_LAST; key++)
|
||||
{
|
||||
UINT vk;
|
||||
int scancode, length;
|
||||
WCHAR chars[16];
|
||||
|
||||
scancode = _glfw.win32.scancodes[key];
|
||||
if (scancode == -1)
|
||||
continue;
|
||||
|
||||
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
|
||||
{
|
||||
const UINT vks[] = {
|
||||
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
|
||||
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
|
||||
VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE,
|
||||
VK_MULTIPLY, VK_SUBTRACT, VK_ADD
|
||||
};
|
||||
|
||||
vk = vks[key - GLFW_KEY_KP_0];
|
||||
}
|
||||
else
|
||||
vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK);
|
||||
|
||||
length = ToUnicode(vk, scancode, state,
|
||||
chars, sizeof(chars) / sizeof(WCHAR),
|
||||
0);
|
||||
|
||||
if (length == -1)
|
||||
{
|
||||
// This is a dead key, so we need a second simulated key press
|
||||
// to make it output its own character (usually a diacritic)
|
||||
length = ToUnicode(vk, scancode, state,
|
||||
chars, sizeof(chars) / sizeof(WCHAR),
|
||||
0);
|
||||
}
|
||||
|
||||
if (length < 1)
|
||||
continue;
|
||||
|
||||
WideCharToMultiByte(CP_UTF8, 0, chars, 1,
|
||||
_glfw.win32.keynames[key],
|
||||
sizeof(_glfw.win32.keynames[key]),
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the
|
||||
// application having a correct embedded manifest
|
||||
//
|
||||
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
|
||||
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
|
||||
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
|
||||
// latter lies unless the user knew to embed a non-default manifest
|
||||
// announcing support for Windows 10 via supportedOS GUID
|
||||
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
|
||||
}
|
||||
|
||||
// Checks whether we are on at least the specified build of Windows 10
|
||||
//
|
||||
BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), 10, 0, build };
|
||||
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
|
||||
ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
|
||||
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
|
||||
// latter lies unless the user knew to embed a non-default manifest
|
||||
// announcing support for Windows 10 via supportedOS GUID
|
||||
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
|
||||
}
|
||||
|
||||
GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
|
||||
{
|
||||
const _GLFWplatform win32 =
|
||||
{
|
||||
GLFW_PLATFORM_WIN32,
|
||||
_glfwInitWin32,
|
||||
_glfwTerminateWin32,
|
||||
_glfwGetCursorPosWin32,
|
||||
_glfwSetCursorPosWin32,
|
||||
_glfwSetCursorModeWin32,
|
||||
_glfwSetRawMouseMotionWin32,
|
||||
_glfwRawMouseMotionSupportedWin32,
|
||||
_glfwCreateCursorWin32,
|
||||
_glfwCreateStandardCursorWin32,
|
||||
_glfwDestroyCursorWin32,
|
||||
_glfwSetCursorWin32,
|
||||
_glfwGetScancodeNameWin32,
|
||||
_glfwGetKeyScancodeWin32,
|
||||
_glfwSetClipboardStringWin32,
|
||||
_glfwGetClipboardStringWin32,
|
||||
_glfwInitJoysticksWin32,
|
||||
_glfwTerminateJoysticksWin32,
|
||||
_glfwPollJoystickWin32,
|
||||
_glfwGetMappingNameWin32,
|
||||
_glfwUpdateGamepadGUIDWin32,
|
||||
_glfwFreeMonitorWin32,
|
||||
_glfwGetMonitorPosWin32,
|
||||
_glfwGetMonitorContentScaleWin32,
|
||||
_glfwGetMonitorWorkareaWin32,
|
||||
_glfwGetVideoModesWin32,
|
||||
_glfwGetVideoModeWin32,
|
||||
_glfwGetGammaRampWin32,
|
||||
_glfwSetGammaRampWin32,
|
||||
_glfwCreateWindowWin32,
|
||||
_glfwDestroyWindowWin32,
|
||||
_glfwSetWindowTitleWin32,
|
||||
_glfwSetWindowIconWin32,
|
||||
_glfwGetWindowPosWin32,
|
||||
_glfwSetWindowPosWin32,
|
||||
_glfwGetWindowSizeWin32,
|
||||
_glfwSetWindowSizeWin32,
|
||||
_glfwSetWindowSizeLimitsWin32,
|
||||
_glfwSetWindowAspectRatioWin32,
|
||||
_glfwGetFramebufferSizeWin32,
|
||||
_glfwGetWindowFrameSizeWin32,
|
||||
_glfwGetWindowContentScaleWin32,
|
||||
_glfwIconifyWindowWin32,
|
||||
_glfwRestoreWindowWin32,
|
||||
_glfwMaximizeWindowWin32,
|
||||
_glfwShowWindowWin32,
|
||||
_glfwHideWindowWin32,
|
||||
_glfwRequestWindowAttentionWin32,
|
||||
_glfwFocusWindowWin32,
|
||||
_glfwSetWindowMonitorWin32,
|
||||
_glfwWindowFocusedWin32,
|
||||
_glfwWindowIconifiedWin32,
|
||||
_glfwWindowVisibleWin32,
|
||||
_glfwWindowMaximizedWin32,
|
||||
_glfwWindowHoveredWin32,
|
||||
_glfwFramebufferTransparentWin32,
|
||||
_glfwGetWindowOpacityWin32,
|
||||
_glfwSetWindowResizableWin32,
|
||||
_glfwSetWindowDecoratedWin32,
|
||||
_glfwSetWindowFloatingWin32,
|
||||
_glfwSetWindowOpacityWin32,
|
||||
_glfwSetWindowMousePassthroughWin32,
|
||||
_glfwPollEventsWin32,
|
||||
_glfwWaitEventsWin32,
|
||||
_glfwWaitEventsTimeoutWin32,
|
||||
_glfwPostEmptyEventWin32,
|
||||
_glfwGetEGLPlatformWin32,
|
||||
_glfwGetEGLNativeDisplayWin32,
|
||||
_glfwGetEGLNativeWindowWin32,
|
||||
_glfwGetRequiredInstanceExtensionsWin32,
|
||||
_glfwGetPhysicalDevicePresentationSupportWin32,
|
||||
_glfwCreateWindowSurfaceWin32,
|
||||
};
|
||||
|
||||
*platform = win32;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
int _glfwInitWin32(void)
|
||||
{
|
||||
if (!loadLibraries())
|
||||
return GLFW_FALSE;
|
||||
|
||||
createKeyTables();
|
||||
_glfwUpdateKeyNamesWin32();
|
||||
|
||||
if (_glfwIsWindows10Version1703OrGreaterWin32())
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
else if (IsWindows8Point1OrGreater())
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
else if (IsWindowsVistaOrGreater())
|
||||
SetProcessDPIAware();
|
||||
|
||||
if (!createHelperWindow())
|
||||
return GLFW_FALSE;
|
||||
|
||||
_glfwPollMonitorsWin32();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateWin32(void)
|
||||
{
|
||||
if (_glfw.win32.deviceNotificationHandle)
|
||||
UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
|
||||
|
||||
if (_glfw.win32.helperWindowHandle)
|
||||
DestroyWindow(_glfw.win32.helperWindowHandle);
|
||||
if (_glfw.win32.helperWindowClass)
|
||||
UnregisterClassW(MAKEINTATOM(_glfw.win32.helperWindowClass), _glfw.win32.instance);
|
||||
if (_glfw.win32.mainWindowClass)
|
||||
UnregisterClassW(MAKEINTATOM(_glfw.win32.mainWindowClass), _glfw.win32.instance);
|
||||
|
||||
_glfw_free(_glfw.win32.clipboardString);
|
||||
_glfw_free(_glfw.win32.rawInput);
|
||||
|
||||
_glfwTerminateWGL();
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateOSMesa();
|
||||
|
||||
freeLibraries();
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
@@ -0,0 +1,762 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#define _GLFW_TYPE_AXIS 0
|
||||
#define _GLFW_TYPE_SLIDER 1
|
||||
#define _GLFW_TYPE_BUTTON 2
|
||||
#define _GLFW_TYPE_POV 3
|
||||
|
||||
// Data produced with DirectInput device object enumeration
|
||||
//
|
||||
typedef struct _GLFWobjenumWin32
|
||||
{
|
||||
IDirectInputDevice8W* device;
|
||||
_GLFWjoyobjectWin32* objects;
|
||||
int objectCount;
|
||||
int axisCount;
|
||||
int sliderCount;
|
||||
int buttonCount;
|
||||
int povCount;
|
||||
} _GLFWobjenumWin32;
|
||||
|
||||
// Define local copies of the necessary GUIDs
|
||||
//
|
||||
static const GUID _glfw_IID_IDirectInput8W =
|
||||
{0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}};
|
||||
static const GUID _glfw_GUID_XAxis =
|
||||
{0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_YAxis =
|
||||
{0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_ZAxis =
|
||||
{0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_RxAxis =
|
||||
{0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_RyAxis =
|
||||
{0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_RzAxis =
|
||||
{0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_Slider =
|
||||
{0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
static const GUID _glfw_GUID_POV =
|
||||
{0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
|
||||
|
||||
#define IID_IDirectInput8W _glfw_IID_IDirectInput8W
|
||||
#define GUID_XAxis _glfw_GUID_XAxis
|
||||
#define GUID_YAxis _glfw_GUID_YAxis
|
||||
#define GUID_ZAxis _glfw_GUID_ZAxis
|
||||
#define GUID_RxAxis _glfw_GUID_RxAxis
|
||||
#define GUID_RyAxis _glfw_GUID_RyAxis
|
||||
#define GUID_RzAxis _glfw_GUID_RzAxis
|
||||
#define GUID_Slider _glfw_GUID_Slider
|
||||
#define GUID_POV _glfw_GUID_POV
|
||||
|
||||
// Object data array for our clone of c_dfDIJoystick
|
||||
// Generated with https://github.com/elmindreda/c_dfDIJoystick2
|
||||
//
|
||||
static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
|
||||
{
|
||||
{ &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
|
||||
{ &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
{ NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
|
||||
};
|
||||
|
||||
// Our clone of c_dfDIJoystick
|
||||
//
|
||||
static const DIDATAFORMAT _glfwDataFormat =
|
||||
{
|
||||
sizeof(DIDATAFORMAT),
|
||||
sizeof(DIOBJECTDATAFORMAT),
|
||||
DIDFT_ABSAXIS,
|
||||
sizeof(DIJOYSTATE),
|
||||
sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
|
||||
_glfwObjectDataFormats
|
||||
};
|
||||
|
||||
// Returns a description fitting the specified XInput capabilities
|
||||
//
|
||||
static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
|
||||
{
|
||||
switch (xic->SubType)
|
||||
{
|
||||
case XINPUT_DEVSUBTYPE_WHEEL:
|
||||
return "XInput Wheel";
|
||||
case XINPUT_DEVSUBTYPE_ARCADE_STICK:
|
||||
return "XInput Arcade Stick";
|
||||
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
|
||||
return "XInput Flight Stick";
|
||||
case XINPUT_DEVSUBTYPE_DANCE_PAD:
|
||||
return "XInput Dance Pad";
|
||||
case XINPUT_DEVSUBTYPE_GUITAR:
|
||||
return "XInput Guitar";
|
||||
case XINPUT_DEVSUBTYPE_DRUM_KIT:
|
||||
return "XInput Drum Kit";
|
||||
case XINPUT_DEVSUBTYPE_GAMEPAD:
|
||||
{
|
||||
if (xic->Flags & XINPUT_CAPS_WIRELESS)
|
||||
return "Wireless Xbox Controller";
|
||||
else
|
||||
return "Xbox Controller";
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown XInput Device";
|
||||
}
|
||||
|
||||
// Lexically compare device objects
|
||||
//
|
||||
static int compareJoystickObjects(const void* first, const void* second)
|
||||
{
|
||||
const _GLFWjoyobjectWin32* fo = first;
|
||||
const _GLFWjoyobjectWin32* so = second;
|
||||
|
||||
if (fo->type != so->type)
|
||||
return fo->type - so->type;
|
||||
|
||||
return fo->offset - so->offset;
|
||||
}
|
||||
|
||||
// Checks whether the specified device supports XInput
|
||||
// Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
|
||||
//
|
||||
static GLFWbool supportsXInput(const GUID* guid)
|
||||
{
|
||||
UINT i, count = 0;
|
||||
RAWINPUTDEVICELIST* ridl;
|
||||
GLFWbool result = GLFW_FALSE;
|
||||
|
||||
if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
return GLFW_FALSE;
|
||||
|
||||
ridl = _glfw_calloc(count, sizeof(RAWINPUTDEVICELIST));
|
||||
|
||||
if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
|
||||
{
|
||||
_glfw_free(ridl);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
RID_DEVICE_INFO rdi;
|
||||
char name[256];
|
||||
UINT size;
|
||||
|
||||
if (ridl[i].dwType != RIM_TYPEHID)
|
||||
continue;
|
||||
|
||||
ZeroMemory(&rdi, sizeof(rdi));
|
||||
rdi.cbSize = sizeof(rdi);
|
||||
size = sizeof(rdi);
|
||||
|
||||
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||
RIDI_DEVICEINFO,
|
||||
&rdi, &size) == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
|
||||
continue;
|
||||
|
||||
memset(name, 0, sizeof(name));
|
||||
size = sizeof(name);
|
||||
|
||||
if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
|
||||
RIDI_DEVICENAME,
|
||||
name, &size) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
if (strstr(name, "IG_"))
|
||||
{
|
||||
result = GLFW_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_glfw_free(ridl);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Frees all resources associated with the specified joystick
|
||||
//
|
||||
static void closeJoystick(_GLFWjoystick* js)
|
||||
{
|
||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||
|
||||
if (js->win32.device)
|
||||
{
|
||||
IDirectInputDevice8_Unacquire(js->win32.device);
|
||||
IDirectInputDevice8_Release(js->win32.device);
|
||||
}
|
||||
|
||||
_glfw_free(js->win32.objects);
|
||||
_glfwFreeJoystick(js);
|
||||
}
|
||||
|
||||
// DirectInput device object enumeration callback
|
||||
// Insights gleaned from SDL
|
||||
//
|
||||
static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
|
||||
void* user)
|
||||
{
|
||||
_GLFWobjenumWin32* data = user;
|
||||
_GLFWjoyobjectWin32* object = data->objects + data->objectCount;
|
||||
|
||||
if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
|
||||
{
|
||||
DIPROPRANGE dipr;
|
||||
|
||||
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_SLIDER(data->sliderCount);
|
||||
else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_X;
|
||||
else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_Y;
|
||||
else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_Z;
|
||||
else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RX;
|
||||
else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RY;
|
||||
else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
|
||||
object->offset = DIJOFS_RZ;
|
||||
else
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
ZeroMemory(&dipr, sizeof(dipr));
|
||||
dipr.diph.dwSize = sizeof(dipr);
|
||||
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
|
||||
dipr.diph.dwObj = doi->dwType;
|
||||
dipr.diph.dwHow = DIPH_BYID;
|
||||
dipr.lMin = -32768;
|
||||
dipr.lMax = 32767;
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetProperty(data->device,
|
||||
DIPROP_RANGE,
|
||||
&dipr.diph)))
|
||||
{
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
|
||||
{
|
||||
object->type = _GLFW_TYPE_SLIDER;
|
||||
data->sliderCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->type = _GLFW_TYPE_AXIS;
|
||||
data->axisCount++;
|
||||
}
|
||||
}
|
||||
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
|
||||
{
|
||||
object->offset = DIJOFS_BUTTON(data->buttonCount);
|
||||
object->type = _GLFW_TYPE_BUTTON;
|
||||
data->buttonCount++;
|
||||
}
|
||||
else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
|
||||
{
|
||||
object->offset = DIJOFS_POV(data->povCount);
|
||||
object->type = _GLFW_TYPE_POV;
|
||||
data->povCount++;
|
||||
}
|
||||
|
||||
data->objectCount++;
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
// DirectInput device enumeration callback
|
||||
//
|
||||
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
|
||||
{
|
||||
int jid = 0;
|
||||
DIDEVCAPS dc;
|
||||
DIPROPDWORD dipd;
|
||||
IDirectInputDevice8* device;
|
||||
_GLFWobjenumWin32 data;
|
||||
_GLFWjoystick* js;
|
||||
char guid[33];
|
||||
char name[256];
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
js = _glfw.joysticks + jid;
|
||||
if (js->connected)
|
||||
{
|
||||
if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsXInput(&di->guidProduct))
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
|
||||
&di->guidInstance,
|
||||
&device,
|
||||
NULL)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to set device data format");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dc, sizeof(dc));
|
||||
dc.dwSize = sizeof(dc);
|
||||
|
||||
if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to query device capabilities");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
ZeroMemory(&dipd, sizeof(dipd));
|
||||
dipd.diph.dwSize = sizeof(dipd);
|
||||
dipd.diph.dwHeaderSize = sizeof(dipd.diph);
|
||||
dipd.diph.dwHow = DIPH_DEVICE;
|
||||
dipd.dwData = DIPROPAXISMODE_ABS;
|
||||
|
||||
if (FAILED(IDirectInputDevice8_SetProperty(device,
|
||||
DIPROP_AXISMODE,
|
||||
&dipd.diph)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to set device axis mode");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.device = device;
|
||||
data.objects = _glfw_calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs,
|
||||
sizeof(_GLFWjoyobjectWin32));
|
||||
|
||||
if (FAILED(IDirectInputDevice8_EnumObjects(device,
|
||||
deviceObjectCallback,
|
||||
&data,
|
||||
DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to enumerate device objects");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
_glfw_free(data.objects);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
qsort(data.objects, data.objectCount,
|
||||
sizeof(_GLFWjoyobjectWin32),
|
||||
compareJoystickObjects);
|
||||
|
||||
if (!WideCharToMultiByte(CP_UTF8, 0,
|
||||
di->tszInstanceName, -1,
|
||||
name, sizeof(name),
|
||||
NULL, NULL))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to convert joystick name to UTF-8");
|
||||
|
||||
IDirectInputDevice8_Release(device);
|
||||
_glfw_free(data.objects);
|
||||
return DIENUM_STOP;
|
||||
}
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0)
|
||||
{
|
||||
sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000",
|
||||
(uint8_t) di->guidProduct.Data1,
|
||||
(uint8_t) (di->guidProduct.Data1 >> 8),
|
||||
(uint8_t) (di->guidProduct.Data1 >> 16),
|
||||
(uint8_t) (di->guidProduct.Data1 >> 24));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
|
||||
name[0], name[1], name[2], name[3],
|
||||
name[4], name[5], name[6], name[7],
|
||||
name[8], name[9], name[10]);
|
||||
}
|
||||
|
||||
js = _glfwAllocJoystick(name, guid,
|
||||
data.axisCount + data.sliderCount,
|
||||
data.buttonCount,
|
||||
data.povCount);
|
||||
if (!js)
|
||||
{
|
||||
IDirectInputDevice8_Release(device);
|
||||
_glfw_free(data.objects);
|
||||
return DIENUM_STOP;
|
||||
}
|
||||
|
||||
js->win32.device = device;
|
||||
js->win32.guid = di->guidInstance;
|
||||
js->win32.objects = data.objects;
|
||||
js->win32.objectCount = data.objectCount;
|
||||
|
||||
_glfwInputJoystick(js, GLFW_CONNECTED);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Checks for new joysticks after DBT_DEVICEARRIVAL
|
||||
//
|
||||
void _glfwDetectJoystickConnectionWin32(void)
|
||||
{
|
||||
if (_glfw.win32.xinput.instance)
|
||||
{
|
||||
DWORD index;
|
||||
|
||||
for (index = 0; index < XUSER_MAX_COUNT; index++)
|
||||
{
|
||||
int jid;
|
||||
char guid[33];
|
||||
XINPUT_CAPABILITIES xic;
|
||||
_GLFWjoystick* js;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
if (_glfw.joysticks[jid].connected &&
|
||||
_glfw.joysticks[jid].win32.device == NULL &&
|
||||
_glfw.joysticks[jid].win32.index == index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jid <= GLFW_JOYSTICK_LAST)
|
||||
continue;
|
||||
|
||||
if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
|
||||
continue;
|
||||
|
||||
// Generate a joystick GUID that matches the SDL 2.0.5+ one
|
||||
sprintf(guid, "78696e707574%02x000000000000000000",
|
||||
xic.SubType & 0xff);
|
||||
|
||||
js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
|
||||
if (!js)
|
||||
continue;
|
||||
|
||||
js->win32.index = index;
|
||||
|
||||
_glfwInputJoystick(js, GLFW_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.win32.dinput8.api)
|
||||
{
|
||||
if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
|
||||
DI8DEVCLASS_GAMECTRL,
|
||||
deviceCallback,
|
||||
NULL,
|
||||
DIEDFL_ALLDEVICES)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Failed to enumerate DirectInput8 devices");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
|
||||
//
|
||||
void _glfwDetectJoystickDisconnectionWin32(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
{
|
||||
_GLFWjoystick* js = _glfw.joysticks + jid;
|
||||
if (js->connected)
|
||||
_glfwPollJoystickWin32(js, _GLFW_POLL_PRESENCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwInitJoysticksWin32(void)
|
||||
{
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
if (FAILED(DirectInput8Create(_glfw.win32.instance,
|
||||
DIRECTINPUT_VERSION,
|
||||
&IID_IDirectInput8W,
|
||||
(void**) &_glfw.win32.dinput8.api,
|
||||
NULL)))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to create interface");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
_glfwDetectJoystickConnectionWin32();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwTerminateJoysticksWin32(void)
|
||||
{
|
||||
int jid;
|
||||
|
||||
for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
|
||||
closeJoystick(_glfw.joysticks + jid);
|
||||
|
||||
if (_glfw.win32.dinput8.api)
|
||||
IDirectInput8_Release(_glfw.win32.dinput8.api);
|
||||
}
|
||||
|
||||
GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
|
||||
{
|
||||
if (js->win32.device)
|
||||
{
|
||||
int i, ai = 0, bi = 0, pi = 0;
|
||||
HRESULT result;
|
||||
DIJOYSTATE state = {0};
|
||||
|
||||
IDirectInputDevice8_Poll(js->win32.device);
|
||||
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
|
||||
sizeof(state),
|
||||
&state);
|
||||
if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
|
||||
{
|
||||
IDirectInputDevice8_Acquire(js->win32.device);
|
||||
IDirectInputDevice8_Poll(js->win32.device);
|
||||
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
|
||||
sizeof(state),
|
||||
&state);
|
||||
}
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
closeJoystick(js);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (mode == _GLFW_POLL_PRESENCE)
|
||||
return GLFW_TRUE;
|
||||
|
||||
for (i = 0; i < js->win32.objectCount; i++)
|
||||
{
|
||||
const void* data = (char*) &state + js->win32.objects[i].offset;
|
||||
|
||||
switch (js->win32.objects[i].type)
|
||||
{
|
||||
case _GLFW_TYPE_AXIS:
|
||||
case _GLFW_TYPE_SLIDER:
|
||||
{
|
||||
const float value = (*((LONG*) data) + 0.5f) / 32767.5f;
|
||||
_glfwInputJoystickAxis(js, ai, value);
|
||||
ai++;
|
||||
break;
|
||||
}
|
||||
|
||||
case _GLFW_TYPE_BUTTON:
|
||||
{
|
||||
const char value = (*((BYTE*) data) & 0x80) != 0;
|
||||
_glfwInputJoystickButton(js, bi, value);
|
||||
bi++;
|
||||
break;
|
||||
}
|
||||
|
||||
case _GLFW_TYPE_POV:
|
||||
{
|
||||
const int states[9] =
|
||||
{
|
||||
GLFW_HAT_UP,
|
||||
GLFW_HAT_RIGHT_UP,
|
||||
GLFW_HAT_RIGHT,
|
||||
GLFW_HAT_RIGHT_DOWN,
|
||||
GLFW_HAT_DOWN,
|
||||
GLFW_HAT_LEFT_DOWN,
|
||||
GLFW_HAT_LEFT,
|
||||
GLFW_HAT_LEFT_UP,
|
||||
GLFW_HAT_CENTERED
|
||||
};
|
||||
|
||||
// Screams of horror are appropriate at this point
|
||||
int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
|
||||
if (stateIndex < 0 || stateIndex > 8)
|
||||
stateIndex = 8;
|
||||
|
||||
_glfwInputJoystickHat(js, pi, states[stateIndex]);
|
||||
pi++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, dpad = 0;
|
||||
DWORD result;
|
||||
XINPUT_STATE xis;
|
||||
const WORD buttons[10] =
|
||||
{
|
||||
XINPUT_GAMEPAD_A,
|
||||
XINPUT_GAMEPAD_B,
|
||||
XINPUT_GAMEPAD_X,
|
||||
XINPUT_GAMEPAD_Y,
|
||||
XINPUT_GAMEPAD_LEFT_SHOULDER,
|
||||
XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||
XINPUT_GAMEPAD_BACK,
|
||||
XINPUT_GAMEPAD_START,
|
||||
XINPUT_GAMEPAD_LEFT_THUMB,
|
||||
XINPUT_GAMEPAD_RIGHT_THUMB
|
||||
};
|
||||
|
||||
result = XInputGetState(js->win32.index, &xis);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
if (result == ERROR_DEVICE_NOT_CONNECTED)
|
||||
closeJoystick(js);
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (mode == _GLFW_POLL_PRESENCE)
|
||||
return GLFW_TRUE;
|
||||
|
||||
_glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f);
|
||||
_glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f);
|
||||
_glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f);
|
||||
_glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f);
|
||||
_glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f);
|
||||
_glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f);
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
|
||||
_glfwInputJoystickButton(js, i, value);
|
||||
}
|
||||
|
||||
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
|
||||
dpad |= GLFW_HAT_UP;
|
||||
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
|
||||
dpad |= GLFW_HAT_RIGHT;
|
||||
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
|
||||
dpad |= GLFW_HAT_DOWN;
|
||||
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
|
||||
dpad |= GLFW_HAT_LEFT;
|
||||
|
||||
_glfwInputJoystickHat(js, 0, dpad);
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
const char* _glfwGetMappingNameWin32(void)
|
||||
{
|
||||
return "Windows";
|
||||
}
|
||||
|
||||
void _glfwUpdateGamepadGUIDWin32(char* guid)
|
||||
{
|
||||
if (strcmp(guid + 20, "504944564944") == 0)
|
||||
{
|
||||
char original[33];
|
||||
strncpy(original, guid, sizeof(original) - 1);
|
||||
sprintf(guid, "03000000%.4s0000%.4s000000000000",
|
||||
original, original + 4);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2021 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(GLFW_BUILD_WIN32_MODULE)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* _glfwPlatformLoadModule(const char* path)
|
||||
{
|
||||
return LoadLibraryA(path);
|
||||
}
|
||||
|
||||
void _glfwPlatformFreeModule(void* module)
|
||||
{
|
||||
FreeLibrary((HMODULE)module);
|
||||
}
|
||||
|
||||
GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
|
||||
{
|
||||
return (GLFWproc)GetProcAddress((HMODULE)module, name);
|
||||
}
|
||||
|
||||
#endif // GLFW_BUILD_WIN32_MODULE
|
||||
|
||||
@@ -0,0 +1,551 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(_GLFW_WIN32)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <wchar.h>
|
||||
|
||||
|
||||
// Callback for EnumDisplayMonitors in createMonitor
|
||||
//
|
||||
static BOOL CALLBACK monitorCallback(HMONITOR handle,
|
||||
HDC dc,
|
||||
RECT* rect,
|
||||
LPARAM data)
|
||||
{
|
||||
MONITORINFOEXW mi;
|
||||
ZeroMemory(&mi, sizeof(mi));
|
||||
mi.cbSize = sizeof(mi);
|
||||
|
||||
if (GetMonitorInfoW(handle, (MONITORINFO*) &mi))
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) data;
|
||||
if (wcscmp(mi.szDevice, monitor->win32.adapterName) == 0)
|
||||
monitor->win32.handle = handle;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Create monitor from an adapter and (optionally) a display
|
||||
//
|
||||
static _GLFWmonitor* createMonitor(DISPLAY_DEVICEW* adapter,
|
||||
DISPLAY_DEVICEW* display)
|
||||
{
|
||||
_GLFWmonitor* monitor;
|
||||
int widthMM, heightMM;
|
||||
char* name;
|
||||
HDC dc;
|
||||
DEVMODEW dm;
|
||||
RECT rect;
|
||||
|
||||
if (display)
|
||||
name = _glfwCreateUTF8FromWideStringWin32(display->DeviceString);
|
||||
else
|
||||
name = _glfwCreateUTF8FromWideStringWin32(adapter->DeviceString);
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
ZeroMemory(&dm, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
EnumDisplaySettingsW(adapter->DeviceName, ENUM_CURRENT_SETTINGS, &dm);
|
||||
|
||||
dc = CreateDCW(L"DISPLAY", adapter->DeviceName, NULL, NULL);
|
||||
|
||||
if (IsWindows8Point1OrGreater())
|
||||
{
|
||||
widthMM = GetDeviceCaps(dc, HORZSIZE);
|
||||
heightMM = GetDeviceCaps(dc, VERTSIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
widthMM = (int) (dm.dmPelsWidth * 25.4f / GetDeviceCaps(dc, LOGPIXELSX));
|
||||
heightMM = (int) (dm.dmPelsHeight * 25.4f / GetDeviceCaps(dc, LOGPIXELSY));
|
||||
}
|
||||
|
||||
DeleteDC(dc);
|
||||
|
||||
monitor = _glfwAllocMonitor(name, widthMM, heightMM);
|
||||
_glfw_free(name);
|
||||
|
||||
if (adapter->StateFlags & DISPLAY_DEVICE_MODESPRUNED)
|
||||
monitor->win32.modesPruned = GLFW_TRUE;
|
||||
|
||||
wcscpy(monitor->win32.adapterName, adapter->DeviceName);
|
||||
WideCharToMultiByte(CP_UTF8, 0,
|
||||
adapter->DeviceName, -1,
|
||||
monitor->win32.publicAdapterName,
|
||||
sizeof(monitor->win32.publicAdapterName),
|
||||
NULL, NULL);
|
||||
|
||||
if (display)
|
||||
{
|
||||
wcscpy(monitor->win32.displayName, display->DeviceName);
|
||||
WideCharToMultiByte(CP_UTF8, 0,
|
||||
display->DeviceName, -1,
|
||||
monitor->win32.publicDisplayName,
|
||||
sizeof(monitor->win32.publicDisplayName),
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
rect.left = dm.dmPosition.x;
|
||||
rect.top = dm.dmPosition.y;
|
||||
rect.right = dm.dmPosition.x + dm.dmPelsWidth;
|
||||
rect.bottom = dm.dmPosition.y + dm.dmPelsHeight;
|
||||
|
||||
EnumDisplayMonitors(NULL, &rect, monitorCallback, (LPARAM) monitor);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsWin32(void)
|
||||
{
|
||||
int i, disconnectedCount;
|
||||
_GLFWmonitor** disconnected = NULL;
|
||||
DWORD adapterIndex, displayIndex;
|
||||
DISPLAY_DEVICEW adapter, display;
|
||||
_GLFWmonitor* monitor;
|
||||
|
||||
disconnectedCount = _glfw.monitorCount;
|
||||
if (disconnectedCount)
|
||||
{
|
||||
disconnected = _glfw_calloc(_glfw.monitorCount, sizeof(_GLFWmonitor*));
|
||||
memcpy(disconnected,
|
||||
_glfw.monitors,
|
||||
_glfw.monitorCount * sizeof(_GLFWmonitor*));
|
||||
}
|
||||
|
||||
for (adapterIndex = 0; ; adapterIndex++)
|
||||
{
|
||||
int type = _GLFW_INSERT_LAST;
|
||||
|
||||
ZeroMemory(&adapter, sizeof(adapter));
|
||||
adapter.cb = sizeof(adapter);
|
||||
|
||||
if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0))
|
||||
break;
|
||||
|
||||
if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE))
|
||||
continue;
|
||||
|
||||
if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
|
||||
type = _GLFW_INSERT_FIRST;
|
||||
|
||||
for (displayIndex = 0; ; displayIndex++)
|
||||
{
|
||||
ZeroMemory(&display, sizeof(display));
|
||||
display.cb = sizeof(display);
|
||||
|
||||
if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0))
|
||||
break;
|
||||
|
||||
if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i] &&
|
||||
wcscmp(disconnected[i]->win32.displayName,
|
||||
display.DeviceName) == 0)
|
||||
{
|
||||
disconnected[i] = NULL;
|
||||
// handle may have changed, update
|
||||
EnumDisplayMonitors(NULL, NULL, monitorCallback, (LPARAM) _glfw.monitors[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < disconnectedCount)
|
||||
continue;
|
||||
|
||||
monitor = createMonitor(&adapter, &display);
|
||||
if (!monitor)
|
||||
{
|
||||
_glfw_free(disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, type);
|
||||
|
||||
type = _GLFW_INSERT_LAST;
|
||||
}
|
||||
|
||||
// HACK: If an active adapter does not have any display devices
|
||||
// (as sometimes happens), add it directly as a monitor
|
||||
if (displayIndex == 0)
|
||||
{
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i] &&
|
||||
wcscmp(disconnected[i]->win32.adapterName,
|
||||
adapter.DeviceName) == 0)
|
||||
{
|
||||
disconnected[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < disconnectedCount)
|
||||
continue;
|
||||
|
||||
monitor = createMonitor(&adapter, NULL);
|
||||
if (!monitor)
|
||||
{
|
||||
_glfw_free(disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, type);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < disconnectedCount; i++)
|
||||
{
|
||||
if (disconnected[i])
|
||||
_glfwInputMonitor(disconnected[i], GLFW_DISCONNECTED, 0);
|
||||
}
|
||||
|
||||
_glfw_free(disconnected);
|
||||
}
|
||||
|
||||
// Change the current video mode
|
||||
//
|
||||
void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired)
|
||||
{
|
||||
GLFWvidmode current;
|
||||
const GLFWvidmode* best;
|
||||
DEVMODEW dm;
|
||||
LONG result;
|
||||
|
||||
best = _glfwChooseVideoMode(monitor, desired);
|
||||
_glfwGetVideoModeWin32(monitor, ¤t);
|
||||
if (_glfwCompareVideoModes(¤t, best) == 0)
|
||||
return;
|
||||
|
||||
ZeroMemory(&dm, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL |
|
||||
DM_DISPLAYFREQUENCY;
|
||||
dm.dmPelsWidth = best->width;
|
||||
dm.dmPelsHeight = best->height;
|
||||
dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits;
|
||||
dm.dmDisplayFrequency = best->refreshRate;
|
||||
|
||||
if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24)
|
||||
dm.dmBitsPerPel = 32;
|
||||
|
||||
result = ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||
&dm,
|
||||
NULL,
|
||||
CDS_FULLSCREEN,
|
||||
NULL);
|
||||
if (result == DISP_CHANGE_SUCCESSFUL)
|
||||
monitor->win32.modeChanged = GLFW_TRUE;
|
||||
else
|
||||
{
|
||||
const char* description = "Unknown error";
|
||||
|
||||
if (result == DISP_CHANGE_BADDUALVIEW)
|
||||
description = "The system uses DualView";
|
||||
else if (result == DISP_CHANGE_BADFLAGS)
|
||||
description = "Invalid flags";
|
||||
else if (result == DISP_CHANGE_BADMODE)
|
||||
description = "Graphics mode not supported";
|
||||
else if (result == DISP_CHANGE_BADPARAM)
|
||||
description = "Invalid parameter";
|
||||
else if (result == DISP_CHANGE_FAILED)
|
||||
description = "Graphics mode failed";
|
||||
else if (result == DISP_CHANGE_NOTUPDATED)
|
||||
description = "Failed to write to registry";
|
||||
else if (result == DISP_CHANGE_RESTART)
|
||||
description = "Computer restart required";
|
||||
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Failed to set video mode: %s",
|
||||
description);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the previously saved (original) video mode
|
||||
//
|
||||
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor)
|
||||
{
|
||||
if (monitor->win32.modeChanged)
|
||||
{
|
||||
ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||
NULL, NULL, CDS_FULLSCREEN, NULL);
|
||||
monitor->win32.modeChanged = GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale)
|
||||
{
|
||||
UINT xdpi, ydpi;
|
||||
|
||||
if (xscale)
|
||||
*xscale = 0.f;
|
||||
if (yscale)
|
||||
*yscale = 0.f;
|
||||
|
||||
if (IsWindows8Point1OrGreater())
|
||||
{
|
||||
if (GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi) != S_OK)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to query monitor DPI");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const HDC dc = GetDC(NULL);
|
||||
xdpi = GetDeviceCaps(dc, LOGPIXELSX);
|
||||
ydpi = GetDeviceCaps(dc, LOGPIXELSY);
|
||||
ReleaseDC(NULL, dc);
|
||||
}
|
||||
|
||||
if (xscale)
|
||||
*xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
if (yscale)
|
||||
*yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwFreeMonitorWin32(_GLFWmonitor* monitor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
{
|
||||
DEVMODEW dm;
|
||||
ZeroMemory(&dm, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
|
||||
EnumDisplaySettingsExW(monitor->win32.adapterName,
|
||||
ENUM_CURRENT_SETTINGS,
|
||||
&dm,
|
||||
EDS_ROTATEDMODE);
|
||||
|
||||
if (xpos)
|
||||
*xpos = dm.dmPosition.x;
|
||||
if (ypos)
|
||||
*ypos = dm.dmPosition.y;
|
||||
}
|
||||
|
||||
void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
_glfwGetHMONITORContentScaleWin32(monitor->win32.handle, xscale, yscale);
|
||||
}
|
||||
|
||||
void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
|
||||
int* xpos, int* ypos,
|
||||
int* width, int* height)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfoW(monitor->win32.handle, &mi);
|
||||
|
||||
if (xpos)
|
||||
*xpos = mi.rcWork.left;
|
||||
if (ypos)
|
||||
*ypos = mi.rcWork.top;
|
||||
if (width)
|
||||
*width = mi.rcWork.right - mi.rcWork.left;
|
||||
if (height)
|
||||
*height = mi.rcWork.bottom - mi.rcWork.top;
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwGetVideoModesWin32(_GLFWmonitor* monitor, int* count)
|
||||
{
|
||||
int modeIndex = 0, size = 0;
|
||||
GLFWvidmode* result = NULL;
|
||||
|
||||
*count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i;
|
||||
GLFWvidmode mode;
|
||||
DEVMODEW dm;
|
||||
|
||||
ZeroMemory(&dm, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
|
||||
if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm))
|
||||
break;
|
||||
|
||||
modeIndex++;
|
||||
|
||||
// Skip modes with less than 15 BPP
|
||||
if (dm.dmBitsPerPel < 15)
|
||||
continue;
|
||||
|
||||
mode.width = dm.dmPelsWidth;
|
||||
mode.height = dm.dmPelsHeight;
|
||||
mode.refreshRate = dm.dmDisplayFrequency;
|
||||
_glfwSplitBPP(dm.dmBitsPerPel,
|
||||
&mode.redBits,
|
||||
&mode.greenBits,
|
||||
&mode.blueBits);
|
||||
|
||||
for (i = 0; i < *count; i++)
|
||||
{
|
||||
if (_glfwCompareVideoModes(result + i, &mode) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip duplicate modes
|
||||
if (i < *count)
|
||||
continue;
|
||||
|
||||
if (monitor->win32.modesPruned)
|
||||
{
|
||||
// Skip modes not supported by the connected displays
|
||||
if (ChangeDisplaySettingsExW(monitor->win32.adapterName,
|
||||
&dm,
|
||||
NULL,
|
||||
CDS_TEST,
|
||||
NULL) != DISP_CHANGE_SUCCESSFUL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (*count == size)
|
||||
{
|
||||
size += 128;
|
||||
result = (GLFWvidmode*) _glfw_realloc(result, size * sizeof(GLFWvidmode));
|
||||
}
|
||||
|
||||
(*count)++;
|
||||
result[*count - 1] = mode;
|
||||
}
|
||||
|
||||
if (!*count)
|
||||
{
|
||||
// HACK: Report the current mode if no valid modes were found
|
||||
result = _glfw_calloc(1, sizeof(GLFWvidmode));
|
||||
_glfwGetVideoModeWin32(monitor, result);
|
||||
*count = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void _glfwGetVideoModeWin32(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
{
|
||||
DEVMODEW dm;
|
||||
ZeroMemory(&dm, sizeof(dm));
|
||||
dm.dmSize = sizeof(dm);
|
||||
|
||||
EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm);
|
||||
|
||||
mode->width = dm.dmPelsWidth;
|
||||
mode->height = dm.dmPelsHeight;
|
||||
mode->refreshRate = dm.dmDisplayFrequency;
|
||||
_glfwSplitBPP(dm.dmBitsPerPel,
|
||||
&mode->redBits,
|
||||
&mode->greenBits,
|
||||
&mode->blueBits);
|
||||
}
|
||||
|
||||
GLFWbool _glfwGetGammaRampWin32(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
HDC dc;
|
||||
WORD values[3][256];
|
||||
|
||||
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
|
||||
GetDeviceGammaRamp(dc, values);
|
||||
DeleteDC(dc);
|
||||
|
||||
_glfwAllocGammaArrays(ramp, 256);
|
||||
|
||||
memcpy(ramp->red, values[0], sizeof(values[0]));
|
||||
memcpy(ramp->green, values[1], sizeof(values[1]));
|
||||
memcpy(ramp->blue, values[2], sizeof(values[2]));
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
HDC dc;
|
||||
WORD values[3][256];
|
||||
|
||||
if (ramp->size != 256)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Win32: Gamma ramp size must be 256");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(values[0], ramp->red, sizeof(values[0]));
|
||||
memcpy(values[1], ramp->green, sizeof(values[1]));
|
||||
memcpy(values[2], ramp->blue, sizeof(values[2]));
|
||||
|
||||
dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL);
|
||||
SetDeviceGammaRamp(dc, values);
|
||||
DeleteDC(dc);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SSCAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->win32.publicAdapterName;
|
||||
}
|
||||
|
||||
SSCAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return monitor->win32.publicDisplayName;
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(GLFW_BUILD_WIN32_THREAD)
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
|
||||
{
|
||||
assert(tls->win32.allocated == GLFW_FALSE);
|
||||
|
||||
tls->win32.index = TlsAlloc();
|
||||
if (tls->win32.index == TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to allocate TLS index");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
tls->win32.allocated = GLFW_TRUE;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyTls(_GLFWtls* tls)
|
||||
{
|
||||
if (tls->win32.allocated)
|
||||
TlsFree(tls->win32.index);
|
||||
memset(tls, 0, sizeof(_GLFWtls));
|
||||
}
|
||||
|
||||
void* _glfwPlatformGetTls(_GLFWtls* tls)
|
||||
{
|
||||
assert(tls->win32.allocated == GLFW_TRUE);
|
||||
return TlsGetValue(tls->win32.index);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
|
||||
{
|
||||
assert(tls->win32.allocated == GLFW_TRUE);
|
||||
TlsSetValue(tls->win32.index, value);
|
||||
}
|
||||
|
||||
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->win32.allocated == GLFW_FALSE);
|
||||
InitializeCriticalSection(&mutex->win32.section);
|
||||
return mutex->win32.allocated = GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
if (mutex->win32.allocated)
|
||||
DeleteCriticalSection(&mutex->win32.section);
|
||||
memset(mutex, 0, sizeof(_GLFWmutex));
|
||||
}
|
||||
|
||||
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->win32.allocated == GLFW_TRUE);
|
||||
EnterCriticalSection(&mutex->win32.section);
|
||||
}
|
||||
|
||||
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
|
||||
{
|
||||
assert(mutex->win32.allocated == GLFW_TRUE);
|
||||
LeaveCriticalSection(&mutex->win32.section);
|
||||
}
|
||||
|
||||
#endif // GLFW_BUILD_WIN32_THREAD
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//========================================================================
|
||||
// GLFW 3.4 Win32 - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2002-2006 Marcus Geelnard
|
||||
// Copyright (c) 2006-2017 Camilla Löwy <elmindreda@glfw.org>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
// Please use C89 style variable declarations in this file because VS 2010
|
||||
//========================================================================
|
||||
|
||||
#include "glfw_internal.h"
|
||||
|
||||
#if defined(GLFW_BUILD_WIN32_TIMER)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformInitTimer(void)
|
||||
{
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*) &_glfw.timer.win32.frequency);
|
||||
}
|
||||
|
||||
uint64_t _glfwPlatformGetTimerValue(void)
|
||||
{
|
||||
uint64_t value;
|
||||
QueryPerformanceCounter((LARGE_INTEGER*) &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64_t _glfwPlatformGetTimerFrequency(void)
|
||||
{
|
||||
return _glfw.timer.win32.frequency;
|
||||
}
|
||||
|
||||
#endif // GLFW_BUILD_WIN32_TIMER
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
@@ -18,7 +18,7 @@ Basic functions as a copy of SIMD intrisic function
|
||||
*/
|
||||
|
||||
|
||||
SSGC_API __m128* __cdecl set_m128ptr_default()
|
||||
SSCAPI __m128* __cdecl set_m128ptr_default()
|
||||
{
|
||||
return defaultVecPtr;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
|
||||
|
||||
|
||||
|
||||
SSGC_API _inline void __cdecl transpose2to3(matrix2map* source, matrix3map* target)
|
||||
SSCAPI _inline void __cdecl transpose2to3(matrix2map* source, matrix3map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -13,7 +13,7 @@ SSGC_API _inline void __cdecl transpose2to3(matrix2map* source, matrix3map* targ
|
||||
target->colum[2] = _mm_shuffle_ps(t1, *defaultVecPtr, _MM_SHUFFLE(2, 0, 2, 0));
|
||||
}
|
||||
|
||||
SSGC_API _inline void __cdecl transpose2to4(matrix2map* source, matrix4map* target)
|
||||
SSCAPI _inline void __cdecl transpose2to4(matrix2map* source, matrix4map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -24,7 +24,7 @@ SSGC_API _inline void __cdecl transpose2to4(matrix2map* source, matrix4map* targ
|
||||
target->colum[3] = _mm_shuffle_ps(t1, *defaultVecPtr, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
}
|
||||
|
||||
SSGC_API _inline void __cdecl deinit_mat2(matrix2map* mat)
|
||||
SSCAPI _inline void __cdecl deinit_mat2(matrix2map* mat)
|
||||
{
|
||||
_aligned_free(mat);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
#include <stdio.h>
|
||||
|
||||
SSGC_API __inline void _cdecl transpose3to2(matrix3map* source, matrix2map* target)
|
||||
SSCAPI __inline void _cdecl transpose3to2(matrix3map* source, matrix2map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t2 = _mm_shuffle_ps(ALIGN(source->m[0][2]), *defaultVecPtr, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
@@ -12,7 +12,7 @@ SSGC_API __inline void _cdecl transpose3to2(matrix3map* source, matrix2map* targ
|
||||
target->colum[1] = _mm_shuffle_ps(t0, t2, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
}
|
||||
|
||||
SSGC_API __inline void _cdecl transpose3to3(matrix3map* source, matrix3map* target)
|
||||
SSCAPI __inline void _cdecl transpose3to3(matrix3map* source, matrix3map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -25,7 +25,7 @@ SSGC_API __inline void _cdecl transpose3to3(matrix3map* source, matrix3map* targ
|
||||
}
|
||||
|
||||
|
||||
SSGC_API __inline void _cdecl transpose3to4(matrix3map* source, matrix4map* target)
|
||||
SSCAPI __inline void _cdecl transpose3to4(matrix3map* source, matrix4map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->m[0][0]), ALIGN(source->m[0][1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -38,7 +38,7 @@ SSGC_API __inline void _cdecl transpose3to4(matrix3map* source, matrix4map* targ
|
||||
target->colum[3] = _mm_shuffle_ps(t1, t3, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
}
|
||||
|
||||
SSGC_API _inline float _cdecl det_mat3_internal(__m128 const c0, __m128 const c1, __m128 const c2)
|
||||
SSCAPI _inline float _cdecl det_mat3_internal(__m128 const c0, __m128 const c1, __m128 const c2)
|
||||
{
|
||||
|
||||
//let adding row aligned
|
||||
@@ -67,7 +67,7 @@ SSGC_API _inline float _cdecl det_mat3_internal(__m128 const c0, __m128 const c1
|
||||
return ret.m128_f32[2];
|
||||
}
|
||||
|
||||
SSGC_API _inline float _cdecl det_mat3(matrix3map* mat)
|
||||
SSCAPI _inline float _cdecl det_mat3(matrix3map* mat)
|
||||
{
|
||||
return det_mat3_internal(
|
||||
mat->colum[0],
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "StgSharpGraphic.h"
|
||||
#include "StgSharpC.h"
|
||||
#include <stdio.h>
|
||||
#include <pmmintrin.h>
|
||||
|
||||
|
||||
|
||||
|
||||
SSGC_API __inline void __cdecl transpose4to2(matrix4map* source, matrix4map* target)
|
||||
SSCAPI __inline void __cdecl transpose4to2(matrix4map* source, matrix4map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->colum[0]), ALIGN(source->colum[1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t2 = _mm_shuffle_ps(ALIGN(source->colum[2]), ALIGN(source->colum[3]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
@@ -14,7 +14,7 @@ SSGC_API __inline void __cdecl transpose4to2(matrix4map* source, matrix4map* tar
|
||||
target->colum[1] = _mm_shuffle_ps(t0, t2, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
}
|
||||
|
||||
SSGC_API __inline void __cdecl transpose4to4(matrix4map* source, matrix4map* target)
|
||||
SSCAPI __inline void __cdecl transpose4to4(matrix4map* source, matrix4map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->colum[0]), ALIGN(source->colum[1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->colum[0]), ALIGN(source->colum[1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -28,7 +28,7 @@ SSGC_API __inline void __cdecl transpose4to4(matrix4map* source, matrix4map* tar
|
||||
|
||||
}
|
||||
|
||||
SSGC_API __inline void __cdecl transpose4to3(matrix4map* source, matrix3map* target)
|
||||
SSCAPI __inline void __cdecl transpose4to3(matrix4map* source, matrix3map* target)
|
||||
{
|
||||
__m128 t0 = _mm_shuffle_ps(ALIGN(source->colum[0]), ALIGN(source->colum[1]), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 t1 = _mm_shuffle_ps(ALIGN(source->colum[0]), ALIGN(source->colum[1]), _MM_SHUFFLE(3, 2, 3, 2));
|
||||
@@ -43,7 +43,7 @@ SSGC_API __inline void __cdecl transpose4to3(matrix4map* source, matrix3map* tar
|
||||
|
||||
|
||||
|
||||
SSGC_API __inline float __cdecl det_mat4(matrix4map* matPtr, matrix4map* transpose)
|
||||
SSCAPI __inline float __cdecl det_mat4(matrix4map* matPtr, matrix4map* transpose)
|
||||
{
|
||||
__m128 mc0 = ALIGN(matPtr->colum[0]);
|
||||
__m128 mc1 = ALIGN(matPtr->colum[1]);
|
||||
@@ -63,7 +63,7 @@ SSGC_API __inline float __cdecl det_mat4(matrix4map* matPtr, matrix4map* transpo
|
||||
|
||||
}
|
||||
|
||||
SSGC_API __inline void __cdecl deinit_mat4(matrix4map* matPtr)
|
||||
SSCAPI __inline void __cdecl deinit_mat4(matrix4map* matPtr)
|
||||
{
|
||||
_aligned_free(matPtr);
|
||||
}
|
||||
Reference in New Issue
Block a user