ref: 237831f5ec11e7bb6da2961c1e5f5bc0c3610347
dir: /libnpe_sdl2/sdl2.c/
#include "_sdl.h" struct SDL_Window { int dummy; }; struct SDL_Renderer { int logiw; int logih; }; struct SDL_Texture { Memimage *m; SDL_BlendMode blend; }; struct SDL_Cursor { Image *i; Image *m; Point hot; }; static SDL_PixelFormat argb8888 = { .format = SDL_PIXELFORMAT_ARGB8888, }; static SDL_PixelFormat xrgb8888 = { .format = SDL_PIXELFORMAT_XRGB8888, }; static SDL_Window onewin; static SDL_Renderer oneren; static Memimage *back; static u8int *backcopy; static Image *front; static int physw, physh; static SDL_Cursor *oldcursor, *cursor; static int showcursor = SDL_ENABLE; static char basepath[PATH_MAX]; static u32int renddrawcol = DBlack; struct npe_sdl npe_sdl = {0}; static Cursor nocursor = { {0, 0}, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }; int SDL_Init(int mask) { /* FIXME actually use the mask? */ USED(mask); if(getwd(basepath, sizeof(basepath)) == nil) strcpy(basepath, "/"); if(mask == 0) return 0; if(memimageinit() < 0) goto err; if(initdraw(nil, nil, argv0) < 0) goto err; if(npe_sdl_init_input() != 0) goto err; npe_sdl.scale = 1; return 0; err: werrstr("SDL_Init: %r"); return -1; } int SDL_ShowCursor(int toggle) { if(toggle == SDL_QUERY) return showcursor; showcursor = toggle == SDL_ENABLE; setcursor(npe_sdl.mctl, (cursor == nil && showcursor) ? nil : &nocursor); return showcursor; } Uint64 SDL_GetPerformanceFrequency(void) { return _tos->cyclefreq; } Uint64 SDL_GetPerformanceCounter(void) { u64int x; cycles(&x); return x; } char * SDL_GetError(void) { static char err[256]; snprint(err, sizeof(err), "%r"); return err; } static void * readfile(char *path, int *got) { void *data, *data2; int f, n, r, sz; if((f = open(path, OREAD|OCEXEC)) < 0) return nil; sz = 32768; data = nil; for(n = 0;; n += r){ if(sz-n < 65536){ sz *= 2; if((data2 = realloc(data, sz)) == nil) goto err; data = data2; } if((r = read(f, (char*)data+n, sz-n-1)) < 0) goto err; if(r == 0) break; } if(got != nil) *got = n; ((char*)data)[n] = 0; return data; err: free(data); close(f); return nil; } char * SDL_GetClipboardText(void) { return readfile("/dev/snarf", nil); } int SDL_SetClipboardText(char *s) { int f, n; n = -1; if((f = open("/dev/snarf", OWRITE|OTRUNC|OCEXEC)) >= 0){ n = strlen(s); n = write(f, s, n) == n ? 0 : -1; close(f); } if(n != 0) werrstr("SDL_SetClipboardText: %r"); return n; } SDL_Texture * SDL_CreateTexture(SDL_Renderer *, Uint32 format, int, int w, int h) { SDL_Texture *t; if(format != SDL_PIXELFORMAT_ARGB8888 && format != SDL_PIXELFORMAT_XRGB8888){ werrstr("SDL_CreateTexture: only SDL_PIXELFORMAT_*RGB8888 is supported"); goto err; } if((t = malloc(sizeof(*t))) == nil) goto err; if((t->m = allocmemimage(Rect(0, 0, w, h), format == SDL_PIXELFORMAT_ARGB8888 ? ARGB32 : XRGB32)) == nil){ free(t); goto err; } memfillcolor(t->m, DBlack); return t; err: werrstr("SDL_CreateTexture: %r"); return nil; } SDL_Texture * SDL_CreateTextureFromSurface(SDL_Renderer *r, SDL_Surface *s) { SDL_Texture *t; SDL_Rect re; if((t = SDL_CreateTexture(r, s->format->format, 0, s->w, s->h)) != nil){ re.x = 0; re.y = 0; re.w = s->w; re.h = s->h; SDL_UpdateTexture(t, &re, s->pixels, s->pitch); } return t; } int SDL_UpdateTexture(SDL_Texture *t, SDL_Rect *re, void *pixels, int pitch) { Rectangle r; u8int *pix; int y, my; r = re ? Rect(re->x, re->y, re->x+re->w, re->y+re->h) : t->m->r; pix = pixels; if(pitch == Dx(r)){ if(loadmemimage(t->m, r, pix, Dx(r)*Dy(r)*4) < 0){ werrstr("SDL_UpdateTexture: %r"); return -1; } }else{ my = Dy(r); for(y = 0; y < my; y++, pix += pitch, r.min.y += 1){ r.max.y = r.min.y + 1; if(loadmemimage(t->m, r, pix, Dx(r)*4) < 0){ werrstr("SDL_UpdateTexture: %r"); return -1; } } } return 0; } int SDL_SetTextureAlphaMod(SDL_Texture *t, Uint8 alpha) { /* FIXME */ USED(t, alpha); return -1; } int SDL_SetTextureColorMod(SDL_Texture *t, Uint8 r, Uint8 g, Uint8 b) { /* FIXME */ USED(t, r, g, b); return -1; } int SDL_RenderClear(SDL_Renderer *) { if(back != nil) memfillcolor(back, renddrawcol); return 0; } int SDL_SetRenderDrawColor(SDL_Renderer *, Uint8 r, Uint8 g, Uint8 b, Uint8 a) { renddrawcol = r<<24 | g<<16 | b<<8 | a; return 0; } int SDL_GetWindowDisplayIndex(SDL_Window *) { return 0; } void SDL_Quit(void) { /* FIXME deinitialize */ } void SDL_free(void *p) { free(p); } SDL_Surface * SDL_CreateRGBSurface(Uint32 flags, int w, int h, int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am) { SDL_Surface *s; int n; USED(flags, rm, gm, bm, am); /* FIXME flags & masks */ n = w*h*bpp/8; if((s = calloc(1, sizeof(*s)+n)) == nil){ werrstr("SDL_CreateRGBSurface: memory"); return nil; } s->format = &argb8888; s->w = w; s->h = h; s->pitch = w*bpp/8; s->clip_rect.x = 0; s->clip_rect.y = 0; s->clip_rect.w = w; s->clip_rect.h = h; return s; } SDL_Surface * SDL_CreateRGBSurfaceFrom(void *pixels, int w, int h, int bpp, int pitch, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am) { SDL_Surface *s; u8int *p; int n, y; if((s = SDL_CreateRGBSurface(0, w, h, bpp, rm, gm, bm, am)) == nil) return nil; n = w*bpp/8; for(y = 0, p = pixels; y < h; y++, p += pitch) memmove(s->pixels + y*n, p, n); return s; } SDL_Surface * SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int w, int h, int bpp, Uint32 fmt) { SDL_PixelFormat *f; SDL_Surface *s; if(fmt == SDL_PIXELFORMAT_ARGB8888) f = &argb8888; else if(fmt == SDL_PIXELFORMAT_XRGB8888) f = &xrgb8888; else{ werrstr("SDL_CreateRGBSurfaceWithFormat: FIXME format %8ux not implemented", fmt); return nil; } if((s = SDL_CreateRGBSurface(flags, w, h, bpp, 0, 0, 0, 0)) == nil) return nil; s->format = f; return s; } void SDL_FreeSurface(SDL_Surface *surface) { memset(surface, 0, sizeof(surface)); free(surface); } Uint32 SDL_MapRGB(SDL_PixelFormat *, Uint8 r, Uint8 g, Uint8 b) { return r<<24 | g<<16 | b<<8 | 0xff; } int SDL_SetColorKey(SDL_Surface *s, int flag, Uint32 key) { s->keyset = flag; s->key = key; return 0; } SDL_Cursor * SDL_CreateColorCursor(SDL_Surface *s, int hot_x, int hot_y) { SDL_Cursor *c; Rectangle r; uchar *m; int n; m = nil; if((c = calloc(1, sizeof(*c))) == nil){ werrstr("memory"); goto err; } r = Rect(0, 0, s->w, s->h); if(s->keyset){ if((c->m = allocimage(display, r, GREY8, 0, DTransparent)) == nil) goto err; if((m = malloc(s->w * s->h)) == nil) goto err; for(n = 0; n < s->w * s->h; n++){ m[n] = ((u32int*)s->pixels)[n] == s->key ? 0x00 : 0xff; if(m[n] == 0) ((u32int*)s->pixels)[n] = 0; } if(loadimage(c->m, r, m, n) < 1) goto err; free(m); m = nil; } if((c->i = allocimage(display, r, s->keyset ? XRGB32 : ARGB32, 0, DTransparent)) == nil) goto err; n = s->w * s->h * 4; /* FIXME non-ARGB8888 */ if(loadimage(c->i, r, s->pixels, n) < 1) goto err; c->hot = Pt(hot_x, hot_y); return c; err: werrstr("SDL_CreateColorCursor: %r"); if(c != nil){ freeimage(c->i); freeimage(c->m); } free(c); free(m); return nil; } SDL_Cursor * SDL_GetDefaultCursor(void) { return nil; } SDL_Cursor * SDL_CreateSystemCursor(SDL_SystemCursor id) { /* FIXME */ USED(id); return nil; } void SDL_SetCursor(SDL_Cursor *c) { if(cursor != c){ cursor = c; npe_sdl.mredraw = 1; setcursor(npe_sdl.mctl, (cursor == nil && showcursor) ? nil : &nocursor); } } void SDL_FreeCursor(SDL_Cursor *c) { freeimage(c->i); free(c); if(cursor == c){ oldcursor = nil; cursor = nil; } } void SDL_WarpMouseInWindow(SDL_Window *, int x, int y) { moveto(npe_sdl.mctl, Pt(screen->r.min.x+x, screen->r.min.y+y)); } Uint32 SDL_GetGlobalMouseState(int *x, int *y) { Uint32 b; if(x != nil) *x = npe_sdl.m.xy.x; if(y != nil) *y = npe_sdl.m.xy.y; b = 0; if(npe_sdl.m.buttons & 1) b |= SDL_BUTTON_LMASK; if(npe_sdl.m.buttons & 2) b |= SDL_BUTTON_MMASK; if(npe_sdl.m.buttons & 4) b |= SDL_BUTTON_RMASK; return b; } Uint32 SDL_GetMouseState(int *x, int *y) { Uint32 b; b = SDL_GetGlobalMouseState(nil, nil); if(x != nil) *x = npe_sdl.m.xy.x - screen->r.min.x; if(y != nil) *y = npe_sdl.m.xy.y - screen->r.min.y; return b; } void SDL_RenderGetScale(SDL_Renderer *, float *scaleX, float *scaleY) { *scaleX = 1.0; *scaleY = 1.0; } int SDL_RenderSetIntegerScale(SDL_Renderer *, SDL_bool enable) { /* FIXME */ USED(enable); return 0; } void SDL_GetWindowSize(SDL_Window *, int *w, int *h) { /* no matter what rio decides */ *w = physw; *h = physh; } void SDL_GetWindowPosition(SDL_Window *, int *x, int *y) { *x = screen->r.min.x; *y = screen->r.min.y; } SDL_bool SDL_IsTextInputActive(void) { return npe_sdl.textinput; } void SDL_StartTextInput(void) { npe_sdl.textinput = SDL_TRUE; } void SDL_StopTextInput(void) { npe_sdl.textinput = SDL_FALSE; } void SDL_Delay(Uint32 ms) { npe_nsleep((uvlong)ms * Nmsec); } static int duff(SDL_BlendMode mode) { if(mode == SDL_BLENDMODE_BLEND) return SoverD; return S; } int SDL_RenderCopy(SDL_Renderer *rend, SDL_Texture *t, SDL_Rect *sre, SDL_Rect *dre) { Rectangle sr, dr; int logiw, logih; if(rend->logiw > 0 && rend->logih > 0){ logiw = rend->logiw; logih = rend->logih; }else{ logiw = physw; logih = physh; } sr = t->m->r; if(sre != nil){ sr.min = Pt(sre->x, sre->y); sr.max = addpt(sr.min, Pt(sre->w, sre->h)); } dr = Rect(0, 0, logiw, logih); if(dre != nil){ dr.min = Pt(dre->x, dre->y); dr.max = addpt(dr.min, Pt(dre->w, dre->h)); } if(back == nil || Dx(back->r) != logiw || Dy(back->r) != logih){ freememimage(back); back = allocmemimage(Rect(0, 0, logiw, logih), ARGB32); if(back == nil){ werrstr("SDL_RenderCopy: %r"); return -1; } free(backcopy); backcopy = malloc(logiw*logih*4); } if(dre == nil && (Dx(sr) != logiw || Dy(sr) != logih)) npe_sdl_scale((u32int*)byteaddr(t->m, ZP), Dx(sr), Dy(sr), (u32int*)byteaddr(back, ZP), logiw, logih); else memimagedraw(back, dr, t->m, sr.min, nil, ZP, duff(t->blend)); return 0; } void SDL_RenderPresent(SDL_Renderer *rend) { Rectangle r, clipr; static u32int *b; uchar *rb; int logiw, logih; if(rend->logiw > 0 && rend->logih > 0){ logiw = rend->logiw; logih = rend->logih; }else{ logiw = physw; logih = physh; } npe_sdl.scale = (float)logiw / (float)physw; if(!npe_sdl.fullredraw && (npe_sdl.fullredraw = memcmp(backcopy, byteaddr(back, ZP), logiw*logih*4)) == 0 && !npe_sdl.mredraw) return; r = Rect(0, 0, physw, physh); if(front != nil && (Dx(front->r) != physw || Dy(front->r) != physh)){ freeimage(front); front = nil; free(b); b = nil; } if(b == nil && (b = realloc(b, physw*physh*4)) == nil){ fprint(2, "SDL_RenderPresent: %r\n"); return; } if(npe_sdl.fullredraw || front == nil){ rb = npe_sdl_scale((u32int*)byteaddr(back, ZP), Dx(back->r), Dy(back->r), b, physw, physh); if(front == nil && (front = allocimage(display, r, XRGB32, 0, DNofill)) == nil){ fprint(2, "SDL_RenderPresent: %r\n"); return; } if(loadimage(front, r, rb, Dx(r)*Dy(r)*4) < 0){ fprint(2, "SDL_RenderPresent: %r\n"); return; } } if(cursor != nil && showcursor){ r.min = subpt(npe_sdl.m.xy, cursor->hot); r.max = addpt(r.min, cursor->i->r.max); if(!npe_sdl.fullredraw && oldcursor != nil){ clipr.min = subpt(npe_sdl.om.xy, oldcursor->hot); clipr.max = addpt(clipr.min, oldcursor->i->r.max); combinerect(&clipr, r); replclipr(screen, 0, clipr); } } draw(screen, screen->r, front, nil, ZP); if(cursor != nil && showcursor) draw(screen, r, cursor->i, cursor->m, ZP); npe_sdl.mredraw = 0; npe_sdl.om.xy = npe_sdl.m.xy; oldcursor = cursor; flushimage(display, 1); if(npe_sdl.fullredraw) memmove(backcopy, byteaddr(back, ZP), logiw*logih*4); else replclipr(screen, 0, screen->r); npe_sdl.fullredraw = 0; } int SDL_RenderReadPixels(SDL_Renderer *rend, SDL_Rect *rect, Uint32 fmt, void *pixels, int pitch) { Rectangle r; USED(pitch); /* FIXME pitch & fmt */ if(fmt != SDL_PIXELFORMAT_ARGB8888 && fmt != SDL_PIXELFORMAT_XRGB8888){ werrstr("SDL_RenderReadPixels: FIXME non-*rgb8888"); return -1; } if(rect != nil) r = Rect(rect->x, rect->y, rect->x+rect->w, rect->y+rect->h); else r = Rect(0, 0, rend->logiw, rend->logih); unloadmemimage(back, r, pixels, Dx(r)*Dy(r)*4); return 0; } Uint32 SDL_GetWindowFlags(SDL_Window *) { /* FIXME is this correct? */ return SDL_WINDOW_INPUT_FOCUS; } int SDL_RenderSetLogicalSize(SDL_Renderer *r, int w, int h) { if(r->logiw != w || r->logih != h){ r->logiw = w; r->logih = h; npe_sdl.fullredraw = 1; } return 0; } int SDL_GetRendererOutputSize(SDL_Renderer *r, int *w, int *h) { if(w != nil) *w = r->logiw; if(h != nil) *h = r->logih; return 0; } void SDL_SetWindowSize(SDL_Window *, int w, int h) { int f, n; if(physw != w || physh != h){ physw = w; physh = h; if((f = open("/dev/wctl", OWRITE|OCEXEC)) >= 0){ n = fprint(f, "resize -dx %d -dy %d", w+Borderwidth*2, h+Borderwidth*2); close(f); if(n > 0){ getwindow(display, Refnone); npe_sdl.fullredraw = 1; } } } } int SDL_ShowSimpleMessageBox(Uint32, char *title, char *message, SDL_Window *) { /* FIXME display a GUI window? */ fprint(2, "%s: %s\n", title, message); return 0; } int SDL_SetWindowFullscreen(SDL_Window *, Uint32) { /* FIXME again, ft2 does NOT check the error code, figure something out */ werrstr("SDL_SetWindowFullscreen: not implemented"); return -1; } void SDL_SetWindowGrab(SDL_Window *, SDL_bool grabbed) { /* FIXME not sure if it's worth anything */ USED(grabbed); } void SDL_SetWindowPosition(SDL_Window *, int x, int y) { int f, n; if((f = open("/dev/wctl", OWRITE|OCEXEC)) >= 0){ n = fprint(f, "move -minx %d -miny %d", x, y); close(f); if(n > 0){ getwindow(display, Refnone); npe_sdl.fullredraw = 1; } } } int SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode *mode) { if(displayIndex != 0) return -1; mode->w = physw; mode->h = physh; mode->format = SDL_PIXELFORMAT_ARGB8888; mode->refresh_rate = 0; return 0; } int SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode *mode) { return SDL_GetDesktopDisplayMode(displayIndex, mode); } void SDL_SetWindowTitle(SDL_Window *, char *title) { int f; if((f = open("/dev/label", OWRITE|OTRUNC|OCEXEC)) >= 0 || (f = open("/mnt/term/dev/label", OWRITE|OTRUNC|OCEXEC)) >= 0){ write(f, title, strlen(title)); close(f); } } void SDL_DestroyTexture(SDL_Texture *t) { freememimage(t->m); free(t); } int SDL_SetTextureBlendMode(SDL_Texture *t, SDL_BlendMode blendMode) { if(blendMode != SDL_BLENDMODE_NONE && blendMode != SDL_BLENDMODE_BLEND){ werrstr("SDL_SetTextureBlendMode: unsupported blend mode %d", blendMode); return -1; } t->blend = blendMode; return 0; } SDL_bool SDL_SetHint(char *name, char *value) { /* FIXME anyone cares about name="SDL_RENDER_SCALE_QUALITY" value="(best|nearest)"? */ if(strcmp(name, SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4) == 0){ npe_sdl.hints = (npe_sdl.hints & ~Altf4noclose) | (atoi(value) ? Altf4noclose : 0); return SDL_TRUE; } return SDL_FALSE; } SDL_Window * SDL_CreateWindow(char *title, int x, int y, int w, int h, Uint32) { SDL_SetWindowTitle(&onewin, title); SDL_SetWindowSize(&onewin, w, h); if(x != SDL_WINDOWPOS_UNDEFINED && y != SDL_WINDOWPOS_UNDEFINED){ /* FIXME either of these can be undefined */ if(x == SDL_WINDOWPOS_CENTERED) x = display->image->r.min.x + (Dx(display->image->r) - w)/2; if(y == SDL_WINDOWPOS_CENTERED) y = display->image->r.min.y + (Dx(display->image->r) - w)/2; SDL_SetWindowPosition(&onewin, x, y); } return &onewin; } SDL_Renderer * SDL_CreateRenderer(SDL_Window *, int, Uint32) { return &oneren; } int SDL_SetRenderDrawBlendMode(SDL_Renderer *, SDL_BlendMode blendMode) { if(blendMode != SDL_BLENDMODE_NONE){ werrstr("SDL_SetRenderDrawBlendMode: only SDL_BLENDMODE_NONE is supported"); return -1; } return 0; } char * SDL_GetCurrentVideoDriver(void) { return "/dev/draw"; } Uint32 SDL_GetTicks(void) { return npe_nanosec() / Nmsec; } int SDL_OpenURL(char *url) { char tmp[PATH_MAX]; Plumbmsg m; int f, r; if((f = plumbopen("send", OWRITE|OCEXEC)) < 0) return -1; memset(&m, 0, sizeof(m)); m.src = argv0; m.wdir = getwd(tmp, sizeof(tmp)); m.type = "text"; m.data = url; m.ndata = -1; r = plumbsend(f, &m); close(f); return r; } char * SDL_GetBasePath(void) { return strdup(basepath); } char * SDL_GetPrefPath(char *org, char *app) { char *home, *p; p = nil; if((home = getenv("home")) != nil){ if((p = smprint("%s/lib/%s/%s", home, org, app)) != nil) npe_mkdirp(cleanname(p), 0755); free(home); } return p; } SDL_bool SDL_HasClipboardText(void) { /* most def */ return SDL_TRUE; } void SDL_RestoreWindow(SDL_Window *) { /* nothing to do here */ } void SDL_RaiseWindow(SDL_Window *) { /* nothing to do here */ } void SDL_ShowWindow(SDL_Window *) { /* nothing to do here */ } int SDL_SetSurfaceRLE(SDL_Surface *, int) { /* nothing to do here */ return 0; } int SDL_SetSurfaceBlendMode(SDL_Surface *, SDL_BlendMode blendMode) { if(blendMode != SDL_BLENDMODE_NONE){ werrstr("SDL_SetSurfaceBlendMode: only SDL_BLENDMODE_NONE is supported"); return -1; } return 0; } int SDL_LockSurface(SDL_Surface *) { /* nothing to do here */ return 0; } int SDL_UnlockSurface(SDL_Surface *) { /* nothing to do here */ return 0; } void SDL_DestroyRenderer(SDL_Renderer *) { /* nothing to do here */ } void SDL_DestroyWindow(SDL_Window *) { } SDL_bool SDL_HasSSE(void) { /* it's not like we have builtins anyway */ return SDL_FALSE; } SDL_bool SDL_HasSSE2(void) { /* it's not like we have builtins anyway */ return SDL_FALSE; } void SDL_EnableScreenSaver(void) { } int SDL_SaveBMP(SDL_Surface *s, const char *file) { /* FIXME implement this */ USED(s, file); return -1; } void SDL_ClearError(void) { } int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action, Uint32 minType, Uint32 maxType) { /* FIXME implement */ USED(events, numevents, action, minType, maxType); return 0; } int SDL_NumJoysticks(void) { /* FIXME implement */ return 0; } SDL_Joystick * SDL_JoystickOpen(int n) { /* FIXME implement */ USED(n); return nil; } void SDL_SetMainReady(void) { }