summaryrefslogtreecommitdiff
path: root/rcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcache.c')
-rw-r--r--rcache.c467
1 files changed, 467 insertions, 0 deletions
diff --git a/rcache.c b/rcache.c
new file mode 100644
index 0000000..9170f71
--- /dev/null
+++ b/rcache.c
@@ -0,0 +1,467 @@
+#include "error.h"
+#include "memory.h"
+#include "maths.h"
+#include "plat.h"
+#include "rcache.h"
+#include "render.h"
+
+#if rcache_enable
+unsigned* hgrid, * ohgrid, * hgrid1, * hgrid2;
+char* cmd_buf;
+int cmd_count;
+int rcache_cell_w, rcache_cell_h;
+
+void rc_init(void) {
+ int i, e;
+ rcache_cell_w = get_render_w() / rcache_gw;
+ rcache_cell_h = get_render_h() / rcache_gh;
+ cmd_buf = stack_alloc(rcache_cmd_buf_size);
+ e = rcache_gw * rcache_gh * sizeof *hgrid1;
+ hgrid1 = stack_alloc(e);
+ hgrid2 = stack_alloc(e);
+ hgrid = hgrid1;
+ ohgrid = hgrid2;
+ cmd_count = 0;
+ e /= sizeof *hgrid1;
+ for (i = 0; i < e; i++)
+ hgrid1[i] = hgrid2[i] = 0;
+}
+
+RC_Cmd* rc_add_cmd(RC_Cmd* cmd) {
+ int i;
+ RC_Cmd* r;
+ cmd->size = (cmd->size + 7) & -8;
+#ifdef DEBUG
+ if (cmd_count + cmd->size >= rcache_cmd_buf_size) {
+ print_err("Out of render command space.");
+ pbreak(error_out_of_memory);
+ return 0;
+ }
+#endif
+ r = (RC_Cmd*)&cmd_buf[cmd_count];
+ for (i = 0; i < cmd->size; i++) {
+ cmd_buf[cmd_count++] = ((char*)cmd)[i];
+ }
+ return r;
+}
+
+void rc_add_cmd_bmp(
+ const Bitmap* bmp,
+ int x,
+ int y,
+ const Rectangle* src
+) {
+ RC_Cmd_Bmp cmd;
+ cmd.cmd.type = rc_cmd_bmp;
+ cmd.cmd.size = sizeof cmd;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = src->w;
+ cmd.cmd.h = src->h;
+ cmd.sx = src->x;
+ cmd.sy = src->y;
+ cmd.bmp = bmp;
+ rc_add_cmd((RC_Cmd*)&cmd);
+}
+
+void rc_add_cmd_bmp_col(
+ const Bitmap* bmp,
+ int x,
+ int y,
+ const Rectangle* src,
+ Colour col
+) {
+ RC_Cmd_Bmp_Mod cmd;
+ cmd.cmd.type = rc_cmd_bmp_mod;
+ cmd.cmd.size = sizeof cmd;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = src->w;
+ cmd.cmd.h = src->h;
+ cmd.sx = src->x;
+ cmd.sy = src->y;
+ cmd.bmp = bmp;
+ cmd.col = col;
+ rc_add_cmd((RC_Cmd*)&cmd);
+}
+
+void rc_add_cmd_bmp_cp(
+ const Bitmap* bmp,
+ int x,
+ int y,
+ const Rectangle* src
+) {
+ RC_Cmd_Bmp_Cp cmd;
+ cmd.cmd.type = rc_cmd_bmp_cp;
+ cmd.cmd.size = sizeof cmd;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = src->w;
+ cmd.cmd.h = src->h;
+ cmd.sx = src->x;
+ cmd.sy = src->y;
+ cmd.bmp = *bmp;
+ rc_add_cmd((RC_Cmd*)&cmd);
+}
+
+void rc_add_cmd_bmp_cp_col(
+ const Bitmap* bmp,
+ int x,
+ int y,
+ const Rectangle* src,
+ Colour col
+) {
+ RC_Cmd_Bmp_Cp_Mod cmd;
+ cmd.cmd.type = rc_cmd_bmp_cp_mod;
+ cmd.cmd.size = sizeof cmd;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = src->w;
+ cmd.cmd.h = src->h;
+ cmd.sx = src->x;
+ cmd.sy = src->y;
+ cmd.bmp = *bmp;
+ cmd.col = col;
+ rc_add_cmd((RC_Cmd*)&cmd);
+}
+
+void rc_add_cmd_rfont_text(
+ Font* font,
+ int x,
+ int y,
+ const char* text
+) {
+ RC_Cmd_RFont_Text cmd;
+ RC_Cmd_RFont_Text* dc;
+ Rectangle r;
+ const char* c;
+ char* d;
+ r = text_rect(font, text);
+ cmd.cmd.type = rc_cmd_rfont_text;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = r.w;
+ cmd.cmd.h = r.h;
+ cmd.font = font;
+ for (c = text; *c; c++);
+ cmd.cmd.size = sizeof cmd + (c - text) + 1;
+ dc = (void*)rc_add_cmd((RC_Cmd*)&cmd);
+ for (
+ c = text, d = (char*)(dc + 1);
+ *c;
+ c++, d++
+ ) *d = *c;
+ *d = 0;
+}
+
+void rc_add_cmd_rfont_text_col(
+ Font* font,
+ int x,
+ int y,
+ const char* text,
+ Colour col
+) {
+ RC_Cmd_RFont_Text_Col cmd;
+ RC_Cmd_RFont_Text_Col* dc;
+ Rectangle r;
+ const char* c;
+ char* d;
+ r = text_rect(font, text);
+ cmd.cmd.type = rc_cmd_rfont_text_col;
+ cmd.cmd.x = x;
+ cmd.cmd.y = y;
+ cmd.cmd.w = r.w;
+ cmd.cmd.h = r.h;
+ cmd.font = font;
+ cmd.col = col;
+ for (c = text; *c; c++);
+ cmd.cmd.size = sizeof cmd + (c - text) + 1;
+ dc = (void*)rc_add_cmd((RC_Cmd*)&cmd);
+ for (
+ c = text, d = (char*)(dc + 1);
+ *c;
+ c++, d++
+ ) *d = *c;
+ *d = 0;
+}
+
+void rc_add_cmd_clip(
+ const Rectangle* rect
+) {
+ RC_Cmd cmd;
+ cmd.type = rc_cmd_set_clip;
+ cmd.size = sizeof cmd;
+ cmd.x = rect->x;
+ cmd.y = rect->y;
+ cmd.w = rect->w - rect->x;
+ cmd.h = rect->h - rect->y;
+ rc_add_cmd(&cmd);
+}
+
+void rc_add_cmd_reset_clip(void) {
+ RC_Cmd cmd;
+ cmd.type = rc_cmd_set_clip;
+ cmd.size = sizeof cmd;
+ cmd.x = 0;
+ cmd.y = 0;
+ cmd.w = get_render_w();
+ cmd.h = get_render_h();
+ rc_add_cmd(&cmd);
+}
+
+void rc_add_cmd_rect(
+ const Rectangle* r,
+ Colour col
+) {
+ RC_Cmd_Rect cmd;
+ cmd.cmd.type = rc_cmd_rect;
+ cmd.cmd.size = sizeof cmd;
+ cmd.cmd.x = r->x;
+ cmd.cmd.y = r->y;
+ cmd.cmd.w = r->w;
+ cmd.cmd.h = r->h;
+ cmd.col = col;
+ rc_add_cmd((RC_Cmd*)&cmd);
+}
+
+static void hash(unsigned* hash, const void* data, int size) {
+ const unsigned char *p = data;
+ while (size--)
+ *hash = (*hash ^ *p++) * 16777619;
+}
+
+void update_hgrid(unsigned* g) {
+ int x, y, x1, y1, x2, y2, w;
+ unsigned* d;
+ RC_Cmd* cmd, * end;
+ w = rcache_gw;
+ x = rcache_gw * rcache_gh;
+ for (y = 0; y < x; y++)
+ g[y] = rcache_hash_seed;
+ cmd = (RC_Cmd*)cmd_buf;
+ end = (RC_Cmd*)(cmd_buf + cmd_count);
+ for (
+ ;
+ cmd != end;
+ cmd = (RC_Cmd*)((char*)cmd + cmd->size)
+ ) {
+ if (
+ cmd->type == rc_cmd_set_clip ||
+ cmd->type == rc_cmd_reset_clip
+ ) continue;
+ x1 = maxi(0, cmd->x / rcache_cell_w);
+ y1 = maxi(0, cmd->y / rcache_cell_h);
+ if (x1 >= rcache_gw) continue;
+ if (y1 >= rcache_gh) continue;
+ x2 = mini(
+ (cmd->x + cmd->w) / rcache_cell_w,
+ rcache_gw - 1
+ );
+ y2 = mini(
+ (cmd->y + cmd->h) / rcache_cell_h,
+ rcache_gh - 1
+ );
+ if (x2 < 0) continue;
+ if (y2 < 0) continue;
+ for (y = y1; y <= y2; y++)
+ for (x = x1; x <= x2; x++) {
+ d = &g[x + y * w];
+ hash(d, cmd, cmd->size);
+ }
+ }
+}
+
+void rc_flush_rect(int x, int y, int w, int h) {
+ RC_Cmd* cmd, * end;
+ RC_Cmd_Bmp* bmpcmd;
+ RC_Cmd_Bmp_Mod* bmpmcmd;
+ RC_Cmd_Bmp_Cp* bmpcpcmd;
+ RC_Cmd_Bmp_Cp_Mod* bmpmcpcmd;
+ RC_Cmd_RFont_Text* txtrfcmd;
+ RC_Cmd_RFont_Text_Col* txtrfccmd;
+ Rectangle c, r;
+ cmd = (RC_Cmd*)cmd_buf;
+ end = (RC_Cmd*)(cmd_buf + cmd_count);
+ int n, rw, rh;
+ rw = get_render_w();
+ rh = get_render_h();
+ if (x > rw) return;
+ if (y > rh) return;
+ x = maxi(x, 0);
+ y = maxi(y, 0);
+ if ((n = x + w - rw) > 0)
+ w -= n;
+ if ((n = y + h - rh) > 0)
+ h -= n;
+ if (w <= 0) return;
+ if (h <= 0) return;
+ c.x = x;
+ c.y = y;
+ c.w = x + w;
+ c.h = y + h;
+ render_clip(&c);
+ render_clear();
+ while (cmd != end) {
+ switch (cmd->type) {
+ case rc_cmd_bmp:
+ bmpcmd = (RC_Cmd_Bmp*)cmd;
+ r.x = bmpcmd->sx;
+ r.y = bmpcmd->sy;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ render_bitmap(
+ bmpcmd->bmp,
+ cmd->x,
+ cmd->y,
+ &r
+ );
+ break;
+ case rc_cmd_bmp_mod:
+ bmpmcmd = (RC_Cmd_Bmp_Mod*)cmd;
+ r.x = bmpmcmd->sx;
+ r.y = bmpmcmd->sy;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ render_bitmap_col(
+ bmpmcmd->bmp,
+ cmd->x,
+ cmd->y,
+ &r,
+ bmpmcmd->col
+ );
+ break;
+ case rc_cmd_bmp_cp:
+ bmpcpcmd = (RC_Cmd_Bmp_Cp*)cmd;
+ r.x = bmpcpcmd->sx;
+ r.y = bmpcpcmd->sy;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ render_bitmap(
+ &bmpcpcmd->bmp,
+ cmd->x,
+ cmd->y,
+ &r
+ );
+ break;
+ case rc_cmd_bmp_cp_mod:
+ bmpmcpcmd = (RC_Cmd_Bmp_Cp_Mod*)cmd;
+ r.x = bmpmcpcmd->sx;
+ r.y = bmpmcpcmd->sy;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ render_bitmap_col(
+ &bmpmcpcmd->bmp,
+ cmd->x,
+ cmd->y,
+ &r,
+ bmpmcpcmd->col
+ );
+ break;
+ case rc_cmd_rfont_text:
+ txtrfcmd = (RC_Cmd_RFont_Text*)cmd;
+ rfont_text(
+ txtrfcmd->font,
+ cmd->x,
+ cmd->y,
+ (char*)(txtrfcmd + 1)
+ );
+ break;
+ case rc_cmd_rfont_text_col:
+ txtrfccmd = (RC_Cmd_RFont_Text_Col*)cmd;
+ rfont_text_col(
+ txtrfccmd->font,
+ cmd->x,
+ cmd->y,
+ (char*)(txtrfccmd + 1),
+ txtrfccmd->col
+ );
+ break;
+ case rc_cmd_set_clip:
+ r.x = cmd->x;
+ r.y = cmd->y;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ r = rect_intersect(&c, &r);
+ r.w += r.x;
+ r.h += r.y;
+ render_clip(&r);
+ break;
+ case rc_cmd_reset_clip:
+ render_clip(&c);
+ break;
+ case rc_cmd_rect:
+ r.x = cmd->x;
+ r.y = cmd->y;
+ r.w = cmd->w;
+ r.h = cmd->h;
+ render_rect(
+ &r,
+ ((RC_Cmd_Rect*)cmd)->col
+ );
+ break;
+ }
+ cmd = (RC_Cmd*)((char*)cmd + cmd->size);
+ }
+ plat_present(x, y, w, h);
+ render_reset_clip();
+}
+
+void rc_flush(void) {
+ int x, y, w, h, i;
+ w = rcache_gw;
+ h = rcache_gh;
+ update_hgrid(hgrid);
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++) {
+ i = x + y * w;
+ if (hgrid[i] != ohgrid[i])
+ rc_flush_rect(
+ x * rcache_cell_w,
+ y * rcache_cell_h,
+ rcache_cell_w,
+ rcache_cell_h
+ );
+ }
+ cmd_count = 0;
+ x = rcache_gw * rcache_gh;
+ for (y = 0; y < x; y++)
+ ohgrid[y] = hgrid[y];
+ ohgrid = hgrid;
+ hgrid = hgrid == hgrid1? hgrid2: hgrid1;
+}
+
+void rc_begin(void) {
+ rcache_cell_w = (get_render_w() / rcache_gw) + 1;
+ rcache_cell_h = (get_render_h() / rcache_gh) + 1;
+}
+
+void rc_invalidate(const Rectangle* r) {
+ int x, y, x1, y1, x2, y2, w;
+ x1 = maxi(0, r->x / rcache_cell_w);
+ y1 = maxi(0, r->y / rcache_cell_h);
+ x2 = mini(
+ (r->x + r->w) / rcache_cell_w,
+ rcache_gw - 1
+ );
+ y2 = mini(
+ (r->y + r->h) / rcache_cell_h,
+ rcache_gh - 1
+ );
+ w = rcache_gw;
+ for (y = y1; y <= y2; y++)
+ for (x = x1; x <= x2; x++) {
+ ohgrid[x + y * w] = -1;
+ }
+}
+#else
+
+void rc_init(void) {
+ render_init();
+}
+
+void rc_flush(void) {
+ plat_present(0, 0, get_render_w(), get_render_h());
+ render_begin();
+}
+
+#endif