ref: 979ae53cfee913c2d303ab0f95aaa65dace1c7b5
dir: /libnpe_sdl3/surface.c/
#include "_sdl.h"
#include <SDL3/SDL_iostream.h>
#include <bio.h>
static void
setformat(SDL_Surface *s, ulong chan, int bpp)
{
if((s->format = calloc(1, sizeof(SDL_PixelFormat))) == nil)
sysfatal("setformat: %r");
s->format->BytesPerPixel = bpp / 8;
s->format->format = chan2pixel(chan);
if(chan == CMAP8){
if((s->format->palette = calloc(1, sizeof(SDL_Palette))) == nil)
sysfatal("setformat: %r");
s->format->palette->ncolors = 256;
if((s->format->palette->colors = calloc(1, sizeof(SDL_Color) * 256)) == nil)
sysfatal("setformat: %r");
}
}
static SDL_Surface *
sfrommem(Memimage *i)
{
int bpp;
SDL_Surface *s;
if((s = mallocz(sizeof *s, 1)) == nil)
return nil;
s->i = i;
s->w = Dx(i->r);
s->h = Dy(i->r);
bpp = i->depth;
s->pitch = s->w * (bpp / 8);
s->clip_rect.x = 0;
s->clip_rect.y = 0;
s->clip_rect.w = s->w;
s->clip_rect.h = s->h;
s->n = s->pitch * s->h;
if(i->chan == CMAP8)
s->pixels = calloc(1, s->n);
else
s->pixels = i->data->bdata;
if(s->pixels == nil)
return nil;
setformat(s, i->chan, bpp);
return s;
}
SDL_Surface *
SDL_CreateRGBSurface(Uint32, int w, int h, int bpp, Uint32 rm, Uint32 gm, Uint32 bm, Uint32 am)
{
SDL_Surface *s;
int n;
ulong chan;
rm = rm ? rm : npe_sdl.defmask.r;
gm = gm ? gm : npe_sdl.defmask.g;
bm = bm ? bm : npe_sdl.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;
}
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, s->n);
}else{
s->i = allocmemimage(Rect(0,0,s->w,s->h), chan);
s->pixels = ((Memimage*)s->i)->data->bdata;
}
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;
s->n = n;
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 fbpp, Uint32 fmt)
{
SDL_Surface *s;
int bpp;
ulong chan;
Uint32 rm, gm, bm, am;
if((chan = pixel2chan(fmt)) == 0){
werrstr("SDL_CreateRGBSurfaceWithFormat: FIXME format %8ux not implemented", fmt);
return nil;
}
chan2mask(chan, &bpp, &rm, &gm, &bm, &am);
if(bpp != fbpp && fbpp != 0)
sysfatal("FIXME SDL_CreateRGBSurfaceWithFormat passes wrong bpp for format: %d not %d", fbpp, bpp);
if((s = SDL_CreateRGBSurface(flags, w, h, bpp, rm, bm, gm, am)) == nil)
return nil;
return s;
}
Uint32
SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b)
{
return SDL_MapRGB(surface->format, r, g, b);
}
bool
SDL_SetSurfacePalette(SDL_Surface *s, SDL_Palette *palette)
{
s->format->palette = palette;
return true;
}
bool
SDL_SetSurfaceColorKey(SDL_Surface *s, bool enable, Uint32 key)
{
s->keyset = enable;
s->key = key;
return true;
}
static void
syncpalette(SDL_Surface *s)
{
SDL_Color *c;
Uint8 *to;
int j;
to = ((Memimage*)s->i)->data->bdata;
for(j = 0; j < s->n; j++){
c = s->format->palette->colors + s->pixels[j];
*to++ = c->b;
*to++ = c->g;
*to++ = c->r;
*to++ = c->a;
}
}
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;
}
}
bool
SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
{
Rectangle r, r2;
r = srcrect == nil ? Rect(0, 0, src->w, src->h) : Rect(srcrect->x, srcrect->y, srcrect->x+srcrect->w, srcrect->y+srcrect->h);
r2 = dstrect == nil ? Rect(0, 0, dst->w, dst->h) : Rect(dstrect->x, dstrect->y, dstrect->x+dstrect->w, dstrect->y+dstrect->h);
if(src->format->format == SDL_PIXELFORMAT_INDEX8)
syncpalette(src);
memimagedraw(dst->i, r2, src->i, ZP, nil, ZP, S);
if(dst->format->format == SDL_PIXELFORMAT_INDEX8)
synctopalette(dst);
return true;
}
bool
SDL_SetSurfaceRLE(SDL_Surface *, int)
{
/* nothing to do here */
return true;
}
bool
SDL_SetSurfaceBlendMode(SDL_Surface *, SDL_BlendMode blendMode)
{
if(blendMode != SDL_BLENDMODE_NONE){
werrstr("SDL_SetSurfaceBlendMode: only SDL_BLENDMODE_NONE is supported");
return false;
}
return true;
}
bool
SDL_LockSurface(SDL_Surface *)
{
/* nothing to do here */
return true;
}
bool
SDL_UnlockSurface(SDL_Surface *)
{
/* nothing to do here */
return true;
}
// https://wiki.libsdl.org/SDL3/SDL_LowerBlit
bool
SDL_LowerBlit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect)
{
return SDL_BlitSurface(src, srcrect, dst, dstrect);
}
bool
SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect)
{
Rectangle r, r2;
Memimage *rowimg;
int w, h;
int scale;
ulong *s, *d, *e;
ulong *out;
int i, y;
r = srcrect == nil ? Rect(0, 0, src->w, src->h) : Rect(srcrect->x, srcrect->y, srcrect->x+srcrect->w, srcrect->y+srcrect->h);
r2 = dstrect == nil ? Rect(0, 0, dst->w, dst->h) : Rect(dstrect->x, dstrect->y, dstrect->x+dstrect->w, dstrect->y+dstrect->h);
w = Dx(r);
h = Dy(r);
scale = Dx(r2)/w;
if(scale <= 0)
scale = 1;
else if(scale > 12)
scale = 12;
rowimg = allocmemimage(Rect(0, 0, scale*w, 1), ((Memimage*)src->i)->chan);
assert(dst->format->format != SDL_PIXELFORMAT_INDEX8);
if(src->format->format == SDL_PIXELFORMAT_INDEX8)
syncpalette(src);
for(y = 0; y < h; y++){
s = wordaddr(src->i, Pt(0, y));
d = (ulong*)rowimg->data->bdata;
e = s + w;
for(; s < e; s++){
switch(scale){
case 12:
*d++ = *s;
case 11:
*d++ = *s;
case 10:
*d++ = *s;
case 9:
*d++ = *s;
case 8:
*d++ = *s;
case 7:
*d++ = *s;
case 6:
*d++ = *s;
case 5:
*d++ = *s;
case 4:
*d++ = *s;
case 3:
*d++ = *s;
case 2:
*d++ = *s;
case 1:
*d++ = *s;
}
}
d = (ulong*)rowimg->data->bdata;
for(i = 0; i < scale; i++){
out = wordaddr(dst->i, Pt(0, y*scale + i));
memcpy(out, d, scale*w*4);
}
}
freememimage(rowimg);
return true;
}
void
SDL_DestroySurface(SDL_Surface *surface)
{
freememimage(surface->i);
memset(surface, 0, sizeof(surface));
free(surface);
}
bool
SDL_SaveBMP(SDL_Surface *s, const char *file)
{
u8int h[54];
Biobuf *f;
int sz, i;
if(s->format->format != SDL_PIXELFORMAT_RGB24){
werrstr("SDL_SaveBMP: not rgb24");
return false;
}
if((f = Bopen(file, OWRITE|OTRUNC)) == nil)
return false;
sz = sizeof(h) + s->n;
memset(h, 0, sizeof(h));
h[0] = 'B';
h[1] = 'M';
h[0x02+0] = sz;
h[0x02+1] = sz>>8;
h[0x02+2] = sz>>16;
h[0x02+3] = sz>>24;
h[0x0a] = sizeof(h);
h[0x0e] = sizeof(h) - 14;
h[0x12+0] = s->w;
h[0x12+1] = s->w>>8;
h[0x12+2] = s->w>>16;
h[0x12+3] = s->w>>24;
h[0x16+0] = s->h;
h[0x16+1] = s->h>>8;
h[0x16+2] = s->h>>16;
h[0x16+3] = s->h>>24;
h[0x1a] = 1;
h[0x1c] = 24;
Bwrite(f, h, sizeof(h));
memset(h, 0, 4);
for(i = s->h-1; i >= 0; i--){
Bwrite(f, s->pixels+i*s->w*3, s->w*3);
if(s->w & 3)
Bwrite(f, h, 4-(s->w&3));
}
Bterm(f);
return true;
}
/* fight me */
SDL_Surface*
SDL_LoadBMP_IO(SDL_IOStream *o, bool closeio)
{
int n, pfd[2];
uchar buf[8192];
Memimage *i, *i2;
if(pipe(pfd) < 0)
sysfatal("SDL_LoadBMP_IO: %r");
switch(fork()){
case -1: sysfatal("SDL_LoadBMP_IO: %r");
case 0:
dup(pfd[0], 0);
dup(pfd[0], 1);
close(pfd[0]);
close(pfd[1]);
execl("/bin/bmp", "bmp", "-9tv", nil);
sysfatal("SDL_LoadBMP_IO: %r");
default:
close(pfd[0]);
}
while((n = SDL_ReadIO(o, buf, sizeof buf)) > 0)
if(write(pfd[1], buf, n) != n)
sysfatal("SDL_LoadBMP_IO: %r");
if(closeio)
SDL_CloseIO(o);
write(pfd[1], buf, 0);
if((i = readmemimage(pfd[1])) == nil)
sysfatal("SDL_LoadBMP_IO: %r");
close(pfd[1]);
/* bmp(1) doesn't do RGBA, SDL3 only does ARGB1555, RGB24 and ARGB32 */
if((i2 = allocmemimage(i->r, ARGB32)) == nil){
freememimage(i);
return nil;
}
memimagedraw(i2, i2->r, i, ZP, nil, ZP, S);
freememimage(i);
return sfrommem(i2);
}