diff --git a/CMakeLists.txt b/CMakeLists.txt index 398b36eb..86c92acb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/deps/tinycthread.c b/deps/tinycthread.c index f9cea2ed..f77b20a1 100644 --- a/deps/tinycthread.c +++ b/deps/tinycthread.c @@ -40,6 +40,8 @@ freely, subject to the following restrictions: #elif defined(_TTHREAD_WIN32_) #include #include +#elif defined(_TTHREAD_OGC_) + #include #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 diff --git a/deps/tinycthread.h b/deps/tinycthread.h index 42958c39..ee8d5f13 100644 --- a/deps/tinycthread.h +++ b/deps/tinycthread.h @@ -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 #include +#elif defined(_TTHREAD_OGC_) + #include #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 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e7a03797..269f9ab2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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() diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 79b06288..bca207be 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1a085b2b..bb325797 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/mappings.h b/src/mappings.h index cd32e5d0..f87de297 100644 --- a/src/mappings.h +++ b/src/mappings.h @@ -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 }; diff --git a/src/mappings.h.in b/src/mappings.h.in index 99d18330..224ec922 100644 --- a/src/mappings.h.in +++ b/src/mappings.h.in @@ -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 }; diff --git a/src/ogc_context.c b/src/ogc_context.c new file mode 100644 index 00000000..0be00e92 --- /dev/null +++ b/src/ogc_context.c @@ -0,0 +1,204 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include +#include +#include +#ifdef __wii__ +#include +#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; +} + diff --git a/src/ogc_cursor.h b/src/ogc_cursor.h new file mode 100644 index 00000000..a374dee4 --- /dev/null +++ b/src/ogc_cursor.h @@ -0,0 +1,487 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 + +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", +}; + diff --git a/src/ogc_init.c b/src/ogc_init.c new file mode 100644 index 00000000..6e4a679b --- /dev/null +++ b/src/ogc_init.c @@ -0,0 +1,161 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + diff --git a/src/ogc_joystick.c b/src/ogc_joystick.c new file mode 100644 index 00000000..38a48ed7 --- /dev/null +++ b/src/ogc_joystick.c @@ -0,0 +1,417 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include +#include +#ifdef __wii__ +#include +#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 + diff --git a/src/ogc_joystick.h b/src/ogc_joystick.h new file mode 100644 index 00000000..9bb3522c --- /dev/null +++ b/src/ogc_joystick.h @@ -0,0 +1,64 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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); + diff --git a/src/ogc_module.c b/src/ogc_module.c new file mode 100644 index 00000000..30249c45 --- /dev/null +++ b/src/ogc_module.c @@ -0,0 +1,50 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 + diff --git a/src/ogc_monitor.c b/src/ogc_monitor.c new file mode 100644 index 00000000..43b0c4e4 --- /dev/null +++ b/src/ogc_monitor.c @@ -0,0 +1,248 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include +#include +#include + +#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 diff --git a/src/ogc_platform.h b/src/ogc_platform.h new file mode 100644 index 00000000..4b07dffb --- /dev/null +++ b/src/ogc_platform.h @@ -0,0 +1,252 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include + +#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); + diff --git a/src/ogc_thread.c b/src/ogc_thread.c new file mode 100644 index 00000000..f5246e11 --- /dev/null +++ b/src/ogc_thread.c @@ -0,0 +1,237 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include + +#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 + diff --git a/src/ogc_thread.h b/src/ogc_thread.h new file mode 100644 index 00000000..da4cd896 --- /dev/null +++ b/src/ogc_thread.h @@ -0,0 +1,49 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 + +#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(); diff --git a/src/ogc_time.c b/src/ogc_time.c new file mode 100644 index 00000000..31929f95 --- /dev/null +++ b/src/ogc_time.c @@ -0,0 +1,52 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 + +////////////////////////////////////////////////////////////////////////// +////// 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 + diff --git a/src/ogc_time.h b/src/ogc_time.h new file mode 100644 index 00000000..66b0b0a4 --- /dev/null +++ b/src/ogc_time.h @@ -0,0 +1,28 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 + diff --git a/src/ogc_window.c b/src/ogc_window.c new file mode 100644 index 00000000..d754af2c --- /dev/null +++ b/src/ogc_window.c @@ -0,0 +1,564 @@ +//======================================================================== +// GLFW 3.5 OGC - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2024 Alberto Mardegan +// +// 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef __wii__ +#include +#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 diff --git a/src/platform.c b/src/platform.c index 9ca64963..c900d45a 100644 --- a/src/platform.c +++ b/src/platform.c @@ -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); diff --git a/src/platform.h b/src/platform.h index 7ce4e015..d943e8af 100644 --- a/src/platform.h +++ b/src/platform.h @@ -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 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f81cfeb9..23c1d1e0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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}")