gnuboy-for-dfi/sys/sdl/sdl.c

436 lines
7.8 KiB
C

/*
* sdl.c
* sdl interfaces -- based on svga.c
*
* (C) 2001 Damian Gryski <dgryski@uwaterloo.ca>
* Joystick code contributed by David Lau
*
* Licensed under the GPLv2, or later.
*/
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include "fb.h"
#include "input.h"
#include "rc.h"
struct fb fb;
static int use_yuv = -1;
static int fullscreen = 0;
static int use_altenter = 1;
static int use_joy = 1, sdl_joy_num;
static SDL_Joystick * sdl_joy = NULL;
static const int joy_commit_range = 3276;
static char Xstatus, Ystatus;
static SDL_Surface *screen;
static SDL_Overlay *overlay;
static SDL_Rect overlay_rect;
static int vmode[3] = { 0, 0, 16 };
rcvar_t vid_exports[] =
{
RCV_VECTOR("vmode", &vmode, 3),
RCV_BOOL("yuv", &use_yuv),
RCV_BOOL("fullscreen", &fullscreen),
RCV_BOOL("altenter", &use_altenter),
RCV_END
};
rcvar_t joy_exports[] =
{
RCV_BOOL("joy", &use_joy),
RCV_END
};
/* keymap - mappings of the form { scancode, localcode } - from sdl/keymap.c */
extern int keymap[][2];
static int mapscancode(SDLKey sym)
{
/* this could be faster: */
/* build keymap as int keymap[256], then ``return keymap[sym]'' */
int i;
for (i = 0; keymap[i][0]; i++)
if (keymap[i][0] == sym)
return keymap[i][1];
if (sym >= '0' && sym <= '9')
return sym;
if (sym >= 'a' && sym <= 'z')
return sym;
return 0;
}
static void joy_init()
{
int i;
int joy_count;
/* Initilize the Joystick, and disable all later joystick code if an error occured */
if (!use_joy) return;
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
return;
joy_count = SDL_NumJoysticks();
if (!joy_count)
return;
/* now try and open one. If, for some reason it fails, move on to the next one */
for (i = 0; i < joy_count; i++)
{
sdl_joy = SDL_JoystickOpen(i);
if (sdl_joy)
{
sdl_joy_num = i;
break;
}
}
/* make sure that Joystick event polling is a go */
SDL_JoystickEventState(SDL_ENABLE);
}
static void overlay_init()
{
if (!use_yuv) return;
if (use_yuv < 0)
if (vmode[0] < 320 || vmode[1] < 288)
return;
overlay = SDL_CreateYUVOverlay(320, 144, SDL_YUY2_OVERLAY, screen);
if (!overlay) return;
if (!overlay->hw_overlay || overlay->planes > 1)
{
SDL_FreeYUVOverlay(overlay);
overlay = 0;
return;
}
SDL_LockYUVOverlay(overlay);
fb.w = 160;
fb.h = 144;
fb.pelsize = 4;
fb.pitch = overlay->pitches[0];
fb.ptr = overlay->pixels[0];
fb.yuv = 1;
fb.cc[0].r = fb.cc[1].r = fb.cc[2].r = fb.cc[3].r = 0;
fb.dirty = 1;
fb.enabled = 1;
overlay_rect.x = 0;
overlay_rect.y = 0;
overlay_rect.w = vmode[0];
overlay_rect.h = vmode[1];
/* Color channels are 0=Y, 1=U, 2=V, 3=Y1 */
switch (overlay->format)
{
/* FIXME - support more formats */
case SDL_YUY2_OVERLAY:
default:
fb.cc[0].l = 0;
fb.cc[1].l = 24;
fb.cc[2].l = 8;
fb.cc[3].l = 16;
break;
}
SDL_UnlockYUVOverlay(overlay);
}
void vid_init()
{
int flags;
if (!vmode[0] || !vmode[1])
{
int scale = rc_getint("scale");
if (scale < 1) scale = 1;
vmode[0] = 160 * scale;
vmode[1] = 144 * scale;
}
flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE;
if (fullscreen)
flags |= SDL_FULLSCREEN;
if (SDL_Init(SDL_INIT_VIDEO))
die("SDL: Couldn't initialize SDL: %s\n", SDL_GetError());
if (!(screen = SDL_SetVideoMode(vmode[0], vmode[1], vmode[2], flags)))
die("SDL: can't set video mode: %s\n", SDL_GetError());
SDL_ShowCursor(0);
joy_init();
overlay_init();
if (fb.yuv) return;
SDL_LockSurface(screen);
fb.w = screen->w;
fb.h = screen->h;
fb.pelsize = screen->format->BytesPerPixel;
fb.pitch = screen->pitch;
fb.indexed = fb.pelsize == 1;
fb.ptr = screen->pixels;
fb.cc[0].r = screen->format->Rloss;
fb.cc[0].l = screen->format->Rshift;
fb.cc[1].r = screen->format->Gloss;
fb.cc[1].l = screen->format->Gshift;
fb.cc[2].r = screen->format->Bloss;
fb.cc[2].l = screen->format->Bshift;
SDL_UnlockSurface(screen);
fb.enabled = 1;
fb.dirty = 0;
}
void ev_poll()
{
event_t ev;
SDL_Event event;
int axisval;
while (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_ACTIVEEVENT:
if (event.active.state == SDL_APPACTIVE)
fb.enabled = event.active.gain;
break;
case SDL_KEYDOWN:
if ((event.key.keysym.sym == SDLK_RETURN) && (event.key.keysym.mod & KMOD_ALT))
SDL_WM_ToggleFullScreen(screen);
ev.type = EV_PRESS;
ev.code = mapscancode(event.key.keysym.sym);
ev_postevent(&ev);
break;
case SDL_KEYUP:
ev.type = EV_RELEASE;
ev.code = mapscancode(event.key.keysym.sym);
ev_postevent(&ev);
break;
case SDL_JOYAXISMOTION:
switch (event.jaxis.axis)
{
case 0: /* X axis */
axisval = event.jaxis.value;
if (axisval > joy_commit_range)
{
if (Xstatus==2) break;
if (Xstatus==0)
{
ev.type = EV_RELEASE;
ev.code = K_JOYLEFT;
ev_postevent(&ev);
}
ev.type = EV_PRESS;
ev.code = K_JOYRIGHT;
ev_postevent(&ev);
Xstatus=2;
break;
}
if (axisval < -(joy_commit_range))
{
if (Xstatus==0) break;
if (Xstatus==2)
{
ev.type = EV_RELEASE;
ev.code = K_JOYRIGHT;
ev_postevent(&ev);
}
ev.type = EV_PRESS;
ev.code = K_JOYLEFT;
ev_postevent(&ev);
Xstatus=0;
break;
}
/* if control reaches here, the axis is centered,
* so just send a release signal if necisary */
if (Xstatus==2)
{
ev.type = EV_RELEASE;
ev.code = K_JOYRIGHT;
ev_postevent(&ev);
}
if (Xstatus==0)
{
ev.type = EV_RELEASE;
ev.code = K_JOYLEFT;
ev_postevent(&ev);
}
Xstatus=1;
break;
case 1: /* Y axis*/
axisval = event.jaxis.value;
if (axisval > joy_commit_range)
{
if (Ystatus==2) break;
if (Ystatus==0)
{
ev.type = EV_RELEASE;
ev.code = K_JOYUP;
ev_postevent(&ev);
}
ev.type = EV_PRESS;
ev.code = K_JOYDOWN;
ev_postevent(&ev);
Ystatus=2;
break;
}
if (axisval < -joy_commit_range)
{
if (Ystatus==0) break;
if (Ystatus==2)
{
ev.type = EV_RELEASE;
ev.code = K_JOYDOWN;
ev_postevent(&ev);
}
ev.type = EV_PRESS;
ev.code = K_JOYUP;
ev_postevent(&ev);
Ystatus=0;
break;
}
/* if control reaches here, the axis is centered,
* so just send a release signal if necisary */
if (Ystatus==2)
{
ev.type = EV_RELEASE;
ev.code = K_JOYDOWN;
ev_postevent(&ev);
}
if (Ystatus==0)
{
ev.type = EV_RELEASE;
ev.code = K_JOYUP;
ev_postevent(&ev);
}
Ystatus=1;
break;
}
break;
case SDL_JOYBUTTONUP:
if (event.jbutton.button>15) break;
ev.type = EV_RELEASE;
ev.code = K_JOY0 + event.jbutton.button;
ev_postevent(&ev);
break;
case SDL_JOYBUTTONDOWN:
if (event.jbutton.button>15) break;
ev.type = EV_PRESS;
ev.code = K_JOY0+event.jbutton.button;
ev_postevent(&ev);
break;
case SDL_QUIT:
exit(1);
break;
default:
break;
}
}
}
void vid_setpal(int i, int r, int g, int b)
{
SDL_Color col;
col.r = r; col.g = g; col.b = b;
SDL_SetColors(screen, &col, i, 1);
}
void vid_preinit()
{
}
void vid_close()
{
if (overlay)
{
SDL_UnlockYUVOverlay(overlay);
SDL_FreeYUVOverlay(overlay);
}
else SDL_UnlockSurface(screen);
SDL_Quit();
fb.enabled = 0;
}
void vid_settitle(char *title)
{
SDL_WM_SetCaption(title, title);
}
void vid_begin()
{
if (overlay)
{
SDL_LockYUVOverlay(overlay);
fb.ptr = overlay->pixels[0];
return;
}
SDL_LockSurface(screen);
fb.ptr = screen->pixels;
}
void vid_end()
{
if (overlay)
{
SDL_UnlockYUVOverlay(overlay);
if (fb.enabled)
SDL_DisplayYUVOverlay(overlay, &overlay_rect);
return;
}
SDL_UnlockSurface(screen);
if (fb.enabled) SDL_Flip(screen);
}