vxKernel/src/modules/display/image/render.c

279 lines
5.0 KiB
C

#include <vhex/display/image.h>
#include <vhex/display/shader.h>
#include <vhex/display.h>
//---
// Internal functions
//---
struct imgbox {
struct {
struct {
int start;
int end;
} y;
struct {
int start;
int end;
} x;
} img;
struct {
uint16_t *vram;
int voff;
} surface;
};
/* dsubimage_default_render() : raw-format image render */
static void dsubimage_default_render(image_t const *image, struct imgbox *box)
{
(void)image;
(void)box;
#if 0
uint16_t *vram;
uint16_t *vidxs;
uint16_t *vidx;
int voff;
vram = surface->draw;
voff = box->surface.idx.offset;
vidxs = &vram[box->surface.idx.start];
for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) {
vidx = vidxs;
for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) {
*(vidx++) = image_decode_pixel(
image,
image_get_pixel(image, ix, iy)
);
}
vidxs = &vidxs[voff];
}
#endif
}
/* dsubimage_alpha_render() : alpha-format image render */
static void dsubimage_alpha_render(image_t const *image, struct imgbox *box)
{
uint16_t *vram;
uint16_t *data;
uint16_t pixel;
uint16_t alpha;
int voff;
int c;
voff = box->surface.voff;
vram = box->surface.vram;
alpha = image_alpha(image->format);
for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) {
data = vram;
c = 0;
for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) {
pixel = image_get_pixel(image, ix, iy);
if (pixel != alpha)
data[c] = image_decode_pixel(image, pixel);
c += 1;
}
vram = &vram[voff];
}
}
//---
// Kernel-level API
//---
void dsubimage_render(
dsurface_t *surface,
int x, int y,
image_t const *image,
int left, int top, int width, int height
) {
uint16_t *vram;
int vxs;
int vys;
/* precalculate culling information */
if (x < 0) {
left -= x;
width += x;
x = 0;
}
if (y < 0) {
top -= y;
height += y;
y = 0;
}
/* check error */
if (top < 0 || left < 0 || width < 0 || height < 0)
return;
/* check culling */
if (y >= surface->y2
|| y + height < surface->y1
|| x >= surface->x2
|| x + width < surface->x1) {
return;
}
/* precalculate geometry information (both image and vram) */
vxs = x - surface->x1;
vys = y - surface->y1;
if (vxs < 0) {
vxs = 0;
left += (surface->x1 - x);
width -= (surface->x1 - x);
}
if (vys < 0) {
vys = 0;
top += (surface->y1 - y);
height -= (surface->y1 + y);
}
if ((size_t)(vxs + width) > surface->width)
width = surface->width - vxs;
if ((size_t)(vys + height) > surface->height)
height = surface->height - vys;
vram = surface->vram;
/* prepare box request */
struct imgbox imgbox = {
.img = {
.y = {
.start = top,
.end = top + height
},
.x = {
.start = left,
.end = left + width
}
},
.surface = {
.vram = &vram[(surface->width * vys) + vxs],
.voff = surface->width
}
};
#if 0
dclear(C_WHITE);
dprint(0, 0, C_BLACK,
"surface.x1 = %d\n"
"surface.x2 = %d\n"
"surface.y1 = %d\n"
"surface.y2 = %d\n"
"surface.width = %d\n"
"surface.height = %d\n"
"\n"
"img.y.start = %d\n"
"img.y.end = %d\n"
"img.x.start = %d\n"
"img.x.end = %d\n"
"\n"
"image.x = %d\n"
"image.y = %d\n"
"image.width = %d\n"
"image.heigt = %d\n",
surface->x1,
surface->x2,
surface->y1,
surface->y2,
surface->width,
surface->height,
imgbox.img.y.start,
imgbox.img.y.end,
imgbox.img.x.start,
imgbox.img.x.end,
x,
y,
width,
height
);
dupdate();
while(1) { __asm__ volatile ("sleep"); }
#endif
/* send drawing request in the approriate optimized function */
if (IMAGE_IS_ALPHA(image->format)) {
dsubimage_alpha_render(image, &imgbox);
return;
}
dsubimage_default_render(image, &imgbox);
}
/* dimage_render(): Render a full image */
void dimage_render(dsurface_t *surface, int x, int y, image_t const *img)
{
dsubimage_render(surface, x, y, img, 0, 0, img->width, img->height);
}
//---
// Dstack API
//---
/* dimage_dstack(): dstack wrapper primitive */
void dimage_dstack(dsurface_t *surface, uint32_t *args)
{
dimage_render(
surface,
(int)args[0],
(int)args[1],
(image_t*)(uintptr_t)args[2]
);
}
/* dsubimage_dstack(): dstack wrapper primitive */
void dsubimage_dstack(dsurface_t *surface, uint32_t *args)
{
dsubimage_render(
surface,
(int)args[0],
(int)args[1],
(image_t*)(uintptr_t)args[2],
(int)args[3],
(int)args[4],
(int)args[5],
(int)args[6]
);
}
//---
// User-level API
//---
/* dimage(): Render a full image */
void dimage(image_t const *image, int x, int y, int mode)
{
if (mode & DIMAGE_CENTER) { x -= image->width >> 1; }
if (mode & DIMAGE_RIGHT) { x -= image->width; }
if (mode & DIMAGE_MIDDLE) { y -= image->height >> 1; }
if (mode & DIMAGE_BOTTOM) { y -= image->height; }
dstack_add_action(
&DSTACK_CALL(&dimage_dstack, x, y, (uintptr_t)image),
NULL,
NULL
);
}
/* dsubimage(): Render a section of an image */
void dsubimage(
int x, int y,
image_t const *image,
int left, int top, int width, int height
) {
dstack_add_action(
&DSTACK_CALL(
&dsubimage_dstack,
x, y,
(uintptr_t)image,
left, top, width, height
),
NULL,
NULL
);
}