#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