aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Guryanov <caiiiycuk@gmail.com>2012-06-09 00:07:12 +0700
committerAleksander Guryanov <caiiiycuk@gmail.com>2012-06-13 20:55:11 +0700
commitaad005f54a21a91b64bc07fe7ede67bd79f4f2d2 (patch)
tree62851317e180d7971678a2cfd61a54e263d66bc0
parentc406b3bc87fa69ae6a1fc7a1c6c8b7118f4ffec4 (diff)
Implementation of SDL_HWPALETTE
Little bit refactoring for copyIndexedColorData now it can accept dirty rect
-rw-r--r--src/library_sdl.js113
-rwxr-xr-xtests/runner.py13
-rw-r--r--tests/sdl_canvas_palette.c61
-rw-r--r--tests/sdl_canvas_palette_2.c77
4 files changed, 254 insertions, 10 deletions
diff --git a/src/library_sdl.js b/src/library_sdl.js
index f7d2f1bf..7011e679 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -218,6 +218,10 @@ var LibrarySDL = {
return 'rgba(' + r + ',' + g + ',' + b + ',' + (a/255) + ')';
},
+ translateRGBAToColor: function(r, g, b, a) {
+ return (r << 24) + (g << 16) + (b << 8) + a;
+ },
+
makeSurface: function(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) {
flags = flags || 0;
var surf = _malloc(14*Runtime.QUANTUM_SIZE); // SDL_Surface has 14 fields of quantum size
@@ -225,19 +229,23 @@ var LibrarySDL = {
var pixelFormat = _malloc(18*Runtime.QUANTUM_SIZE);
flags |= 1; // SDL_HWSURFACE - this tells SDL_MUSTLOCK that this needs to be locked
+ //surface with SDL_HWPALETTE flag is 8bpp surface (1 byte)
+ var is_SDL_HWPALETTE = flags & 0x00200000;
+ var bpp = is_SDL_HWPALETTE ? 1 : 4;
+
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}} // SDL_Surface.flags
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*1', '0', 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*2', '0', 'width', 'i32') }}} // SDL_Surface.w
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*3', '0', 'height', 'i32') }}} // SDL_Surface.h
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*4', '0', 'width*4', 'i32') }}} // SDL_Surface.pitch, assuming RGBA for now,
+ {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*4', '0', 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now,
// since that is what ImageData gives us in browsers
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*5', '0', 'buffer', 'void*') }}} // SDL_Surface.pixels
{{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*6', '0', '0', 'i32*') }}} // SDL_Surface.offset
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.format', '0', '-2042224636', 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.palette', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BitsPerPixel', '0', '32', 'i8') }}} // TODO
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BytesPerPixel', '0', '4', 'i8') }}} // TODO
+ {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BitsPerPixel', '0', 'bpp * 8', 'i8') }}}
+ {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BytesPerPixel', '0', 'bpp', 'i8') }}}
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Rmask', '0', 'rmask || 0x000000ff', 'i32') }}}
{{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Gmask', '0', 'gmask || 0x0000ff00', 'i32') }}}
@@ -267,11 +275,54 @@ var LibrarySDL = {
flags: flags,
locked: 0,
usePageCanvas: usePageCanvas,
- source: source
+ source: source,
+
+ isFlagSet: function (flag) {
+ return flags & flag;
+ }
};
+
return surf;
},
+ // Copy data from the C++-accessible storage to the canvas backing
+ // for surface with HWPALETTE flag(8bpp depth)
+ copyIndexedColorData: function(surfData, rX, rY, rW, rH) {
+ // HWPALETTE works with palette
+ // setted by SDL_SetColors
+ if (!surfData.colors) {
+ return;
+ }
+
+ var fullWidth = Module['canvas'].width;
+ var fullHeight = Module['canvas'].height;
+
+ var startX = rX || 0;
+ var startY = rY || 0;
+ var endX = (rW || (fullWidth - startX)) + startX;
+ var endY = (rH || (fullHeight - startY)) + startY;
+
+ var buffer = surfData.buffer;
+ var data = surfData.image.data;
+ var colors = surfData.colors;
+
+ for (var y = startY; y < endY; ++y) {
+ var indexBase = y * fullWidth;
+ var colorBase = indexBase * 4;
+ for (var x = startX; x < endX; ++x) {
+ // HWPALETTE have only 256 colors (not rgba)
+ var index = {{{ makeGetValue('buffer + indexBase + x', '0', 'i8', null, true) }}};
+ var color = colors[index] || [Math.floor(Math.random()*255),Math.floor(Math.random()*255),Math.floor(Math.random()*255)]; // XXX
+ var colorOffset = colorBase + x * 4;
+
+ data[colorOffset ] = color[0];
+ data[colorOffset +1] = color[1];
+ data[colorOffset +2] = color[2];
+ //unused: data[colorOffset +3] = color[3];
+ }
+ }
+ },
+
freeSurface: function(surf) {
_free(SDL.surfaces[surf].buffer);
_free(SDL.surfaces[surf].pixelFormat);
@@ -566,6 +617,26 @@ var LibrarySDL = {
}
if (SDL.defaults.copyOnLock) {
// Copy pixel data to somewhere accessible to 'C/C++'
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ // If this is neaded then
+ // we should compact the data from 32bpp to 8bpp index.
+ // I think best way to implement this is use
+ // additional colorMap hash (color->index).
+ // Something like this:
+ //
+ // var size = surfData.width * surfData.height;
+ // var data = '';
+ // for (var i = 0; i<size; i++) {
+ // var color = SDL.translateRGBAToColor(
+ // surfData.image.data[i*4 ],
+ // surfData.image.data[i*4 +1],
+ // surfData.image.data[i*4 +2],
+ // 255);
+ // var index = surfData.colorMap[color];
+ // {{{ makeSetValue('surfData.buffer', 'i', 'index', 'i8') }}};
+ // }
+ throw 'CopyOnLock is not supported for SDL_LockSurface with SDL_HWPALETTE flag set' + new Error().stack;
+ } else {
#if USE_TYPED_ARRAYS == 2
HEAPU8.set(surfData.image.data, surfData.buffer);
#else
@@ -574,7 +645,9 @@ var LibrarySDL = {
{{{ makeSetValue('surfData.buffer', 'i', 'surfData.image.data[i]', 'i8') }}};
}
#endif
+ }
}
+
// Mark in C/C++-accessible SDL structure
// SDL_Surface has the following fields: Uint32 flags, SDL_PixelFormat *format; int w, h; Uint16 pitch; void *pixels; ...
// So we have fields all of the same size, and 5 of them before us.
@@ -592,8 +665,10 @@ var LibrarySDL = {
if (surfData.locked > 0) return;
// Copy pixel data to image
- var num = surfData.image.data.length;
- if (!surfData.colors) {
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ SDL.copyIndexedColorData(surfData);
+ } else if (!surfData.colors) {
+ var num = surfData.image.data.length;
var data = surfData.image.data;
var buffer = surfData.buffer;
#if USE_TYPED_ARRAYS == 2
@@ -615,7 +690,7 @@ var LibrarySDL = {
for (var i = 0; i < num; i++) {
// We may need to correct signs here. Potentially you can hardcode a write of 255 to alpha, say, and
// the compiler may decide to write -1 in the llvm bitcode...
- data[i] = {{{ makeGetValue('buffer', 'i', 'i8') + (CORRECT_SIGNS ? '&0xff' : '') }}};
+ data[i] = {{{ makeGetValue('buffer', 'i', 'i8', null, true) }}};
if (i % 4 == 3) data[i] = 0xff;
}
#endif
@@ -629,7 +704,7 @@ var LibrarySDL = {
var base = y*width*4;
for (var x = 0; x < width; x++) {
// See comment above about signs
- var val = {{{ makeGetValue('s++', '0', 'i8') + (CORRECT_SIGNS ? '&0xff' : '') }}};
+ var val = {{{ makeGetValue('s++', '0', 'i8', null, true) }}};
var color = colors[val] || [Math.floor(Math.random()*255),Math.floor(Math.random()*255),Math.floor(Math.random()*255)]; // XXX
var start = base + x*4;
data[start] = color[0];
@@ -753,6 +828,15 @@ var LibrarySDL = {
SDL_FillRect: function(surf, rect, color) {
var surfData = SDL.surfaces[surf];
assert(!surfData.locked); // but we could unlock and re-lock if we must..
+
+ if (surfData.isFlagSet(0x00200000 /* SDL_HWPALETTE */)) {
+ //in SDL_HWPALETTE color is index (0..255)
+ //so we should translate 1 byte value to
+ //32 bit canvas
+ color = surfData.colors[color] || [0, 0, 0, 255];
+ color = SDL.translateRGBAToColor(color[0], color[1], color[2], 255);
+ }
+
var r = SDL.loadRect(rect);
surfData.ctx.save();
surfData.ctx.fillStyle = SDL.translateColorToCSSRGBA(color);
@@ -809,8 +893,16 @@ var LibrarySDL = {
SDL_SetColors: function(surf, colors, firstColor, nColors) {
var surfData = SDL.surfaces[surf];
- surfData.colors = [];
- for (var i = firstColor; i < nColors; i++) {
+
+ // we should create colors array
+ // only once cause client code
+ // often wants to change portion
+ // of palette not all palette.
+ if (!surfData.colors) {
+ surfData.colors = [];
+ }
+
+ for (var i = firstColor; i < firstColor + nColors; i++) {
surfData.colors[i] = [
{{{ makeGetValue('colors', 'i*4', 'i8', null, true) }}},
{{{ makeGetValue('colors', 'i*4 + 1', 'i8', null, true) }}},
@@ -818,6 +910,7 @@ var LibrarySDL = {
{{{ makeGetValue('colors', 'i*4 + 3', 'i8', null, true) }}}
];
}
+
return 1;
},
diff --git a/tests/runner.py b/tests/runner.py
index 779e51da..49991498 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -7448,6 +7448,19 @@ elif 'browser' in str(sys.argv):
Popen(['python', EMCC, os.path.join(self.get_dir(), 'sdl_canvas.c'), '-o', 'page.html']).communicate()
self.run_browser('page.html', '', '/report_result?1')
+ def test_sdl_canvas_palette(self):
+ open(os.path.join(self.get_dir(), 'sdl_canvas_palette.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas_palette.c')).read()))
+
+ Popen(['python', EMCC, os.path.join(self.get_dir(), 'sdl_canvas_palette.c'), '-o', 'page.html']).communicate()
+ self.run_browser('page.html', '')
+
+ def test_sdl_canvas_palette_2(self):
+ open(os.path.join(self.get_dir(), 'sdl_canvas_palette_2.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_canvas_palette_2.c')).read()))
+ open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('Module[\'preRun\'] = function() { SDL.defaults.copyOnLock = false }')
+
+ Popen(['python', EMCC, os.path.join(self.get_dir(), 'sdl_canvas_palette_2.c'), '-o', 'page.html', '--pre-js', 'pre.js']).communicate()
+ self.run_browser('page.html', '')
+
def test_sdl_key(self):
open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
Module.postRun = function() {
diff --git a/tests/sdl_canvas_palette.c b/tests/sdl_canvas_palette.c
new file mode 100644
index 00000000..1ba07760
--- /dev/null
+++ b/tests/sdl_canvas_palette.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <SDL/SDL.h>
+#include <emscripten.h>
+
+int main() {
+ SDL_Init(SDL_INIT_VIDEO);
+ SDL_Surface *screen = SDL_SetVideoMode(600, 400, 8, SDL_HWSURFACE | SDL_HWPALETTE);
+
+ //initialize sdl palette
+ //with red green and blue
+ //colors
+ SDL_Color pal[3];
+ pal[0].r = 255;
+ pal[0].g = 0;
+ pal[0].b = 0;
+ pal[0].unused = 0;
+
+ pal[1].r = 0;
+ pal[1].g = 255;
+ pal[1].b = 0;
+ pal[1].unused = 0;
+
+ pal[2].r = 0;
+ pal[2].g = 0;
+ pal[2].b = 255;
+ pal[2].unused = 0;
+
+ SDL_SetColors(screen, pal, 0, 3);
+
+ {
+ SDL_Rect rect = { 0, 0, 300, 200 };
+ SDL_FillRect(screen, &rect, 0);
+ }
+
+ {
+ SDL_Rect rect = { 300, 0, 300, 200 };
+ SDL_FillRect(screen, &rect, 1);
+ }
+
+ {
+ SDL_Rect rect = { 0, 200, 600, 200 };
+ SDL_FillRect(screen, &rect, 2);
+ }
+
+ //changing green color
+ //to yellow
+ pal[1].r = 255;
+ SDL_SetColors(screen, pal, 1, 1);
+
+ {
+ SDL_Rect rect = { 300, 200, 300, 200 };
+ SDL_FillRect(screen, &rect, 1);
+ }
+
+ printf("you should see red, blue and yellow rectangle\n");
+
+ SDL_Quit();
+
+ return 0;
+}
+
diff --git a/tests/sdl_canvas_palette_2.c b/tests/sdl_canvas_palette_2.c
new file mode 100644
index 00000000..db051b2b
--- /dev/null
+++ b/tests/sdl_canvas_palette_2.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <SDL/SDL.h>
+#include <emscripten.h>
+
+static const int COLOR_COUNT = 32;
+
+static SDL_Surface *screen;
+static SDL_Color pal[COLOR_COUNT +1];
+
+void initializePalette() {
+ //initialize sdl palette
+ //with red green and blue
+ //colors
+ pal[0].r = 0;
+ pal[0].g = 0;
+ pal[0].b = 0;
+ pal[0].unused = 0;
+
+ for (int i=1; i< 1 + COLOR_COUNT; i++) {
+ pal[i].r = 255 / COLOR_COUNT * i;
+ pal[i].g = 0;
+ pal[i].b = 0;
+ pal[i].unused = 0;
+ }
+
+ SDL_SetColors(screen, pal, 0, 1 + COLOR_COUNT);
+}
+
+void animatePalette() {
+ SDL_Color temporary;
+ temporary = pal[1];
+ for (int i=2; i< 1 + COLOR_COUNT; i++) {
+ pal[i-1] = pal[i];
+ }
+ pal[COLOR_COUNT] = temporary;
+
+ SDL_SetColors(screen, pal, 1, COLOR_COUNT);
+
+ //refreshing
+ SDL_LockSurface(screen);
+ SDL_UnlockSurface(screen);
+
+ printf("yet another cycle\n");
+}
+
+int main() {
+ SDL_Init(SDL_INIT_VIDEO);
+ screen = SDL_SetVideoMode(600, 400, 8, SDL_HWSURFACE | SDL_HWPALETTE);
+
+ //test empty pallete
+ SDL_LockSurface(screen);
+ SDL_UnlockSurface(screen);
+
+ initializePalette();
+
+ //palette is red yellow blue
+ SDL_LockSurface(screen);
+ int size = screen->h * screen->pitch;
+ char *color = screen->pixels;
+ int divider = size / COLOR_COUNT;
+ int i = 0;
+ while (i < size) {
+ *color = 1 + (i / divider); //red
+ color++;
+ i++;
+ }
+ SDL_UnlockSurface(screen);
+
+ //Animation
+ printf("you should see red gradient animation\n");
+ emscripten_set_main_loop(animatePalette, 0);
+
+ SDL_Quit();
+
+ return 0;
+}
+