shithub: npe

Download patch

ref: b699be1156cb41be910dadb3c8a6df0bea12bf67
parent: d85902512f9a5208b21a39ea7d861c236d701ca1
author: Jacob Moody <moody@posixcafe.org>
date: Wed Aug 30 20:20:38 EDT 2023

sdl2: refactor image channel code, more palette function coverage

--- a/include/npe/SDL2/SDL.h
+++ b/include/npe/SDL2/SDL.h
@@ -46,7 +46,18 @@
 
 #define SDL_zero(x) do{ memset(&(x), 0, sizeof(x)); }while(0)
 #define SDL_memset memset
+#define SDL_malloc malloc
 #define SDL_realloc realloc
+#define SDL_calloc calloc
+#define SDL_memcpy memcpy
+#define SDL_memmove memmove
+#define SDL_memcmp memcmp
+#define SDL_printf printf
+#define SDL_snprintf snprintf
+#define SDL_strlen strlen
+#define SDL_strlcpy strlcpy
+#define SDL_strstr strstr
+#define SDL_strncmp strncmp
 
 #include <SDL2/SDL_keycode.h>
 #include <SDL2/SDL_scancode.h>
@@ -81,6 +92,7 @@
 void SDL_RaiseWindow(SDL_Window *window);
 int SDL_UpdateTexture(SDL_Texture *texture, SDL_Rect *rect, void *pixels, int pitch);
 int SDL_RenderClear(SDL_Renderer *renderer);
+int SDL_RenderFillRect(SDL_Renderer *r, SDL_Rect *rect);
 int SDL_GetWindowDisplayIndex(SDL_Window *window);
 void SDL_FreeSurface(SDL_Surface *surface);
 Uint32 SDL_GetGlobalMouseState(int *x, int *y);
@@ -92,6 +104,7 @@
 SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int w, int h, int bpp, Uint32 fmt);
 SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am);
 SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int w, int h, int bpp, int pitch, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am);
+void SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat *format, Uint8 *r, Uint8 *g, Uint8 *b);
 Uint32 SDL_MapRGB(SDL_PixelFormat *format, Uint8 r, Uint8 g, Uint8 b);
 int SDL_SetColorKey(SDL_Surface *surface, int flag, Uint32 key);
 int SDL_SetSurfaceRLE(SDL_Surface *surface, int flag);
@@ -121,6 +134,7 @@
 void SDL_DestroyTexture(SDL_Texture *texture);
 void SDL_DestroyRenderer(SDL_Renderer *renderer);
 void SDL_DestroyWindow(SDL_Window *window);
+int SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect *rect);
 int SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode *mode);
 void SDL_SetWindowTitle(SDL_Window *window, char *title);
 int SDL_SetTextureBlendMode(SDL_Texture *texture, SDL_BlendMode blendMode);
@@ -127,6 +141,7 @@
 SDL_bool SDL_SetHint(char *name, char *value);
 SDL_Window *SDL_CreateWindow(char *title, int x, int y, int w, int h, Uint32 flags);
 SDL_Renderer *SDL_CreateRenderer(SDL_Window *window, int index, Uint32 flags);
+int SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags, SDL_Window **window, SDL_Renderer **renderer);
 int SDL_SetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode);
 char *SDL_GetCurrentVideoDriver(void);
 SDL_Texture *SDL_CreateTexture(SDL_Renderer *renderer, Uint32 format, int access, int w, int h);
@@ -133,6 +148,7 @@
 void SDL_EnableScreenSaver(void);
 Uint32 SDL_GetTicks(void);
 int SDL_GetRendererOutputSize(SDL_Renderer *renderer, int *w, int *h);
+void SDL_RenderGetViewport(SDL_Renderer *rebderer, SDL_Rect *rect);
 int SDL_SaveBMP(SDL_Surface *s, const char *file);
 void SDL_ClearError(void);
 int SDL_SetTextureAlphaMod(SDL_Texture *texture, Uint8 alpha);
@@ -156,7 +172,9 @@
 #define SDL_mutexV(x) SDL_UnlockMutex(x)
 #define SDL_mutexP(x) SDL_LockMutex(x)
 int SDL_FillRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color);
+SDL_Palette *SDL_AllocPalette(int ncolors);
 int SDL_SetPaletteColors(SDL_Palette *palette, const SDL_Color *colors, int firstcolor, int ncolors);
+int SDL_SetSurfacePalette(SDL_Surface *s, SDL_Palette *palette);
 int SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
 int SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
 int SDL_LockTexture(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch);
@@ -197,7 +215,10 @@
 	SDL_PIXELFORMAT_INDEX8 = 0x13000801,
 	SDL_PIXELFORMAT_RGB24 = 0x17101803,
 	SDL_PIXELFORMAT_ABGR8888 = 0x16762004,
+	SDL_PIXELFORMAT_XBGR8888 = 0x16561804,
+	SDL_PIXELFORMAT_BGR24 = 0x17401803,
 	SDL_PIXELFORMAT_RGB888 = SDL_PIXELFORMAT_XRGB8888,
+	SDL_PIXELFORMAT_BGR888 = SDL_PIXELFORMAT_XBGR8888,
 
 	/* shit no one cares about */
 	SDL_TEXTUREACCESS_STREAMING = 0,
@@ -245,6 +266,7 @@
 #define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4"
 #define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH "SDL_MOUSE_FOCUS_CLICKTHROUGH"
 #define SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING "SDL_WINDOWS_DISABLE_THREAD_NAMING"
+#define SDL_HINT_RENDER_VSYNC "SDL_RENDER_VSYNC"
 
 struct SDL_Point {
 	int x, y;
@@ -288,6 +310,7 @@
 struct SDL_PixelFormat {
 	SDL_Palette *palette;
 	int format;
+	int BytesPerPixel;
 };
 
 struct SDL_RendererInfo {
--- a/include/npe/SDL2/SDL_events.h
+++ b/include/npe/SDL2/SDL_events.h
@@ -58,6 +58,7 @@
 typedef struct SDL_Keysym SDL_Keysym;
 typedef struct SDL_Event SDL_Event;
 typedef int SDL_eventaction;
+typedef int (*SDL_EventFilter)(void *userdata, SDL_Event *event);
 
 struct SDL_WindowEvent {
 	Uint32	type;
@@ -127,6 +128,7 @@
 	struct {
 		int x, y;
 		int xrel, yrel;
+		int state;
 	}motion;
 	struct {
 		char text[SDL_TEXTINPUTEVENT_TEXT_SIZE+1];
@@ -145,5 +147,9 @@
 int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action, Uint32 minType, Uint32 maxType);
 Uint32 SDL_GetWindowID(SDL_Window *window);
 void SDL_PumpEvents(void);
+void SDL_SetEventFilter(SDL_EventFilter filter, void *userdata);
+SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key);
+Uint8* SDL_GetKeyboardState(int *numkeys);
+char* SDL_GetKeyName(SDL_Keycode key);
 
 #endif
--- a/include/npe/string.h
+++ b/include/npe/string.h
@@ -5,5 +5,6 @@
 
 char *strerror(int errnum);
 int strerror_r(int errnum, char *buf, size_t buflen);
+size_t strlcpy(char *dst, char *src, size_t sz);
 
 #endif
--- a/libnpe/mkfile
+++ b/libnpe/mkfile
@@ -62,6 +62,7 @@
 	strerror.$O\
 	strerror_r.$O\
 	strftime.$O\
+	strlcpy.$O\
 	trunc.$O\
 	unlink.$O\
 	usleep.$O\
--- /dev/null
+++ b/libnpe/strlcpy.c
@@ -1,0 +1,19 @@
+#include <string.h>
+
+size_t
+strlcpy(char *dst, char *src, size_t sz)
+{
+	char *start;
+
+	start = src;
+	if(sz == 0)
+		return strlen(start);
+
+	while(sz-- > 0 && (*dst++ = *src++) != '\0')
+		;
+	if(dst[-1] != '\0')
+		dst[-1] = '\0';
+	while(*src++)
+		;
+	return src - start - 1;
+}
--- a/libnpe_sdl2/_sdl.h
+++ b/libnpe_sdl2/_sdl.h
@@ -1,6 +1,7 @@
 #include <SDL2/SDL.h>
 #include <sys/stat.h>
 #include <stdint.h>
+#include <string.h>
 #include <tos.h>
 #include <thread.h>
 #include <draw.h>
--- a/libnpe_sdl2/events.c
+++ b/libnpe_sdl2/events.c
@@ -26,7 +26,6 @@
 	[Numchan] = { nil, nil, CHANNOBLK },
 };
 
-static int rune2scancode(Rune r);
 static void kbdproc(void *);
 static void mouseproc(void *);
 
@@ -91,7 +90,22 @@
 	return quitreq;
 }
 
+struct {
+	SDL_EventFilter f;
+	void *aux;
+} filter = {
+	nil,
+	nil,
+};
+
 void
+SDL_SetEventFilter(SDL_EventFilter f, void *userdata)
+{
+	filter.f = f;
+	filter.aux = userdata;
+}
+
+void
 SDL_PumpEvents(void)
 {
 	/* FIXME does it matter? */
@@ -116,20 +130,20 @@
 				break;
 			e->type = SDL_TEXTINPUT;
 			e->text.text[runetochar(e->text.text, &rune)] = 0;
-			return 1;
+			goto Filter;
 		}else if((npe_sdl.hints & Altf4noclose) == 0 && (kmod & KMOD_LALT) != 0 && rune == (KF|4)){
 			e->type = SDL_QUIT;
 			quitreq = 1;
-			return 1;
+			goto Filter;
 		}else{
 			e->type = (t == Rup) ? SDL_KEYUP : SDL_KEYDOWN;
 			e->key.repeat = t == Rrepeat;
-			e->key.keysym.scancode = rune2scancode(rune);
+			e->key.keysym.scancode = SDL_GetScancodeFromKey(rune);
 			if(rune == '\n')
 				rune = SDLK_RETURN;
 			e->key.keysym.sym = rune;
 			e->key.state = e->type;
-			return 1;
+			goto Filter;
 		}
 		break;
 
@@ -153,7 +167,8 @@
 			npe_sdl.mredraw = 1;
 			if(npe_sdl.m.buttons == npe_sdl.om.buttons){
 				e->type = SDL_MOUSEMOTION;
-				return 1;
+				e->motion.state = npe_sdl.m.buttons;
+				goto Filter;
 			}
 		}
 		if(npe_sdl.m.buttons == npe_sdl.om.buttons)
@@ -163,25 +178,25 @@
 			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
 			e->button.button = SDL_BUTTON_LEFT;
 			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~1) | (npe_sdl.m.buttons & 1);
-			return 1;
+			goto Filter;
 		}
 		if((down = (npe_sdl.m.buttons & 2)) != (npe_sdl.om.buttons & 2)){ /* middle */
 			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
 			e->button.button = SDL_BUTTON_MIDDLE;
 			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~2) | (npe_sdl.m.buttons & 2);
-			return 1;
+			goto Filter;
 		}
 		if((down = (npe_sdl.m.buttons & 4)) != (npe_sdl.om.buttons & 4)){ /* right */
 			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
 			e->button.button = SDL_BUTTON_RIGHT;
 			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~4) | (npe_sdl.m.buttons & 4);
-			return 1;
+			goto Filter;
 		}
 		if(npe_sdl.m.buttons & (8|16)){
 			e->type = SDL_MOUSEWHEEL;
 			e->wheel.x = 0;
 			e->wheel.y = (npe_sdl.m.buttons & 8) ? 1 : -1;
-			return 1;
+			goto Filter;
 		}
 		break;
 
@@ -193,10 +208,15 @@
 		e->type = SDL_WINDOWEVENT;
 		e->window.event = SDL_WINDOWEVENT_EXPOSED;
 		e->window.windowID = 1; //TODO more then one?
-		return 1;
+		goto Filter;
 	}
 
 	return 0;
+
+Filter:
+	if(filter.f != nil && filter.f(filter.aux, e) == 0)
+		return 0;
+	return 1;
 }
 
 int
@@ -211,8 +231,8 @@
 	return r;
 }
 
-static int
-rune2scancode(Rune r)
+SDL_Scancode
+SDL_GetScancodeFromKey(SDL_Keycode r)
 {
 	if(r >= 'a' && r <= 'z')
 		return r - 'a' + SDL_SCANCODE_A;
@@ -282,12 +302,29 @@
 	return r;
 }
 
+static Uint8 kbdstate[SDL_NUM_SCANCODES];
+
+Uint8*
+SDL_GetKeyboardState(int *numkeys)
+{
+	if(numkeys != nil)
+		*numkeys = SDL_NUM_SCANCODES;
+	return kbdstate;
+}
+
+char*
+SDL_GetKeyName(SDL_Keycode key)
+{
+	USED(key);
+	return ""; /* FIXME */
+}
+
 static void
 kbdproc(void *)
 {
 	char buf[128], buf2[128], *s;
 	int kfd, n, kbin, t;
-	Rune r, o;
+	Rune r, scan, o;
 
 	threadsetname("kbdproc");
 	if((kfd = open("/dev/kbd", OREAD|OCEXEC)) < 0)
@@ -325,8 +362,12 @@
 
 		case 'k':
 			s = buf+1;
+			memset(kbdstate, 0, sizeof kbdstate);
 			while(*s){
 				s += chartorune(&r, s);
+				scan = SDL_GetScancodeFromKey(r);
+				if(scan < nelem(kbdstate))
+					kbdstate[scan] = 1;
 				if(utfrune(buf2+1, r) == nil){
 					t = Rdown;
 					if(r == Kalt){
@@ -356,8 +397,12 @@
 
 		case 'K':
 			s = buf2+1;
+			memset(kbdstate, 0, sizeof kbdstate);
 			while(*s){
 				s += chartorune(&r, s);
+				scan = SDL_GetScancodeFromKey(r);
+				if(scan < nelem(kbdstate))
+					kbdstate[scan] = 1;
 				if(utfrune(buf+1, r) == nil){
 					if(r == Kalt)
 						kmod &= ~KMOD_LALT;
--- a/libnpe_sdl2/sdl2.c
+++ b/libnpe_sdl2/sdl2.c
@@ -21,22 +21,6 @@
 	Point hot;
 };
 
-static SDL_PixelFormat argb8888 = {
-	.format = SDL_PIXELFORMAT_ARGB8888,
-};
-
-static SDL_PixelFormat xrgb8888 = {
-	.format = SDL_PIXELFORMAT_XRGB8888,
-};
-
-static SDL_PixelFormat abgr8888 = {
-	.format = SDL_PIXELFORMAT_ABGR8888,
-};
-
-static SDL_PixelFormat rgb24 = {
-	.format = SDL_PIXELFORMAT_RGB24,
-};
-
 static SDL_Window onewin;
 static SDL_Renderer oneren;
 static Memimage *back;
@@ -47,6 +31,9 @@
 static int showcursor = SDL_ENABLE;
 static char basepath[PATH_MAX];
 static u32int renddrawcol = DBlack;
+struct {
+	Uint32 r, g, b, a;
+} defmask;
 
 struct npe_sdl npe_sdl = {0};
 
@@ -92,6 +79,114 @@
 	USED(w); USED(flag);
 }
 
+static int
+chan2mask(Uint32 chan, Uint32 *rm, Uint32 *gm, Uint32 *bm, Uint32 *am)
+{
+	switch(chan){
+	case ARGB32:
+		*am = 0xFF000000;
+	if(0){
+	case XRGB32:
+		*am = 0x00000000;
+	}
+	case RGB24:
+		*rm = 0x00FF0000;
+		*gm = 0x0000FF00;
+		*bm = 0x000000FF;
+		break;
+	case ABGR32:
+		*am = 0xFF000000;
+	if(0){
+	case XBGR32:
+		*am = 0x00000000;
+	}
+	case BGR24:
+		*bm = 0x00FF0000;
+		*gm = 0x0000FF00;
+		*rm = 0x000000FF;
+		break;
+	default:
+		assert(0);
+	}
+	return 0;
+}
+
+static ulong
+mask2chan(int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am)
+{
+	USED(gm, bm);
+
+	switch(bpp){
+	case 8:
+		return CMAP8;
+	case 24:
+		if(rm & 0xFF0000)
+			return RGB24;
+		else
+			return BGR24;
+	case 32:
+		if(am == 0){
+			if(rm & 0xFF0000)
+				return XRGB32;
+			else
+				return XBGR32;
+		} else {
+			if(rm & 0xFF0000)
+				return ARGB32;
+			else
+				return XBGR32;
+		}
+	}
+	assert(0);
+	return 0;
+}
+
+static Uint32
+chan2pixel(ulong chan)
+{
+	switch(chan){
+	case ARGB32:
+		return SDL_PIXELFORMAT_ARGB8888;
+	case XRGB32:
+		return SDL_PIXELFORMAT_XRGB8888;
+	case RGB24:
+		return SDL_PIXELFORMAT_RGB24;
+	case ABGR32:
+		return SDL_PIXELFORMAT_ABGR8888;
+	case XBGR32:
+		return SDL_PIXELFORMAT_XBGR8888;
+	case BGR24:
+		return SDL_PIXELFORMAT_BGR24;
+	case CMAP8:
+		return SDL_PIXELFORMAT_INDEX8;
+	}
+	assert(0);
+	return 0;
+}
+
+static ulong
+pixel2chan(Uint32 format)
+{
+	switch(format){
+	case SDL_PIXELFORMAT_ARGB8888:
+		return ARGB32;
+	case SDL_PIXELFORMAT_XRGB8888:
+		return XRGB32;
+	case SDL_PIXELFORMAT_RGB24:
+		return RGB24;
+	case SDL_PIXELFORMAT_ABGR8888:
+		return ABGR32;
+	case SDL_PIXELFORMAT_XBGR8888:
+		return XBGR32;
+	case SDL_PIXELFORMAT_BGR24:
+		return BGR24;
+	case SDL_PIXELFORMAT_INDEX8:
+		return CMAP8;
+	}
+	assert(0);
+	return 0;
+}
+
 int
 SDL_Init(int mask)
 {
@@ -113,7 +208,10 @@
 	npe_sdl.scale = 1;
 	physw = Dx(screen->r);
 	physh = Dy(screen->r);
-
+	if(chan2mask(screen->chan, &defmask.r, &defmask.g, &defmask.b, &defmask.a) < 0){
+		werrstr("SDL_Init: unsupported screen channel");
+		return -1;
+	}
 	return 0;
 err:
 	werrstr("SDL_Init: %r");
@@ -223,17 +321,7 @@
 	SDL_Texture *t;
 	int dformat;
 
-	switch(format){
-	case SDL_PIXELFORMAT_ARGB8888:
-		dformat = ARGB32;
-		break;
-	case SDL_PIXELFORMAT_XRGB8888:
-		dformat = XRGB32;
-		break;
-	case SDL_PIXELFORMAT_ABGR8888:
-		dformat = ABGR32;
-		break;
-	default:
+	if((dformat = pixel2chan(format)) == 0){
 		werrstr("SDL_CreateTexture: format is not supported");
 		goto err;
 	}
@@ -342,6 +430,14 @@
 }
 
 int
+SDL_RenderFillRect(SDL_Renderer *r, SDL_Rect *rect)
+{
+	/* FIXME */
+	assert(rect == nil);
+	return SDL_RenderClear(r);
+}
+
+int
 SDL_SetRenderDrawColor(SDL_Renderer *, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
 {
 	renddrawcol = r<<24 | g<<16 | b<<8 | a;
@@ -368,40 +464,37 @@
 }
 
 SDL_Surface *
-SDL_CreateRGBSurface(Uint32 flags, int w, int h, int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am)
+SDL_CreateRGBSurface(Uint32, int w, int h, int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am)
 {
 	SDL_Surface *s;
 	int n;
-	Memimage *i;
+	ulong chan;
 
-	USED(flags, rm, gm, bm, am); /* FIXME flags & masks */
-
+	rm = rm ? rm : defmask.r;
+	gm = gm ? gm : defmask.g;
+	bm = bm ? bm : defmask.b;
+	if((chan = mask2chan(bpp, rm, gm, bm, am)) == 0){
+		werrstr("bad bpp and/or mask");
+		return nil;
+	}
 	n = w*h*bpp/8;
 	if((s = calloc(1, sizeof(*s))) == nil){
 		werrstr("SDL_CreateRGBSurface: memory");
 		return nil;
 	}
-	s->i = i = allocmemimage(Rect(0,0,w,h), screen->chan);
+	s->i = allocmemimage(Rect(0,0,w,h), chan == CMAP8 ? screen->chan : chan);
 	s->format = calloc(1, sizeof(SDL_PixelFormat));
-	switch(bpp){
-	case 32:
-		s->format->format = SDL_PIXELFORMAT_ARGB8888;
-		s->pixels = i->data->bdata;
-		break;
-	case 24:
-		s->format->format = SDL_PIXELFORMAT_RGB24;
-		s->pixels = calloc(1, n);
-		break;
-	case 8:
-		s->format->format = SDL_PIXELFORMAT_INDEX8;
+	s->format->BytesPerPixel = bpp/8;
+	s->format->format = chan2pixel(chan);
+	if(chan == CMAP8){
+		s->i = allocmemimage(Rect(0,0,w,h), screen->chan);
 		s->format->palette = calloc(1, sizeof(SDL_Palette));
 		s->format->palette->ncolors = 256;
 		s->format->palette->colors = calloc(1, sizeof(SDL_Color) * 256);
 		s->pixels = calloc(1, n);
-		break;
-	default:
-		werrstr("non supported bpp");
-		return nil;
+	}else{
+		s->i = allocmemimage(Rect(0,0,w,h), chan);
+		s->pixels = ((Memimage*)s->i)->data->bdata;
 	}
 	
 	s->w = w;
@@ -436,27 +529,17 @@
 SDL_Surface *
 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int w, int h, int bpp, Uint32 fmt)
 {
-	SDL_PixelFormat *f;
 	SDL_Surface *s;
+	ulong chan;
+	Uint32 rm, gm, bm, am;
 
-	if(fmt == SDL_PIXELFORMAT_ARGB8888)
-		f = &argb8888;
-	else if(fmt == SDL_PIXELFORMAT_XRGB8888)
-		f = &xrgb8888;
-	else if(fmt == SDL_PIXELFORMAT_RGB24)
-		f = &rgb24;
-	else if(fmt == SDL_PIXELFORMAT_ABGR8888)
-		f = &abgr8888;
-	else{
+	if((chan = pixel2chan(fmt)) == 0){
 		werrstr("SDL_CreateRGBSurfaceWithFormat: FIXME format %8ux not implemented", fmt);
 		return nil;
 	}
-
-	if((s = SDL_CreateRGBSurface(flags, w, h, bpp, 0, 0, 0, 0)) == nil)
+	chan2mask(chan, &rm, &gm, &bm, &am);
+	if((s = SDL_CreateRGBSurface(flags, w, h, bpp, rm, bm, gm, am)) == nil)
 		return nil;
-
-	s->format = f;
-
 	return s;
 }
 
@@ -470,6 +553,7 @@
 	switch(dst->format->format){
 	case SDL_PIXELFORMAT_XRGB8888:
 	case SDL_PIXELFORMAT_ARGB8888:
+	case SDL_PIXELFORMAT_XBGR8888:
 	case SDL_PIXELFORMAT_ABGR8888:
 		p = (Uint32*)dst->pixels;
 		for(i = 0; i < dst->n / sizeof(*p); i++)
@@ -491,6 +575,17 @@
 	return 0;
 }
 
+SDL_Palette*
+SDL_AllocPalette(int ncolors)
+{
+	SDL_Palette *p;
+
+	p = malloc(sizeof(*p));
+	p->ncolors = ncolors;
+	p->colors = mallocz(sizeof(SDL_Color)*ncolors, 1);
+	return p;
+}
+
 int
 SDL_SetPaletteColors(SDL_Palette *palette, const SDL_Color *colors, int firstcolor, int ncolors)
 {
@@ -502,6 +597,13 @@
 	return 0;
 }
 
+int
+SDL_SetSurfacePalette(SDL_Surface *s, SDL_Palette *palette)
+{
+	s->format->palette = palette;
+	return 0;
+}
+
 static void
 syncpalette(SDL_Surface *s)
 {
@@ -519,6 +621,32 @@
 	}
 }
 
+static void
+synctopalette(SDL_Surface *s)
+{
+	SDL_Color c, *f;
+	Uint32 *from;
+	int j, k;
+	Memimage *i;
+	SDL_PixelFormat fmt;
+
+	i = s->i;
+	fmt.format = chan2pixel(screen->chan);
+	from = (void*)i->data->bdata;
+	for(j = 0; j < s->n; j++){
+		SDL_GetRGB(from[j], &fmt, &c.r, &c.g, &c.b);
+		for(k = 0; k < s->format->palette->ncolors; k++){
+			f = s->format->palette->colors + k;
+			if(c.r == f->r && c.g == f->g && c.b == f->b)
+				break;
+		}
+		if(k == s->format->palette->ncolors)
+			s->pixels[j] = 0; /* FIXME */
+		else
+			s->pixels[j] = k;
+	}
+}
+
 int
 SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
 {
@@ -530,9 +658,10 @@
 	if(src->format->format == SDL_PIXELFORMAT_INDEX8)
 		syncpalette(src);
 
-	/* FIXME */
-	assert(dst->format->format != SDL_PIXELFORMAT_INDEX8);
 	memimagedraw(dst->i, r2, src->i, ZP, nil, ZP, S);
+
+	if(dst->format->format == SDL_PIXELFORMAT_INDEX8)
+		synctopalette(dst);
 	return 0;
 }
 
@@ -615,10 +744,63 @@
 	free(surface);
 }
 
+void
+SDL_GetRGB(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r, Uint8 *g, Uint8 *b)
+{
+	SDL_Color *c;
+
+	switch(fmt->format){
+	case SDL_PIXELFORMAT_ARGB8888:
+	case SDL_PIXELFORMAT_XRGB8888:
+	case SDL_PIXELFORMAT_RGB24:
+		*r = pixel>>16;
+		*g = pixel>>8;
+		*b = pixel;
+		break;
+	case SDL_PIXELFORMAT_ABGR8888:
+	case SDL_PIXELFORMAT_XBGR8888:
+	case SDL_PIXELFORMAT_BGR24:
+		*b = pixel>>16;
+		*g = pixel>>8;
+		*r = pixel;
+		break;
+	case SDL_PIXELFORMAT_INDEX8:
+		assert(fmt->palette);
+		assert(pixel < fmt->palette->ncolors);
+		c = fmt->palette->colors + pixel;
+		*r = c->r;
+		*g = c->g;
+		*b = c->b;
+		break;
+	default:
+		assert(0);
+	}
+}
+
 Uint32
-SDL_MapRGB(SDL_PixelFormat *, Uint8 r, Uint8 g, Uint8 b)
+SDL_MapRGB(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b)
 {
-	return r<<24 | g<<16 | b<<8 | 0xff;
+	SDL_Color *c;
+
+	switch(fmt->format){
+	case SDL_PIXELFORMAT_ARGB8888:
+	case SDL_PIXELFORMAT_XRGB8888:
+	case SDL_PIXELFORMAT_RGB24:
+		return 0xff<<24 | r<<16 | g<<8 | b;
+	case SDL_PIXELFORMAT_ABGR8888:
+	case SDL_PIXELFORMAT_XBGR8888:
+	case SDL_PIXELFORMAT_BGR24:
+		return 0xff<<24 | b<<16 | g<<8 | r;
+	case SDL_PIXELFORMAT_INDEX8:
+		assert(fmt->palette);
+		for(c = fmt->palette->colors; c < fmt->palette->colors + fmt->palette->ncolors; c++){
+			if(c->r == r && c->g == g && c->b == b)
+				return c - fmt->palette->colors;
+		}
+	default:
+		assert(0);
+		return 0;
+	}
 }
 
 int
@@ -1028,6 +1210,14 @@
 }
 
 void
+SDL_RenderGetViewport(SDL_Renderer *r, SDL_Rect *rect)
+{
+	rect->x = rect->y = 0;
+	rect->w = r->logiw;
+	rect->h = r->logih;
+}
+
+void
 SDL_SetWindowSize(SDL_Window *, int w, int h)
 {
 	int f, n;
@@ -1095,6 +1285,22 @@
 }
 
 int
+SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect *r)
+{
+	if(displayIndex != 0)
+		return -1;
+
+	if(r == nil)
+		return 0;
+
+	r->x = display->image->r.min.x;
+	r->y = display->image->r.min.y;
+	r->w = Dx(display->image->r);
+	r->h = Dy(display->image->r);
+	return 0;
+}
+
+int
 SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode *mode)
 {
 	if(displayIndex != 0)
@@ -1203,6 +1409,15 @@
 }
 
 int
+SDL_CreateWindowAndRenderer(int w, int h, Uint32, SDL_Window **win, SDL_Renderer **rend)
+{
+	SDL_SetWindowSize(&onewin, w, h);
+	*win = &onewin;
+	*rend = &oneren;
+	return 0;
+}
+
+int
 SDL_SetRenderDrawBlendMode(SDL_Renderer *, SDL_BlendMode blendMode)
 {
 	if(blendMode != SDL_BLENDMODE_NONE){
@@ -1533,7 +1748,7 @@
 {
 	SDL_mutex *m;
 
-	m = mallocz(sizeof *m, 1);
+	m = mallocz(sizeof(*m), 1);
 	return m;
 }