OGC: video, joystick, keyboard and mouse support

pull/168/head
Alberto Mardegan 2024-04-25 23:04:31 +03:00 committed by John Tsiombikas
parent 0a940376ba
commit 0e9258a1f8
9 changed files with 437 additions and 20 deletions

View File

@ -214,6 +214,7 @@ ELSEIF(CMAKE_SYSTEM_NAME MATCHES "NintendoWii|NintendoGameCube")
src/ogc/fg_structure_ogc.c
src/ogc/fg_window_ogc.c
)
LIST(APPEND LIBS wiikeyboard fat)
SET(FREEGLUT_BUILD_SHARED_LIBS OFF)
# Only used in fg_window.c, to declare support for double buffering
ADD_DEFINITIONS(-DEGL_VERSION_1_0)

View File

@ -25,4 +25,21 @@
#include <GL/freeglut.h>
#include "../fg_internal.h"
#define MAX_GC_JOYSTICKS 4
#ifdef __wii__
#define MAX_WII_JOYSTICKS 4
#else
#define MAX_WII_JOYSTICKS 0
#endif
#define MAX_OGC_JOYSTICKS (MAX_GC_JOYSTICKS + MAX_WII_JOYSTICKS)
extern void fghOnReshapeNotify(SFG_Window *window, int width, int height,
GLboolean forceNotify);
void fgOgcDisplaySetupVideoMode();
void fgOgcDisplaySetupXfb();
void fgOgcDisplayShowEFB();
#endif /* FREEGLUT_COMMON_OGC_H */

View File

@ -21,8 +21,83 @@
#include "fg_common_ogc.h"
void fgOgcDisplaySetupXfb()
{
GXRModeObj *vmode = fgDisplay.pDisplay.vmode;
if (fgDisplay.pDisplay.vmode_changed) {
/* The size of the XFB might be different, so reallocate it */
if (fgDisplay.pDisplay.xfb[0]) {
free(MEM_K1_TO_K0(fgDisplay.pDisplay.xfb[0]));
fgDisplay.pDisplay.xfb[0] = NULL;
}
if (fgDisplay.pDisplay.xfb[1]) {
free(MEM_K1_TO_K0(fgDisplay.pDisplay.xfb[1]));
fgDisplay.pDisplay.xfb[1] = NULL;
}
}
if (!fgDisplay.pDisplay.xfb[0]) {
fgDisplay.pDisplay.xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
}
if (fgState.DisplayMode & GLUT_DOUBLE && !fgDisplay.pDisplay.xfb[1]) {
fgDisplay.pDisplay.xfb[1] =
MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode));
}
}
void fgOgcDisplaySetupVideoMode()
{
GXRModeObj *vmode = fgDisplay.pDisplay.vmode;
fgOgcDisplaySetupXfb();
VIDEO_Configure(vmode);
VIDEO_SetNextFramebuffer(fgDisplay.pDisplay.xfb[0]);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
f32 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);
fgDisplay.ScreenWidth = vmode->fbWidth;
fgDisplay.ScreenHeight = vmode->efbHeight;
fgDisplay.pDisplay.vmode_changed = 0;
}
void fgOgcDisplayShowEFB()
{
void *xfb;
u8 mustClear, mustWait;
if (fgState.DisplayMode & GLUT_DOUBLE) {
mustClear = GX_TRUE;
mustWait = GX_TRUE;
xfb = fgDisplay.pDisplay.xfb[fgDisplay.pDisplay.fbIndex];
fgDisplay.pDisplay.fbIndex ^= 1;
} else {
mustClear = GX_FALSE;
mustWait = GX_FALSE;
xfb = fgDisplay.pDisplay.xfb[0];
}
GX_CopyDisp(xfb, mustClear);
GX_DrawDone();
GX_Flush();
VIDEO_SetNextFramebuffer(xfb);
VIDEO_Flush();
if (mustWait)
VIDEO_WaitVSync();
}
void fgPlatformGlutSwapBuffers(SFG_PlatformDisplay *pDisplayPtr,
SFG_Window *CurrentWindow)
{
fgWarning("%s() : not implemented", __func__);
fgOgcDisplayShowEFB();
}

View File

@ -23,13 +23,19 @@
SFG_Proc fgPlatformGetProcAddress(const char *procName)
{
fgWarning("%s() : not implemented", __func__);
#define CHECK_NAME(x) if (strcmp(procName, #x) == 0) return (SFG_Proc)x
/* TODO: add functions here */
#undef CHECK_NAME
fgWarning("%s() : not implemented (%s)", __func__, procName);
return NULL;
}
GLUTproc fgPlatformGetGLUTProcAddress(const char *procName)
{
fgWarning("%s() : not implemented", __func__);
if (strncmp(procName, "glut", 4) != 0)
return NULL;
fgWarning("%s() : not implemented (%s)", __func__, procName);
return NULL;
}

View File

@ -21,9 +21,30 @@
#include "fg_common_ogc.h"
#include <fat.h>
#include <malloc.h>
#include <opengx.h>
#define FIFO_SIZE (256*1024)
void fgPlatformInitialize(const char *displayName)
{
fgWarning("%s() : not implemented", __func__);
VIDEO_Init();
void *fifoBuffer = MEM_K0_TO_K1(memalign(32, FIFO_SIZE));
memset(fifoBuffer, 0, FIFO_SIZE);
GX_Init(fifoBuffer, FIFO_SIZE);
fgDisplay.pDisplay.vmode = VIDEO_GetPreferredMode(NULL);
fgOgcDisplaySetupVideoMode();
ogx_initialize();
fatInitDefault();
fgState.Time = fgSystemTime();
fgState.FPSInterval = 2000;
fgState.Initialised = GL_TRUE;
}
void fgPlatformDeinitialiseInputDevices(void)

View File

@ -23,14 +23,22 @@
#define FREEGLUT_INTERNAL_OGC_H
/* -- PLATFORM-SPECIFIC INCLUDES ------------------------------------------- */
/* TODO: add libogc and opengx */
#include <ogc/gx.h>
#include <ogc/gx_struct.h>
#include <ogc/system.h>
#include <ogc/video.h>
/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */
/* The structure used by display initialization in fg_init.c */
typedef struct tagSFG_PlatformDisplay SFG_PlatformDisplay;
struct tagSFG_PlatformDisplay
{
bool unused;
/* The pointer(s) to the XFB(s). The second one can be NULL if double
* buffering is not used. */
void *xfb[2];
u8 fbIndex;
bool vmode_changed;
GXRModeObj *vmode;
};
/* The structure used by window creation in fg_window.c */
@ -67,6 +75,7 @@ typedef uint32_t SFG_WindowColormapType;
#define FREEGLUT_MENU_PEN_HFORE_COLORS {0.0f, 0.0f, 0.0f, 1.0f}
#define FREEGLUT_MENU_PEN_HBACK_COLORS {1.0f, 1.0f, 1.0f, 1.0f}
#define _JS_MAX_AXES 9
#define _JS_MAX_AXES 4
#define MAX_NUM_JOYSTICKS 8
#endif /* FREEGLUT_INTERNAL_OGC_H */

View File

@ -21,19 +21,93 @@
#include "fg_common_ogc.h"
#include <wiiuse/wpad.h>
void fgPlatformJoystickRawRead(SFG_Joystick *joy, int *buttons, float *axes)
{
fgWarning("%s() : not implemented", __func__);
*buttons = 0;
if (joy->id < MAX_GC_JOYSTICKS) {
u16 btns = PAD_ButtonsHeld(joy->id);
if (btns & PAD_BUTTON_A) *buttons |= 0x1;
if (btns & PAD_BUTTON_B) *buttons |= 0x2;
if (btns & PAD_BUTTON_X) *buttons |= 0x4;
if (btns & PAD_BUTTON_Y) *buttons |= 0x8;
if (btns & PAD_TRIGGER_L) *buttons |= 0x10;
if (btns & PAD_TRIGGER_R) *buttons |= 0x20;
if (btns & PAD_TRIGGER_Z) *buttons |= 0x40;
if (btns & PAD_BUTTON_MENU) *buttons |= 0x80;
if (btns & PAD_BUTTON_START) *buttons |= 0x100;
axes[0] = PAD_StickX(joy->id) / 127.0;
axes[1] = PAD_StickY(joy->id) / 127.0;
axes[2] = PAD_SubStickX(joy->id) / 127.0;
axes[3] = PAD_SubStickY(joy->id) / 127.0;
return;
}
#ifdef __wii__
int id = joy->id - MAX_GC_JOYSTICKS;
if (id < MAX_WII_JOYSTICKS) {
WPADData *data = WPAD_Data(id);
u32 btns = data->btns_h;
axes[0] = 0.0;
axes[1] = 0.0;
if (btns & WPAD_BUTTON_LEFT) axes[0] = -1.0;
if (btns & WPAD_BUTTON_RIGHT) axes[0] = 1.0;
if (btns & WPAD_BUTTON_UP) axes[1] = 1.0;
if (btns & WPAD_BUTTON_DOWN) axes[1] = -1.0;
if (btns & WPAD_BUTTON_1) *buttons |= 0x1;
if (btns & WPAD_BUTTON_2) *buttons |= 0x2;
if (btns & WPAD_BUTTON_A) *buttons |= 0x4;
if (btns & WPAD_BUTTON_B) *buttons |= 0x8;
if (btns & WPAD_BUTTON_MINUS) *buttons |= 0x10;
if (btns & WPAD_BUTTON_PLUS) *buttons |= 0x20;
if (btns & WPAD_BUTTON_HOME) *buttons |= 0x40;
}
#endif
}
void fgPlatformJoystickOpen(SFG_Joystick *joy)
{
fgWarning("%s() : not implemented", __func__);
fgWarning("%s() called for joystick %d", __func__, joy->id);
joy->error = GL_FALSE;
if (joy->id < MAX_GC_JOYSTICKS) {
sprintf(joy->name, "GameCube #%d", joy->id);
joy->num_axes = 4;
joy->num_buttons = 8;
} else {
sprintf(joy->name, "Wiimote #%d", joy->id - MAX_GC_JOYSTICKS);
joy->num_axes = 2;
joy->num_buttons = 7;
}
for (int i = 0; i < joy->num_axes; i++) {
joy->center[i] = 0.0;
joy->max[i] = 1.0;
joy->min[i] = -1.0;
joy->dead_band[i] = 0.0;
joy->saturate[i] = 1.0;
}
}
void fgPlatformJoystickInit(SFG_Joystick *fgJoystick[], int ident)
{
fgWarning("%s() : not implemented", __func__);
static bool initialized = false;
if (!initialized) {
initialized = true;
PAD_Init();
/* WPAD is initialized in fgPlatformMainLoopPreliminaryWork(), since
* it's used for mouse emulation as well. */
}
fgWarning("%s called for ident %d\n", __func__, ident);
if (ident < MAX_OGC_JOYSTICKS) {
SFG_Joystick *joy = fgJoystick[ident];
joy->id = ident;
joy->error = GL_FALSE;
}
}
void fgPlatformJoystickClose(int ident)

View File

@ -21,30 +21,234 @@
#include "fg_common_ogc.h"
fg_time_t fgPlatformSystemTime(void)
#include <ogc/lwp_watchdog.h>
#include <wiikeyboard/keyboard.h>
#include <wiiuse/wpad.h>
extern SFG_Joystick *fgJoystick[MAX_OGC_JOYSTICKS];
static void keysym_to_utf8(uint16_t symbol, char *utf8)
{
fgWarning("%s() : not implemented", __func__);
return 0;
/* 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);
}
}
void fgPlatformSleepForEvents(fg_time_t msec)
static void processKeyboardEvent()
{
fgWarning("%s() : not implemented", __func__);
SFG_Window* window = fgStructure.CurrentWindow;
FGCBKeyboardUC keyboard_cb;
FGCBSpecialUC special_cb;
FGCBUserData keyboard_ud;
FGCBUserData special_ud;
char string[4] = {'\0'};
int special = -1;
keyboard_event ke;
s32 res = KEYBOARD_GetEvent(&ke);
if (!res || (ke.type != KEYBOARD_RELEASED && ke.type != KEYBOARD_PRESSED))
return;
if (ke.type == KEYBOARD_PRESSED) {
fprintf(stderr, "Key pressed 0x%04x\n", (int)ke.symbol);
keyboard_cb = (FGCBKeyboardUC)(FETCH_WCB(*window, Keyboard));
special_cb = (FGCBSpecialUC)(FETCH_WCB(*window, Special));
keyboard_ud = FETCH_USER_DATA_WCB(*window, Keyboard);
special_ud = FETCH_USER_DATA_WCB(*window, Special);
} else {
keyboard_cb = (FGCBKeyboardUC)(FETCH_WCB(*window, KeyboardUp));
special_cb = (FGCBSpecialUC)(FETCH_WCB(*window, SpecialUp));
keyboard_ud = FETCH_USER_DATA_WCB(*window, KeyboardUp);
special_ud = FETCH_USER_DATA_WCB(*window, SpecialUp);
}
switch (ke.symbol) {
case KS_Up: special = GLUT_KEY_UP; break;
case KS_Down: special = GLUT_KEY_DOWN; break;
case KS_Left: special = GLUT_KEY_LEFT; break;
case KS_Right: special = GLUT_KEY_RIGHT; break;
case KS_Prior: special = GLUT_KEY_PAGE_UP; break;
case KS_Next: special = GLUT_KEY_PAGE_DOWN; break;
case KS_Home: special = GLUT_KEY_HOME; break;
case KS_End: special = GLUT_KEY_END; break;
case KS_Insert: special = GLUT_KEY_INSERT; break;
}
if (special == -1) {
if (ke.symbol >= KS_F1 && ke.symbol <= KS_F12) {
special = ke.symbol + GLUT_KEY_F1 - KS_F1;
} else if (ke.symbol >= KS_f1 && ke.symbol <= KS_f12) {
special = ke.symbol + GLUT_KEY_F1 - KS_f1;
}
}
if (special_cb && special != -1) {
special_cb(special, window->State.MouseX, window->State.MouseY, special_ud);
} else if (keyboard_cb && special == -1) {
unsigned char key = 0;
switch (ke.symbol) {
case KS_Return: key = '\n'; break;
case KS_Escape: key = 27; break;
default:
keysym_to_utf8(ke.symbol, string);
key = string[0];
}
keyboard_cb(key, window->State.MouseX, window->State.MouseY, keyboard_ud);
}
}
static void updateJoysticks()
{
static u32 lastScanPads = 0;
if (fgState.JoysticksInitialised) {
lastScanPads = PAD_ScanPads();
for (int i = 0; i < MAX_GC_JOYSTICKS; i++) {
SFG_Joystick *joy = fgJoystick[i];
joy->error = !(lastScanPads & (1 << joy->id));
}
}
#ifdef __wii__
/* The WPAD data is also used for the mouse, so we read it even if
* joysticks haven't been initialized */
WPAD_ScanPads();
WPAD_ReadPending(WPAD_CHAN_ALL, NULL);
if (fgState.JoysticksInitialised) {
for (int i = 0; i < MAX_WII_JOYSTICKS; i++) {
SFG_Joystick *joy = fgJoystick[i + MAX_GC_JOYSTICKS];
WPADData *data = WPAD_Data(i);
joy->error = data->err != WPAD_ERR_NONE || !data->data_present;
}
}
#endif
}
/* We don't have a mouse-like device we can use on the GameCube. On the Wii,
* we'll use the first WiiMote IR. */
#ifdef __wii__
#define MAX_WII_MOUSE_BUTTONS 2
static const struct {
int wii;
int mouse;
} s_mouse_button_map[MAX_WII_MOUSE_BUTTONS] = {
{ WPAD_BUTTON_B, GLUT_LEFT_BUTTON },
{ WPAD_BUTTON_A, GLUT_RIGHT_BUTTON },
};
static void updateMouse()
{
int oldX, oldY;
WPADData *data = WPAD_Data(0);
SFG_Window *window = fgStructure.CurrentWindow;
if (!window) return;
oldX = window->State.MouseX;
oldY = window->State.MouseY;
window->State.MouseX = data->ir.x * fgDisplay.ScreenWidth / 640;
window->State.MouseY = data->ir.y * fgDisplay.ScreenHeight / 480;
bool buttonPressed = false;
for (int b = 0; b < MAX_WII_MOUSE_BUTTONS; b++) {
if (data->btns_d & s_mouse_button_map[b].wii) {
INVOKE_WCB(*window, Mouse,
(s_mouse_button_map[b].mouse,
GLUT_DOWN,
window->State.MouseX,
window->State.MouseY)
);
}
if (data->btns_u & s_mouse_button_map[b].wii) {
INVOKE_WCB(*window, Mouse,
(s_mouse_button_map[b].mouse,
GLUT_UP,
window->State.MouseX,
window->State.MouseY)
);
buttonPressed = true;
}
if (data->btns_h & s_mouse_button_map[b].wii) {
buttonPressed = true;
}
}
if (oldX != window->State.MouseX || oldY != window->State.MouseY) {
if (buttonPressed) {
INVOKE_WCB(*window, Motion, (window->State.MouseX,
window->State.MouseY));
} else {
INVOKE_WCB(*window, Passive, (window->State.MouseX,
window->State.MouseY));
}
}
}
#endif
fg_time_t fgPlatformSystemTime(void)
{
return gettime() / TB_TIMER_CLOCK;
}
void fgPlatformSleepForEvents(fg_time_t ms)
{
fgWarning("%s() : sleeping for %lld ms", __func__, ms);
/* FreeGlut does not offer a hook for redrawing the window in single-buffer
* mode, so let's to it here. */
if (!(fgState.DisplayMode & GLUT_DOUBLE)) {
fgOgcDisplayShowEFB();
}
struct timespec tv;
tv.tv_sec = ms / 1000;
tv.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&tv, NULL);
}
void fgPlatformProcessSingleEvent(void)
{
fgWarning("%s() : not implemented", __func__);
/* If an idle callback is specified, then fgPlatformSleepForEvents is not
* called, so we must find another place to render our scene (if using a
* single buffer). Let's do it here. */
if (fgState.IdleCallback && !(fgState.DisplayMode & GLUT_DOUBLE)) {
fgOgcDisplayShowEFB();
}
processKeyboardEvent();
updateJoysticks();
#ifdef __wii__
updateMouse();
#endif
}
void fgPlatformMainLoopPreliminaryWork(void)
{
fgWarning("%s() : not implemented", __func__);
fgWarning("%s()", __func__);
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
}
void fgPlatformInitWork(SFG_Window *window)
{
fgWarning("%s() : not implemented", __func__);
fghOnReshapeNotify(window,
fgDisplay.ScreenWidth, fgDisplay.ScreenHeight,
GL_FALSE);
}
void fgPlatformPosResZordWork(SFG_Window *window, unsigned int workMask)

View File

@ -23,7 +23,6 @@
void fgPlatformSetWindow(SFG_Window *window)
{
fgWarning("%s() : not implemented", __func__);
}
void fgPlatformOpenWindow(SFG_Window *window, const char *title,
@ -31,7 +30,18 @@ void fgPlatformOpenWindow(SFG_Window *window, const char *title,
GLboolean sizeUse, int w, int h,
GLboolean gameMode, GLboolean isSubWindow)
{
fgWarning("%s() : not implemented", __func__);
fgWarning("%s(): %d,%d - %dx%d", __func__, x, y, w, h);
/* We always ignore the requested size, we only support fullscreen windows
*/
window->State.IsFullscreen = GL_TRUE;
window->State.Xpos = 0;
window->State.Ypos = 0;
window->State.WorkMask |= GLUT_INIT_WORK;
window->State.Visible = GL_TRUE;
/* This sets up the XFB for the chosen buffering scheme */
fgOgcDisplaySetupXfb();
}
void fgPlatformReshapeWindow(SFG_Window *window, int width, int height)