Re: [Tuxnes-devel] Trying to add SDL Renderer
Brought to you by:
tmmm
|
From: W. M. P. <mi...@fl...> - 2002-03-23 15:13:01
|
> > > I'm trying to add an SDL renderer to tuxnes. Eventually this will give
> > > us full-screen support and additional platforms for free.
> > > [...]
> > I have the basic renderer working, though I don't really understand
> > tuxnes's color code (UpdateColor.* functions).
> > [...]
> The palette stuff is confusing. The first time it took me a while to
> figure it out. The second time (when I went back and converted it to use
> hardware palette entries) again took me a while, so I took notes that time:
> [...]
Great, thanks for the help. I now have a SDL video renderer working.
I can now play NES titles in full screen mode.
I would also like to implement the following, submitting the changes as
seperate patches:
1. Make repeated code into shared code:
o magstep init code
o synchronization (frameskip) code
o InitScreenshot.*/SaveScreenshot.*
2. Implement UpdateAudio using SDL.
3. Implement joystick code using SDL.
Here is the patch:
================================================================================
diff -u --new-file --recursive tuxnes-0.75-vanilla/Makefile.am tuxnes-0.75/Makefile.am
--- tuxnes-0.75-vanilla/Makefile.am Mon Apr 16 14:43:25 2001
+++ tuxnes-0.75/Makefile.am Sat Mar 9 10:42:48 2002
@@ -5,7 +5,7 @@
noinst_PROGRAMS = comptbl
tuxnes_SOURCES = x86.S d6502.c dynrec.c emu.c fb.c gamegenie.c io.c mapper.c \
- sound.c sound.h ggi.c x11.c w.c consts.h gamegenie.h globals.h \
+ sdl.c sound.c sound.h ggi.c x11.c w.c consts.h gamegenie.h globals.h \
mapper.h renderer.c renderer.h ntsc_pal.c unzip.c unzip.h \
ziploader.c ziploader.h
EXTRA_tuxnes_SOURCES = pixels.h
diff -u --new-file --recursive tuxnes-0.75-vanilla/configure.in tuxnes-0.75/configure.in
--- tuxnes-0.75-vanilla/configure.in Mon Apr 16 03:08:07 2001
+++ tuxnes-0.75/configure.in Sat Mar 9 10:51:44 2002
@@ -31,7 +31,7 @@
dnl Don't assume we want high level optimisations, it is known to
dnl produce broken code on certain architectures using certain compilers
dnl --------------------------------------------------------------------
-CFLAGS="-O"
+CFLAGS="-O -g"
AC_SUBST(CFLAGS)
dnl --------------------------------------------------------------------
@@ -138,6 +138,20 @@
AC_CHECK_LIB(snss, openSnssFile)
dnl --------------------------------------------------------------------
+dnl Check for SDL
+dnl --------------------------------------------------------------------
+AC_ARG_WITH(sdl,\
+[ --without-sdl disable check for SDL (Simple Directmedia Lib.)])
+
+if test "x$with_sdl" != "xno"; then
+ OCPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-I/usr/local/include"
+ AC_CHECK_HEADERS(SDL/SDL.h, CFLAGS="$CFLAGS -I/usr/local/include")
+ AC_CHECK_LIB(SDL, SDL_Init)
+ CPPFLAGS="$OCPPFLAGS"
+fi
+
+dnl --------------------------------------------------------------------
dnl Check for GGI
dnl --------------------------------------------------------------------
AC_ARG_WITH(ggi,\
diff -u --new-file --recursive tuxnes-0.75-vanilla/renderer.c tuxnes-0.75/renderer.c
--- tuxnes-0.75-vanilla/renderer.c Wed Apr 11 23:45:47 2001
+++ tuxnes-0.75/renderer.c Sat Mar 9 10:47:10 2002
@@ -34,6 +34,12 @@
extern void UpdateDisplayOldX11(void);
#endif
+#ifdef HAVE_SDL
+extern int InitDisplaySDL(int argc, char **argv);
+extern void UpdateColorsSDL(void);
+extern void UpdateDisplaySDL(void);
+#endif
+
#ifdef HAVE_GGI
extern int InitDisplayGGI(int argc, char **argv);
extern void UpdateColorsGGI(void);
@@ -69,6 +75,11 @@
RENDERER_OLD,
InitDisplayX11, UpdateDisplayOldX11, UpdateColorsX11 },
#endif /* HAVE_X */
+#ifdef HAVE_SDL
+ { "sdl", "SDL renderer",
+ 0,
+ InitDisplaySDL, UpdateDisplaySDL, UpdateColorsSDL },
+#endif /* HAVE_SDL */
#ifdef HAVE_GGI
{ "ggi", "GGI renderer",
0,
diff -u --new-file --recursive tuxnes-0.75-vanilla/renderer.h tuxnes-0.75/renderer.h
--- tuxnes-0.75-vanilla/renderer.h Wed Apr 11 23:45:47 2001
+++ tuxnes-0.75/renderer.h Sat Mar 9 10:33:45 2002
@@ -29,6 +29,12 @@
#endif
#endif
+#ifdef HAVE_LIBSDL
+#ifdef HAVE_SDL_SDL_H
+#define HAVE_SDL 1
+#endif
+#endif
+
/* only the no-op renderer `none' is universally known */
extern int InitDisplayNone(int argc, char **argv);
extern void UpdateColorsNone(void);
diff -u --new-file --recursive tuxnes-0.75-vanilla/sdl.c tuxnes-0.75/sdl.c
--- tuxnes-0.75-vanilla/sdl.c Thu Jan 1 01:00:00 1970
+++ tuxnes-0.75/sdl.c Sat Mar 23 15:08:19 2002
@@ -0,0 +1,419 @@
+/*
+ * This file is part of the TuxNES project codebase.
+ *
+ * Please see the README and COPYING files for more information regarding
+ * this project.
+ *
+ * Description: This file handles the I/O subsystem when using SDL.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif /* HAVE_FEATRES_H */
+
+#include "consts.h"
+#include "globals.h"
+#include "mapper.h"
+#include "renderer.h"
+#include "sound.h"
+
+#ifdef HAVE_SDL
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_endian.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/* FIXME: Share with x11.c, w.c, etc. */
+#include <dirent.h>
+#include <sys/stat.h>
+char *screenshotfile;
+static int screenshotnumber = 0;
+
+#define BPP 16
+
+SDL_Surface *screen;
+unsigned int paletteSDL[64];
+
+/* ============================ InitScreenshotSDL () ======================= */
+static void InitScreenshotSDL(void)
+{
+ DIR *dir;
+ struct dirent *dirp;
+ int currentnumber = 0;
+ /* Allocate space for (tuxnesdir) + (basefilename-snap-xxxx.bmp) + ('\0') */
+ if ((screenshotfile = (char *) malloc(strlen(tuxnesdir) +
+ strlen(basefilename) + 1 + 4 +
+ 1 + 4 + 1 + 3 + 1)) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ sprintf(screenshotfile, "%s-snap-", basefilename);
+ /* open the screenshot directory */
+ if ((dir = opendir(tuxnesdir)) == NULL) {
+ return;
+ }
+ /* iterate through the files and establish the starting screenshot number */
+ while ((dirp = readdir(dir)) != NULL) {
+ if ((strlen(dirp->d_name) >= 8)
+ &&
+ (strncmp(dirp->d_name, screenshotfile, strlen(screenshotfile))
+ == 0)
+ &&
+ (strncmp
+ (dirp->d_name + strlen(dirp->d_name) - 4, ".bmp",
+ strlen(".bmp")) == 0)) {
+ dirp->d_name[strlen(dirp->d_name) - 4] = '\0';
+ if ((currentnumber =
+ atoi(dirp->d_name + strlen(screenshotfile))) >
+ screenshotnumber) {
+ screenshotnumber = currentnumber;
+ }
+ }
+ }
+ if (++screenshotnumber > 9999) {
+ screenshotnumber = 0;
+ }
+ closedir(dir);
+}
+
+
+/* ============================ SaveScreenshotSDL () ======================= */
+static void SaveScreenshotSDL(void)
+{
+ int status;
+ /* make sure we don't over-write screenshots written by a concurrent TuxNES process */
+ {
+ struct stat buf[1];
+ do
+ sprintf(screenshotfile, "%s%s-snap-%04u.bmp", tuxnesdir,
+ basefilename, screenshotnumber++);
+ while ((!stat(screenshotfile, buf)) && !(screenshotnumber > 9999));
+ }
+ if (screenshotnumber > 9999) {
+ screenshotnumber = 0;
+ }
+ SDL_SaveBMP(screen, screenshotfile);
+}
+
+/* ============================ InitDisplaySDL () ========================== */
+int InitDisplaySDL(int argc, char **argv)
+{
+ int i;
+ struct timeval time;
+ if (magstep < 1)
+ magstep = 1;
+ if (magstep > maxsize) {
+ fprintf(stderr, "Warning: Enlargement factor %d is too large!\n",
+ magstep);
+ magstep = maxsize;
+ }
+ bpp = BPP;
+ bytes_per_line = 256 * magstep * BPP / 8;
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
+ exit(1);
+ }
+ atexit(SDL_Quit);
+ if ((screen =
+ SDL_SetVideoMode(256 * magstep, 240 * magstep, BPP,
+ SDL_SWSURFACE)) == NULL) {
+ fprintf(stderr, "Unable to set 256x240 video: %s\n",
+ SDL_GetError());
+ exit(1);
+ }
+ SDL_WM_ToggleFullScreen(screen);
+ rfb = fb = screen->pixels;
+ for (i = 0; i < 64; i++) {
+ unsigned char r, g, b;
+ r = (NES_palette[i] >> 16 >> 3) & 0x1f;
+ g = (NES_palette[i] >> 8 >> 2) & 0x3f;
+ b = (NES_palette[i] >> 3) & 0x1f;
+ paletteSDL[i] = (r << 11) | (g << 5) | (b);
+ }
+ fbinit();
+ InitScreenshotSDL();
+ gettimeofday(&time, NULL);
+ renderer_data.basetime = time.tv_sec;
+ return 0;
+}
+
+/* ============================ handle_key () ============================== */
+static void handle_key(SDL_KeyboardEvent * ev)
+{
+ if (ev->keysym.sym == SDLK_ESCAPE)
+ exit(0);
+
+ /* the coin and dipswitch inputs work only in VS UniSystem mode */
+ if (unisystem)
+ switch (ev->keysym.sym) {
+ case SDLK_LEFTBRACKET:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ coinslot ^= 1;
+ } else if (ev->type == SDL_KEYDOWN)
+ coinslot |= 1;
+ else
+ coinslot &= ~1;
+ break;
+ case SDLK_RIGHTBRACKET:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ coinslot ^= 2;
+ } else if (ev->type == SDL_KEYDOWN)
+ coinslot |= 2;
+ else
+ coinslot &= ~2;
+ break;
+ case SDLK_BACKSLASH:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ coinslot ^= 4;
+ } else if (ev->type == SDL_KEYDOWN)
+ coinslot |= 4;
+ else
+ coinslot &= ~4;
+ break;
+ case SDLK_q:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x01;
+ break;
+ case SDLK_w:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x02;
+ break;
+ case SDLK_e:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x04;
+ break;
+ case SDLK_r:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x08;
+ break;
+ case SDLK_t:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x10;
+ break;
+ case SDLK_y:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x20;
+ break;
+ case SDLK_u:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x40;
+ break;
+ case SDLK_i:
+ if (ev->type == SDL_KEYDOWN)
+ dipswitches ^= 0x80;
+ break;
+ default:
+ break;
+ }
+
+ switch (ev->keysym.sym) {
+ /* controller 1 keyboard mapping */
+ case SDLK_RETURN:
+ case SDLK_KP_ENTER:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= STARTBUTTON;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= STARTBUTTON;
+ else
+ controller[0] &= ~STARTBUTTON;
+ break;
+ case SDLK_TAB:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= SELECTBUTTON;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= SELECTBUTTON;
+ else
+ controller[0] &= ~SELECTBUTTON;
+ break;
+ case SDLK_UP:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= UP;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= UP;
+ else
+ controller[0] &= ~UP;
+ break;
+ case SDLK_DOWN:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= DOWN;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= DOWN;
+ else
+ controller[0] &= ~DOWN;
+ break;
+ case SDLK_LEFT:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= LEFT;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= LEFT;
+ else
+ controller[0] &= ~LEFT;
+ break;
+ case SDLK_RIGHT:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= RIGHT;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= RIGHT;
+ else
+ controller[0] &= ~RIGHT;
+ break;
+ case SDLK_HOME:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controllerd[0] ^= (UP | LEFT);
+ } else if (ev->type == SDL_KEYDOWN)
+ controllerd[0] |= (UP | LEFT);
+ else
+ controllerd[0] &= ~(UP | LEFT);
+ break;
+ case SDLK_PAGEUP:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controllerd[0] ^= (UP | RIGHT);
+ } else if (ev->type == SDL_KEYDOWN)
+ controllerd[0] |= (UP | RIGHT);
+ else
+ controllerd[0] &= ~(UP | RIGHT);
+ break;
+ case SDLK_END:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controllerd[0] ^= (DOWN | LEFT);
+ } else if (ev->type == SDL_KEYDOWN)
+ controllerd[0] |= (DOWN | LEFT);
+ else
+ controllerd[0] &= ~(DOWN | LEFT);
+ break;
+ case SDLK_PAGEDOWN:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controllerd[0] ^= (DOWN | RIGHT);
+ } else if (ev->type == SDL_KEYDOWN)
+ controllerd[0] |= (DOWN | RIGHT);
+ else
+ controllerd[0] &= ~(DOWN | RIGHT);
+ break;
+ case SDLK_z:
+ case SDLK_x:
+ case SDLK_d:
+ case SDLK_INSERT:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= BUTTONB;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= BUTTONB;
+ else
+ controller[0] &= ~BUTTONB;
+ break;
+ case SDLK_a:
+ case SDLK_c:
+ case SDLK_SPACE:
+ case SDLK_DELETE:
+ if (renderer_config.sticky_keys) {
+ if (ev->type == SDL_KEYDOWN)
+ controller[0] ^= BUTTONA;
+ } else if (ev->type == SDL_KEYDOWN)
+ controller[0] |= BUTTONA;
+ else
+ controller[0] &= ~BUTTONA;
+ break;
+ case SDLK_F7:
+ case SDLK_PRINT:
+ case SDLK_s:
+ SaveScreenshotSDL();
+ break;
+ default:
+ break;
+ }
+}
+
+/* ============================ UpdateDisplaySDL () ======================== */
+void UpdateDisplaySDL(void)
+{
+ struct timeval time;
+ unsigned static int frame;
+ unsigned int timeframe;
+ SDL_Event event;
+ /* FIXME: Write SDL audio handler */
+ UpdateAudio();
+ gettimeofday(&time, NULL);
+ timeframe = (time.tv_sec - renderer_data.basetime) * 50 + time.tv_usec / 20000; /* PAL */
+ timeframe = (time.tv_sec - renderer_data.basetime) * 60 + time.tv_usec / 16666; /* NTSC */
+ frame++;
+ if (halfspeed)
+ timeframe >>= 1;
+ if (doublespeed == 2)
+ timeframe <<= 1;
+ else if (doublespeed > 2)
+ timeframe *= doublespeed;
+ if (desync)
+ frame = timeframe;
+ desync = 0;
+ if (frame < timeframe - 20 && frame % 20 == 0)
+ desync = 1; /* If we're more than 20 frames behind, might as well stop counting. */
+ drawimage(PBL);
+ if (!frameskip) {
+ SDL_UpdateRect(screen, 0, 0, 0, 0);
+ }
+ if (frame > timeframe + 1 && frameskip == 0) {
+ usleep(16666 * (frame - timeframe - 1));
+ }
+
+ /* FIXME: write SDL handler */
+ if (jsfd[0] >= 0)
+ HandleJoystickLinux(0);
+
+ if (jsfd[1] >= 0)
+ HandleJoystickLinux(1);
+
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ case SDL_KEYUP:
+ handle_key(&event.key);
+ break;
+ case SDL_QUIT:
+ exit(0);
+ }
+ }
+
+ gettimeofday(&time, NULL);
+ timeframe = (time.tv_sec - renderer_data.basetime) * 60 + time.tv_usec / 16666; /* NTSC */
+ if (halfspeed)
+ timeframe >>= 1;
+ if (doublespeed == 2)
+ timeframe <<= 1;
+ else if (doublespeed > 2)
+ timeframe *= doublespeed;
+ if (frame >= timeframe || frame % 20 == 0)
+ frameskip = 0;
+ else
+ frameskip = 1;
+}
+
+/* ============================ UpdateColorsSDL () ========================= */
+void UpdateColorsSDL(void)
+{
+ int i;
+ palette[24] = paletteSDL[VRAM[0x3f00] & 63];
+ for (i = 0; i < 24; i++)
+ palette[i] = paletteSDL[VRAM[0x3f01 + i + (i / 3)] & 63];
+}
+
+#endif /* HAVE_SDL */
================================================================================
--
Mike
:wq
|