Support arbitrary pixel formats with more rawfb demos

This commit is contained in:
Cameron Cawley 2024-05-03 11:46:23 +01:00
parent 37e54da201
commit 488525745a
7 changed files with 114 additions and 1207 deletions

View File

@ -28,23 +28,23 @@
* *
* =============================================================== * ===============================================================
*/ */
#ifndef NK_RAWFB_H_ #ifndef NK_RAWFB_H_
#define NK_RAWFB_H_ #define NK_RAWFB_H_
struct rawfb_context; struct rawfb_context;
typedef enum rawfb_pixel_layout { struct rawfb_pl {
PIXEL_LAYOUT_XRGB_8888, unsigned char bytesPerPixel;
PIXEL_LAYOUT_RGBX_8888 unsigned char rshift, gshift, bshift, ashift;
} unsigned char rloss, gloss, bloss, aloss;
rawfb_pl; };
/* All functions are thread-safe */ /* All functions are thread-safe */
NK_API struct rawfb_context *nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, const unsigned int pitch, const rawfb_pl pl); NK_API struct rawfb_context *nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, const unsigned int pitch, const struct rawfb_pl pl);
NK_API void nk_rawfb_render(const struct rawfb_context *rawfb, const struct nk_color clear, const unsigned char enable_clear); NK_API void nk_rawfb_render(const struct rawfb_context *rawfb, const struct nk_color clear, const unsigned char enable_clear);
NK_API void nk_rawfb_shutdown(struct rawfb_context *rawfb); NK_API void nk_rawfb_shutdown(struct rawfb_context *rawfb);
NK_API void nk_rawfb_resize_fb(struct rawfb_context *rawfb, void *fb, const unsigned int w, const unsigned int h, const unsigned int pitch, const rawfb_pl pl); NK_API void nk_rawfb_resize_fb(struct rawfb_context *rawfb, void *fb, const unsigned int w, const unsigned int h, const unsigned int pitch, const struct rawfb_pl pl);
#endif #endif
/* /*
@ -62,8 +62,7 @@ NK_API void nk_rawfb_resize_fb(struct rawfb_context *rawfb, voi
struct rawfb_image { struct rawfb_image {
void *pixels; void *pixels;
int w, h, pitch; int w, h, pitch;
rawfb_pl pl; struct rawfb_pl pl;
enum nk_font_atlas_format format;
}; };
struct rawfb_context { struct rawfb_context {
struct nk_context ctx; struct nk_context ctx;
@ -81,54 +80,28 @@ struct rawfb_context {
#endif #endif
static unsigned int static unsigned int
nk_rawfb_color2int(const struct nk_color c, rawfb_pl pl) nk_rawfb_color2int(const struct nk_color c, const struct rawfb_pl pl)
{ {
unsigned int res = 0; unsigned int res = 0;
switch (pl) { res |= (c.r >> pl.rloss) << pl.rshift;
case PIXEL_LAYOUT_RGBX_8888: res |= (c.g >> pl.gloss) << pl.gshift;
res |= c.r << 24; res |= (c.b >> pl.bloss) << pl.bshift;
res |= c.g << 16; res |= (c.a >> pl.aloss) << pl.ashift;
res |= c.b << 8;
res |= c.a;
break;
case PIXEL_LAYOUT_XRGB_8888:
res |= c.a << 24;
res |= c.r << 16;
res |= c.g << 8;
res |= c.b;
break;
default:
perror("nk_rawfb_color2int(): Unsupported pixel layout.\n");
break;
}
return (res); return (res);
} }
static struct nk_color static struct nk_color
nk_rawfb_int2color(const unsigned int i, rawfb_pl pl) nk_rawfb_int2color(const unsigned int i, const struct rawfb_pl pl)
{ {
struct nk_color col = {0,0,0,0}; struct nk_color col = {0,0,0,0};
switch (pl) { col.r = (pl.rloss == 8) ? 0xff : ((i >> pl.rshift) << pl.rloss) & 0xff;
case PIXEL_LAYOUT_RGBX_8888: col.g = (pl.gloss == 8) ? 0xff : ((i >> pl.gshift) << pl.gloss) & 0xff;
col.r = (i >> 24) & 0xff; col.b = (pl.bloss == 8) ? 0xff : ((i >> pl.bshift) << pl.bloss) & 0xff;
col.g = (i >> 16) & 0xff; col.a = (pl.aloss == 8) ? 0xff : ((i >> pl.ashift) << pl.aloss) & 0xff;
col.b = (i >> 8) & 0xff;
col.a = i & 0xff;
break;
case PIXEL_LAYOUT_XRGB_8888:
col.a = (i >> 24) & 0xff;
col.r = (i >> 16) & 0xff;
col.g = (i >> 8) & 0xff;
col.b = i & 0xff;
break;
default:
perror("nk_rawfb_int2color(): Unsupported pixel layout.\n");
break;
}
return col; return col;
} }
@ -138,14 +111,20 @@ nk_rawfb_ctx_setpixel(const struct rawfb_context *rawfb,
{ {
unsigned int c = nk_rawfb_color2int(col, rawfb->fb.pl); unsigned int c = nk_rawfb_color2int(col, rawfb->fb.pl);
unsigned char *pixels = rawfb->fb.pixels; unsigned char *pixels = rawfb->fb.pixels;
unsigned int *ptr;
pixels += y0 * rawfb->fb.pitch; pixels += y0 * rawfb->fb.pitch;
ptr = (unsigned int *)pixels + x0;
if (y0 < rawfb->scissors.h && y0 >= rawfb->scissors.y && if (y0 < rawfb->scissors.h && y0 >= rawfb->scissors.y &&
x0 >= rawfb->scissors.x && x0 < rawfb->scissors.w) x0 >= rawfb->scissors.x && x0 < rawfb->scissors.w) {
*ptr = c;
if (rawfb->fb.pl.bytesPerPixel == sizeof(unsigned int)) {
*((unsigned int *)pixels + x0) = c;
} else if (rawfb->fb.pl.bytesPerPixel == sizeof(unsigned short)) {
*((unsigned short *)pixels + x0) = c;
} else {
*((unsigned char *)pixels + x0) = c;
}
}
} }
static void static void
@ -156,22 +135,29 @@ nk_rawfb_line_horizontal(const struct rawfb_context *rawfb,
* It does not check for scissors or image borders. * It does not check for scissors or image borders.
* The caller has to make sure it does no exceed bounds. */ * The caller has to make sure it does no exceed bounds. */
unsigned int i, n; unsigned int i, n;
unsigned int c[16]; unsigned char c[16 * 4];
unsigned char *pixels = rawfb->fb.pixels; unsigned char *pixels = rawfb->fb.pixels;
unsigned int *ptr; unsigned int bpp = rawfb->fb.pl.bytesPerPixel;
pixels += y * rawfb->fb.pitch; pixels += (y * rawfb->fb.pitch) + (x0 * bpp);
ptr = (unsigned int *)pixels + x0;
n = x1 - x0; n = (x1 - x0) * bpp;
for (i = 0; i < sizeof(c) / sizeof(c[0]); i++) if (bpp == sizeof(unsigned int)) {
c[i] = nk_rawfb_color2int(col, rawfb->fb.pl); for (i = 0; i < sizeof(c) / bpp; i++)
((unsigned int *)c)[i] = nk_rawfb_color2int(col, rawfb->fb.pl);
} else if (bpp == sizeof(unsigned short)) {
for (i = 0; i < sizeof(c) / bpp; i++)
((unsigned short *)c)[i] = nk_rawfb_color2int(col, rawfb->fb.pl);
} else {
for (i = 0; i < sizeof(c) / bpp; i++)
((unsigned char *)c)[i] = nk_rawfb_color2int(col, rawfb->fb.pl);
}
while (n > 16) { while (n > sizeof(c)) {
memcpy((void *)ptr, c, sizeof(c)); memcpy((void*)pixels, c, sizeof(c));
n -= 16; ptr += 16; n -= sizeof(c); pixels += sizeof(c);
} for (i = 0; i < n; i++) } for (i = 0; i < n; i++)
ptr[i] = c[i]; pixels[i] = c[i];
} }
static void static void
@ -180,16 +166,16 @@ nk_rawfb_img_setpixel(const struct rawfb_image *img,
{ {
unsigned int c = nk_rawfb_color2int(col, img->pl); unsigned int c = nk_rawfb_color2int(col, img->pl);
unsigned char *ptr; unsigned char *ptr;
unsigned int *pixel;
NK_ASSERT(img); NK_ASSERT(img);
if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) { if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) {
ptr = (unsigned char *)img->pixels + (img->pitch * y0); ptr = (unsigned char *)img->pixels + (img->pitch * y0);
pixel = (unsigned int *)ptr;
if (img->format == NK_FONT_ATLAS_ALPHA8) { if (img->pl.bytesPerPixel == sizeof(unsigned int)) {
ptr[x0] = col.a; ((unsigned int *)ptr)[x0] = c;
} else if (img->pl.bytesPerPixel == sizeof(unsigned short)) {
((unsigned short *)ptr)[x0] = c;
} else { } else {
pixel[x0] = c; ((unsigned char *)ptr)[x0] = c;
} }
} }
} }
@ -204,12 +190,15 @@ nk_rawfb_img_getpixel(const struct rawfb_image *img, const int x0, const int y0)
if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) { if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) {
ptr = (unsigned char *)img->pixels + (img->pitch * y0); ptr = (unsigned char *)img->pixels + (img->pitch * y0);
if (img->format == NK_FONT_ATLAS_ALPHA8) { if (img->pl.bytesPerPixel == sizeof(unsigned int)) {
col.a = ptr[x0];
col.b = col.g = col.r = 0xff;
} else {
pixel = ((unsigned int *)ptr)[x0]; pixel = ((unsigned int *)ptr)[x0];
col = nk_rawfb_int2color(pixel, img->pl); col = nk_rawfb_int2color(pixel, img->pl);
} else if (img->pl.bytesPerPixel == sizeof(unsigned short)) {
pixel = ((unsigned short *)ptr)[x0];
col = nk_rawfb_int2color(pixel, img->pl);
} else {
pixel = ((unsigned char *)ptr)[x0];
col = nk_rawfb_int2color(pixel, img->pl);
} }
} return col; } return col;
} }
@ -823,33 +812,34 @@ nk_rawfb_clear(const struct rawfb_context *rawfb, const struct nk_color col)
NK_API struct rawfb_context* NK_API struct rawfb_context*
nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h,
const unsigned int pitch, const rawfb_pl pl) const unsigned int pitch, const struct rawfb_pl pl)
{ {
const void *tex; const void *tex;
struct rawfb_context *rawfb; struct rawfb_context *rawfb;
rawfb = malloc(sizeof(struct rawfb_context)); rawfb = malloc(sizeof(struct rawfb_context));
if (!rawfb) if (!rawfb)
return NULL; return NULL;
memset(rawfb, 0, sizeof(struct rawfb_context)); memset(rawfb, 0, sizeof(struct rawfb_context));
rawfb->font_tex.pixels = tex_mem; rawfb->font_tex.pixels = tex_mem;
rawfb->font_tex.format = NK_FONT_ATLAS_ALPHA8; rawfb->font_tex.pl.bytesPerPixel = 1;
rawfb->font_tex.w = rawfb->font_tex.h = 0; rawfb->font_tex.pl.rshift = 0;
rawfb->font_tex.pl.gshift = 0;
rawfb->font_tex.pl.bshift = 0;
rawfb->font_tex.pl.ashift = 0;
rawfb->font_tex.pl.rloss = 8;
rawfb->font_tex.pl.gloss = 8;
rawfb->font_tex.pl.bloss = 8;
rawfb->font_tex.pl.aloss = 0;
rawfb->font_tex.w = rawfb->font_tex.h = rawfb->font_tex.pitch = 0;
rawfb->fb.pixels = fb; rawfb->fb.pixels = fb;
rawfb->fb.w = w; rawfb->fb.w = w;
rawfb->fb.h = h; rawfb->fb.h = h;
rawfb->fb.pitch = pitch;
rawfb->fb.pl = pl; rawfb->fb.pl = pl;
if (pl == PIXEL_LAYOUT_RGBX_8888 || pl == PIXEL_LAYOUT_XRGB_8888) {
rawfb->fb.format = NK_FONT_ATLAS_RGBA32;
rawfb->fb.pitch = pitch;
} else {
perror("nk_rawfb_init(): Unsupported pixel layout.\n");
free(rawfb);
return NULL;
}
if (0 == nk_init_default(&rawfb->ctx, 0)) { if (0 == nk_init_default(&rawfb->ctx, 0)) {
free(rawfb); free(rawfb);
return NULL; return NULL;
@ -857,21 +847,13 @@ nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int
nk_font_atlas_init_default(&rawfb->atlas); nk_font_atlas_init_default(&rawfb->atlas);
nk_font_atlas_begin(&rawfb->atlas); nk_font_atlas_begin(&rawfb->atlas);
tex = nk_font_atlas_bake(&rawfb->atlas, &rawfb->font_tex.w, &rawfb->font_tex.h, rawfb->font_tex.format); tex = nk_font_atlas_bake(&rawfb->atlas, &rawfb->font_tex.w, &rawfb->font_tex.h, NK_FONT_ATLAS_ALPHA8);
if (!tex) { if (!tex) {
free(rawfb); free(rawfb);
return NULL; return NULL;
} }
switch(rawfb->font_tex.format) { rawfb->font_tex.pitch = rawfb->font_tex.w * 1;
case NK_FONT_ATLAS_ALPHA8:
rawfb->font_tex.pitch = rawfb->font_tex.w * 1;
break;
case NK_FONT_ATLAS_RGBA32:
rawfb->font_tex.pitch = rawfb->font_tex.w * 4;
break;
};
/* Store the font texture in tex scratch memory */
memcpy(rawfb->font_tex.pixels, tex, rawfb->font_tex.pitch * rawfb->font_tex.h); memcpy(rawfb->font_tex.pixels, tex, rawfb->font_tex.pitch * rawfb->font_tex.h);
nk_font_atlas_end(&rawfb->atlas, nk_handle_ptr(NULL), NULL); nk_font_atlas_end(&rawfb->atlas, nk_handle_ptr(NULL), NULL);
if (rawfb->atlas.default_font) if (rawfb->atlas.default_font)
@ -1036,7 +1018,7 @@ nk_rawfb_resize_fb(struct rawfb_context *rawfb,
const unsigned int w, const unsigned int w,
const unsigned int h, const unsigned int h,
const unsigned int pitch, const unsigned int pitch,
const rawfb_pl pl) const struct rawfb_pl pl)
{ {
rawfb->fb.w = w; rawfb->fb.w = w;
rawfb->fb.h = h; rawfb->fb.h = h;

View File

@ -2,7 +2,7 @@ CFLAGS=`sdl2-config --cflags --libs` -std=c89 -Wall -Wextra -pedantic -Wno-unu
.PHONY: clean .PHONY: clean
demo: main.c nuklear_sdl_rawfb.h demo: main.c ../nuklear_rawfb.h
$(CC) -o demo *.c $(CFLAGS) -lrt -lm $(CC) -o demo *.c $(CFLAGS) -lrt -lm
clean: clean:

View File

@ -20,7 +20,7 @@
#define NK_INCLUDE_SOFTWARE_FONT #define NK_INCLUDE_SOFTWARE_FONT
#include "../../../nuklear.h" #include "../../../nuklear.h"
#define NK_RAWFB_IMPLEMENTATION #define NK_RAWFB_IMPLEMENTATION
#include "nuklear_sdl_rawfb.h" #include "../nuklear_rawfb.h"
/* =============================================================== /* ===============================================================
* *
@ -132,6 +132,8 @@ int main(int argc, char **argv)
struct nk_vec2 vec; struct nk_vec2 vec;
struct nk_rect bounds = {40,40,0,0}; struct nk_rect bounds = {40,40,0,0};
struct rawfb_context *context; struct rawfb_context *context;
struct rawfb_pl pl;
unsigned char tex_scratch[512 * 512];
SDL_DisplayMode dm; SDL_DisplayMode dm;
SDL_Window *window; SDL_Window *window;
@ -164,8 +166,17 @@ int main(int argc, char **argv)
surface = SDL_CreateRGBSurfaceWithFormat(0, dm.w-200, dm.h-200, 32, SDL_PIXELFORMAT_ARGB8888); surface = SDL_CreateRGBSurfaceWithFormat(0, dm.w-200, dm.h-200, 32, SDL_PIXELFORMAT_ARGB8888);
pl.bytesPerPixel = surface->format->BytesPerPixel;
pl.rshift = surface->format->Rshift;
pl.gshift = surface->format->Gshift;
pl.bshift = surface->format->Bshift;
pl.ashift = surface->format->Ashift;
pl.rloss = surface->format->Rloss;
pl.gloss = surface->format->Gloss;
pl.bloss = surface->format->Bloss;
pl.aloss = surface->format->Aloss;
context = nk_rawfb_init(surface, 13.0f); context = nk_rawfb_init(surface->pixels, tex_scratch, surface->w, surface->h, surface->pitch, pl);
while(1) while(1)

File diff suppressed because it is too large Load Diff

View File

@ -450,6 +450,7 @@ int main ()
struct nk_wayland nk_wayland_ctx; struct nk_wayland nk_wayland_ctx;
struct wl_registry *registry; struct wl_registry *registry;
int running = 1; int running = 1;
struct rawfb_pl pl;
//1. Initialize display //1. Initialize display
nk_wayland_ctx.display = wl_display_connect (NULL); nk_wayland_ctx.display = wl_display_connect (NULL);
@ -495,7 +496,17 @@ int main ()
wl_surface_attach (nk_wayland_ctx.surface, nk_wayland_ctx.front_buffer, 0, 0); wl_surface_attach (nk_wayland_ctx.surface, nk_wayland_ctx.front_buffer, 0, 0);
wl_surface_commit (nk_wayland_ctx.surface); wl_surface_commit (nk_wayland_ctx.surface);
nk_rawfb_init(nk_wayland_ctx.data, nk_wayland_ctx.tex_scratch, WIDTH, HEIGHT, WIDTH*4, PIXEL_LAYOUT_XRGB_8888); pl.bytesPerPixel = 4;
pl.ashift = 24;
pl.rshift = 16;
pl.gshift = 8;
pl.bshift = 0;
pl.aloss = 0;
pl.rloss = 0;
pl.gloss = 0;
pl.bloss = 0;
nk_rawfb_init(nk_wayland_ctx.data, nk_wayland_ctx.tex_scratch, WIDTH, HEIGHT, WIDTH*4, pl);
//4. rendering UI //4. rendering UI

View File

@ -156,7 +156,7 @@ main(void)
XWindow xw; XWindow xw;
struct rawfb_context *rawfb; struct rawfb_context *rawfb;
void *fb = NULL; void *fb = NULL;
rawfb_pl pl; struct rawfb_pl pl;
unsigned char tex_scratch[512 * 512]; unsigned char tex_scratch[512 * 512];
/* X11 */ /* X11 */

View File

@ -35,7 +35,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
NK_API int nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, unsigned int w, unsigned int h, void **fb, rawfb_pl *pl); NK_API int nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, unsigned int w, unsigned int h, void **fb, struct rawfb_pl *pl);
NK_API int nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb); NK_API int nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb);
NK_API void nk_xlib_render(Drawable screen); NK_API void nk_xlib_render(Drawable screen);
NK_API void nk_xlib_shutdown(void); NK_API void nk_xlib_shutdown(void);
@ -74,7 +74,7 @@ static struct {
NK_API int NK_API int
nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root,
unsigned int w, unsigned int h, void **fb, rawfb_pl *pl) unsigned int w, unsigned int h, void **fb, struct rawfb_pl *pl)
{ {
unsigned int depth = XDefaultDepth(dpy, screen); unsigned int depth = XDefaultDepth(dpy, screen);
xlib.dpy = dpy; xlib.dpy = dpy;
@ -138,22 +138,15 @@ nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root,
xlib.gc = XDefaultGC(dpy, screen); xlib.gc = XDefaultGC(dpy, screen);
*fb = xlib.ximg->data; *fb = xlib.ximg->data;
if (xlib.ximg->red_mask == 0xff0000 && pl->bytesPerPixel = xlib.ximg->bits_per_pixel / 8;
xlib.ximg->green_mask == 0xff00 && pl->rshift = __builtin_ctzl(xlib.ximg->red_mask);
xlib.ximg->blue_mask == 0xff && pl->gshift = __builtin_ctzl(xlib.ximg->green_mask);
xlib.ximg->bits_per_pixel == 32) { pl->bshift = __builtin_ctzl(xlib.ximg->blue_mask);
*pl = PIXEL_LAYOUT_XRGB_8888; pl->ashift = 0;
} pl->rloss = 8 - __builtin_popcount(xlib.ximg->red_mask);
else if (xlib.ximg->red_mask == 0xff000000 && pl->gloss = 8 - __builtin_popcount(xlib.ximg->green_mask);
xlib.ximg->green_mask == 0xff0000 && pl->bloss = 8 - __builtin_popcount(xlib.ximg->blue_mask);
xlib.ximg->blue_mask == 0xff00 && pl->aloss = 8;
xlib.ximg->bits_per_pixel == 32) {
*pl = PIXEL_LAYOUT_RGBX_8888;
}
else {
perror("nk_xlib_init(): Unrecognized pixel layout.\n");
return 0;
}
return 1; return 1;
} }
@ -257,7 +250,7 @@ nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct r
} else if (evt->type == Expose || evt->type == ConfigureNotify) { } else if (evt->type == Expose || evt->type == ConfigureNotify) {
/* Window resize handler */ /* Window resize handler */
void *fb; void *fb;
rawfb_pl pl; struct rawfb_pl pl;
unsigned int width, height; unsigned int width, height;
XWindowAttributes attr; XWindowAttributes attr;
XGetWindowAttributes(dpy, win, &attr); XGetWindowAttributes(dpy, win, &attr);