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 |