mirror of
https://github.com/gwm17/glfw.git
synced 2024-11-23 02:38:52 -05:00
Added support for custom system cursors.
This adds 3 functions to the GLFW API: glfwCreateCursor, glfwDestroyCursor and glfwSetCursor.
This commit is contained in:
parent
30f86286f5
commit
40c04a7565
|
@ -268,6 +268,15 @@ if (_GLFW_X11)
|
||||||
set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lm")
|
set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lm")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Check for Xcursor
|
||||||
|
if (NOT X11_Xcursor_FOUND)
|
||||||
|
message(FATAL_ERROR "The Xcursor libraries and headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND glfw_INCLUDE_DIR ${X11_Xcursor_INCLUDE_PATH})
|
||||||
|
list(APPEND glfw_LIBRARIES ${X11_Xcursor_LIB})
|
||||||
|
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xcursor")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
#--------------------------------------------------------------------
|
||||||
|
|
|
@ -575,6 +575,14 @@ typedef struct GLFWmonitor GLFWmonitor;
|
||||||
*/
|
*/
|
||||||
typedef struct GLFWwindow GLFWwindow;
|
typedef struct GLFWwindow GLFWwindow;
|
||||||
|
|
||||||
|
/*! @brief Opaque cursor object.
|
||||||
|
*
|
||||||
|
* Opaque cursor object.
|
||||||
|
*
|
||||||
|
* @ingroup cursor
|
||||||
|
*/
|
||||||
|
typedef struct GLFWcursor GLFWcursor;
|
||||||
|
|
||||||
/*! @brief The function signature for error callbacks.
|
/*! @brief The function signature for error callbacks.
|
||||||
*
|
*
|
||||||
* This is the function signature for error callback functions.
|
* This is the function signature for error callback functions.
|
||||||
|
@ -1926,6 +1934,50 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
|
||||||
*/
|
*/
|
||||||
GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
|
GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
|
||||||
|
|
||||||
|
/*! @brief Creates a cursor.
|
||||||
|
*
|
||||||
|
* @param[in] width The desired cursor width.
|
||||||
|
* @param[in] height The desired cursor height.
|
||||||
|
* @param[in] xhot The desired x-coordinate of the cursor hotspot.
|
||||||
|
* @param[in] yhot The desired y-coordinate of the cursor hotspot.
|
||||||
|
* @param[in] format Not used.
|
||||||
|
* @param[in] data The cursor image data in RGBA8 format, packed in rows from
|
||||||
|
* top to bottom.
|
||||||
|
*
|
||||||
|
* @return A new cursor ready to use or `NULL` if an error occurred. If you
|
||||||
|
* don't destroy the cursor by calling `glfwDestroyCursor` it will be destroyed
|
||||||
|
* automatically by `GLFW` on termination.
|
||||||
|
*
|
||||||
|
* @note This function may only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI GLFWcursor* glfwCreateCursor(int width, int height, int xhot, int yhot, int format, const void* data);
|
||||||
|
|
||||||
|
/*! @brief Destroys a cursor.
|
||||||
|
*
|
||||||
|
* This function destroys a cursor previously created by a call to
|
||||||
|
* `glfwCreateCursor`. `GLFW` will destroy all cursors automatically on
|
||||||
|
* termination.
|
||||||
|
*
|
||||||
|
* @param[in] cursor The cursor to destroy.
|
||||||
|
*
|
||||||
|
* @note This function may only be called from the main thread.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor);
|
||||||
|
|
||||||
|
/*! @brief Sets the cursor for a given window.
|
||||||
|
*
|
||||||
|
* @param[in] window The window to set the cursor for.
|
||||||
|
* @param[in] cursor The cursor to change to, or `NULL` to switch back to the
|
||||||
|
* default system cursor.
|
||||||
|
*
|
||||||
|
* @ingroup input
|
||||||
|
*/
|
||||||
|
GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
|
||||||
|
|
||||||
/*! @brief Sets the key callback.
|
/*! @brief Sets the key callback.
|
||||||
*
|
*
|
||||||
* This function sets the key callback of the specific window, which is called
|
* This function sets the key callback of the specific window, which is called
|
||||||
|
|
|
@ -51,6 +51,7 @@ typedef void* id;
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
@ -67,6 +68,7 @@ typedef struct _GLFWwindowNS
|
||||||
id delegate;
|
id delegate;
|
||||||
id view;
|
id view;
|
||||||
unsigned int modifierFlags;
|
unsigned int modifierFlags;
|
||||||
|
int cursorInside;
|
||||||
} _GLFWwindowNS;
|
} _GLFWwindowNS;
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,6 +125,15 @@ typedef struct _GLFWmonitorNS
|
||||||
} _GLFWmonitorNS;
|
} _GLFWmonitorNS;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Platform-specific cursor structure
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
typedef struct _GLFWcursorNS
|
||||||
|
{
|
||||||
|
id handle;
|
||||||
|
} _GLFWcursorNS;
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Prototypes for platform specific internal functions
|
// Prototypes for platform specific internal functions
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
|
@ -44,7 +44,12 @@ static void centerCursor(_GLFWwindow *window)
|
||||||
static void setModeCursor(_GLFWwindow* window)
|
static void setModeCursor(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||||
[[NSCursor arrowCursor] set];
|
{
|
||||||
|
if (window->cursor)
|
||||||
|
[(NSCursor*) window->cursor->ns.handle set];
|
||||||
|
else
|
||||||
|
[[NSCursor arrowCursor] set];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
[(NSCursor*) _glfw.ns.cursor set];
|
[(NSCursor*) _glfw.ns.cursor set];
|
||||||
}
|
}
|
||||||
|
@ -556,11 +561,13 @@ static int translateKey(unsigned int key)
|
||||||
|
|
||||||
- (void)mouseExited:(NSEvent *)event
|
- (void)mouseExited:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
window->ns.cursorInside = GL_FALSE;
|
||||||
_glfwInputCursorEnter(window, GL_FALSE);
|
_glfwInputCursorEnter(window, GL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseEntered:(NSEvent *)event
|
- (void)mouseEntered:(NSEvent *)event
|
||||||
{
|
{
|
||||||
|
window->ns.cursorInside = GL_TRUE;
|
||||||
_glfwInputCursorEnter(window, GL_TRUE);
|
_glfwInputCursorEnter(window, GL_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1194,6 +1201,61 @@ void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
|
||||||
CGAssociateMouseAndMouseCursorPosition(true);
|
CGAssociateMouseAndMouseCursorPosition(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int width, int height, int cx, int cy,
|
||||||
|
int format, const void* data)
|
||||||
|
{
|
||||||
|
NSImage* image;
|
||||||
|
NSBitmapImageRep* rep;
|
||||||
|
|
||||||
|
rep = [[NSBitmapImageRep alloc]
|
||||||
|
initWithBitmapDataPlanes:NULL
|
||||||
|
pixelsWide:width
|
||||||
|
pixelsHigh:height
|
||||||
|
bitsPerSample:8
|
||||||
|
samplesPerPixel:4
|
||||||
|
hasAlpha:YES
|
||||||
|
isPlanar:NO
|
||||||
|
colorSpaceName:NSCalibratedRGBColorSpace
|
||||||
|
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
|
||||||
|
bytesPerRow:width * 4
|
||||||
|
bitsPerPixel:32];
|
||||||
|
|
||||||
|
if (rep == nil)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
memcpy([rep bitmapData], data, 4 * width * height);
|
||||||
|
|
||||||
|
image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
|
||||||
|
[image addRepresentation: rep];
|
||||||
|
|
||||||
|
cursor->ns.handle = [[NSCursor alloc] initWithImage:image
|
||||||
|
hotSpot:NSMakePoint(cx, cy)];
|
||||||
|
|
||||||
|
[image release];
|
||||||
|
[rep release];
|
||||||
|
|
||||||
|
if (cursor->ns.handle == nil)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
return GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
[(NSCursor*) cursor->ns.handle release];
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_NORMAL && window->ns.cursorInside)
|
||||||
|
{
|
||||||
|
if (cursor)
|
||||||
|
[(NSCursor*) cursor->ns.handle set];
|
||||||
|
else
|
||||||
|
[[NSCursor arrowCursor] set];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
|
|
@ -156,6 +156,10 @@ GLFWAPI void glfwTerminate(void)
|
||||||
while (_glfw.windowListHead)
|
while (_glfw.windowListHead)
|
||||||
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
|
glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead);
|
||||||
|
|
||||||
|
// Destroy all cursors
|
||||||
|
while (_glfw.cursorListHead)
|
||||||
|
glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead);
|
||||||
|
|
||||||
for (i = 0; i < _glfw.monitorCount; i++)
|
for (i = 0; i < _glfw.monitorCount; i++)
|
||||||
{
|
{
|
||||||
_GLFWmonitor* monitor = _glfw.monitors[i];
|
_GLFWmonitor* monitor = _glfw.monitors[i];
|
||||||
|
|
75
src/input.c
75
src/input.c
|
@ -27,6 +27,11 @@
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Internal key state used for sticky keys
|
// Internal key state used for sticky keys
|
||||||
#define _GLFW_STICK 3
|
#define _GLFW_STICK 3
|
||||||
|
|
||||||
|
@ -348,6 +353,76 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
|
||||||
_glfwPlatformSetCursorPos(window, xpos, ypos);
|
_glfwPlatformSetCursorPos(window, xpos, ypos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GLFWAPI GLFWcursor* glfwCreateCursor(int width, int height, int cx, int cy,
|
||||||
|
int format, const void* data)
|
||||||
|
{
|
||||||
|
_GLFWcursor* cursor;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||||
|
|
||||||
|
cursor = calloc(1, sizeof(_GLFWcursor));
|
||||||
|
|
||||||
|
if (!_glfwPlatformCreateCursor(cursor, width, height, cx, cy, format, data))
|
||||||
|
{
|
||||||
|
free(cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->next = _glfw.cursorListHead;
|
||||||
|
_glfw.cursorListHead = cursor;
|
||||||
|
|
||||||
|
return (GLFWcursor*) cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
|
||||||
|
{
|
||||||
|
_GLFWcursor* cursor = (_GLFWcursor*) handle;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
if (cursor == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure the cursor is not being used by any window
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = _glfw.windowListHead;
|
||||||
|
|
||||||
|
while (window)
|
||||||
|
{
|
||||||
|
if (window->cursor == cursor)
|
||||||
|
glfwSetCursor((GLFWwindow*) window, NULL);
|
||||||
|
|
||||||
|
window = window->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_glfwPlatformDestroyCursor(cursor);
|
||||||
|
|
||||||
|
// Unlink cursor from global linked list
|
||||||
|
{
|
||||||
|
_GLFWcursor** prev = &_glfw.cursorListHead;
|
||||||
|
|
||||||
|
while (*prev != cursor)
|
||||||
|
prev = &((*prev)->next);
|
||||||
|
|
||||||
|
*prev = cursor->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
|
||||||
|
{
|
||||||
|
_GLFWwindow* window = (_GLFWwindow*) windowHandle;
|
||||||
|
_GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
|
||||||
|
|
||||||
|
_GLFW_REQUIRE_INIT();
|
||||||
|
|
||||||
|
_glfwPlatformSetCursor(window, cursor);
|
||||||
|
|
||||||
|
window->cursor = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
|
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
|
|
|
@ -65,6 +65,7 @@ typedef struct _GLFWfbconfig _GLFWfbconfig;
|
||||||
typedef struct _GLFWwindow _GLFWwindow;
|
typedef struct _GLFWwindow _GLFWwindow;
|
||||||
typedef struct _GLFWlibrary _GLFWlibrary;
|
typedef struct _GLFWlibrary _GLFWlibrary;
|
||||||
typedef struct _GLFWmonitor _GLFWmonitor;
|
typedef struct _GLFWmonitor _GLFWmonitor;
|
||||||
|
typedef struct _GLFWcursor _GLFWcursor;
|
||||||
|
|
||||||
#if defined(_GLFW_COCOA)
|
#if defined(_GLFW_COCOA)
|
||||||
#include "cocoa_platform.h"
|
#include "cocoa_platform.h"
|
||||||
|
@ -218,6 +219,7 @@ struct _GLFWwindow
|
||||||
void* userPointer;
|
void* userPointer;
|
||||||
GLFWvidmode videoMode;
|
GLFWvidmode videoMode;
|
||||||
_GLFWmonitor* monitor;
|
_GLFWmonitor* monitor;
|
||||||
|
_GLFWcursor* cursor;
|
||||||
|
|
||||||
// Window input state
|
// Window input state
|
||||||
GLboolean stickyKeys;
|
GLboolean stickyKeys;
|
||||||
|
@ -285,6 +287,17 @@ struct _GLFWmonitor
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*! @brief Cursor structure
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct _GLFWcursor
|
||||||
|
{
|
||||||
|
_GLFWcursor* next;
|
||||||
|
|
||||||
|
// This is defined in the window API's platform.h
|
||||||
|
_GLFW_PLATFORM_CURSOR_STATE;
|
||||||
|
};
|
||||||
|
|
||||||
/*! @brief Library global data.
|
/*! @brief Library global data.
|
||||||
*/
|
*/
|
||||||
struct _GLFWlibrary
|
struct _GLFWlibrary
|
||||||
|
@ -319,6 +332,8 @@ struct _GLFWlibrary
|
||||||
|
|
||||||
double cursorPosX, cursorPosY;
|
double cursorPosX, cursorPosY;
|
||||||
|
|
||||||
|
_GLFWcursor* cursorListHead;
|
||||||
|
|
||||||
_GLFWwindow* windowListHead;
|
_GLFWwindow* windowListHead;
|
||||||
_GLFWwindow* focusedWindow;
|
_GLFWwindow* focusedWindow;
|
||||||
|
|
||||||
|
@ -573,6 +588,12 @@ int _glfwPlatformExtensionSupported(const char* extension);
|
||||||
*/
|
*/
|
||||||
GLFWglproc _glfwPlatformGetProcAddress(const char* procname);
|
GLFWglproc _glfwPlatformGetProcAddress(const char* procname);
|
||||||
|
|
||||||
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int width, int height, int cx, int cy,
|
||||||
|
int format, const void* data);
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor);
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor);
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Event API functions
|
// Event API functions
|
||||||
|
|
|
@ -164,6 +164,7 @@ typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*);
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
@ -250,6 +251,15 @@ typedef struct _GLFWmonitorWin32
|
||||||
} _GLFWmonitorWin32;
|
} _GLFWmonitorWin32;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Platform-specific cursor structure
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
typedef struct _GLFWcursorWin32
|
||||||
|
{
|
||||||
|
HCURSOR handle;
|
||||||
|
} _GLFWcursorWin32;
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Prototypes for platform specific internal functions
|
// Prototypes for platform specific internal functions
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
|
@ -100,7 +100,12 @@ static void restoreCursor(_GLFWwindow* window)
|
||||||
if (GetCursorPos(&pos))
|
if (GetCursorPos(&pos))
|
||||||
{
|
{
|
||||||
if (WindowFromPoint(pos) == window->win32.handle)
|
if (WindowFromPoint(pos) == window->win32.handle)
|
||||||
SetCursor(LoadCursorW(NULL, IDC_ARROW));
|
{
|
||||||
|
if (window->cursor)
|
||||||
|
SetCursor(window->cursor->win32.handle);
|
||||||
|
else
|
||||||
|
SetCursor(LoadCursorW(NULL, IDC_ARROW));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,6 +725,11 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||||
SetCursor(NULL);
|
SetCursor(NULL);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
else if (window->cursor)
|
||||||
|
{
|
||||||
|
SetCursor(window->cursor->win32.handle);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1213,6 +1223,89 @@ void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int width, int height, int cx, int cy,
|
||||||
|
int format, const void* data)
|
||||||
|
{
|
||||||
|
HDC hdc;
|
||||||
|
HBITMAP hBitmap, hMonoBitmap;
|
||||||
|
BITMAPV5HEADER bi;
|
||||||
|
ICONINFO ii;
|
||||||
|
DWORD *buffer = 0;
|
||||||
|
BYTE *image = (BYTE*) data;
|
||||||
|
int i, size = width * height;
|
||||||
|
|
||||||
|
ZeroMemory(&bi, sizeof(BITMAPV5HEADER));
|
||||||
|
|
||||||
|
bi.bV5Size = sizeof(BITMAPV5HEADER);
|
||||||
|
bi.bV5Width = width;
|
||||||
|
bi.bV5Height = -height;
|
||||||
|
bi.bV5Planes = 1;
|
||||||
|
bi.bV5BitCount = 32;
|
||||||
|
bi.bV5Compression = BI_BITFIELDS;
|
||||||
|
bi.bV5RedMask = 0x00FF0000;
|
||||||
|
bi.bV5GreenMask = 0x0000FF00;
|
||||||
|
bi.bV5BlueMask = 0x000000FF;
|
||||||
|
bi.bV5AlphaMask = 0xFF000000;
|
||||||
|
|
||||||
|
hdc = GetDC(NULL);
|
||||||
|
|
||||||
|
hBitmap = CreateDIBSection(hdc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &buffer,
|
||||||
|
NULL, (DWORD) 0);
|
||||||
|
|
||||||
|
ReleaseDC(NULL, hdc);
|
||||||
|
|
||||||
|
if (hBitmap == NULL)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
hMonoBitmap = CreateBitmap(width, height, 1, 1, NULL);
|
||||||
|
|
||||||
|
if (hMonoBitmap == NULL)
|
||||||
|
{
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
return GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++, buffer++, image += 4)
|
||||||
|
*buffer = (image[3] << 24) | (image[0] << 16) | (image[1] << 8) | image[2];
|
||||||
|
|
||||||
|
ii.fIcon = FALSE;
|
||||||
|
ii.xHotspot = cx;
|
||||||
|
ii.yHotspot = cy;
|
||||||
|
ii.hbmMask = hMonoBitmap;
|
||||||
|
ii.hbmColor = hBitmap;
|
||||||
|
|
||||||
|
cursor->win32.handle = (HCURSOR) CreateIconIndirect(&ii);
|
||||||
|
|
||||||
|
DeleteObject(hBitmap);
|
||||||
|
DeleteObject(hMonoBitmap);
|
||||||
|
|
||||||
|
if (cursor->win32.handle == NULL)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
return GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
DestroyIcon((HICON) cursor->win32.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
// It should be guaranteed that the cursor is not being used by this window if
|
||||||
|
// the following condition is not met. That way it should be safe to destroy the
|
||||||
|
// cursor after calling glfwSetCursor(window, NULL) on all windows using the cursor.
|
||||||
|
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_NORMAL && _glfw.focusedWindow == window &&
|
||||||
|
window->win32.cursorInside)
|
||||||
|
{
|
||||||
|
if (cursor)
|
||||||
|
SetCursor(cursor->win32.handle);
|
||||||
|
else
|
||||||
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xcursor/Xcursor.h>
|
||||||
|
|
||||||
// The Xf86VidMode extension provides fallback gamma control
|
// The Xf86VidMode extension provides fallback gamma control
|
||||||
#include <X11/extensions/xf86vmode.h>
|
#include <X11/extensions/xf86vmode.h>
|
||||||
|
@ -62,6 +63,7 @@
|
||||||
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
||||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
||||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
||||||
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
@ -232,6 +234,15 @@ typedef struct _GLFWmonitorX11
|
||||||
} _GLFWmonitorX11;
|
} _GLFWmonitorX11;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
// Platform-specific cursor structure
|
||||||
|
//------------------------------------------------------------------------
|
||||||
|
typedef struct _GLFWcursorX11
|
||||||
|
{
|
||||||
|
Cursor handle;
|
||||||
|
} _GLFWcursorX11;
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Prototypes for platform specific internal functions
|
// Prototypes for platform specific internal functions
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
|
@ -394,7 +394,14 @@ static void disableCursor(_GLFWwindow* window)
|
||||||
static void restoreCursor(_GLFWwindow* window)
|
static void restoreCursor(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
||||||
XUndefineCursor(_glfw.x11.display, window->x11.handle);
|
|
||||||
|
if (window->cursor)
|
||||||
|
{
|
||||||
|
XDefineCursor(_glfw.x11.display, window->x11.handle,
|
||||||
|
window->cursor->x11.handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
XUndefineCursor(_glfw.x11.display, window->x11.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter fullscreen mode
|
// Enter fullscreen mode
|
||||||
|
@ -1349,6 +1356,55 @@ void _glfwPlatformApplyCursorMode(_GLFWwindow* window)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int width, int height, int cx, int cy,
|
||||||
|
int format, const void* data)
|
||||||
|
{
|
||||||
|
XcursorImage* cursorImage;
|
||||||
|
XcursorPixel* buffer;
|
||||||
|
unsigned char* image = (unsigned char*) data;
|
||||||
|
int i, size = width * height;
|
||||||
|
|
||||||
|
cursorImage = XcursorImageCreate(width, height);
|
||||||
|
|
||||||
|
if (cursorImage == NULL)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
cursorImage->xhot = cx;
|
||||||
|
cursorImage->yhot = cy;
|
||||||
|
|
||||||
|
buffer = cursorImage->pixels;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++, buffer++, image += 4)
|
||||||
|
*buffer = (image[3] << 24) | (image[0] << 16) | (image[1] << 8) | image[2];
|
||||||
|
|
||||||
|
cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, cursorImage);
|
||||||
|
|
||||||
|
XcursorImageDestroy(cursorImage);
|
||||||
|
|
||||||
|
if (cursor->x11.handle == None)
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
|
return GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
XFreeCursor(_glfw.x11.display, cursor->x11.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
|
||||||
|
{
|
||||||
|
if (window->cursorMode == GLFW_CURSOR_NORMAL)
|
||||||
|
{
|
||||||
|
if (cursor)
|
||||||
|
XDefineCursor(_glfw.x11.display, window->x11.handle, cursor->x11.handle);
|
||||||
|
else
|
||||||
|
XUndefineCursor(_glfw.x11.display, window->x11.handle);
|
||||||
|
|
||||||
|
XFlush(_glfw.x11.display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW native API //////
|
////// GLFW native API //////
|
||||||
|
|
|
@ -32,6 +32,10 @@ add_executable(joysticks joysticks.c)
|
||||||
add_executable(modes modes.c ${GETOPT})
|
add_executable(modes modes.c ${GETOPT})
|
||||||
add_executable(peter peter.c)
|
add_executable(peter peter.c)
|
||||||
add_executable(reopen reopen.c)
|
add_executable(reopen reopen.c)
|
||||||
|
add_executable(cursor cursor.c)
|
||||||
|
|
||||||
|
add_executable(cursoranim WIN32 MACOSX_BUNDLE cursoranim.c)
|
||||||
|
set_target_properties(cursoranim PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Cursor animation")
|
||||||
|
|
||||||
add_executable(accuracy WIN32 MACOSX_BUNDLE accuracy.c)
|
add_executable(accuracy WIN32 MACOSX_BUNDLE accuracy.c)
|
||||||
set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy")
|
set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy")
|
||||||
|
@ -57,9 +61,9 @@ set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows")
|
||||||
target_link_libraries(empty ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY})
|
target_link_libraries(empty ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY})
|
||||||
target_link_libraries(threads ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY})
|
target_link_libraries(threads ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY})
|
||||||
|
|
||||||
set(WINDOWS_BINARIES accuracy empty sharing tearing threads title windows)
|
set(WINDOWS_BINARIES accuracy empty sharing tearing threads title windows cursoranim)
|
||||||
set(CONSOLE_BINARIES clipboard defaults events fsaa gamma glfwinfo
|
set(CONSOLE_BINARIES clipboard defaults events fsaa gamma glfwinfo
|
||||||
iconify joysticks modes peter reopen)
|
iconify joysticks modes peter reopen cursor)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Tell MSVC to use main instead of WinMain for Windows subsystem executables
|
# Tell MSVC to use main instead of WinMain for Windows subsystem executables
|
||||||
|
|
283
tests/cursor.c
Normal file
283
tests/cursor.c
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
//========================================================================
|
||||||
|
// Cursor & input mode tests
|
||||||
|
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org>
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would
|
||||||
|
// be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not
|
||||||
|
// be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
//
|
||||||
|
// System cursors and input modes tests.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_GLU
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int W = 640;
|
||||||
|
static int H = 480;
|
||||||
|
static int delay = 0;
|
||||||
|
|
||||||
|
static GLFWwindow* windows[2] = {NULL, NULL};
|
||||||
|
static GLFWwindow* activeWindow = NULL;
|
||||||
|
static GLFWcursor* cursor = NULL;
|
||||||
|
|
||||||
|
static struct { int key; double time; } commands[] = {
|
||||||
|
{GLFW_KEY_H, 0},
|
||||||
|
{GLFW_KEY_C, 0},
|
||||||
|
{GLFW_KEY_D, 0},
|
||||||
|
{GLFW_KEY_S, 0},
|
||||||
|
{GLFW_KEY_N, 0},
|
||||||
|
{GLFW_KEY_1, 0},
|
||||||
|
{GLFW_KEY_2, 0},
|
||||||
|
{GLFW_KEY_3, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CommandCount = sizeof(commands) / sizeof(commands[0]);
|
||||||
|
|
||||||
|
static struct { int w, h; } cursorSize[] = {
|
||||||
|
{24, 24}, {13, 37}, {5, 53}, {43, 64}, {300, 300}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int SizeCount = sizeof(cursorSize) / sizeof(cursorSize[0]);
|
||||||
|
static int currentSize = 0;
|
||||||
|
|
||||||
|
static void command_callback(int key)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_H:
|
||||||
|
{
|
||||||
|
printf("H: show this help\n");
|
||||||
|
printf("C: call glfwCreateCursor()\n");
|
||||||
|
printf("D: call glfwDestroyCursor()\n");
|
||||||
|
printf("S: call glfwSetCursor()\n");
|
||||||
|
printf("N: call glfwSetCursor() with NULL\n");
|
||||||
|
printf("1: set GLFW_CURSOR_NORMAL\n");
|
||||||
|
printf("2: set GLFW_CURSOR_HIDDEN\n");
|
||||||
|
printf("3: set GLFW_CURSOR_DISABLED\n");
|
||||||
|
printf("T: enable 3s delay for all previous commands\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_C:
|
||||||
|
{
|
||||||
|
if (cursor == NULL)
|
||||||
|
{
|
||||||
|
int w = cursorSize[currentSize].w;
|
||||||
|
int h = cursorSize[currentSize].h;
|
||||||
|
int x, y, i = 0;
|
||||||
|
unsigned char *image = malloc(4 * w * h);
|
||||||
|
|
||||||
|
for (y = 0; y < h; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
image[i++] = 0xFF;
|
||||||
|
image[i++] = 0;
|
||||||
|
image[i++] = 255 * y / h;
|
||||||
|
image[i++] = 255 * x / w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = glfwCreateCursor(w, h, w / 2, h / 2, 0, image);
|
||||||
|
currentSize = (currentSize + 1) % SizeCount;
|
||||||
|
free(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_D:
|
||||||
|
{
|
||||||
|
if (cursor != NULL)
|
||||||
|
{
|
||||||
|
glfwDestroyCursor(cursor);
|
||||||
|
cursor = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_S:
|
||||||
|
{
|
||||||
|
if (cursor != NULL)
|
||||||
|
glfwSetCursor(activeWindow, cursor);
|
||||||
|
else
|
||||||
|
printf("The cursor is not created\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_N:
|
||||||
|
{
|
||||||
|
glfwSetCursor(activeWindow, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_1:
|
||||||
|
{
|
||||||
|
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_2:
|
||||||
|
{
|
||||||
|
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_3:
|
||||||
|
{
|
||||||
|
glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_callback(int error, const char* description)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
W = width;
|
||||||
|
H = height;
|
||||||
|
|
||||||
|
glViewport(0, 0, W, H);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_callback(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
glClearColor(0.0f, window == activeWindow ? 0.8f : 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||||
|
{
|
||||||
|
if (action != GLFW_PRESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_ESCAPE:
|
||||||
|
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW_KEY_T:
|
||||||
|
delay = !delay;
|
||||||
|
printf("Delay %s.\n", delay ? "enabled" : "disabled");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (delay)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < CommandCount && commands[i].key != key)
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i < CommandCount)
|
||||||
|
commands[i].time = glfwGetTime();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
command_callback(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void focus_callback(GLFWwindow* window, int focused)
|
||||||
|
{
|
||||||
|
if (focused)
|
||||||
|
{
|
||||||
|
activeWindow = window;
|
||||||
|
refresh_callback(windows[0]);
|
||||||
|
refresh_callback(windows[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GLboolean running = GL_TRUE;
|
||||||
|
|
||||||
|
glfwSetErrorCallback(error_callback);
|
||||||
|
|
||||||
|
if (!glfwInit())
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
windows[i] = glfwCreateWindow(W, H, "Cursor testing", NULL, NULL);
|
||||||
|
|
||||||
|
if (!windows[i])
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetWindowPos(windows[i], 100 + (i & 1) * (W + 50), 100);
|
||||||
|
|
||||||
|
glfwSetWindowRefreshCallback(windows[i], refresh_callback);
|
||||||
|
glfwSetFramebufferSizeCallback(windows[i], framebuffer_size_callback);
|
||||||
|
glfwSetKeyCallback(windows[i], key_callback);
|
||||||
|
glfwSetWindowFocusCallback(windows[i], focus_callback);
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(windows[i]);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glfwSwapBuffers(windows[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeWindow = windows[0];
|
||||||
|
|
||||||
|
key_callback(NULL, GLFW_KEY_H, 0, GLFW_PRESS, 0);
|
||||||
|
|
||||||
|
while (running)
|
||||||
|
{
|
||||||
|
if (delay)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double t = glfwGetTime();
|
||||||
|
|
||||||
|
for (i = 0; i < CommandCount; i++)
|
||||||
|
{
|
||||||
|
if (commands[i].time != 0 && t - commands[i].time >= 3.0)
|
||||||
|
{
|
||||||
|
command_callback(commands[i].key);
|
||||||
|
commands[i].time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
running = !(glfwWindowShouldClose(windows[0]) || glfwWindowShouldClose(windows[1]));
|
||||||
|
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
133
tests/cursoranim.c
Normal file
133
tests/cursoranim.c
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
//========================================================================
|
||||||
|
// Cursor animation
|
||||||
|
// Copyright (c) Camilla Berglund <elmindreda@elmindreda.org>
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would
|
||||||
|
// be appreciated but is not required.
|
||||||
|
//
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not
|
||||||
|
// be misrepresented as being the original software.
|
||||||
|
//
|
||||||
|
// 3. This notice may not be removed or altered from any source
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
//
|
||||||
|
// Cursor animation test.
|
||||||
|
//
|
||||||
|
//========================================================================
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef min
|
||||||
|
#undef min
|
||||||
|
#endif
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZE 64 // cursor size (width & height)
|
||||||
|
#define N 60 // number of frames
|
||||||
|
|
||||||
|
unsigned char buffer[4 * SIZE * SIZE];
|
||||||
|
|
||||||
|
static float max(float a, float b) { return a > b ? a : b; }
|
||||||
|
static float min(float a, float b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
static float star(int x, int y, float t)
|
||||||
|
{
|
||||||
|
float c = SIZE / 2.0f;
|
||||||
|
|
||||||
|
float i = (0.25f * (float)sin(2.0f * 3.1415926f * t) + 0.75f);
|
||||||
|
float k = SIZE * 0.046875f * i;
|
||||||
|
|
||||||
|
float dist = (float)sqrt((x - c) * (x - c) + (y - c) * (y - c));
|
||||||
|
|
||||||
|
float salpha = 1.0f - dist / c;
|
||||||
|
float xalpha = (float)x == c ? c : k / (float)fabs(x - c);
|
||||||
|
float yalpha = (float)y == c ? c : k / (float)fabs(y - c);
|
||||||
|
|
||||||
|
return max(0.0f, min(1.0f, i * salpha * 0.2f + salpha * xalpha * yalpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLFWcursor* load_frame(float t)
|
||||||
|
{
|
||||||
|
int i = 0, x, y;
|
||||||
|
|
||||||
|
for (y = 0; y < SIZE; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < SIZE; x++)
|
||||||
|
{
|
||||||
|
buffer[i++] = 255;
|
||||||
|
buffer[i++] = 255;
|
||||||
|
buffer[i++] = 255;
|
||||||
|
buffer[i++] = (unsigned char)(255 * star(x, y, t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return glfwCreateCursor(SIZE, SIZE, SIZE / 2, SIZE / 2, 0, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double t0, t1, frameTime = 0.0;
|
||||||
|
|
||||||
|
GLFWwindow* window;
|
||||||
|
GLFWcursor* frames[N];
|
||||||
|
|
||||||
|
if (!glfwInit())
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
window = glfwCreateWindow(640, 480, "Cursor animation", NULL, NULL);
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
glfwSwapInterval(1);
|
||||||
|
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
frames[i] = load_frame(i / (float)N);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
t0 = glfwGetTime();
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(window))
|
||||||
|
{
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glfwSetCursor(window, frames[i]);
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
t1 = glfwGetTime();
|
||||||
|
frameTime += t1 - t0;
|
||||||
|
t0 = t1;
|
||||||
|
|
||||||
|
while (frameTime > 1.0 / (double)N)
|
||||||
|
{
|
||||||
|
i = (i + 1) % N;
|
||||||
|
frameTime -= 1.0 / (double)N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user