mirror of
https://github.com/raysan5/raylib.git
synced 2026-09-25 23:08:22 +00:00
Merge branch 'master' into window-visibility
This commit is contained in:
+3
-4
@@ -47,12 +47,11 @@ add_definitions("-DRAYLIB_CMAKE=1")
|
||||
if(USE_AUDIO)
|
||||
file(GLOB mini_al external/mini_al.c)
|
||||
MESSAGE(STATUS "Audio Backend: mini_al")
|
||||
file(GLOB stb_vorbis external/stb_vorbis.c)
|
||||
set(sources ${raylib_sources} ${mini_al} ${stb_vorbis})
|
||||
set(sources ${raylib_sources} ${mini_al})
|
||||
else()
|
||||
MESSAGE(STATUS "Audio Backend: None (-DUSE_AUDIO=OFF)")
|
||||
set(INCLUDE_AUDIO_MODULE 0)
|
||||
list(REMOVE_ITEM raylib_sources ${CMAKE_CURRENT_SOURCE_DIR}/audio.c)
|
||||
list(REMOVE_ITEM raylib_sources ${CMAKE_CURRENT_SOURCE_DIR}/raudio.c)
|
||||
set(sources ${raylib_sources})
|
||||
endif()
|
||||
|
||||
@@ -251,7 +250,7 @@ file(COPY "raylib.h" DESTINATION ".")
|
||||
file(COPY "rlgl.h" DESTINATION ".")
|
||||
file(COPY "physac.h" DESTINATION ".")
|
||||
file(COPY "raymath.h" DESTINATION ".")
|
||||
file(COPY "audio.h" DESTINATION ".")
|
||||
file(COPY "raudio.h" DESTINATION ".")
|
||||
|
||||
# Print the flags for the user
|
||||
message(STATUS "Compiling with the flags:")
|
||||
|
||||
@@ -61,7 +61,7 @@ option(SUPPORT_FILEFORMAT_OBJ "Support loading OBJ file format" ON)
|
||||
option(SUPPORT_FILEFORMAT_MTL "Support loading MTL file format" ON)
|
||||
option(SUPPORT_MESH_GENERATION "Support procedural mesh generation functions, uses external par_shapes.h library. NOTE: Some generated meshes DO NOT include generated texture coordinates" ON)
|
||||
|
||||
# audio.c
|
||||
# raudio.c
|
||||
option(SUPPORT_FILEFORMAT_WAV "Support loading WAV for sound" ON)
|
||||
option(SUPPORT_FILEFORMAT_OGG "Support loading OGG for sound" ON)
|
||||
option(SUPPORT_FILEFORMAT_XM "Support loading XM for sound" ON)
|
||||
|
||||
+7
-12
@@ -149,8 +149,8 @@ endif
|
||||
ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
# Emscripten required variables
|
||||
EMSDK_PATH = C:/emsdk
|
||||
EMSCRIPTEN_VERSION = 1.38.20
|
||||
CLANG_VERSION = e1.38.20_64bit
|
||||
EMSCRIPTEN_VERSION ?= 1.38.21
|
||||
CLANG_VERSION = e$(EMSCRIPTEN_VERSION)_64bit
|
||||
PYTHON_VERSION = 2.7.13.1_64bit\python-2.7.13.amd64
|
||||
NODE_VERSION = 8.9.1_64bit
|
||||
export PATH = $(EMSDK_PATH);$(EMSDK_PATH)\clang\$(CLANG_VERSION);$(EMSDK_PATH)\node\$(NODE_VERSION)\bin;$(EMSDK_PATH)\python\$(PYTHON_VERSION);$(EMSDK_PATH)\emscripten\$(EMSCRIPTEN_VERSION);C:\raylib\MinGW\bin:$$(PATH)
|
||||
@@ -300,7 +300,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
|
||||
# -s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing
|
||||
# -s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB)
|
||||
# -s USE_PTHREADS=1 # multithreading support
|
||||
CFLAGS += -s USE_GLFW=3 -s USE_SDL=2 -s ASSERTIONS=1 --profiling
|
||||
CFLAGS += -s USE_GLFW=3 -s ASSERTIONS=1 --profiling
|
||||
endif
|
||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||
# Compiler flags for arquitecture
|
||||
@@ -403,8 +403,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
|
||||
endif
|
||||
|
||||
ifeq ($(INCLUDE_AUDIO_MODULE),TRUE)
|
||||
OBJS += audio.o
|
||||
OBJS += stb_vorbis.o
|
||||
OBJS += raudio.o
|
||||
OBJS += mini_al.o
|
||||
endif
|
||||
|
||||
@@ -530,17 +529,13 @@ models.o : models.c raylib.h rlgl.h raymath.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) -D$(GRAPHICS)
|
||||
|
||||
# Compile audio module
|
||||
audio.o : audio.c raylib.h
|
||||
raudio.o : raudio.c raylib.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
|
||||
|
||||
# Compile mini_al audio library
|
||||
mini_al.o : external/mini_al.c external/mini_al.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
|
||||
|
||||
# Compile stb_vorbis library
|
||||
stb_vorbis.o: external/stb_vorbis.c external/stb_vorbis.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
|
||||
|
||||
# Compile utils module
|
||||
utils.o : utils.c utils.h
|
||||
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
|
||||
@@ -628,9 +623,9 @@ endif
|
||||
# Clean everything
|
||||
clean:
|
||||
ifeq ($(PLATFORM_OS),WINDOWS)
|
||||
del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so external/stb_vorbis.o
|
||||
del *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so
|
||||
else
|
||||
rm -fv *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so* external/stb_vorbis.o
|
||||
rm -fv *.o $(RAYLIB_RELEASE_PATH)/libraylib.a $(RAYLIB_RELEASE_PATH)/libraylib.bc $(RAYLIB_RELEASE_PATH)/libraylib.so*
|
||||
endif
|
||||
ifeq ($(PLATFORM),PLATFORM_ANDROID)
|
||||
rm -rf $(ANDROID_TOOLCHAIN)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#define RAYLIB_VERSION "2.2-dev"
|
||||
#define RAYLIB_VERSION "2.4-dev"
|
||||
|
||||
// Edit to control what features Makefile'd raylib is compiled with
|
||||
#if defined(RAYLIB_CMAKE)
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@
|
||||
* NOTE: Some generated meshes DO NOT include generated texture coordinates */
|
||||
#cmakedefine SUPPORT_MESH_GENERATION 1
|
||||
|
||||
// audio.c
|
||||
// raudio.c
|
||||
/* Desired fileformats to be supported for loading. */
|
||||
#cmakedefine SUPPORT_FILEFORMAT_WAV 1
|
||||
#cmakedefine SUPPORT_FILEFORMAT_OGG 1
|
||||
|
||||
+96
-75
@@ -175,11 +175,9 @@
|
||||
#include <GLFW/glfw3native.h> // Required for: glfwGetX11Window()
|
||||
#elif defined(__APPLE__)
|
||||
#include <unistd.h> // Required for: usleep()
|
||||
#include <objc/message.h> // Required for: objc_msgsend(), sel_registerName()
|
||||
|
||||
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
|
||||
#define GLFW_EXPOSE_NATIVE_NSGL
|
||||
#include <GLFW/glfw3native.h> // Required for: glfwGetCocoaWindow(), glfwGetNSGLContext()
|
||||
#include <GLFW/glfw3native.h> // Required for: glfwGetCocoaWindow()
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -277,10 +275,6 @@ static bool windowReady = false; // Check if window has been init
|
||||
static bool windowMinimized = false; // Check if window has been minimized
|
||||
static const char *windowTitle = NULL; // Window text title...
|
||||
|
||||
#if defined(__APPLE__)
|
||||
static int windowNeedsUpdating = 2; // Times the Cocoa window needs to be updated initially
|
||||
#endif
|
||||
|
||||
static unsigned int displayWidth, displayHeight;// Display width and height (monitor, device-screen, LCD, ...)
|
||||
static int screenWidth, screenHeight; // Screen width and height (used render area)
|
||||
static int renderWidth, renderHeight; // Framebuffer width and height (render area, including black bars if required)
|
||||
@@ -311,7 +305,7 @@ extern EGLNativeWindowType uwpWindow; // Native EGL window handler for
|
||||
static struct android_app *androidApp; // Android activity
|
||||
static struct android_poll_source *source; // Android events polling source
|
||||
static int ident, events; // Android ALooper_pollAll() variables
|
||||
static const char *internalDataPath; // Android internal data path to write data (/data/data/<package>/files)
|
||||
static const char *internalDataPath = NULL; // Android internal data path to write data (/data/data/<package>/files)
|
||||
|
||||
static bool appEnabled = true; // Used to detec if app is active
|
||||
static bool contextRebindRequired = false; // Used to know context rebind required
|
||||
@@ -332,8 +326,9 @@ static int defaultKeyboardMode; // Used to store default keyboar
|
||||
#endif
|
||||
|
||||
// Mouse states
|
||||
static Vector2 mousePosition; // Mouse position on screen
|
||||
static float mouseScale = 1.0f; // Mouse default scale
|
||||
static Vector2 mousePosition = { 0.0f, 0.0f }; // Mouse position on screen
|
||||
static Vector2 mouseScale = { 1.0f, 1.0f }; // Mouse scaling
|
||||
static Vector2 mouseOffset = { 0.0f, 0.0f }; // Mouse offset
|
||||
static bool cursorHidden = false; // Track if cursor is hidden
|
||||
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
|
||||
static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen
|
||||
@@ -1485,12 +1480,6 @@ Color Fade(Color color, float alpha)
|
||||
return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
|
||||
}
|
||||
|
||||
// Activate raylib logo at startup (can be done with flags)
|
||||
void ShowLogo(void)
|
||||
{
|
||||
showLogo = true;
|
||||
}
|
||||
|
||||
// Setup window configuration flags (view FLAGS)
|
||||
void SetConfigFlags(unsigned char flags)
|
||||
{
|
||||
@@ -1503,17 +1492,32 @@ void SetConfigFlags(unsigned char flags)
|
||||
// NOTE TraceLog() function is located in [utils.h]
|
||||
|
||||
// Takes a screenshot of current screen (saved a .png)
|
||||
// NOTE: This function could work in any platform but some platforms: PLATFORM_ANDROID and PLATFORM_WEB
|
||||
// have their own internal file-systems, to dowload image to user file-system some additional mechanism is required
|
||||
void TakeScreenshot(const char *fileName)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
|
||||
unsigned char *imgData = rlReadScreenPixels(renderWidth, renderHeight);
|
||||
|
||||
Image image = { imgData, renderWidth, renderHeight, 1, UNCOMPRESSED_R8G8B8A8 };
|
||||
ExportImage(image, fileName);
|
||||
free(imgData);
|
||||
|
||||
TraceLog(LOG_INFO, "Screenshot taken: %s", fileName);
|
||||
|
||||
char path[512] = { 0 };
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
strcpy(path, internalDataPath);
|
||||
strcat(path, "/");
|
||||
strcat(path, fileName);
|
||||
#else
|
||||
strcpy(path, fileName);
|
||||
#endif
|
||||
|
||||
ExportImage(image, path);
|
||||
free(imgData);
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
// Download file from MEMFS (emscripten memory filesystem)
|
||||
// SaveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html
|
||||
emscripten_run_script(TextFormat("SaveFileFromMEMFSToDisk('%s','%s')", GetFileName(path), GetFileName(path)));
|
||||
#endif
|
||||
|
||||
TraceLog(LOG_INFO, "Screenshot taken: %s", path);
|
||||
}
|
||||
|
||||
// Check if the file exists
|
||||
@@ -1522,11 +1526,10 @@ bool FileExists(const char *fileName)
|
||||
bool result = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (_access(fileName, 0) != -1)
|
||||
if (_access(fileName, 0) != -1) result = true;
|
||||
#else
|
||||
if (access(fileName, F_OK) != -1)
|
||||
if (access(fileName, F_OK) != -1) result = true;
|
||||
#endif
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1539,7 +1542,7 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||
|
||||
if ((fileExt = strrchr(fileName, '.')) != NULL)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
result = true;
|
||||
int extLen = strlen(ext);
|
||||
|
||||
@@ -1555,9 +1558,9 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||
}
|
||||
}
|
||||
else result = false;
|
||||
#else
|
||||
#else
|
||||
if (strcmp(fileExt, ext) == 0) result = true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1759,7 +1762,7 @@ void StorageSaveValue(int position, int value)
|
||||
{
|
||||
FILE *storageFile = NULL;
|
||||
|
||||
char path[128];
|
||||
char path[512] = { 0 };
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
strcpy(path, internalDataPath);
|
||||
strcat(path, "/");
|
||||
@@ -1799,7 +1802,7 @@ int StorageLoadValue(int position)
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
char path[128];
|
||||
char path[512] = { 0 };
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
strcpy(path, internalDataPath);
|
||||
strcat(path, "/");
|
||||
@@ -1844,7 +1847,9 @@ void OpenURL(const char *url)
|
||||
if (strchr(url, '\'') != NULL)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "Provided URL does not seem to be valid.");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cmd = calloc(strlen(url) + 10, sizeof(char));
|
||||
|
||||
#if defined(_WIN32)
|
||||
@@ -2100,7 +2105,7 @@ int GetMouseX(void)
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
return (int)touchPosition[0].x;
|
||||
#else
|
||||
return (int)(mousePosition.x*mouseScale);
|
||||
return (int)((mousePosition.x + mouseOffset.x)*mouseScale.x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2110,7 +2115,7 @@ int GetMouseY(void)
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
return (int)touchPosition[0].x;
|
||||
#else
|
||||
return (int)(mousePosition.y*mouseScale);
|
||||
return (int)((mousePosition.y + mouseOffset.y)*mouseScale.y);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2120,27 +2125,32 @@ Vector2 GetMousePosition(void)
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
return GetTouchPosition(0);
|
||||
#else
|
||||
return (Vector2){ mousePosition.x*mouseScale, mousePosition.y*mouseScale };
|
||||
return (Vector2){ (mousePosition.x + mouseOffset.x)*mouseScale.x, (mousePosition.y + mouseOffset.y)*mouseScale.y };
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set mouse position XY
|
||||
void SetMousePosition(Vector2 position)
|
||||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
mousePosition = position;
|
||||
mousePosition = (Vector2){ (float)x, (float)y };
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
// NOTE: emscripten not implemented
|
||||
glfwSetCursorPos(window, position.x, position.y);
|
||||
glfwSetCursorPos(window, mousePosition.x, mousePosition.y);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set mouse offset
|
||||
// NOTE: Useful when rendering to different size targets
|
||||
void SetMouseOffset(int offsetX, int offsetY)
|
||||
{
|
||||
mouseOffset = (Vector2){ (float)offsetX, (float)offsetY };
|
||||
}
|
||||
|
||||
// Set mouse scaling
|
||||
// NOTE: Useful when rendering to different size targets
|
||||
void SetMouseScale(float scale)
|
||||
void SetMouseScale(float scaleX, float scaleY)
|
||||
{
|
||||
#if !defined(PLATFORM_ANDROID)
|
||||
mouseScale = scale;
|
||||
#endif
|
||||
mouseScale = (Vector2){ scaleX, scaleY };
|
||||
}
|
||||
|
||||
// Returns mouse wheel movement Y
|
||||
@@ -2278,8 +2288,8 @@ static bool InitGraphicsDevice(int width, int height)
|
||||
if (configFlags & FLAG_WINDOW_RESIZABLE) glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window
|
||||
else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
|
||||
|
||||
if (configFlags & FLAG_WINDOW_UNDECORATED) glfwWindowHint(GLFW_DECORATED, GL_FALSE); // Border and buttons on Window
|
||||
else glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Decorated window
|
||||
if (configFlags & FLAG_WINDOW_UNDECORATED) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
|
||||
else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window
|
||||
// FLAG_WINDOW_TRANSPARENT not supported on HTML5 and not included in any released GLFW version yet
|
||||
#if defined(GLFW_TRANSPARENT_FRAMEBUFFER)
|
||||
if (configFlags & FLAG_WINDOW_TRANSPARENT) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
|
||||
@@ -2295,21 +2305,28 @@ static bool InitGraphicsDevice(int width, int height)
|
||||
// Check selection OpenGL version
|
||||
if (rlGetVersion() == OPENGL_21)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); // Choose OpenGL minor version (just hint)
|
||||
}
|
||||
else if (rlGetVersion() == OPENGL_33)
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
|
||||
// Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
|
||||
#if defined(__APPLE__)
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires fordward compatibility
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // OSX Requires fordward compatibility
|
||||
#else
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above!
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_FALSE); // Fordward Compatibility Hint: Only 3.3 and above!
|
||||
#endif
|
||||
//glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); // Request OpenGL DEBUG context
|
||||
//glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
|
||||
}
|
||||
else if (rlGetVersion() == OPENGL_ES_20) // Request OpenGL ES 2.0 context
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); // Alternative: GLFW_EGL_CONTEXT_API (ANGLE)
|
||||
}
|
||||
|
||||
if (fullscreen)
|
||||
@@ -2402,7 +2419,9 @@ static bool InitGraphicsDevice(int width, int height)
|
||||
|
||||
// Try to disable GPU V-Sync by default, set framerate using SetTargetFPS()
|
||||
// NOTE: V-Sync can be enabled by graphic driver configuration
|
||||
#if !defined(PLATFORM_WEB)
|
||||
glfwSwapInterval(0);
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
// Load OpenGL 3.3 extensions
|
||||
@@ -3138,16 +3157,6 @@ static void SwapBuffers(void)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
glfwSwapBuffers(window);
|
||||
#if __APPLE__
|
||||
// Workaround for missing/erroneous initial rendering on macOS
|
||||
if (windowNeedsUpdating)
|
||||
{
|
||||
// Desugared version of Objective C: [glfwGetNSGLContext(window) update]
|
||||
((id (*)(id, SEL))objc_msgSend)(glfwGetNSGLContext(window), sel_registerName("update"));
|
||||
|
||||
windowNeedsUpdating--;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_UWP)
|
||||
@@ -3173,20 +3182,25 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
|
||||
{
|
||||
if (key == exitKey && action == GLFW_PRESS)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
|
||||
// NOTE: Before closing window, while loop must be left!
|
||||
}
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
else if (key == GLFW_KEY_F12 && action == GLFW_PRESS)
|
||||
{
|
||||
#if defined(SUPPORT_GIF_RECORDING)
|
||||
#if defined(SUPPORT_GIF_RECORDING)
|
||||
if (mods == GLFW_MOD_CONTROL)
|
||||
{
|
||||
if (gifRecording)
|
||||
{
|
||||
GifEnd();
|
||||
gifRecording = false;
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
// Download file from MEMFS (emscripten memory filesystem)
|
||||
// SaveFileFromMEMFSToDisk() function is defined in raylib/templates/web_shel/shell.html
|
||||
emscripten_run_script(TextFormat("SaveFileFromMEMFSToDisk('%s','%s')", TextFormat("screenrec%03i.gif", screenshotCounter - 1), TextFormat("screenrec%03i.gif", screenshotCounter - 1)));
|
||||
#endif
|
||||
|
||||
TraceLog(LOG_INFO, "End animated GIF recording");
|
||||
}
|
||||
@@ -3194,25 +3208,32 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
|
||||
{
|
||||
gifRecording = true;
|
||||
gifFramesCounter = 0;
|
||||
|
||||
char path[512] = { 0 };
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
strcpy(path, internalDataPath);
|
||||
strcat(path, TextFormat("/screenrec%03i.gif", screenshotCounter));
|
||||
#else
|
||||
strcpy(path, TextFormat("/screenrec%03i.gif", screenshotCounter));
|
||||
#endif
|
||||
|
||||
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
|
||||
// 10 game frames and each frame trakes 16.6ms (60fps), delay between gif frames should be ~16.6*10.
|
||||
GifBegin(FormatText("screenrec%03i.gif", screenshotCounter), screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false);
|
||||
GifBegin(path, screenWidth, screenHeight, (int)(GetFrameTime()*10.0f), 8, false);
|
||||
screenshotCounter++;
|
||||
|
||||
TraceLog(LOG_INFO, "Begin animated GIF recording: %s", FormatText("screenrec%03i.gif", screenshotCounter));
|
||||
TraceLog(LOG_INFO, "Begin animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // SUPPORT_GIF_RECORDING
|
||||
#if defined(SUPPORT_SCREEN_CAPTURE)
|
||||
#endif // SUPPORT_GIF_RECORDING
|
||||
#if defined(SUPPORT_SCREEN_CAPTURE)
|
||||
{
|
||||
TakeScreenshot(FormatText("screenshot%03i.png", screenshotCounter));
|
||||
TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
|
||||
screenshotCounter++;
|
||||
}
|
||||
#endif // SUPPORT_SCREEN_CAPTURE
|
||||
#endif // SUPPORT_SCREEN_CAPTURE
|
||||
}
|
||||
#endif // PLATFORM_DESKTOP
|
||||
else
|
||||
{
|
||||
currentKeyState[key] = action;
|
||||
@@ -3394,11 +3415,11 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
// Init hi-res timer
|
||||
InitTimer();
|
||||
|
||||
#if defined(SUPPORT_DEFAULT_FONT)
|
||||
#if defined(SUPPORT_DEFAULT_FONT)
|
||||
// Load default font
|
||||
// NOTE: External function (defined in module: text)
|
||||
LoadDefaultFont();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO: GPU assets reload in case of lost focus (lost context)
|
||||
// NOTE: This problem has been solved just unbinding and rebinding context from display
|
||||
@@ -4246,10 +4267,10 @@ static void *EventThread(void *arg)
|
||||
|
||||
// Screen confinement
|
||||
if (mousePosition.x < 0) mousePosition.x = 0;
|
||||
if (mousePosition.x > screenWidth/mouseScale) mousePosition.x = screenWidth/mouseScale;
|
||||
if (mousePosition.x > screenWidth/mouseScale.x) mousePosition.x = screenWidth/mouseScale.x;
|
||||
|
||||
if (mousePosition.y < 0) mousePosition.y = 0;
|
||||
if (mousePosition.y > screenHeight/mouseScale) mousePosition.y = screenHeight/mouseScale;
|
||||
if (mousePosition.y > screenHeight/mouseScale.y) mousePosition.y = screenHeight/mouseScale.y;
|
||||
|
||||
// Gesture update
|
||||
if (GestureNeedsUpdate)
|
||||
@@ -4475,7 +4496,7 @@ static void LogoAnimation(void)
|
||||
|
||||
DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
|
||||
|
||||
DrawText(SubText("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
|
||||
DrawText(TextSubtext("raylib", 0, lettersCount), screenWidth/2 - 44, screenHeight/2 + 48, 50, Fade(BLACK, alpha));
|
||||
}
|
||||
|
||||
EndDrawing();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
glfw/docs/
|
||||
glfw/examples/
|
||||
glfw/tests/
|
||||
Vendored
+1
-1
@@ -65,7 +65,7 @@ script:
|
||||
sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb;
|
||||
git clone git://anongit.freedesktop.org/wayland/wayland-protocols;
|
||||
pushd wayland-protocols;
|
||||
git checkout 1.12 && ./autogen.sh --prefix=/usr && make && sudo make install;
|
||||
git checkout 1.15 && ./autogen.sh --prefix=/usr && make && sudo make install;
|
||||
popd;
|
||||
fi
|
||||
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} ..
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
# FindMir
|
||||
# -------
|
||||
# Finds the Mir library
|
||||
#
|
||||
# This will will define the following variables::
|
||||
#
|
||||
# MIR_FOUND - the system has Mir
|
||||
# MIR_INCLUDE_DIRS - the Mir include directory
|
||||
# MIR_LIBRARIES - the Mir libraries
|
||||
# MIR_DEFINITIONS - the Mir definitions
|
||||
|
||||
|
||||
find_package (PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules (PC_MIR mirclient>=0.26.2 QUIET)
|
||||
|
||||
find_path(MIR_INCLUDE_DIR NAMES mir_toolkit/mir_client_library.h
|
||||
PATHS ${PC_MIR_INCLUDE_DIRS})
|
||||
|
||||
find_library(MIR_LIBRARY NAMES mirclient
|
||||
PATHS ${PC_MIR_LIBRARIES} ${PC_MIR_LIBRARY_DIRS})
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args (MIR
|
||||
REQUIRED_VARS MIR_LIBRARY MIR_INCLUDE_DIR)
|
||||
|
||||
if (MIR_FOUND)
|
||||
set(MIR_LIBRARIES ${MIR_LIBRARY})
|
||||
set(MIR_INCLUDE_DIRS ${PC_MIR_INCLUDE_DIRS})
|
||||
set(MIR_DEFINITIONS -DHAVE_MIR=1)
|
||||
endif()
|
||||
|
||||
mark_as_advanced (MIR_LIBRARY MIR_INCLUDE_DIR)
|
||||
endif()
|
||||
Vendored
+9
-26
@@ -4,7 +4,7 @@ project(GLFW C)
|
||||
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 OFF)
|
||||
|
||||
if (NOT CMAKE_VERSION VERSION_LESS "3.1")
|
||||
if (POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
|
||||
@@ -14,7 +14,6 @@ set(GLFW_VERSION_PATCH "0")
|
||||
set(GLFW_VERSION_EXTRA "")
|
||||
set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}")
|
||||
set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}")
|
||||
set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64")
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
@@ -25,6 +24,8 @@ option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
|
||||
option(GLFW_INSTALL "Generate installation target" ON)
|
||||
option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if (UNIX)
|
||||
option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF)
|
||||
endif()
|
||||
@@ -35,7 +36,6 @@ endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF)
|
||||
option(GLFW_USE_MIR "Use Mir for window creation" OFF)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
@@ -141,9 +141,6 @@ endif()
|
||||
if (GLFW_USE_WAYLAND)
|
||||
set(_GLFW_WAYLAND 1)
|
||||
message(STATUS "Using Wayland for window creation")
|
||||
elseif (GLFW_USE_MIR)
|
||||
set(_GLFW_MIR 1)
|
||||
message(STATUS "Using Mir for window creation")
|
||||
elseif (GLFW_USE_OSMESA)
|
||||
set(_GLFW_OSMESA 1)
|
||||
message(STATUS "Using OSMesa for headless context creation")
|
||||
@@ -262,7 +259,7 @@ if (_GLFW_WAYLAND)
|
||||
|
||||
find_package(Wayland REQUIRED Client Cursor Egl)
|
||||
find_package(WaylandScanner REQUIRED)
|
||||
find_package(WaylandProtocols 1.12 REQUIRED)
|
||||
find_package(WaylandProtocols 1.15 REQUIRED)
|
||||
|
||||
list(APPEND glfw_PKG_DEPS "wayland-egl")
|
||||
|
||||
@@ -273,7 +270,9 @@ if (_GLFW_WAYLAND)
|
||||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckFunctionExists)
|
||||
check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H)
|
||||
check_function_exists(memfd_create HAVE_MEMFD_CREATE)
|
||||
|
||||
if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux"))
|
||||
find_package(EpollShim)
|
||||
@@ -284,22 +283,6 @@ if (_GLFW_WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Use Mir for window creation
|
||||
#--------------------------------------------------------------------
|
||||
if (_GLFW_MIR)
|
||||
find_package(Mir REQUIRED)
|
||||
list(APPEND glfw_PKG_DEPS "mirclient")
|
||||
|
||||
list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIRS}")
|
||||
list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}")
|
||||
|
||||
find_package(XKBCommon REQUIRED)
|
||||
list(APPEND glfw_PKG_DEPS "xkbcommon")
|
||||
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
|
||||
list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}")
|
||||
endif()
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Use OSMesa for offscreen context creation
|
||||
#--------------------------------------------------------------------
|
||||
@@ -340,7 +323,7 @@ endforeach()
|
||||
#--------------------------------------------------------------------
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
set(GLFW_CONFIG_PATH "lib${LIB_SUFFIX}/cmake/glfw3")
|
||||
set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/glfw3")
|
||||
|
||||
configure_package_config_file(src/glfw3Config.cmake.in
|
||||
src/glfw3Config.cmake
|
||||
@@ -377,7 +360,7 @@ endif()
|
||||
# The library is installed by src/CMakeLists.txt
|
||||
#--------------------------------------------------------------------
|
||||
if (GLFW_INSTALL)
|
||||
install(DIRECTORY include/GLFW DESTINATION include
|
||||
install(DIRECTORY include/GLFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h)
|
||||
|
||||
install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake"
|
||||
@@ -388,7 +371,7 @@ if (GLFW_INSTALL)
|
||||
EXPORT_LINK_INTERFACE_LIBRARIES
|
||||
DESTINATION "${GLFW_CONFIG_PATH}")
|
||||
install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc"
|
||||
DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
# Only generate this target if no higher-level project already has
|
||||
if (NOT TARGET uninstall)
|
||||
|
||||
Vendored
+23
-2
@@ -11,8 +11,8 @@ application development. It provides a simple, platform-independent API for
|
||||
creating windows, contexts and surfaces, reading input, handling events, etc.
|
||||
|
||||
GLFW natively supports Windows, macOS and Linux and other Unix-like systems.
|
||||
Experimental implementations for the Wayland protocol and the Mir display server
|
||||
are available but not yet officially supported.
|
||||
An experimental implementation for the Wayland protocol is available but not
|
||||
yet officially supported.
|
||||
|
||||
GLFW is licensed under the [zlib/libpng
|
||||
license](http://www.glfw.org/license.html).
|
||||
@@ -167,6 +167,8 @@ information on what to include when reporting a bug.
|
||||
(#749,#842)
|
||||
- Added `GLFW_FOCUS_ON_SHOW` window hint and attribute to control input focus
|
||||
on calling show window (#1189)
|
||||
- Added `GLFW_SCALE_TO_MONITOR` window hint for automatic window resizing
|
||||
(#676,#1115)
|
||||
- Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
|
||||
- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946)
|
||||
- Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint
|
||||
@@ -180,6 +182,10 @@ information on what to include when reporting a bug.
|
||||
- Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with
|
||||
[OSMesa](https://www.mesa3d.org/osmesa.html) (#281)
|
||||
- Added `GenerateMappings.cmake` script for updating gamepad mappings
|
||||
- Export CMake `GLFW_PKG_DEPS` and `GLFW_PKG_LIBS` to parent scope for use
|
||||
in client pkg-configs (#1307)
|
||||
- Added a `glfw_objlib` CMake OBJECT library target for embedding into static
|
||||
libraries (#1307)
|
||||
- Made `glfwCreateWindowSurface` emit an error when the window has a context
|
||||
(#1194,#1205)
|
||||
- Deprecated window parameter of clipboard string functions
|
||||
@@ -195,6 +201,8 @@ information on what to include when reporting a bug.
|
||||
- Bugfix: Invalid library paths were used in test and example CMake files (#930)
|
||||
- Bugfix: The scancode for synthetic key release events was always zero
|
||||
- Bugfix: The generated Doxyfile did not handle paths with spaces (#1081)
|
||||
- Bugfix: The gamma ramp generated by `glfwSetGamma` did not use the monitor
|
||||
ramp size (#1387,#1388)
|
||||
- [Win32] Added system error strings to relevant GLFW error descriptions (#733)
|
||||
- [Win32] Moved to `WM_INPUT` for disabled cursor mode motion input (#125)
|
||||
- [Win32] Removed XInput circular deadzone from joystick axis data (#1045)
|
||||
@@ -221,6 +229,10 @@ information on what to include when reporting a bug.
|
||||
- [Win32] Bugfix: The HID device notification was not unregistered (#1170)
|
||||
- [Win32] Bugfix: `glfwCreateWindow` activated window even with `GLFW_FOCUSED`
|
||||
hint set to false (#1179,#1180)
|
||||
- [Win32] Bugfix: The keypad equals key was reported as `GLFW_KEY_UNKNOWN`
|
||||
(#1315,#1316)
|
||||
- [Win32] Bugfix: A title bar would be drawn over undecorated windows in some
|
||||
circumstances (#1383)
|
||||
- [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125)
|
||||
- [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading
|
||||
- [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X
|
||||
@@ -235,6 +247,8 @@ information on what to include when reporting a bug.
|
||||
- [X11] Bugfix: Selection I/O reported but did not support `COMPOUND_TEXT`
|
||||
- [X11] Bugfix: Latin-1 text read from selections was not converted to UTF-8
|
||||
- [X11] Bugfix: NVidia EGL would segfault if unloaded before closing the display
|
||||
- [X11] Bugfix: Checking window maximized attrib could crash some WMs (#1356)
|
||||
- [X11] Bugfix: Update cursor position on enter event (#1366)
|
||||
- [Linux] Added workaround for missing `SYN_DROPPED` in pre-2.6.39 kernel
|
||||
headers (#1196)
|
||||
- [Linux] Moved to evdev for joystick input (#906,#1005)
|
||||
@@ -267,6 +281,9 @@ information on what to include when reporting a bug.
|
||||
- [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085)
|
||||
- [Cocoa] Bugfix: Duplicate size events were not filtered (#1085)
|
||||
- [Cocoa] Bugfix: Event polling did not initialize AppKit if necessary (#1218)
|
||||
- [Cocoa] Bugfix: OpenGL rendering was not initially visible on 10.14
|
||||
(#1334,#1346)
|
||||
- [Cocoa] Bugfix: Caps Lock did not generate any key events (#1368,#1373)
|
||||
- [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts
|
||||
- [WGL] Added support for `WGL_ARB_create_context_no_error`
|
||||
- [GLX] Added support for `GLX_ARB_create_context_no_error`
|
||||
@@ -304,7 +321,9 @@ skills.
|
||||
- David Avedissian
|
||||
- Keith Bauer
|
||||
- John Bartholomew
|
||||
- Coşku Baş
|
||||
- Niklas Behrens
|
||||
- Andrew Belt
|
||||
- Niklas Bergström
|
||||
- Denis Bernard
|
||||
- Doug Binks
|
||||
@@ -371,6 +390,7 @@ skills.
|
||||
- Glenn Lewis
|
||||
- Shane Liesegang
|
||||
- Eyal Lotem
|
||||
- Aaron Loucks
|
||||
- Tristam MacDonald
|
||||
- Hans Mackowiak
|
||||
- Дмитри Малышев
|
||||
@@ -387,6 +407,7 @@ skills.
|
||||
- Bruce Mitchener
|
||||
- Jack Moffitt
|
||||
- Jeff Molofee
|
||||
- Alexander Monakov
|
||||
- Pierre Morel
|
||||
- Jon Morton
|
||||
- Pierre Moulon
|
||||
|
||||
Vendored
+9621
-7799
File diff suppressed because it is too large
Load Diff
-6
@@ -35,12 +35,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
#include <mir_toolkit/client_types.h>
|
||||
#include "vulkan_mir.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VK_USE_PLATFORM_VI_NN
|
||||
#include "vulkan_vi.h"
|
||||
#endif
|
||||
|
||||
+44
-26
@@ -269,23 +269,22 @@ extern "C" {
|
||||
#define GLFW_VERSION_REVISION 0
|
||||
/*! @} */
|
||||
|
||||
/*! @name Boolean values
|
||||
* @{ */
|
||||
/*! @brief One.
|
||||
*
|
||||
* One. Seriously. You don't _need_ to use this symbol in your code. It's
|
||||
* semantic sugar for the number 1. You can also use `1` or `true` or `_True`
|
||||
* or `GL_TRUE` or whatever you want.
|
||||
* This is only semantic sugar for the number 1. You can instead use `1` or
|
||||
* `true` or `_True` or `GL_TRUE` or anything else that is equal to one.
|
||||
*
|
||||
* @ingroup init
|
||||
*/
|
||||
#define GLFW_TRUE 1
|
||||
/*! @brief Zero.
|
||||
*
|
||||
* Zero. Seriously. You don't _need_ to use this symbol in your code. It's
|
||||
* semantic sugar for the number 0. You can also use `0` or `false` or
|
||||
* `_False` or `GL_FALSE` or whatever you want.
|
||||
* This is only semantic sugar for the number 0. You can instead use `0` or
|
||||
* `false` or `_False` or `GL_FALSE` or anything else that is equal to zero.
|
||||
*
|
||||
* @ingroup init
|
||||
*/
|
||||
#define GLFW_FALSE 0
|
||||
/*! @} */
|
||||
|
||||
/*! @name Key and button actions
|
||||
* @{ */
|
||||
@@ -313,6 +312,7 @@ extern "C" {
|
||||
/*! @} */
|
||||
|
||||
/*! @defgroup hat_state Joystick hat states
|
||||
* @brief Joystick hat states.
|
||||
*
|
||||
* See [joystick hat input](@ref joystick_hat) for how these are used.
|
||||
*
|
||||
@@ -973,6 +973,10 @@ extern "C" {
|
||||
* [attribute](@ref GLFW_CLIENT_API_attrib).
|
||||
*/
|
||||
#define GLFW_CONTEXT_CREATION_API 0x0002200B
|
||||
/*! @brief Window content area scaling window
|
||||
* [window hint](@ref GLFW_SCALE_TO_MONITOR).
|
||||
*/
|
||||
#define GLFW_SCALE_TO_MONITOR 0x0002200C
|
||||
|
||||
#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001
|
||||
#define GLFW_COCOA_FRAME_NAME 0x00023002
|
||||
@@ -1056,9 +1060,20 @@ extern "C" {
|
||||
|
||||
/*! @addtogroup init
|
||||
* @{ */
|
||||
/*! @brief Joystick hat buttons init hint.
|
||||
*
|
||||
* Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS)
|
||||
*/
|
||||
#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001
|
||||
|
||||
/*! @brief macOS specific init hint.
|
||||
*
|
||||
* macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES)
|
||||
*/
|
||||
#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001
|
||||
/*! @brief macOS specific init hint.
|
||||
*
|
||||
* macOS specific [init hint](@ref GLFW_COCOA_MENUBAR)
|
||||
*/
|
||||
#define GLFW_COCOA_MENUBAR 0x00051002
|
||||
/*! @} */
|
||||
|
||||
@@ -1129,7 +1144,7 @@ typedef struct GLFWwindow GLFWwindow;
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup cursor
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef struct GLFWcursor GLFWcursor;
|
||||
|
||||
@@ -1567,6 +1582,8 @@ typedef struct GLFWgammaramp
|
||||
*
|
||||
* @since Added in version 2.1.
|
||||
* @glfw3 Removed format and bytes-per-pixel members.
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
typedef struct GLFWimage
|
||||
{
|
||||
@@ -1589,6 +1606,8 @@ typedef struct GLFWimage
|
||||
* @sa @ref glfwGetGamepadState
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef struct GLFWgamepadstate
|
||||
{
|
||||
@@ -2137,9 +2156,9 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Generates a gamma ramp and sets it for the specified monitor.
|
||||
*
|
||||
* This function generates a 256-element gamma ramp from the specified exponent
|
||||
* and then calls @ref glfwSetGammaRamp with it. The value must be a finite
|
||||
* number greater than zero.
|
||||
* This function generates an appropriately sized gamma ramp from the specified
|
||||
* exponent and then calls @ref glfwSetGammaRamp with it. The value must be
|
||||
* a finite number greater than zero.
|
||||
*
|
||||
* The software controlled gamma ramp is applied _in addition_ to the hardware
|
||||
* gamma correction, which today is usually an approximation of sRGB gamma.
|
||||
@@ -2218,8 +2237,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @remark Gamma ramp sizes other than 256 are not supported by all platforms
|
||||
* or graphics hardware.
|
||||
* @remark The size of the specified gamma ramp should match the size of the
|
||||
* current ramp for that monitor.
|
||||
*
|
||||
* @remark @win32 The gamma ramp size must be 256.
|
||||
*
|
||||
@@ -3758,6 +3777,9 @@ GLFWAPI void glfwWaitEvents(void);
|
||||
*
|
||||
* @param[in] timeout The maximum amount of time, in seconds, to wait.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @reentrancy This function must not be called from a callback.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
@@ -4011,8 +4033,8 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key);
|
||||
* `GLFW_RELEASE`.
|
||||
*
|
||||
* If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function
|
||||
* `GLFW_PRESS` the first time you call it for a mouse button that was pressed,
|
||||
* even if that mouse button has already been released.
|
||||
* returns `GLFW_PRESS` the first time you call it for a mouse button that was
|
||||
* pressed, even if that mouse button has already been released.
|
||||
*
|
||||
* @param[in] window The desired window.
|
||||
* @param[in] button The desired [mouse button](@ref buttons).
|
||||
@@ -4283,9 +4305,7 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
|
||||
* The character callback behaves as system text input normally does and will
|
||||
* not be called if modifier keys are held down that would prevent normal text
|
||||
* input on that platform, for example a Super (Command) key on macOS or Alt key
|
||||
* on Windows. There is a
|
||||
* [character with modifiers callback](@ref glfwSetCharModsCallback) that
|
||||
* receives these events.
|
||||
* on Windows.
|
||||
*
|
||||
* @param[in] window The window whose callback to set.
|
||||
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
|
||||
@@ -4581,7 +4601,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
|
||||
* Each element in the array is one of the following values:
|
||||
*
|
||||
* Name | Value
|
||||
* --------------------- | --------------------------------
|
||||
* ---- | -----
|
||||
* `GLFW_HAT_CENTERED` | 0
|
||||
* `GLFW_HAT_UP` | 1
|
||||
* `GLFW_HAT_RIGHT` | 2
|
||||
@@ -4901,6 +4921,8 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_INVALID_ENUM.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref gamepad
|
||||
* @sa @ref glfwUpdateGamepadMappings
|
||||
* @sa @ref glfwJoystickIsGamepad
|
||||
@@ -4922,8 +4944,6 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @remark @wayland Clipboard is currently unimplemented.
|
||||
*
|
||||
* @pointer_lifetime The specified string is copied before this function
|
||||
* returns.
|
||||
*
|
||||
@@ -4952,8 +4972,6 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @remark @wayland Clipboard is currently unimplemented.
|
||||
*
|
||||
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
|
||||
* should not free it yourself. It is valid until the next call to @ref
|
||||
* glfwGetClipboardString or @ref glfwSetClipboardString, or until the library
|
||||
|
||||
+5
-54
@@ -62,7 +62,6 @@ extern "C" {
|
||||
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||
* * `GLFW_EXPOSE_NATIVE_MIR`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
@@ -82,7 +81,7 @@ extern "C" {
|
||||
* System headers and types
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||
@@ -96,23 +95,19 @@ extern "C" {
|
||||
typedef void *PVOID;
|
||||
typedef PVOID HANDLE;
|
||||
typedef HANDLE HWND;
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
// RAY: Added protection in case OBJC types defined
|
||||
#if !OBJC_TYPES_DEFINED
|
||||
typedef void* id;
|
||||
#endif
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
@@ -426,50 +421,6 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
/*! @brief Returns the `MirConnection*` used by GLFW.
|
||||
*
|
||||
* @return The `MirConnection*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirConnection* glfwGetMirDisplay(void);
|
||||
|
||||
/*! @brief Returns the Mir output ID of the specified monitor.
|
||||
*
|
||||
* @return The Mir output ID of the specified monitor, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `MirWindow*` of the specified window.
|
||||
*
|
||||
* @return The `MirWindow*` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||
*
|
||||
|
||||
Vendored
+10
-13
@@ -35,6 +35,10 @@ elseif (_GLFW_WAYLAND)
|
||||
PROTOCOL
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/xdg-shell/xdg-shell.xml"
|
||||
BASENAME xdg-shell)
|
||||
ecm_add_wayland_client_protocol(glfw_SOURCES
|
||||
PROTOCOL
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
BASENAME xdg-decoration)
|
||||
ecm_add_wayland_client_protocol(glfw_SOURCES
|
||||
PROTOCOL
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/stable/viewporter/viewporter.xml"
|
||||
@@ -51,13 +55,6 @@ elseif (_GLFW_WAYLAND)
|
||||
PROTOCOL
|
||||
"${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
BASENAME idle-inhibit-unstable-v1)
|
||||
elseif (_GLFW_MIR)
|
||||
set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
|
||||
posix_time.h posix_thread.h xkb_unicode.h egl_context.h
|
||||
osmesa_context.h)
|
||||
set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c
|
||||
linux_joystick.c posix_time.c posix_thread.c xkb_unicode.c
|
||||
egl_context.c osmesa_context.c)
|
||||
elseif (_GLFW_OSMESA)
|
||||
set(glfw_HEADERS ${common_HEADERS} null_platform.h null_joystick.h
|
||||
posix_time.h posix_thread.h osmesa_context.h)
|
||||
@@ -104,10 +101,10 @@ set_target_properties(glfw PROPERTIES
|
||||
target_compile_definitions(glfw_objlib PRIVATE _GLFW_USE_CONFIG_H)
|
||||
target_include_directories(glfw_objlib PUBLIC
|
||||
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>")
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_FULL_INCLUDEDIR}>")
|
||||
target_include_directories(glfw PUBLIC
|
||||
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>")
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_FULL_INCLUDEDIR}>")
|
||||
target_include_directories(glfw_objlib PRIVATE
|
||||
"${GLFW_SOURCE_DIR}/src"
|
||||
"${GLFW_BINARY_DIR}/src"
|
||||
@@ -128,7 +125,7 @@ target_compile_options(glfw_objlib PRIVATE
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if (WIN32)
|
||||
if (MINGW)
|
||||
# Remove the lib prefix on the DLL (but not the import library
|
||||
# Remove the lib prefix on the DLL (but not the import library)
|
||||
set_target_properties(glfw PROPERTIES PREFIX "")
|
||||
|
||||
# Add a suffix to the import library to avoid naming conflicts
|
||||
@@ -142,7 +139,7 @@ if (BUILD_SHARED_LIBS)
|
||||
target_compile_options(glfw_objlib PRIVATE "-fno-common")
|
||||
|
||||
set_target_properties(glfw PROPERTIES
|
||||
INSTALL_NAME_DIR "lib${LIB_SUFFIX}")
|
||||
INSTALL_NAME_DIR "${CMAKE_INSTALL_LIBDIR}")
|
||||
elseif (UNIX)
|
||||
# Hide symbols not explicitly tagged for export from the shared library
|
||||
target_compile_options(glfw_objlib PRIVATE "-fvisibility=hidden")
|
||||
@@ -162,7 +159,7 @@ if (GLFW_INSTALL)
|
||||
install(TARGETS glfw
|
||||
EXPORT glfwTargets
|
||||
RUNTIME DESTINATION "bin"
|
||||
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
|
||||
LIBRARY DESTINATION "lib${LIB_SUFFIX}")
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
|
||||
Vendored
+39
-10
@@ -27,6 +27,10 @@
|
||||
#include "internal.h"
|
||||
#include <sys/param.h> // For MAXPATHLEN
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSEventMaskKeyUp NSKeyUpMask
|
||||
#define NSEventModifierFlagCommand NSCommandKeyMask
|
||||
#endif
|
||||
|
||||
// Change to our application bundle's resources directory, if present
|
||||
//
|
||||
@@ -271,17 +275,21 @@ static GLFWbool initializeTIS(void)
|
||||
return updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
@interface GLFWLayoutListener : NSObject
|
||||
@interface GLFWHelper : NSObject
|
||||
@end
|
||||
|
||||
@implementation GLFWLayoutListener
|
||||
@implementation GLFWHelper
|
||||
|
||||
- (void)selectedKeyboardInputSourceChanged:(NSObject* )object
|
||||
{
|
||||
updateUnicodeDataNS();
|
||||
}
|
||||
|
||||
@end
|
||||
- (void)doNothing:(id)object
|
||||
{
|
||||
}
|
||||
|
||||
@end // GLFWHelper
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -291,13 +299,31 @@ static GLFWbool initializeTIS(void)
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
_glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||
toTarget:_glfw.ns.helper
|
||||
withObject:nil];
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
if ([event modifierFlags] & NSEventModifierFlagCommand)
|
||||
[[NSApp keyWindow] sendEvent:event];
|
||||
|
||||
return event;
|
||||
};
|
||||
|
||||
_glfw.ns.keyUpMonitor =
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
|
||||
handler:block];
|
||||
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
_glfw.ns.listener = [[GLFWLayoutListener alloc] init];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
addObserver:_glfw.ns.listener
|
||||
addObserver:_glfw.ns.helper
|
||||
selector:@selector(selectedKeyboardInputSourceChanged:)
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
@@ -342,18 +368,21 @@ void _glfwPlatformTerminate(void)
|
||||
_glfw.ns.delegate = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.listener)
|
||||
if (_glfw.ns.helper)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:_glfw.ns.listener
|
||||
removeObserver:_glfw.ns.helper
|
||||
name:NSTextInputContextKeyboardSelectionDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:_glfw.ns.listener];
|
||||
[_glfw.ns.listener release];
|
||||
_glfw.ns.listener = nil;
|
||||
removeObserver:_glfw.ns.helper];
|
||||
[_glfw.ns.helper release];
|
||||
_glfw.ns.helper = nil;
|
||||
}
|
||||
|
||||
if (_glfw.ns.keyUpMonitor)
|
||||
[NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
|
||||
|
||||
free(_glfw.ns.clipboardString);
|
||||
|
||||
_glfwTerminateNSGL();
|
||||
|
||||
+2
-1
@@ -467,7 +467,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode)
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
|
||||
CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue));
|
||||
@@ -489,6 +489,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
}
|
||||
|
||||
free(values);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
|
||||
+4
-4
@@ -27,12 +27,10 @@
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
|
||||
@@ -111,7 +109,9 @@ typedef struct _GLFWlibraryNS
|
||||
TISInputSourceRef inputSource;
|
||||
IOHIDManagerRef hidManager;
|
||||
id unicodeData;
|
||||
id listener;
|
||||
id helper;
|
||||
id keyUpMonitor;
|
||||
id nibObjects;
|
||||
|
||||
char keyName[64];
|
||||
short int keycodes[256];
|
||||
|
||||
Vendored
+63
-125
@@ -32,7 +32,6 @@
|
||||
// Needed for _NSGetProgname
|
||||
#include <crt_externs.h>
|
||||
|
||||
// HACK: The 10.12 SDK adds new symbols and immediately deprecates the old ones
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
|
||||
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
|
||||
#define NSWindowStyleMaskClosable NSClosableWindowMask
|
||||
@@ -47,10 +46,9 @@
|
||||
#define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
|
||||
#define NSEventMaskAny NSAnyEventMask
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
#define NSEventTypeKeyUp NSKeyUp
|
||||
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
|
||||
#endif
|
||||
|
||||
|
||||
// Returns the style mask corresponding to the window settings
|
||||
//
|
||||
static NSUInteger getStyleMask(_GLFWwindow* window)
|
||||
@@ -237,6 +235,8 @@ static NSUInteger translateKeyToModifierFlag(int key)
|
||||
case GLFW_KEY_LEFT_SUPER:
|
||||
case GLFW_KEY_RIGHT_SUPER:
|
||||
return NSEventModifierFlagCommand;
|
||||
case GLFW_KEY_CAPS_LOCK:
|
||||
return NSEventModifierFlagCapsLock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -365,7 +365,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
// Delegate for application related notifications
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
@interface GLFWApplicationDelegate : NSObject
|
||||
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||
@end
|
||||
|
||||
@implementation GLFWApplicationDelegate
|
||||
@@ -438,8 +438,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
markedText = [[NSMutableAttributedString alloc] init];
|
||||
|
||||
[self updateTrackingAreas];
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObjects:
|
||||
NSFilenamesPboardType, nil]];
|
||||
// NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available
|
||||
// on 10.7 without having been deprecated yet
|
||||
[self registerForDraggedTypes:@[(__bridge NSString*) kUTTypeURL]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -472,6 +473,14 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)updateLayer
|
||||
{
|
||||
if (window->context.client != GLFW_NO_API)
|
||||
[window->context.nsgl.object update];
|
||||
|
||||
_glfwInputWindowDamage(window);
|
||||
}
|
||||
|
||||
- (id)makeBackingLayer
|
||||
{
|
||||
if (window->ns.layer)
|
||||
@@ -485,6 +494,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
updateCursorImage(window);
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstMouse:(NSEvent *)event
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
_glfwInputMouseClick(window,
|
||||
@@ -650,7 +664,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
_glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
|
||||
|
||||
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
|
||||
[self interpretKeyEvents:@[event]];
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent *)event
|
||||
@@ -701,45 +715,33 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
|
||||
== NSDragOperationGeneric)
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
return NSDragOperationGeneric;
|
||||
}
|
||||
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
return YES;
|
||||
// HACK: We don't know what to say here because we don't know what the
|
||||
// application wants to do with the paths
|
||||
return NSDragOperationGeneric;
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
|
||||
|
||||
const NSRect contentRect = [window->ns.view frame];
|
||||
_glfwInputCursorPos(window,
|
||||
[sender draggingLocation].x,
|
||||
contentRect.size.height - [sender draggingLocation].y);
|
||||
|
||||
const NSUInteger count = [files count];
|
||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||
NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
|
||||
options:options];
|
||||
const NSUInteger count = [urls count];
|
||||
if (count)
|
||||
{
|
||||
NSEnumerator* e = [files objectEnumerator];
|
||||
char** paths = calloc(count, sizeof(char*));
|
||||
NSUInteger i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
paths[i] = _glfw_strdup([[e nextObject] UTF8String]);
|
||||
for (NSUInteger i = 0; i < count; i++)
|
||||
paths[i] = _glfw_strdup([[urls objectAtIndex:i] fileSystemRepresentation]);
|
||||
|
||||
_glfwInputDrop(window, (int) count, (const char**) paths);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
for (NSUInteger i = 0; i < count; i++)
|
||||
free(paths[i]);
|
||||
free(paths);
|
||||
}
|
||||
@@ -747,11 +749,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (BOOL)hasMarkedText
|
||||
{
|
||||
return [markedText length] > 0;
|
||||
@@ -865,52 +862,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
@end
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// GLFW application class
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
@interface GLFWApplication : NSApplication
|
||||
{
|
||||
NSArray* nibObjects;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GLFWApplication
|
||||
|
||||
// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
|
||||
// This works around an AppKit bug, where key up events while holding
|
||||
// down the command key don't get sent to the key window.
|
||||
- (void)sendEvent:(NSEvent *)event
|
||||
{
|
||||
if ([event type] == NSEventTypeKeyUp &&
|
||||
([event modifierFlags] & NSEventModifierFlagCommand))
|
||||
{
|
||||
[[self keyWindow] sendEvent:event];
|
||||
}
|
||||
else
|
||||
[super sendEvent:event];
|
||||
}
|
||||
|
||||
|
||||
// No-op thread entry point
|
||||
//
|
||||
- (void)doNothing:(id)object
|
||||
{
|
||||
}
|
||||
|
||||
- (void)loadMainMenu
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||
owner:NSApp
|
||||
topLevelObjects:&nibObjects];
|
||||
#else
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp];
|
||||
#endif
|
||||
}
|
||||
@end
|
||||
|
||||
// Set up the menu bar (manually)
|
||||
// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
|
||||
// could go away at any moment, lots of stuff that really should be
|
||||
@@ -1020,32 +971,9 @@ static void createMenuBar(void)
|
||||
//
|
||||
static GLFWbool initializeAppKit(void)
|
||||
{
|
||||
if (NSApp)
|
||||
if (_glfw.ns.delegate)
|
||||
return GLFW_TRUE;
|
||||
|
||||
// Implicitly create shared NSApplication instance
|
||||
[GLFWApplication sharedApplication];
|
||||
|
||||
// Make Cocoa enter multi-threaded mode
|
||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||
toTarget:NSApp
|
||||
withObject:nil];
|
||||
|
||||
if (_glfw.hints.init.ns.menubar)
|
||||
{
|
||||
// In case we are unbundled, make us a proper UI application
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
// Menu bar setup must go between sharedApplication above and
|
||||
// finishLaunching below, in order to properly emulate the behavior
|
||||
// of NSApplicationMain
|
||||
|
||||
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
|
||||
[NSApp loadMainMenu];
|
||||
else
|
||||
createMenuBar();
|
||||
}
|
||||
|
||||
// There can only be one application delegate, but we allocate it the
|
||||
// first time a window is created to keep all window code in this file
|
||||
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
|
||||
@@ -1057,13 +985,34 @@ static GLFWbool initializeAppKit(void)
|
||||
}
|
||||
|
||||
[NSApp setDelegate:_glfw.ns.delegate];
|
||||
|
||||
if (_glfw.hints.init.ns.menubar)
|
||||
{
|
||||
// In case we are unbundled, make us a proper UI application
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
// Menu bar setup must go between sharedApplication above and
|
||||
// finishLaunching below, in order to properly emulate the behavior
|
||||
// of NSApplicationMain
|
||||
|
||||
if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu"
|
||||
owner:NSApp
|
||||
topLevelObjects:&_glfw.ns.nibObjects];
|
||||
#else
|
||||
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp];
|
||||
#endif
|
||||
}
|
||||
else
|
||||
createMenuBar();
|
||||
}
|
||||
|
||||
[NSApp run];
|
||||
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
NSDictionary* defaults =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
|
||||
@"ApplePressAndHoldEnabled",
|
||||
nil];
|
||||
NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
return GLFW_TRUE;
|
||||
@@ -1563,9 +1512,6 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
if (!initializeAppKit())
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||
@@ -1716,9 +1662,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
NSImage* native;
|
||||
NSBitmapImageRep* rep;
|
||||
|
||||
if (!initializeAppKit())
|
||||
return GLFW_FALSE;
|
||||
|
||||
rep = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:image->width
|
||||
@@ -1728,7 +1671,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
|
||||
bitmapFormat:NSBitmapFormatAlphaNonpremultiplied
|
||||
bytesPerRow:image->width * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
@@ -1754,9 +1697,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
if (!initializeAppKit())
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (shape == GLFW_ARROW_CURSOR)
|
||||
cursor->ns.object = [NSCursor arrowCursor];
|
||||
else if (shape == GLFW_IBEAM_CURSOR)
|
||||
@@ -1795,26 +1735,24 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil];
|
||||
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard declareTypes:types owner:nil];
|
||||
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
|
||||
[pasteboard setString:[NSString stringWithUTF8String:string]
|
||||
forType:NSStringPboardType];
|
||||
forType:NSPasteboardTypeString];
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(void)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
|
||||
if (![[pasteboard types] containsObject:NSStringPboardType])
|
||||
if (![[pasteboard types] containsObject:NSPasteboardTypeString])
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"Cocoa: Failed to retrieve string from pasteboard");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NSString* object = [pasteboard stringForType:NSStringPboardType];
|
||||
NSString* object = [pasteboard stringForType:NSPasteboardTypeString];
|
||||
if (!object)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
|
||||
Vendored
-4
@@ -43,10 +43,6 @@ typedef Window EGLNativeWindowType;
|
||||
#define EGLAPIENTRY
|
||||
typedef struct wl_display* EGLNativeDisplayType;
|
||||
typedef struct wl_egl_window* EGLNativeWindowType;
|
||||
#elif defined(_GLFW_MIR)
|
||||
#define EGLAPIENTRY
|
||||
typedef MirEGLNativeDisplayType EGLNativeDisplayType;
|
||||
typedef MirEGLNativeWindowType EGLNativeWindowType;
|
||||
#else
|
||||
#error "No supported EGL platform selected"
|
||||
#endif
|
||||
|
||||
Vendored
+3
-3
@@ -1,12 +1,12 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
includedir=${prefix}/include
|
||||
libdir=${exec_prefix}/lib@LIB_SUFFIX@
|
||||
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
|
||||
Name: GLFW
|
||||
Description: A multi-platform library for OpenGL, window and input
|
||||
Version: @GLFW_VERSION_FULL@
|
||||
URL: http://www.glfw.org/
|
||||
URL: https://www.glfw.org/
|
||||
Requires.private: @GLFW_PKG_DEPS@
|
||||
Libs: -L${libdir} -l@GLFW_LIB_NAME@
|
||||
Libs.private: @GLFW_PKG_LIBS@
|
||||
|
||||
+2
-2
@@ -42,8 +42,6 @@
|
||||
#cmakedefine _GLFW_COCOA
|
||||
// Define this to 1 if building GLFW for Wayland
|
||||
#cmakedefine _GLFW_WAYLAND
|
||||
// Define this to 1 if building GLFW for Mir
|
||||
#cmakedefine _GLFW_MIR
|
||||
// Define this to 1 if building GLFW for OSMesa
|
||||
#cmakedefine _GLFW_OSMESA
|
||||
|
||||
@@ -57,4 +55,6 @@
|
||||
|
||||
// Define this to 1 if xkbcommon supports the compose key
|
||||
#cmakedefine HAVE_XKBCOMMON_COMPOSE_H
|
||||
// Define this to 1 if the libc supports memfd_create()
|
||||
#cmakedefine HAVE_MEMFD_CREATE
|
||||
|
||||
|
||||
Vendored
+24
@@ -119,6 +119,30 @@ char* _glfw_strdup(const char* source)
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW event API //////
|
||||
|
||||
Vendored
+1
-1
@@ -1242,7 +1242,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
|
||||
if (e->type == _GLFW_JOYSTICK_AXIS)
|
||||
{
|
||||
const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
|
||||
state->axes[i] = fminf(fmaxf(value, -1.f), 1.f);
|
||||
state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f);
|
||||
}
|
||||
else if (e->type == _GLFW_JOYSTICK_HATBIT)
|
||||
{
|
||||
|
||||
Vendored
+4
-6
@@ -126,7 +126,6 @@ typedef enum VkStructureType
|
||||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
|
||||
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
|
||||
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
|
||||
VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
|
||||
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
|
||||
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
|
||||
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
|
||||
@@ -188,8 +187,6 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
|
||||
#include "x11_platform.h"
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
#include "wl_platform.h"
|
||||
#elif defined(_GLFW_MIR)
|
||||
#include "mir_platform.h"
|
||||
#elif defined(_GLFW_OSMESA)
|
||||
#include "null_platform.h"
|
||||
#else
|
||||
@@ -268,6 +265,7 @@ struct _GLFWwndconfig
|
||||
GLFWbool maximized;
|
||||
GLFWbool centerCursor;
|
||||
GLFWbool focusOnShow;
|
||||
GLFWbool scaleToMonitor;
|
||||
struct {
|
||||
GLFWbool retina;
|
||||
char frameName[256];
|
||||
@@ -562,8 +560,6 @@ struct _GLFWlibrary
|
||||
GLFWbool KHR_xcb_surface;
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
GLFWbool KHR_wayland_surface;
|
||||
#elif defined(_GLFW_MIR)
|
||||
GLFWbool KHR_mir_surface;
|
||||
#endif
|
||||
} vk;
|
||||
|
||||
@@ -615,7 +611,7 @@ void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale);
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count);
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode);
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string);
|
||||
@@ -770,4 +766,6 @@ void _glfwTerminateVulkan(void);
|
||||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
float _glfw_fminf(float a, float b);
|
||||
float _glfw_fmaxf(float a, float b);
|
||||
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ static GLFWbool openJoystickDevice(const char* path)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
strncpy(linjs.path, path, sizeof(linjs.path));
|
||||
strncpy(linjs.path, path, sizeof(linjs.path) - 1);
|
||||
memcpy(&js->linjs, &linjs, sizeof(linjs));
|
||||
|
||||
pollAbsState(js);
|
||||
|
||||
Vendored
-240
@@ -1,240 +0,0 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// Create key code translation tables
|
||||
//
|
||||
static void createKeyTables(void)
|
||||
{
|
||||
int scancode;
|
||||
|
||||
memset(_glfw.mir.keycodes, -1, sizeof(_glfw.mir.keycodes));
|
||||
memset(_glfw.mir.scancodes, -1, sizeof(_glfw.mir.scancodes));
|
||||
|
||||
_glfw.mir.keycodes[KEY_GRAVE] = GLFW_KEY_GRAVE_ACCENT;
|
||||
_glfw.mir.keycodes[KEY_1] = GLFW_KEY_1;
|
||||
_glfw.mir.keycodes[KEY_2] = GLFW_KEY_2;
|
||||
_glfw.mir.keycodes[KEY_3] = GLFW_KEY_3;
|
||||
_glfw.mir.keycodes[KEY_4] = GLFW_KEY_4;
|
||||
_glfw.mir.keycodes[KEY_5] = GLFW_KEY_5;
|
||||
_glfw.mir.keycodes[KEY_6] = GLFW_KEY_6;
|
||||
_glfw.mir.keycodes[KEY_7] = GLFW_KEY_7;
|
||||
_glfw.mir.keycodes[KEY_8] = GLFW_KEY_8;
|
||||
_glfw.mir.keycodes[KEY_9] = GLFW_KEY_9;
|
||||
_glfw.mir.keycodes[KEY_0] = GLFW_KEY_0;
|
||||
_glfw.mir.keycodes[KEY_SPACE] = GLFW_KEY_SPACE;
|
||||
_glfw.mir.keycodes[KEY_MINUS] = GLFW_KEY_MINUS;
|
||||
_glfw.mir.keycodes[KEY_EQUAL] = GLFW_KEY_EQUAL;
|
||||
_glfw.mir.keycodes[KEY_Q] = GLFW_KEY_Q;
|
||||
_glfw.mir.keycodes[KEY_W] = GLFW_KEY_W;
|
||||
_glfw.mir.keycodes[KEY_E] = GLFW_KEY_E;
|
||||
_glfw.mir.keycodes[KEY_R] = GLFW_KEY_R;
|
||||
_glfw.mir.keycodes[KEY_T] = GLFW_KEY_T;
|
||||
_glfw.mir.keycodes[KEY_Y] = GLFW_KEY_Y;
|
||||
_glfw.mir.keycodes[KEY_U] = GLFW_KEY_U;
|
||||
_glfw.mir.keycodes[KEY_I] = GLFW_KEY_I;
|
||||
_glfw.mir.keycodes[KEY_O] = GLFW_KEY_O;
|
||||
_glfw.mir.keycodes[KEY_P] = GLFW_KEY_P;
|
||||
_glfw.mir.keycodes[KEY_LEFTBRACE] = GLFW_KEY_LEFT_BRACKET;
|
||||
_glfw.mir.keycodes[KEY_RIGHTBRACE] = GLFW_KEY_RIGHT_BRACKET;
|
||||
_glfw.mir.keycodes[KEY_A] = GLFW_KEY_A;
|
||||
_glfw.mir.keycodes[KEY_S] = GLFW_KEY_S;
|
||||
_glfw.mir.keycodes[KEY_D] = GLFW_KEY_D;
|
||||
_glfw.mir.keycodes[KEY_F] = GLFW_KEY_F;
|
||||
_glfw.mir.keycodes[KEY_G] = GLFW_KEY_G;
|
||||
_glfw.mir.keycodes[KEY_H] = GLFW_KEY_H;
|
||||
_glfw.mir.keycodes[KEY_J] = GLFW_KEY_J;
|
||||
_glfw.mir.keycodes[KEY_K] = GLFW_KEY_K;
|
||||
_glfw.mir.keycodes[KEY_L] = GLFW_KEY_L;
|
||||
_glfw.mir.keycodes[KEY_SEMICOLON] = GLFW_KEY_SEMICOLON;
|
||||
_glfw.mir.keycodes[KEY_APOSTROPHE] = GLFW_KEY_APOSTROPHE;
|
||||
_glfw.mir.keycodes[KEY_Z] = GLFW_KEY_Z;
|
||||
_glfw.mir.keycodes[KEY_X] = GLFW_KEY_X;
|
||||
_glfw.mir.keycodes[KEY_C] = GLFW_KEY_C;
|
||||
_glfw.mir.keycodes[KEY_V] = GLFW_KEY_V;
|
||||
_glfw.mir.keycodes[KEY_B] = GLFW_KEY_B;
|
||||
_glfw.mir.keycodes[KEY_N] = GLFW_KEY_N;
|
||||
_glfw.mir.keycodes[KEY_M] = GLFW_KEY_M;
|
||||
_glfw.mir.keycodes[KEY_COMMA] = GLFW_KEY_COMMA;
|
||||
_glfw.mir.keycodes[KEY_DOT] = GLFW_KEY_PERIOD;
|
||||
_glfw.mir.keycodes[KEY_SLASH] = GLFW_KEY_SLASH;
|
||||
_glfw.mir.keycodes[KEY_BACKSLASH] = GLFW_KEY_BACKSLASH;
|
||||
_glfw.mir.keycodes[KEY_ESC] = GLFW_KEY_ESCAPE;
|
||||
_glfw.mir.keycodes[KEY_TAB] = GLFW_KEY_TAB;
|
||||
_glfw.mir.keycodes[KEY_LEFTSHIFT] = GLFW_KEY_LEFT_SHIFT;
|
||||
_glfw.mir.keycodes[KEY_RIGHTSHIFT] = GLFW_KEY_RIGHT_SHIFT;
|
||||
_glfw.mir.keycodes[KEY_LEFTCTRL] = GLFW_KEY_LEFT_CONTROL;
|
||||
_glfw.mir.keycodes[KEY_RIGHTCTRL] = GLFW_KEY_RIGHT_CONTROL;
|
||||
_glfw.mir.keycodes[KEY_LEFTALT] = GLFW_KEY_LEFT_ALT;
|
||||
_glfw.mir.keycodes[KEY_RIGHTALT] = GLFW_KEY_RIGHT_ALT;
|
||||
_glfw.mir.keycodes[KEY_LEFTMETA] = GLFW_KEY_LEFT_SUPER;
|
||||
_glfw.mir.keycodes[KEY_RIGHTMETA] = GLFW_KEY_RIGHT_SUPER;
|
||||
_glfw.mir.keycodes[KEY_MENU] = GLFW_KEY_MENU;
|
||||
_glfw.mir.keycodes[KEY_NUMLOCK] = GLFW_KEY_NUM_LOCK;
|
||||
_glfw.mir.keycodes[KEY_CAPSLOCK] = GLFW_KEY_CAPS_LOCK;
|
||||
_glfw.mir.keycodes[KEY_PRINT] = GLFW_KEY_PRINT_SCREEN;
|
||||
_glfw.mir.keycodes[KEY_SCROLLLOCK] = GLFW_KEY_SCROLL_LOCK;
|
||||
_glfw.mir.keycodes[KEY_PAUSE] = GLFW_KEY_PAUSE;
|
||||
_glfw.mir.keycodes[KEY_DELETE] = GLFW_KEY_DELETE;
|
||||
_glfw.mir.keycodes[KEY_BACKSPACE] = GLFW_KEY_BACKSPACE;
|
||||
_glfw.mir.keycodes[KEY_ENTER] = GLFW_KEY_ENTER;
|
||||
_glfw.mir.keycodes[KEY_HOME] = GLFW_KEY_HOME;
|
||||
_glfw.mir.keycodes[KEY_END] = GLFW_KEY_END;
|
||||
_glfw.mir.keycodes[KEY_PAGEUP] = GLFW_KEY_PAGE_UP;
|
||||
_glfw.mir.keycodes[KEY_PAGEDOWN] = GLFW_KEY_PAGE_DOWN;
|
||||
_glfw.mir.keycodes[KEY_INSERT] = GLFW_KEY_INSERT;
|
||||
_glfw.mir.keycodes[KEY_LEFT] = GLFW_KEY_LEFT;
|
||||
_glfw.mir.keycodes[KEY_RIGHT] = GLFW_KEY_RIGHT;
|
||||
_glfw.mir.keycodes[KEY_DOWN] = GLFW_KEY_DOWN;
|
||||
_glfw.mir.keycodes[KEY_UP] = GLFW_KEY_UP;
|
||||
_glfw.mir.keycodes[KEY_F1] = GLFW_KEY_F1;
|
||||
_glfw.mir.keycodes[KEY_F2] = GLFW_KEY_F2;
|
||||
_glfw.mir.keycodes[KEY_F3] = GLFW_KEY_F3;
|
||||
_glfw.mir.keycodes[KEY_F4] = GLFW_KEY_F4;
|
||||
_glfw.mir.keycodes[KEY_F5] = GLFW_KEY_F5;
|
||||
_glfw.mir.keycodes[KEY_F6] = GLFW_KEY_F6;
|
||||
_glfw.mir.keycodes[KEY_F7] = GLFW_KEY_F7;
|
||||
_glfw.mir.keycodes[KEY_F8] = GLFW_KEY_F8;
|
||||
_glfw.mir.keycodes[KEY_F9] = GLFW_KEY_F9;
|
||||
_glfw.mir.keycodes[KEY_F10] = GLFW_KEY_F10;
|
||||
_glfw.mir.keycodes[KEY_F11] = GLFW_KEY_F11;
|
||||
_glfw.mir.keycodes[KEY_F12] = GLFW_KEY_F12;
|
||||
_glfw.mir.keycodes[KEY_F13] = GLFW_KEY_F13;
|
||||
_glfw.mir.keycodes[KEY_F14] = GLFW_KEY_F14;
|
||||
_glfw.mir.keycodes[KEY_F15] = GLFW_KEY_F15;
|
||||
_glfw.mir.keycodes[KEY_F16] = GLFW_KEY_F16;
|
||||
_glfw.mir.keycodes[KEY_F17] = GLFW_KEY_F17;
|
||||
_glfw.mir.keycodes[KEY_F18] = GLFW_KEY_F18;
|
||||
_glfw.mir.keycodes[KEY_F19] = GLFW_KEY_F19;
|
||||
_glfw.mir.keycodes[KEY_F20] = GLFW_KEY_F20;
|
||||
_glfw.mir.keycodes[KEY_F21] = GLFW_KEY_F21;
|
||||
_glfw.mir.keycodes[KEY_F22] = GLFW_KEY_F22;
|
||||
_glfw.mir.keycodes[KEY_F23] = GLFW_KEY_F23;
|
||||
_glfw.mir.keycodes[KEY_F24] = GLFW_KEY_F24;
|
||||
_glfw.mir.keycodes[KEY_KPSLASH] = GLFW_KEY_KP_DIVIDE;
|
||||
_glfw.mir.keycodes[KEY_KPDOT] = GLFW_KEY_KP_MULTIPLY;
|
||||
_glfw.mir.keycodes[KEY_KPMINUS] = GLFW_KEY_KP_SUBTRACT;
|
||||
_glfw.mir.keycodes[KEY_KPPLUS] = GLFW_KEY_KP_ADD;
|
||||
_glfw.mir.keycodes[KEY_KP0] = GLFW_KEY_KP_0;
|
||||
_glfw.mir.keycodes[KEY_KP1] = GLFW_KEY_KP_1;
|
||||
_glfw.mir.keycodes[KEY_KP2] = GLFW_KEY_KP_2;
|
||||
_glfw.mir.keycodes[KEY_KP3] = GLFW_KEY_KP_3;
|
||||
_glfw.mir.keycodes[KEY_KP4] = GLFW_KEY_KP_4;
|
||||
_glfw.mir.keycodes[KEY_KP5] = GLFW_KEY_KP_5;
|
||||
_glfw.mir.keycodes[KEY_KP6] = GLFW_KEY_KP_6;
|
||||
_glfw.mir.keycodes[KEY_KP7] = GLFW_KEY_KP_7;
|
||||
_glfw.mir.keycodes[KEY_KP8] = GLFW_KEY_KP_8;
|
||||
_glfw.mir.keycodes[KEY_KP9] = GLFW_KEY_KP_9;
|
||||
_glfw.mir.keycodes[KEY_KPCOMMA] = GLFW_KEY_KP_DECIMAL;
|
||||
_glfw.mir.keycodes[KEY_KPEQUAL] = GLFW_KEY_KP_EQUAL;
|
||||
_glfw.mir.keycodes[KEY_KPENTER] = GLFW_KEY_KP_ENTER;
|
||||
|
||||
for (scancode = 0; scancode < 256; scancode++)
|
||||
{
|
||||
if (_glfw.mir.keycodes[scancode] > 0)
|
||||
_glfw.mir.scancodes[_glfw.mir.keycodes[scancode]] = scancode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
_glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__);
|
||||
|
||||
if (!mir_connection_is_valid(_glfw.mir.connection))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unable to connect to server: %s",
|
||||
mir_connection_get_error_message(_glfw.mir.connection));
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfw.mir.display =
|
||||
mir_connection_get_egl_native_display(_glfw.mir.connection);
|
||||
|
||||
createKeyTables();
|
||||
|
||||
if (!_glfwInitJoysticksLinux())
|
||||
return GLFW_FALSE;
|
||||
|
||||
_glfwInitTimerPOSIX();
|
||||
|
||||
_glfw.mir.eventQueue = calloc(1, sizeof(EventQueue));
|
||||
_glfwInitEventQueueMir(_glfw.mir.eventQueue);
|
||||
|
||||
error = pthread_mutex_init(&_glfw.mir.eventMutex, NULL);
|
||||
if (error)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Failed to create event mutex: %s",
|
||||
strerror(error));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
_glfwPollMonitorsMir();
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
_glfwTerminateEGL();
|
||||
_glfwTerminateJoysticksLinux();
|
||||
|
||||
_glfwDeleteEventQueueMir(_glfw.mir.eventQueue);
|
||||
|
||||
pthread_mutex_destroy(&_glfw.mir.eventMutex);
|
||||
|
||||
mir_connection_release(_glfw.mir.connection);
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
{
|
||||
return _GLFW_VERSION_NUMBER " Mir EGL"
|
||||
#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
|
||||
" clock_gettime"
|
||||
#else
|
||||
" gettimeofday"
|
||||
#endif
|
||||
" evdev"
|
||||
#if defined(_GLFW_BUILD_DLL)
|
||||
" shared"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
Vendored
-218
@@ -1,218 +0,0 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsMir(void)
|
||||
{
|
||||
int i;
|
||||
MirDisplayConfig* displayConfig =
|
||||
mir_connection_create_display_configuration(_glfw.mir.connection);
|
||||
|
||||
int numOutputs = mir_display_config_get_num_outputs(displayConfig);
|
||||
|
||||
for (i = 0; i < numOutputs; i++)
|
||||
{
|
||||
const MirOutput* output = mir_display_config_get_output(displayConfig, i);
|
||||
MirOutputConnectionState state = mir_output_get_connection_state(output);
|
||||
bool enabled = mir_output_is_enabled(output);
|
||||
|
||||
if (enabled && state == mir_output_connection_state_connected)
|
||||
{
|
||||
int widthMM = mir_output_get_physical_width_mm(output);
|
||||
int heightMM = mir_output_get_physical_height_mm(output);
|
||||
int x = mir_output_get_position_x(output);
|
||||
int y = mir_output_get_position_y(output);
|
||||
int id = mir_output_get_id(output);
|
||||
size_t currentMode = mir_output_get_current_mode_index(output);
|
||||
const char* name = mir_output_type_name(mir_output_get_type(output));
|
||||
|
||||
_GLFWmonitor* monitor = _glfwAllocMonitor(name,
|
||||
widthMM,
|
||||
heightMM);
|
||||
monitor->mir.x = x;
|
||||
monitor->mir.y = y;
|
||||
monitor->mir.outputId = id;
|
||||
monitor->mir.curMode = currentMode;
|
||||
monitor->modes = _glfwPlatformGetVideoModes(monitor, &monitor->modeCount);
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
}
|
||||
|
||||
mir_display_config_release(displayConfig);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwPlatformFreeMonitor(_GLFWmonitor* monitor)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos)
|
||||
{
|
||||
if (xpos)
|
||||
*xpos = monitor->mir.x;
|
||||
if (ypos)
|
||||
*ypos = monitor->mir.y;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor* monitor,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
static void FillInRGBBitsFromPixelFormat(GLFWvidmode* mode, const MirPixelFormat pf)
|
||||
{
|
||||
switch (pf)
|
||||
{
|
||||
case mir_pixel_format_rgb_565:
|
||||
mode->redBits = 5;
|
||||
mode->greenBits = 6;
|
||||
mode->blueBits = 5;
|
||||
break;
|
||||
case mir_pixel_format_rgba_5551:
|
||||
mode->redBits = 5;
|
||||
mode->greenBits = 5;
|
||||
mode->blueBits = 5;
|
||||
break;
|
||||
case mir_pixel_format_rgba_4444:
|
||||
mode->redBits = 4;
|
||||
mode->greenBits = 4;
|
||||
mode->blueBits = 4;
|
||||
break;
|
||||
case mir_pixel_format_abgr_8888:
|
||||
case mir_pixel_format_xbgr_8888:
|
||||
case mir_pixel_format_argb_8888:
|
||||
case mir_pixel_format_xrgb_8888:
|
||||
case mir_pixel_format_bgr_888:
|
||||
case mir_pixel_format_rgb_888:
|
||||
default:
|
||||
mode->redBits = 8;
|
||||
mode->greenBits = 8;
|
||||
mode->blueBits = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found)
|
||||
{
|
||||
int i;
|
||||
GLFWvidmode* modes = NULL;
|
||||
MirDisplayConfig* displayConfig =
|
||||
mir_connection_create_display_configuration(_glfw.mir.connection);
|
||||
|
||||
int numOutputs = mir_display_config_get_num_outputs(displayConfig);
|
||||
|
||||
for (i = 0; i < numOutputs; i++)
|
||||
{
|
||||
const MirOutput* output = mir_display_config_get_output(displayConfig, i);
|
||||
int id = mir_output_get_id(output);
|
||||
|
||||
if (id != monitor->mir.outputId)
|
||||
continue;
|
||||
|
||||
MirOutputConnectionState state = mir_output_get_connection_state(output);
|
||||
bool enabled = mir_output_is_enabled(output);
|
||||
|
||||
// We must have been disconnected
|
||||
if (!enabled || state != mir_output_connection_state_connected)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Monitor no longer connected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int numModes = mir_output_get_num_modes(output);
|
||||
modes = calloc(numModes, sizeof(GLFWvidmode));
|
||||
|
||||
for (*found = 0; *found < numModes; (*found)++)
|
||||
{
|
||||
const MirOutputMode* mode = mir_output_get_mode(output, *found);
|
||||
int width = mir_output_mode_get_width(mode);
|
||||
int height = mir_output_mode_get_height(mode);
|
||||
double refreshRate = mir_output_mode_get_refresh_rate(mode);
|
||||
MirPixelFormat currentFormat = mir_output_get_current_pixel_format(output);
|
||||
|
||||
modes[*found].width = width;
|
||||
modes[*found].height = height;
|
||||
modes[*found].refreshRate = refreshRate;
|
||||
|
||||
FillInRGBBitsFromPixelFormat(&modes[*found], currentFormat);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mir_display_config_release(displayConfig);
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
{
|
||||
*mode = monitor->modes[monitor->mir.curMode];
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||
return monitor->mir.outputId;
|
||||
}
|
||||
Vendored
-133
@@ -1,133 +0,0 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
|
||||
typedef VkFlags VkMirWindowCreateFlagsKHR;
|
||||
|
||||
typedef struct VkMirWindowCreateInfoKHR
|
||||
{
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkMirWindowCreateFlagsKHR flags;
|
||||
MirConnection* connection;
|
||||
MirWindow* mirWindow;
|
||||
} VkMirWindowCreateInfoKHR;
|
||||
|
||||
typedef VkResult (APIENTRY *PFN_vkCreateMirWindowKHR)(VkInstance,const VkMirWindowCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
||||
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)(VkPhysicalDevice,uint32_t,MirConnection*);
|
||||
|
||||
#include "posix_thread.h"
|
||||
#include "posix_time.h"
|
||||
#include "linux_joystick.h"
|
||||
#include "xkb_unicode.h"
|
||||
#include "egl_context.h"
|
||||
#include "osmesa_context.h"
|
||||
|
||||
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define _glfw_dlclose(handle) dlclose(handle)
|
||||
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
||||
|
||||
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->mir.nativeWindow)
|
||||
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.mir.display)
|
||||
|
||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir
|
||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir
|
||||
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir
|
||||
|
||||
#define _GLFW_PLATFORM_CONTEXT_STATE
|
||||
#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE
|
||||
|
||||
|
||||
// Mir-specific Event Queue
|
||||
//
|
||||
typedef struct EventQueue
|
||||
{
|
||||
TAILQ_HEAD(, EventNode) head;
|
||||
} EventQueue;
|
||||
|
||||
// Mir-specific per-window data
|
||||
//
|
||||
typedef struct _GLFWwindowMir
|
||||
{
|
||||
MirWindow* window;
|
||||
int width;
|
||||
int height;
|
||||
MirEGLNativeWindowType nativeWindow;
|
||||
_GLFWcursor* currentCursor;
|
||||
|
||||
} _GLFWwindowMir;
|
||||
|
||||
// Mir-specific per-monitor data
|
||||
//
|
||||
typedef struct _GLFWmonitorMir
|
||||
{
|
||||
int curMode;
|
||||
int outputId;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
} _GLFWmonitorMir;
|
||||
|
||||
// Mir-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryMir
|
||||
{
|
||||
MirConnection* connection;
|
||||
MirEGLNativeDisplayType display;
|
||||
EventQueue* eventQueue;
|
||||
|
||||
short int keycodes[256];
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
|
||||
pthread_mutex_t eventMutex;
|
||||
pthread_cond_t eventCond;
|
||||
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
|
||||
} _GLFWlibraryMir;
|
||||
|
||||
// Mir-specific per-cursor data
|
||||
// TODO: Only system cursors are implemented in Mir atm. Need to wait for support.
|
||||
//
|
||||
typedef struct _GLFWcursorMir
|
||||
{
|
||||
MirCursorConfiguration* conf;
|
||||
MirBufferStream* customCursor;
|
||||
char const* cursorName; // only needed for system cursors
|
||||
} _GLFWcursorMir;
|
||||
|
||||
|
||||
extern void _glfwPollMonitorsMir(void);
|
||||
extern void _glfwInitEventQueueMir(EventQueue* queue);
|
||||
extern void _glfwDeleteEventQueueMir(EventQueue* queue);
|
||||
|
||||
Vendored
-975
@@ -1,975 +0,0 @@
|
||||
//========================================================================
|
||||
// GLFW 3.3 Mir - www.glfw.org
|
||||
//------------------------------------------------------------------------
|
||||
// Copyright (c) 2014-2017 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would
|
||||
// be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
//========================================================================
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct EventNode
|
||||
{
|
||||
TAILQ_ENTRY(EventNode) entries;
|
||||
const MirEvent* event;
|
||||
_GLFWwindow* window;
|
||||
} EventNode;
|
||||
|
||||
static void deleteNode(EventQueue* queue, EventNode* node)
|
||||
{
|
||||
mir_event_unref(node->event);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static GLFWbool emptyEventQueue(EventQueue* queue)
|
||||
{
|
||||
return queue->head.tqh_first == NULL;
|
||||
}
|
||||
|
||||
// TODO The mir_event_ref is not supposed to be used but ... its needed
|
||||
// in this case. Need to wait until we can read from an FD set up by mir
|
||||
// for single threaded event handling.
|
||||
static EventNode* newEventNode(const MirEvent* event, _GLFWwindow* context)
|
||||
{
|
||||
EventNode* newNode = calloc(1, sizeof(EventNode));
|
||||
newNode->event = mir_event_ref(event);
|
||||
newNode->window = context;
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
static void enqueueEvent(const MirEvent* event, _GLFWwindow* context)
|
||||
{
|
||||
pthread_mutex_lock(&_glfw.mir.eventMutex);
|
||||
|
||||
EventNode* newNode = newEventNode(event, context);
|
||||
TAILQ_INSERT_TAIL(&_glfw.mir.eventQueue->head, newNode, entries);
|
||||
|
||||
pthread_cond_signal(&_glfw.mir.eventCond);
|
||||
|
||||
pthread_mutex_unlock(&_glfw.mir.eventMutex);
|
||||
}
|
||||
|
||||
static EventNode* dequeueEvent(EventQueue* queue)
|
||||
{
|
||||
EventNode* node = NULL;
|
||||
|
||||
pthread_mutex_lock(&_glfw.mir.eventMutex);
|
||||
|
||||
node = queue->head.tqh_first;
|
||||
|
||||
if (node)
|
||||
TAILQ_REMOVE(&queue->head, node, entries);
|
||||
|
||||
pthread_mutex_unlock(&_glfw.mir.eventMutex);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static MirPixelFormat findValidPixelFormat(void)
|
||||
{
|
||||
unsigned int i, validFormats, mirPixelFormats = 32;
|
||||
MirPixelFormat formats[mir_pixel_formats];
|
||||
|
||||
mir_connection_get_available_surface_formats(_glfw.mir.connection, formats,
|
||||
mirPixelFormats, &validFormats);
|
||||
|
||||
for (i = 0; i < validFormats; i++)
|
||||
{
|
||||
if (formats[i] == mir_pixel_format_abgr_8888 ||
|
||||
formats[i] == mir_pixel_format_xbgr_8888 ||
|
||||
formats[i] == mir_pixel_format_argb_8888 ||
|
||||
formats[i] == mir_pixel_format_xrgb_8888)
|
||||
{
|
||||
return formats[i];
|
||||
}
|
||||
}
|
||||
|
||||
return mir_pixel_format_invalid;
|
||||
}
|
||||
|
||||
static int mirModToGLFWMod(uint32_t mods)
|
||||
{
|
||||
int publicMods = 0x0;
|
||||
|
||||
if (mods & mir_input_event_modifier_alt)
|
||||
publicMods |= GLFW_MOD_ALT;
|
||||
if (mods & mir_input_event_modifier_shift)
|
||||
publicMods |= GLFW_MOD_SHIFT;
|
||||
if (mods & mir_input_event_modifier_ctrl)
|
||||
publicMods |= GLFW_MOD_CONTROL;
|
||||
if (mods & mir_input_event_modifier_meta)
|
||||
publicMods |= GLFW_MOD_SUPER;
|
||||
if (mods & mir_input_event_modifier_caps_lock)
|
||||
publicMods |= GLFW_MOD_CAPS_LOCK;
|
||||
if (mods & mir_input_event_modifier_num_lock)
|
||||
publicMods |= GLFW_MOD_NUM_LOCK;
|
||||
|
||||
return publicMods;
|
||||
}
|
||||
|
||||
static int toGLFWKeyCode(uint32_t key)
|
||||
{
|
||||
if (key < sizeof(_glfw.mir.keycodes) / sizeof(_glfw.mir.keycodes[0]))
|
||||
return _glfw.mir.keycodes[key];
|
||||
|
||||
return GLFW_KEY_UNKNOWN;
|
||||
}
|
||||
|
||||
static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* window)
|
||||
{
|
||||
const int action = mir_keyboard_event_action (key_event);
|
||||
const int scan_code = mir_keyboard_event_scan_code(key_event);
|
||||
const int key_code = mir_keyboard_event_key_code (key_event);
|
||||
const int modifiers = mir_keyboard_event_modifiers(key_event);
|
||||
|
||||
const int pressed = action == mir_keyboard_action_up ? GLFW_RELEASE : GLFW_PRESS;
|
||||
const int mods = mirModToGLFWMod(modifiers);
|
||||
const long text = _glfwKeySym2Unicode(key_code);
|
||||
const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
|
||||
|
||||
_glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
|
||||
|
||||
if (text != -1)
|
||||
_glfwInputChar(window, text, mods, plain);
|
||||
}
|
||||
|
||||
static void handlePointerButton(_GLFWwindow* window,
|
||||
int pressed,
|
||||
const MirPointerEvent* pointer_event)
|
||||
{
|
||||
int mods = mir_pointer_event_modifiers(pointer_event);
|
||||
const int publicMods = mirModToGLFWMod(mods);
|
||||
MirPointerButton button = mir_pointer_button_primary;
|
||||
static uint32_t oldButtonStates = 0;
|
||||
uint32_t newButtonStates = mir_pointer_event_buttons(pointer_event);
|
||||
int publicButton = GLFW_MOUSE_BUTTON_LEFT;
|
||||
|
||||
// XOR our old button states our new states to figure out what was added or removed
|
||||
button = newButtonStates ^ oldButtonStates;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
case mir_pointer_button_primary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_LEFT;
|
||||
break;
|
||||
case mir_pointer_button_secondary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_RIGHT;
|
||||
break;
|
||||
case mir_pointer_button_tertiary:
|
||||
publicButton = GLFW_MOUSE_BUTTON_MIDDLE;
|
||||
break;
|
||||
case mir_pointer_button_forward:
|
||||
// FIXME What is the forward button?
|
||||
publicButton = GLFW_MOUSE_BUTTON_4;
|
||||
break;
|
||||
case mir_pointer_button_back:
|
||||
// FIXME What is the back button?
|
||||
publicButton = GLFW_MOUSE_BUTTON_5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
oldButtonStates = newButtonStates;
|
||||
|
||||
_glfwInputMouseClick(window, publicButton, pressed, publicMods);
|
||||
}
|
||||
|
||||
static void handlePointerMotion(_GLFWwindow* window,
|
||||
const MirPointerEvent* pointer_event)
|
||||
{
|
||||
const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
|
||||
const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
if (_glfw.mir.disabledCursorWindow != window)
|
||||
return;
|
||||
|
||||
const int dx = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_x);
|
||||
const int dy = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_relative_y);
|
||||
const int current_x = window->virtualCursorPosX;
|
||||
const int current_y = window->virtualCursorPosY;
|
||||
|
||||
_glfwInputCursorPos(window, dx + current_x, dy + current_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
|
||||
const int y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
|
||||
|
||||
_glfwInputCursorPos(window, x, y);
|
||||
}
|
||||
|
||||
if (hscroll != 0 || vscroll != 0)
|
||||
_glfwInputScroll(window, hscroll, vscroll);
|
||||
}
|
||||
|
||||
static void handlePointerEvent(const MirPointerEvent* pointer_event,
|
||||
_GLFWwindow* window)
|
||||
{
|
||||
int action = mir_pointer_event_action(pointer_event);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case mir_pointer_action_button_down:
|
||||
handlePointerButton(window, GLFW_PRESS, pointer_event);
|
||||
break;
|
||||
case mir_pointer_action_button_up:
|
||||
handlePointerButton(window, GLFW_RELEASE, pointer_event);
|
||||
break;
|
||||
case mir_pointer_action_motion:
|
||||
handlePointerMotion(window, pointer_event);
|
||||
break;
|
||||
case mir_pointer_action_enter:
|
||||
case mir_pointer_action_leave:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleInput(const MirInputEvent* input_event, _GLFWwindow* window)
|
||||
{
|
||||
int type = mir_input_event_get_type(input_event);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case mir_input_event_type_key:
|
||||
handleKeyEvent(mir_input_event_get_keyboard_event(input_event), window);
|
||||
break;
|
||||
case mir_input_event_type_pointer:
|
||||
handlePointerEvent(mir_input_event_get_pointer_event(input_event), window);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEvent(const MirEvent* event, _GLFWwindow* window)
|
||||
{
|
||||
int type = mir_event_get_type(event);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case mir_event_type_input:
|
||||
handleInput(mir_event_get_input_event(event), window);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void addNewEvent(MirWindow* window, const MirEvent* event, void* context)
|
||||
{
|
||||
enqueueEvent(event, context);
|
||||
}
|
||||
|
||||
static GLFWbool createWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
MirBufferUsage buffer_usage = mir_buffer_usage_hardware;
|
||||
MirPixelFormat pixel_format = findValidPixelFormat();
|
||||
|
||||
if (pixel_format == mir_pixel_format_invalid)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unable to find a correct pixel format");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
spec = mir_create_normal_window_spec(_glfw.mir.connection,
|
||||
window->mir.width,
|
||||
window->mir.height);
|
||||
|
||||
mir_window_spec_set_pixel_format(spec, pixel_format);
|
||||
mir_window_spec_set_buffer_usage(spec, buffer_usage);
|
||||
|
||||
window->mir.window = mir_create_window_sync(spec);
|
||||
mir_window_spec_release(spec);
|
||||
|
||||
if (!mir_window_is_valid(window->mir.window))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unable to create window: %s",
|
||||
mir_window_get_error_message(window->mir.window));
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
mir_window_set_event_handler(window->mir.window, addNewEvent, window);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void setWindowConfinement(_GLFWwindow* window, MirPointerConfinementState state)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_pointer_confinement(spec, state);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwInitEventQueueMir(EventQueue* queue)
|
||||
{
|
||||
TAILQ_INIT(&queue->head);
|
||||
}
|
||||
|
||||
void _glfwDeleteEventQueueMir(EventQueue* queue)
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
EventNode* node, *node_next;
|
||||
node = queue->head.tqh_first;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
node_next = node->entries.tqe_next;
|
||||
|
||||
TAILQ_REMOVE(&queue->head, node, entries);
|
||||
deleteNode(queue, node);
|
||||
|
||||
node = node_next;
|
||||
}
|
||||
|
||||
free(queue);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
const _GLFWctxconfig* ctxconfig,
|
||||
const _GLFWfbconfig* fbconfig)
|
||||
{
|
||||
if (window->monitor)
|
||||
{
|
||||
GLFWvidmode mode;
|
||||
_glfwPlatformGetVideoMode(window->monitor, &mode);
|
||||
|
||||
mir_window_set_state(window->mir.window, mir_window_state_fullscreen);
|
||||
|
||||
if (wndconfig->width > mode.width || wndconfig->height > mode.height)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Requested window size too large: %ix%i",
|
||||
wndconfig->width, wndconfig->height);
|
||||
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
window->mir.width = wndconfig->width;
|
||||
window->mir.height = wndconfig->height;
|
||||
window->mir.currentCursor = NULL;
|
||||
|
||||
if (!createWindow(window))
|
||||
return GLFW_FALSE;
|
||||
|
||||
window->mir.nativeWindow = mir_buffer_stream_get_egl_native_window(
|
||||
mir_window_get_buffer_stream(window->mir.window));
|
||||
|
||||
if (ctxconfig->client != GLFW_NO_API)
|
||||
{
|
||||
if (ctxconfig->source == GLFW_EGL_CONTEXT_API ||
|
||||
ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitEGL())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
|
||||
{
|
||||
if (!_glfwInitOSMesa())
|
||||
return GLFW_FALSE;
|
||||
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.mir.disabledCursorWindow == window)
|
||||
_glfw.mir.disabledCursorWindow = NULL;
|
||||
|
||||
if (mir_window_is_valid(window->mir.window))
|
||||
{
|
||||
mir_window_release_sync(window->mir.window);
|
||||
window->mir.window= NULL;
|
||||
}
|
||||
|
||||
if (window->context.destroy)
|
||||
window->context.destroy(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_name(spec, title);
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
int count, const GLFWimage* images)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_width (spec, width);
|
||||
mir_window_spec_set_height(spec, height);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
int minwidth, int minheight,
|
||||
int maxwidth, int maxheight)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_max_width (spec, maxwidth);
|
||||
mir_window_spec_set_max_height(spec, maxheight);
|
||||
mir_window_spec_set_min_width (spec, minwidth);
|
||||
mir_window_spec_set_min_height(spec, minheight);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->mir.width;
|
||||
if (height)
|
||||
*height = window->mir.height;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
|
||||
float* xscale, float* yscale)
|
||||
{
|
||||
if (xscale)
|
||||
*xscale = 1.f;
|
||||
if (yscale)
|
||||
*yscale = 1.f;
|
||||
}
|
||||
|
||||
void _glfwPlatformIconifyWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_state(spec, mir_window_state_minimized);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_state(spec, mir_window_state_restored);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_state(spec, mir_window_state_maximized);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_state(spec, mir_window_state_hidden);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||
{
|
||||
MirWindowSpec* spec;
|
||||
|
||||
spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_state(spec, mir_window_state_restored);
|
||||
|
||||
mir_window_apply_spec(window->mir.window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformFocusWindow(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
_GLFWmonitor* monitor,
|
||||
int xpos, int ypos,
|
||||
int width, int height,
|
||||
int refreshRate)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowFocused(_GLFWwindow* window)
|
||||
{
|
||||
return mir_window_get_focus_state(window->mir.window) == mir_window_focus_state_focused;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowIconified(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowVisible(_GLFWwindow* window)
|
||||
{
|
||||
return mir_window_get_visibility(window->mir.window) == mir_window_visibility_exposed;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||
{
|
||||
return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
|
||||
}
|
||||
|
||||
int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
EventNode* node = NULL;
|
||||
|
||||
while ((node = dequeueEvent(_glfw.mir.eventQueue)))
|
||||
{
|
||||
handleEvent(node->event, node->window);
|
||||
deleteNode(_glfw.mir.eventQueue, node);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
pthread_mutex_lock(&_glfw.mir.eventMutex);
|
||||
|
||||
while (emptyEventQueue(_glfw.mir.eventQueue))
|
||||
pthread_cond_wait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex);
|
||||
|
||||
pthread_mutex_unlock(&_glfw.mir.eventMutex);
|
||||
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
{
|
||||
pthread_mutex_lock(&_glfw.mir.eventMutex);
|
||||
|
||||
if (emptyEventQueue(_glfw.mir.eventQueue))
|
||||
{
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_REALTIME, &time);
|
||||
time.tv_sec += (long) timeout;
|
||||
time.tv_nsec += (long) ((timeout - (long) timeout) * 1e9);
|
||||
pthread_cond_timedwait(&_glfw.mir.eventCond, &_glfw.mir.eventMutex, &time);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_glfw.mir.eventMutex);
|
||||
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
if (width)
|
||||
*width = window->mir.width;
|
||||
if (height)
|
||||
*height = window->mir.height;
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
const GLFWimage* image,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
MirBufferStream* stream;
|
||||
|
||||
int i_w = image->width;
|
||||
int i_h = image->height;
|
||||
|
||||
stream = mir_connection_create_buffer_stream_sync(_glfw.mir.connection,
|
||||
i_w, i_h,
|
||||
mir_pixel_format_argb_8888,
|
||||
mir_buffer_usage_software);
|
||||
|
||||
cursor->mir.conf = mir_cursor_configuration_from_buffer_stream(stream, xhot, yhot);
|
||||
|
||||
MirGraphicsRegion region;
|
||||
mir_buffer_stream_get_graphics_region(stream, ®ion);
|
||||
|
||||
unsigned char* pixels = image->pixels;
|
||||
char* dest = region.vaddr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < i_w * i_h; i++, pixels += 4)
|
||||
{
|
||||
unsigned int alpha = pixels[3];
|
||||
*dest++ = (char)(pixels[2] * alpha / 255);
|
||||
*dest++ = (char)(pixels[1] * alpha / 255);
|
||||
*dest++ = (char)(pixels[0] * alpha / 255);
|
||||
*dest++ = (char)alpha;
|
||||
}
|
||||
|
||||
mir_buffer_stream_swap_buffers_sync(stream);
|
||||
cursor->mir.customCursor = stream;
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static const char* getSystemCursorName(int shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case GLFW_ARROW_CURSOR:
|
||||
return mir_arrow_cursor_name;
|
||||
case GLFW_IBEAM_CURSOR:
|
||||
return mir_caret_cursor_name;
|
||||
case GLFW_CROSSHAIR_CURSOR:
|
||||
return mir_crosshair_cursor_name;
|
||||
case GLFW_HAND_CURSOR:
|
||||
return mir_open_hand_cursor_name;
|
||||
case GLFW_HRESIZE_CURSOR:
|
||||
return mir_horizontal_resize_cursor_name;
|
||||
case GLFW_VRESIZE_CURSOR:
|
||||
return mir_vertical_resize_cursor_name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
cursor->mir.conf = NULL;
|
||||
cursor->mir.customCursor = NULL;
|
||||
cursor->mir.cursorName = getSystemCursorName(shape);
|
||||
|
||||
return cursor->mir.cursorName != NULL;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
if (cursor->mir.conf)
|
||||
mir_cursor_configuration_destroy(cursor->mir.conf);
|
||||
if (cursor->mir.customCursor)
|
||||
mir_buffer_stream_release_sync(cursor->mir.customCursor);
|
||||
}
|
||||
|
||||
static void setCursorNameForWindow(MirWindow* window, char const* name)
|
||||
{
|
||||
MirWindowSpec* spec = mir_create_window_spec(_glfw.mir.connection);
|
||||
mir_window_spec_set_cursor_name(spec, name);
|
||||
mir_window_apply_spec(window, spec);
|
||||
mir_window_spec_release(spec);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
if (cursor)
|
||||
{
|
||||
window->mir.currentCursor = cursor;
|
||||
|
||||
if (cursor->mir.cursorName)
|
||||
{
|
||||
setCursorNameForWindow(window->mir.window, cursor->mir.cursorName);
|
||||
}
|
||||
else if (cursor->mir.conf)
|
||||
{
|
||||
mir_window_configure_cursor(window->mir.window, cursor->mir.conf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursorNameForWindow(window->mir.window, mir_default_cursor_name);
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||
{
|
||||
if (mode == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
_glfw.mir.disabledCursorWindow = window;
|
||||
setWindowConfinement(window, mir_pointer_confined_to_window);
|
||||
setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we were disabled before lets undo that!
|
||||
if (_glfw.mir.disabledCursorWindow == window)
|
||||
{
|
||||
_glfw.mir.disabledCursorWindow = NULL;
|
||||
setWindowConfinement(window, mir_pointer_unconfined);
|
||||
}
|
||||
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
{
|
||||
_glfwPlatformSetCursor(window, window->mir.currentCursor);
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
|
||||
{
|
||||
setCursorNameForWindow(window->mir.window, mir_disabled_cursor_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetScancodeName(int scancode)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int _glfwPlatformGetKeyScancode(int key)
|
||||
{
|
||||
return _glfw.mir.scancodes[key];
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(void)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Unsupported function %s", __PRETTY_FUNCTION__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||
{
|
||||
if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_mir_surface)
|
||||
return;
|
||||
|
||||
extensions[0] = "VK_KHR_surface";
|
||||
extensions[1] = "VK_KHR_mir_surface";
|
||||
}
|
||||
|
||||
int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
|
||||
VkPhysicalDevice device,
|
||||
uint32_t queuefamily)
|
||||
{
|
||||
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR
|
||||
vkGetPhysicalDeviceMirPresentationSupportKHR =
|
||||
(PFN_vkGetPhysicalDeviceMirPresentationSupportKHR)
|
||||
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR");
|
||||
if (!vkGetPhysicalDeviceMirPresentationSupportKHR)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return vkGetPhysicalDeviceMirPresentationSupportKHR(device,
|
||||
queuefamily,
|
||||
_glfw.mir.connection);
|
||||
}
|
||||
|
||||
VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
_GLFWwindow* window,
|
||||
const VkAllocationCallbacks* allocator,
|
||||
VkSurfaceKHR* surface)
|
||||
{
|
||||
VkResult err;
|
||||
VkMirWindowCreateInfoKHR sci;
|
||||
PFN_vkCreateMirWindowKHR vkCreateMirWindowKHR;
|
||||
|
||||
vkCreateMirWindowKHR = (PFN_vkCreateMirWindowKHR)
|
||||
vkGetInstanceProcAddr(instance, "vkCreateMirWindowKHR");
|
||||
if (!vkCreateMirWindowKHR)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"Mir: Vulkan instance missing VK_KHR_mir_surface extension");
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
memset(&sci, 0, sizeof(sci));
|
||||
sci.sType = VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR;
|
||||
sci.connection = _glfw.mir.connection;
|
||||
sci.mirWindow = window->mir.window;
|
||||
|
||||
err = vkCreateMirWindowKHR(instance, &sci, allocator, surface);
|
||||
if (err)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Mir: Failed to create Vulkan surface: %s",
|
||||
_glfwGetVulkanResultString(err));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW native API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GLFWAPI MirConnection* glfwGetMirDisplay(void)
|
||||
{
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return _glfw.mir.connection;
|
||||
}
|
||||
|
||||
GLFWAPI MirWindow* glfwGetMirWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return window->mir.window;
|
||||
}
|
||||
|
||||
Vendored
+21
-12
@@ -427,12 +427,12 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle)
|
||||
|
||||
GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
{
|
||||
int i;
|
||||
unsigned short values[256];
|
||||
unsigned int i;
|
||||
unsigned short* values;
|
||||
GLFWgammaramp ramp;
|
||||
const GLFWgammaramp* original;
|
||||
assert(handle != NULL);
|
||||
assert(gamma == gamma);
|
||||
assert(gamma >= 0.f);
|
||||
assert(gamma > 0.f);
|
||||
assert(gamma <= FLT_MAX);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
@@ -443,18 +443,22 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
original = glfwGetGammaRamp(handle);
|
||||
if (!original)
|
||||
return;
|
||||
|
||||
values = calloc(original->size, sizeof(unsigned short));
|
||||
|
||||
for (i = 0; i < original->size; i++)
|
||||
{
|
||||
float value;
|
||||
|
||||
// Calculate intensity
|
||||
value = i / 255.f;
|
||||
value = i / (float) (original->size - 1);
|
||||
// Apply gamma curve
|
||||
value = powf(value, 1.f / gamma) * 65535.f + 0.5f;
|
||||
|
||||
// Clamp to value range
|
||||
if (value > 65535.f)
|
||||
value = 65535.f;
|
||||
value = _glfw_fminf(value, 65535.f);
|
||||
|
||||
values[i] = (unsigned short) value;
|
||||
}
|
||||
@@ -462,9 +466,10 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma)
|
||||
ramp.red = values;
|
||||
ramp.green = values;
|
||||
ramp.blue = values;
|
||||
ramp.size = 256;
|
||||
ramp.size = original->size;
|
||||
|
||||
glfwSetGammaRamp(handle, &ramp);
|
||||
free(values);
|
||||
}
|
||||
|
||||
GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
|
||||
@@ -475,7 +480,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle)
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
_glfwFreeGammaArrays(&monitor->currentRamp);
|
||||
_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp);
|
||||
if (!_glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp))
|
||||
return NULL;
|
||||
|
||||
return &monitor->currentRamp;
|
||||
}
|
||||
@@ -501,7 +507,10 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
|
||||
_GLFW_REQUIRE_INIT();
|
||||
|
||||
if (!monitor->originalRamp.size)
|
||||
_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp);
|
||||
{
|
||||
if (!_glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp))
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwPlatformSetGammaRamp(monitor, ramp);
|
||||
}
|
||||
|
||||
Vendored
+7
-2
@@ -26,6 +26,10 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400
|
||||
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
static void makeContextCurrentNSGL(_GLFWwindow* window)
|
||||
{
|
||||
@@ -49,7 +53,7 @@ static void swapIntervalNSGL(int interval)
|
||||
|
||||
GLint sync = interval;
|
||||
[window->context.nsgl.object setValues:&sync
|
||||
forParameter:NSOpenGLCPSwapInterval];
|
||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
||||
}
|
||||
|
||||
static int extensionSupportedNSGL(const char* extension)
|
||||
@@ -299,7 +303,8 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
if (fbconfig->transparent)
|
||||
{
|
||||
GLint opaque = 0;
|
||||
[window->context.nsgl.object setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
|
||||
[window->context.nsgl.object setValues:&opaque
|
||||
forParameter:NSOpenGLContextParameterSurfaceOpacity];
|
||||
}
|
||||
|
||||
[window->context.nsgl.object setView:window->ns.view];
|
||||
|
||||
Vendored
+2
-1
@@ -58,8 +58,9 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
{
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
|
||||
+1
-1
@@ -240,7 +240,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
|
||||
if (ctxconfig->forward)
|
||||
{
|
||||
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
|
||||
"OSMesa: Foward-compatible contexts not supported");
|
||||
"OSMesa: Forward-compatible contexts not supported");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
|
||||
Vendored
-3
@@ -136,9 +136,6 @@ GLFWbool _glfwInitVulkan(int mode)
|
||||
#elif defined(_GLFW_WAYLAND)
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
|
||||
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
|
||||
#elif defined(_GLFW_MIR)
|
||||
else if (strcmp(ep[i].extensionName, "VK_KHR_mir_surface") == 0)
|
||||
_glfw.vk.KHR_mir_surface = GLFW_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Vendored
+32
-28
@@ -256,12 +256,20 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
|
||||
|
||||
static void swapBuffersWGL(_GLFWwindow* window)
|
||||
{
|
||||
// HACK: Use DwmFlush when desktop composition is enabled
|
||||
if (_glfwIsCompositionEnabledWin32() && !window->monitor)
|
||||
if (!window->monitor)
|
||||
{
|
||||
int count = abs(window->context.wgl.interval);
|
||||
while (count--)
|
||||
DwmFlush();
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Use DwmFlush when desktop composition is enabled
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
int count = abs(window->context.wgl.interval);
|
||||
while (count--)
|
||||
DwmFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwapBuffers(window->context.wgl.dc);
|
||||
@@ -273,10 +281,18 @@ static void swapIntervalWGL(int interval)
|
||||
|
||||
window->context.wgl.interval = interval;
|
||||
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||
// avoid interfering with DWM vsync
|
||||
if (_glfwIsCompositionEnabledWin32() && !window->monitor)
|
||||
interval = 0;
|
||||
if (!window->monitor)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
||||
// avoid interfering with DWM vsync
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
interval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wgl.EXT_swap_control)
|
||||
_glfw.wgl.SwapIntervalEXT(interval);
|
||||
@@ -284,29 +300,17 @@ static void swapIntervalWGL(int interval)
|
||||
|
||||
static int extensionSupportedWGL(const char* extension)
|
||||
{
|
||||
const char* extensions;
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringEXT)
|
||||
{
|
||||
extensions = _glfw.wgl.GetExtensionsStringEXT();
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
const char* extensions = NULL;
|
||||
|
||||
if (_glfw.wgl.GetExtensionsStringARB)
|
||||
{
|
||||
extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
|
||||
if (extensions)
|
||||
{
|
||||
if (_glfwStringInExtensionString(extension, extensions))
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
else if (_glfw.wgl.GetExtensionsStringEXT)
|
||||
extensions = _glfw.wgl.GetExtensionsStringEXT();
|
||||
|
||||
return GLFW_FALSE;
|
||||
if (!extensions)
|
||||
return GLFW_FALSE;
|
||||
|
||||
return _glfwStringInExtensionString(extension, extensions);
|
||||
}
|
||||
|
||||
static GLFWglproc getProcAddressWGL(const char* procname)
|
||||
|
||||
Vendored
+54
-14
@@ -62,17 +62,6 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
|
||||
|
||||
#endif // _GLFW_BUILD_DLL
|
||||
|
||||
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
|
||||
BOOL IsWindowsVersionOrGreater(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);
|
||||
return VerifyVersionInfoW(&osvi, mask, cond);
|
||||
}
|
||||
|
||||
// Load necessary libraries (DLLs)
|
||||
//
|
||||
static GLFWbool loadLibraries(void)
|
||||
@@ -100,6 +89,14 @@ static GLFWbool loadLibraries(void)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
|
||||
_glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
|
||||
_glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
|
||||
_glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext");
|
||||
_glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow");
|
||||
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
|
||||
|
||||
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
@@ -155,6 +152,13 @@ static GLFWbool loadLibraries(void)
|
||||
GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor");
|
||||
}
|
||||
|
||||
_glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll");
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
{
|
||||
_glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo)
|
||||
GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
@@ -179,6 +183,9 @@ static void freeLibraries(void)
|
||||
|
||||
if (_glfw.win32.shcore.instance)
|
||||
FreeLibrary(_glfw.win32.shcore.instance);
|
||||
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
FreeLibrary(_glfw.win32.ntdll.instance);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
@@ -309,6 +316,7 @@ static void createKeyTables(void)
|
||||
_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;
|
||||
|
||||
@@ -339,8 +347,8 @@ static HWND createHelperWindow(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// HACK: The first call to ShowWindow is ignored if the parent process
|
||||
// passed along a STARTUPINFO, so clear that flag with a no-op call
|
||||
// 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(window, SW_HIDE);
|
||||
|
||||
// Register for HID device notifications
|
||||
@@ -502,6 +510,36 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
|
||||
//
|
||||
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 embedd 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 embedd a non-default manifest
|
||||
// announcing support for Windows 10 via supportedOS GUID
|
||||
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
@@ -523,7 +561,9 @@ int _glfwPlatformInit(void)
|
||||
createKeyTables();
|
||||
_glfwUpdateKeyNamesWin32();
|
||||
|
||||
if (IsWindows8Point1OrGreater())
|
||||
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
else if (IsWindows8Point1OrGreater())
|
||||
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
else if (IsWindowsVistaOrGreater())
|
||||
SetProcessDPIAware();
|
||||
|
||||
+2
@@ -260,6 +260,8 @@ static void closeJoystick(_GLFWjoystick* js)
|
||||
IDirectInputDevice8_Release(js->win32.device);
|
||||
}
|
||||
|
||||
free(js->win32.objects);
|
||||
|
||||
_glfwFreeJoystick(js);
|
||||
_glfwInputJoystick(js, GLFW_DISCONNECTED);
|
||||
}
|
||||
|
||||
+5
-3
@@ -324,9 +324,9 @@ void _glfwGetMonitorContentScaleWin32(HMONITOR handle, float* xscale, float* ysc
|
||||
}
|
||||
|
||||
if (xscale)
|
||||
*xscale = xdpi / 96.f;
|
||||
*xscale = xdpi / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
if (yscale)
|
||||
*yscale = ydpi / 96.f;
|
||||
*yscale = ydpi / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
|
||||
@@ -455,7 +455,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
&mode->blueBits);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
HDC dc;
|
||||
WORD values[768];
|
||||
@@ -469,6 +469,8 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short));
|
||||
memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short));
|
||||
memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short));
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
|
||||
+55
-14
@@ -98,6 +98,12 @@
|
||||
#ifndef _WIN32_WINNT_WINBLUE
|
||||
#define _WIN32_WINNT_WINBLUE 0x0602
|
||||
#endif
|
||||
#ifndef WM_GETDPISCALEDSIZE
|
||||
#define WM_GETDPISCALEDSIZE 0x02e4
|
||||
#endif
|
||||
#ifndef USER_DEFAULT_SCREEN_DPI
|
||||
#define USER_DEFAULT_SCREEN_DPI 96
|
||||
#endif
|
||||
|
||||
#if WINVER < 0x0601
|
||||
typedef struct
|
||||
@@ -140,20 +146,31 @@ typedef enum
|
||||
} MONITOR_DPI_TYPE;
|
||||
#endif /*DPI_ENUMS_DECLARED*/
|
||||
|
||||
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
|
||||
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
|
||||
|
||||
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
|
||||
BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp);
|
||||
#define IsWindowsVistaOrGreater() \
|
||||
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), \
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 0)
|
||||
#define IsWindows7OrGreater() \
|
||||
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), \
|
||||
LOBYTE(_WIN32_WINNT_WIN7), 0)
|
||||
#define IsWindows8OrGreater() \
|
||||
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), \
|
||||
LOBYTE(_WIN32_WINNT_WIN8), 0)
|
||||
#define IsWindows8Point1OrGreater() \
|
||||
IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), \
|
||||
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
|
||||
#define IsWindowsXPOrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), \
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 0)
|
||||
#define IsWindowsVistaOrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 0)
|
||||
#define IsWindows7OrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN7), \
|
||||
LOBYTE(_WIN32_WINNT_WIN7), 0)
|
||||
#define IsWindows8OrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WIN8), \
|
||||
LOBYTE(_WIN32_WINNT_WIN8), 0)
|
||||
#define IsWindows8Point1OrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \
|
||||
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
|
||||
|
||||
#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \
|
||||
_glfwIsWindows10BuildOrGreaterWin32(14393)
|
||||
#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \
|
||||
_glfwIsWindows10BuildOrGreaterWin32(15063)
|
||||
|
||||
// HACK: Define macros that some xinput.h variants don't
|
||||
#ifndef XINPUT_CAPS_WIRELESS
|
||||
@@ -206,8 +223,16 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID*
|
||||
// user32.dll function pointer typedefs
|
||||
typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void);
|
||||
typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*);
|
||||
typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
|
||||
typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
|
||||
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
|
||||
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
|
||||
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
|
||||
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
|
||||
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
|
||||
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
|
||||
|
||||
// dwmapi.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
|
||||
@@ -223,6 +248,10 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,
|
||||
#define SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness_
|
||||
#define GetDpiForMonitor _glfw.win32.shcore.GetDpiForMonitor_
|
||||
|
||||
// ntdll.dll function pointer typedefs
|
||||
typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
|
||||
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
|
||||
|
||||
typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
|
||||
|
||||
typedef struct VkWin32SurfaceCreateInfoKHR
|
||||
@@ -276,6 +305,7 @@ typedef struct _GLFWwindowWin32
|
||||
GLFWbool maximized;
|
||||
// Whether to enable framebuffer transparency on DWM
|
||||
GLFWbool transparent;
|
||||
GLFWbool scaleToMonitor;
|
||||
|
||||
// The last received cursor position, regardless of source
|
||||
int lastCursorPosX, lastCursorPosY;
|
||||
@@ -300,6 +330,7 @@ typedef struct _GLFWlibraryWin32
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
RAWINPUT* rawInput;
|
||||
int rawInputSize;
|
||||
UINT mouseTrailSize;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
@@ -322,6 +353,10 @@ typedef struct _GLFWlibraryWin32
|
||||
HINSTANCE instance;
|
||||
PFN_SetProcessDPIAware SetProcessDPIAware_;
|
||||
PFN_ChangeWindowMessageFilterEx ChangeWindowMessageFilterEx_;
|
||||
PFN_EnableNonClientDpiScaling EnableNonClientDpiScaling_;
|
||||
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
|
||||
PFN_GetDpiForWindow GetDpiForWindow_;
|
||||
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
|
||||
} user32;
|
||||
|
||||
struct {
|
||||
@@ -337,6 +372,11 @@ typedef struct _GLFWlibraryWin32
|
||||
PFN_GetDpiForMonitor GetDpiForMonitor_;
|
||||
} shcore;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
|
||||
} ntdll;
|
||||
|
||||
} _GLFWlibraryWin32;
|
||||
|
||||
// Win32-specific per-monitor data
|
||||
@@ -392,10 +432,11 @@ typedef struct _GLFWmutexWin32
|
||||
|
||||
GLFWbool _glfwRegisterWindowClassWin32(void);
|
||||
void _glfwUnregisterWindowClassWin32(void);
|
||||
GLFWbool _glfwIsCompositionEnabledWin32(void);
|
||||
|
||||
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
|
||||
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
|
||||
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp);
|
||||
BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build);
|
||||
void _glfwInputErrorWin32(int error, const char* description);
|
||||
void _glfwUpdateKeyNamesWin32(void);
|
||||
|
||||
|
||||
Vendored
+239
-60
@@ -186,14 +186,20 @@ static HICON createIcon(const GLFWimage* image,
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Translate client window size to full window size according to styles
|
||||
// Translate client window size to full window size according to styles and DPI
|
||||
//
|
||||
static void getFullWindowSize(DWORD style, DWORD exStyle,
|
||||
int clientWidth, int clientHeight,
|
||||
int* fullWidth, int* fullHeight)
|
||||
int* fullWidth, int* fullHeight,
|
||||
UINT dpi)
|
||||
{
|
||||
RECT rect = { 0, 0, clientWidth, clientHeight };
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
|
||||
*fullWidth = rect.right - rect.left;
|
||||
*fullHeight = rect.bottom - rect.top;
|
||||
}
|
||||
@@ -203,10 +209,14 @@ static void getFullWindowSize(DWORD style, DWORD exStyle,
|
||||
static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
|
||||
{
|
||||
int xoff, yoff;
|
||||
UINT dpi = USER_DEFAULT_SCREEN_DPI;
|
||||
const float ratio = (float) window->numer / (float) window->denom;
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
dpi = GetDpiForWindow(window->win32.handle);
|
||||
|
||||
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
|
||||
0, 0, &xoff, &yoff);
|
||||
0, 0, &xoff, &yoff, dpi);
|
||||
|
||||
if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT ||
|
||||
edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
|
||||
@@ -337,7 +347,16 @@ static void updateWindowStyles(const _GLFWwindow* window)
|
||||
style |= getWindowStyle(window);
|
||||
|
||||
GetClientRect(window->win32.handle, &rect);
|
||||
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE,
|
||||
getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
|
||||
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
|
||||
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
|
||||
@@ -351,10 +370,12 @@ static void updateWindowStyles(const _GLFWwindow* window)
|
||||
//
|
||||
static void updateFramebufferTransparency(const _GLFWwindow* window)
|
||||
{
|
||||
BOOL enabled;
|
||||
|
||||
if (!IsWindowsVistaOrGreater())
|
||||
return;
|
||||
|
||||
if (_glfwIsCompositionEnabledWin32())
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
|
||||
{
|
||||
HRGN region = CreateRectRgn(0, 0, -1, -1);
|
||||
DWM_BLURBEHIND bb = {0};
|
||||
@@ -396,29 +417,6 @@ static void updateFramebufferTransparency(const _GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
// Translates a GLFW standard cursor to a resource ID
|
||||
//
|
||||
static LPWSTR translateCursorShape(int shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case GLFW_ARROW_CURSOR:
|
||||
return IDC_ARROW;
|
||||
case GLFW_IBEAM_CURSOR:
|
||||
return IDC_IBEAM;
|
||||
case GLFW_CROSSHAIR_CURSOR:
|
||||
return IDC_CROSS;
|
||||
case GLFW_HAND_CURSOR:
|
||||
return IDC_HAND;
|
||||
case GLFW_HRESIZE_CURSOR:
|
||||
return IDC_SIZEWE;
|
||||
case GLFW_VRESIZE_CURSOR:
|
||||
return IDC_SIZENS;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Retrieves and translates modifier keys
|
||||
//
|
||||
static int getKeyMods(void)
|
||||
@@ -529,7 +527,18 @@ static void fitToMonitor(_GLFWwindow* window)
|
||||
static void acquireMonitor(_GLFWwindow* window)
|
||||
{
|
||||
if (!_glfw.win32.acquiredMonitorCount)
|
||||
{
|
||||
SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
|
||||
|
||||
// HACK: When mouse trails are enabled the cursor becomes invisible when
|
||||
// the OpenGL ICD switches to page flipping
|
||||
if (IsWindowsXPOrGreater())
|
||||
{
|
||||
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!window->monitor->window)
|
||||
_glfw.win32.acquiredMonitorCount++;
|
||||
|
||||
@@ -546,8 +555,14 @@ static void releaseMonitor(_GLFWwindow* window)
|
||||
|
||||
_glfw.win32.acquiredMonitorCount--;
|
||||
if (!_glfw.win32.acquiredMonitorCount)
|
||||
{
|
||||
SetThreadExecutionState(ES_CONTINUOUS);
|
||||
|
||||
// HACK: Restore mouse trail length saved in acquireMonitor
|
||||
if (IsWindowsXPOrGreater())
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
|
||||
}
|
||||
|
||||
_glfwInputMonitorWindow(window->monitor, NULL);
|
||||
_glfwRestoreVideoModeWin32(window->monitor);
|
||||
}
|
||||
@@ -561,9 +576,18 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
if (!window)
|
||||
{
|
||||
// This is the message handling for the hidden helper window
|
||||
// and for a regular window during its initial creation
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
{
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
EnableNonClientDpiScaling(hWnd);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DISPLAYCHANGE:
|
||||
_glfwPollMonitorsWin32();
|
||||
break;
|
||||
@@ -980,13 +1004,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
int xoff, yoff;
|
||||
UINT dpi = USER_DEFAULT_SCREEN_DPI;
|
||||
MINMAXINFO* mmi = (MINMAXINFO*) lParam;
|
||||
|
||||
if (window->monitor)
|
||||
break;
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
dpi = GetDpiForWindow(window->win32.handle);
|
||||
|
||||
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
|
||||
0, 0, &xoff, &yoff);
|
||||
0, 0, &xoff, &yoff, dpi);
|
||||
|
||||
if (window->minwidth != GLFW_DONT_CARE &&
|
||||
window->minheight != GLFW_DONT_CARE)
|
||||
@@ -1032,6 +1060,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_NCACTIVATE:
|
||||
case WM_NCPAINT:
|
||||
{
|
||||
// Prevent title bar from being drawn after restoring a minimized
|
||||
// undecorated window
|
||||
if (!window->decorated)
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DWMCOMPOSITIONCHANGED:
|
||||
{
|
||||
if (window->win32.transparent)
|
||||
@@ -1039,10 +1078,52 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_GETDPISCALEDSIZE:
|
||||
{
|
||||
if (window->win32.scaleToMonitor)
|
||||
break;
|
||||
|
||||
// Adjust the window size to keep the client area size constant
|
||||
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
|
||||
{
|
||||
RECT source = {0}, target = {0};
|
||||
SIZE* size = (SIZE*) lParam;
|
||||
|
||||
AdjustWindowRectExForDpi(&source, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
AdjustWindowRectExForDpi(&target, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
LOWORD(wParam));
|
||||
|
||||
size->cx += (target.right - target.left) -
|
||||
(source.right - source.left);
|
||||
size->cy += (target.bottom - target.top) -
|
||||
(source.bottom - source.top);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_DPICHANGED:
|
||||
{
|
||||
const float xscale = HIWORD(wParam) / 96.f;
|
||||
const float yscale = LOWORD(wParam) / 96.f;
|
||||
const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
|
||||
|
||||
// Only apply the suggested size if the OS is new enough to have
|
||||
// sent a WM_GETDPISCALEDSIZE before this
|
||||
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
|
||||
{
|
||||
RECT* suggested = (RECT*) lParam;
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
suggested->left,
|
||||
suggested->top,
|
||||
suggested->right - suggested->left,
|
||||
suggested->bottom - suggested->top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
_glfwInputWindowContentScale(window, xscale, yscale);
|
||||
break;
|
||||
}
|
||||
@@ -1129,7 +1210,8 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
getFullWindowSize(style, exStyle,
|
||||
wndconfig->width, wndconfig->height,
|
||||
&fullWidth, &fullHeight);
|
||||
&fullWidth, &fullHeight,
|
||||
USER_DEFAULT_SCREEN_DPI);
|
||||
}
|
||||
|
||||
wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
|
||||
@@ -1168,6 +1250,40 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
|
||||
}
|
||||
|
||||
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
|
||||
|
||||
// Adjust window size to account for DPI scaling of the window frame and
|
||||
// optionally DPI scaling of the client area
|
||||
// This cannot be done until we know what monitor it was placed on
|
||||
if (!window->monitor)
|
||||
{
|
||||
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
|
||||
|
||||
if (wndconfig->scaleToMonitor)
|
||||
{
|
||||
float xscale, yscale;
|
||||
_glfwPlatformGetWindowContentScale(window, &xscale, &yscale);
|
||||
rect.right = (int) (rect.right * xscale);
|
||||
rect.bottom = (int) (rect.bottom * yscale);
|
||||
}
|
||||
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
|
||||
SetWindowPos(window->win32.handle, NULL,
|
||||
rect.left, rect.top,
|
||||
rect.right - rect.left, rect.bottom - rect.top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
DragAcceptFiles(window->win32.handle, TRUE);
|
||||
|
||||
if (fbconfig->transparent)
|
||||
@@ -1227,20 +1343,6 @@ void _glfwUnregisterWindowClassWin32(void)
|
||||
UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
|
||||
}
|
||||
|
||||
// Returns whether desktop compositing is enabled
|
||||
//
|
||||
GLFWbool _glfwIsCompositionEnabledWin32(void)
|
||||
{
|
||||
if (IsWindowsVistaOrGreater())
|
||||
{
|
||||
BOOL enabled;
|
||||
if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)))
|
||||
return enabled;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
////// GLFW platform API //////
|
||||
@@ -1378,8 +1480,19 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||
void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
|
||||
{
|
||||
RECT rect = { xpos, ypos, xpos, ypos };
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
}
|
||||
|
||||
SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
|
||||
}
|
||||
@@ -1408,8 +1521,19 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
|
||||
else
|
||||
{
|
||||
RECT rect = { 0, 0, width, height };
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
}
|
||||
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
||||
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
|
||||
@@ -1464,8 +1588,18 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
|
||||
_glfwPlatformGetWindowSize(window, &width, &height);
|
||||
SetRect(&rect, 0, 0, width, height);
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
}
|
||||
|
||||
if (left)
|
||||
*left = -rect.left;
|
||||
@@ -1541,8 +1675,19 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
else
|
||||
{
|
||||
RECT rect = { xpos, ypos, xpos + width, ypos + height };
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
}
|
||||
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
rect.left, rect.top,
|
||||
rect.right - rect.left, rect.bottom - rect.top,
|
||||
@@ -1602,8 +1747,18 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
else
|
||||
after = HWND_NOTOPMOST;
|
||||
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window),
|
||||
GetDpiForWindow(window->win32.handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, getWindowStyle(window),
|
||||
FALSE, getWindowExStyle(window));
|
||||
}
|
||||
|
||||
SetWindowPos(window->win32.handle, after,
|
||||
rect.left, rect.top,
|
||||
rect.right - rect.left, rect.bottom - rect.top,
|
||||
@@ -1638,7 +1793,15 @@ int _glfwPlatformWindowHovered(_GLFWwindow* window)
|
||||
|
||||
int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
|
||||
{
|
||||
return window->win32.transparent && _glfwIsCompositionEnabledWin32();
|
||||
BOOL enabled;
|
||||
|
||||
if (!window->win32.transparent)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!IsWindowsVistaOrGreater())
|
||||
return GLFW_FALSE;
|
||||
|
||||
return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
|
||||
@@ -1845,8 +2008,24 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
cursor->win32.handle =
|
||||
CopyCursor(LoadCursorW(NULL, translateCursorShape(shape)));
|
||||
LPCWSTR name = NULL;
|
||||
|
||||
if (shape == GLFW_ARROW_CURSOR)
|
||||
name = IDC_ARROW;
|
||||
else if (shape == GLFW_IBEAM_CURSOR)
|
||||
name = IDC_IBEAM;
|
||||
else if (shape == GLFW_CROSSHAIR_CURSOR)
|
||||
name = IDC_CROSS;
|
||||
else if (shape == GLFW_HAND_CURSOR)
|
||||
name = IDC_HAND;
|
||||
else if (shape == GLFW_HRESIZE_CURSOR)
|
||||
name = IDC_SIZEWE;
|
||||
else if (shape == GLFW_VRESIZE_CURSOR)
|
||||
name = IDC_SIZENS;
|
||||
else
|
||||
return GLFW_FALSE;
|
||||
|
||||
cursor->win32.handle = CopyCursor(LoadCursorW(NULL, name));
|
||||
if (!cursor->win32.handle)
|
||||
{
|
||||
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
|
||||
|
||||
Vendored
+3
@@ -369,6 +369,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
|
||||
case GLFW_COCOA_GRAPHICS_SWITCHING:
|
||||
_glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
case GLFW_SCALE_TO_MONITOR:
|
||||
_glfw.hints.window.scaleToMonitor = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
case GLFW_CENTER_CURSOR:
|
||||
_glfw.hints.window.centerCursor = value ? GLFW_TRUE : GLFW_FALSE;
|
||||
return;
|
||||
|
||||
Vendored
+170
-13
@@ -27,6 +27,8 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -42,7 +44,8 @@ static inline int min(int n1, int n2)
|
||||
return n1 < n2 ? n1 : n2;
|
||||
}
|
||||
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface, int* which)
|
||||
static _GLFWwindow* findWindowFromDecorationSurface(struct wl_surface* surface,
|
||||
int* which)
|
||||
{
|
||||
int focus;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
@@ -96,7 +99,7 @@ static void pointerHandleEnter(void* data,
|
||||
}
|
||||
|
||||
window->wl.decorations.focus = focus;
|
||||
_glfw.wl.pointerSerial = serial;
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerFocus = window;
|
||||
|
||||
window->wl.hovered = GLFW_TRUE;
|
||||
@@ -117,26 +120,36 @@ static void pointerHandleLeave(void* data,
|
||||
|
||||
window->wl.hovered = GLFW_FALSE;
|
||||
|
||||
_glfw.wl.pointerSerial = serial;
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
_glfwInputCursorEnter(window, GLFW_FALSE);
|
||||
}
|
||||
|
||||
static void setCursor(const char* name)
|
||||
static void setCursor(_GLFWwindow* window, const char* name)
|
||||
{
|
||||
struct wl_buffer* buffer;
|
||||
struct wl_cursor* cursor;
|
||||
struct wl_cursor_image* image;
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
|
||||
int scale = 1;
|
||||
|
||||
cursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
|
||||
name);
|
||||
if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
|
||||
{
|
||||
// We only support up to scale=2 for now, since libwayland-cursor
|
||||
// requires us to load a different theme for each size.
|
||||
scale = 2;
|
||||
theme = _glfw.wl.cursorThemeHiDPI;
|
||||
}
|
||||
|
||||
cursor = wl_cursor_theme_get_cursor(theme, name);
|
||||
if (!cursor)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Standard cursor not found");
|
||||
return;
|
||||
}
|
||||
// TODO: handle animated cursors too.
|
||||
image = cursor->images[0];
|
||||
|
||||
if (!image)
|
||||
@@ -145,10 +158,11 @@ static void setCursor(const char* name)
|
||||
buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||
surface,
|
||||
image->hotspot_x,
|
||||
image->hotspot_y);
|
||||
image->hotspot_x / scale,
|
||||
image->hotspot_y / scale);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
image->width, image->height);
|
||||
@@ -211,7 +225,7 @@ static void pointerHandleMotion(void* data,
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
setCursor(cursorName);
|
||||
setCursor(window, cursorName);
|
||||
}
|
||||
|
||||
static void pointerHandleButton(void* data,
|
||||
@@ -295,7 +309,7 @@ static void pointerHandleButton(void* data,
|
||||
if (window->wl.decorations.focus != mainWindow)
|
||||
return;
|
||||
|
||||
_glfw.wl.pointerSerial = serial;
|
||||
_glfw.wl.serial = serial;
|
||||
|
||||
/* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
|
||||
* codes. */
|
||||
@@ -464,6 +478,7 @@ static void keyboardHandleEnter(void* data,
|
||||
return;
|
||||
}
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = window;
|
||||
_glfwInputWindowFocus(window, GLFW_TRUE);
|
||||
}
|
||||
@@ -478,6 +493,7 @@ static void keyboardHandleLeave(void* data,
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.keyboardFocus = NULL;
|
||||
_glfwInputWindowFocus(window, GLFW_FALSE);
|
||||
}
|
||||
@@ -561,6 +577,7 @@ static void keyboardHandleKey(void* data,
|
||||
action = state == WL_KEYBOARD_KEY_STATE_PRESSED
|
||||
? GLFW_PRESS : GLFW_RELEASE;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfwInputKey(window, keyCode, key, action,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
|
||||
@@ -592,6 +609,8 @@ static void keyboardHandleModifiers(void* data,
|
||||
xkb_mod_mask_t mask;
|
||||
unsigned int modifiers = 0;
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
|
||||
if (!_glfw.wl.xkb.keymap)
|
||||
return;
|
||||
|
||||
@@ -686,6 +705,70 @@ static const struct wl_seat_listener seatListener = {
|
||||
seatHandleName,
|
||||
};
|
||||
|
||||
static void dataOfferHandleOffer(void* data,
|
||||
struct wl_data_offer* dataOffer,
|
||||
const char* mimeType)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_listener dataOfferListener = {
|
||||
dataOfferHandleOffer,
|
||||
};
|
||||
|
||||
static void dataDeviceHandleDataOffer(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
struct wl_data_offer* id)
|
||||
{
|
||||
if (_glfw.wl.dataOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
||||
|
||||
_glfw.wl.dataOffer = id;
|
||||
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
|
||||
}
|
||||
|
||||
static void dataDeviceHandleEnter(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
uint32_t serial,
|
||||
struct wl_surface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
struct wl_data_offer *id)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleLeave(void* data,
|
||||
struct wl_data_device* dataDevice)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleMotion(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
uint32_t time,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleDrop(void* data,
|
||||
struct wl_data_device* dataDevice)
|
||||
{
|
||||
}
|
||||
|
||||
static void dataDeviceHandleSelection(void* data,
|
||||
struct wl_data_device* dataDevice,
|
||||
struct wl_data_offer* id)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_data_device_listener dataDeviceListener = {
|
||||
dataDeviceHandleDataOffer,
|
||||
dataDeviceHandleEnter,
|
||||
dataDeviceHandleLeave,
|
||||
dataDeviceHandleMotion,
|
||||
dataDeviceHandleDrop,
|
||||
dataDeviceHandleSelection,
|
||||
};
|
||||
|
||||
static void wmBaseHandlePing(void* data,
|
||||
struct xdg_wm_base* wmBase,
|
||||
uint32_t serial)
|
||||
@@ -740,12 +823,28 @@ static void registryHandleGlobal(void* data,
|
||||
wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
|
||||
}
|
||||
}
|
||||
else if (strcmp(interface, "wl_data_device_manager") == 0)
|
||||
{
|
||||
if (!_glfw.wl.dataDeviceManager)
|
||||
{
|
||||
_glfw.wl.dataDeviceManager =
|
||||
wl_registry_bind(registry, name,
|
||||
&wl_data_device_manager_interface, 1);
|
||||
}
|
||||
}
|
||||
else if (strcmp(interface, "xdg_wm_base") == 0)
|
||||
{
|
||||
_glfw.wl.wmBase =
|
||||
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
|
||||
}
|
||||
else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0)
|
||||
{
|
||||
_glfw.wl.decorationManager =
|
||||
wl_registry_bind(registry, name,
|
||||
&zxdg_decoration_manager_v1_interface,
|
||||
1);
|
||||
}
|
||||
else if (strcmp(interface, "wp_viewporter") == 0)
|
||||
{
|
||||
_glfw.wl.viewporter =
|
||||
@@ -939,6 +1038,12 @@ static void createKeyTables(void)
|
||||
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
const char *cursorTheme;
|
||||
const char *cursorSizeStr;
|
||||
char *cursorSizeEnd;
|
||||
long cursorSizeLong;
|
||||
int cursorSize;
|
||||
|
||||
_glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
|
||||
if (!_glfw.wl.cursor.handle)
|
||||
{
|
||||
@@ -1059,15 +1164,46 @@ int _glfwPlatformInit(void)
|
||||
|
||||
if (_glfw.wl.pointer && _glfw.wl.shm)
|
||||
{
|
||||
_glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm);
|
||||
cursorTheme = getenv("XCURSOR_THEME");
|
||||
cursorSizeStr = getenv("XCURSOR_SIZE");
|
||||
cursorSize = 32;
|
||||
if (cursorSizeStr)
|
||||
{
|
||||
errno = 0;
|
||||
cursorSizeLong = strtol(cursorSizeStr, &cursorSizeEnd, 10);
|
||||
if (!*cursorSizeEnd && !errno && cursorSizeLong > 0 && cursorSizeLong <= INT_MAX)
|
||||
cursorSize = (int)cursorSizeLong;
|
||||
}
|
||||
_glfw.wl.cursorTheme =
|
||||
wl_cursor_theme_load(cursorTheme, cursorSize, _glfw.wl.shm);
|
||||
if (!_glfw.wl.cursorTheme)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unable to load default cursor theme");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
// If this happens to be NULL, we just fallback to the scale=1 version.
|
||||
_glfw.wl.cursorThemeHiDPI =
|
||||
wl_cursor_theme_load(cursorTheme, 2 * cursorSize, _glfw.wl.shm);
|
||||
_glfw.wl.cursorSurface =
|
||||
wl_compositor_create_surface(_glfw.wl.compositor);
|
||||
_glfw.wl.cursorTimerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
}
|
||||
|
||||
if (_glfw.wl.seat && _glfw.wl.dataDeviceManager)
|
||||
{
|
||||
_glfw.wl.dataDevice =
|
||||
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
|
||||
_glfw.wl.seat);
|
||||
wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
|
||||
_glfw.wl.clipboardString = malloc(4096);
|
||||
if (!_glfw.wl.clipboardString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unable to allocate clipboard memory");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
_glfw.wl.clipboardSize = 4096;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
@@ -1103,6 +1239,8 @@ void _glfwPlatformTerminate(void)
|
||||
|
||||
if (_glfw.wl.cursorTheme)
|
||||
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
|
||||
if (_glfw.wl.cursorThemeHiDPI)
|
||||
wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
|
||||
if (_glfw.wl.cursor.handle)
|
||||
{
|
||||
_glfw_dlclose(_glfw.wl.cursor.handle);
|
||||
@@ -1121,8 +1259,18 @@ void _glfwPlatformTerminate(void)
|
||||
wl_shell_destroy(_glfw.wl.shell);
|
||||
if (_glfw.wl.viewporter)
|
||||
wp_viewporter_destroy(_glfw.wl.viewporter);
|
||||
if (_glfw.wl.decorationManager)
|
||||
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
||||
if (_glfw.wl.wmBase)
|
||||
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
||||
if (_glfw.wl.dataSource)
|
||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
||||
if (_glfw.wl.dataDevice)
|
||||
wl_data_device_destroy(_glfw.wl.dataDevice);
|
||||
if (_glfw.wl.dataOffer)
|
||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
||||
if (_glfw.wl.dataDeviceManager)
|
||||
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
||||
if (_glfw.wl.pointer)
|
||||
wl_pointer_destroy(_glfw.wl.pointer);
|
||||
if (_glfw.wl.keyboard)
|
||||
@@ -1142,6 +1290,16 @@ void _glfwPlatformTerminate(void)
|
||||
wl_display_flush(_glfw.wl.display);
|
||||
wl_display_disconnect(_glfw.wl.display);
|
||||
}
|
||||
|
||||
if (_glfw.wl.timerfd >= 0)
|
||||
close(_glfw.wl.timerfd);
|
||||
if (_glfw.wl.cursorTimerfd >= 0)
|
||||
close(_glfw.wl.cursorTimerfd);
|
||||
|
||||
if (_glfw.wl.clipboardString)
|
||||
free(_glfw.wl.clipboardString);
|
||||
if (_glfw.wl.clipboardSendString)
|
||||
free(_glfw.wl.clipboardSendString);
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
@@ -1158,4 +1316,3 @@ const char* _glfwPlatformGetVersionString(void)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+30
-30
@@ -32,16 +32,16 @@
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static void geometry(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physicalWidth,
|
||||
int32_t physicalHeight,
|
||||
int32_t subpixel,
|
||||
const char* make,
|
||||
const char* model,
|
||||
int32_t transform)
|
||||
static void outputHandleGeometry(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physicalWidth,
|
||||
int32_t physicalHeight,
|
||||
int32_t subpixel,
|
||||
const char* make,
|
||||
const char* model,
|
||||
int32_t transform)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
char name[1024];
|
||||
@@ -55,12 +55,12 @@ static void geometry(void* data,
|
||||
monitor->name = _glfw_strdup(name);
|
||||
}
|
||||
|
||||
static void mode(void* data,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
static void outputHandleMode(void* data,
|
||||
struct wl_output* output,
|
||||
uint32_t flags,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t refresh)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
GLFWvidmode mode;
|
||||
@@ -81,16 +81,16 @@ static void mode(void* data,
|
||||
monitor->wl.currentMode = monitor->modeCount - 1;
|
||||
}
|
||||
|
||||
static void done(void* data, struct wl_output* output)
|
||||
static void outputHandleDone(void* data, struct wl_output* output)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
|
||||
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
|
||||
}
|
||||
|
||||
static void scale(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t factor)
|
||||
static void outputHandleScale(void* data,
|
||||
struct wl_output* output,
|
||||
int32_t factor)
|
||||
{
|
||||
struct _GLFWmonitor *monitor = data;
|
||||
|
||||
@@ -98,10 +98,10 @@ static void scale(void* data,
|
||||
}
|
||||
|
||||
static const struct wl_output_listener outputListener = {
|
||||
geometry,
|
||||
mode,
|
||||
done,
|
||||
scale,
|
||||
outputHandleGeometry,
|
||||
outputHandleMode,
|
||||
outputHandleDone,
|
||||
outputHandleScale,
|
||||
};
|
||||
|
||||
|
||||
@@ -180,18 +180,18 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
*mode = monitor->modes[monitor->wl.currentMode];
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Gamma ramp getting not supported yet");
|
||||
"Wayland: Gamma ramp access it not available");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor,
|
||||
const GLFWgammaramp* ramp)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Gamma ramp setting not supported yet");
|
||||
"Wayland: Gamma ramp access is not available");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+18
-2
@@ -57,6 +57,7 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
|
||||
#include "osmesa_context.h"
|
||||
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-client-protocol.h"
|
||||
#include "wayland-viewporter-client-protocol.h"
|
||||
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
@@ -185,6 +186,7 @@ typedef struct _GLFWwindowWayland
|
||||
struct {
|
||||
struct xdg_surface* surface;
|
||||
struct xdg_toplevel* toplevel;
|
||||
struct zxdg_toplevel_decoration_v1* decoration;
|
||||
} xdg;
|
||||
|
||||
_GLFWcursor* currentCursor;
|
||||
@@ -210,6 +212,7 @@ typedef struct _GLFWwindowWayland
|
||||
GLFWbool justCreated;
|
||||
|
||||
struct {
|
||||
GLFWbool serverSide;
|
||||
struct wl_buffer* buffer;
|
||||
_GLFWdecorationWayland top, left, right, bottom;
|
||||
int focus;
|
||||
@@ -230,7 +233,12 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_seat* seat;
|
||||
struct wl_pointer* pointer;
|
||||
struct wl_keyboard* keyboard;
|
||||
struct wl_data_device_manager* dataDeviceManager;
|
||||
struct wl_data_device* dataDevice;
|
||||
struct wl_data_offer* dataOffer;
|
||||
struct wl_data_source* dataSource;
|
||||
struct xdg_wm_base* wmBase;
|
||||
struct zxdg_decoration_manager_v1* decorationManager;
|
||||
struct wp_viewporter* viewporter;
|
||||
struct zwp_relative_pointer_manager_v1* relativePointerManager;
|
||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||
@@ -240,13 +248,19 @@ typedef struct _GLFWlibraryWayland
|
||||
int seatVersion;
|
||||
|
||||
struct wl_cursor_theme* cursorTheme;
|
||||
struct wl_cursor_theme* cursorThemeHiDPI;
|
||||
struct wl_surface* cursorSurface;
|
||||
uint32_t pointerSerial;
|
||||
int cursorTimerfd;
|
||||
uint32_t serial;
|
||||
|
||||
int32_t keyboardRepeatRate;
|
||||
int32_t keyboardRepeatDelay;
|
||||
int keyboardLastKey;
|
||||
int keyboardLastScancode;
|
||||
char* clipboardString;
|
||||
size_t clipboardSize;
|
||||
char* clipboardSendString;
|
||||
size_t clipboardSendSize;
|
||||
int timerfd;
|
||||
short int keycodes[256];
|
||||
short int scancodes[GLFW_KEY_LAST + 1];
|
||||
@@ -332,10 +346,12 @@ typedef struct _GLFWmonitorWayland
|
||||
//
|
||||
typedef struct _GLFWcursorWayland
|
||||
{
|
||||
struct wl_cursor_image* image;
|
||||
struct wl_cursor* cursor;
|
||||
struct wl_cursor* cursorHiDPI;
|
||||
struct wl_buffer* buffer;
|
||||
int width, height;
|
||||
int xhot, yhot;
|
||||
int currentImage;
|
||||
} _GLFWcursorWayland;
|
||||
|
||||
|
||||
|
||||
Vendored
+428
-113
@@ -39,18 +39,18 @@
|
||||
#include <poll.h>
|
||||
|
||||
|
||||
static void handlePing(void* data,
|
||||
struct wl_shell_surface* shellSurface,
|
||||
uint32_t serial)
|
||||
static void shellSurfaceHandlePing(void* data,
|
||||
struct wl_shell_surface* shellSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
wl_shell_surface_pong(shellSurface, serial);
|
||||
}
|
||||
|
||||
static void handleConfigure(void* data,
|
||||
struct wl_shell_surface* shellSurface,
|
||||
uint32_t edges,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
static void shellSurfaceHandleConfigure(void* data,
|
||||
struct wl_shell_surface* shellSurface,
|
||||
uint32_t edges,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
float aspectRatio;
|
||||
@@ -94,19 +94,18 @@ static void handleConfigure(void* data,
|
||||
_glfwInputWindowDamage(window);
|
||||
}
|
||||
|
||||
static void handlePopupDone(void* data,
|
||||
struct wl_shell_surface* shellSurface)
|
||||
static void shellSurfaceHandlePopupDone(void* data,
|
||||
struct wl_shell_surface* shellSurface)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_listener shellSurfaceListener = {
|
||||
handlePing,
|
||||
handleConfigure,
|
||||
handlePopupDone
|
||||
shellSurfaceHandlePing,
|
||||
shellSurfaceHandleConfigure,
|
||||
shellSurfaceHandlePopupDone
|
||||
};
|
||||
|
||||
static int
|
||||
createTmpfileCloexec(char* tmpname)
|
||||
static int createTmpfileCloexec(char* tmpname)
|
||||
{
|
||||
int fd;
|
||||
|
||||
@@ -137,8 +136,7 @@ createTmpfileCloexec(char* tmpname)
|
||||
* is set to ENOSPC. If posix_fallocate() is not supported, program may
|
||||
* receive SIGBUS on accessing mmap()'ed file contents instead.
|
||||
*/
|
||||
static int
|
||||
createAnonymousFile(off_t size)
|
||||
static int createAnonymousFile(off_t size)
|
||||
{
|
||||
static const char template[] = "/glfw-shared-XXXXXX";
|
||||
const char* path;
|
||||
@@ -146,23 +144,37 @@ createAnonymousFile(off_t size)
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path)
|
||||
#ifdef HAVE_MEMFD_CREATE
|
||||
fd = memfd_create("glfw-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd >= 0)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
// We can add this seal before calling posix_fallocate(), as the file
|
||||
// is currently zero-sized anyway.
|
||||
//
|
||||
// There is also no need to check for the return value, we couldn’t do
|
||||
// anything with it anyway.
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
path = getenv("XDG_RUNTIME_DIR");
|
||||
if (!path)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = calloc(strlen(path) + sizeof(template), 1);
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = createTmpfileCloexec(name);
|
||||
free(name);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = calloc(strlen(path) + sizeof(template), 1);
|
||||
strcpy(name, path);
|
||||
strcat(name, template);
|
||||
|
||||
fd = createTmpfileCloexec(name);
|
||||
|
||||
free(name);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
ret = posix_fallocate(fd, 0, size);
|
||||
if (ret != 0)
|
||||
{
|
||||
@@ -188,7 +200,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Creating a buffer file for %d B failed: %m",
|
||||
length);
|
||||
return GLFW_FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
@@ -197,7 +209,7 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: mmap failed: %m");
|
||||
close(fd);
|
||||
return GLFW_FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pool = wl_shm_create_pool(_glfw.wl.shm, fd, length);
|
||||
@@ -262,11 +274,13 @@ static void createDecorations(_GLFWwindow* window)
|
||||
const GLFWimage image = { 1, 1, data };
|
||||
GLFWbool opaque = (data[3] == 255);
|
||||
|
||||
if (!_glfw.wl.viewporter)
|
||||
if (!_glfw.wl.viewporter || !window->decorated || window->wl.decorations.serverSide)
|
||||
return;
|
||||
|
||||
if (!window->wl.decorations.buffer)
|
||||
window->wl.decorations.buffer = createShmBuffer(&image);
|
||||
if (!window->wl.decorations.buffer)
|
||||
return;
|
||||
|
||||
createDecoration(&window->wl.decorations.top, window->wl.surface,
|
||||
window->wl.decorations.buffer, opaque,
|
||||
@@ -307,6 +321,22 @@ static void destroyDecorations(_GLFWwindow* window)
|
||||
destroyDecoration(&window->wl.decorations.bottom);
|
||||
}
|
||||
|
||||
static void xdgDecorationHandleConfigure(void* data,
|
||||
struct zxdg_toplevel_decoration_v1* decoration,
|
||||
uint32_t mode)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
|
||||
window->wl.decorations.serverSide = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
|
||||
if (!window->wl.decorations.serverSide)
|
||||
createDecorations(window);
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
|
||||
xdgDecorationHandleConfigure,
|
||||
};
|
||||
|
||||
// Makes the surface considered as XRGB instead of ARGB.
|
||||
static void setOpaqueRegion(_GLFWwindow* window)
|
||||
{
|
||||
@@ -389,9 +419,9 @@ static void checkScaleChange(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEnter(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_output *output)
|
||||
static void surfaceHandleEnter(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_output *output)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
||||
@@ -409,9 +439,9 @@ static void handleEnter(void *data,
|
||||
checkScaleChange(window);
|
||||
}
|
||||
|
||||
static void handleLeave(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_output *output)
|
||||
static void surfaceHandleLeave(void *data,
|
||||
struct wl_surface *surface,
|
||||
struct wl_output *output)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
_GLFWmonitor* monitor = wl_output_get_user_data(output);
|
||||
@@ -431,8 +461,8 @@ static void handleLeave(void *data,
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener surfaceListener = {
|
||||
handleEnter,
|
||||
handleLeave
|
||||
surfaceHandleEnter,
|
||||
surfaceHandleLeave
|
||||
};
|
||||
|
||||
static void setIdleInhibitor(_GLFWwindow* window, GLFWbool enable)
|
||||
@@ -479,13 +509,11 @@ static GLFWbool createSurface(_GLFWwindow* window,
|
||||
if (!window->wl.transparent)
|
||||
setOpaqueRegion(window);
|
||||
|
||||
if (window->decorated && !window->monitor)
|
||||
createDecorations(window);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refreshRate)
|
||||
static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor,
|
||||
int refreshRate)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
@@ -502,7 +530,8 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, int refres
|
||||
monitor->wl.output);
|
||||
}
|
||||
setIdleInhibitor(window, GLFW_TRUE);
|
||||
destroyDecorations(window);
|
||||
if (!window->wl.decorations.serverSide)
|
||||
destroyDecorations(window);
|
||||
}
|
||||
|
||||
static GLFWbool createShellSurface(_GLFWwindow* window)
|
||||
@@ -538,11 +567,13 @@ static GLFWbool createShellSurface(_GLFWwindow* window)
|
||||
{
|
||||
wl_shell_surface_set_maximized(window->wl.shellSurface, NULL);
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
createDecorations(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_shell_surface_set_toplevel(window->wl.shellSurface);
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
createDecorations(window);
|
||||
}
|
||||
|
||||
wl_surface_commit(window->wl.surface);
|
||||
@@ -631,6 +662,27 @@ static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
xdgSurfaceHandleConfigure
|
||||
};
|
||||
|
||||
static void setXdgDecorations(_GLFWwindow* window)
|
||||
{
|
||||
if (_glfw.wl.decorationManager)
|
||||
{
|
||||
window->wl.xdg.decoration =
|
||||
zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
_glfw.wl.decorationManager, window->wl.xdg.toplevel);
|
||||
zxdg_toplevel_decoration_v1_add_listener(window->wl.xdg.decoration,
|
||||
&xdgDecorationListener,
|
||||
window);
|
||||
zxdg_toplevel_decoration_v1_set_mode(
|
||||
window->wl.xdg.decoration,
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->wl.decorations.serverSide = GLFW_FALSE;
|
||||
createDecorations(window);
|
||||
}
|
||||
}
|
||||
|
||||
static GLFWbool createXdgSurface(_GLFWwindow* window)
|
||||
{
|
||||
window->wl.xdg.surface = xdg_wm_base_get_xdg_surface(_glfw.wl.wmBase,
|
||||
@@ -678,10 +730,12 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
|
||||
{
|
||||
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
setXdgDecorations(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
setXdgDecorations(window);
|
||||
}
|
||||
|
||||
wl_surface_commit(window->wl.surface);
|
||||
@@ -690,13 +744,75 @@ static GLFWbool createXdgSurface(_GLFWwindow* window)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
handleEvents(int timeout)
|
||||
static void setCursorImage(_GLFWwindow* window,
|
||||
_GLFWcursorWayland* cursorWayland)
|
||||
{
|
||||
struct itimerspec timer = {};
|
||||
struct wl_cursor* wlCursor = cursorWayland->cursor;
|
||||
struct wl_cursor_image* image;
|
||||
struct wl_buffer* buffer;
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
int scale = 1;
|
||||
|
||||
if (!wlCursor)
|
||||
buffer = cursorWayland->buffer;
|
||||
else
|
||||
{
|
||||
if (window->wl.scale > 1 && cursorWayland->cursorHiDPI)
|
||||
{
|
||||
wlCursor = cursorWayland->cursorHiDPI;
|
||||
scale = 2;
|
||||
}
|
||||
|
||||
image = wlCursor->images[cursorWayland->currentImage];
|
||||
buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
timer.it_value.tv_sec = image->delay / 1000;
|
||||
timer.it_value.tv_nsec = (image->delay % 1000) * 1000000;
|
||||
timerfd_settime(_glfw.wl.cursorTimerfd, 0, &timer, NULL);
|
||||
|
||||
cursorWayland->width = image->width;
|
||||
cursorWayland->height = image->height;
|
||||
cursorWayland->xhot = image->hotspot_x;
|
||||
cursorWayland->yhot = image->hotspot_y;
|
||||
}
|
||||
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||
surface,
|
||||
cursorWayland->xhot / scale,
|
||||
cursorWayland->yhot / scale);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
cursorWayland->width, cursorWayland->height);
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
|
||||
static void incrementCursorImage(_GLFWwindow* window)
|
||||
{
|
||||
_GLFWcursor* cursor;
|
||||
|
||||
if (!window || window->wl.decorations.focus != mainWindow)
|
||||
return;
|
||||
|
||||
cursor = window->wl.currentCursor;
|
||||
if (cursor && cursor->wl.cursor)
|
||||
{
|
||||
cursor->wl.currentImage += 1;
|
||||
cursor->wl.currentImage %= cursor->wl.cursor->image_count;
|
||||
setCursorImage(window, &cursor->wl);
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEvents(int timeout)
|
||||
{
|
||||
struct wl_display* display = _glfw.wl.display;
|
||||
struct pollfd fds[] = {
|
||||
{ wl_display_get_fd(display), POLLIN },
|
||||
{ _glfw.wl.timerfd, POLLIN },
|
||||
{ _glfw.wl.cursorTimerfd, POLLIN },
|
||||
};
|
||||
ssize_t read_ret;
|
||||
uint64_t repeats, i;
|
||||
@@ -719,7 +835,7 @@ handleEvents(int timeout)
|
||||
return;
|
||||
}
|
||||
|
||||
if (poll(fds, 2, timeout) > 0)
|
||||
if (poll(fds, 3, timeout) > 0)
|
||||
{
|
||||
if (fds[0].revents & POLLIN)
|
||||
{
|
||||
@@ -742,6 +858,15 @@ handleEvents(int timeout)
|
||||
_glfw.wl.keyboardLastScancode, GLFW_REPEAT,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
}
|
||||
|
||||
if (fds[2].revents & POLLIN)
|
||||
{
|
||||
read_ret = read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats));
|
||||
if (read_ret != 8)
|
||||
return;
|
||||
|
||||
incrementCursorImage(_glfw.wl.pointerFocus);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -860,6 +985,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||
window->context.destroy(window);
|
||||
|
||||
destroyDecorations(window);
|
||||
if (window->wl.xdg.decoration)
|
||||
zxdg_toplevel_decoration_v1_destroy(window->wl.xdg.decoration);
|
||||
|
||||
if (window->wl.decorations.buffer)
|
||||
wl_buffer_destroy(window->wl.decorations.buffer);
|
||||
|
||||
@@ -956,13 +1084,15 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
|
||||
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window,
|
||||
int numer, int denom)
|
||||
{
|
||||
// TODO: find out how to trigger a resize.
|
||||
// The actual limits are checked in the wl_shell_surface::configure handler.
|
||||
}
|
||||
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
|
||||
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window,
|
||||
int* width, int* height)
|
||||
{
|
||||
_glfwPlatformGetWindowSize(window, width, height);
|
||||
*width *= window->wl.scale;
|
||||
@@ -973,7 +1103,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
int* left, int* top,
|
||||
int* right, int* bottom)
|
||||
{
|
||||
if (window->decorated && !window->monitor)
|
||||
if (window->decorated && !window->monitor && !window->wl.decorations.serverSide)
|
||||
{
|
||||
if (top)
|
||||
*top = _GLFW_DECORATION_TOP;
|
||||
@@ -1102,7 +1232,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
else if (window->wl.shellSurface)
|
||||
wl_shell_surface_set_toplevel(window->wl.shellSurface);
|
||||
setIdleInhibitor(window, GLFW_FALSE);
|
||||
if (window->decorated)
|
||||
if (!_glfw.wl.decorationManager)
|
||||
createDecorations(window);
|
||||
}
|
||||
_glfwInputWindowMonitor(window, monitor);
|
||||
@@ -1236,6 +1366,9 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
int xhot, int yhot)
|
||||
{
|
||||
cursor->wl.buffer = createShmBuffer(image);
|
||||
if (!cursor->wl.buffer)
|
||||
return GLFW_FALSE;
|
||||
|
||||
cursor->wl.width = image->width;
|
||||
cursor->wl.height = image->height;
|
||||
cursor->wl.xhot = xhot;
|
||||
@@ -1257,28 +1390,37 @@ int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
cursor->wl.image = standardCursor->images[0];
|
||||
cursor->wl.cursor = standardCursor;
|
||||
cursor->wl.currentImage = 0;
|
||||
|
||||
if (_glfw.wl.cursorThemeHiDPI)
|
||||
{
|
||||
standardCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
|
||||
translateCursorShape(shape));
|
||||
cursor->wl.cursorHiDPI = standardCursor;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||
{
|
||||
// If it's a standard cursor we don't need to do anything here
|
||||
if (cursor->wl.image)
|
||||
if (cursor->wl.cursor)
|
||||
return;
|
||||
|
||||
if (cursor->wl.buffer)
|
||||
wl_buffer_destroy(cursor->wl.buffer);
|
||||
}
|
||||
|
||||
static void handleRelativeMotion(void* data,
|
||||
struct zwp_relative_pointer_v1* pointer,
|
||||
uint32_t timeHi,
|
||||
uint32_t timeLo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dxUnaccel,
|
||||
wl_fixed_t dyUnaccel)
|
||||
static void relativePointerHandleRelativeMotion(void* data,
|
||||
struct zwp_relative_pointer_v1* pointer,
|
||||
uint32_t timeHi,
|
||||
uint32_t timeLo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dxUnaccel,
|
||||
wl_fixed_t dyUnaccel)
|
||||
{
|
||||
_GLFWwindow* window = data;
|
||||
|
||||
@@ -1291,11 +1433,11 @@ static void handleRelativeMotion(void* data,
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
||||
handleRelativeMotion
|
||||
relativePointerHandleRelativeMotion
|
||||
};
|
||||
|
||||
static void handleLocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
static void lockedPointerHandleLocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1315,14 +1457,14 @@ static void unlockPointer(_GLFWwindow* window)
|
||||
|
||||
static void lockPointer(_GLFWwindow* window);
|
||||
|
||||
static void handleUnlocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
static void lockedPointerHandleUnlocked(void* data,
|
||||
struct zwp_locked_pointer_v1* lockedPointer)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
|
||||
handleLocked,
|
||||
handleUnlocked
|
||||
lockedPointerHandleLocked,
|
||||
lockedPointerHandleUnlocked
|
||||
};
|
||||
|
||||
static void lockPointer(_GLFWwindow* window)
|
||||
@@ -1359,7 +1501,7 @@ static void lockPointer(_GLFWwindow* window)
|
||||
window->wl.pointerLock.relativePointer = relativePointer;
|
||||
window->wl.pointerLock.lockedPointer = lockedPointer;
|
||||
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
|
||||
NULL, 0, 0);
|
||||
}
|
||||
|
||||
@@ -1370,10 +1512,8 @@ static GLFWbool isPointerLocked(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
{
|
||||
struct wl_buffer* buffer;
|
||||
struct wl_cursor* defaultCursor;
|
||||
struct wl_cursor_image* image;
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
struct wl_cursor* defaultCursorHiDPI = NULL;
|
||||
|
||||
if (!_glfw.wl.pointer)
|
||||
return;
|
||||
@@ -1382,7 +1522,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
|
||||
// If we're not in the correct window just save the cursor
|
||||
// the next time the pointer enters the window the cursor will change
|
||||
if (window != _glfw.wl.pointerFocus)
|
||||
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
|
||||
return;
|
||||
|
||||
// Unlock possible pointer lock if no longer disabled.
|
||||
@@ -1392,7 +1532,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||
{
|
||||
if (cursor)
|
||||
image = cursor->wl.image;
|
||||
setCursorImage(window, &cursor->wl);
|
||||
else
|
||||
{
|
||||
defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme,
|
||||
@@ -1403,33 +1543,19 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
"Wayland: Standard cursor not found");
|
||||
return;
|
||||
}
|
||||
image = defaultCursor->images[0];
|
||||
}
|
||||
|
||||
if (image)
|
||||
{
|
||||
buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
surface,
|
||||
image->hotspot_x,
|
||||
image->hotspot_y);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
image->width, image->height);
|
||||
wl_surface_commit(surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
surface,
|
||||
cursor->wl.xhot,
|
||||
cursor->wl.yhot);
|
||||
wl_surface_attach(surface, cursor->wl.buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0,
|
||||
cursor->wl.width, cursor->wl.height);
|
||||
wl_surface_commit(surface);
|
||||
if (_glfw.wl.cursorThemeHiDPI)
|
||||
defaultCursorHiDPI =
|
||||
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI,
|
||||
"left_ptr");
|
||||
_GLFWcursorWayland cursorWayland = {
|
||||
defaultCursor,
|
||||
defaultCursorHiDPI,
|
||||
NULL,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0
|
||||
};
|
||||
setCursorImage(window, &cursorWayland);
|
||||
}
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
@@ -1439,24 +1565,213 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||
}
|
||||
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
|
||||
{
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
|
||||
NULL, 0, 0);
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void dataSourceHandleTarget(void* data,
|
||||
struct wl_data_source* dataSource,
|
||||
const char* mimeType)
|
||||
{
|
||||
if (_glfw.wl.dataSource != dataSource)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unknown clipboard data source");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dataSourceHandleSend(void* data,
|
||||
struct wl_data_source* dataSource,
|
||||
const char* mimeType,
|
||||
int fd)
|
||||
{
|
||||
const char* string = _glfw.wl.clipboardSendString;
|
||||
size_t len = _glfw.wl.clipboardSendSize;
|
||||
int ret;
|
||||
|
||||
if (_glfw.wl.dataSource != dataSource)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unknown clipboard data source");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Copy requested from an invalid string");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(mimeType, "text/plain;charset=utf-8") != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Wrong MIME type asked from clipboard");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
ret = write(fd, string, len);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == -1)
|
||||
{
|
||||
// TODO: also report errno maybe.
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Error while writing the clipboard");
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
len -= ret;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static void dataSourceHandleCancelled(void* data,
|
||||
struct wl_data_source* dataSource)
|
||||
{
|
||||
wl_data_source_destroy(dataSource);
|
||||
|
||||
if (_glfw.wl.dataSource != dataSource)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Unknown clipboard data source");
|
||||
return;
|
||||
}
|
||||
|
||||
_glfw.wl.dataSource = NULL;
|
||||
}
|
||||
|
||||
static const struct wl_data_source_listener dataSourceListener = {
|
||||
dataSourceHandleTarget,
|
||||
dataSourceHandleSend,
|
||||
dataSourceHandleCancelled,
|
||||
};
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Clipboard setting not implemented yet");
|
||||
if (_glfw.wl.dataSource)
|
||||
{
|
||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
||||
_glfw.wl.dataSource = NULL;
|
||||
}
|
||||
|
||||
if (_glfw.wl.clipboardSendString)
|
||||
{
|
||||
free(_glfw.wl.clipboardSendString);
|
||||
_glfw.wl.clipboardSendString = NULL;
|
||||
}
|
||||
|
||||
_glfw.wl.clipboardSendString = strdup(string);
|
||||
if (!_glfw.wl.clipboardSendString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Impossible to allocate clipboard string");
|
||||
return;
|
||||
}
|
||||
_glfw.wl.clipboardSendSize = strlen(string);
|
||||
_glfw.wl.dataSource =
|
||||
wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
|
||||
if (!_glfw.wl.dataSource)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Impossible to create clipboard source");
|
||||
free(_glfw.wl.clipboardSendString);
|
||||
return;
|
||||
}
|
||||
wl_data_source_add_listener(_glfw.wl.dataSource,
|
||||
&dataSourceListener,
|
||||
NULL);
|
||||
wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8");
|
||||
wl_data_device_set_selection(_glfw.wl.dataDevice,
|
||||
_glfw.wl.dataSource,
|
||||
_glfw.wl.serial);
|
||||
}
|
||||
|
||||
static GLFWbool growClipboardString(void)
|
||||
{
|
||||
char* clipboard = _glfw.wl.clipboardString;
|
||||
|
||||
clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);
|
||||
if (!clipboard)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Impossible to grow clipboard string");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
_glfw.wl.clipboardString = clipboard;
|
||||
_glfw.wl.clipboardSize = _glfw.wl.clipboardSize * 2;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(void)
|
||||
{
|
||||
// TODO
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Clipboard getting not implemented yet");
|
||||
return NULL;
|
||||
int fds[2];
|
||||
int ret;
|
||||
size_t len = 0;
|
||||
|
||||
if (!_glfw.wl.dataOffer)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"No clipboard data has been sent yet");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = pipe2(fds, O_CLOEXEC);
|
||||
if (ret < 0)
|
||||
{
|
||||
// TODO: also report errno maybe?
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Impossible to create clipboard pipe fds");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);
|
||||
close(fds[1]);
|
||||
|
||||
// XXX: this is a huge hack, this function shouldn’t be synchronous!
|
||||
handleEvents(-1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Grow the clipboard if we need to paste something bigger, there is no
|
||||
// shrink operation yet.
|
||||
if (len + 4096 > _glfw.wl.clipboardSize)
|
||||
{
|
||||
if (!growClipboardString())
|
||||
{
|
||||
close(fds[0]);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Then read from the fd to the clipboard, handling all known errors.
|
||||
ret = read(fds[0], _glfw.wl.clipboardString + len, 4096);
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == -1)
|
||||
{
|
||||
// TODO: also report errno maybe.
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"Wayland: Impossible to read from clipboard fd");
|
||||
close(fds[0]);
|
||||
return NULL;
|
||||
}
|
||||
len += ret;
|
||||
}
|
||||
close(fds[0]);
|
||||
if (len + 1 > _glfw.wl.clipboardSize)
|
||||
{
|
||||
if (!growClipboardString())
|
||||
return NULL;
|
||||
}
|
||||
_glfw.wl.clipboardString[len] = '\0';
|
||||
return _glfw.wl.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
|
||||
|
||||
Vendored
+3
-2
@@ -780,8 +780,9 @@ static GLFWbool initExtensions(void)
|
||||
//
|
||||
static void getSystemContentScale(float* xscale, float* yscale)
|
||||
{
|
||||
// NOTE: Default to the display-wide DPI as we don't currently have a policy
|
||||
// for which monitor a window is considered to be on
|
||||
// NOTE: Fall back to the display-wide DPI instead of RandR monitor DPI if
|
||||
// Xft.dpi retrieval below fails as we don't currently have an exact
|
||||
// policy for which monitor a window is considered to "be on"
|
||||
float xdpi = DisplayWidth(_glfw.x11.display, _glfw.x11.screen) *
|
||||
25.4f / DisplayWidthMM(_glfw.x11.display, _glfw.x11.screen);
|
||||
float ydpi = DisplayHeight(_glfw.x11.display, _glfw.x11.screen) *
|
||||
|
||||
Vendored
+14
-1
@@ -422,7 +422,7 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode)
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
{
|
||||
if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken)
|
||||
{
|
||||
@@ -438,6 +438,7 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short));
|
||||
|
||||
XRRFreeGamma(gamma);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
else if (_glfw.x11.vidmode.available)
|
||||
{
|
||||
@@ -449,6 +450,13 @@ void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
|
||||
XF86VidModeGetGammaRamp(_glfw.x11.display,
|
||||
_glfw.x11.screen,
|
||||
ramp->size, ramp->red, ramp->green, ramp->blue);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Gamma ramp access not supported by server");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,6 +489,11 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
(unsigned short*) ramp->green,
|
||||
(unsigned short*) ramp->blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Gamma ramp access not supported by server");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vendored
+49
-46
@@ -175,29 +175,6 @@ static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer po
|
||||
event->xproperty.atom == notification->xselection.property;
|
||||
}
|
||||
|
||||
// Translates a GLFW standard cursor to a font cursor shape
|
||||
//
|
||||
static int translateCursorShape(int shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case GLFW_ARROW_CURSOR:
|
||||
return XC_left_ptr;
|
||||
case GLFW_IBEAM_CURSOR:
|
||||
return XC_xterm;
|
||||
case GLFW_CROSSHAIR_CURSOR:
|
||||
return XC_crosshair;
|
||||
case GLFW_HAND_CURSOR:
|
||||
return XC_hand1;
|
||||
case GLFW_HRESIZE_CURSOR:
|
||||
return XC_sb_h_double_arrow;
|
||||
case GLFW_VRESIZE_CURSOR:
|
||||
return XC_sb_v_double_arrow;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Translates an X event modifier state mask
|
||||
//
|
||||
static int translateState(int state)
|
||||
@@ -231,23 +208,6 @@ static int translateKey(int scancode)
|
||||
return _glfw.x11.keycodes[scancode];
|
||||
}
|
||||
|
||||
// Return the GLFW window corresponding to the specified X11 window
|
||||
//
|
||||
static _GLFWwindow* findWindowByHandle(Window handle)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
|
||||
if (XFindContext(_glfw.x11.display,
|
||||
handle,
|
||||
_glfw.x11.context,
|
||||
(XPointer*) &window) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
// Sends an EWMH or ICCCM event to the window manager
|
||||
//
|
||||
static void sendEventToWM(_GLFWwindow* window, Atom type,
|
||||
@@ -632,6 +592,15 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
const _GLFWwndconfig* wndconfig,
|
||||
Visual* visual, int depth)
|
||||
{
|
||||
int width = wndconfig->width;
|
||||
int height = wndconfig->height;
|
||||
|
||||
if (wndconfig->scaleToMonitor)
|
||||
{
|
||||
width *= _glfw.x11.contentScaleX;
|
||||
height *= _glfw.x11.contentScaleY;
|
||||
}
|
||||
|
||||
// Create a colormap based on the visual used by the current context
|
||||
window->x11.colormap = XCreateColormap(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
@@ -657,7 +626,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
window->x11.handle = XCreateWindow(_glfw.x11.display,
|
||||
_glfw.x11.root,
|
||||
0, 0,
|
||||
wndconfig->width, wndconfig->height,
|
||||
width, height,
|
||||
0, // Border width
|
||||
depth, // Color depth
|
||||
InputOutput,
|
||||
@@ -760,7 +729,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
||||
XFree(hints);
|
||||
}
|
||||
|
||||
updateNormalHints(window, wndconfig->width, wndconfig->height);
|
||||
updateNormalHints(window, width, height);
|
||||
|
||||
// Set ICCCM WM_CLASS property
|
||||
{
|
||||
@@ -1264,8 +1233,10 @@ static void processEvent(XEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
window = findWindowByHandle(event->xany.window);
|
||||
if (window == NULL)
|
||||
if (XFindContext(_glfw.x11.display,
|
||||
event->xany.window,
|
||||
_glfw.x11.context,
|
||||
(XPointer*) &window) != 0)
|
||||
{
|
||||
// This is an event for a window that has already been destroyed
|
||||
return;
|
||||
@@ -1484,12 +1455,20 @@ static void processEvent(XEvent *event)
|
||||
|
||||
case EnterNotify:
|
||||
{
|
||||
// XEnterWindowEvent is XCrossingEvent
|
||||
const int x = event->xcrossing.x;
|
||||
const int y = event->xcrossing.y;
|
||||
|
||||
// HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise
|
||||
// ignore the defined cursor for hidden cursor mode
|
||||
if (window->cursorMode == GLFW_CURSOR_HIDDEN)
|
||||
updateCursorImage(window);
|
||||
|
||||
_glfwInputCursorEnter(window, GLFW_TRUE);
|
||||
_glfwInputCursorPos(window, x, y);
|
||||
|
||||
window->x11.lastCursorPosX = x;
|
||||
window->x11.lastCursorPosY = y;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2479,6 +2458,14 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
|
||||
Atom* states;
|
||||
unsigned long i;
|
||||
GLFWbool maximized = GLFW_FALSE;
|
||||
|
||||
if (!_glfw.x11.NET_WM_STATE ||
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT ||
|
||||
!_glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ)
|
||||
{
|
||||
return maximized;
|
||||
}
|
||||
|
||||
const unsigned long count =
|
||||
_glfwGetWindowPropertyX11(window->x11.handle,
|
||||
_glfw.x11.NET_WM_STATE,
|
||||
@@ -2814,8 +2801,24 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
|
||||
|
||||
int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
|
||||
{
|
||||
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display,
|
||||
translateCursorShape(shape));
|
||||
int native = 0;
|
||||
|
||||
if (shape == GLFW_ARROW_CURSOR)
|
||||
native = XC_left_ptr;
|
||||
else if (shape == GLFW_IBEAM_CURSOR)
|
||||
native = XC_xterm;
|
||||
else if (shape == GLFW_CROSSHAIR_CURSOR)
|
||||
native = XC_crosshair;
|
||||
else if (shape == GLFW_HAND_CURSOR)
|
||||
native = XC_hand1;
|
||||
else if (shape == GLFW_HRESIZE_CURSOR)
|
||||
native = XC_sb_h_double_arrow;
|
||||
else if (shape == GLFW_VRESIZE_CURSOR)
|
||||
native = XC_sb_v_double_arrow;
|
||||
else
|
||||
return GLFW_FALSE;
|
||||
|
||||
cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native);
|
||||
if (!cursor->x11.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
|
||||
Vendored
+1
@@ -3,5 +3,6 @@
|
||||
#define MINI_AL_IMPLEMENTATION
|
||||
#define MAL_NO_JACK
|
||||
#define MAL_NO_OPENAL
|
||||
#define MAL_NO_SDL
|
||||
//#define MAL_NO_NULL
|
||||
#include "mini_al.h"
|
||||
|
||||
Vendored
+1625
-554
File diff suppressed because it is too large
Load Diff
Vendored
-5074
File diff suppressed because it is too large
Load Diff
Vendored
+5113
-32
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+62
-36
@@ -12,7 +12,7 @@
|
||||
*
|
||||
* CONFIGURATION:
|
||||
*
|
||||
* #define AUDIO_STANDALONE
|
||||
* #define RAUDIO_STANDALONE
|
||||
* Define to use the module as standalone library (independently of raylib).
|
||||
* Required types and functions are defined in the same module.
|
||||
*
|
||||
@@ -70,8 +70,8 @@
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
#include "audio.h"
|
||||
#if defined(RAUDIO_STANDALONE)
|
||||
#include "raudio.h"
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
|
||||
#else
|
||||
#include "raylib.h" // Declares module functions
|
||||
@@ -91,7 +91,7 @@
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||
//#define STB_VORBIS_HEADER_ONLY
|
||||
#define STB_VORBIS_IMPLEMENTATION
|
||||
#include "external/stb_vorbis.h" // OGG loading functions
|
||||
#endif
|
||||
|
||||
@@ -169,7 +169,7 @@ typedef struct MusicData {
|
||||
unsigned int samplesLeft; // Number of samples left to end
|
||||
} MusicData;
|
||||
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
#if defined(RAUDIO_STANDALONE)
|
||||
typedef enum {
|
||||
LOG_INFO = 0,
|
||||
LOG_ERROR,
|
||||
@@ -201,7 +201,7 @@ static Wave LoadFLAC(const char *fileName); // Load FLAC file
|
||||
static Wave LoadMP3(const char *fileName); // Load MP3 file
|
||||
#endif
|
||||
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
#if defined(RAUDIO_STANDALONE)
|
||||
bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
|
||||
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
|
||||
#endif
|
||||
@@ -1176,14 +1176,15 @@ Music LoadMusicStream(const char *fileName)
|
||||
|
||||
if (jar_mod_load_file(&music->ctxMod, fileName))
|
||||
{
|
||||
// NOTE: Only stereo is supported for MOD
|
||||
music->stream = InitAudioStream(48000, 16, 2);
|
||||
music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod);
|
||||
music->samplesLeft = music->totalSamples;
|
||||
music->ctxType = MUSIC_MODULE_MOD;
|
||||
music->loopCount = -1; // Infinite loop by default
|
||||
|
||||
TraceLog(LOG_DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
|
||||
TraceLog(LOG_DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
|
||||
TraceLog(LOG_INFO, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
|
||||
TraceLog(LOG_INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
|
||||
}
|
||||
else musicLoaded = false;
|
||||
}
|
||||
@@ -1218,6 +1219,8 @@ Music LoadMusicStream(const char *fileName)
|
||||
// Unload music stream
|
||||
void UnloadMusicStream(Music music)
|
||||
{
|
||||
if (music == NULL) return;
|
||||
|
||||
CloseAudioStream(music->stream);
|
||||
|
||||
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
|
||||
@@ -1240,41 +1243,46 @@ void UnloadMusicStream(Music music)
|
||||
// Start music playing (open stream)
|
||||
void PlayMusicStream(Music music)
|
||||
{
|
||||
AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer;
|
||||
|
||||
if (audioBuffer == NULL)
|
||||
if (music != NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer");
|
||||
return;
|
||||
AudioBuffer *audioBuffer = (AudioBuffer *)music->stream.audioBuffer;
|
||||
|
||||
if (audioBuffer == NULL)
|
||||
{
|
||||
TraceLog(LOG_ERROR, "PlayMusicStream() : No audio buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
// For music streams, we need to make sure we maintain the frame cursor position. This is hack for this section of code in UpdateMusicStream()
|
||||
// // NOTE: In case window is minimized, music stream is stopped,
|
||||
// // just make sure to play again on window restore
|
||||
// if (IsMusicPlaying(music)) PlayMusicStream(music);
|
||||
mal_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
||||
|
||||
PlayAudioStream(music->stream); // <-- This resets the cursor position.
|
||||
|
||||
audioBuffer->frameCursorPos = frameCursorPos;
|
||||
}
|
||||
|
||||
// For music streams, we need to make sure we maintain the frame cursor position. This is hack for this section of code in UpdateMusicStream()
|
||||
// // NOTE: In case window is minimized, music stream is stopped,
|
||||
// // just make sure to play again on window restore
|
||||
// if (IsMusicPlaying(music)) PlayMusicStream(music);
|
||||
mal_uint32 frameCursorPos = audioBuffer->frameCursorPos;
|
||||
|
||||
PlayAudioStream(music->stream); // <-- This resets the cursor position.
|
||||
|
||||
audioBuffer->frameCursorPos = frameCursorPos;
|
||||
}
|
||||
|
||||
// Pause music playing
|
||||
void PauseMusicStream(Music music)
|
||||
{
|
||||
PauseAudioStream(music->stream);
|
||||
if (music != NULL) PauseAudioStream(music->stream);
|
||||
}
|
||||
|
||||
// Resume music playing
|
||||
void ResumeMusicStream(Music music)
|
||||
{
|
||||
ResumeAudioStream(music->stream);
|
||||
if (music != NULL) ResumeAudioStream(music->stream);
|
||||
}
|
||||
|
||||
// Stop music playing (close stream)
|
||||
// TODO: To clear a buffer, make sure they have been already processed!
|
||||
void StopMusicStream(Music music)
|
||||
{
|
||||
if (music == NULL) return;
|
||||
|
||||
StopAudioStream(music->stream);
|
||||
|
||||
// Restart music context
|
||||
@@ -1303,6 +1311,8 @@ void StopMusicStream(Music music)
|
||||
// TODO: Make sure buffers are ready for update... check music state
|
||||
void UpdateMusicStream(Music music)
|
||||
{
|
||||
if (music == NULL) return;
|
||||
|
||||
bool streamEnding = false;
|
||||
|
||||
unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2;
|
||||
@@ -1345,18 +1355,28 @@ void UpdateMusicStream(Music music)
|
||||
#if defined(SUPPORT_FILEFORMAT_XM)
|
||||
case MUSIC_MODULE_XM:
|
||||
{
|
||||
// NOTE: Internally this function considers 2 channels generation, so samplesCount/2 --> WEIRD
|
||||
// NOTE: Internally this function considers 2 channels generation, so samplesCount/2
|
||||
jar_xm_generate_samples_16bit(music->ctxXm, (short *)pcm, samplesCount/2);
|
||||
} break;
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||
case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break;
|
||||
case MUSIC_MODULE_MOD:
|
||||
{
|
||||
// NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
|
||||
jar_mod_fillbuffer(&music->ctxMod, (short *)pcm, samplesCount/2, 0);
|
||||
} break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
UpdateAudioStream(music->stream, pcm, samplesCount);
|
||||
music->samplesLeft -= samplesCount;
|
||||
if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD))
|
||||
{
|
||||
if (samplesCount > 1) music->samplesLeft -= samplesCount/2;
|
||||
else music->samplesLeft -= samplesCount;
|
||||
}
|
||||
else music->samplesLeft -= samplesCount;
|
||||
|
||||
if (music->samplesLeft <= 0)
|
||||
{
|
||||
@@ -1395,32 +1415,35 @@ void UpdateMusicStream(Music music)
|
||||
// Check if any music is playing
|
||||
bool IsMusicPlaying(Music music)
|
||||
{
|
||||
return IsAudioStreamPlaying(music->stream);
|
||||
if (music == NULL) return false;
|
||||
else return IsAudioStreamPlaying(music->stream);
|
||||
}
|
||||
|
||||
// Set volume for music
|
||||
void SetMusicVolume(Music music, float volume)
|
||||
{
|
||||
SetAudioStreamVolume(music->stream, volume);
|
||||
if (music != NULL) SetAudioStreamVolume(music->stream, volume);
|
||||
}
|
||||
|
||||
// Set pitch for music
|
||||
void SetMusicPitch(Music music, float pitch)
|
||||
{
|
||||
SetAudioStreamPitch(music->stream, pitch);
|
||||
if (music != NULL) SetAudioStreamPitch(music->stream, pitch);
|
||||
}
|
||||
|
||||
// Set music loop count (loop repeats)
|
||||
// NOTE: If set to -1, means infinite loop
|
||||
void SetMusicLoopCount(Music music, int count)
|
||||
{
|
||||
music->loopCount = count;
|
||||
if (music != NULL) music->loopCount = count;
|
||||
}
|
||||
|
||||
// Get music time length (in seconds)
|
||||
float GetMusicTimeLength(Music music)
|
||||
{
|
||||
float totalSeconds = (float)music->totalSamples/(music->stream.sampleRate*music->stream.channels);
|
||||
float totalSeconds = 0.0f;
|
||||
|
||||
if (music != NULL) totalSeconds = (float)music->totalSamples/(music->stream.sampleRate*music->stream.channels);
|
||||
|
||||
return totalSeconds;
|
||||
}
|
||||
@@ -1430,8 +1453,11 @@ float GetMusicTimePlayed(Music music)
|
||||
{
|
||||
float secondsPlayed = 0.0f;
|
||||
|
||||
unsigned int samplesPlayed = music->totalSamples - music->samplesLeft;
|
||||
secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels);
|
||||
if (music != NULL)
|
||||
{
|
||||
unsigned int samplesPlayed = music->totalSamples - music->samplesLeft;
|
||||
secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels);
|
||||
}
|
||||
|
||||
return secondsPlayed;
|
||||
}
|
||||
@@ -1892,7 +1918,7 @@ static Wave LoadMP3(const char *fileName)
|
||||
#endif
|
||||
|
||||
// Some required functions for audio standalone module version
|
||||
#if defined(AUDIO_STANDALONE)
|
||||
#if defined(RAUDIO_STANDALONE)
|
||||
// Check file extension
|
||||
bool IsFileExtension(const char *fileName, const char *ext)
|
||||
{
|
||||
+49
-18
@@ -135,6 +135,11 @@
|
||||
#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta
|
||||
#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo)
|
||||
|
||||
// Temporal hack to avoid breaking old codebases using
|
||||
// deprecated raylib implementation of these functions
|
||||
#define FormatText TextFormat
|
||||
#define SubText TextSubtext
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -471,7 +476,7 @@ typedef enum {
|
||||
KEY_X = 88,
|
||||
KEY_Y = 89,
|
||||
KEY_Z = 90,
|
||||
|
||||
|
||||
// Function keys
|
||||
KEY_SPACE = 32,
|
||||
KEY_ESCAPE = 256,
|
||||
@@ -518,7 +523,7 @@ typedef enum {
|
||||
KEY_BACKSLASH = 92,
|
||||
KEY_RIGHT_BRACKET = 93,
|
||||
KEY_GRAVE = 96,
|
||||
|
||||
|
||||
// Keypad keys
|
||||
KEY_KP_0 = 320,
|
||||
KEY_KP_1 = 321,
|
||||
@@ -672,6 +677,19 @@ typedef enum {
|
||||
#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
|
||||
#define LOC_MAP_SPECULAR LOC_MAP_METALNESS
|
||||
|
||||
// Shader uniform data types
|
||||
typedef enum {
|
||||
UNIFORM_FLOAT = 0,
|
||||
UNIFORM_VEC2,
|
||||
UNIFORM_VEC3,
|
||||
UNIFORM_VEC4,
|
||||
UNIFORM_INT,
|
||||
UNIFORM_IVEC2,
|
||||
UNIFORM_IVEC3,
|
||||
UNIFORM_IVEC4,
|
||||
UNIFORM_SAMPLER2D
|
||||
} ShaderUniformDataType;
|
||||
|
||||
// Material map type
|
||||
typedef enum {
|
||||
MAP_ALBEDO = 0, // MAP_DIFFUSE
|
||||
@@ -877,7 +895,6 @@ RLAPI Color GetColor(int hexValue); // Returns a C
|
||||
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
|
||||
|
||||
// Misc. functions
|
||||
RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags)
|
||||
RLAPI void SetConfigFlags(unsigned char flags); // Setup window configuration flags (view FLAGS)
|
||||
RLAPI void SetTraceLog(unsigned char types); // Enable trace log message types (bit flags based)
|
||||
RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set a trace log callback to enable custom logging bypassing raylib's one
|
||||
@@ -939,8 +956,9 @@ RLAPI bool IsMouseButtonUp(int button); // Detect if a mou
|
||||
RLAPI int GetMouseX(void); // Returns mouse position X
|
||||
RLAPI int GetMouseY(void); // Returns mouse position Y
|
||||
RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY
|
||||
RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY
|
||||
RLAPI void SetMouseScale(float scale); // Set mouse scaling
|
||||
RLAPI void SetMousePosition(int x, int y); // Set mouse position XY
|
||||
RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset
|
||||
RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling
|
||||
RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y
|
||||
|
||||
// Input-related functions: touch
|
||||
@@ -990,7 +1008,7 @@ RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);
|
||||
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
|
||||
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
|
||||
RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle
|
||||
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color colors[4]); // Draw a color-filled rectangle with pro parameters
|
||||
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
|
||||
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle
|
||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors
|
||||
@@ -1089,8 +1107,9 @@ RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
|
||||
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
|
||||
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
|
||||
RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
|
||||
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
|
||||
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely.
|
||||
RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters
|
||||
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
|
||||
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Font Loading and Text Drawing Functions (Module: text)
|
||||
@@ -1099,7 +1118,7 @@ RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle
|
||||
// Font loading/unloading functions
|
||||
RLAPI Font GetFontDefault(void); // Get the default Font
|
||||
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
|
||||
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load font from file with extended parameters
|
||||
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // Load font from file with extended parameters
|
||||
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
|
||||
RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, int type); // Load font data for further use
|
||||
RLAPI Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
||||
@@ -1108,18 +1127,30 @@ RLAPI void UnloadFont(Font font);
|
||||
// Text drawing functions
|
||||
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS
|
||||
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
|
||||
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
||||
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
||||
RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
|
||||
|
||||
// Text misc. functions
|
||||
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
||||
RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
|
||||
RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on font
|
||||
|
||||
// Text string edition functions
|
||||
RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed'
|
||||
RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string
|
||||
RLAPI char **SplitText(char *text, char delimiter, int *strCount); // Split text string into multiple strings (memory should be freed manually!)
|
||||
RLAPI bool IsEqualText(const char *text1, const char *text2); // Check if two text string are equal
|
||||
// Text strings management functions
|
||||
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
||||
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
|
||||
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
|
||||
RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf style)
|
||||
RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string
|
||||
RLAPI const char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (memory should be freed!)
|
||||
RLAPI const char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (memory should be freed!)
|
||||
RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter
|
||||
RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings (memory should be freed!)
|
||||
RLAPI void TextSplitEx(const char *text, char delimiter, int *count, const char **ptrs, int *lengths); // Get pointers to substrings separated by delimiter
|
||||
RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor!
|
||||
RLAPI int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string
|
||||
RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string
|
||||
RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string
|
||||
RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Basic 3d Shapes Drawing Functions (Module: models)
|
||||
@@ -1215,8 +1246,8 @@ RLAPI Texture2D GetTextureDefault(void); // Get
|
||||
|
||||
// Shader configuration functions
|
||||
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
|
||||
RLAPI void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float)
|
||||
RLAPI void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int)
|
||||
RLAPI void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType); // Set shader uniform value
|
||||
RLAPI void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count); // Set shader uniform value vector
|
||||
RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
|
||||
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
|
||||
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
|
||||
@@ -1227,7 +1258,7 @@ RLAPI Matrix GetMatrixModelview(); // Get
|
||||
RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture
|
||||
RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
|
||||
RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
|
||||
RLAPI Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data
|
||||
RLAPI Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture using cubemap data
|
||||
|
||||
// Shading begin/end functions
|
||||
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#define _GLFW_USE_MENUBAR // To create and populate the menu bar when the first window is created
|
||||
#define _GLFW_USE_RETINA // To have windows use the full resolution of Retina displays
|
||||
#endif
|
||||
#if defined(__TINYC__)
|
||||
#define _WIN32_WINNT_WINXP 0x0501
|
||||
#endif
|
||||
|
||||
// NOTE: _GLFW_MIR experimental platform not supported at this moment
|
||||
|
||||
|
||||
+128
-82
@@ -165,14 +165,6 @@ typedef unsigned char byte;
|
||||
unsigned char a;
|
||||
} Color;
|
||||
|
||||
// Rectangle type
|
||||
typedef struct Rectangle {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} Rectangle;
|
||||
|
||||
// Texture2D type
|
||||
// NOTE: Data stored in GPU memory
|
||||
typedef struct Texture2D {
|
||||
@@ -340,6 +332,19 @@ typedef unsigned char byte;
|
||||
LOC_MAP_PREFILTER,
|
||||
LOC_MAP_BRDF
|
||||
} ShaderLocationIndex;
|
||||
|
||||
// Shader uniform data types
|
||||
typedef enum {
|
||||
UNIFORM_FLOAT = 0,
|
||||
UNIFORM_VEC2,
|
||||
UNIFORM_VEC3,
|
||||
UNIFORM_VEC4,
|
||||
UNIFORM_INT,
|
||||
UNIFORM_IVEC2,
|
||||
UNIFORM_IVEC3,
|
||||
UNIFORM_IVEC4,
|
||||
UNIFORM_SAMPLER2D
|
||||
} ShaderUniformDataType;
|
||||
|
||||
#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
|
||||
#define LOC_MAP_SPECULAR LOC_MAP_METALNESS
|
||||
@@ -435,7 +440,7 @@ void rlglClose(void); // De-inititialize rlgl (buffers
|
||||
void rlglDraw(void); // Update and draw default internal buffers
|
||||
|
||||
int rlGetVersion(void); // Returns current OpenGL version
|
||||
bool rlCheckBufferLimit(int type, int vCount); // Check internal buffer overflow for a given number of vertex
|
||||
bool rlCheckBufferLimit(int vCount); // Check internal buffer overflow for a given number of vertex
|
||||
void rlSetDebugMarker(const char *text); // Set debug marker for analysis
|
||||
void rlLoadExtensions(void *loader); // Load OpenGL extensions
|
||||
Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
|
||||
@@ -476,8 +481,8 @@ Texture2D GetTextureDefault(void); // Get defau
|
||||
|
||||
// Shader configuration functions
|
||||
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
|
||||
void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size); // Set shader uniform value (float)
|
||||
void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size); // Set shader uniform value (int)
|
||||
void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType); // Set shader uniform value
|
||||
void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count); // Set shader uniform value vector
|
||||
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
|
||||
void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
|
||||
void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
|
||||
@@ -488,7 +493,7 @@ Matrix GetMatrixModelview(); // Get inter
|
||||
Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture
|
||||
Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
|
||||
Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
|
||||
Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data
|
||||
Texture2D GenTextureBRDF(Shader shader, int size); // Generate BRDF texture using cubemap data
|
||||
|
||||
// Shading begin/end functions
|
||||
void BeginShaderMode(Shader shader); // Begin custom shader drawing
|
||||
@@ -703,9 +708,9 @@ typedef struct DrawCall {
|
||||
typedef struct VrStereoConfig {
|
||||
RenderTexture2D stereoFbo; // VR stereo rendering framebuffer
|
||||
Shader distortionShader; // VR stereo rendering distortion shader
|
||||
Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports
|
||||
Matrix eyesProjection[2]; // VR stereo rendering eyes projection matrices
|
||||
Matrix eyesViewOffset[2]; // VR stereo rendering eyes view offset matrices
|
||||
int eyesViewport[2][4]; // VR stereo rendering eyes viewports [x, y, w, h]
|
||||
} VrStereoConfig;
|
||||
#endif
|
||||
|
||||
@@ -857,7 +862,7 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays;
|
||||
|
||||
#if defined(SUPPORT_VR_SIMULATOR)
|
||||
// VR global variables
|
||||
static VrStereoConfig vrConfig; // VR stereo configuration for simulator
|
||||
static VrStereoConfig vrConfig = { 0 }; // VR stereo configuration for simulator
|
||||
static bool vrSimulatorReady = false; // VR simulator ready flag
|
||||
static bool vrStereoRender = false; // VR stereo rendering enabled/disabled flag
|
||||
// NOTE: This flag is useful to render data over stereo image (i.e. FPS)
|
||||
@@ -1110,7 +1115,8 @@ void rlEnd(void)
|
||||
// processed but are placed in a single point to not result in a fragment output...
|
||||
// TODO: System could be improved (a bit) just storing every draw alignment value
|
||||
// and adding it to vertexOffset on drawing... maybe in a future...
|
||||
int vertexToAlign = draws[drawsCounter - 1].vertexCount%4;
|
||||
int vertexCount = draws[drawsCounter - 1].vertexCount;
|
||||
int vertexToAlign = (vertexCount >= 4) ? vertexCount%4 : (4 - vertexCount%4);
|
||||
for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1);
|
||||
|
||||
// Make sure vertexCount is the same for vertices, texcoords, colors and normals
|
||||
@@ -1153,7 +1159,7 @@ void rlEnd(void)
|
||||
|
||||
// Verify internal buffers limits
|
||||
// NOTE: This check is combined with usage of rlCheckBufferLimit()
|
||||
if ((vertexData[currentBuffer].vCounter/4) >= (MAX_BATCH_ELEMENTS - 4))
|
||||
if ((vertexData[currentBuffer].vCounter) >= (MAX_BATCH_ELEMENTS*4 - 4))
|
||||
{
|
||||
// WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlglDraw(),
|
||||
// we need to call rlPopMatrix() before to recover *currentMatrix (modelview) for the next forced draw call!
|
||||
@@ -1173,7 +1179,7 @@ void rlVertex3f(float x, float y, float z)
|
||||
if (useTransformMatrix) vec = Vector3Transform(vec, transformMatrix);
|
||||
|
||||
// Verify that MAX_BATCH_ELEMENTS limit not reached
|
||||
if (vertexData[currentBuffer].vCounter/4 < MAX_BATCH_ELEMENTS)
|
||||
if (vertexData[currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4))
|
||||
{
|
||||
vertexData[currentBuffer].vertices[3*vertexData[currentBuffer].vCounter] = vec.x;
|
||||
vertexData[currentBuffer].vertices[3*vertexData[currentBuffer].vCounter + 1] = vec.y;
|
||||
@@ -1270,7 +1276,7 @@ void rlDisableTexture(void)
|
||||
#else
|
||||
// NOTE: If quads batch limit is reached,
|
||||
// we force a draw call and next batch starts
|
||||
if (vertexData[currentBuffer].vCounter/4 >= MAX_BATCH_ELEMENTS) rlglDraw();
|
||||
if (vertexData[currentBuffer].vCounter >= (MAX_BATCH_ELEMENTS*4)) rlglDraw();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1476,10 +1482,10 @@ void rlglInit(int width, int height)
|
||||
//for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]);
|
||||
|
||||
// NOTE: We don't need that much data on screen... right now...
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_11)
|
||||
//TraceLog(LOG_INFO, "OpenGL 1.1 (or driver default) profile initialized");
|
||||
#endif
|
||||
|
||||
// TODO: Automatize extensions loading using rlLoadExtensions() and GLAD
|
||||
// Actually, when rlglInit() is called in InitWindow() in core.c,
|
||||
// OpenGL required extensions have already been loaded (PLATFORM_DESKTOP)
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Get supported extensions list
|
||||
@@ -1560,7 +1566,6 @@ void rlglInit(int width, int height)
|
||||
// Check texture float support
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true;
|
||||
#endif
|
||||
|
||||
// DDS texture compression support
|
||||
if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
|
||||
(strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
|
||||
@@ -1616,6 +1621,8 @@ void rlglInit(int width, int height)
|
||||
|
||||
if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported");
|
||||
|
||||
|
||||
|
||||
// Initialize buffers, default shaders and default textures
|
||||
//----------------------------------------------------------
|
||||
|
||||
@@ -1738,11 +1745,11 @@ int rlGetVersion(void)
|
||||
}
|
||||
|
||||
// Check internal buffer overflow for a given number of vertex
|
||||
bool rlCheckBufferLimit(int type, int vCount)
|
||||
bool rlCheckBufferLimit(int vCount)
|
||||
{
|
||||
bool overflow = false;
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if ((vertexData[currentBuffer].vCounter + vCount)/4 >= MAX_BATCH_ELEMENTS) overflow = true;
|
||||
if ((vertexData[currentBuffer].vCounter + vCount) >= (MAX_BATCH_ELEMENTS*4)) overflow = true;
|
||||
#endif
|
||||
return overflow;
|
||||
}
|
||||
@@ -2897,37 +2904,36 @@ int GetShaderLocation(Shader shader, const char *uniformName)
|
||||
return location;
|
||||
}
|
||||
|
||||
// Set shader uniform value (float)
|
||||
void SetShaderValue(Shader shader, int uniformLoc, const float *value, int size)
|
||||
// Set shader uniform value
|
||||
void SetShaderValue(Shader shader, int uniformLoc, const void *value, int uniformType)
|
||||
{
|
||||
SetShaderValueV(shader, uniformLoc, value, uniformType, 1);
|
||||
}
|
||||
|
||||
// Set shader uniform value vector
|
||||
void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int uniformType, int count)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glUseProgram(shader.id);
|
||||
|
||||
if (size == 1) glUniform1fv(uniformLoc, 1, value); // Shader uniform type: float
|
||||
else if (size == 2) glUniform2fv(uniformLoc, 1, value); // Shader uniform type: vec2
|
||||
else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3
|
||||
else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4
|
||||
else TraceLog(LOG_WARNING, "Shader value float array size not supported");
|
||||
|
||||
switch (uniformType)
|
||||
{
|
||||
case UNIFORM_FLOAT: glUniform1fv(uniformLoc, count, (float *)value); break;
|
||||
case UNIFORM_VEC2: glUniform2fv(uniformLoc, count, (float *)value); break;
|
||||
case UNIFORM_VEC3: glUniform3fv(uniformLoc, count, (float *)value); break;
|
||||
case UNIFORM_VEC4: glUniform4fv(uniformLoc, count, (float *)value); break;
|
||||
case UNIFORM_INT: glUniform1iv(uniformLoc, count, (int *)value); break;
|
||||
case UNIFORM_IVEC2: glUniform2iv(uniformLoc, count, (int *)value); break;
|
||||
case UNIFORM_IVEC3: glUniform3iv(uniformLoc, count, (int *)value); break;
|
||||
case UNIFORM_IVEC4: glUniform4iv(uniformLoc, count, (int *)value); break;
|
||||
case UNIFORM_SAMPLER2D: glUniform1iv(uniformLoc, count, (int *)value); break;
|
||||
default: TraceLog(LOG_WARNING, "Shader uniform could not be set data type not recognized");
|
||||
}
|
||||
|
||||
//glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set shader uniform value (int)
|
||||
void SetShaderValuei(Shader shader, int uniformLoc, const int *value, int size)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glUseProgram(shader.id);
|
||||
|
||||
if (size == 1) glUniform1iv(uniformLoc, 1, value); // Shader uniform type: int
|
||||
else if (size == 2) glUniform2iv(uniformLoc, 1, value); // Shader uniform type: ivec2
|
||||
else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3
|
||||
else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4
|
||||
else TraceLog(LOG_WARNING, "Shader value int array size not supported");
|
||||
|
||||
//glUseProgram(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set shader uniform value (matrix 4x4)
|
||||
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat)
|
||||
@@ -2975,7 +2981,7 @@ Matrix GetMatrixModelview()
|
||||
Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
|
||||
{
|
||||
Texture2D cubemap = { 0 };
|
||||
#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// NOTE: SetShaderDefaultLocations() already setups locations for projection and view Matrix in shader
|
||||
// Other locations should be setup externally in shader before calling the function
|
||||
|
||||
@@ -2985,22 +2991,32 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Flag not supported on OpenGL ES 2.0
|
||||
#endif
|
||||
|
||||
|
||||
// Setup framebuffer
|
||||
unsigned int fbo, rbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
|
||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
|
||||
#endif
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
|
||||
// Set up cubemap to render and attach to framebuffer
|
||||
// NOTE: faces are stored with 16 bit floating point values
|
||||
// NOTE: Faces are stored as 32 bit floating point values
|
||||
glGenTextures(1, &cubemap.id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if (texFloatSupported) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
@@ -3009,9 +3025,8 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Create projection (transposed) and different views for each face
|
||||
// Create projection and different views for each face
|
||||
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0);
|
||||
//MatrixTranspose(&fboProjection);
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
@@ -3031,7 +3046,7 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
|
||||
glViewport(0, 0, size, size);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap.id, 0);
|
||||
@@ -3046,8 +3061,11 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
|
||||
glViewport(0, 0, screenWidth, screenHeight);
|
||||
//glEnable(GL_CULL_FACE);
|
||||
|
||||
// NOTE: Texture2D is a GL_TEXTURE_CUBE_MAP, not a GL_TEXTURE_2D!
|
||||
cubemap.width = size;
|
||||
cubemap.height = size;
|
||||
cubemap.mipmaps = 1;
|
||||
cubemap.format = UNCOMPRESSED_R32G32B32;
|
||||
#endif
|
||||
return cubemap;
|
||||
}
|
||||
@@ -3075,7 +3093,10 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
|
||||
glGenTextures(1, &irradiance.id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance.id);
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
@@ -3084,7 +3105,6 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
// Create projection (transposed) and different views for each face
|
||||
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0);
|
||||
//MatrixTranspose(&fboProjection);
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
@@ -3104,7 +3124,7 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
|
||||
glViewport(0, 0, size, size);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance.id, 0);
|
||||
@@ -3120,6 +3140,8 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
irradiance.width = size;
|
||||
irradiance.height = size;
|
||||
irradiance.mipmaps = 1;
|
||||
//irradiance.format = UNCOMPRESSED_R16G16B16;
|
||||
#endif
|
||||
return irradiance;
|
||||
}
|
||||
@@ -3149,7 +3171,10 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
|
||||
glGenTextures(1, &prefilter.id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, prefilter.id);
|
||||
for (unsigned int i = 0; i < 6; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
@@ -3161,7 +3186,6 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
// Create projection (transposed) and different views for each face
|
||||
Matrix fboProjection = MatrixPerspective(90.0*DEG2RAD, 1.0, 0.01, 1000.0);
|
||||
//MatrixTranspose(&fboProjection);
|
||||
Matrix fboViews[6] = {
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
MatrixLookAt((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ -1.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, -1.0f, 0.0f }),
|
||||
@@ -3181,11 +3205,11 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
#define MAX_MIPMAP_LEVELS 5 // Max number of prefilter texture mipmaps
|
||||
|
||||
for (unsigned int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++)
|
||||
for (int mip = 0; mip < MAX_MIPMAP_LEVELS; mip++)
|
||||
{
|
||||
// Resize framebuffer according to mip-level size.
|
||||
unsigned int mipWidth = size*(int) powf(0.5f, (float) mip);
|
||||
unsigned int mipHeight = size* (int) powf(0.5f, (float) mip);
|
||||
unsigned int mipWidth = size*(int)powf(0.5f, (float)mip);
|
||||
unsigned int mipHeight = size*(int)powf(0.5f, (float)mip);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
|
||||
@@ -3194,7 +3218,7 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
|
||||
float roughness = (float)mip/(float)(MAX_MIPMAP_LEVELS - 1);
|
||||
glUniform1f(roughnessLoc, roughness);
|
||||
|
||||
for (unsigned int i = 0; i < 6; ++i)
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip);
|
||||
@@ -3211,20 +3235,28 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
prefilter.width = size;
|
||||
prefilter.height = size;
|
||||
//prefilter.mipmaps = 1 + (int)floor(log(size)/log(2));
|
||||
//prefilter.format = UNCOMPRESSED_R16G16B16;
|
||||
#endif
|
||||
return prefilter;
|
||||
}
|
||||
|
||||
// Generate BRDF texture using cubemap data
|
||||
// TODO: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
|
||||
Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size)
|
||||
// NOTE: OpenGL ES 2.0 does not support GL_RGB16F texture format, neither GL_DEPTH_COMPONENT24
|
||||
// TODO: Review implementation: https://github.com/HectorMF/BRDFGenerator
|
||||
Texture2D GenTextureBRDF(Shader shader, int size)
|
||||
{
|
||||
Texture2D brdf = { 0 };
|
||||
#if defined(GRAPHICS_API_OPENGL_33) // || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Generate BRDF convolution texture
|
||||
glGenTextures(1, &brdf.id);
|
||||
glBindTexture(GL_TEXTURE_2D, brdf.id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, size, size, 0, GL_RG, GL_FLOAT, 0);
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if (texFloatSupported) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
#endif
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
@@ -3236,7 +3268,11 @@ Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size)
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size, size);
|
||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
|
||||
#endif
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdf.id, 0);
|
||||
|
||||
glViewport(0, 0, size, size);
|
||||
@@ -3246,12 +3282,18 @@ Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size)
|
||||
|
||||
// Unbind framebuffer and textures
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Unload framebuffer but keep color texture
|
||||
glDeleteRenderbuffers(1, &rbo);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
|
||||
// Reset viewport dimensions to default
|
||||
glViewport(0, 0, screenWidth, screenHeight);
|
||||
|
||||
brdf.width = size;
|
||||
brdf.height = size;
|
||||
brdf.mipmaps = 1;
|
||||
brdf.format = UNCOMPRESSED_R32G32B32;
|
||||
#endif
|
||||
return brdf;
|
||||
}
|
||||
@@ -3961,7 +4003,7 @@ static void DrawBuffersDefault(void)
|
||||
if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView);
|
||||
#endif
|
||||
|
||||
// Draw quads buffers
|
||||
// Draw buffers
|
||||
if (vertexData[currentBuffer].vCounter > 0)
|
||||
{
|
||||
// Set current shader and upload current MVP matrix
|
||||
@@ -4047,10 +4089,14 @@ static void DrawBuffersDefault(void)
|
||||
projection = matProjection;
|
||||
modelview = matModelView;
|
||||
|
||||
// Reset draws counter
|
||||
draws[0].mode = RL_QUADS;
|
||||
draws[0].vertexCount = 0;
|
||||
draws[0].textureId = defaultTextureId;
|
||||
// Reset draws array
|
||||
for (int i = 0; i < MAX_DRAWCALL_REGISTERED; i++)
|
||||
{
|
||||
draws[i].mode = RL_QUADS;
|
||||
draws[i].vertexCount = 0;
|
||||
draws[i].textureId = defaultTextureId;
|
||||
}
|
||||
|
||||
drawsCounter = 1;
|
||||
|
||||
// Change to next buffer in the list
|
||||
@@ -4238,15 +4284,15 @@ static void SetStereoConfig(VrDeviceInfo hmd)
|
||||
|
||||
#if defined(SUPPORT_DISTORTION_SHADER)
|
||||
// Update distortion shader with lens and distortion-scale parameters
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftScreenCenter"), leftScreenCenter, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightScreenCenter"), rightScreenCenter, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, UNIFORM_VEC2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, UNIFORM_VEC2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftScreenCenter"), leftScreenCenter, UNIFORM_VEC2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightScreenCenter"), rightScreenCenter, UNIFORM_VEC2);
|
||||
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scale"), scale, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, 4);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, 4);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scale"), scale, UNIFORM_VEC2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, UNIFORM_VEC2);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, UNIFORM_VEC4);
|
||||
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, UNIFORM_VEC4);
|
||||
#endif
|
||||
|
||||
// Fovy is normally computed with: 2*atan2(hmd.vScreenSize, 2*hmd.eyeToScreenDistance)
|
||||
@@ -4268,8 +4314,8 @@ static void SetStereoConfig(VrDeviceInfo hmd)
|
||||
vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);
|
||||
|
||||
// Compute eyes Viewports
|
||||
vrConfig.eyesViewport[0] = (Rectangle){ 0.0f, 0.0f, (float)hmd.hResolution/2, (float)hmd.vResolution };
|
||||
vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2.0f, 0.0f, (float)hmd.hResolution/2, (float) hmd.vResolution };
|
||||
//vrConfig.eyesViewport[0] = { 0.0f, 0.0f, (float)hmd.hResolution/2, (float)hmd.vResolution };
|
||||
//vrConfig.eyesViewport[1] = { hmd.hResolution/2.0f, 0.0f, (float)hmd.hResolution/2, (float) hmd.vResolution };
|
||||
}
|
||||
|
||||
// Set internal projection and modelview matrix depending on eyes tracking data
|
||||
|
||||
+58
-50
@@ -130,9 +130,9 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef((float)startPos.x, (float)startPos.y, 0);
|
||||
rlRotatef(RAD2DEG*angle, 0, 0, 1);
|
||||
rlTranslatef(0, (thick > 1.0f) ? -thick/2.0f : -1.0f, 0);
|
||||
rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f);
|
||||
rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f);
|
||||
rlTranslatef(0, (thick > 1.0f) ? -thick/2.0f : -1.0f, 0.0f);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
@@ -186,7 +186,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
|
||||
// NOTE: Gradient goes from center (color1) to border (color2)
|
||||
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
|
||||
{
|
||||
if (rlCheckBufferLimit(RL_TRIANGLES, 3*36)) rlglDraw();
|
||||
if (rlCheckBufferLimit(3*36)) rlglDraw();
|
||||
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
@@ -206,7 +206,7 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
|
||||
void DrawCircleV(Vector2 center, float radius, Color color)
|
||||
{
|
||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||
if (rlCheckBufferLimit(RL_QUADS, 4*(36/2))) rlglDraw();
|
||||
if (rlCheckBufferLimit(4*(36/2))) rlglDraw();
|
||||
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
|
||||
@@ -231,7 +231,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
|
||||
|
||||
rlDisableTexture();
|
||||
#else
|
||||
if (rlCheckBufferLimit(RL_TRIANGLES, 3*(36/2))) rlglDraw();
|
||||
if (rlCheckBufferLimit(3*(36/2))) rlglDraw();
|
||||
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i = 0; i < 360; i += 10)
|
||||
@@ -249,7 +249,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
|
||||
// Draw circle outline
|
||||
void DrawCircleLines(int centerX, int centerY, float radius, Color color)
|
||||
{
|
||||
if (rlCheckBufferLimit(RL_LINES, 2*36)) rlglDraw();
|
||||
if (rlCheckBufferLimit(2*36)) rlglDraw();
|
||||
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
@@ -273,48 +273,40 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
|
||||
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
|
||||
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
|
||||
{
|
||||
Color colors[4] = { color, color, color, color };
|
||||
|
||||
DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
|
||||
DrawRectanglePro((Rectangle){ position.x, position.y, size.x, size.y }, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
|
||||
}
|
||||
|
||||
// Draw a color-filled rectangle
|
||||
void DrawRectangleRec(Rectangle rec, Color color)
|
||||
{
|
||||
Color colors[4] = { color, color, color, color };
|
||||
|
||||
DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
|
||||
DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, color);
|
||||
}
|
||||
|
||||
// Draw a color-filled rectangle with pro parameters
|
||||
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color colors[4])
|
||||
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
|
||||
{
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
|
||||
rlPushMatrix();
|
||||
//rlTranslatef(rec.x, rec.y, 0); // Already considered on vertex position
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
rlTranslatef(-origin.x, -origin.y, 0);
|
||||
rlTranslatef(rec.x, rec.y, 0.0f);
|
||||
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
|
||||
rlTranslatef(-origin.x, -origin.y, 0.0f);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
// NOTE: Default raylib font character 95 is a white square
|
||||
rlColor4ub(colors[0].r, colors[0].g, colors[0].b, colors[0].a);
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y);
|
||||
|
||||
rlColor4ub(colors[1].r, colors[1].g, colors[1].b, colors[1].a);
|
||||
rlVertex2f(0.0f, 0.0f);
|
||||
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(colors[2].r, colors[2].g, colors[2].b, colors[2].a);
|
||||
rlVertex2f(0.0f, rec.height);
|
||||
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
||||
rlVertex2f(rec.width, rec.height);
|
||||
|
||||
rlColor4ub(colors[3].r, colors[3].g, colors[3].b, colors[3].a);
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y);
|
||||
rlVertex2f(rec.width, 0.0f);
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
|
||||
@@ -339,9 +331,32 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color col
|
||||
// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
|
||||
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
|
||||
{
|
||||
Color colors[4] = { col1, col2, col3, col4 };
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
|
||||
DrawRectanglePro(rec, (Vector2){ 0.0f, 0.0f }, 0.0f, colors);
|
||||
rlPushMatrix();
|
||||
rlBegin(RL_QUADS);
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
// NOTE: Default raylib font character 95 is a white square
|
||||
rlColor4ub(col1.r, col1.g, col1.b, col1.a);
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y);
|
||||
|
||||
rlColor4ub(col2.r, col2.g, col2.b, col2.a);
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(rec.x, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(col3.r, col3.g, col3.b, col3.a);
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
||||
|
||||
rlColor4ub(col4.r, col4.g, col4.b, col4.a);
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(rec.x + rec.width, rec.y);
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
|
||||
rlDisableTexture();
|
||||
}
|
||||
|
||||
// Draw rectangle outline
|
||||
@@ -440,11 +455,11 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
|
||||
{
|
||||
if (sides < 3) sides = 3;
|
||||
|
||||
if (rlCheckBufferLimit(RL_QUADS, 4*(360/sides))) rlglDraw();
|
||||
if (rlCheckBufferLimit(4*(360/sides))) rlglDraw();
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef(center.x, center.y, 0.0);
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
rlTranslatef(center.x, center.y, 0.0f);
|
||||
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
@@ -488,35 +503,28 @@ void DrawPolyEx(Vector2 *points, int pointsCount, Color color)
|
||||
{
|
||||
if (pointsCount >= 3)
|
||||
{
|
||||
if (rlCheckBufferLimit(RL_QUADS, pointsCount)) rlglDraw();
|
||||
if (rlCheckBufferLimit((pointsCount - 2)*4)) rlglDraw();
|
||||
|
||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||
rlEnableTexture(GetShapesTexture().id);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
for (int i = 1; i < pointsCount - 1; i++)
|
||||
{
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(points[0].x, points[0].y);
|
||||
|
||||
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(points[i].x, points[i].y);
|
||||
rlVertex2f(points[i].x, points[i].y);
|
||||
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
|
||||
rlVertex2f(points[i + 1].x, points[i + 1].y);
|
||||
|
||||
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, recTexShapes.y/texShapes.height);
|
||||
rlVertex2f(points[i + 1].x, points[i + 1].y);
|
||||
}
|
||||
rlEnd();
|
||||
rlDisableTexture();
|
||||
#else
|
||||
rlBegin(RL_TRIANGLES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
for (int i = 1; i < pointsCount - 1; i++)
|
||||
{
|
||||
rlVertex2f(points[0].x, points[0].y);
|
||||
rlVertex2f(points[i].x, points[i].y);
|
||||
rlVertex2f(points[i + 1].x, points[i + 1].y);
|
||||
}
|
||||
rlEnd();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,7 +533,7 @@ void DrawPolyExLines(Vector2 *points, int pointsCount, Color color)
|
||||
{
|
||||
if (pointsCount >= 2)
|
||||
{
|
||||
if (rlCheckBufferLimit(RL_LINES, pointsCount)) rlglDraw();
|
||||
if (rlCheckBufferLimit(pointsCount)) rlglDraw();
|
||||
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
+398
-45
@@ -47,6 +47,7 @@
|
||||
#include <string.h> // Required for: strlen()
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
|
||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
|
||||
#include <ctype.h> // Required for: toupper(), tolower()
|
||||
|
||||
#include "utils.h" // Required for: fopen() Android mapping
|
||||
|
||||
@@ -62,8 +63,7 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define MAX_FORMATTEXT_LENGTH 512
|
||||
#define MAX_SUBTEXT_LENGTH 512
|
||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers of some Text*() functions
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
@@ -275,7 +275,7 @@ Font LoadFont(const char *fileName)
|
||||
Font font = { 0 };
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, DEFAULT_TTF_NUMCHARS, NULL);
|
||||
if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
||||
else
|
||||
#endif
|
||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||
@@ -301,7 +301,7 @@ Font LoadFont(const char *fileName)
|
||||
// Load Font from TTF font file with generation parameters
|
||||
// NOTE: You can pass an array with desired characters, those characters should be available in the font
|
||||
// if array is NULL, default char set is selected 32..126
|
||||
Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars)
|
||||
Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount)
|
||||
{
|
||||
Font font = { 0 };
|
||||
|
||||
@@ -700,7 +700,7 @@ void DrawFPS(int posX, int posY)
|
||||
}
|
||||
|
||||
// NOTE: We have rounding errors every frame, so it oscillates a lot
|
||||
DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME);
|
||||
DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, LIME);
|
||||
}
|
||||
|
||||
// Draw text (using default font)
|
||||
@@ -779,6 +779,131 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
||||
}
|
||||
}
|
||||
|
||||
// Draw text using font inside rectangle limits
|
||||
void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
|
||||
{
|
||||
int length = strlen(text);
|
||||
int textOffsetX = 0; // Offset between characters
|
||||
int textOffsetY = 0; // Required for line break!
|
||||
float scaleFactor = 0.0f;
|
||||
|
||||
unsigned char letter = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
|
||||
scaleFactor = fontSize/font.baseSize;
|
||||
|
||||
enum { MEASURE_WORD = 0, DRAW_WORD = 1 };
|
||||
int state = wordWrap ? MEASURE_WORD : DRAW_WORD;
|
||||
int lastTextOffsetX = 0;
|
||||
int wordStart = 0;
|
||||
|
||||
bool firstWord = true;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int glyphWidth = 0;
|
||||
letter = (unsigned char)text[i];
|
||||
|
||||
if (letter != '\n')
|
||||
{
|
||||
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK!
|
||||
{
|
||||
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
|
||||
letter = (unsigned char)text[i + 1];
|
||||
index = GetGlyphIndex(font, (int)letter);
|
||||
i++;
|
||||
}
|
||||
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK!
|
||||
{
|
||||
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
|
||||
letter = (unsigned char)text[i + 1];
|
||||
index = GetGlyphIndex(font, (int)letter + 64);
|
||||
i++;
|
||||
}
|
||||
else index = GetGlyphIndex(font, (unsigned char)text[i]);
|
||||
|
||||
glyphWidth = (font.chars[index].advanceX == 0)?
|
||||
(int)(font.chars[index].rec.width*scaleFactor + spacing):
|
||||
(int)(font.chars[index].advanceX*scaleFactor + spacing);
|
||||
}
|
||||
|
||||
// NOTE: When word wrap is active first we measure a `word`(measure until a ' ','\n','\t' is found)
|
||||
// then set all the variables back to what they were before the measurement, change the state to
|
||||
// draw that word then change the state again and repeat until the end of the string...when the word
|
||||
// doesn't fit inside the rect we simple increase `textOffsetY` to draw it on the next line
|
||||
if (state == MEASURE_WORD)
|
||||
{
|
||||
// Measuring state
|
||||
if ((letter == ' ') || (letter == '\n') || (letter == '\t') || ((i + 1) == length))
|
||||
{
|
||||
int t = textOffsetX + glyphWidth;
|
||||
|
||||
if (textOffsetX+1>=rec.width)
|
||||
{
|
||||
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
|
||||
lastTextOffsetX = t - lastTextOffsetX;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
textOffsetX = lastTextOffsetX;
|
||||
lastTextOffsetX = t;
|
||||
}
|
||||
|
||||
glyphWidth = 0;
|
||||
state = !state; // Change state
|
||||
t = i;
|
||||
i = firstWord?-1:wordStart;
|
||||
wordStart = t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drawing state
|
||||
int t = textOffsetX + glyphWidth;
|
||||
|
||||
if (letter == '\n')
|
||||
{
|
||||
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
|
||||
lastTextOffsetX = t - lastTextOffsetX;
|
||||
if (lastTextOffsetX < 0) lastTextOffsetX = 0;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
else if ((letter != ' ') && (letter != '\t'))
|
||||
{
|
||||
if ((t + 1) >= rec.width)
|
||||
{
|
||||
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
|
||||
textOffsetX = 0;
|
||||
}
|
||||
|
||||
if ((textOffsetY + (int)((font.baseSize + font.baseSize/2)*scaleFactor)) > rec.height) break;
|
||||
|
||||
DrawTexturePro(font.texture, font.chars[index].rec,
|
||||
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
|
||||
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
|
||||
font.chars[index].rec.width*scaleFactor,
|
||||
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||
}
|
||||
|
||||
if (wordWrap)
|
||||
{
|
||||
if ((letter == ' ') || (letter == '\n') || (letter == '\t'))
|
||||
{
|
||||
// After drawing a word change the state
|
||||
firstWord = false;
|
||||
i = wordStart;
|
||||
textOffsetX = lastTextOffsetX;
|
||||
glyphWidth = 0;
|
||||
state = !state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textOffsetX += glyphWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Measure string width for default font
|
||||
int MeasureText(const char *text, int fontSize)
|
||||
{
|
||||
@@ -810,13 +935,30 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
||||
float textHeight = (float)font.baseSize;
|
||||
float scaleFactor = fontSize/(float)font.baseSize;
|
||||
|
||||
unsigned char letter = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
lenCounter++;
|
||||
|
||||
|
||||
if (text[i] != '\n')
|
||||
{
|
||||
int index = GetGlyphIndex(font, (int)text[i]);
|
||||
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification
|
||||
{
|
||||
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
|
||||
letter = (unsigned char)text[i + 1];
|
||||
index = GetGlyphIndex(font, (int)letter);
|
||||
i++;
|
||||
}
|
||||
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification
|
||||
{
|
||||
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
|
||||
letter = (unsigned char)text[i + 1];
|
||||
index = GetGlyphIndex(font, (int)letter + 64);
|
||||
i++;
|
||||
}
|
||||
else index = GetGlyphIndex(font, (unsigned char)text[i]);
|
||||
|
||||
if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
|
||||
else textWidth += (font.chars[index].rec.width + font.chars[index].offsetX);
|
||||
@@ -863,10 +1005,33 @@ int GetGlyphIndex(Font font, int character)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Formatting of text with variables to 'embed'
|
||||
const char *FormatText(const char *text, ...)
|
||||
// Text strings management functions
|
||||
//----------------------------------------------------------------------------------
|
||||
// Check if two text string are equal
|
||||
// REQUIRES: strcmp()
|
||||
bool TextIsEqual(const char *text1, const char *text2)
|
||||
{
|
||||
static char buffer[MAX_FORMATTEXT_LENGTH];
|
||||
bool result = false;
|
||||
|
||||
if (strcmp(text1, text2) == 0) result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get text length in bytes, check for \0 character
|
||||
unsigned int TextLength(const char *text)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
|
||||
while (*text++) length++;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// Formatting of text with variables to 'embed'
|
||||
const char *TextFormat(const char *text, ...)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
@@ -877,9 +1042,11 @@ const char *FormatText(const char *text, ...)
|
||||
}
|
||||
|
||||
// Get a piece of a text string
|
||||
const char *SubText(const char *text, int position, int length)
|
||||
// REQUIRES: strlen()
|
||||
const char *TextSubtext(const char *text, int position, int length)
|
||||
{
|
||||
static char buffer[MAX_SUBTEXT_LENGTH] = { 0 };
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
int textLength = strlen(text);
|
||||
|
||||
if (position >= textLength)
|
||||
@@ -901,52 +1068,238 @@ const char *SubText(const char *text, int position, int length)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Split string into multiple strings
|
||||
// NOTE: Files count is returned by parameters pointer
|
||||
// NOTE: Allocated memory should be manually freed
|
||||
char **SplitText(char *text, char delimiter, int *strCount)
|
||||
// Replace text string
|
||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
||||
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
|
||||
const char *TextReplace(char *text, const char *replace, const char *by)
|
||||
{
|
||||
#define MAX_SUBSTRING_LENGTH 128
|
||||
char *result;
|
||||
|
||||
char *insertPoint; // Next insert point
|
||||
char *temp; // Temp pointer
|
||||
int replaceLen; // Replace string length of (the string to remove)
|
||||
int byLen; // Replacement length (the string to replace replace by)
|
||||
int lastReplacePos; // Distance between replace and end of last replace
|
||||
int count; // Number of replacements
|
||||
|
||||
char **strings = NULL;
|
||||
int len = strlen(text);
|
||||
char *strDup = (char *)malloc(len + 1);
|
||||
strcpy(strDup, text);
|
||||
int counter = 1;
|
||||
// Sanity checks and initialization
|
||||
if (!text || !replace) return NULL;
|
||||
|
||||
// Count how many substrings we have on string
|
||||
for (int i = 0; i < len; i++) if (text[i] == delimiter) counter++;
|
||||
replaceLen = strlen(replace);
|
||||
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
|
||||
|
||||
// Memory allocation for substrings
|
||||
strings = (char **)malloc(sizeof(char *)*counter);
|
||||
for (int i = 0; i < counter; i++) strings[i] = (char *)malloc(sizeof(char)*MAX_SUBSTRING_LENGTH);
|
||||
if (!by) by = ""; // Replace by nothing if not provided
|
||||
byLen = strlen(by);
|
||||
|
||||
char *substrPtr = NULL;
|
||||
char delimiters[1] = { delimiter }; // Only caring for one delimiter
|
||||
substrPtr = strtok(strDup, delimiters);
|
||||
// Count the number of replacements needed
|
||||
insertPoint = text;
|
||||
for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
|
||||
|
||||
for (int i = 0; (i < counter) && (substrPtr != NULL); i++)
|
||||
// Allocate returning string and point temp to it
|
||||
temp = result = malloc(strlen(text) + (byLen - replaceLen)*count + 1);
|
||||
|
||||
if (!result) return NULL; // Memory could not be allocated
|
||||
|
||||
// First time through the loop, all the variable are set correctly from here on,
|
||||
// temp points to the end of the result string
|
||||
// insertPoint points to the next occurrence of replace in text
|
||||
// text points to the remainder of text after "end of replace"
|
||||
while (count--)
|
||||
{
|
||||
strcpy(strings[i], substrPtr);
|
||||
substrPtr = strtok(NULL, delimiters);
|
||||
insertPoint = strstr(text, replace);
|
||||
lastReplacePos = insertPoint - text;
|
||||
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
|
||||
temp = strcpy(temp, by) + byLen;
|
||||
text += lastReplacePos + replaceLen; // Move to next "end of replace"
|
||||
}
|
||||
|
||||
*strCount = counter;
|
||||
free(strDup);
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
// Check if two text string are equal
|
||||
bool IsEqualText(const char *text1, const char *text2)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (strcmp(text1, text2) == 0) result = true;
|
||||
// Copy remaind text part after replacement to result (pointed by moving temp)
|
||||
strcpy(temp, text);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Insert text in a specific position, moves all text forward
|
||||
// REQUIRES: strlen(), strcpy(), strtok()
|
||||
// WARNING: Allocated memory should be manually freed
|
||||
const char *TextInsert(const char *text, const char *insert, int position)
|
||||
{
|
||||
int textLen = strlen(text);
|
||||
int insertLen = strlen(insert);
|
||||
|
||||
char *result = (char *)malloc(textLen + insertLen + 1);
|
||||
|
||||
for (int i = 0; i < position; i++) result[i] = text[i];
|
||||
for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
|
||||
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
|
||||
|
||||
result[textLen + insertLen] = '\0'; // Make sure text string is valid!
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Join text strings with delimiter
|
||||
// REQUIRES: strcat()
|
||||
const char *TextJoin(const char **textList, int count, const char *delimiter)
|
||||
{
|
||||
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
int delimiterLen = strlen(delimiter);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
strcat(text, textList[i]);
|
||||
if ((delimiterLen > 0) && (i < (count - 1))) strcat(text, delimiter);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// Split string into multiple strings
|
||||
// REQUIRES: strlen(), strcpy(), strtok()
|
||||
// WARNING: Allocated memory should be manually freed
|
||||
char **TextSplit(const char *text, char delimiter, int *count)
|
||||
{
|
||||
#define MAX_SUBSTRING_LENGTH 128
|
||||
|
||||
// TODO: Allocate memory properly for every substring size
|
||||
|
||||
char **result = NULL;
|
||||
|
||||
int len = strlen(text);
|
||||
char *textcopy = (char *)malloc(len + 1);
|
||||
strcpy(textcopy, text);
|
||||
int counter = 1;
|
||||
|
||||
// Count how many substrings we have on text and init memory for each of them
|
||||
for (int i = 0; i < len; i++) if (text[i] == delimiter) counter++;
|
||||
|
||||
// Memory allocation for substrings
|
||||
result = (char **)malloc(sizeof(char *)*counter);
|
||||
for (int i = 0; i < counter; i++) result[i] = (char *)malloc(sizeof(char)*MAX_SUBSTRING_LENGTH);
|
||||
|
||||
char *substrPtr = NULL;
|
||||
char delimiters[1] = { delimiter }; // Only caring for one delimiter
|
||||
substrPtr = strtok(textcopy, delimiters);
|
||||
|
||||
for (int i = 0; (i < counter) && (substrPtr != NULL); i++)
|
||||
{
|
||||
strcpy(result[i], substrPtr);
|
||||
substrPtr = strtok(NULL, delimiters);
|
||||
}
|
||||
|
||||
*count = counter;
|
||||
free(textcopy);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get pointers to substrings separated by delimiter
|
||||
void TextSplitEx(const char *text, char delimiter, int *count, const char **ptrs, int *lengths)
|
||||
{
|
||||
int elementsCount = 0;
|
||||
int charsCount = 0;
|
||||
|
||||
ptrs[0] = text;
|
||||
|
||||
for (int i = 0; text[i] != '\0'; i++)
|
||||
{
|
||||
charsCount++;
|
||||
|
||||
if (text[i] == delimiter)
|
||||
{
|
||||
lengths[elementsCount] = charsCount - 1;
|
||||
charsCount = 0;
|
||||
elementsCount++;
|
||||
|
||||
ptrs[elementsCount] = &text[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
lengths[elementsCount] = charsCount;
|
||||
elementsCount++;
|
||||
|
||||
*count = elementsCount;
|
||||
}
|
||||
|
||||
// Append text at specific position and move cursor!
|
||||
// REQUIRES: strcpy()
|
||||
void TextAppend(char *text, const char *append, int *position)
|
||||
{
|
||||
strcpy(text + *position, append);
|
||||
*position += strlen(append);
|
||||
}
|
||||
|
||||
// Find first text occurrence within a string
|
||||
// REQUIRES: strstr()
|
||||
int TextFindIndex(const char *text, const char *find)
|
||||
{
|
||||
int position = -1;
|
||||
|
||||
char *ptr = strstr(text, find);
|
||||
|
||||
if (ptr != NULL) position = ptr - text;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
// Get upper case version of provided string
|
||||
// REQUIRES: toupper()
|
||||
const char *TextToUpper(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0') buffer[i] = (char)toupper(text[i]);
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Get lower case version of provided string
|
||||
// REQUIRES: tolower()
|
||||
const char *TextToLower(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0') buffer[i] = (char)tolower(text[i]);
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Get Pascal case notation version of provided string
|
||||
// REQUIRES: toupper()
|
||||
const char *TextToPascal(const char *text)
|
||||
{
|
||||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
|
||||
buffer[0] = (char)toupper(text[0]);
|
||||
|
||||
for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
|
||||
{
|
||||
if (text[j] != '\0')
|
||||
{
|
||||
if (text[j] != '_') buffer[i] = text[j];
|
||||
else
|
||||
{
|
||||
j++;
|
||||
buffer[i] = (char)toupper(text[j]);
|
||||
}
|
||||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
+18
-6
@@ -2418,6 +2418,17 @@ void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Co
|
||||
DrawTexturePro(texture, sourceRec, destRec, origin, 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw texture quad with tiling and offset parameters
|
||||
// NOTE: Tiling and offset should be provided considering normalized texture values [0..1]
|
||||
// i.e tiling = { 1.0f, 1.0f } refers to all texture, offset = { 0.5f, 0.5f } moves texture origin to center
|
||||
void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint)
|
||||
{
|
||||
Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height };
|
||||
Vector2 origin = { 0.0f, 0.0f };
|
||||
|
||||
DrawTexturePro(texture, source, quad, origin, 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
|
||||
// NOTE: origin is relative to destination rectangle size
|
||||
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
|
||||
@@ -2434,9 +2445,9 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
|
||||
rlEnableTexture(texture.id);
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef(destRec.x, destRec.y, 0);
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
rlTranslatef(-origin.x, -origin.y, 0);
|
||||
rlTranslatef(destRec.x, destRec.y, 0.0f);
|
||||
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
|
||||
rlTranslatef(-origin.x, -origin.y, 0.0f);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
@@ -2464,6 +2475,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
|
||||
}
|
||||
}
|
||||
|
||||
// Draws a texture (or part of it) that stretches or shrinks nicely using n-patch info
|
||||
void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint)
|
||||
{
|
||||
if (texture.id > 0)
|
||||
@@ -2524,9 +2536,9 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destR
|
||||
rlEnableTexture(texture.id);
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef(destRec.x, destRec.y, 0);
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
rlTranslatef(-origin.x, -origin.y, 0);
|
||||
rlTranslatef(destRec.x, destRec.y, 0.0f);
|
||||
rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
|
||||
rlTranslatef(-origin.x, -origin.y, 0.0f);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
|
||||
+5
-5
@@ -46,11 +46,6 @@
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
|
||||
#include <string.h> // Required for: strlen(), strrchr(), strcmp()
|
||||
|
||||
/* This should be in <stdio.h>, but Travis doesn't find it... */
|
||||
FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int),
|
||||
int (*writefn)(void *, const char *, int),
|
||||
fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -67,6 +62,11 @@ AAssetManager *assetManager;
|
||||
// Module specific Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
/* This should be in <stdio.h>, but Travis doesn't find it... */
|
||||
FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int),
|
||||
int (*writefn)(void *, const char *, int),
|
||||
fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));
|
||||
|
||||
static int android_read(void *cookie, char *buf, int size);
|
||||
static int android_write(void *cookie, const char *buf, int size);
|
||||
static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
|
||||
|
||||
Reference in New Issue
Block a user