ref: c9370126decbe7c864f5118ea7421188e255c1e5
dir: /libnpe_sdl2/sdl2.c/
#include <npe.h> #include <stdint.h> #include <tos.h> #include <draw.h> #include <memdraw.h> #include <mouse.h> #include <cursor.h> #include <plumb.h> #include <SDL2/SDL.h> #include <sys/stat.h> #include "_npe.h" typedef struct Audiodev Audiodev; enum { Aout = 2, Arec, /* FIXME missing plumber→dropfile and enter()→text */ Ckey = 0, Ckeytype, Cmouse, Cresize, Numchan, Rdown = 0, Rup, Rrepeat, Audiobufsz = 16384, }; struct SDL_Window { int dummy; }; struct SDL_Renderer { int dummy; }; struct SDL_Texture { Memimage; }; struct SDL_PixelFormat { int format; }; struct SDL_Cursor { Image *i; Image *m; Point hot; }; struct SDL_Thread { SDL_ThreadFunction f; char *name; void *userdata; }; static SDL_PixelFormat argb8888 = { .format = SDL_PIXELFORMAT_ARGB8888, }; struct Audiodev { QLock; int paused; int fd; int pid; int mode; Uint8 buf[Audiobufsz]; void *userdata; void (*cb)(void *, Uint8 *, int); }; /* FIXME extra USB audio devices? */ static Audiodev au[4] = { [0] = {.fd = -1, .mode = -1}, [1] = {.fd = -1, .mode = -1}, [Aout] = {.fd = -1, .pid = -1, .mode = OWRITE}, [Arec] = {.fd = -1, .pid = -1, .mode = OREAD}, }; static SDL_Window onewin; static SDL_Renderer oneren; static int kmod; static Mouse mouse, oldmouse; static Rune rune; static Mousectl *mctl; static Keyboardctl kctl; static Memimage *back; static u8int *backcopy; static Image *front; static int logiw, logih; static int physw, physh; static int forceredraw = 1; static SDL_Cursor *oldcursor, *cursor; static int mouseredraw = 0; static int showcursor = SDL_ENABLE; static int textinput; static char basepath[PATH_MAX]; static u32int renddrawcol = DBlack; 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, }, }; static Alt salt[Numchan+1] = { [Ckey] = { nil, &rune, CHANRCV }, [Ckeytype] = { nil, nil, CHANNOP }, [Cmouse] = { nil, &mouse, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, [Numchan] = { nil, nil, CHANNOBLK }, }; static void kbdproc(void *) { char buf[128], buf2[128], *s; int kfd, n, kbin, t; Rune r, o; threadsetname("kbdproc"); if((kfd = open("/dev/kbd", OREAD|OCEXEC)) < 0) sysfatal("/dev/kbd: %r"); kbin = open("/dev/kbin", OWRITE|OCEXEC); buf2[0] = 0; buf2[1] = 0; buf[0] = 0; kmod = 0; o = 0; for(;;){ if(buf[0] != 0){ n = strlen(buf)+1; memmove(buf, buf+n, sizeof(buf)-n); } if(buf[0] == 0){ n = read(kfd, buf, sizeof(buf)-1); if(n <= 0) break; buf[n-1] = 0; buf[n] = 0; } switch(buf[0]){ case 'c': if(chartorune(&r, buf+1) > 0 && r != Runeerror){ t = Rrepeat; if(!textinput) r = tolowerrune(r); if(textinput || o != r){ send(salt[Ckey].c, &r); send(salt[Ckeytype].c, &t); } o = 0; } default: continue; case 'k': s = buf+1; while(*s){ s += chartorune(&r, s); if(utfrune(buf2+1, r) == nil){ if(r == Kalt){ /* magic trick: write Alt scancode to disable the "compose" mode */ /* FIXME: does this work in both native AND drawterm? */ write(kbin, "\x46", 1); kmod |= KMOD_LALT; }else if (r == Kshift) kmod |= KMOD_LSHIFT; else if(r == Kctl) kmod |= KMOD_LCTRL; else{ t = Rdown; send(salt[Ckey].c, &r); send(salt[Ckeytype].c, &t); o = r; } } } break; case 'K': s = buf2+1; while(*s){ s += chartorune(&r, s); if(utfrune(buf+1, r) == nil){ if(r == Kalt) kmod &= ~KMOD_LALT; else if(r == Kshift) kmod &= ~KMOD_LSHIFT; else if(r == Kctl) kmod &= ~KMOD_LCTRL; else{ t = Rup; send(salt[Ckey].c, &r); send(salt[Ckeytype].c, &t); } } } break; } strcpy(buf2, buf); } threadexits(nil); } 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((mctl = initmouse(nil, screen)) == nil) goto err; salt[Ckey].c = chancreate(sizeof(Rune), 20); salt[Ckeytype].c = chancreate(sizeof(int), 20); salt[Cmouse].c = mctl->c; salt[Cresize].c = mctl->resizec; kctl.c = salt[Ckey].c; /* for enter() */ if(salt[Ckey].c == nil || salt[Ckeytype].c == nil || proccreate(kbdproc, nil, 4096) < 0) goto err; return 0; err: werrstr("SDL_Init: %r"); return -1; } int SDL_EventState(Uint32, int) { return 0; } SDL_Keymod SDL_GetModState(void) { return kmod; } int SDL_ShowCursor(int toggle) { if(toggle == SDL_QUERY) return showcursor; showcursor = toggle == SDL_ENABLE; setcursor(mctl, (cursor == nil && showcursor) ? nil : &nocursor); return showcursor; } int SDL_GetNumAudioDevices(int iscapture) { /* FIXME look for extra USB devices? */ USED(iscapture); return 1; } char * SDL_GetAudioDeviceName(int index, int iscapture) { /* FIXME look for extra USB devices? */ USED(index); USED(iscapture); return "/dev/audio"; } void SDL_LockAudioDevice(SDL_AudioDeviceID id) { qlock(&au[id]); } void SDL_UnlockAudioDevice(SDL_AudioDeviceID id) { qunlock(&au[id]); } static void audiothread(void *p) { Audiodev *d; d = p; threadsetname("audio %s", d == &au[Aout] ? "out" : "in"); for(;;){ qlock(d); if(d->paused) memset(d->buf, 0, sizeof(d->buf)); else d->cb(d->userdata, d->buf, sizeof(d->buf)); qunlock(d); if(write(d->fd, d->buf, sizeof(d->buf)) != sizeof(d->buf)) break; } threadexits(nil); } void SDL_PauseAudioDevice(SDL_AudioDeviceID id, SDL_bool pause) { Audiodev *a; a = &au[id]; if(a->paused && !pause){ if(a->pid < 0) a->pid = proccreate(audiothread, a, mainstacksize); a->paused = 0; }else if(!a->paused && pause){ a->paused = 1; } } SDL_AudioDeviceID SDL_OpenAudioDevice(char *dev, int rec, SDL_AudioSpec *want, SDL_AudioSpec *have, u32int change) { Audiodev *a; SDL_AudioDeviceID id; /* FIXME look for extra USB devices? */ USED(dev); if(change != SDL_AUDIO_ALLOW_ANY_CHANGE){ /* FIXME sampling in mono */ werrstr("SDL_OpenAudioDevice: changes not implemented"); return 0; } have->freq = 44100; have->format = AUDIO_S16; have->channels = 2; have->samples = want->samples; id = rec ? Arec : Aout; a = &au[id]; if(a->fd < 0 && (a->fd = open("/dev/audio", a->mode|OCEXEC)) < 0){ werrstr("SDL_OpenAudioDevice: %r"); return 0; } a->userdata = want->userdata; a->cb = want->callback; a->paused = 1; return id; } void SDL_CloseAudioDevice(SDL_AudioDeviceID id) { Audiodev *a; a = &au[id]; qlock(a); close(a->fd); a->fd = -1; a->pid = -1; a->userdata = nil; a->cb = nil; qunlock(a); } u64int SDL_GetPerformanceFrequency(void) { return _tos->cyclefreq; } u64int 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 sdlthread(void *p) { SDL_Thread t; t = *(SDL_Thread*)p; if(t.name != nil) threadsetname(t.name); free(p); threadexits(t.f(t.userdata) == 0 ? nil : "error"); } SDL_Thread * SDL_CreateThread(SDL_ThreadFunction f, char *name, void *userdata) { SDL_Thread *t; if((t = calloc(1, sizeof(*t))) == nil) return nil; t->f = f; t->name = name; t->userdata = userdata; if(proccreate(sdlthread, t, mainstacksize) < 0){ free(t); t = nil; } return t; } void SDL_DetachThread(SDL_Thread *) { } 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){ werrstr("SDL_CreateTexture: only SDL_PIXELFORMAT_ARGB8888 is supported"); goto err; } if((t = (SDL_Texture*)allocmemimage(Rect(0, 0, w, h), XRGB32)) == nil) /* FIXME ARGB32? */ goto err; memfillcolor(t, DTransparent); 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; r = re ? Rect(re->x, re->y, re->x+re->w, re->y+re->h) : t->r; /* FIXME non-ARGB8888 */ /* FIXME pitch */ USED(pitch); if(loadmemimage(t, r, pixels, Dx(r)*Dy(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, int w, int h, int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am) { SDL_Surface *s; int n; USED(rm, gm, bm, am); /* FIXME 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(Uint32 *pixels, int w, int h, int bpp, int pitch, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am) { SDL_Surface *s; int n; USED(pitch); /* FIXME pitch */ if((s = SDL_CreateRGBSurface(0, w, h, bpp, rm, gm, bm, am)) == nil) return nil; n = w*h*bpp/8; memmove(s->pixels, pixels, n); 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; mouseredraw = 1; setcursor(mctl, (cursor == nil && showcursor) ? nil : &nocursor); } } void SDL_FreeCursor(SDL_Cursor *c) { freeimage(c->i); free(c); if(cursor == c){ oldcursor = nil; cursor = nil; } } static int rune2scancode(Rune r) { if(r >= 'a' && r <= 'z') return r - 'a' + SDL_SCANCODE_A; if(r >= '1' && r <= '9') return r - '1' + SDL_SCANCODE_1; if(r == '0') return SDL_SCANCODE_0; if(r == '\n') return SDL_SCANCODE_ENTER; if(r == Kesc) return SDL_SCANCODE_ESCAPE; if(r == Kbs) return SDL_SCANCODE_BACKSPACE; if(r == '\t') return SDL_SCANCODE_TAB; if(r == ' ') return SDL_SCANCODE_SPACE; if(r == '-') return SDL_SCANCODE_MINUS; if(r == '=') return SDL_SCANCODE_EQUALS; if(r == '[') return SDL_SCANCODE_LEFTBRACKET; if(r == ']') return SDL_SCANCODE_RIGHTBRACKET; if(r == '\\') return SDL_SCANCODE_BACKSLASH; if(r == ';') return SDL_SCANCODE_SEMICOLON; if(r == '\'') return SDL_SCANCODE_APOSTROPHE; if(r == '/') return SDL_SCANCODE_SLASH; if(r == Kright) return SDL_SCANCODE_RIGHT; if(r == Kleft) return SDL_SCANCODE_LEFT; if(r == Kdown) return SDL_SCANCODE_DOWN; if(r == Kup) return SDL_SCANCODE_UP; /* FIXME SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_KP_MULTIPLY, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_KP_1, SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_7, SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_NONUSBACKSLASH, SDL_SCANCODE_NONUSHASH, */ /* FIXME there are some missing */ if(r == L'`' || r == L'´') /* FIXME this is most likely wrong */ return SDL_SCANCODE_GRAVE; return r; } int SDL_PollEvent(SDL_Event *e) { int t, down; if(e == nil) /* FIXME need to buffer the event so it won't get lost */ return 0; switch(alt(salt)){ case Ckey: recv(salt[Ckeytype].c, &t); if(textinput && rune >= 0x20 && (rune < KF || rune >= KF+0x1000)){ if(t != Rrepeat) break; e->type = SDL_TEXTINPUT; e->text.text[runetochar(e->text.text, &rune)] = 0; }else if((kmod & KMOD_LALT) != 0 && rune == Kdel){ /* alt+del = quit */ e->type = SDL_QUIT; return 1; }else if(textinput && t == Rdown){ break; }else{ e->type = (t == Rup) ? SDL_KEYUP : SDL_KEYDOWN; e->key.repeat = !textinput && t == Rrepeat; e->key.keysym.scancode = rune2scancode(rune); e->key.keysym.sym = rune; } return 1; case Cmouse: e->motion.x = mouse.xy.x - screen->r.min.x; e->motion.y = mouse.xy.y - screen->r.min.y; if(!eqpt(mouse.xy, oldmouse.xy)){ mouseredraw = 1; if(mouse.buttons == oldmouse.buttons){ e->type = SDL_MOUSEMOTION; return 1; } } if(mouse.buttons == oldmouse.buttons) break; /* FIXME there is a lot of hope for multiple buttons to never change its state at the same time */ if((down = (mouse.buttons & 1)) != (oldmouse.buttons & 1)){ /* left */ e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; e->button.button = SDL_BUTTON_LEFT; oldmouse.buttons = (oldmouse.buttons & ~1) | (mouse.buttons & 1); return 1; } if((down = (mouse.buttons & 2)) != (oldmouse.buttons & 2)){ /* middle */ e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; e->button.button = SDL_BUTTON_MIDDLE; oldmouse.buttons = (oldmouse.buttons & ~2) | (mouse.buttons & 2); return 1; } if((down = (mouse.buttons & 4)) != (oldmouse.buttons & 4)){ /* right */ e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; e->button.button = SDL_BUTTON_RIGHT; oldmouse.buttons = (oldmouse.buttons & ~4) | (mouse.buttons & 4); return 1; } if(mouse.buttons & (8|16)){ e->type = SDL_MOUSEWHEEL; e->wheel.x = 0; e->wheel.y = (mouse.buttons & 8) ? -1 : 1; return 1; } break; case Cresize: forceredraw = 1; if(getwindow(display, Refnone) < 0){ fprint(2, "%r\n"); /* FIXME do something here? */ //threadexitsall(nil); } e->type = SDL_WINDOWEVENT; e->window.event = SDL_WINDOWEVENT_EXPOSED; return 1; } return 0; } int SDL_PushEvent(SDL_Event *event) { /* FIXME does it matter? */ USED(event); return -1; } void SDL_WarpMouseInWindow(SDL_Window *, int x, int y) { moveto(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 = mouse.xy.x; if(y != nil) *y = mouse.xy.y; b = 0; if(mouse.buttons & 1) b |= SDL_BUTTON_LMASK; if(mouse.buttons & 2) b |= SDL_BUTTON_MMASK; if(mouse.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 = (mouse.xy.x - screen->r.min.x) * logiw / physw; if(y != nil) *y = (mouse.xy.y - screen->r.min.y) * logih / physh; return b; } void SDL_RenderGetScale(SDL_Renderer *, float *scaleX, float *scaleY) { *scaleX = 1.0; *scaleY = 1.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 textinput; } void SDL_StartTextInput(void) { textinput = SDL_TRUE; } void SDL_StopTextInput(void) { textinput = SDL_FALSE; } void SDL_Delay(Uint32 ms) { npe_nsleep((uvlong)ms*1000000ULL); } static void * resize(u32int *src, int iw, int ih, u32int *dst, int ow, int oh) { int i, j, m, n; u32int *d; if(iw == ow && ih == oh) return src; d = dst; n = ow/iw; for(; ih > 0 && oh > 0; ih--){ for(i = j = 0; i < iw; i++, src++) for(m = 0; m < n && j < ow; m++, j++) *dst++ = *src; oh--; for(m = 1; m < n && oh > 0; m++){ memmove(dst, dst-j, j*4); dst += j; oh--; } } return d; } int SDL_RenderCopy(SDL_Renderer *, SDL_Texture *t, SDL_Rect *sre, SDL_Rect *dre) { Rectangle sr, dr; if(sre != nil){ sr.min = Pt(sre->x, sre->y); sr.max = addpt(sr.min, Pt(sre->w, sre->h)); }else sr = t->r; if(dre != nil){ dr.min = Pt(dre->x, dre->y); dr.max = addpt(dr.min, Pt(dre->w, dre->h)); }else /* stretch */ dr = Rect(0, 0, logiw, logih); if(back == nil || Dx(back->r) != logiw || Dy(back->r) != logih){ freememimage(back); back = allocmemimage(Rect(0, 0, logiw, logih), XRGB32); 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)) resize((u32int*)byteaddr(t, ZP), Dx(sr), Dy(sr), (u32int*)byteaddr(back, ZP), logiw, logih); else memimagedraw(back, dr, t, sr.min, nil, ZP, S); return 0; } void SDL_RenderPresent(SDL_Renderer *) { Rectangle r, clipr; static u32int *b; uchar *rb; if(!forceredraw && (forceredraw = memcmp(backcopy, byteaddr(back, ZP), logiw*logih*4)) == 0 && !mouseredraw) 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(forceredraw || front == nil){ rb = resize((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(mouse.xy, cursor->hot); r.max = addpt(r.min, cursor->i->r.max); if(!forceredraw && oldcursor != nil){ clipr.min = subpt(oldmouse.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); mouseredraw = 0; oldmouse.xy = mouse.xy; oldcursor = cursor; flushimage(display, 1); if(forceredraw) memmove(backcopy, byteaddr(back, ZP), logiw*logih*4); else replclipr(screen, 0, screen->r); forceredraw = 0; } Uint32 SDL_GetWindowFlags(SDL_Window *) { /* FIXME is this correct? */ return SDL_WINDOW_INPUT_FOCUS; } int SDL_RenderSetLogicalSize(SDL_Renderer *, int w, int h) { if(logiw != w || logih != h){ logiw = w; logih = h; forceredraw = 1; } return 0; } int SDL_GetRendererOutputSize(SDL_Renderer *, int *w, int *h) { if(w != nil) *w = logiw; if(h != nil) *h = 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); forceredraw = 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); forceredraw = 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); } int SDL_SetTextureBlendMode(SDL_Texture *, SDL_BlendMode blendMode) { if(blendMode != SDL_BLENDMODE_NONE){ werrstr("SDL_SetTextureBlendMode: only SDL_BLENDMODE_NONE is supported"); return -1; } return 0; } SDL_bool SDL_SetHint(char *name, char *value) { /* FIXME anyone cares about name="SDL_RENDER_SCALE_QUALITY" value="(best|nearest)"? */ USED(name); USED(value); 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) { SDL_RenderSetLogicalSize(nil, physw, physh); 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()/1000000ULL; } 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_SetThreadPriority(int) { /* nothing to do here */ } void SDL_RestoreWindow(SDL_Window *) { /* nothing to do here */ } void SDL_RaiseWindow(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) { }