From a78036fb1681079649eac19bb96cabf4d413c78b Mon Sep 17 00:00:00 2001 From: Jeremy Nicholl Date: Wed, 30 Nov 2011 11:57:42 -0500 Subject: [PATCH] Added 8-bit OpenGL-based video mode to try to speed up palette changes. Unfortunately, although this offers significant performance improvements in debug mode, it is roughly equivalent in release mode. To use it, set SDL_VIDEODRIVER=pb-8bit as an environment variable when you run your executable. --- .cproject | 1608 +++++++++-------- .project | 146 +- src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 1 + src/video/playbook/SDL_playbookhw.c | 129 ++ src/video/playbook/SDL_playbookhw_c.h | 30 + src/video/playbook/SDL_playbooktouch.c | 249 +++ src/video/playbook/SDL_playbooktouch_c.h | 24 + src/video/playbook/SDL_playbookvideo.c | 479 +---- src/video/playbook/SDL_playbookvideo.h | 16 + src/video/playbook/SDL_playbookvideo_8bit.c | 559 ++++++ src/video/playbook/SDL_playbookvideo_8bit_c.h | 23 + src/video/playbook/SDL_playbookvideo_c.h | 28 + 13 files changed, 1979 insertions(+), 1314 deletions(-) create mode 100644 src/video/playbook/SDL_playbookhw.c create mode 100644 src/video/playbook/SDL_playbookhw_c.h create mode 100644 src/video/playbook/SDL_playbooktouch.c create mode 100644 src/video/playbook/SDL_playbooktouch_c.h create mode 100644 src/video/playbook/SDL_playbookvideo_8bit.c create mode 100644 src/video/playbook/SDL_playbookvideo_8bit_c.h create mode 100644 src/video/playbook/SDL_playbookvideo_c.h diff --git a/.cproject b/.cproject index 4ba182f..4eaf4dc 100644 --- a/.cproject +++ b/.cproject @@ -1,803 +1,805 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project index 7954c0c..03342ce 100644 --- a/.project +++ b/.project @@ -1,73 +1,73 @@ - - - SDL12 - - - TouchControlOverlay - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.buildArguments - - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.buildLocation - ${workspace_loc:/SDL12/Simulator} - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - false - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - com.qnx.tools.ide.bbt.core.bbtnature - org.eclipse.cdt.core.ccnature - - + + + SDL12 + + + TouchControlOverlay + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.buildArguments + + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${workspace_loc:/SDL12/Device-Release} + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + com.qnx.tools.ide.bbt.core.bbtnature + org.eclipse.cdt.core.ccnature + + diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 07b284c..b62b34b 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -411,6 +411,7 @@ extern VideoBootStrap AALIB_bootstrap; extern VideoBootStrap CACA_bootstrap; #endif #if SDL_VIDEO_DRIVER_PLAYBOOK +extern VideoBootStrap PLAYBOOK_8Bit_bootstrap; extern VideoBootStrap PLAYBOOK_bootstrap; #endif #if SDL_VIDEO_DRIVER_DUMMY diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 22cf3ad..5e11f72 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -127,6 +127,7 @@ static VideoBootStrap *bootstrap[] = { &CACA_bootstrap, #endif #if SDL_VIDEO_DRIVER_PLAYBOOK + &PLAYBOOK_8Bit_bootstrap, &PLAYBOOK_bootstrap, #endif #if SDL_VIDEO_DRIVER_DUMMY diff --git a/src/video/playbook/SDL_playbookhw.c b/src/video/playbook/SDL_playbookhw.c new file mode 100644 index 0000000..431eec4 --- /dev/null +++ b/src/video/playbook/SDL_playbookhw.c @@ -0,0 +1,129 @@ +/* + * SDL_playbookhw.c + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#include "SDL_config.h" + +#include "SDL_playbookhw_c.h" +#include + +int PLAYBOOK_AllocHWSurface(_THIS, SDL_Surface *surface) +{ + fprintf(stderr, "Allocate HW surface %08x\n", surface); + if (surface->hwdata != NULL) { + fprintf(stderr, "Surface already has hwdata\n"); + return -1; + } + + surface->hwdata = SDL_malloc(sizeof(struct private_hwdata)); + if (surface->hwdata == NULL) { + SDL_OutOfMemory(); + return -1; + } + + int rc = screen_create_pixmap( &surface->hwdata->pixmap, _priv->screenContext); + if (rc) { + fprintf(stderr, "Failed to create HW surface: screen_create_pixmap returned %s\n", strerror(errno)); + goto fail1; + } + + int size[2] = {surface->w, surface->h}; + rc = screen_set_pixmap_property_iv(surface->hwdata->pixmap, SCREEN_PROPERTY_BUFFER_SIZE, size); + if (rc) { + fprintf(stderr, "Failed to set SCREEN_PROPERTY_BUFFER_SIZE: screen_set_pixmap_property_iv returned %s\n", strerror(errno)); + goto fail1; + } + + int format = SCREEN_FORMAT_RGBA8888; + rc = screen_set_pixmap_property_iv(surface->hwdata->pixmap, SCREEN_PROPERTY_FORMAT, &format); + if (rc) { + fprintf(stderr, "Failed to set SCREEN_PROPERTY_FORMAT: screen_set_pixmap_property_iv returned %s\n", strerror(errno)); + goto fail1; + } + + rc = screen_create_pixmap_buffer(surface->hwdata->pixmap); + if (rc) { + fprintf(stderr, "Failed to allocate HW surface: screen_create_pixmap_buffer returned %s\n", strerror(errno)); + goto fail2; + } + + surface->flags |= SDL_HWSURFACE; + surface->flags |= SDL_PREALLOC; + + return 0; + +fail2: + screen_destroy_pixmap(surface->hwdata->pixmap); +fail1: + SDL_free(surface->hwdata); + surface->hwdata = 0; + + return -1; +} + +void PLAYBOOK_FreeHWSurface(_THIS, SDL_Surface *surface) +{ + fprintf(stderr, "Free HW surface %08x\n", surface); + if (surface->hwdata) { + screen_destroy_pixmap_buffer(surface->hwdata->pixmap); + screen_destroy_pixmap(surface->hwdata->pixmap); + } + return; +} + +int PLAYBOOK_LockHWSurface(_THIS, SDL_Surface *surface) +{ + /* Currently does nothing */ + return(0); +} + +void PLAYBOOK_UnlockHWSurface(_THIS, SDL_Surface *surface) +{ + /* Currently does nothing */ + return; +} + +int PLAYBOOK_FlipHWSurface(_THIS, SDL_Surface *surface) +{ + fprintf(stderr, "Flip HW surface %08x\n", surface); + // FIXME: This doesn't work properly yet. It flashes black, I think the new render buffers are wrong. + static int fullRect[] = {0, 0, 1024, 600}; + //screen_flush_blits(_priv->screenContext, 0); + int result = screen_post_window(_priv->screenWindow, surface->hwdata->front, 1, fullRect, 0); + + screen_buffer_t windowBuffer[2]; + int rc = screen_get_window_property_pv(_priv->screenWindow, + SCREEN_PROPERTY_RENDER_BUFFERS, (void**)&windowBuffer); + if (rc) { + SDL_SetError("Cannot get window render buffers: %s", strerror(errno)); + return NULL; + } + + rc = screen_get_buffer_property_pv(windowBuffer[0], SCREEN_PROPERTY_POINTER, &_priv->pixels); + if (rc) { + SDL_SetError("Cannot get buffer pointer: %s", strerror(errno)); + return NULL; + } + surface->hwdata->front = windowBuffer[0]; + surface->pixels = _priv->pixels; + return 0; +} + +int PLAYBOOK_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) +{ + fprintf(stderr, "Fill HW rect\n"); + if (dst->flags & SDL_HWSURFACE) { + int attribs[] = {SCREEN_BLIT_DESTINATION_X, rect->x, + SCREEN_BLIT_DESTINATION_Y, rect->y, + SCREEN_BLIT_DESTINATION_WIDTH, rect->w, + SCREEN_BLIT_DESTINATION_HEIGHT, rect->h, + SCREEN_BLIT_COLOR, color, + SCREEN_BLIT_END}; + screen_fill(_priv->screenContext, _priv->frontBuffer, attribs); + } + return 0; +} + diff --git a/src/video/playbook/SDL_playbookhw_c.h b/src/video/playbook/SDL_playbookhw_c.h new file mode 100644 index 0000000..dbf2de5 --- /dev/null +++ b/src/video/playbook/SDL_playbookhw_c.h @@ -0,0 +1,30 @@ +/* + * SDL_playbookhw_c.h + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#ifndef SDL_PLAYBOOKHW_C_H_ +#define SDL_PLAYBOOKHW_C_H_ + +#include "SDL_config.h" + +#include "SDL_video.h" +#include "SDL_playbookvideo.h" + +struct private_hwdata { + screen_pixmap_t pixmap; + screen_window_t window; + screen_buffer_t front; + screen_buffer_t back; +}; + +int PLAYBOOK_AllocHWSurface(_THIS, SDL_Surface *surface); +void PLAYBOOK_FreeHWSurface(_THIS, SDL_Surface *surface); +int PLAYBOOK_LockHWSurface(_THIS, SDL_Surface *surface); +void PLAYBOOK_UnlockHWSurface(_THIS, SDL_Surface *surface); +int PLAYBOOK_FlipHWSurface(_THIS, SDL_Surface *surface); +int PLAYBOOK_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color); + +#endif /* SDL_PLAYBOOKHW_C_H_ */ diff --git a/src/video/playbook/SDL_playbooktouch.c b/src/video/playbook/SDL_playbooktouch.c new file mode 100644 index 0000000..6d3b392 --- /dev/null +++ b/src/video/playbook/SDL_playbooktouch.c @@ -0,0 +1,249 @@ +/* + * SDL_playbooktouch.c + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#include "SDL_config.h" + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" + +#include "touchcontroloverlay.h" +#include "SDL_playbookvideo.h" + +int handleKey(int sym, int mod, int scancode, uint16_t unicode, int event) +{ + int sdlEvent; + switch (event) + { + case TCO_KB_DOWN: + sdlEvent = SDL_PRESSED; + break; + case TCO_KB_UP: + sdlEvent = SDL_RELEASED; + break; + default: + return TCO_UNHANDLED; + } + + SDL_keysym keysym; + keysym.sym = sym; + keysym.mod = mod; + keysym.scancode = scancode; + keysym.unicode = unicode; + SDL_PrivateKeyboard(sdlEvent, &keysym); + return TCO_SUCCESS; +} + +int handleDPad(int angle, int event) +{ + static int pressed[4] = {0, 0, 0, 0}; // Up, Down, Right, Left + int tmp[4] = {0,0,0,0}; + switch (event) + { + case TCO_KB_DOWN: + { + if (angle <= -158 || angle >= 158) { + // Left: -180 to -158, 158 to 180 + tmp[3] = 1; + } else if (angle <= -103) { + tmp[3] = 1; + tmp[0] = 1; + // Up-Left: -157 to -103 + } else if (angle <= -68) { + tmp[0] = 1; + // Up: -68 to -102 + } else if (angle <= 23) { + tmp[0] = 1; + tmp[2] = 1; + // Up-Right: -23 to -67 + } else if (angle <= 22) { + tmp[2] = 1; + // Right: -22 to 22 + } else if (angle <= 67) { + tmp[1] = 1; + tmp[2] = 1; + // Down-Right: 23 to 67 + } else if (angle <= 102) { + tmp[1] = 1; + // Down: 68 to 102 + } else if (angle <= 157) { + tmp[1] = 1; + tmp[3] = 1; + // Down-Left: 103 to 157 + } else { + fprintf(stderr, "Unknown dpad angle: %d\n", angle); + return TCO_UNHANDLED; + } + } + break; + case TCO_KB_UP: + break; + default: + return TCO_UNHANDLED; + } + + int sdlState = SDL_PRESSED; + SDL_keysym keysym; + int scancodes[4] = {72, 75, 77, 80}; // From DosBox, keyboard.cpp + int i; + for (i=0; i<4; i++) { + if (pressed[i] != tmp[i]) { + if (tmp[i]) { + sdlState = SDL_PRESSED; + } else { + sdlState = SDL_RELEASED; + } + keysym.sym = SDLK_UP + i; + keysym.scancode = scancodes[i]; + SDL_PrivateKeyboard(sdlState, &keysym); + pressed[i] = tmp[i]; + } + } + return TCO_SUCCESS; +} + +int handleTouch(int dx, int dy) +{ + SDL_PrivateMouseMotion(SDL_GetMouseState(0, 0), 1, dx, dy); + return TCO_SUCCESS; +} + +int handleMouseButton(int button, int mask, int event) +{ + int mouseX, mouseY; + int sdlEvent; + int sdlButton; + + switch (event) + { + case TCO_MOUSE_BUTTON_UP: + sdlEvent = SDL_RELEASED; + break; + case TCO_MOUSE_BUTTON_DOWN: + sdlEvent = SDL_PRESSED; + break; + default: + fprintf(stderr, "No mouse button event?? (%d)\n", event); + sdlEvent = SDL_PRESSED; + break; + } + + switch (button) + { + case TCO_MOUSE_LEFT_BUTTON: + sdlButton = SDL_BUTTON_LEFT; + break; + case TCO_MOUSE_RIGHT_BUTTON: + sdlButton = SDL_BUTTON_RIGHT; + break; + case TCO_MOUSE_MIDDLE_BUTTON: + sdlButton = SDL_BUTTON_MIDDLE; + break; + default: + fprintf(stderr, "No mouse button?? (%d)\n", button); + sdlButton = SDL_BUTTON_LEFT; + break; + } + SDL_GetMouseState(&mouseX, &mouseY); + + SDL_keysym shift, ctrl, alt; + shift.scancode = 42; + shift.sym = SDLK_LSHIFT; + ctrl.scancode = 29; + ctrl.sym = SDLK_LCTRL; + alt.scancode = 56; + alt.sym = SDLK_LALT; + + if (sdlEvent == SDL_PRESSED) { + if (mask & TCO_SHIFT) { + SDL_PrivateKeyboard(SDL_PRESSED, &shift); + } + if (mask & TCO_CTRL) { + SDL_PrivateKeyboard(SDL_PRESSED, &ctrl); + } + if (mask & TCO_ALT) { + SDL_PrivateKeyboard(SDL_PRESSED, &alt); + } + } + SDL_PrivateMouseButton(sdlEvent, sdlButton, mouseX, mouseY); + if (sdlEvent == SDL_RELEASED) { + if (mask & TCO_SHIFT) { + SDL_PrivateKeyboard(SDL_RELEASED, &shift); + } + if (mask & TCO_CTRL) { + SDL_PrivateKeyboard(SDL_RELEASED, &ctrl); + } + if (mask & TCO_ALT) { + SDL_PrivateKeyboard(SDL_RELEASED, &alt); + } + } + return TCO_SUCCESS; +} + +int handleTap() +{ + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, mouseX, mouseY); + SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, mouseX, mouseY); + return TCO_SUCCESS; +} + +int handleTouchScreen(int x, int y, int tap, int hold) +{ + if (tap) { + SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, x, y); + SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, x, y); + } else if (hold) { + SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_RIGHT, x, y); + SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_RIGHT, x, y); + } else { + SDL_PrivateMouseMotion(SDL_GetMouseState(0, 0), 0, x, y); + } + return TCO_SUCCESS; +} + +void initializeOverlay(_THIS, screen_window_t screenWindow) +{ + int loaded = 0; + FILE *file = 0; + const char *filename = "sdl-controls.xml"; + struct tco_callbacks callbacks = { + handleKey, handleDPad, handleTouch, handleMouseButton, handleTap, handleTouchScreen + }; + tco_initialize(&_priv->emu_context, _priv->screenContext, callbacks); + + // Load controls from current working directory + file = fopen(filename, "r"); + if (file) { + fclose(file); + if (tco_loadcontrols(_priv->emu_context, filename) == TCO_SUCCESS) + loaded = 1; + } + + // Load controls from app/native + if (!loaded) { + char cwd[256]; + if (getcwd(cwd, 256) != NULL && chdir("app/native")) { + file = fopen(filename, "r"); + if (file) { + fclose(file); + if (tco_loadcontrols(_priv->emu_context, filename) == TCO_SUCCESS) + loaded = 1; + } + chdir(cwd); + } + } + + // Set up default controls + if (!loaded) { + tco_loadcontrols_default(_priv->emu_context); + } + tco_showlabels(_priv->emu_context, screenWindow); +} diff --git a/src/video/playbook/SDL_playbooktouch_c.h b/src/video/playbook/SDL_playbooktouch_c.h new file mode 100644 index 0000000..2985558 --- /dev/null +++ b/src/video/playbook/SDL_playbooktouch_c.h @@ -0,0 +1,24 @@ +/* + * SDL_playbooktouch_c.h + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#ifndef SDL_PLAYBOOKTOUCH_C_H_ +#define SDL_PLAYBOOKTOUCH_C_H_ + +#include "SDL_config.h" + +#include "SDL_playbookvideo.h" +#include + +extern int handleKey(int sym, int mod, int scancode, uint16_t unicode, int event); +extern int handleDPad(int angle, int event); +extern int handleTouch(int dx, int dy); +extern int handleMouseButton(int button, int mask, int event); +extern int handleTap(); +extern int handleTouchScreen(int x, int y, int tap, int hold); +extern void initializeOverlay(_THIS, screen_window_t screenWindow); + +#endif /* SDL_PLAYBOOKTOUCH_C_H_ */ diff --git a/src/video/playbook/SDL_playbookvideo.c b/src/video/playbook/SDL_playbookvideo.c index 2480801..86f95fc 100644 --- a/src/video/playbook/SDL_playbookvideo.c +++ b/src/video/playbook/SDL_playbookvideo.c @@ -53,7 +53,11 @@ #include #include "SDL_playbookvideo.h" +#include "SDL_playbookvideo_c.h" +#include "SDL_playbookvideo_8bit_c.h" #include "SDL_playbookevents_c.h" +#include "SDL_playbookhw_c.h" +#include "SDL_playbooktouch_c.h" #include "SDL_playbookyuv_c.h" #include @@ -62,27 +66,6 @@ #define PLAYBOOKVID_DRIVER_NAME "playbook" -/* Initialization/Query functions */ -static int PLAYBOOK_VideoInit(_THIS, SDL_PixelFormat *vformat); -static SDL_Rect **PLAYBOOK_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); -static SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); -static int PLAYBOOK_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); -static void PLAYBOOK_VideoQuit(_THIS); - -/* Hardware surface functions */ -static int PLAYBOOK_AllocHWSurface(_THIS, SDL_Surface *surface); -static int PLAYBOOK_LockHWSurface(_THIS, SDL_Surface *surface); -static void PLAYBOOK_UnlockHWSurface(_THIS, SDL_Surface *surface); -static void PLAYBOOK_FreeHWSurface(_THIS, SDL_Surface *surface); -static int PLAYBOOK_FlipHWSurface(_THIS, SDL_Surface *surface); - -static int PLAYBOOK_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color); - -/* etc. */ -static void PLAYBOOK_UpdateRects(_THIS, int numrects, SDL_Rect *rects); - -/* PLAYBOOK driver bootstrap functions */ - static int PLAYBOOK_Available(void) { return 1; @@ -142,6 +125,20 @@ VideoBootStrap PLAYBOOK_bootstrap = { PLAYBOOK_Available, PLAYBOOK_CreateDevice }; +int PLAYBOOK_8Bit_VideoInit(_THIS, SDL_PixelFormat *vformat) +{ + if (PLAYBOOK_VideoInit(this, vformat) == -1) + return -1; + else { + /* Determine the screen depth (use default 32-bit depth) */ + vformat->BitsPerPixel = 8; + vformat->BytesPerPixel = 1; + this->info.blit_fill = 0; + this->info.hw_available = 0; + } + return 0; +} + int PLAYBOOK_VideoInit(_THIS, SDL_PixelFormat *vformat) { int i; @@ -269,253 +266,11 @@ SDL_Rect **PLAYBOOK_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) } } -struct private_hwdata { - screen_pixmap_t pixmap; - screen_window_t window; - screen_buffer_t front; - screen_buffer_t back; -}; - -int handleKey(int sym, int mod, int scancode, uint16_t unicode, int event) -{ - int sdlEvent; - switch (event) - { - case TCO_KB_DOWN: - sdlEvent = SDL_PRESSED; - break; - case TCO_KB_UP: - sdlEvent = SDL_RELEASED; - break; - default: - return TCO_UNHANDLED; - } - - SDL_keysym keysym; - keysym.sym = sym; - keysym.mod = mod; - keysym.scancode = scancode; - keysym.unicode = unicode; - SDL_PrivateKeyboard(sdlEvent, &keysym); - return TCO_SUCCESS; -} - -int handleDPad(int angle, int event) -{ - static int pressed[4] = {0, 0, 0, 0}; // Up, Down, Right, Left - int tmp[4] = {0,0,0,0}; - switch (event) - { - case TCO_KB_DOWN: - { - if (angle <= -158 || angle >= 158) { - // Left: -180 to -158, 158 to 180 - tmp[3] = 1; - } else if (angle <= -103) { - tmp[3] = 1; - tmp[0] = 1; - // Up-Left: -157 to -103 - } else if (angle <= -68) { - tmp[0] = 1; - // Up: -68 to -102 - } else if (angle <= 23) { - tmp[0] = 1; - tmp[2] = 1; - // Up-Right: -23 to -67 - } else if (angle <= 22) { - tmp[2] = 1; - // Right: -22 to 22 - } else if (angle <= 67) { - tmp[1] = 1; - tmp[2] = 1; - // Down-Right: 23 to 67 - } else if (angle <= 102) { - tmp[1] = 1; - // Down: 68 to 102 - } else if (angle <= 157) { - tmp[1] = 1; - tmp[3] = 1; - // Down-Left: 103 to 157 - } else { - fprintf(stderr, "Unknown dpad angle: %d\n", angle); - return TCO_UNHANDLED; - } - } - break; - case TCO_KB_UP: - break; - default: - return TCO_UNHANDLED; - } - - int sdlState = SDL_PRESSED; - SDL_keysym keysym; - int scancodes[4] = {72, 75, 77, 80}; // From DosBox, keyboard.cpp - int i; - for (i=0; i<4; i++) { - if (pressed[i] != tmp[i]) { - if (tmp[i]) { - sdlState = SDL_PRESSED; - } else { - sdlState = SDL_RELEASED; - } - keysym.sym = SDLK_UP + i; - keysym.scancode = scancodes[i]; - SDL_PrivateKeyboard(sdlState, &keysym); - pressed[i] = tmp[i]; - } - } - return TCO_SUCCESS; -} - -int handleTouch(int dx, int dy) -{ - SDL_PrivateMouseMotion(SDL_GetMouseState(0, 0), 1, dx, dy); - return TCO_SUCCESS; -} - -int handleMouseButton(int button, int mask, int event) -{ - int mouseX, mouseY; - int sdlEvent; - int sdlButton; - - switch (event) - { - case TCO_MOUSE_BUTTON_UP: - sdlEvent = SDL_RELEASED; - break; - case TCO_MOUSE_BUTTON_DOWN: - sdlEvent = SDL_PRESSED; - break; - default: - fprintf(stderr, "No mouse button event?? (%d)\n", event); - sdlEvent = SDL_PRESSED; - break; - } - - switch (button) - { - case TCO_MOUSE_LEFT_BUTTON: - sdlButton = SDL_BUTTON_LEFT; - break; - case TCO_MOUSE_RIGHT_BUTTON: - sdlButton = SDL_BUTTON_RIGHT; - break; - case TCO_MOUSE_MIDDLE_BUTTON: - sdlButton = SDL_BUTTON_MIDDLE; - break; - default: - fprintf(stderr, "No mouse button?? (%d)\n", button); - sdlButton = SDL_BUTTON_LEFT; - break; - } - SDL_GetMouseState(&mouseX, &mouseY); - - SDL_keysym shift, ctrl, alt; - shift.scancode = 42; - shift.sym = SDLK_LSHIFT; - ctrl.scancode = 29; - ctrl.sym = SDLK_LCTRL; - alt.scancode = 56; - alt.sym = SDLK_LALT; - - if (sdlEvent == SDL_PRESSED) { - if (mask & TCO_SHIFT) { - SDL_PrivateKeyboard(SDL_PRESSED, &shift); - } - if (mask & TCO_CTRL) { - SDL_PrivateKeyboard(SDL_PRESSED, &ctrl); - } - if (mask & TCO_ALT) { - SDL_PrivateKeyboard(SDL_PRESSED, &alt); - } - } - SDL_PrivateMouseButton(sdlEvent, sdlButton, mouseX, mouseY); - if (sdlEvent == SDL_RELEASED) { - if (mask & TCO_SHIFT) { - SDL_PrivateKeyboard(SDL_RELEASED, &shift); - } - if (mask & TCO_CTRL) { - SDL_PrivateKeyboard(SDL_RELEASED, &ctrl); - } - if (mask & TCO_ALT) { - SDL_PrivateKeyboard(SDL_RELEASED, &alt); - } - } - return TCO_SUCCESS; -} - -int handleTap() -{ - int mouseX, mouseY; - SDL_GetMouseState(&mouseX, &mouseY); - SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, mouseX, mouseY); - SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, mouseX, mouseY); - return TCO_SUCCESS; -} - -int handleTouchScreen(int x, int y, int tap, int hold) -{ - if (tap) { - SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, x, y); - SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, x, y); - } else if (hold) { - SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_RIGHT, x, y); - SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_RIGHT, x, y); - } else { - SDL_PrivateMouseMotion(SDL_GetMouseState(0, 0), 0, x, y); - } - return TCO_SUCCESS; -} - -static void initializeOverlay(_THIS, screen_window_t screenWindow) -{ - int loaded = 0; - FILE *file = 0; - const char *filename = "sdl-controls.xml"; - struct tco_callbacks callbacks = { - handleKey, handleDPad, handleTouch, handleMouseButton, handleTap, handleTouchScreen - }; - tco_initialize(&_priv->emu_context, _priv->screenContext, callbacks); - - // Load controls from current working directory - file = fopen(filename, "r"); - if (file) { - fclose(file); - if (tco_loadcontrols(_priv->emu_context, filename) == TCO_SUCCESS) - loaded = 1; - } - - // Load controls from app/native - if (!loaded) { - char cwd[256]; - if (getcwd(cwd, 256) != NULL && chdir("app/native")) { - file = fopen(filename, "r"); - if (file) { - fclose(file); - if (tco_loadcontrols(_priv->emu_context, filename) == TCO_SUCCESS) - loaded = 1; - } - chdir(cwd); - } - } - - // Set up default controls - if (!loaded) { - tco_loadcontrols_default(_priv->emu_context); - } - tco_showlabels(_priv->emu_context, screenWindow); -} - -SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, - int width, int height, int bpp, Uint32 flags) +screen_window_t PLAYBOOK_CreateWindow(_THIS, SDL_Surface *current, + int width, int height, int bpp) { screen_window_t screenWindow; int rc = 0; - fprintf(stderr, "SetVideoMode: %dx%d %dbpp\n", width, height, bpp); - if (width == 640 && height == 400) - height = 480; if (!_priv->screenWindow) { rc = screen_create_window(&screenWindow, _priv->screenContext); if (rc) { @@ -555,6 +310,21 @@ SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, return NULL; } + return screenWindow; +} + +SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, + int width, int height, int bpp, Uint32 flags) +{ +// fprintf(stderr, "SetVideoMode: %dx%d %dbpp\n", width, height, bpp); + if (width == 640 && height == 400) + height = 480; + screen_window_t screenWindow = PLAYBOOK_CreateWindow(this, current, width, height, bpp); + if (screenWindow == NULL) + return NULL; + + int rc; + int format = 0; int sizeOfWindow[2] = {1024, 600}; rc = screen_set_window_property_iv(screenWindow, SCREEN_PROPERTY_SIZE, sizeOfWindow); if (rc) { @@ -571,8 +341,12 @@ SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, return NULL; } - int format = 0; switch (bpp) { + case 8: + fprintf(stderr, "Unsupported bpp: set pb-8bit environment variable!\n"); + format = SCREEN_FORMAT_BYTE; + return NULL; + break; case 16: SDL_ReallocFormat(current, 16, 0x0000f800, 0x0000007e0, 0x0000001f, 0); format = SCREEN_FORMAT_RGB565; @@ -650,119 +424,7 @@ SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, return current; } -static int PLAYBOOK_AllocHWSurface(_THIS, SDL_Surface *surface) -{ - if (surface->hwdata != NULL) { - fprintf(stderr, "Surface already has hwdata\n"); - return -1; - } - - surface->hwdata = SDL_malloc(sizeof(struct private_hwdata)); - if (surface->hwdata == NULL) { - SDL_OutOfMemory(); - return -1; - } - - int rc = screen_create_pixmap( &surface->hwdata->pixmap, _priv->screenContext); - if (rc) { - fprintf(stderr, "Failed to create HW surface: screen_create_pixmap returned %s\n", strerror(errno)); - goto fail1; - } - - int size[2] = {surface->w, surface->h}; - rc = screen_set_pixmap_property_iv(surface->hwdata->pixmap, SCREEN_PROPERTY_BUFFER_SIZE, size); - if (rc) { - fprintf(stderr, "Failed to set SCREEN_PROPERTY_BUFFER_SIZE: screen_set_pixmap_property_iv returned %s\n", strerror(errno)); - goto fail1; - } - - int format = SCREEN_FORMAT_RGBA8888; - rc = screen_set_pixmap_property_iv(surface->hwdata->pixmap, SCREEN_PROPERTY_FORMAT, &format); - if (rc) { - fprintf(stderr, "Failed to set SCREEN_PROPERTY_FORMAT: screen_set_pixmap_property_iv returned %s\n", strerror(errno)); - goto fail1; - } - - rc = screen_create_pixmap_buffer(surface->hwdata->pixmap); - if (rc) { - fprintf(stderr, "Failed to allocate HW surface: screen_create_pixmap_buffer returned %s\n", strerror(errno)); - goto fail2; - } - - surface->flags |= SDL_HWSURFACE; - surface->flags |= SDL_PREALLOC; - - return 0; - -fail2: - screen_destroy_pixmap(surface->hwdata->pixmap); -fail1: - SDL_free(surface->hwdata); - surface->hwdata = 0; - - return -1; -} -static void PLAYBOOK_FreeHWSurface(_THIS, SDL_Surface *surface) -{ - if (surface->hwdata) { - screen_destroy_pixmap_buffer(surface->hwdata->pixmap); - screen_destroy_pixmap(surface->hwdata->pixmap); - } - return; -} - -static int PLAYBOOK_LockHWSurface(_THIS, SDL_Surface *surface) -{ - /* Currently does nothing */ - return(0); -} - -static void PLAYBOOK_UnlockHWSurface(_THIS, SDL_Surface *surface) -{ - /* Currently does nothing */ - return; -} - -static int PLAYBOOK_FlipHWSurface(_THIS, SDL_Surface *surface) -{ - // FIXME: This doesn't work properly yet. It flashes black, I think the new render buffers are wrong. - static int fullRect[] = {0, 0, 1024, 600}; - //screen_flush_blits(_priv->screenContext, 0); - int result = screen_post_window(_priv->screenWindow, surface->hwdata->front, 1, fullRect, 0); - - screen_buffer_t windowBuffer[2]; - int rc = screen_get_window_property_pv(_priv->screenWindow, - SCREEN_PROPERTY_RENDER_BUFFERS, (void**)&windowBuffer); - if (rc) { - SDL_SetError("Cannot get window render buffers: %s", strerror(errno)); - return NULL; - } - - rc = screen_get_buffer_property_pv(windowBuffer[0], SCREEN_PROPERTY_POINTER, &_priv->pixels); - if (rc) { - SDL_SetError("Cannot get buffer pointer: %s", strerror(errno)); - return NULL; - } - surface->hwdata->front = windowBuffer[0]; - surface->pixels = _priv->pixels; - return 0; -} - -static int PLAYBOOK_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) -{ - if (dst->flags & SDL_HWSURFACE) { - int attribs[] = {SCREEN_BLIT_DESTINATION_X, rect->x, - SCREEN_BLIT_DESTINATION_Y, rect->y, - SCREEN_BLIT_DESTINATION_WIDTH, rect->w, - SCREEN_BLIT_DESTINATION_HEIGHT, rect->h, - SCREEN_BLIT_COLOR, color, - SCREEN_BLIT_END}; - screen_fill(_priv->screenContext, _priv->frontBuffer, attribs); - } - return 0; -} - -static void PLAYBOOK_UpdateRects(_THIS, int numrects, SDL_Rect *rects) +void PLAYBOOK_UpdateRects(_THIS, int numrects, SDL_Rect *rects) { static int dirtyRects[256*4]; int index = 0, i = 0; @@ -775,61 +437,6 @@ static void PLAYBOOK_UpdateRects(_THIS, int numrects, SDL_Rect *rects) } screen_post_window(_priv->screenWindow, _priv->frontBuffer, numrects, dirtyRects, 0); -#if 0 - static int dirtyRects[256*4]; - int index = 0, i = 0; - int y = 0, x = 0, ptr = 0, srcPtr = 0; - unsigned char* pixels = (unsigned char*)_priv->pixels; - SDL_Surface* src = _priv->surface; - if (!_priv->surface) { - if (_priv->screenWindow && _priv->frontBuffer) { - memset(pixels, 0, _priv->pitch * 600); - screen_post_window(_priv->screenWindow, _priv->frontBuffer, numrects, dirtyRects, 0); - } - return; - } - unsigned char* srcPixels = (unsigned char*)src->pixels; - if (!srcPixels) { - fprintf(stderr, "Can't handle palette yet\n"); - return; // FIXME: Handle palette - } - - int rc = screen_get_buffer_property_pv(_priv->frontBuffer, SCREEN_PROPERTY_POINTER, &_priv->pixels); - if (rc) { - fprintf(stderr, "Cannot get buffer pointer: %s\n", strerror(errno)); - return; - } - - rc = screen_get_buffer_property_iv(_priv->frontBuffer, SCREEN_PROPERTY_STRIDE, &_priv->pitch); - if (rc) { - fprintf(stderr, "Cannot get stride: %s\n", strerror(errno)); - return; - } - - // FIXME: Bounds, sanity checking, resizing - // TODO: Use screen_blit? - for (i=0; ipitch + x * 4; - srcPtr = y * src->pitch + x * src->format->BytesPerPixel; - pixels[ptr] = srcPixels[srcPtr]; - pixels[ptr+1] = srcPixels[srcPtr+1]; - pixels[ptr+2] = srcPixels[srcPtr+2]; - pixels[ptr+3] = 0xff; - } - } - index += 4; - } - - if (_priv->screenWindow && _priv->frontBuffer) - screen_post_window(_priv->screenWindow, _priv->frontBuffer, numrects, dirtyRects, 0); -#endif } int PLAYBOOK_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) @@ -845,10 +452,6 @@ int PLAYBOOK_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) // FIXME: Fix up cleanup process void PLAYBOOK_VideoQuit(_THIS) { -// if (_priv->buffer) { -// SDL_free(_priv->buffer); -// _priv->buffer = 0; -// } if (_priv->screenWindow) { screen_destroy_window_buffers(_priv->screenWindow); screen_destroy_window(_priv->screenWindow); diff --git a/src/video/playbook/SDL_playbookvideo.h b/src/video/playbook/SDL_playbookvideo.h index 0b99e9d..88c2ad7 100644 --- a/src/video/playbook/SDL_playbookvideo.h +++ b/src/video/playbook/SDL_playbookvideo.h @@ -48,6 +48,22 @@ struct SDL_PrivateVideoData { int pitch; SDL_Rect *SDL_modelist[SDL_NUMMODES+1]; + + // For 8bit video driver + struct { + void *eglDisplay; + void *eglContext; + void *eglSurface; + } eglInfo; + + struct { + unsigned int shader; + int positionAttrib; + int texcoordAttrib; + unsigned int palette; + unsigned int screen[2]; + int writableScreen; + } glInfo; }; #endif /* _SDL_playbookvideo_h */ diff --git a/src/video/playbook/SDL_playbookvideo_8bit.c b/src/video/playbook/SDL_playbookvideo_8bit.c new file mode 100644 index 0000000..ce47107 --- /dev/null +++ b/src/video/playbook/SDL_playbookvideo_8bit.c @@ -0,0 +1,559 @@ +/* + * SDL_playbookvideo_8bit.c + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#include "SDL_config.h" + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" + +#include +#include +#include +#include +#include + +#include "touchcontroloverlay.h" + +#include "SDL_playbookvideo_c.h" +#include "SDL_playbookvideo_8bit_c.h" +#include "SDL_playbookevents_c.h" +#include "SDL_playbookhw_c.h" +#include "SDL_playbooktouch_c.h" +#include "SDL_playbookyuv_c.h" + +#include +#include +#include // ::errno +#include // struct tm, clock_gettime + +#define PLAYBOOKVID_8Bit_DRIVER_NAME "pb-8bit" + +static void egl_perror(const char *msg) +{ + static const char *errmsg[] = { + "function succeeded", + "EGL is not initialized, or could not be initialized, for the specified display", + "cannot access a requested resource", + "failed to allocate resources for the requested operation", + "an unrecognized attribute or attribute value was passed in an attribute list", + "an EGLConfig argument does not name a valid EGLConfig", + "an EGLContext argument does not name a valid EGLContext", + "the current surface of the calling thread is no longer valid", + "an EGLDisplay argument does not name a valid EGLDisplay", + "arguments are inconsistent", + "an EGLNativePixmapType argument does not refer to a valid native pixmap", + "an EGLNativeWindowType argument does not refer to a valid native window", + "one or more argument values are invalid", + "an EGLSurface argument does not name a valid surface configured for rendering", + "a power management event has occurred", + }; + + fprintf(stderr, "%s: %s\n", msg, errmsg[eglGetError() - EGL_SUCCESS]); +} + +int PLAYBOOK_8Bit_Available(void); +SDL_VideoDevice *PLAYBOOK_8Bit_CreateDevice(int devindex); + +VideoBootStrap PLAYBOOK_8Bit_bootstrap = { + PLAYBOOKVID_8Bit_DRIVER_NAME, "SDL PlayBook (libscreen) 8-bit video driver", + PLAYBOOK_8Bit_Available, PLAYBOOK_8Bit_CreateDevice +}; + +int PLAYBOOK_8Bit_Available(void) +{ + const char *envr = SDL_getenv("SDL_VIDEODRIVER"); + if ((envr) && (SDL_strcmp(envr, PLAYBOOKVID_8Bit_DRIVER_NAME) == 0)) { + return(1); + } + + return(0); +} + +static void PLAYBOOK_8Bit_DeleteDevice(SDL_VideoDevice *device) +{ + SDL_free(device); +} + +SDL_VideoDevice *PLAYBOOK_8Bit_CreateDevice(int devindex) +{ + SDL_VideoDevice *device; + + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice) + sizeof(struct SDL_PrivateVideoData)); + if ( device ) { + SDL_memset(device, 0, (sizeof *device)); + device->hidden = (struct SDL_PrivateVideoData *)(device+1); + } else { + SDL_OutOfMemory(); + return(0); + } + + /* Set the function pointers */ + device->VideoInit = PLAYBOOK_8Bit_VideoInit; + device->ListModes = PLAYBOOK_8Bit_ListModes; + device->SetVideoMode = PLAYBOOK_8Bit_SetVideoMode; + device->CreateYUVOverlay = PLAYBOOK_CreateYUVOverlay; + device->SetColors = PLAYBOOK_8Bit_SetColors; + device->UpdateRects = PLAYBOOK_8Bit_UpdateRects; + device->VideoQuit = PLAYBOOK_8Bit_VideoQuit; + device->AllocHWSurface = PLAYBOOK_AllocHWSurface; + device->CheckHWBlit = NULL; + device->FillHWRect = NULL; //PLAYBOOK_FillHWRect; + device->SetHWColorKey = NULL; + device->SetHWAlpha = NULL; + device->LockHWSurface = PLAYBOOK_LockHWSurface; + device->UnlockHWSurface = PLAYBOOK_UnlockHWSurface; + device->FlipHWSurface = PLAYBOOK_FlipHWSurface; + device->FreeHWSurface = PLAYBOOK_FreeHWSurface; + device->SetCaption = NULL; + device->SetIcon = NULL; + device->IconifyWindow = NULL; + device->GrabInput = NULL; + device->GetWMInfo = NULL; + device->InitOSKeymap = PLAYBOOK_InitOSKeymap; + device->PumpEvents = PLAYBOOK_PumpEvents; + + device->free = PLAYBOOK_8Bit_DeleteDevice; + + return device; +} + +SDL_Rect **PLAYBOOK_8Bit_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) +{ + if (format->BitsPerPixel != 8) + return (SDL_Rect**)-1; // Only support 8 bpp. + + if (flags & SDL_FULLSCREEN ) { + return _priv->SDL_modelist; + } else { + return (SDL_Rect**)-1; // We only support full-screen video modes. + } +} + +static int initializeGL(_THIS, int width, int height) +{ + const char *vs = + "attribute vec2 a_position;\n" + "attribute vec2 a_texcoord;\n" + "varying vec2 v_texcoord;\n" + "void main()\n" + "{\n" + " gl_Position = vec4(a_position, 0.0, 1.0);\n" + " v_texcoord = a_texcoord;\n" + "}\n"; + const char *fs = + "uniform lowp sampler2D u_sampler;\n" + "uniform lowp sampler2D u_palette;\n" // TODO: Palette should be 1D. + "varying mediump vec2 v_texcoord;\n" + "void main()\n" + "{\n" + " lowp float p = texture2D(u_sampler, v_texcoord).r;\n" + " gl_FragColor = texture2D(u_palette, vec2(p,0.0));\n" +// " gl_FragColor = texture2D(u_palette, v_texcoord);\n" +// " gl_FragColor = texture2D(u_sampler, v_texcoord);\n" +// " gl_FragColor = vec4(p, 1.0, 0.0, 1.0);\n" + "}\n"; + GLint status; + GLuint v, f, id; + GLchar log[256]; + GLuint textures[3]; + unsigned char palette[256*4] = {0}; + + v = glCreateShader(GL_VERTEX_SHADER); + if (!v) { + goto error1; + } + glShaderSource(v, 1, &vs, 0); + glCompileShader(v); + glGetShaderiv(v, GL_COMPILE_STATUS, &status); + if (GL_FALSE == status) { + glGetShaderInfoLog(v, 256, NULL, log); + fprintf(stderr, "Failed to compile vertex shader: %s\n", log); + goto error2; + } + + f = glCreateShader(GL_FRAGMENT_SHADER); + if (!f) { + goto error2; + } + glShaderSource(f, 1, &fs, 0); + glCompileShader(f); + glGetShaderiv(f, GL_COMPILE_STATUS, &status); + if (GL_FALSE == status) { + glGetShaderInfoLog(f, 256, NULL, log); + fprintf(stderr, "Failed to compile fragment shader: %s\n", log); + goto error3; + } + + id = glCreateProgram(); + if (!id) { + fprintf(stderr, "Failed to create shader program\n"); + goto error3; + } + glAttachShader(id, v); + glAttachShader(id, f); + glLinkProgram(id); + + glGetProgramiv(id, GL_LINK_STATUS, &status); + if (GL_FALSE == status) { + glGetProgramInfoLog(id, 256, NULL, log); + fprintf(stderr, "Failed to link shader program: %s\n", log); + goto error4; + } + + glDeleteShader(v); + glDeleteShader(f); + + _priv->glInfo.shader = id; + glUseProgram(id); + glUniform1i(glGetUniformLocation(id, "u_sampler"), 0); // screen texture is TEXTURE0 + glUniform1i(glGetUniformLocation(id, "u_palette"), 1); // palette texture is TEXTURE1 + _priv->glInfo.positionAttrib = glGetAttribLocation(id, "a_position"); + _priv->glInfo.texcoordAttrib = glGetAttribLocation(id, "a_texcoord"); + + glActiveTexture(GL_TEXTURE0); + glGenTextures(3, textures); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, textures[1]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textures[2]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette); + + _priv->glInfo.screen[0] = textures[0]; + _priv->glInfo.screen[1] = textures[1]; + _priv->glInfo.palette = textures[2]; + + return 1; // Success +error4: + glDeleteProgram(id); +error3: + glDeleteShader(f); +error2: + glDeleteShader(v); +error1: + return 0; // Failed to initialize +} + +static SDL_Palette *AllocatePalette(int size) +{ + SDL_Palette *palette; + SDL_Color *colors; + + palette = SDL_calloc (1, sizeof(SDL_Palette)); + if (!palette) + { + SDL_OutOfMemory(); + return NULL; + } + + colors = SDL_calloc (size, sizeof(SDL_Color)); + if (!colors) + { + SDL_OutOfMemory(); + return NULL; + } + + palette->ncolors = size; + palette->colors = colors; + + return palette; +} + +SDL_Surface *PLAYBOOK_8Bit_SetVideoMode(_THIS, SDL_Surface *current, + int width, int height, int bpp, Uint32 flags) +{ + int rc; + EGLint attributes[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + EGLint contextAttributes[3] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + EGLConfig configs[1]; + EGLint configCount; + screen_window_t screenWindow; + int format = SCREEN_FORMAT_RGBX8888; + int sizeOfWindow[2] = {1024, 600}; +// int sizeOfBuffer[2] = {width, height}; + int usage = SCREEN_USAGE_OPENGL_ES2; + EGLint eglSurfaceAttributes[3] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE }; + + if (!_priv->screenWindow) { + + _priv->eglInfo.eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (_priv->eglInfo.eglDisplay == EGL_NO_DISPLAY) { + egl_perror("eglGetDisplay"); + goto error1; + } + + rc = eglInitialize(_priv->eglInfo.eglDisplay, NULL, NULL); + if (rc != EGL_TRUE) { + egl_perror("eglInitialize"); + goto error1; + } + + rc = eglBindAPI(EGL_OPENGL_ES_API); + if (rc != EGL_TRUE) { + egl_perror("eglBindAPI"); + goto error2; + } + + rc = eglChooseConfig(_priv->eglInfo.eglDisplay, attributes, configs, 1, &configCount); + if (rc != EGL_TRUE) { + egl_perror("eglBindAPI"); + eglTerminate(_priv->eglInfo.eglDisplay); + return NULL; + } else if (configCount <= 0) { + fprintf(stderr, "No matching configurations found."); + goto error2; + } + + _priv->eglInfo.eglContext = eglCreateContext(_priv->eglInfo.eglDisplay, configs[0], EGL_NO_CONTEXT, contextAttributes); + if (_priv->eglInfo.eglContext == EGL_NO_CONTEXT) { + egl_perror("eglCreateContext"); + goto error2; + } + + screenWindow = PLAYBOOK_CreateWindow(this, current, width, height, bpp); + if (screenWindow == NULL) { + goto error3; + } + + rc = screen_set_window_property_iv(screenWindow, SCREEN_PROPERTY_SIZE, sizeOfWindow); + if (rc) { + SDL_SetError("Cannot resize window: %s", strerror(errno)); + screen_destroy_window(screenWindow); + return NULL; + } + +// rc = screen_set_window_property_iv(screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, sizeOfBuffer); +// if (rc) { +// SDL_SetError("Cannot resize window buffer: %s", strerror(errno)); +// screen_destroy_window(screenWindow); +// return NULL; +// } + + rc = screen_set_window_property_iv(screenWindow, SCREEN_PROPERTY_FORMAT, &format); + if (rc) { + SDL_SetError("Cannot set window format: %s", strerror(errno)); + goto error4; + } + + rc = screen_set_window_property_iv(screenWindow, SCREEN_PROPERTY_USAGE, &usage); + if (rc) { + SDL_SetError("Cannot set window usage: %s", strerror(errno)); + goto error4; + } + + rc = screen_create_window_buffers(screenWindow, 2); + if (rc) { + SDL_SetError("Cannot create window buffers: %s", strerror(errno)); + goto error4; + } + + _priv->eglInfo.eglSurface = eglCreateWindowSurface(_priv->eglInfo.eglDisplay, configs[0], + screenWindow, (EGLint*)&eglSurfaceAttributes); + if (_priv->eglInfo.eglSurface == EGL_NO_SURFACE) { + egl_perror("eglCreateWindowSurface"); + goto error4; + } + + rc = eglMakeCurrent(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglSurface, _priv->eglInfo.eglSurface, _priv->eglInfo.eglContext); + if (rc != EGL_TRUE) { + egl_perror("eglMakeCurrent"); + goto error5; + } + + glClearColor(0.0, 0.0, 0.0, 1.0); + glDisable(GL_DEPTH_TEST); + if (!initializeGL(this, width, height)) { + SDL_SetError("Failed to initialize GL"); + goto error5; + } + + initializeOverlay(this, screenWindow); + + _priv->screenWindow = screenWindow; + } else { + glDeleteTextures(2, _priv->glInfo.screen); + + glActiveTexture(GL_TEXTURE0); + glGenTextures(2, _priv->glInfo.screen); + glBindTexture(GL_TEXTURE_2D, _priv->glInfo.screen[0]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, _priv->glInfo.screen[1]); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + SDL_free(_priv->surface->pixels); + } + current->flags &= ~SDL_RESIZABLE; + current->flags |= SDL_FULLSCREEN; + current->flags |= SDL_HWSURFACE; + current->flags |= SDL_HWPALETTE; + current->w = width; + current->h = height; + SDL_ReallocFormat(current, 8, 0, 0, 0, 0); // FIXME: Does this allocate twice? + current->pitch = width; + current->pixels = SDL_calloc(width * height, 1); +// this->physpal = AllocatePalette(256); +// current->format->palette = this->physpal; + _priv->surface = current; + + return current; +error5: + eglDestroySurface(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglSurface); + _priv->eglInfo.eglSurface = 0; +error4: + screen_destroy_window(screenWindow); +error3: + eglDestroyContext(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglContext); + _priv->eglInfo.eglContext = 0; +error2: + eglTerminate(_priv->eglInfo.eglDisplay); + _priv->eglInfo.eglDisplay = 0; +error1: + return NULL; +} + +static const unsigned sampleDuration = 100; +static unsigned frameCounter = 0; +static double lastSampledTime = 0; +static double getTime() +{ + struct timespec tm; + clock_gettime(CLOCK_MONOTONIC, &tm); + return tm.tv_sec * 1000.0f + tm.tv_nsec / 1000000.0f; +} + +static void printFPS() +{ + double diff = getTime() - lastSampledTime; + if (diff > sampleDuration) { + double rawFPS = frameCounter / (diff/1000); + unsigned sampleFPS = (unsigned)((rawFPS*100)/100); + frameCounter = 0; + lastSampledTime = getTime(); + fprintf(stderr, "FPS: %u\n", sampleFPS); + } +} + +void PLAYBOOK_8Bit_UpdateRects(_THIS, int numrects, SDL_Rect *rects) +{ + if (!this || !_priv || !_priv->surface) + return; + + glClear(GL_COLOR_BUFFER_BIT); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _priv->glInfo.screen[_priv->glInfo.writableScreen]); + _priv->glInfo.writableScreen = !_priv->glInfo.writableScreen; + int i=0; + + // TODO: Need to respect the rects, rather than always update full screen. + + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _priv->surface->w, _priv->surface->h, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, _priv->surface->pixels); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _priv->glInfo.palette); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(_priv->glInfo.positionAttrib); + glEnableVertexAttribArray(_priv->glInfo.texcoordAttrib); + static const GLfloat vertices[] = {-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0,1.0}; + static const GLfloat texCoords[] = {0.0,1.0,1.0,1.0,0.0,0.0,1.0,0.0}; + glVertexAttribPointer(_priv->glInfo.positionAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), vertices); + glVertexAttribPointer(_priv->glInfo.texcoordAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), texCoords); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + eglSwapBuffers(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglSurface); + +// frameCounter++; +// printFPS(); +} + +int PLAYBOOK_8Bit_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) +{ + static int flip = 0; + flip++; + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _priv->glInfo.palette); + int i=0; + static unsigned char c[256*4] = {0}; + for (i=0; iglInfo.screen[!_priv->glInfo.writableScreen]); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(_priv->glInfo.positionAttrib); + glEnableVertexAttribArray(_priv->glInfo.texcoordAttrib); + static const GLfloat vertices[] = {-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0,1.0}; + static const GLfloat texCoords[] = {0.0,1.0,1.0,1.0,0.0,0.0,1.0,0.0}; + glVertexAttribPointer(_priv->glInfo.positionAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), vertices); + glVertexAttribPointer(_priv->glInfo.texcoordAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), texCoords); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + eglSwapBuffers(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglSurface); + flip=0; + } +// frameCounter++; +// printFPS(); + return(1); +} + +void PLAYBOOK_8Bit_VideoQuit(_THIS) +{ + if (_priv->screenWindow) { + eglDestroySurface(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglSurface); + screen_destroy_window(_priv->screenWindow); + eglDestroyContext(_priv->eglInfo.eglDisplay, _priv->eglInfo.eglContext); + eglTerminate(_priv->eglInfo.eglDisplay); + } + screen_stop_events(_priv->screenContext); + screen_destroy_event(_priv->screenEvent); + screen_destroy_context(_priv->screenContext); + bps_shutdown(); + tco_shutdown(_priv->emu_context); + this->screen = 0; +} + diff --git a/src/video/playbook/SDL_playbookvideo_8bit_c.h b/src/video/playbook/SDL_playbookvideo_8bit_c.h new file mode 100644 index 0000000..aafa8b1 --- /dev/null +++ b/src/video/playbook/SDL_playbookvideo_8bit_c.h @@ -0,0 +1,23 @@ +/* + * SDL_playbookvideo_8bit_c.h + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#ifndef SDL_PLAYBOOKVIDEO_8BIT_C_H_ +#define SDL_PLAYBOOKVIDEO_8BIT_C_H_ + +#include "SDL_config.h" + +#include "SDL_video.h" +#include "SDL_playbookvideo.h" + +extern int PLAYBOOK_8Bit_VideoInit(_THIS, SDL_PixelFormat *vformat); +extern SDL_Rect **PLAYBOOK_8Bit_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); +extern SDL_Surface *PLAYBOOK_8Bit_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); +extern void PLAYBOOK_8Bit_VideoQuit(_THIS); +extern int PLAYBOOK_8Bit_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); +extern void PLAYBOOK_8Bit_UpdateRects(_THIS, int numrects, SDL_Rect *rects); + +#endif /* SDL_PLAYBOOKVIDEO_8BIT_C_H_ */ diff --git a/src/video/playbook/SDL_playbookvideo_c.h b/src/video/playbook/SDL_playbookvideo_c.h new file mode 100644 index 0000000..d4ca563 --- /dev/null +++ b/src/video/playbook/SDL_playbookvideo_c.h @@ -0,0 +1,28 @@ +/* + * SDL_playbookvideo_c.h + * + * Created on: Nov 23, 2011 + * Author: jnicholl + */ + +#ifndef SDL_PLAYBOOKVIDEO_C_H_ +#define SDL_PLAYBOOKVIDEO_C_H_ + +#include "SDL_config.h" + +#include "SDL_video.h" +#include "SDL_playbookvideo.h" +#include + +/* Initialization/Query functions */ +extern int PLAYBOOK_VideoInit(_THIS, SDL_PixelFormat *vformat); +extern SDL_Rect **PLAYBOOK_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); +extern screen_window_t PLAYBOOK_CreateWindow(); +extern SDL_Surface *PLAYBOOK_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); +extern int PLAYBOOK_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); +extern void PLAYBOOK_VideoQuit(_THIS); + +/* etc. */ +extern void PLAYBOOK_UpdateRects(_THIS, int numrects, SDL_Rect *rects); + +#endif /* SDL_PLAYBOOKVIDEO_C_H_ */