WIP: add GameCube & Wii support

This commit is contained in:
Alberto Mardegan 2024-12-31 16:21:31 +03:00 committed by Alberto Mardegan
parent bc0d63cf82
commit 7c224bcd71
24 changed files with 2937 additions and 9 deletions

View File

@ -24,8 +24,15 @@ if (DEFINED GLFW_USE_WAYLAND AND UNIX AND NOT APPLE)
"GLFW_USE_WAYLAND has been removed; delete the CMake cache and set GLFW_BUILD_WAYLAND and GLFW_BUILD_X11 instead")
endif()
IF(CMAKE_SYSTEM_NAME MATCHES "NintendoWii|NintendoGameCube")
SET(OGC ON)
ELSE()
SET(OGC OFF)
ENDIF()
cmake_dependent_option(GLFW_BUILD_WIN32 "Build support for Win32" ON "WIN32" OFF)
cmake_dependent_option(GLFW_BUILD_COCOA "Build support for Cocoa" ON "APPLE" OFF)
cmake_dependent_option(GLFW_BUILD_OGC "Build support for Nintendo GameCube/Wii" ON "OGC" OFF)
cmake_dependent_option(GLFW_BUILD_X11 "Build support for X11" ON "UNIX;NOT APPLE" OFF)
cmake_dependent_option(GLFW_BUILD_WAYLAND "Build support for Wayland" ON "UNIX;NOT APPLE" OFF)
@ -49,7 +56,7 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
find_package(Threads REQUIRED)
find_package(Threads)
#--------------------------------------------------------------------
# Report backend selection

28
deps/tinycthread.c vendored
View File

@ -40,6 +40,8 @@ freely, subject to the following restrictions:
#elif defined(_TTHREAD_WIN32_)
#include <process.h>
#include <sys/timeb.h>
#elif defined(_TTHREAD_OGC_)
#include <ogcsys.h>
#endif
/* Standard, good-to-have defines */
@ -60,6 +62,8 @@ int mtx_init(mtx_t *mtx, int type)
mtx->mRecursive = type & mtx_recursive;
InitializeCriticalSection(&mtx->mHandle);
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
int ret;
pthread_mutexattr_t attr;
@ -78,6 +82,7 @@ void mtx_destroy(mtx_t *mtx)
{
#if defined(_TTHREAD_WIN32_)
DeleteCriticalSection(&mtx->mHandle);
#elif defined(_TTHREAD_OGC_)
#else
pthread_mutex_destroy(mtx);
#endif
@ -93,6 +98,8 @@ int mtx_lock(mtx_t *mtx)
mtx->mAlreadyLocked = TRUE;
}
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error;
#endif
@ -116,6 +123,8 @@ int mtx_trylock(mtx_t *mtx)
ret = thrd_busy;
}
return ret;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
#endif
@ -127,6 +136,8 @@ int mtx_unlock(mtx_t *mtx)
mtx->mAlreadyLocked = FALSE;
LeaveCriticalSection(&mtx->mHandle);
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;;
#endif
@ -161,6 +172,8 @@ int cnd_init(cnd_t *cond)
}
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error;
#endif
@ -178,6 +191,7 @@ void cnd_destroy(cnd_t *cond)
CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]);
}
DeleteCriticalSection(&cond->mWaitersCountLock);
#elif defined(_TTHREAD_OGC_)
#else
pthread_cond_destroy(cond);
#endif
@ -203,6 +217,8 @@ int cnd_signal(cnd_t *cond)
}
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
#endif
@ -228,6 +244,8 @@ int cnd_broadcast(cnd_t *cond)
}
return thrd_success;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error;
#endif
@ -286,6 +304,8 @@ int cnd_wait(cnd_t *cond, mtx_t *mtx)
{
#if defined(_TTHREAD_WIN32_)
return _cnd_timedwait_win32(cond, mtx, INFINITE);
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error;
#endif
@ -303,6 +323,8 @@ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
}
else
return thrd_error;
#elif defined(_TTHREAD_OGC_)
return thrd_error;
#else
int ret;
ret = pthread_cond_timedwait(cond, mtx, ts);
@ -324,14 +346,14 @@ typedef struct {
/* Thread wrapper function. */
#if defined(_TTHREAD_WIN32_)
static unsigned WINAPI _thrd_wrapper_function(void * aArg)
#elif defined(_TTHREAD_POSIX_)
#else
static void * _thrd_wrapper_function(void * aArg)
#endif
{
thrd_start_t fun;
void *arg;
int res;
#if defined(_TTHREAD_POSIX_)
#if defined(_TTHREAD_POSIX_) || defined(_TTHREAD_OGC_)
void *pres;
#endif
@ -394,6 +416,8 @@ thrd_t thrd_current(void)
{
#if defined(_TTHREAD_WIN32_)
return GetCurrentThread();
#elif defined(_TTHREAD_OGC_)
return LWP_GetSelf();
#else
return pthread_self();
#endif

6
deps/tinycthread.h vendored
View File

@ -51,6 +51,8 @@ freely, subject to the following restrictions:
#if !defined(_TTHREAD_PLATFORM_DEFINED_)
#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
#define _TTHREAD_WIN32_
#elif defined(GEKKO)
#define _TTHREAD_OGC_
#else
#define _TTHREAD_POSIX_
#endif
@ -80,6 +82,8 @@ freely, subject to the following restrictions:
#if defined(_TTHREAD_POSIX_)
#include <sys/time.h>
#include <pthread.h>
#elif defined(_TTHREAD_OGC_)
#include <ogcsys.h>
#elif defined(_TTHREAD_WIN32_)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
@ -313,6 +317,8 @@ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts);
/* Thread */
#if defined(_TTHREAD_WIN32_)
typedef HANDLE thrd_t;
#elif defined(_TTHREAD_OGC_)
typedef lwp_t thrd_t;
#else
typedef pthread_t thrd_t;
#endif

View File

@ -37,7 +37,9 @@ add_executable(triangle-opengles WIN32 MACOSX_BUNDLE triangle-opengles.c ${ICON}
add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL})
add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${ICON} ${GLAD_GL})
target_link_libraries(particles Threads::Threads)
if (Threads_FOUND)
target_link_libraries(particles Threads::Threads)
endif()
if (RT_LIBRARY)
target_link_libraries(particles "${RT_LIBRARY}")
endif()

View File

@ -1342,6 +1342,7 @@ extern "C" {
#define GLFW_PLATFORM_WAYLAND 0x00060003
#define GLFW_PLATFORM_X11 0x00060004
#define GLFW_PLATFORM_NULL 0x00060005
#define GLFW_PLATFORM_OGC 0x00060006
/*! @} */
#define GLFW_DONT_CARE -1

View File

@ -15,6 +15,9 @@ if (APPLE)
elseif (WIN32)
target_sources(glfw PRIVATE win32_time.h win32_thread.h win32_module.c
win32_time.c win32_thread.c)
elseif (OGC)
target_sources(glfw PRIVATE ogc_time.h ogc_thread.h ogc_module.c
ogc_time.c ogc_thread.c)
else()
target_sources(glfw PRIVATE posix_time.h posix_thread.h posix_module.c
posix_time.c posix_thread.c)
@ -57,6 +60,13 @@ if (GLFW_BUILD_WAYLAND)
wl_monitor.c wl_window.c)
endif()
if (GLFW_BUILD_OGC)
target_compile_definitions(glfw PRIVATE _GLFW_OGC)
target_sources(glfw PRIVATE ogc_platform.h ogc_init.c ogc_joystick.c
ogc_monitor.c ogc_window.c ogc_context.c
ogc_cursor.h)
endif()
if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)
@ -136,7 +146,9 @@ target_include_directories(glfw PUBLIC
target_include_directories(glfw PRIVATE
"${GLFW_SOURCE_DIR}/src"
"${GLFW_BINARY_DIR}/src")
target_link_libraries(glfw PRIVATE Threads::Threads)
if (Threads_FOUND)
target_link_libraries(glfw PRIVATE Threads::Threads)
endif()
if (GLFW_BUILD_WIN32)
list(APPEND glfw_PKG_LIBS "-lgdi32")
@ -213,6 +225,13 @@ if (GLFW_BUILD_X11)
target_include_directories(glfw PRIVATE "${X11_Xshape_INCLUDE_PATH}")
endif()
if (GLFW_BUILD_OGC)
include(FindPkgConfig)
pkg_check_modules(Opengx REQUIRED IMPORTED_TARGET opengl)
target_link_libraries(glfw PRIVATE PkgConfig::Opengx wiikeyboard fat)
endif()
if (UNIX AND NOT APPLE)
find_library(RT_LIBRARY rt)
mark_as_advanced(RT_LIBRARY)

View File

@ -997,5 +997,13 @@ const char* _glfwDefaultMappings[] =
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
#endif // GLFW_BUILD_LINUX_JOYSTICK
#if defined(_GLFW_OGC)
"05002bf87e0500000105000001000000,Nintendo Wiimote 1,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
"0500ea387e0500000106000001000000,Nintendo Wiimote 2,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
"0500aa397e0500000107000001000000,Nintendo Wiimote 3,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
"05006bf97e0500000108000001000000,Nintendo Wiimote 4,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
"0500b98e7e0500000305000001000000,Nintendo Wii Classic 1,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
#endif
};

View File

@ -78,5 +78,9 @@ const char* _glfwDefaultMappings[] =
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
@GLFW_LINUX_MAPPINGS@
#endif // GLFW_BUILD_LINUX_JOYSTICK
#if defined(_GLFW_OGC)
"05002bf87e0500000105000001000000,Nintendo Wiimote,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b4,start:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Ogc,",
#endif
};

204
src/ogc_context.c Normal file
View File

@ -0,0 +1,204 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <opengx.h>
#ifdef __wii__
#include <wiiuse/wpad.h>
#endif
#ifdef __wii__
static void drawCursorRect(_GLFWcursor* cursor)
{
short xhot = cursor->ogc.xhot;
short yhot = cursor->ogc.yhot;
u16 width = GX_GetTexObjWidth(&cursor->ogc.texobj);
u16 height = GX_GetTexObjHeight(&cursor->ogc.texobj);
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
GX_Position2s16(-xhot, -yhot);
GX_TexCoord2u8(0, 0);
GX_Position2s16(width - xhot, -yhot);
GX_TexCoord2u8(1, 0);
GX_Position2s16(width - xhot, height - yhot);
GX_TexCoord2u8(1, 1);
GX_Position2s16(-xhot, height - yhot);
GX_TexCoord2u8(0, 1);
GX_End();
}
static void drawCursor(_GLFWwindow* window)
{
Mtx44 proj;
Mtx mv;
_GLFWcursor* cursor = window->ogc.currentCursor;
if (!cursor) return;
GX_LoadTexObj(&cursor->ogc.texobj, GX_TEXMAP0);
int width = window->ogc.width;
int height = window->ogc.height;
guOrtho(proj, 0, height, 0, width, 0, 1);
GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC);
guMtxIdentity(mv);
guMtxScaleApply(mv, mv,
width / 640.0f,
height / 480.0f, 1.0f);
if (cursor->ogc.canRotate) {
Mtx rot;
float angle;
WPADData *data = WPAD_Data(0);
angle = data->ir.angle;
guMtxRotDeg(rot, 'z', angle);
guMtxConcat(mv, rot, mv);
}
guMtxTransApply(mv, mv,
window->virtualCursorPosX,
window->virtualCursorPosY, 0);
GX_LoadPosMtxImm(mv, GX_PNMTX1);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0);
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GX_SetNumTevStages(1);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetNumTexGens(1);
GX_SetCurrentMtx(GX_PNMTX1);
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
GX_SetScissor(0, 0, width, height);
drawCursorRect(cursor);
GX_SetCurrentMtx(GX_PNMTX0);
GX_DrawDone();
}
#endif // __wii__
static void makeContextCurrentOgc(_GLFWwindow* window)
{
_glfwPlatformSetTls(&_glfw.contextSlot, window);
}
static GLFWglproc getProcAddressOgc(const char* procname)
{
return (GLFWglproc) ogx_get_proc_address(procname);
}
static void destroyContextOgc(_GLFWwindow* window)
{
}
static void swapBuffersOgc(_GLFWwindow* window)
{
void *xfb;
u8 mustClear, mustWait;
if (ogx_prepare_swap_buffers() < 0) return;
#ifdef __wii__
if (window->ogc.hovered &&
(window->callbacks.mouseButton || window->callbacks.cursorPos))
drawCursor(window);
#endif // __wii__
if (window->doublebuffer) {
mustClear = GX_TRUE;
mustWait = GX_TRUE;
xfb = _glfw.ogc.xfb[_glfw.ogc.fbIndex];
_glfw.ogc.fbIndex ^= 1;
} else {
mustClear = GX_FALSE;
mustWait = GX_FALSE;
xfb = _glfw.ogc.xfb[0];
}
GX_CopyDisp(xfb, mustClear);
GX_DrawDone();
GX_Flush();
VIDEO_SetNextFramebuffer(xfb);
VIDEO_Flush();
if (mustWait)
VIDEO_WaitVSync();
}
static void swapIntervalOgc(int interval)
{
// No swap interval on Ogc
}
static int extensionSupportedOgc(const char* extension)
{
const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
return strstr(extensions, extensions) != NULL;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwCreateContextOgc(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Ogc: OpenGL ES is not available on Ogc");
return GLFW_FALSE;
}
ogx_enable_double_buffering(fbconfig->doublebuffer);
if (fbconfig->stencilBits > 0) {
OgxStencilFlags stencilFlags = OGX_STENCIL_NONE;
if (fbconfig->stencilBits > 4) stencilFlags |= OGX_STENCIL_8BIT;
ogx_stencil_create(stencilFlags);
}
window->context.makeCurrent = makeContextCurrentOgc;
window->context.swapBuffers = swapBuffersOgc;
window->context.swapInterval = swapIntervalOgc;
window->context.extensionSupported = extensionSupportedOgc;
window->context.getProcAddress = getProcAddressOgc;
window->context.destroy = destroyContextOgc;
return GLFW_TRUE;
}

487
src/ogc_cursor.h Normal file
View File

@ -0,0 +1,487 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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 <gctypes.h>
typedef struct {
u16 width;
u16 height;
u8 hot_x;
u8 hot_y;
u8 bytes_per_pixel;
u8 pixel_data[];
} _GLFWcursorDataOgc;
static const _GLFWcursorDataOgc OGC_cursor_hand = {
37, 52, 11, 0, 4,
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000Q\000"
"\000\000\262\000\000\000\337\000\000\000\345\000\000\000\313\000\000\000\203\000\000\000\032\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\005"
"\000\000\000\224\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000"
"\000\000\330\000\000\000\062\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\177\000\000\000\377\000\000\000\377\026\026\026\377bbb\377ttt\377"
"<<<\377\000\000\000\377\000\000\000\377\000\000\000\334\000\000\000\030\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000%\000\000\000\364\000\000\000\377...\377\327\327"
"\327\377\377\377\377\377\377\377\377\377\373\373\373\377\177\177\177\377"
"\000\000\000\377\000\000\000\377\000\000\000\206\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000n\000\000\000\377\005\005\005\377\277\277\277\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377BBB\377\000"
"\000\000\377\000\000\000\323\000\000\000\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\225\000\000\000\377###\377\366\366\366\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\206\206\206\377\000\000"
"\000\377\000\000\000\356\000\000\000\033\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\231\000\000\000\377+++\377\370\370\370\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\217\217\217\377\000\000\000\377"
"\000\000\000\361\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\230\000\000\000\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000"
"\000\000\360\000\000\000\037\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230"
"\000\000\000\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000"
"\360\000\000\000\037\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000"
"\000\000\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\360"
"\000\000\000\037\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000"
"\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\360\000\000"
"\000\037\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377"
"***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\360\000\000\000\037"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377***\377"
"\367\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\360\000\000\000\037\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377***\377\367"
"\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\357\000\000\000\026\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377***\377\367\367"
"\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\370\000\000\000\244\000\000\000\223"
"\000\000\000e\000\000\000\032\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377***\377\367\367"
"\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\215\215\215\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
"\000\000\000\377\000\000\000\340\000\000\000Z\000\000\000\000\000\000\000\003\000\000\000\022\000\000\000\006\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000\377***\377\367"
"\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\215\215\215\377\000\000\000\377\001\001\001\377%%%\377\036\036\036"
"\377\000\000\000\377\000\000\000\377\000\000\000\373\000\000\000\244\000\000\000\310\000\000\000\341\000\000\000\320"
"\000\000\000\220\000\000\000*\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\230\000\000\000"
"\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\210\210\210\377\022\022\022\377\270\270\270"
"\377\356\356\356\377\351\351\351\377\236\236\236\377\022\022\022\377\000\000\000\377"
"\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\357\000\000\000[\000\000\000"
"\030\000\000\000<\000\000\000B\000\000\000(\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\227\000\000\000\377***\377\367\367\367\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\202\202\202\377\065\065\065\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\246\246\246\377\001\001\001\377\003\003\003\377@@@\377iii\377DD"
"D\377\002\002\002\377\000\000\000\377\000\000\000\372\000\000\000\342\000\000\000\375\000\000\000\377\000\000\000\360"
"\000\000\000\264\000\000\000:\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\233\000\000\000\377***\377\367\367\367\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\203\203\203\377\061\061\061"
"\377\375\375\375\377\377\377\377\377\377\377\377\377\377\377\377\377\372"
"\372\372\377\036\036\036\377kkk\377\375\375\375\377\377\377\377\377\377\377"
"\377\377\253\253\253\377\015\015\015\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000"
"\377\000\000\000\377\000\000\000\377\000\000\000\366\000\000\000U\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016"
"\000\000\000n\000\000\000\272\000\000\000\360\000\000\000\377***\377\367\367\367\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\203"
"\203\203\377\061\061\061\377\375\375\375\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\376\376\376\377\063\063\063\377\211\211\211\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\177\177\177\377\000\000"
"\000\377AAA\377\236\236\236\377\256\256\256\377lll\377\011\011\011\377\000\000\000\377"
"\000\000\000\360\000\000\000)\000\000\000\000\000\000\000!\000\000\000\304\000\000\000\377\000\000\000\377\000\000\000\377"
"\000\000\000\377***\377\367\367\367\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\203\203\203\377\061\061\061\377\375"
"\375\375\377\377\377\377\377\377\377\377\377\377\377\377\377\375\375\375"
"\377\061\061\061\377\203\203\203\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\304\304\304\377\011\011\011\377\327\327\327\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\247\247\247\377\006\006\006\377\000"
"\000\000\377\000\000\000\225\000\000\000\016\000\000\000\312\000\000\000\377\000\000\000\377(((\377aaa\377\067"
"\067\067\377'''\377\366\366\366\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\203\203\203\377\061\061\061\377\375"
"\375\375\377\377\377\377\377\377\377\377\377\377\377\377\377\375\375\375"
"\377\061\061\061\377\203\203\203\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\313\313\313\377\015\015\015\377\323\323\323\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377NNN\377\000\000\000"
"\377\000\000\000\324\000\000\000s\000\000\000\377\000\000\000\377fff\377\357\357\357\377\377\377"
"\377\377\244\244\244\377###\377\365\365\365\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377|||\377&&&\377\375\375"
"\375\377\377\377\377\377\377\377\377\377\377\377\377\377\375\375\375\377"
"&&&\377|||\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\306\306\306\377\001\001\001\377\317\317\317\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\200\200\200\377\000\000\000\377\000\000\000\345"
"\000\000\000\305\000\000\000\377\062\062\062\377\371\371\371\377\377\377\377\377\377\377"
"\377\377\235\235\235\377###\377\365\365\365\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\274\274\274\377\221"
"\221\221\377\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\376\376\376\377\221\221\221\377\274\274\274\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\342\342\340\377\200\200\200"
"\377\347\347\347\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\202\202\202\377\000\000\000\377\000\000\000\345\000\000\000\342\000\000\000\377www\377"
"\377\377\377\377\376\376\376\377\377\377\377\377\235\235\235\377!##\377\365"
"\365\365\377\377\377\377\377\374\376\376\377\374\376\376\377\374\376\376"
"\377\374\376\376\377\377\377\377\377\377\377\377\377\374\376\376\377\374"
"\376\376\377\374\376\376\377\374\376\376\377\374\376\376\377\377\377\377"
"\377\377\377\377\377\374\376\376\377\374\376\376\377\374\376\376\377\374"
"\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377\374\376\376"
"\377\374\376\376\377\374\376\376\377\377\377\377\377\201\201\201\377\000\000"
"\000\377\000\000\000\345\000\000\000\346\000\000\000\377\203\203\203\377\377\377\377\377\375"
"\373\375\377\377\377\377\377\233\233\235\377!!#\377\363\363\365\377\377\377"
"\377\377\373\373\376\377\373\373\376\377\373\373\376\377\373\373\376\377"
"\373\373\376\377\373\373\376\377\373\373\376\377\373\373\375\377\373\373"
"\376\377\373\373\376\377\373\373\376\377\373\373\375\377\373\373\376\377"
"\373\373\376\377\373\373\376\377\373\373\376\377\373\373\376\377\373\373"
"\376\377\373\373\375\377\373\373\375\377\373\373\375\377\373\373\376\377"
"\373\374\376\377\377\377\377\377\201\201\201\377\000\000\000\377\000\000\000\345\000\000"
"\000\345\000\000\000\377\177\201\201\377\377\377\377\377\371\373\376\377\377\377"
"\377\377\233\233\235\377\"\"\"\377\361\363\366\377\375\377\377\377\371\373"
"\376\377\371\373\376\377\371\373\376\377\367\372\376\377\367\372\376\377"
"\371\371\376\377\371\371\376\377\371\373\376\377\371\373\376\377\371\373"
"\376\377\371\373\376\377\367\372\376\377\367\372\376\377\371\373\376\377"
"\367\372\376\377\367\372\376\377\371\373\376\377\367\372\376\377\371\373"
"\376\377\371\373\376\377\367\372\376\377\367\372\376\377\371\373\376\377"
"\377\377\377\377\177\201\201\377\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377"
"\177\177\201\377\377\377\377\377\365\370\377\377\377\377\377\377\234\234"
"\234\377\"\"\"\377\356\361\365\377\372\375\377\377\365\370\375\377\365\370"
"\375\377\365\370\375\377\365\370\375\377\365\370\375\377\365\370\375\377"
"\365\370\375\377\365\370\375\377\365\370\375\377\365\370\375\377\365\370"
"\375\377\365\370\375\377\365\370\375\377\365\370\375\377\365\370\375\377"
"\365\370\375\377\365\370\375\377\365\370\375\377\365\370\375\377\365\370"
"\375\377\365\370\375\377\365\370\375\377\366\371\376\377\377\377\377\377"
"\177\177\201\377\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377}\200\202\377\377"
"\377\377\377\363\366\375\377\377\377\377\377\232\234\234\377\"\"\"\377\355"
"\357\364\377\370\372\377\377\363\366\375\377\363\366\375\377\363\366\375"
"\377\363\366\375\377\363\366\375\377\363\366\375\377\363\366\375\377\363"
"\366\375\377\363\366\375\377\363\366\375\377\363\366\375\377\363\366\375"
"\377\363\366\375\377\363\366\375\377\363\366\375\377\363\366\375\377\363"
"\366\375\377\363\366\375\377\363\366\375\377\363\366\375\377\363\366\375"
"\377\363\366\375\377\364\367\376\377\377\377\377\377~\177\201\377\000\000\000\377"
"\000\000\000\345\000\000\000\345\000\000\000\377|~\201\377\377\377\377\377\357\362\374\377"
"\377\377\377\377\231\232\234\377\"\"\"\377\352\355\364\377\364\370\377\377"
"\357\362\374\377\357\364\374\377\357\364\374\377\357\364\374\377\357\362"
"\374\377\357\364\374\377\357\364\374\377\357\364\374\377\357\364\374\377"
"\357\362\374\377\357\364\374\377\357\364\374\377\357\364\374\377\357\364"
"\374\377\357\364\374\377\357\364\374\377\357\364\374\377\357\364\374\377"
"\357\364\374\377\357\364\374\377\357\362\374\377\357\364\374\377\360\363"
"\375\377\377\377\377\377|~\201\377\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377"
"z|\201\377\377\377\377\377\353\360\374\377\375\377\377\377\230\232\235\377"
"\"\"\"\377\347\352\364\377\360\364\377\377\353\360\374\377\355\360\374\377"
"\355\360\374\377\355\360\374\377\353\360\374\377\355\360\374\377\353\360"
"\374\377\353\360\374\377\353\360\374\377\355\360\374\377\355\360\374\377"
"\355\360\374\377\355\362\374\377\355\360\374\377\353\360\374\377\353\360"
"\374\377\355\360\374\377\353\360\374\377\355\360\374\377\355\360\374\377"
"\355\360\374\377\353\360\374\377\355\362\374\377\377\377\377\377z|\201\377"
"\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377y{\201\377\377\377\377\377\351\356"
"\372\377\373\377\377\377\220\223\230\377\026\026\026\377\344\351\363\377\353"
"\362\377\377\350\357\374\377\350\357\372\377\350\357\372\377\350\357\374"
"\377\350\357\374\377\350\357\372\377\350\357\374\377\350\357\372\377\350"
"\357\372\377\350\357\374\377\350\357\374\377\350\357\374\377\350\357\372"
"\377\350\357\372\377\350\357\372\377\350\357\374\377\350\357\374\377\350"
"\357\372\377\350\357\372\377\350\357\372\377\350\357\372\377\350\357\372"
"\377\351\360\373\377\377\377\377\377y{\201\377\000\000\000\377\000\000\000\345\000\000\000"
"\345\000\000\000\377xz\200\377\375\377\377\377\346\354\373\377\352\362\376\377"
"\304\313\325\377\226\233\243\377\343\353\370\377\345\355\374\377\345\355"
"\372\377\345\355\372\377\345\353\372\377\345\353\372\377\345\355\372\377"
"\345\355\372\377\345\353\372\377\345\353\372\377\345\353\372\377\345\355"
"\372\377\345\355\372\377\345\353\372\377\345\353\372\377\345\353\372\377"
"\345\353\372\377\345\353\372\377\345\353\372\377\345\353\372\377\345\353"
"\372\377\345\353\372\377\345\353\372\377\345\353\372\377\344\354\373\377"
"\375\377\377\377xz\200\377\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377ux\201"
"\377\373\377\377\377\342\352\373\377\340\350\371\377\350\360\377\377\362"
"\370\377\377\341\351\373\377\341\351\372\377\341\351\372\377\341\351\372"
"\377\341\351\372\377\341\351\372\377\341\351\372\377\341\351\372\377\341"
"\351\372\377\341\351\372\377\341\351\372\377\341\351\372\377\341\351\372"
"\377\341\351\372\377\341\351\372\377\341\351\372\377\341\351\372\377\341"
"\351\372\377\341\351\372\377\341\351\372\377\341\351\372\377\341\351\372"
"\377\341\351\372\377\341\351\372\377\342\352\373\377\373\377\377\377ux\201"
"\377\000\000\000\377\000\000\000\345\000\000\000\345\000\000\000\377ty\200\377\367\375\377\377\336"
"\346\372\377\334\346\372\377\334\346\372\377\334\346\370\377\335\345\371"
"\377\335\345\371\377\335\345\371\377\335\345\371\377\335\345\371\377\335"
"\345\371\377\335\345\371\377\335\345\371\377\335\345\371\377\335\345\371"
"\377\335\345\371\377\335\345\371\377\335\345\371\377\334\346\372\377\335"
"\345\371\377\335\345\371\377\335\345\371\377\335\345\371\377\335\345\371"
"\377\335\345\371\377\335\345\371\377\334\346\372\377\335\345\371\377\335"
"\345\371\377\335\347\373\377\367\375\377\377ty\200\377\000\000\000\377\000\000\000\345"
"\000\000\000\345\000\000\000\377sx\200\377\366\373\377\377\334\344\372\377\331\344\370"
"\377\330\343\371\377\331\344\370\377\330\343\371\377\330\343\371\377\331"
"\344\370\377\331\344\370\377\331\344\370\377\331\344\370\377\330\343\371"
"\377\331\344\370\377\331\344\370\377\331\344\370\377\331\344\370\377\331"
"\344\370\377\330\343\371\377\330\343\371\377\330\343\371\377\331\344\370"
"\377\331\344\370\377\331\344\370\377\330\343\371\377\330\342\371\377\331"
"\344\370\377\331\343\370\377\331\344\370\377\331\343\370\377\334\344\370"
"\377\366\373\377\377sx\200\377\000\000\000\377\000\000\000\345\000\000\000\346\000\000\000\377QV"
"[\377\365\373\377\377\334\346\372\377\325\341\370\377\325\337\370\377\325"
"\341\370\377\325\341\370\377\325\341\370\377\325\341\370\377\325\341\370"
"\377\325\341\370\377\325\341\370\377\325\341\370\377\325\341\370\377\325"
"\341\370\377\325\341\370\377\325\341\370\377\325\341\370\377\325\341\370"
"\377\325\341\370\377\325\341\370\377\325\341\370\377\325\341\370\377\325"
"\341\370\377\325\341\370\377\325\341\370\377\325\341\370\377\325\341\370"
"\377\324\341\370\377\324\341\370\377\334\346\372\377\365\373\377\377PU\\"
"\377\000\000\000\377\000\000\000\346\000\000\000\314\000\000\000\377\012\012\014\377\254\264\301\377"
"\362\370\377\377\325\341\370\377\321\335\367\377\320\335\370\377\320\335"
"\370\377\320\335\370\377\320\335\370\377\320\335\370\377\320\335\370\377"
"\320\335\370\377\320\335\370\377\321\335\367\377\320\335\370\377\320\335"
"\370\377\320\335\370\377\320\335\370\377\320\335\370\377\321\335\367\377"
"\321\335\367\377\320\335\370\377\320\335\370\377\320\335\370\377\320\335"
"\370\377\320\335\370\377\321\335\367\377\320\335\370\377\321\335\367\377"
"\326\340\371\377\362\370\377\377\254\264\301\377\012\012\014\377\000\000\000\377\000"
"\000\000\314\000\000\000d\000\000\000\377\000\000\000\377\024\025\027\377\262\274\314\377\355\365"
"\377\377\323\336\367\377\315\334\366\377\315\334\366\377\314\333\367\377"
"\315\334\366\377\314\333\367\377\314\333\367\377\314\333\367\377\314\333"
"\367\377\316\333\367\377\314\333\367\377\314\333\367\377\315\334\366\377"
"\315\334\366\377\315\334\366\377\316\333\367\377\316\333\367\377\314\333"
"\367\377\314\333\367\377\315\334\366\377\315\334\366\377\314\333\367\377"
"\314\333\367\377\314\333\367\377\323\340\367\377\356\365\377\377\262\274"
"\314\377\024\025\027\377\000\000\000\377\000\000\000\377\000\000\000d\000\000\000\002\000\000\000\220\000\000\000"
"\377\000\000\000\377\025\027\032\377\261\273\315\377\352\362\377\377\317\333\367\377"
"\311\326\366\377\311\330\366\377\311\330\366\377\311\330\366\377\311\330"
"\366\377\311\330\366\377\311\330\366\377\311\330\366\377\311\330\366\377"
"\311\330\366\377\311\330\366\377\311\330\366\377\311\330\366\377\311\330"
"\366\377\311\330\366\377\311\330\366\377\311\330\366\377\311\330\366\377"
"\311\330\366\377\311\330\366\377\311\330\366\377\317\333\367\377\352\362"
"\377\377\261\271\315\377\025\027\032\377\000\000\000\377\000\000\000\377\000\000\000\220\000\000\000"
"\002\000\000\000\000\000\000\000\002\000\000\000\224\000\000\000\377\000\000\000\377\025\030\032\377\257\272\320"
"\377\346\356\377\377\313\330\366\377\305\325\365\377\305\324\365\377\305"
"\324\365\377\305\325\365\377\305\324\365\377\305\324\365\377\305\325\365"
"\377\305\325\365\377\305\324\365\377\305\325\365\377\305\325\365\377\305"
"\324\365\377\305\325\365\377\305\325\365\377\305\325\365\377\305\325\365"
"\377\305\325\365\377\305\324\365\377\305\324\365\377\313\332\366\377\346"
"\356\377\377\257\272\320\377\025\027\032\377\000\000\000\377\000\000\000\377\000\000\000\224\000"
"\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004\000\000\000\235\000\000\000\377\000\000\000\377\031\032"
"\034\377\267\304\335\377\327\345\377\377\307\326\365\377\302\322\365\377\302"
"\322\365\377\302\322\365\377\302\322\365\377\302\322\365\377\302\322\365"
"\377\302\322\365\377\302\322\365\377\302\322\365\377\302\322\365\377\302"
"\322\365\377\302\322\365\377\302\322\365\377\302\322\365\377\302\322\365"
"\377\302\322\365\377\302\322\365\377\305\326\367\377\327\343\377\377\267"
"\304\335\377\031\032\034\377\000\000\000\377\000\000\000\377\000\000\000\235\000\000\000\004\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\241\000\000\000\377\000\000\000\377GJV\377"
"\327\345\377\377\311\330\367\377\275\317\365\377\276\317\365\377\276\320"
"\365\377\276\320\365\377\276\320\365\377\276\320\365\377\276\320\365\377"
"\276\320\365\377\276\320\365\377\276\320\365\377\276\320\365\377\276\320"
"\365\377\276\320\365\377\276\320\365\377\276\320\365\377\276\320\365\377"
"\275\317\365\377\311\330\367\377\326\345\377\377GJV\377\000\000\000\377\000\000\000\377"
"\000\000\000\241\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\011\000\000\000\313\000\000\000\377\015\015\017\377\270\305\341\377\312\334\374"
"\377\271\315\364\377\272\314\364\377\272\316\364\377\272\316\364\377\272"
"\316\364\377\272\316\364\377\272\316\364\377\272\316\364\377\272\316\364"
"\377\272\316\364\377\272\316\364\377\272\316\364\377\272\316\364\377\272"
"\316\364\377\272\316\364\377\272\316\364\377\271\316\364\377\312\334\374"
"\377\270\305\341\377\015\015\017\377\000\000\000\377\000\000\000\313\000\000\000\011\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000s\000\000"
"\000\377\004\004\006\377\254\270\324\377\311\332\376\377\267\313\364\377\270\312"
"\363\377\270\314\363\377\270\314\363\377\270\314\363\377\270\314\363\377"
"\270\312\363\377\270\312\363\377\270\314\363\377\270\314\363\377\270\314"
"\363\377\270\314\363\377\270\312\363\377\270\314\363\377\270\314\363\377"
"\270\314\363\377\267\313\364\377\311\332\376\377\254\270\324\377\004\004\006\377"
"\000\000\000\377\000\000\000s\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000a\000\000\000\377\005\005\007\377\253\270\324\377\306\332"
"\376\377\263\310\363\377\264\311\363\377\264\311\363\377\264\311\363\377"
"\264\311\363\377\264\311\363\377\264\311\364\377\264\311\364\377\264\311"
"\363\377\264\311\363\377\264\311\363\377\264\311\363\377\264\311\363\377"
"\264\311\363\377\264\311\364\377\264\311\364\377\263\310\363\377\306\332"
"\376\377\253\270\324\377\005\005\007\377\000\000\000\377\000\000\000a\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000d\000\000\000\377"
"\005\005\007\377\255\274\332\377\306\330\376\377\261\306\363\377\262\307\362\377"
"\262\307\362\377\262\307\362\377\262\307\362\377\262\307\362\377\262\307"
"\362\377\262\307\362\377\262\307\362\377\262\307\362\377\262\307\362\377"
"\262\307\362\377\262\307\362\377\262\307\362\377\262\307\362\377\262\307"
"\362\377\261\306\363\377\306\330\376\377\255\274\332\377\005\005\007\377\000\000\000"
"\377\000\000\000d\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000W\000\000\000\377\002\002\002\377\205\220\251\377\341\354\377"
"\377\313\333\377\377\311\333\377\377\311\333\377\377\311\333\377\377\311"
"\333\377\377\311\333\377\377\311\333\377\377\311\333\377\377\311\333\377"
"\377\311\333\377\377\310\332\377\377\311\333\377\377\311\333\377\377\311"
"\333\377\377\310\332\377\377\310\332\377\377\313\333\377\377\340\354\377"
"\377\205\220\251\377\002\002\002\377\000\000\000\377\000\000\000W\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\034\000\000\000\354"
"\000\000\000\377\020\022\025\377RZi\377]ev\377Zdt\377Zdt\377[ct\377[ct\377Zdt\377"
"Zdt\377Zdt\377[ct\377[ct\377Zds\377[ct\377[ct\377Zdt\377[cr\377Zds\377]e"
"v\377RZi\377\020\022\025\377\000\000\000\377\000\000\000\354\000\000\000\034\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000f\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377"
"\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000"
"\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000"
"\000\377\000\000\000\377\000\000\000f\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000R\000\000\000\275\000"
"\000\000\344\000\000\000\345\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000"
"\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000\344\000\000\000"
"\344\000\000\000\344\000\000\000\344\000\000\000\345\000\000\000\344\000\000\000\275\000\000\000R\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
};
static const _GLFWcursorDataOgc OGC_cursor_arrow = {
24, 31, 0, 0, 4,
"\002\002\002\337\000\000\000\224\000\000\000\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377"
"\005\005\005\321\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377ddd\377\037\037\037\373\003\003\003\364"
"\000\000\000V\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\361\361\361\377VVV\376\000\000\000\377"
"\002\002\002\243\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377\377\377\241"
"\241\241\377\007\007\007\375\005\005\005\322\000\000\000%\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\315\315\315\377!!!\373\003\003\003\365\000\000\000Y\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\362\362\362\377"
"WWW\376\000\000\000\377\002\002\002\243\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\377\225\225\225\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\241\241\241\377\007\007\007\375\005"
"\005\005\331\000\000\000+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\316\316\316\377!!!\373\003\003\003\365\000\000\000Z"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\362\362\362\377XXX\376\000\000\000\377\002\002\002\243\000\000\000"
"\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\375\375\377\377\373\374\376\377\235\236\240\377\007\007\007\374\005"
"\005\005\331\000\000\000+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\375\375\377\377"
"\373\374\376\377\371\373\376\377\367\371\376\377\366\370\375\377\305\310"
"\314\377\037!\"\373\003\003\003\366\000\000\000[\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377\377\377\377\377\377"
"\377\377\377\377\377\377\377\377\377\375\375\377\377\373\374\376\377\371"
"\373\376\377\367\371\376\377\366\370\375\377\364\367\375\377\362\365\375"
"\377\360\364\374\377\342\347\357\377QSW\376\000\000\000\377\002\002\002\243\000\000\000\012"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\225\225\225\377\377\377"
"\377\377\377\377\377\377\375\375\377\377\373\374\376\377\371\373\376\377"
"\367\371\376\377\366\370\375\377\364\367\375\377\362\365\375\377\360\364"
"\374\377\356\363\374\377\354\362\374\377\353\360\374\377\351\357\373\377"
"\222\226\236\377\007\007\007\374\004\005\005\331\000\000\000+\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\377\225\225\225\377\375\375\377\377\373\374\376\377\371\373\376"
"\377\367\371\376\377\366\370\375\377\364\367\375\377\362\365\375\377\360"
"\364\374\377\356\363\374\377\354\362\374\377\353\360\374\377\351\357\373"
"\377\347\356\373\377\345\354\373\377\343\353\372\377\275\303\321\377#%'\373"
"\003\003\003\366\000\000\000[\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\223\223\224\377\371\373"
"\376\377\367\371\376\377\366\370\375\377\364\367\375\377\362\365\375\377"
"\360\364\374\377\356\363\374\377\354\362\374\377\353\360\374\377\351\357"
"\373\377\347\356\373\377\345\354\373\377\343\353\372\377\342\352\372\377"
"\340\350\372\377\336\347\371\377\321\332\354\377LOW\376\000\000\000\377\002\002\002\243"
"\000\000\000\012\000\000\000\000\000\000\000\377\220\221\224\377\366\370\375\377\364\367\375\377"
"\362\365\375\377\360\364\374\377\356\363\374\377\354\362\374\377\353\360"
"\374\377\351\357\373\377\347\356\373\377\345\354\373\377\343\353\372\377"
"\342\352\372\377\340\350\372\377\336\347\371\377\334\346\371\377\332\344"
"\371\377\330\343\370\377\327\342\370\377\206\215\235\377\006\006\007\374\004\004\005"
"\332\000\000\000,\000\000\000\377\217\220\224\377\362\365\375\377\360\364\374\377\356"
"\363\374\377\354\361\374\377\353\360\374\377\351\357\373\377\347\356\373"
"\377\345\354\373\377\343\353\372\377\342\352\372\377\340\350\372\377\336"
"\347\371\377\334\346\371\377\332\344\371\377\330\343\370\377\327\342\370"
"\377\325\340\370\377\323\337\370\377\321\336\367\377pw\206\377\000\000\000\377"
"\001\001\001\347\000\000\000\377\214\217\223\377\356\363\374\377\354\361\374\377\353"
"\360\374\377\351\357\373\377\347\356\373\377\345\354\373\377\343\353\372"
"\377\342\352\372\377\340\350\372\377\336\347\371\377\334\346\371\377\332"
"\344\371\377\330\343\370\377\327\342\370\377\325\340\370\377\323\337\370"
"\377\321\336\367\377\225\236\261\377,/\065\374\000\000\000\377\004\004\005\316\000\000\000F"
"\000\000\000\377\212\215\223\377\353\360\374\377\351\357\373\377\347\356\373\377"
"\345\354\373\377\343\353\372\377\342\352\372\377\340\350\372\377\336\347"
"\371\377\334\346\371\377\332\344\371\377\330\343\370\377\327\342\370\377"
"\325\340\370\377\323\337\370\377\321\336\367\377\236\250\275\377\062\065<\374"
"\000\000\000\377\002\004\004\323\000\000\000U\000\000\000\001\000\000\000\000\000\000\000\377\210\214\223\377\347"
"\356\373\377\345\354\373\377\343\353\372\377\342\352\372\377\340\350\372"
"\377\336\347\371\377\334\346\371\377\332\344\371\377\330\343\370\377\327"
"\342\370\377\325\340\370\377\323\337\370\377\321\336\367\377\230\241\265"
"\377,/\064\374\000\000\000\377\002\004\004\323\000\000\000U\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\377\206\212\223\377\343\353\372\377\341\352\372\377\340\350\372\377"
"\336\347\371\377\334\346\371\377\332\344\371\377\330\343\370\377\327\342"
"\370\377\325\340\370\377\323\337\370\377\321\336\367\377\317\334\367\377"
"DHQ\374\000\000\000\377\004\004\004\314\000\000\000J\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\377\203\211\222\377\340\350\372\377\336\347\371\377\334"
"\346\371\377\332\344\371\377\330\343\370\377\327\342\370\377\325\340\370"
"\377\323\337\370\377\321\336\367\377\317\334\367\377\315\333\367\377\314"
"\332\366\377JOZ\376\002\002\003\362\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\202\207\221\377\334\346\371\377\332\344"
"\371\377\330\343\370\377\327\342\370\377\325\340\370\377\323\337\370\377"
"\321\336\367\377\316\333\366\377\315\333\367\377\314\332\366\377\312\330"
"\366\377\310\327\366\377\250\266\320\377\002\002\002\376\000\000\000r\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\177\205\221\377\330\343"
"\370\377\327\342\370\377\325\340\370\377\323\337\370\377\321\336\367\377"
"\223\234\257\377),\062\374\036\040$\374\306\324\361\377\310\327\366\377\306"
"\326\365\377\304\324\365\377\303\323\365\377FLX\376\003\003\004\354\000\000\000\012\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377~\204\221\377\325"
"\340\370\377\323\337\370\377\321\336\367\377\222\233\256\377)-\063\374\000\000"
"\000\377\002\004\004\321\000\000\000\376y\203\226\377\304\324\365\377\303\323\365\377\301"
"\322\364\377\277\320\364\377\242\261\321\377\001\002\002\376\000\000\000s\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377{\202\221\377\321\336\367\377"
"\222\233\256\377),\062\374\000\000\000\377\004\004\005\313\000\000\000I\000\000\000\000\001\001\003\263\026"
"\030\034\373\275\316\357\377\277\320\364\377\275\317\364\377\273\316\364\377"
"\271\314\363\377CJY\376\003\003\004\354\000\000\000\012\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\377INW\377)+\061\373\000\000\000\377\004\004\004\312\000\000\000H\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\062\000\000\000\376t\177\225\377\273\316\364\377\271\314\363"
"\377\270\313\363\377\212\232\271\377(,\066\375\000\000\000\377\000\000\000F\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\377\000\000\000\377\004\004\004\311\000\000\000H\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\003\003\262\025\027\034\373\264\307"
"\356\377\212\232\271\377.\063>\374\000\000\000\377\004\004\005\330\000\000\000V\000\000\000\001\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000t\000\000\000G\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\062\000\000\000\376\032\035$\375"
"\000\000\000\377\004\004\005\327\000\000\000V\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\003\003\247\004\004\005\325\000\000\000U\000\000\000\002\000\000"
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
};

161
src/ogc_init.c Normal file
View File

@ -0,0 +1,161 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(_GLFW_OGC)
#include <assert.h>
#include <fat.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiikeyboard/keyboard.h>
#include <wiiuse/wpad.h>
#define FIFO_SIZE (256*1024)
char _glfwUnimplementedFmt[] = "Ogc: the platform does not support %s";
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwConnectOgc(int platformID, _GLFWplatform* platform)
{
const _GLFWplatform ogc =
{
.platformID = GLFW_PLATFORM_OGC,
.init = _glfwInitOgc,
.terminate = _glfwTerminateOgc,
.getCursorPos = _glfwGetCursorPosOgc,
.setCursorPos = _glfwSetCursorPosOgc,
.setCursorMode = _glfwSetCursorModeOgc,
.setRawMouseMotion = _glfwSetRawMouseMotionOgc,
.rawMouseMotionSupported = _glfwRawMouseMotionSupportedOgc,
.createCursor = _glfwCreateCursorOgc,
.createStandardCursor = _glfwCreateStandardCursorOgc,
.destroyCursor = _glfwDestroyCursorOgc,
.setCursor = _glfwSetCursorOgc,
.getScancodeName = _glfwGetScancodeNameOgc,
.getKeyScancode = _glfwGetKeyScancodeOgc,
.setClipboardString = _glfwSetClipboardStringOgc,
.getClipboardString = _glfwGetClipboardStringOgc,
.initJoysticks = _glfwInitJoysticksOgc,
.terminateJoysticks = _glfwTerminateJoysticksOgc,
.pollJoystick = _glfwPollJoystickOgc,
.getMappingName = _glfwGetMappingNameOgc,
.updateGamepadGUID = _glfwUpdateGamepadGUIDOgc,
.freeMonitor = _glfwFreeMonitorOgc,
.getMonitorPos = _glfwGetMonitorPosOgc,
.getMonitorContentScale = _glfwGetMonitorContentScaleOgc,
.getMonitorWorkarea = _glfwGetMonitorWorkareaOgc,
.getVideoModes = _glfwGetVideoModesOgc,
.getVideoMode = _glfwGetVideoModeOgc,
.getGammaRamp = _glfwGetGammaRampOgc,
.setGammaRamp = _glfwSetGammaRampOgc,
.createWindow = _glfwCreateWindowOgc,
.destroyWindow = _glfwDestroyWindowOgc,
.setWindowTitle = _glfwSetWindowTitleOgc,
.setWindowIcon = _glfwSetWindowIconOgc,
.getWindowPos = _glfwGetWindowPosOgc,
.setWindowPos = _glfwSetWindowPosOgc,
.getWindowSize = _glfwGetWindowSizeOgc,
.setWindowSize = _glfwSetWindowSizeOgc,
.setWindowSizeLimits = _glfwSetWindowSizeLimitsOgc,
.setWindowAspectRatio = _glfwSetWindowAspectRatioOgc,
.getFramebufferSize = _glfwGetFramebufferSizeOgc,
.getWindowFrameSize = _glfwGetWindowFrameSizeOgc,
.getWindowContentScale = _glfwGetWindowContentScaleOgc,
.iconifyWindow = _glfwIconifyWindowOgc,
.restoreWindow = _glfwRestoreWindowOgc,
.maximizeWindow = _glfwMaximizeWindowOgc,
.showWindow = _glfwShowWindowOgc,
.hideWindow = _glfwHideWindowOgc,
.requestWindowAttention = _glfwRequestWindowAttentionOgc,
.focusWindow = _glfwFocusWindowOgc,
.setWindowMonitor = _glfwSetWindowMonitorOgc,
.windowFocused = _glfwWindowFocusedOgc,
.windowIconified = _glfwWindowIconifiedOgc,
.windowVisible = _glfwWindowVisibleOgc,
.windowMaximized = _glfwWindowMaximizedOgc,
.windowHovered = _glfwWindowHoveredOgc,
.framebufferTransparent = _glfwFramebufferTransparentOgc,
.getWindowOpacity = _glfwGetWindowOpacityOgc,
.setWindowResizable = _glfwSetWindowResizableOgc,
.setWindowDecorated = _glfwSetWindowDecoratedOgc,
.setWindowFloating = _glfwSetWindowFloatingOgc,
.setWindowOpacity = _glfwSetWindowOpacityOgc,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughOgc,
.pollEvents = _glfwPollEventsOgc,
.waitEvents = _glfwWaitEventsOgc,
.waitEventsTimeout = _glfwWaitEventsTimeoutOgc,
.postEmptyEvent = _glfwPostEmptyEventOgc,
.getEGLPlatform = _glfwGetEGLPlatformOgc,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayOgc,
.getEGLNativeWindow = _glfwGetEGLNativeWindowOgc,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsOgc,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportOgc,
.createWindowSurface = _glfwCreateWindowSurfaceOgc
};
*platform = ogc;
return GLFW_TRUE;
}
int _glfwInitOgc(void)
{
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__);
VIDEO_Init();
void *fifoBuffer = MEM_K0_TO_K1(memalign(32, FIFO_SIZE));
memset(fifoBuffer, 0, FIFO_SIZE);
GX_Init(fifoBuffer, FIFO_SIZE);
fatInitDefault();
PAD_Init();
KEYBOARD_Init(NULL);
#ifdef __wii__
WPAD_Init();
WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
WPAD_SetVRes(WPAD_CHAN_ALL, 640, 480);
#endif
_glfwCreateMonitorOgc();
return GLFW_TRUE;
}
void _glfwTerminateOgc(void)
{
_glfwTerminateEGL();
_glfwTerminateOSMesa();
}
#endif // _GLFW_OGC

417
src/ogc_joystick.c Normal file
View File

@ -0,0 +1,417 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(_GLFW_OGC)
#include <ogc/lwp_watchdog.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __wii__
#include <wiiuse/wpad.h>
#endif
#define MAX_FAILED_GC_READS 10
#define MAX_GC_AXES 6
#define MAX_GC_BUTTONS 8
#define MAX_GC_HATS 1
/* PAD_ScanPads() returns 0 if no joystick is connected, but also if querying
* the hardware failed for whatever reason. This can occasionally happen at
* runtime; so, we want to ignore these events and only report the joystick
* disconnection if PAD_ScanPads() consistently returns 0.
*
* This function returns true if the scanPads value is reliable.
*/
static GLFWbool readGCJoysticks(u32 *scanPads)
{
static GLFWbool lastReadFailed = GLFW_FALSE;
static u64 firstDisconnectedTimestamp = 0;
u32 currScanPads;
u64 timestamp;
currScanPads = PAD_ScanPads();
if (currScanPads == 0) {
timestamp = gettime();
if (lastReadFailed) {
if (ticks_to_millisecs(timestamp - firstDisconnectedTimestamp) < 500)
return GLFW_FALSE;
} else {
firstDisconnectedTimestamp = timestamp;
lastReadFailed = GLFW_TRUE;
return GLFW_FALSE;
}
} else {
lastReadFailed = GLFW_FALSE;
}
*scanPads = currScanPads;
return GLFW_TRUE;
}
static void readGCJoystick(_GLFWjoystick* js)
{
u32 id = js->ogc.id;
u16 btns = PAD_ButtonsHeld(id);
js->buttons[0] = btns & PAD_BUTTON_A ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[1] = btns & PAD_BUTTON_B ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[2] = btns & PAD_BUTTON_X ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[3] = btns & PAD_BUTTON_Y ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[4] = btns & PAD_TRIGGER_L ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[5] = btns & PAD_TRIGGER_R ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[6] = btns & PAD_TRIGGER_Z ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[7] = btns & PAD_BUTTON_START ? GLFW_PRESS : GLFW_RELEASE;
js->axes[0] = PAD_StickX(id) / 100.0;
js->axes[1] = PAD_StickY(id) / 100.0;
js->axes[2] = PAD_SubStickX(id) / 100.0;
js->axes[3] = PAD_SubStickY(id) / 100.0;
js->axes[4] = PAD_TriggerL(id) / 200.0;
js->axes[5] = PAD_TriggerR(id) / 200.0;
unsigned char hat = 0;
if (btns & PAD_BUTTON_UP) hat |= GLFW_HAT_UP;
if (btns & PAD_BUTTON_DOWN) hat |= GLFW_HAT_DOWN;
if (btns & PAD_BUTTON_LEFT) hat |= GLFW_HAT_LEFT;
if (btns & PAD_BUTTON_RIGHT) hat |= GLFW_HAT_RIGHT;
_glfwInputJoystickHat(js, 0, hat);
}
/* CRC algorithm used by SDL */
static uint16_t crc16_for_byte(uint8_t r)
{
uint16_t crc = 0;
int i;
for (i = 0; i < 8; ++i) {
crc = ((crc ^ r) & 1 ? 0xA001 : 0) ^ crc >> 1;
r >>= 1;
}
return crc;
}
uint16_t SDL_crc16(uint16_t crc, const void *data, size_t len)
{
/* As an optimization we can precalculate a 256 entry table for each byte */
size_t i;
for (i = 0; i < len; ++i) {
crc = crc16_for_byte((uint8_t)crc ^ ((const uint8_t *)data)[i]) ^ crc >> 8;
}
return crc;
}
static _GLFWjoystick* addJoystick(int deviceId,
const char *name, const char* guid,
int axisCount, int buttonCount, int hatCount)
{
fprintf(stderr, "Add controller %d %s\n", deviceId, name);
_GLFWjoystick* js =
_glfwAllocJoystick(name, guid,
axisCount, buttonCount, hatCount);
js->ogc.id = deviceId;
_glfw.ogcjs.joystickIndex[deviceId] = js - _glfw.joysticks;
_glfwInputJoystick(js, GLFW_CONNECTED);
return js;
}
static void addGCJoystick(int deviceId)
{
char name[16], guid[33];
uint16_t nameCrc;
sprintf(name, "Gamecube %d", deviceId);
nameCrc = SDL_crc16(0, name, strlen(name));
sprintf(guid, "0000%02x%02x7e050000000%d000001000000",
nameCrc & 0xff, nameCrc >> 8, deviceId + 1);
addJoystick(deviceId, name, guid,
MAX_GC_AXES, MAX_GC_BUTTONS, MAX_GC_HATS);
}
#ifdef __wii__
static inline float readAxis(uint8_t pos, uint8_t center, uint8_t min, uint8_t max)
{
if (pos < center) {
return (pos - center) / (float)(center - min);
} else {
return (pos - center) / (float)(max - center);
}
}
static void readJoystickAxes(_GLFWjoystick* js, int index, const joystick_t *data)
{
js->axes[index] = readAxis(data->pos.x, data->center.x, data->min.x, data->max.x);
js->axes[index + 1] = readAxis(data->pos.y, data->center.y, data->min.y, data->max.y);
}
static inline float clampUnity(float value)
{
if (value < -1.0f) return -1.0f;
if (value > 1.0f) return 1.0f;
return value;
}
static void readOrientationAxes(_GLFWjoystick* js, int index, const orient_t *data)
{
/* Orientation fields range from -180 to 180 (they are measured in
* degrees), but in order to use them as joystick axes it's more reasonable
* to limit their range to -90/90. */
js->axes[index] = clampUnity(-data->pitch / 90.0f);
js->axes[index + 1] = clampUnity(data->roll / 90.0f);
js->axes[index + 2] = clampUnity(data->yaw / 90.0f);
}
static void readWiimote(_GLFWjoystick* js)
{
u32 id = js->ogc.id - MAX_GC_JOYSTICKS;
WPADData *data = WPAD_Data(id);
u32 btns = data->btns_h | data->btns_d;
unsigned char hat = 0;
GLFWbool readWiimote = GLFW_FALSE;
GLFWbool wiimotePointer = GLFW_FALSE;
int wiimoteFirstAxis = 0;
if (js->ogc.expansion == EXP_NUNCHUK) {
js->buttons[7] = btns & WPAD_NUNCHUK_BUTTON_Z ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[8] = btns & WPAD_NUNCHUK_BUTTON_C ? GLFW_PRESS : GLFW_RELEASE;
/* When a nunchuk is connected, we report its joystick as the first two axes,
* followed by three axes from the wiimote orientation, followed by
* three axes from the nunchuk orientation. */
readJoystickAxes(js, 0, &data->exp.nunchuk.js);
readWiimote = GLFW_TRUE;
wiimotePointer = GLFW_TRUE;
wiimoteFirstAxis = 2;
readOrientationAxes(js, wiimoteFirstAxis + 3, &data->exp.nunchuk.orient);
} else if (js->ogc.expansion == EXP_CLASSIC) {
if (btns & WPAD_CLASSIC_BUTTON_LEFT) hat |= GLFW_HAT_LEFT;
if (btns & WPAD_CLASSIC_BUTTON_RIGHT) hat |= GLFW_HAT_RIGHT;
if (btns & WPAD_CLASSIC_BUTTON_UP) hat |= GLFW_HAT_UP;
if (btns & WPAD_CLASSIC_BUTTON_DOWN) hat |= GLFW_HAT_DOWN;
js->buttons[0] = btns & WPAD_CLASSIC_BUTTON_A ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[1] = btns & WPAD_CLASSIC_BUTTON_B ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[2] = btns & WPAD_CLASSIC_BUTTON_X ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[3] = btns & WPAD_CLASSIC_BUTTON_Y ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[4] = btns & WPAD_CLASSIC_BUTTON_FULL_L ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[5] = btns & WPAD_CLASSIC_BUTTON_FULL_R ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[6] = btns & WPAD_CLASSIC_BUTTON_ZL ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[7] = btns & WPAD_CLASSIC_BUTTON_ZR ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[8] = btns & WPAD_CLASSIC_BUTTON_MINUS ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[9] = btns & WPAD_CLASSIC_BUTTON_PLUS ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[10] = btns & WPAD_CLASSIC_BUTTON_HOME ? GLFW_PRESS : GLFW_RELEASE;
readJoystickAxes(js, 0, &data->exp.classic.ljs);
readJoystickAxes(js, 2, &data->exp.classic.rjs);
} else if (js->ogc.expansion == EXP_NONE) {
readWiimote = GLFW_TRUE;
wiimotePointer = data->ir.valid;
}
if (readWiimote) {
if (wiimotePointer) {
if (btns & WPAD_BUTTON_LEFT) hat |= GLFW_HAT_LEFT;
if (btns & WPAD_BUTTON_RIGHT) hat |= GLFW_HAT_RIGHT;
if (btns & WPAD_BUTTON_UP) hat |= GLFW_HAT_UP;
if (btns & WPAD_BUTTON_DOWN) hat |= GLFW_HAT_DOWN;
} else {
if (btns & WPAD_BUTTON_LEFT) hat |= GLFW_HAT_DOWN;
if (btns & WPAD_BUTTON_RIGHT) hat |= GLFW_HAT_UP;
if (btns & WPAD_BUTTON_UP) hat |= GLFW_HAT_LEFT;
if (btns & WPAD_BUTTON_DOWN) hat |= GLFW_HAT_RIGHT;
}
js->buttons[0] = btns & WPAD_BUTTON_1 ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[1] = btns & WPAD_BUTTON_2 ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[2] = btns & WPAD_BUTTON_A ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[3] = btns & WPAD_BUTTON_B ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[4] = btns & WPAD_BUTTON_MINUS ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[5] = btns & WPAD_BUTTON_PLUS ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[6] = btns & WPAD_BUTTON_HOME ? GLFW_PRESS : GLFW_RELEASE;
readOrientationAxes(js, wiimoteFirstAxis, &data->orient);
}
_glfwInputJoystickHat(js, 0, hat);
/* On the Wii, let's close the window when the HOME button is pressed,
* since that's the default behaviour for homebrew applications. The close
* event can anyway be overridden in the application, if this behaviour is
* not desired. */
if (btns & WPAD_BUTTON_HOME && _glfw.windowListHead) {
_glfwInputWindowCloseRequest(_glfw.windowListHead);
}
}
static void addWiimote(int deviceId, uint8_t expansion)
{
char name[64], guid[40];
uint16_t nameCrc;
int axisCount, buttonCount, hatCount;
/* These counters are for the bare Wiimote */
axisCount = 3;
buttonCount = 7;
hatCount = 1;
char *name_ptr = name;
name_ptr += sprintf(name_ptr, "Wiimote %d", deviceId - MAX_GC_JOYSTICKS);
switch (expansion) {
case WPAD_EXP_NUNCHUK:
strcpy(name_ptr, " + Nunchuk");
axisCount += 5;
buttonCount += 2;
break;
case WPAD_EXP_CLASSIC:
strcpy(name_ptr, " + Classic");
axisCount = 4;
buttonCount = 11;
hatCount = 1;
break;
case WPAD_EXP_GUITARHERO3:
strcpy(name_ptr, " + Guitar Hero 3");
break;
case WPAD_EXP_WIIBOARD:
strcpy(name_ptr, " + Balance board");
break;
}
nameCrc = SDL_crc16(0, name, strlen(name));
sprintf(guid, "0500%02x%02x7e0500000%d0%d000001000000",
nameCrc & 0xff, nameCrc >> 8, expansion + 1, deviceId + 1);
_GLFWjoystick *js = addJoystick(deviceId, name, guid,
axisCount, buttonCount, hatCount);
js->ogc.expansion = expansion;
}
#endif /* __wii__ */
static void removeJoystick(int deviceId)
{
_GLFWjoystick* js = JOYSTICK_FROM_DEVICE(deviceId);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
_glfwFreeJoystick(js);
_glfw.ogcjs.joystickIndex[deviceId] = -1;
fprintf(stderr, "Removed controller %d\n", deviceId);
}
static GLFWbool updateJoysticks()
{
u32 scanPads = 0;
if (_glfw.joysticksInitialized && readGCJoysticks(&scanPads)) {
for (int i = 0; i < MAX_GC_JOYSTICKS; i++) {
GLFWbool connected = !!(scanPads & (1 << i));
int joystickIndex = JOYSTICK_INDEX_FROM_DEVICE(i);
GLFWbool wasConnected = joystickIndex >= 0 ?
_glfw.joysticks[joystickIndex].connected : GLFW_FALSE;
if (connected != wasConnected) {
if (connected) {
addGCJoystick(i);
joystickIndex = JOYSTICK_INDEX_FROM_DEVICE(i);
} else {
removeJoystick(i);
}
}
if (connected)
readGCJoystick(&_glfw.joysticks[joystickIndex]);
}
}
#ifdef __wii__
/* The WPAD data is also used for the mouse, so we read it even if
* joysticks haven't been initialized */
WPAD_ReadPending(WPAD_CHAN_ALL, NULL);
if (_glfw.joysticksInitialized) {
for (int i = 0; i < MAX_WIIMOTES; i++) {
int deviceId = i + MAX_GC_JOYSTICKS;
int joystickIndex = JOYSTICK_INDEX_FROM_DEVICE(deviceId);
WPADData *data = WPAD_Data(i);
/* Ignore all reads where an error occurred */
if (data->err != WPAD_ERR_NONE) continue;
GLFWbool connected = data->data_present != 0;
uint8_t expansion = data->data_present & WPAD_DATA_EXPANSION ?
data->exp.type : EXP_NONE;
GLFWbool wasConnected = joystickIndex >= 0 ?
_glfw.joysticks[joystickIndex].connected : GLFW_FALSE;
uint8_t hadExpansion = joystickIndex >= 0 ?
_glfw.joysticks[joystickIndex].ogc.expansion : EXP_NONE;
if (connected != wasConnected || expansion != hadExpansion) {
if (wasConnected) {
removeJoystick(deviceId);
}
if (connected) {
addWiimote(deviceId, expansion);
joystickIndex = JOYSTICK_INDEX_FROM_DEVICE(deviceId);
}
}
if (connected)
readWiimote(&_glfw.joysticks[joystickIndex]);
}
}
#endif
return GLFW_TRUE;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwPollJoysticksOgc(void)
{
return updateJoysticks();
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitJoysticksOgc(void)
{
/* Hardware initialization done in ogc_init.c, since we want it to happen
* ASAP */
for (int i = 0; i < MAX_JOYSTICKS; i++) {
_glfw.ogcjs.joystickIndex[i] = -1;
}
return GLFW_TRUE;
}
void _glfwTerminateJoysticksOgc(void)
{
// TODO
}
GLFWbool _glfwPollJoystickOgc(_GLFWjoystick* js, int mode)
{
updateJoysticks();
return js->connected;
}
const char* _glfwGetMappingNameOgc(void)
{
return "Ogc";
}
void _glfwUpdateGamepadGUIDOgc(char* guid)
{
}
#endif // _GLFW_OGC

64
src/ogc_joystick.h Normal file
View File

@ -0,0 +1,64 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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.
//
//========================================================================
#define GLFW_OGC_JOYSTICK_STATE _GLFWjoystickOgc ogc;
#define GLFW_OGC_LIBRARY_JOYSTICK_STATE _GLFWlibraryJoystickOgc ogcjs;
#define MAX_GC_JOYSTICKS 4
#ifdef __wii__
#define MAX_WIIMOTES 4
#else
#define MAX_WIIMOTES 0
#endif
#define MAX_JOYSTICKS (MAX_GC_JOYSTICKS + MAX_WIIMOTES)
// Ogc-specific joystick data
//
typedef struct _GLFWjoystickOgc
{
int id;
uint8_t expansion;
} _GLFWjoystickOgc;
typedef struct _GLFWlibraryJoystickOgc
{
char joystickIndex[MAX_JOYSTICKS];
} _GLFWlibraryJoystickOgc;
#define JOYSTICK_INDEX_FROM_DEVICE(deviceId) \
((int)_glfw.ogcjs.joystickIndex[deviceId])
#define JOYSTICK_FROM_DEVICE(deviceId) \
(&_glfw.joysticks[JOYSTICK_INDEX_FROM_DEVICE(deviceId)])
GLFWbool _glfwPollJoysticksOgc(void);
GLFWbool _glfwInitJoysticksOgc(void);
void _glfwTerminateJoysticksOgc(void);
GLFWbool _glfwPollJoystickOgc(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameOgc(void);
void _glfwUpdateGamepadGUIDOgc(char* guid);

50
src/ogc_module.c Normal file
View File

@ -0,0 +1,50 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(GLFW_BUILD_OGC_MODULE)
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void* _glfwPlatformLoadModule(const char* path)
{
return NULL;
}
void _glfwPlatformFreeModule(void* module)
{
}
GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
{
return NULL;
}
#endif // GLFW_BUILD_OGC_MODULE

248
src/ogc_monitor.c Normal file
View File

@ -0,0 +1,248 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(_GLFW_OGC)
#include <ogc/color.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAX_OGC_MODES 4 /* - VIDEO_GetPreferredMode()
- 240p progressive mode
- 480p progressive mode
- 528p PAL progressive mode
*/
static GXRModeObj *s_videoModes[MAX_OGC_MODES + 1]; // +1 for the NULL entry
// Inverse of the VI_TVMODE macro
#define VI_FORMAT_FROM_MODE(tvmode) (tvmode >> 2)
static void setupXfb(_GLFWmonitor* monitor)
{
if (_glfw.ogc.xfb[0]) {
free(MEM_K1_TO_K0(_glfw.ogc.xfb[0]));
_glfw.ogc.xfb[0] = NULL;
}
if (_glfw.ogc.xfb[1]) {
free(MEM_K1_TO_K0(_glfw.ogc.xfb[1]));
_glfw.ogc.xfb[1] = NULL;
}
if (!_glfw.ogc.xfb[0]) {
_glfw.ogc.xfb[0] =
MEM_K0_TO_K1(SYS_AllocateFramebuffer(monitor->ogc.ogcMode));
}
if (monitor->window && monitor->window->doublebuffer) {
_glfw.ogc.xfb[1] =
MEM_K0_TO_K1(SYS_AllocateFramebuffer(monitor->ogc.ogcMode));
}
_glfw.ogc.fbIndex = 0;
}
static void ogcVideoModeToGlfw(const GXRModeObj *in, GLFWvidmode *out)
{
out->width = in->fbWidth;
out->height = in->efbHeight;
out->redBits = out->greenBits = out->blueBits = 8;
u32 format = VI_FORMAT_FROM_MODE(in->viTVMode);
switch (format) {
case VI_DEBUG:
case VI_NTSC:
case VI_EURGB60:
case VI_MPAL:
out->refreshRate = 60;
break;
case VI_PAL:
case VI_DEBUG_PAL:
out->refreshRate = 50;
break;
}
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
void _glfwCreateMonitorOgc()
{
_GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0);
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_FIRST);
}
void _glfwSetVideoModeOgc(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
int i;
const GLFWvidmode* best = _glfwChooseVideoMode(monitor, desired);
fprintf(stderr, "%s:%d %s chosen %dx%d window %p\n", __FILE__, __LINE__, __func__,
best->width, best->height, monitor->window);
for (i = 0; i < monitor->modeCount; i++) {
GLFWvidmode tmp;
ogcVideoModeToGlfw(s_videoModes[i], &tmp);
if (_glfwCompareVideoModes(best, &tmp) == 0)
break;
}
/* In the unlikely case that this is not one of our modes, just pick our
* preferred one */
if (i >= monitor->modeCount) i = 0;
GXRModeObj *vmode = s_videoModes[i];
monitor->ogc.currentMode = i;
monitor->ogc.ogcMode = vmode;
setupXfb(monitor);
VIDEO_Configure(vmode);
VIDEO_ClearFrameBuffer(vmode, _glfw.ogc.xfb[0], COLOR_BLACK);
VIDEO_SetNextFramebuffer(_glfw.ogc.xfb[0]);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
float yscale = GX_GetYScaleFactor(vmode->efbHeight, vmode->xfbHeight);
GX_SetDispCopyYScale(yscale);
GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopyDst(vmode->fbWidth, vmode->xfbHeight);
GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwFreeMonitorOgc(_GLFWmonitor* monitor)
{
}
void _glfwGetMonitorPosOgc(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
}
void _glfwGetMonitorContentScaleOgc(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.0f;
if (yscale)
*yscale = 1.0f;
}
void _glfwGetMonitorWorkareaOgc(_GLFWmonitor* monitor,
int* xpos, int* ypos,
int* width, int* height)
{
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
if (width)
*width = monitor->modes[monitor->ogc.currentMode].width;
if (height)
*height = monitor->modes[monitor->ogc.currentMode].height;
}
GLFWvidmode* _glfwGetVideoModesOgc(_GLFWmonitor* monitor, int* found)
{
int i, count;
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__);
i = 0;
s_videoModes[i++] = VIDEO_GetPreferredMode(NULL);
/* Add more video modes, depending on the TV mode of the preferred mode
* (NTSC, PAL, etc.) */
switch (VI_FORMAT_FROM_MODE(s_videoModes[0]->viTVMode))
{
case VI_DEBUG:
case VI_NTSC:
s_videoModes[i++] = &TVNtsc240Ds;
s_videoModes[i++] = &TVNtsc480Prog;
break;
case VI_MPAL:
s_videoModes[i++] = &TVMpal240Ds;
s_videoModes[i++] = &TVMpal480Prog;
break;
case VI_EURGB60:
s_videoModes[i++] = &TVEurgb60Hz240Ds;
s_videoModes[i++] = &TVEurgb60Hz480Prog;
s_videoModes[i++] = &TVPal528Prog;
break;
case VI_PAL:
case VI_DEBUG_PAL:
s_videoModes[i++] = &TVPal264Ds;
s_videoModes[i++] = &TVPal576ProgScale; // EFB height is 480
s_videoModes[i++] = &TVPal528Prog;
break;
default:
return NULL;
}
s_videoModes[i] = NULL;
GLFWvidmode* modes = _glfw_calloc(i, sizeof(GLFWvidmode));
count = i;
for (int i = 0; i < count; i++)
{
ogcVideoModeToGlfw(s_videoModes[i], &modes[i]);
}
*found = count;
return modes;
}
GLFWbool _glfwGetVideoModeOgc(_GLFWmonitor* monitor, GLFWvidmode* mode)
{
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__);
*mode = monitor->modes[monitor->ogc.currentMode];
return GLFW_TRUE;
}
GLFWbool _glfwGetGammaRampOgc(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"gamma ramp");
return GLFW_FALSE;
}
void _glfwSetGammaRampOgc(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"gamma ramp");
}
#endif // _GLFW_OGC

252
src/ogc_platform.h Normal file
View File

@ -0,0 +1,252 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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 <ogc/gx.h>
#include <ogc/system.h>
#include <ogc/video.h>
#define GLFW_OGC_WINDOW_STATE _GLFWwindowOgc ogc;
#define GLFW_OGC_LIBRARY_WINDOW_STATE _GLFWlibraryOgc ogc;
#define GLFW_OGC_MONITOR_STATE _GLFWmonitorOgc ogc;
#define GLFW_OGC_CURSOR_STATE _GLFWcursorOgc ogc;
extern char _glfwUnimplementedFmt[];
#if 0
typedef struct ogc_cursor_theme* (* PFN_ogc_cursor_theme_load)(const char*, int, struct ogc_shm*);
typedef void (* PFN_ogc_cursor_theme_destroy)(struct ogc_cursor_theme*);
typedef struct ogc_cursor* (* PFN_ogc_cursor_theme_get_cursor)(struct ogc_cursor_theme*, const char*);
typedef struct ogc_buffer* (* PFN_ogc_cursor_image_get_buffer)(struct ogc_cursor_image*);
#define ogc_cursor_theme_load _glfw.ogc.cursor.theme_load
#define ogc_cursor_theme_destroy _glfw.ogc.cursor.theme_destroy
#define ogc_cursor_theme_get_cursor _glfw.ogc.cursor.theme_get_cursor
#define ogc_cursor_image_get_buffer _glfw.ogc.cursor.image_get_buffer
typedef struct ogc_egl_window* (* PFN_ogc_egl_window_create)(struct ogc_surface*, int, int);
typedef void (* PFN_ogc_egl_window_destroy)(struct ogc_egl_window*);
typedef void (* PFN_ogc_egl_window_resize)(struct ogc_egl_window*, int, int, int, int);
#define ogc_egl_window_create _glfw.ogc.egl.window_create
#define ogc_egl_window_destroy _glfw.ogc.egl.window_destroy
#define ogc_egl_window_resize _glfw.ogc.egl.window_resize
typedef struct xkb_context* (* PFN_xkb_context_new)(enum xkb_context_flags);
typedef void (* PFN_xkb_context_unref)(struct xkb_context*);
typedef struct xkb_keymap* (* PFN_xkb_keymap_new_from_string)(struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
typedef void (* PFN_xkb_keymap_unref)(struct xkb_keymap*);
typedef xkb_mod_index_t (* PFN_xkb_keymap_mod_get_index)(struct xkb_keymap*, const char*);
typedef int (* PFN_xkb_keymap_key_repeats)(struct xkb_keymap*, xkb_keycode_t);
typedef int (* PFN_xkb_keymap_key_get_syms_by_level)(struct xkb_keymap*,xkb_keycode_t,xkb_layout_index_t,xkb_level_index_t,const xkb_keysym_t**);
typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*);
typedef void (* PFN_xkb_state_unref)(struct xkb_state*);
typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t);
typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component);
typedef uint32_t (* PFN_xkb_keysym_to_utf32)(xkb_keysym_t);
typedef int (* PFN_xkb_keysym_to_utf8)(xkb_keysym_t, char*, size_t);
#define xkb_context_new _glfw.ogc.xkb.context_new
#define xkb_context_unref _glfw.ogc.xkb.context_unref
#define xkb_keymap_new_from_string _glfw.ogc.xkb.keymap_new_from_string
#define xkb_keymap_unref _glfw.ogc.xkb.keymap_unref
#define xkb_keymap_mod_get_index _glfw.ogc.xkb.keymap_mod_get_index
#define xkb_keymap_key_repeats _glfw.ogc.xkb.keymap_key_repeats
#define xkb_keymap_key_get_syms_by_level _glfw.ogc.xkb.keymap_key_get_syms_by_level
#define xkb_state_new _glfw.ogc.xkb.state_new
#define xkb_state_unref _glfw.ogc.xkb.state_unref
#define xkb_state_key_get_syms _glfw.ogc.xkb.state_key_get_syms
#define xkb_state_update_mask _glfw.ogc.xkb.state_update_mask
#define xkb_state_key_get_layout _glfw.ogc.xkb.state_key_get_layout
#define xkb_state_mod_index_is_active _glfw.ogc.xkb.state_mod_index_is_active
#define xkb_keysym_to_utf32 _glfw.ogc.xkb.keysym_to_utf32
#define xkb_keysym_to_utf8 _glfw.ogc.xkb.keysym_to_utf8
typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*);
typedef struct xkb_compose_state* (* PFN_xkb_compose_state_new)(struct xkb_compose_table*, enum xkb_compose_state_flags);
typedef void (* PFN_xkb_compose_state_unref)(struct xkb_compose_state*);
typedef enum xkb_compose_feed_result (* PFN_xkb_compose_state_feed)(struct xkb_compose_state*, xkb_keysym_t);
typedef enum xkb_compose_status (* PFN_xkb_compose_state_get_status)(struct xkb_compose_state*);
typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_state*);
#define xkb_compose_table_new_from_locale _glfw.ogc.xkb.compose_table_new_from_locale
#define xkb_compose_table_unref _glfw.ogc.xkb.compose_table_unref
#define xkb_compose_state_new _glfw.ogc.xkb.compose_state_new
#define xkb_compose_state_unref _glfw.ogc.xkb.compose_state_unref
#define xkb_compose_state_feed _glfw.ogc.xkb.compose_state_feed
#define xkb_compose_state_get_status _glfw.ogc.xkb.compose_state_get_status
#define xkb_compose_state_get_one_sym _glfw.ogc.xkb.compose_state_get_one_sym
#endif
// Ogc-specific per-window data
//
typedef struct _GLFWwindowOgc
{
int width, height;
GLFWbool maximized;
GLFWbool activated;
GLFWbool fullscreen;
GLFWbool hovered;
GLFWbool transparent;
GLFWbool scaleFramebuffer;
struct ogc_surface* surface;
struct ogc_callback* callback;
_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY;
char* appId;
} _GLFWwindowOgc;
// Ogc-specific global data
//
typedef struct _GLFWlibraryOgc
{
void * xfb[2];
int fbIndex;
struct ogc_cursor_theme* cursorTheme;
struct ogc_cursor_theme* cursorThemeHiDPI;
struct ogc_surface* cursorSurface;
const char* cursorPreviousName;
int cursorTimerfd;
uint32_t serial;
uint32_t pointerEnterSerial;
int keyRepeatTimerfd;
int32_t keyRepeatRate;
int32_t keyRepeatDelay;
int keyRepeatScancode;
char* clipboardString;
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
char keynames[GLFW_KEY_LAST + 1][5];
_GLFWwindow* pointerFocus;
_GLFWwindow* keyboardFocus;
} _GLFWlibraryOgc;
// Ogc-specific per-monitor data
//
typedef struct _GLFWmonitorOgc
{
int currentMode;
GXRModeObj* ogcMode;
} _GLFWmonitorOgc;
// Ogc-specific per-cursor data
//
typedef struct _GLFWcursorOgc
{
GXTexObj texobj;
short xhot, yhot;
GLFWbool canRotate;
} _GLFWcursorOgc;
GLFWbool _glfwConnectOgc(int platformID, _GLFWplatform* platform);
int _glfwInitOgc(void);
void _glfwTerminateOgc(void);
void _glfwCreateMonitorOgc(void);
void _glfwSetVideoModeOgc(_GLFWmonitor* monitor, const GLFWvidmode* desired);
GLFWbool _glfwCreateContextOgc(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowOgc(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowOgc(_GLFWwindow* window);
void _glfwSetWindowTitleOgc(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconOgc(_GLFWwindow* window, int count, const GLFWimage* images);
void _glfwGetWindowPosOgc(_GLFWwindow* window, int* xpos, int* ypos);
void _glfwSetWindowPosOgc(_GLFWwindow* window, int xpos, int ypos);
void _glfwGetWindowSizeOgc(_GLFWwindow* window, int* width, int* height);
void _glfwSetWindowSizeOgc(_GLFWwindow* window, int width, int height);
void _glfwSetWindowSizeLimitsOgc(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight);
void _glfwSetWindowAspectRatioOgc(_GLFWwindow* window, int numer, int denom);
void _glfwGetFramebufferSizeOgc(_GLFWwindow* window, int* width, int* height);
void _glfwGetWindowFrameSizeOgc(_GLFWwindow* window, int* left, int* top, int* right, int* bottom);
void _glfwGetWindowContentScaleOgc(_GLFWwindow* window, float* xscale, float* yscale);
void _glfwIconifyWindowOgc(_GLFWwindow* window);
void _glfwRestoreWindowOgc(_GLFWwindow* window);
void _glfwMaximizeWindowOgc(_GLFWwindow* window);
void _glfwShowWindowOgc(_GLFWwindow* window);
void _glfwHideWindowOgc(_GLFWwindow* window);
void _glfwRequestWindowAttentionOgc(_GLFWwindow* window);
void _glfwFocusWindowOgc(_GLFWwindow* window);
void _glfwSetWindowMonitorOgc(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
GLFWbool _glfwWindowFocusedOgc(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedOgc(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleOgc(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedOgc(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredOgc(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentOgc(_GLFWwindow* window);
void _glfwSetWindowResizableOgc(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedOgc(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingOgc(_GLFWwindow* window, GLFWbool enabled);
float _glfwGetWindowOpacityOgc(_GLFWwindow* window);
void _glfwSetWindowOpacityOgc(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughOgc(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetRawMouseMotionOgc(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedOgc(void);
void _glfwPollEventsOgc(void);
void _glfwWaitEventsOgc(void);
void _glfwWaitEventsTimeoutOgc(double timeout);
void _glfwPostEmptyEventOgc(void);
void _glfwGetCursorPosOgc(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwSetCursorPosOgc(_GLFWwindow* window, double xpos, double ypos);
void _glfwSetCursorModeOgc(_GLFWwindow* window, int mode);
const char* _glfwGetScancodeNameOgc(int scancode);
int _glfwGetKeyScancodeOgc(int key);
GLFWbool _glfwCreateCursorOgc(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorOgc(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorOgc(_GLFWcursor* cursor);
void _glfwSetCursorOgc(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringOgc(const char* string);
const char* _glfwGetClipboardStringOgc(void);
EGLenum _glfwGetEGLPlatformOgc(EGLint** attribs);
EGLNativeDisplayType _glfwGetEGLNativeDisplayOgc(void);
EGLNativeWindowType _glfwGetEGLNativeWindowOgc(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsOgc(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportOgc(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceOgc(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwFreeMonitorOgc(_GLFWmonitor* monitor);
void _glfwGetMonitorPosOgc(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleOgc(_GLFWmonitor* monitor, float* xscale, float* yscale);
void _glfwGetMonitorWorkareaOgc(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height);
GLFWvidmode* _glfwGetVideoModesOgc(_GLFWmonitor* monitor, int* count);
GLFWbool _glfwGetVideoModeOgc(_GLFWmonitor* monitor, GLFWvidmode* mode);
GLFWbool _glfwGetGammaRampOgc(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwSetGammaRampOgc(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwAddOutputOgc(uint32_t name, uint32_t version);
void _glfwUpdateBufferScaleFromOutputsOgc(_GLFWwindow* window);

237
src/ogc_thread.c Normal file
View File

@ -0,0 +1,237 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(GLFW_BUILD_OGC_THREAD)
#include <assert.h>
#include <ogcsys.h>
#include <string.h>
#define MAX_THREADS 32
#define INITIAL_STORAGE_CAPACITY 64
#define INCREMENT_STORAGE_CAPACITY 64
typedef struct _GLFWthreadStorageOgc {
size_t capacity;
size_t used;
void *data[0]; /* Array of pointers to the stored data element */
} _GLFWthreadStorageOgc;
#define RESERVED_PTR ((void*)0x1)
typedef struct _GLFWthreadMapOgc {
lwp_t threadId;
_GLFWthreadStorageOgc *storage;
} _GLFWthreadMapOgc;
static _GLFWthreadMapOgc threadMap[MAX_THREADS];
static mutex_t threadMapMutex = 0; // TODO initialize!
static _GLFWthreadMapOgc *storageEntryForThread()
{
lwp_t currentThreadId = LWP_GetSelf();
/* We are not creating entries here and only our thread can modify our
* entry, so we don't need to lock the mutex here. */
for (int i = 0; i < MAX_THREADS; i++) {
_GLFWthreadMapOgc *entry = &threadMap[i];
if (entry->threadId == currentThreadId) {
return entry;
}
}
return NULL;
}
static inline _GLFWthreadStorageOgc *storageForThread()
{
_GLFWthreadMapOgc *entry = storageEntryForThread();
return entry ? entry->storage : NULL;
}
static _GLFWthreadMapOgc *createStorageEntryForThread()
{
size_t initialSize = sizeof(_GLFWthreadStorageOgc) +
INITIAL_STORAGE_CAPACITY * sizeof(void*);
_GLFWthreadStorageOgc *storage = _glfw_calloc(1, initialSize);
if (!storage) {
_glfwInputError(GLFW_OUT_OF_MEMORY,
"OGC: Failed to allocate TLS data");
return NULL;
}
storage->capacity = INITIAL_STORAGE_CAPACITY;
storage->used = 0;
if (!LWP_MutexLock(threadMapMutex)) {
_glfw_free(storage);
_glfwInputError(GLFW_PLATFORM_ERROR,
"OGC: Failed to lock TLS mutex");
return NULL;
}
_GLFWthreadMapOgc *entry = NULL;
lwp_t currentThreadId = LWP_GetSelf();
for (int i = 0; i < MAX_THREADS; i++) {
entry = &threadMap[i];
if (!entry->threadId) {
entry->threadId = currentThreadId;
entry->storage = storage;
break;
}
}
if (entry->threadId != currentThreadId) {
// We didn't find a free slot
entry = NULL;
}
LWP_MutexUnlock(threadMapMutex);
return entry;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwPlatformCreateTls(_GLFWtls* tls)
{
assert(tls->ogc.allocated == GLFW_FALSE);
_GLFWthreadMapOgc *entry = storageEntryForThread();
if (!entry) {
entry = createStorageEntryForThread();
if (!entry) {
// The error has already been logged
return GLFW_FALSE;
}
}
_GLFWthreadStorageOgc *storage = entry->storage;
if (storage->used >= storage->capacity) {
size_t newSize = sizeof(_GLFWthreadStorageOgc) +
(storage->capacity + INCREMENT_STORAGE_CAPACITY) * sizeof(void*);
storage = _glfw_realloc(storage, newSize);
if (!storage) {
_glfwInputError(GLFW_OUT_OF_MEMORY,
"OGC: Failed to reallocate TLS data");
return GLFW_FALSE;
}
// No need to lock the map, since we are changing our own thread's
// entry
entry->storage = storage;
storage->capacity += INCREMENT_STORAGE_CAPACITY;
}
// Find the first free entry in the TLS data
int index = -1;
for (int i = 0; i < storage->capacity; i++) {
if (!storage->data[i]) {
index = i;
break;
}
}
/* We know that storage->capacity > storage->used, so there must be free
* slots */
assert(index >= 0);
storage->data[index] = RESERVED_PTR;
storage->used++;
tls->ogc.index = index;
tls->ogc.allocated = GLFW_TRUE;
return GLFW_TRUE;
}
void _glfwPlatformDestroyTls(_GLFWtls* tls)
{
if (tls->ogc.allocated) {
_GLFWthreadMapOgc *entry = storageEntryForThread();
if (entry) {
assert(entry->storage->capacity > tls->ogc.index);
assert(entry->storage->used > 0);
entry->storage->data[tls->ogc.index] = NULL;
entry->storage->used--;
}
}
memset(tls, 0, sizeof(_GLFWtls));
}
void* _glfwPlatformGetTls(_GLFWtls* tls)
{
assert(tls->ogc.allocated == GLFW_TRUE);
_GLFWthreadMapOgc *entry = storageEntryForThread();
void *ptr = entry->storage->data[tls->ogc.index];
return ptr == RESERVED_PTR ? NULL : ptr;
}
void _glfwPlatformSetTls(_GLFWtls* tls, void* value)
{
assert(tls->posix.allocated == GLFW_TRUE);
_GLFWthreadMapOgc *entry = storageEntryForThread();
entry->storage->data[tls->ogc.index] = value;
}
GLFWbool _glfwPlatformCreateMutex(_GLFWmutex* mutex)
{
assert(mutex->ogc.allocated == GLFW_FALSE);
if (LWP_MutexInit(&mutex->ogc.handle, false) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR, "OGC: Failed to create mutex");
return GLFW_FALSE;
}
return mutex->ogc.allocated = GLFW_TRUE;
}
void _glfwPlatformDestroyMutex(_GLFWmutex* mutex)
{
if (mutex->ogc.allocated)
LWP_MutexDestroy(mutex->ogc.handle);
memset(mutex, 0, sizeof(_GLFWmutex));
}
void _glfwPlatformLockMutex(_GLFWmutex* mutex)
{
assert(mutex->ogc.allocated == GLFW_TRUE);
LWP_MutexLock(mutex->ogc.handle);
}
void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
{
assert(mutex->ogc.allocated == GLFW_TRUE);
LWP_MutexUnlock(mutex->ogc.handle);
}
void _glfwThreadInitMutexOgc()
{
LWP_MutexInit(&threadMapMutex, false);
}
#endif // GLFW_BUILD_OGC_THREAD

49
src/ogc_thread.h Normal file
View File

@ -0,0 +1,49 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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 <ogc/mutex.h>
#define GLFW_OGC_TLS_STATE _GLFWtlsOgc ogc;
#define GLFW_OGC_MUTEX_STATE _GLFWmutexOgc ogc;
// POSIX-specific thread local storage data
//
typedef struct _GLFWtlsOgc
{
GLFWbool allocated;
int index;
} _GLFWtlsOgc;
// POSIX-specific mutex data
//
typedef struct _GLFWmutexOgc
{
GLFWbool allocated;
mutex_t handle;
} _GLFWmutexOgc;
void _glfwThreadInitMutexOgc();

52
src/ogc_time.c Normal file
View File

@ -0,0 +1,52 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#if defined(GLFW_BUILD_OGC_TIMER)
#include <ogc/lwp_watchdog.h>
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPlatformInitTimer(void)
{
}
uint64_t _glfwPlatformGetTimerValue(void)
{
return gettime();
}
uint64_t _glfwPlatformGetTimerFrequency(void)
{
return secs_to_ticks(1);
}
#endif // GLFW_BUILD_OGC_TIMER

28
src/ogc_time.h Normal file
View File

@ -0,0 +1,28 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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.
//
//========================================================================
#define GLFW_OGC_LIBRARY_TIMER_STATE

564
src/ogc_window.c Normal file
View File

@ -0,0 +1,564 @@
//========================================================================
// GLFW 3.5 OGC - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 Alberto Mardegan <info@mardy.it>
//
// 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.
//
//========================================================================
#define _GNU_SOURCE
#include "internal.h"
#if defined(_GLFW_OGC)
#include "ogc_cursor.h"
#include <assert.h>
#include <errno.h>
#include <malloc.h>
#include <opengx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiikeyboard/keyboard.h>
#ifdef __wii__
#include <wiiuse/wpad.h>
#endif
static void keysym_to_utf8(uint16_t symbol, char *utf8)
{
/* ignore private symbols, used by wiikeyboard for special keys */
if ((symbol >= 0xE000 && symbol <= 0xF8FF) || symbol == 0xFFFF)
return;
/* convert UCS-2 to UTF-8 */
if (symbol < 0x80) {
utf8[0] = symbol;
} else if (symbol < 0x800) {
utf8[0] = 0xC0 | (symbol >> 6);
utf8[1] = 0x80 | (symbol & 0x3F);
} else {
utf8[0] = 0xE0 | (symbol >> 12);
utf8[1] = 0x80 | ((symbol >> 6) & 0x3F);
utf8[2] = 0x80 | (symbol & 0x3F);
}
}
static void acquireMonitor(_GLFWwindow* window)
{
fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, __func__);
if (!window->monitor) {
window->monitor = _glfw.monitors[0];
}
_glfwInputMonitorWindow(window->monitor, window);
_glfwSetVideoModeOgc(window->monitor, &window->videoMode);
}
static void releaseMonitor(_GLFWwindow* window)
{
if (window->monitor->window != window)
return;
_glfwInputMonitorWindow(window->monitor, NULL);
}
/* Convert the RGBA pixels to the 4x4 tile ARGB texture used by GX */
static void setPixelToTextureARGB(char *texture, u32 offset, u32 color)
{
*(u16*)(texture + offset) = color >> 16;
*(u16*)(texture + offset + 32) = color;
}
static void setPixelToTextureRGBA(char *texture, u32 offset, u32 color)
{
setPixelToTextureARGB(texture, offset, (color << 24) | (color >> 8));
}
static void pixelsToTextureARGB(const void *pixels, s16 width, s16 height,
s16 pitch, void *texture)
{
s16 tex_pitch = (width + 3) / 4 * 4;
int row, col;
for (row = 0; row < height; row++) {
int y = row;
u32 *src = (u32 *)((u8 *)pixels + pitch * row);
for (col = 0; col < width; col++) {
int x = col;
u32 offset = (((y >> 2) << 4) * tex_pitch) +
((x >> 2) << 6) + (((y % 4 << 2) + x % 4) << 1);
setPixelToTextureRGBA(texture, offset, *src++);
}
}
}
static void* createRGBAtexture(const GLFWimage* image)
{
u32 textureSize;
void *texels;
textureSize = GX_GetTexBufferSize(image->width, image->height, GX_TF_RGBA8,
GX_FALSE, 0);
texels = memalign(32, textureSize);
if (!texels) {
_glfwInputError(GLFW_OUT_OF_MEMORY,
"OGC: Failed to allocate cursor texture");
return NULL;
}
pixelsToTextureARGB(image->pixels, image->width, image->height,
image->width * 4, texels);
DCStoreRange(texels, textureSize);
return texels;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwCreateWindowOgc(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
fprintf(stderr, "%s:%d %s %p\n", __FILE__, __LINE__, __func__, window);
acquireMonitor(window);
window->ogc.width = window->monitor->ogc.ogcMode->fbWidth;
window->ogc.height = window->monitor->ogc.ogcMode->efbHeight;
if (ctxconfig->client != GLFW_NO_API)
{
ogx_initialize();
if (!_glfwCreateContextOgc(window, ctxconfig, fbconfig))
return GLFW_FALSE;
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
/* Set the default Wii cursor */
GLFWcursor *cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR);
_glfwSetCursorOgc(window, (_GLFWcursor*) cursor);
return GLFW_TRUE;
}
void _glfwDestroyWindowOgc(_GLFWwindow* window)
{
if (window->monitor)
releaseMonitor(window);
}
void _glfwSetWindowTitleOgc(_GLFWwindow* window, const char* title)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the window title");
}
void _glfwSetWindowIconOgc(_GLFWwindow* window,
int count, const GLFWimage* images)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the window icon");
}
void _glfwGetWindowPosOgc(_GLFWwindow* window, int* xpos, int* ypos)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"getting the window position");
}
void _glfwSetWindowPosOgc(_GLFWwindow* window, int xpos, int ypos)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the window position");
}
void _glfwGetWindowSizeOgc(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->ogc.width;
if (height)
*height = window->ogc.height;
}
void _glfwSetWindowSizeOgc(_GLFWwindow* window, int width, int height)
{
fprintf(stderr, "%s:%d %s %dx%d\n", __FILE__, __LINE__, __func__, width, height);
if (window->monitor)
{
}
else
{
_glfwInputWindowDamage(window);
}
}
void _glfwSetWindowSizeLimitsOgc(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the size limits");
}
void _glfwSetWindowAspectRatioOgc(_GLFWwindow* window, int numer, int denom)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the aspect ratio");
}
void _glfwGetFramebufferSizeOgc(_GLFWwindow* window, int* width, int* height)
{
if (width)
*width = window->monitor->ogc.ogcMode->fbWidth;
if (height)
*height = window->monitor->ogc.ogcMode->efbHeight;;
}
void _glfwGetWindowFrameSizeOgc(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
*left = *top = *right = *bottom = 0;
}
void _glfwGetWindowContentScaleOgc(_GLFWwindow* window,
float* xscale, float* yscale)
{
if (xscale)
*xscale = 1.0f;
if (yscale)
*yscale = 1.0f;
}
void _glfwIconifyWindowOgc(_GLFWwindow* window)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"iconifying the window");
}
void _glfwRestoreWindowOgc(_GLFWwindow* window)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"restoring the window");
}
void _glfwMaximizeWindowOgc(_GLFWwindow* window)
{
}
void _glfwShowWindowOgc(_GLFWwindow* window)
{
}
void _glfwHideWindowOgc(_GLFWwindow* window)
{
}
void _glfwRequestWindowAttentionOgc(_GLFWwindow* window)
{
}
void _glfwFocusWindowOgc(_GLFWwindow* window)
{
}
void _glfwSetWindowMonitorOgc(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
}
GLFWbool _glfwWindowFocusedOgc(_GLFWwindow* window)
{
return GLFW_TRUE;
}
GLFWbool _glfwWindowIconifiedOgc(_GLFWwindow* window)
{
return GLFW_FALSE;
}
GLFWbool _glfwWindowVisibleOgc(_GLFWwindow* window)
{
return GLFW_TRUE;
}
GLFWbool _glfwWindowMaximizedOgc(_GLFWwindow* window)
{
return GLFW_TRUE;
}
GLFWbool _glfwWindowHoveredOgc(_GLFWwindow* window)
{
return window->ogc.hovered;
}
GLFWbool _glfwFramebufferTransparentOgc(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwSetWindowResizableOgc(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwSetWindowDecoratedOgc(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwSetWindowFloatingOgc(_GLFWwindow* window, GLFWbool enabled)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"making a window floating");
}
void _glfwSetWindowMousePassthroughOgc(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwGetWindowOpacityOgc(_GLFWwindow* window)
{
return 1.f;
}
void _glfwSetWindowOpacityOgc(_GLFWwindow* window, float opacity)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the window opacity");
}
void _glfwSetRawMouseMotionOgc(_GLFWwindow* window, GLFWbool enabled)
{
}
GLFWbool _glfwRawMouseMotionSupportedOgc(void)
{
return GLFW_FALSE;
}
#ifdef __wii__
static void handleWiimoteCursorOgc(_GLFWwindow* window)
{
WPADData *data = WPAD_Data(0);
float x, y;
GLFWbool mouseActive = !!data->ir.valid;
if (mouseActive != window->ogc.hovered) {
window->ogc.hovered = mouseActive;
_glfwInputCursorEnter(window, mouseActive);
}
if (!mouseActive) return;
x = data->ir.x * window->ogc.width / data->ir.vres[0];
y = data->ir.y * window->ogc.height / data->ir.vres[1];
_glfwInputCursorPos(window, x, y);
if (data->btns_d & WPAD_BUTTON_A)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_1, GLFW_PRESS, 0);
if (data->btns_u & WPAD_BUTTON_A)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_1, GLFW_RELEASE, 0);
if (data->btns_d & WPAD_BUTTON_B)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_2, GLFW_PRESS, 0);
if (data->btns_u & WPAD_BUTTON_B)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_2, GLFW_RELEASE, 0);
}
#endif
void _glfwPollEventsOgc(void)
{
//fprintf(stderr, "Polling for events %d\n", 0);
GLFWbool hasEvents = GLFW_FALSE;
if (_glfwPollJoysticksOgc()) {
hasEvents = GLFW_TRUE;
#ifdef __wii__
/* Use the first wiimote as mouse */
if (_glfw.windowListHead)
handleWiimoteCursorOgc(_glfw.windowListHead);
#endif
}
}
void _glfwWaitEventsOgc(void)
{
// TODO: check if events were produced or sleep?
_glfwPollEventsOgc();
}
void _glfwWaitEventsTimeoutOgc(double timeout)
{
// TODO: check if events were produced or sleep?
_glfwPollEventsOgc();
}
void _glfwPostEmptyEventOgc(void)
{
}
void _glfwGetCursorPosOgc(_GLFWwindow* window, double* xpos, double* ypos)
{
if (xpos)
*xpos = window->virtualCursorPosX;
if (ypos)
*ypos = window->virtualCursorPosY;
}
void _glfwSetCursorPosOgc(_GLFWwindow* window, double x, double y)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE, _glfwUnimplementedFmt,
"setting the cursor position");
}
void _glfwSetCursorModeOgc(_GLFWwindow* window, int mode)
{
// TODO
}
const char* _glfwGetScancodeNameOgc(int scancode)
{
static char name[10];
name[0] = name[1] = '\0';
switch (scancode) {
case KS_Return: name[0] = '\n'; break;
case KS_Escape: return "ESC";
default:
keysym_to_utf8(scancode, name);
}
return name;
}
int _glfwGetKeyScancodeOgc(int key)
{
return _glfw.ogc.scancodes[key];
}
GLFWbool _glfwCreateCursorOgc(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
void* texels = createRGBAtexture(image);
if (!texels) return GLFW_FALSE;
cursor->ogc.xhot = xhot;
cursor->ogc.yhot = yhot;
GX_InvalidateTexAll();
GX_InitTexObj(&cursor->ogc.texobj, texels,
image->width, image->height,
GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
GX_InitTexObjLOD(&cursor->ogc.texobj, GX_LINEAR, GX_LINEAR,
0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
return GLFW_TRUE;
}
GLFWbool _glfwCreateStandardCursorOgc(_GLFWcursor* cursor, int shape)
{
const _GLFWcursorDataOgc* cd = NULL;
switch (shape)
{
case GLFW_ARROW_CURSOR:
cd = &OGC_cursor_arrow;
break;
case GLFW_POINTING_HAND_CURSOR:
cd = &OGC_cursor_hand;
break;
default:
return GLFW_FALSE;
}
GLFWimage image = {
cd->width, cd->height, cd->pixel_data
};
return _glfwCreateCursorOgc(cursor, &image,
cd->hot_x, cd->hot_y);
}
void _glfwDestroyCursorOgc(_GLFWcursor* cursor)
{
void *data = GX_GetTexObjData(&cursor->ogc.texobj);
if (data != 0)
free(MEM_PHYSICAL_TO_K0(data));
}
void _glfwSetCursorOgc(_GLFWwindow* window, _GLFWcursor* cursor)
{
window->ogc.currentCursor = cursor;
}
void _glfwSetClipboardStringOgc(const char* string)
{
}
const char* _glfwGetClipboardStringOgc(void)
{
return NULL;
}
EGLenum _glfwGetEGLPlatformOgc(EGLint** attribs)
{
return EGL_PLATFORM_ANGLE_ANGLE;
}
EGLNativeDisplayType _glfwGetEGLNativeDisplayOgc(void)
{
return EGL_DEFAULT_DISPLAY;
}
EGLNativeWindowType _glfwGetEGLNativeWindowOgc(_GLFWwindow* window)
{
return 0;
}
void _glfwGetRequiredInstanceExtensionsOgc(char** extensions)
{
}
GLFWbool _glfwGetPhysicalDevicePresentationSupportOgc(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_FALSE;
}
VkResult _glfwCreateWindowSurfaceOgc(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
#endif // _GLFW_OGC

View File

@ -56,6 +56,9 @@ static const struct
#if defined(_GLFW_X11)
{ GLFW_PLATFORM_X11, _glfwConnectX11 },
#endif
#if defined(_GLFW_OGC)
{ GLFW_PLATFORM_OGC, _glfwConnectOgc },
#endif
};
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
@ -68,6 +71,7 @@ GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
desiredID != GLFW_PLATFORM_COCOA &&
desiredID != GLFW_PLATFORM_WAYLAND &&
desiredID != GLFW_PLATFORM_X11 &&
desiredID != GLFW_PLATFORM_OGC &&
desiredID != GLFW_PLATFORM_NULL)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", desiredID);

View File

@ -29,6 +29,8 @@
defined(GLFW_BUILD_WIN32_MODULE) || \
defined(GLFW_BUILD_WIN32_THREAD) || \
defined(GLFW_BUILD_COCOA_TIMER) || \
defined(GLFW_BUILD_OGC_MODULE) || \
defined(GLFW_BUILD_OGC_THREAD) || \
defined(GLFW_BUILD_POSIX_TIMER) || \
defined(GLFW_BUILD_POSIX_MODULE) || \
defined(GLFW_BUILD_POSIX_THREAD) || \
@ -90,6 +92,16 @@
#define GLFW_GLX_LIBRARY_CONTEXT_STATE
#endif
#if defined(_GLFW_OGC)
#include "ogc_platform.h"
#define GLFW_EXPOSE_NATIVE_OGC
#else
#define GLFW_OGC_WINDOW_STATE
#define GLFW_OGC_MONITOR_STATE
#define GLFW_OGC_CURSOR_STATE
#define GLFW_OGC_LIBRARY_WINDOW_STATE
#endif
#include "null_joystick.h"
#if defined(_GLFW_WIN32)
@ -106,6 +118,13 @@
#define GLFW_COCOA_LIBRARY_JOYSTICK_STATE
#endif
#if defined(_GLFW_OGC)
#include "ogc_joystick.h"
#else
#define GLFW_OGC_JOYSTICK_STATE
#define GLFW_OGC_LIBRARY_JOYSTICK_STATE
#endif
#if (defined(_GLFW_X11) || defined(_GLFW_WAYLAND)) && defined(__linux__)
#define GLFW_BUILD_LINUX_JOYSTICK
#endif
@ -123,6 +142,7 @@
GLFW_WAYLAND_WINDOW_STATE \
GLFW_X11_WINDOW_STATE \
GLFW_NULL_WINDOW_STATE \
GLFW_OGC_WINDOW_STATE \
#define GLFW_PLATFORM_MONITOR_STATE \
GLFW_WIN32_MONITOR_STATE \
@ -130,6 +150,7 @@
GLFW_WAYLAND_MONITOR_STATE \
GLFW_X11_MONITOR_STATE \
GLFW_NULL_MONITOR_STATE \
GLFW_OGC_MONITOR_STATE \
#define GLFW_PLATFORM_CURSOR_STATE \
GLFW_WIN32_CURSOR_STATE \
@ -137,11 +158,13 @@
GLFW_WAYLAND_CURSOR_STATE \
GLFW_X11_CURSOR_STATE \
GLFW_NULL_CURSOR_STATE \
GLFW_OGC_CURSOR_STATE \
#define GLFW_PLATFORM_JOYSTICK_STATE \
GLFW_WIN32_JOYSTICK_STATE \
GLFW_COCOA_JOYSTICK_STATE \
GLFW_LINUX_JOYSTICK_STATE
GLFW_LINUX_JOYSTICK_STATE \
GLFW_OGC_JOYSTICK_STATE \
#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \
GLFW_WIN32_LIBRARY_WINDOW_STATE \
@ -149,11 +172,13 @@
GLFW_WAYLAND_LIBRARY_WINDOW_STATE \
GLFW_X11_LIBRARY_WINDOW_STATE \
GLFW_NULL_LIBRARY_WINDOW_STATE \
GLFW_OGC_LIBRARY_WINDOW_STATE \
#define GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
GLFW_WIN32_LIBRARY_JOYSTICK_STATE \
GLFW_COCOA_LIBRARY_JOYSTICK_STATE \
GLFW_LINUX_LIBRARY_JOYSTICK_STATE
GLFW_LINUX_LIBRARY_JOYSTICK_STATE \
GLFW_OGC_LIBRARY_JOYSTICK_STATE \
#define GLFW_PLATFORM_CONTEXT_STATE \
GLFW_WGL_CONTEXT_STATE \
@ -167,6 +192,8 @@
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_THREAD
#elif defined(_GLFW_OGC)
#define GLFW_BUILD_OGC_THREAD
#else
#define GLFW_BUILD_POSIX_THREAD
#endif
@ -179,12 +206,18 @@
#include "posix_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_POSIX_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_POSIX_MUTEX_STATE
#elif defined(GLFW_BUILD_OGC_THREAD)
#include "ogc_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_OGC_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_OGC_MUTEX_STATE
#endif
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_TIMER
#elif defined(__APPLE__)
#define GLFW_BUILD_COCOA_TIMER
#elif defined(_GLFW_OGC)
#define GLFW_BUILD_OGC_TIMER
#else
#define GLFW_BUILD_POSIX_TIMER
#endif
@ -198,10 +231,15 @@
#elif defined(GLFW_BUILD_POSIX_TIMER)
#include "posix_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_POSIX_LIBRARY_TIMER_STATE
#elif defined(GLFW_BUILD_OGC_TIMER)
#include "ogc_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_OGC_LIBRARY_TIMER_STATE
#endif
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_MODULE
#elif defined(__wii__) || defined(__gamecube)
#define GLFW_BUILD_OGC_MODULE
#else
#define GLFW_BUILD_POSIX_MODULE
#endif

View File

@ -41,8 +41,10 @@ add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD_GL})
add_executable(triangle-vulkan WIN32 triangle-vulkan.c ${GLAD_VULKAN})
add_executable(window WIN32 MACOSX_BUNDLE window.c ${GLAD_GL})
target_link_libraries(empty Threads::Threads)
target_link_libraries(threads Threads::Threads)
if (Threads_FOUND)
target_link_libraries(empty Threads::Threads)
target_link_libraries(threads Threads::Threads)
endif()
if (RT_LIBRARY)
target_link_libraries(empty "${RT_LIBRARY}")
target_link_libraries(threads "${RT_LIBRARY}")