Compare commits
5 Commits
amiga2.1
...
rencache-t
Author | SHA1 | Date |
---|---|---|
Francesco Abbate | 1b39a4cb37 | |
Francesco Abbate | 4e9208f768 | |
Francesco Abbate | 23c6b182f6 | |
Francesco Abbate | ed3acbc29b | |
Francesco Abbate | 2b6867b4bc |
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#define API_TYPE_FONT "Font"
|
#define API_TYPE_FONT "Font"
|
||||||
#define API_TYPE_REPLACE "Replace"
|
#define API_TYPE_REPLACE "Replace"
|
||||||
|
#define API_TYPE_RENCACHE "RenCache"
|
||||||
|
|
||||||
void api_load_libs(lua_State *L);
|
void api_load_libs(lua_State *L);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "rencache.h"
|
#include "rencache.h"
|
||||||
|
|
||||||
|
extern RenCache *window_rencache;
|
||||||
|
|
||||||
static RenColor checkcolor(lua_State *L, int idx, int def) {
|
static RenColor checkcolor(lua_State *L, int idx, int def) {
|
||||||
RenColor color;
|
RenColor color;
|
||||||
|
@ -21,16 +22,27 @@ static RenColor checkcolor(lua_State *L, int idx, int def) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static RenCache *opt_rencache_arg(lua_State *L, int *index) {
|
||||||
|
RenCache *rencache;
|
||||||
|
if (lua_touserdata(L, 1)) {
|
||||||
|
return luaL_checkudata(L, *(index++), API_TYPE_RENCACHE);
|
||||||
|
}
|
||||||
|
return window_rencache;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_show_debug(lua_State *L) {
|
static int f_show_debug(lua_State *L) {
|
||||||
luaL_checkany(L, 1);
|
int index = 1;
|
||||||
rencache_show_debug(lua_toboolean(L, 1));
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
|
luaL_checkany(L, index);
|
||||||
|
rencache_show_debug(rencache, lua_toboolean(L, index));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_get_size(lua_State *L) {
|
static int f_get_size(lua_State *L) {
|
||||||
int w, h;
|
int w, h;
|
||||||
ren_get_size(&w, &h);
|
ren_get_size(window_ren_surface, &w, &h);
|
||||||
lua_pushnumber(L, w);
|
lua_pushnumber(L, w);
|
||||||
lua_pushnumber(L, h);
|
lua_pushnumber(L, h);
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -38,59 +50,69 @@ static int f_get_size(lua_State *L) {
|
||||||
|
|
||||||
|
|
||||||
static int f_begin_frame(lua_State *L) {
|
static int f_begin_frame(lua_State *L) {
|
||||||
rencache_begin_frame(L);
|
int index = 1;
|
||||||
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
|
rencache_begin_frame(rencache, window_ren_surface, L);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_end_frame(lua_State *L) {
|
static int f_end_frame(lua_State *L) {
|
||||||
rencache_end_frame(L);
|
int index = 1;
|
||||||
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
|
rencache_end_frame(rencache, L);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_set_clip_rect(lua_State *L) {
|
static int f_set_clip_rect(lua_State *L) {
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
rect.x = luaL_checknumber(L, 1);
|
int index = 1;
|
||||||
rect.y = luaL_checknumber(L, 2);
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
rect.width = luaL_checknumber(L, 3);
|
rect.x = luaL_checknumber(L, index);
|
||||||
rect.height = luaL_checknumber(L, 4);
|
rect.y = luaL_checknumber(L, index + 1);
|
||||||
rencache_set_clip_rect(rect);
|
rect.width = luaL_checknumber(L, index + 2);
|
||||||
|
rect.height = luaL_checknumber(L, index + 3);
|
||||||
|
rencache_set_clip_rect(rencache, rect);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_draw_rect(lua_State *L) {
|
static int f_draw_rect(lua_State *L) {
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
rect.x = luaL_checknumber(L, 1);
|
int index = 1;
|
||||||
rect.y = luaL_checknumber(L, 2);
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
rect.width = luaL_checknumber(L, 3);
|
rect.x = luaL_checknumber(L, index);
|
||||||
rect.height = luaL_checknumber(L, 4);
|
rect.y = luaL_checknumber(L, index + 1);
|
||||||
RenColor color = checkcolor(L, 5, 255);
|
rect.width = luaL_checknumber(L, index + 2);
|
||||||
rencache_draw_rect(rect, color);
|
rect.height = luaL_checknumber(L, index + 3);
|
||||||
|
RenColor color = checkcolor(L, index + 4, 255);
|
||||||
|
rencache_draw_rect(rencache, rect, color);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) {
|
static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) {
|
||||||
FontDesc *font_desc = luaL_checkudata(L, 1, API_TYPE_FONT);
|
int index = 1;
|
||||||
const char *text = luaL_checkstring(L, 2);
|
RenCache *rencache = opt_rencache_arg(L, &index);
|
||||||
|
FontDesc *font_desc = luaL_checkudata(L, index, API_TYPE_FONT);
|
||||||
|
const char *text = luaL_checkstring(L, index + 1);
|
||||||
/* The coordinate below will be in subpixel iff draw_subpixel is true.
|
/* The coordinate below will be in subpixel iff draw_subpixel is true.
|
||||||
Otherwise it will be in pixels. */
|
Otherwise it will be in pixels. */
|
||||||
int x_subpixel = luaL_checknumber(L, 3);
|
int x_subpixel = luaL_checknumber(L, index + 2);
|
||||||
int y = luaL_checknumber(L, 4);
|
int y = luaL_checknumber(L, index + 3);
|
||||||
RenColor color = checkcolor(L, 5, 255);
|
RenColor color = checkcolor(L, index + 4, 255);
|
||||||
|
|
||||||
CPReplaceTable *rep_table;
|
CPReplaceTable *rep_table;
|
||||||
RenColor replace_color;
|
RenColor replace_color;
|
||||||
if (lua_gettop(L) >= 7) {
|
if (lua_gettop(L) >= index + 6) {
|
||||||
rep_table = luaL_checkudata(L, 6, API_TYPE_REPLACE);
|
rep_table = luaL_checkudata(L, index + 5, API_TYPE_REPLACE);
|
||||||
replace_color = checkcolor(L, 7, 255);
|
replace_color = checkcolor(L, index + 6, 255);
|
||||||
} else {
|
} else {
|
||||||
rep_table = NULL;
|
rep_table = NULL;
|
||||||
replace_color = (RenColor) {0};
|
replace_color = (RenColor) {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
x_subpixel = rencache_draw_text(L, font_desc, 1, text, x_subpixel, y, color, draw_subpixel, rep_table, replace_color);
|
x_subpixel = rencache_draw_text(rencache, L, font_desc, 1, text, x_subpixel, y, color, draw_subpixel, rep_table, replace_color);
|
||||||
lua_pushnumber(L, x_subpixel);
|
lua_pushnumber(L, x_subpixel);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +145,14 @@ int luaopen_renderer_replacements(lua_State *L);
|
||||||
|
|
||||||
int luaopen_renderer(lua_State *L) {
|
int luaopen_renderer(lua_State *L) {
|
||||||
luaL_newlib(L, lib);
|
luaL_newlib(L, lib);
|
||||||
|
|
||||||
|
window_rencache = lua_newuserdata(L, sizeof(RenCache));
|
||||||
|
rencache_init(window_rencache);
|
||||||
|
luaL_setmetatable(L, API_TYPE_RENCACHE);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
luaL_ref(L, -1);
|
||||||
|
lua_setfield(L, -2, "window");
|
||||||
|
|
||||||
luaopen_renderer_font(L);
|
luaopen_renderer_font(L);
|
||||||
lua_setfield(L, -2, "font");
|
lua_setfield(L, -2, "font");
|
||||||
luaopen_renderer_replacements(L);
|
luaopen_renderer_replacements(L);
|
||||||
|
|
|
@ -74,7 +74,7 @@ static int f_get_width(lua_State *L) {
|
||||||
const char *text = luaL_checkstring(L, 2);
|
const char *text = luaL_checkstring(L, 2);
|
||||||
/* By calling ren_get_font_width with NULL as third arguments
|
/* By calling ren_get_font_width with NULL as third arguments
|
||||||
we will obtain the width in points. */
|
we will obtain the width in points. */
|
||||||
int w = ren_get_font_width(self, text, NULL);
|
int w = ren_get_font_width(window_ren_surface, self, text, NULL);
|
||||||
lua_pushnumber(L, w);
|
lua_pushnumber(L, w);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ static int f_get_width(lua_State *L) {
|
||||||
|
|
||||||
static int f_subpixel_scale(lua_State *L) {
|
static int f_subpixel_scale(lua_State *L) {
|
||||||
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
||||||
lua_pushnumber(L, ren_get_font_subpixel_scale(self));
|
lua_pushnumber(L, ren_get_font_subpixel_scale(window_ren_surface, self));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,14 +92,14 @@ static int f_get_width_subpixel(lua_State *L) {
|
||||||
int subpixel_scale;
|
int subpixel_scale;
|
||||||
/* We need to pass a non-null subpixel_scale pointer to force
|
/* We need to pass a non-null subpixel_scale pointer to force
|
||||||
subpixel width calculation. */
|
subpixel width calculation. */
|
||||||
lua_pushnumber(L, ren_get_font_width(self, text, &subpixel_scale));
|
lua_pushnumber(L, ren_get_font_width(window_ren_surface, self, text, &subpixel_scale));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_get_height(lua_State *L) {
|
static int f_get_height(lua_State *L) {
|
||||||
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
||||||
lua_pushnumber(L, ren_get_font_height(self) );
|
lua_pushnumber(L, ren_get_font_height(window_ren_surface, self) );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern SDL_Window *window;
|
extern SDL_Window *window;
|
||||||
|
extern RenCache *window_rencache;
|
||||||
|
|
||||||
static const char* button_name(int button) {
|
static const char* button_name(int button) {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
|
@ -116,7 +116,7 @@ top:
|
||||||
lua_pushnumber(L, e.window.data2);
|
lua_pushnumber(L, e.window.data2);
|
||||||
return 3;
|
return 3;
|
||||||
} else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) {
|
} else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) {
|
||||||
rencache_invalidate();
|
rencache_invalidate(&rencache);
|
||||||
lua_pushstring(L, "exposed");
|
lua_pushstring(L, "exposed");
|
||||||
return 1;
|
return 1;
|
||||||
} else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
|
} else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
|
RenCache *window_rencache;
|
||||||
|
|
||||||
static double get_scale(void) {
|
static double get_scale(void) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
166
src/rencache.c
166
src/rencache.c
|
@ -5,18 +5,10 @@
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
#include "rencache.h"
|
#include "rencache.h"
|
||||||
|
|
||||||
/* a cache over the software renderer -- all drawing operations are stored as
|
|
||||||
** commands when issued. At the end of the frame we write the commands to a grid
|
|
||||||
** of hash values, take the cells that have changed since the previous frame,
|
|
||||||
** merge them into dirty rectangles and redraw only those regions */
|
|
||||||
|
|
||||||
#define CELLS_X 80
|
|
||||||
#define CELLS_Y 50
|
|
||||||
#define CELL_SIZE 96
|
#define CELL_SIZE 96
|
||||||
#define COMMAND_BUF_SIZE (1024 * 512)
|
|
||||||
#define COMMAND_BARE_SIZE offsetof(Command, text)
|
#define COMMAND_BARE_SIZE offsetof(Command, text)
|
||||||
|
|
||||||
enum { SET_CLIP, DRAW_TEXT, DRAW_RECT, DRAW_TEXT_SUBPIXEL };
|
enum { SET_CLIP, DRAW_TEXT, DRAW_RECT, DRAW_TEXT_SUBPIXEL, DRAW_IMAGE };
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int8_t type;
|
int8_t type;
|
||||||
|
@ -29,6 +21,7 @@ typedef struct {
|
||||||
FontDesc *font_desc;
|
FontDesc *font_desc;
|
||||||
CPReplaceTable *replacements;
|
CPReplaceTable *replacements;
|
||||||
RenColor replace_color;
|
RenColor replace_color;
|
||||||
|
uint32_t image_id; /* FIXME: do not add a new field but use unions or alias another field. */
|
||||||
char text[0];
|
char text[0];
|
||||||
} Command;
|
} Command;
|
||||||
|
|
||||||
|
@ -41,18 +34,6 @@ typedef struct FontRef FontRef;
|
||||||
FontRef font_refs[FONT_REFS_MAX];
|
FontRef font_refs[FONT_REFS_MAX];
|
||||||
int font_refs_len = 0;
|
int font_refs_len = 0;
|
||||||
|
|
||||||
|
|
||||||
static unsigned cells_buf1[CELLS_X * CELLS_Y];
|
|
||||||
static unsigned cells_buf2[CELLS_X * CELLS_Y];
|
|
||||||
static unsigned *cells_prev = cells_buf1;
|
|
||||||
static unsigned *cells = cells_buf2;
|
|
||||||
static RenRect rect_buf[CELLS_X * CELLS_Y / 2];
|
|
||||||
static char command_buf[COMMAND_BUF_SIZE];
|
|
||||||
static int command_buf_idx;
|
|
||||||
static RenRect screen_rect;
|
|
||||||
static bool show_debug;
|
|
||||||
|
|
||||||
|
|
||||||
static inline int min(int a, int b) { return a < b ? a : b; }
|
static inline int min(int a, int b) { return a < b ? a : b; }
|
||||||
static inline int max(int a, int b) { return a > b ? a : b; }
|
static inline int max(int a, int b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
@ -123,14 +104,14 @@ static RenRect merge_rects(RenRect a, RenRect b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Command* push_command(int type, int size) {
|
static Command* push_command(RenCache *rc, int type, int size) {
|
||||||
Command *cmd = (Command*) (command_buf + command_buf_idx);
|
Command *cmd = (Command*) (rc->command_buf + rc->command_buf_idx);
|
||||||
int n = command_buf_idx + size;
|
int n = rc->command_buf_idx + size;
|
||||||
if (n > COMMAND_BUF_SIZE) {
|
if (n > COMMAND_BUF_SIZE) {
|
||||||
fprintf(stderr, "Warning: (" __FILE__ "): exhausted command buffer\n");
|
fprintf(stderr, "Warning: (" __FILE__ "): exhausted command buffer\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
command_buf_idx = n;
|
rc->command_buf_idx = n;
|
||||||
memset(cmd, 0, COMMAND_BARE_SIZE);
|
memset(cmd, 0, COMMAND_BARE_SIZE);
|
||||||
cmd->type = type;
|
cmd->type = type;
|
||||||
cmd->size = size;
|
cmd->size = size;
|
||||||
|
@ -138,51 +119,70 @@ static Command* push_command(int type, int size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool next_command(Command **prev) {
|
static bool next_command(RenCache *rc, Command **prev) {
|
||||||
if (*prev == NULL) {
|
if (*prev == NULL) {
|
||||||
*prev = (Command*) command_buf;
|
*prev = (Command*) rc->command_buf;
|
||||||
} else {
|
} else {
|
||||||
*prev = (Command*) (((char*) *prev) + (*prev)->size);
|
*prev = (Command*) (((char*) *prev) + (*prev)->size);
|
||||||
}
|
}
|
||||||
return *prev != ((Command*) (command_buf + command_buf_idx));
|
return *prev != ((Command*) (rc->command_buf + rc->command_buf_idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rencache_init(RenCache *rc) {
|
||||||
|
rc->cells_prev = rc->cells_buf1;
|
||||||
|
rc->cells = rc->cells_buf2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_show_debug(bool enable) {
|
void rencache_show_debug(RenCache *rc, bool enable) {
|
||||||
show_debug = enable;
|
rc->show_debug = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_set_clip_rect(RenRect rect) {
|
void rencache_set_clip_rect(RenCache *rc, RenRect rect) {
|
||||||
Command *cmd = push_command(SET_CLIP, COMMAND_BARE_SIZE);
|
Command *cmd = push_command(rc, SET_CLIP, COMMAND_BARE_SIZE);
|
||||||
if (cmd) { cmd->rect = intersect_rects(rect, screen_rect); }
|
if (cmd) { cmd->rect = intersect_rects(rect, rc->screen_rect); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color) {
|
void rencache_draw_rect(RenCache *rc, RenRect rect, RenColor color) {
|
||||||
if (!rects_overlap(screen_rect, rect)) { return; }
|
if (!rects_overlap(rc->screen_rect, rect)) { return; }
|
||||||
Command *cmd = push_command(DRAW_RECT, COMMAND_BARE_SIZE);
|
Command *cmd = push_command(rc, DRAW_RECT, COMMAND_BARE_SIZE);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
cmd->rect = rect;
|
cmd->rect = rect;
|
||||||
cmd->color = color;
|
cmd->color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rencache_draw_text(lua_State *L, FontDesc *font_desc, int font_index,
|
|
||||||
|
void rencache_draw_image(RenCache *rc, int image_id, int x, int y, RenRect image_rect) {
|
||||||
|
RenRect rect = {x, y, image_rect.width, image_rect.height};
|
||||||
|
if (!rects_overlap(rc->screen_rect, rect)) { return; }
|
||||||
|
Command *cmd = push_command(rc, DRAW_IMAGE, COMMAND_BARE_SIZE + 2 * sizeof(int));
|
||||||
|
int *img_coord = (int *) cmd->text;
|
||||||
|
if (cmd) {
|
||||||
|
cmd->rect = rect;
|
||||||
|
cmd->image_id = image_id;
|
||||||
|
img_coord[0] = image_rect.x;
|
||||||
|
img_coord[1] = image_rect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rencache_draw_text(RenCache *rc, lua_State *L, FontDesc *font_desc, int font_index,
|
||||||
const char *text, int x, int y, RenColor color, bool draw_subpixel,
|
const char *text, int x, int y, RenColor color, bool draw_subpixel,
|
||||||
CPReplaceTable *replacements, RenColor replace_color)
|
CPReplaceTable *replacements, RenColor replace_color)
|
||||||
{
|
{
|
||||||
int subpixel_scale;
|
int subpixel_scale;
|
||||||
int w_subpixel = ren_get_font_width(font_desc, text, &subpixel_scale);
|
int w_subpixel = ren_get_font_width(rc->ren_surface, font_desc, text, &subpixel_scale);
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
rect.x = (draw_subpixel ? ren_font_subpixel_round(x, subpixel_scale, -1) : x);
|
rect.x = (draw_subpixel ? ren_font_subpixel_round(x, subpixel_scale, -1) : x);
|
||||||
rect.y = y;
|
rect.y = y;
|
||||||
rect.width = ren_font_subpixel_round(w_subpixel, subpixel_scale, 0);
|
rect.width = ren_font_subpixel_round(w_subpixel, subpixel_scale, 0);
|
||||||
rect.height = ren_get_font_height(font_desc);
|
rect.height = ren_get_font_height(rc->ren_surface, font_desc);
|
||||||
|
|
||||||
if (rects_overlap(screen_rect, rect) && font_refs_add(L, font_desc, font_index) >= 0) {
|
if (rects_overlap(rc->screen_rect, rect) && font_refs_add(L, font_desc, font_index) >= 0) {
|
||||||
int sz = strlen(text) + 1;
|
int sz = strlen(text) + 1;
|
||||||
Command *cmd = push_command(draw_subpixel ? DRAW_TEXT_SUBPIXEL : DRAW_TEXT, COMMAND_BARE_SIZE + sz);
|
Command *cmd = push_command(rc, draw_subpixel ? DRAW_TEXT_SUBPIXEL : DRAW_TEXT, COMMAND_BARE_SIZE + sz);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
memcpy(cmd->text, text, sz);
|
memcpy(cmd->text, text, sz);
|
||||||
cmd->color = color;
|
cmd->color = color;
|
||||||
|
@ -200,25 +200,26 @@ int rencache_draw_text(lua_State *L, FontDesc *font_desc, int font_index,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_invalidate(void) {
|
void rencache_invalidate(RenCache *rc) {
|
||||||
memset(cells_prev, 0xff, sizeof(cells_buf1));
|
memset(rc->cells_prev, 0xff, sizeof(rc->cells_buf1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_begin_frame(lua_State *L) {
|
void rencache_begin_frame(RenCache *rc, RenSurface *ren, lua_State *L) {
|
||||||
/* reset all cells if the screen width/height has changed */
|
/* reset all cells if the screen width/height has changed */
|
||||||
int w, h;
|
int w, h;
|
||||||
ren_get_size(&w, &h);
|
ren_get_size(ren, &w, &h);
|
||||||
if (screen_rect.width != w || h != screen_rect.height) {
|
if (rc->screen_rect.width != w || h != rc->screen_rect.height) {
|
||||||
screen_rect.width = w;
|
rc->screen_rect.width = w;
|
||||||
screen_rect.height = h;
|
rc->screen_rect.height = h;
|
||||||
rencache_invalidate();
|
rencache_invalidate(rc);
|
||||||
}
|
}
|
||||||
|
rc->ren_surface = ren;
|
||||||
font_refs_clear(L);
|
font_refs_clear(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void update_overlapping_cells(RenRect r, unsigned h) {
|
static void update_overlapping_cells(RenCache *rc, RenRect r, unsigned h) {
|
||||||
int x1 = r.x / CELL_SIZE;
|
int x1 = r.x / CELL_SIZE;
|
||||||
int y1 = r.y / CELL_SIZE;
|
int y1 = r.y / CELL_SIZE;
|
||||||
int x2 = (r.x + r.width) / CELL_SIZE;
|
int x2 = (r.x + r.width) / CELL_SIZE;
|
||||||
|
@ -227,108 +228,115 @@ static void update_overlapping_cells(RenRect r, unsigned h) {
|
||||||
for (int y = y1; y <= y2; y++) {
|
for (int y = y1; y <= y2; y++) {
|
||||||
for (int x = x1; x <= x2; x++) {
|
for (int x = x1; x <= x2; x++) {
|
||||||
int idx = cell_idx(x, y);
|
int idx = cell_idx(x, y);
|
||||||
hash(&cells[idx], &h, sizeof(h));
|
hash(&rc->cells[idx], &h, sizeof(h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void push_rect(RenRect r, int *count) {
|
static void push_rect(RenCache *rc, RenRect r, int *count) {
|
||||||
/* try to merge with existing rectangle */
|
/* try to merge with existing rectangle */
|
||||||
for (int i = *count - 1; i >= 0; i--) {
|
for (int i = *count - 1; i >= 0; i--) {
|
||||||
RenRect *rp = &rect_buf[i];
|
RenRect *rp = &rc->rect_buf[i];
|
||||||
if (rects_overlap(*rp, r)) {
|
if (rects_overlap(*rp, r)) {
|
||||||
*rp = merge_rects(*rp, r);
|
*rp = merge_rects(*rp, r);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* couldn't merge with previous rectangle: push */
|
/* couldn't merge with previous rectangle: push */
|
||||||
rect_buf[(*count)++] = r;
|
rc->rect_buf[(*count)++] = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void rencache_end_frame(lua_State *L) {
|
void rencache_end_frame(RenCache *rc, lua_State *L) {
|
||||||
/* update cells from commands */
|
/* update cells from commands */
|
||||||
Command *cmd = NULL;
|
Command *cmd = NULL;
|
||||||
RenRect cr = screen_rect;
|
RenRect cr = rc->screen_rect;
|
||||||
while (next_command(&cmd)) {
|
while (next_command(rc, &cmd)) {
|
||||||
if (cmd->type == SET_CLIP) { cr = cmd->rect; }
|
if (cmd->type == SET_CLIP) { cr = cmd->rect; }
|
||||||
RenRect r = intersect_rects(cmd->rect, cr);
|
RenRect r = intersect_rects(cmd->rect, cr);
|
||||||
if (r.width == 0 || r.height == 0) { continue; }
|
if (r.width == 0 || r.height == 0) { continue; }
|
||||||
unsigned h = HASH_INITIAL;
|
unsigned h = HASH_INITIAL;
|
||||||
hash(&h, cmd, cmd->size);
|
hash(&h, cmd, cmd->size);
|
||||||
update_overlapping_cells(r, h);
|
update_overlapping_cells(rc, r, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push rects for all cells changed from last frame, reset cells */
|
/* push rects for all cells changed from last frame, reset cells */
|
||||||
int rect_count = 0;
|
int rect_count = 0;
|
||||||
int max_x = screen_rect.width / CELL_SIZE + 1;
|
int max_x = rc->screen_rect.width / CELL_SIZE + 1;
|
||||||
int max_y = screen_rect.height / CELL_SIZE + 1;
|
int max_y = rc->screen_rect.height / CELL_SIZE + 1;
|
||||||
for (int y = 0; y < max_y; y++) {
|
for (int y = 0; y < max_y; y++) {
|
||||||
for (int x = 0; x < max_x; x++) {
|
for (int x = 0; x < max_x; x++) {
|
||||||
/* compare previous and current cell for change */
|
/* compare previous and current cell for change */
|
||||||
int idx = cell_idx(x, y);
|
int idx = cell_idx(x, y);
|
||||||
if (cells[idx] != cells_prev[idx]) {
|
if (rc->cells[idx] != rc->cells_prev[idx]) {
|
||||||
push_rect((RenRect) { x, y, 1, 1 }, &rect_count);
|
push_rect(rc, (RenRect) { x, y, 1, 1 }, &rect_count);
|
||||||
}
|
}
|
||||||
cells_prev[idx] = HASH_INITIAL;
|
rc->cells_prev[idx] = HASH_INITIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* expand rects from cells to pixels */
|
/* expand rects from cells to pixels */
|
||||||
for (int i = 0; i < rect_count; i++) {
|
for (int i = 0; i < rect_count; i++) {
|
||||||
RenRect *r = &rect_buf[i];
|
RenRect *r = &rc->rect_buf[i];
|
||||||
r->x *= CELL_SIZE;
|
r->x *= CELL_SIZE;
|
||||||
r->y *= CELL_SIZE;
|
r->y *= CELL_SIZE;
|
||||||
r->width *= CELL_SIZE;
|
r->width *= CELL_SIZE;
|
||||||
r->height *= CELL_SIZE;
|
r->height *= CELL_SIZE;
|
||||||
*r = intersect_rects(*r, screen_rect);
|
*r = intersect_rects(*r, rc->screen_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* redraw updated regions */
|
/* redraw updated regions */
|
||||||
for (int i = 0; i < rect_count; i++) {
|
for (int i = 0; i < rect_count; i++) {
|
||||||
|
const int *image_coord;
|
||||||
/* draw */
|
/* draw */
|
||||||
RenRect r = rect_buf[i];
|
RenRect r = rc->rect_buf[i];
|
||||||
ren_set_clip_rect(r);
|
ren_set_clip_rect(rc->ren_surface, r);
|
||||||
|
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
while (next_command(&cmd)) {
|
while (next_command(rc, &cmd)) {
|
||||||
switch (cmd->type) {
|
switch (cmd->type) {
|
||||||
case SET_CLIP:
|
case SET_CLIP:
|
||||||
ren_set_clip_rect(intersect_rects(cmd->rect, r));
|
ren_set_clip_rect(rc->ren_surface, intersect_rects(cmd->rect, r));
|
||||||
break;
|
break;
|
||||||
case DRAW_RECT:
|
case DRAW_RECT:
|
||||||
ren_draw_rect(cmd->rect, cmd->color);
|
ren_draw_rect(rc->ren_surface, cmd->rect, cmd->color);
|
||||||
break;
|
break;
|
||||||
case DRAW_TEXT:
|
case DRAW_TEXT:
|
||||||
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
||||||
ren_draw_text(cmd->font_desc, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color,
|
ren_draw_text(rc->ren_surface, cmd->font_desc, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color,
|
||||||
cmd->replacements, cmd->replace_color);
|
cmd->replacements, cmd->replace_color);
|
||||||
break;
|
break;
|
||||||
case DRAW_TEXT_SUBPIXEL:
|
case DRAW_TEXT_SUBPIXEL:
|
||||||
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
||||||
ren_draw_text_subpixel(cmd->font_desc, cmd->text,
|
ren_draw_text_subpixel(rc->ren_surface, cmd->font_desc, cmd->text,
|
||||||
cmd->subpixel_scale * cmd->rect.x + cmd->x_subpixel_offset, cmd->rect.y, cmd->color,
|
cmd->subpixel_scale * cmd->rect.x + cmd->x_subpixel_offset, cmd->rect.y, cmd->color,
|
||||||
cmd->replacements, cmd->replace_color);
|
cmd->replacements, cmd->replace_color);
|
||||||
break;
|
break;
|
||||||
|
case DRAW_IMAGE:
|
||||||
|
image_coord = (const int *) cmd->text;
|
||||||
|
ren_draw_image(rc->ren_surface, cmd->image_id, image_coord[0], image_coord[1], cmd->rect);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show_debug) {
|
if (rc->show_debug) {
|
||||||
RenColor color = { rand(), rand(), rand(), 50 };
|
RenColor color = { rand(), rand(), rand(), 50 };
|
||||||
ren_draw_rect(r, color);
|
ren_draw_rect(rc->ren_surface, r, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update dirty rects */
|
/* update dirty rects */
|
||||||
if (rect_count > 0) {
|
if (rect_count > 0) {
|
||||||
ren_update_rects(rect_buf, rect_count);
|
ren_update_rects(rc->ren_surface, rc->rect_buf, rect_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* swap cell buffer and reset */
|
/* swap cell buffer and reset */
|
||||||
unsigned *tmp = cells;
|
unsigned *tmp = rc->cells;
|
||||||
cells = cells_prev;
|
rc->cells = rc->cells_prev;
|
||||||
cells_prev = tmp;
|
rc->cells_prev = tmp;
|
||||||
command_buf_idx = 0;
|
rc->command_buf_idx = 0;
|
||||||
|
|
||||||
|
rc->ren_surface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,37 @@
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
void rencache_show_debug(bool enable);
|
/* a cache over the software renderer -- all drawing operations are stored as
|
||||||
void rencache_set_clip_rect(RenRect rect);
|
** commands when issued. At the end of the frame we write the commands to a grid
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color);
|
** of hash values, take the cells that have changed since the previous frame,
|
||||||
int rencache_draw_text(lua_State *L, FontDesc *font_desc, int font_index, const char *text, int x, int y, RenColor color,
|
** merge them into dirty rectangles and redraw only those regions */
|
||||||
|
|
||||||
|
#define CELLS_X 80
|
||||||
|
#define CELLS_Y 50
|
||||||
|
#define COMMAND_BUF_SIZE (1024 * 512)
|
||||||
|
|
||||||
|
struct RenCache {
|
||||||
|
unsigned cells_buf1[CELLS_X * CELLS_Y];
|
||||||
|
unsigned cells_buf2[CELLS_X * CELLS_Y];
|
||||||
|
unsigned *cells_prev;
|
||||||
|
unsigned *cells;
|
||||||
|
RenRect rect_buf[CELLS_X * CELLS_Y / 2];
|
||||||
|
char command_buf[COMMAND_BUF_SIZE];
|
||||||
|
int command_buf_idx;
|
||||||
|
RenRect screen_rect;
|
||||||
|
bool show_debug;
|
||||||
|
RenSurface *ren_surface;
|
||||||
|
};
|
||||||
|
typedef struct RenCache RenCache;
|
||||||
|
|
||||||
|
void rencache_init(RenCache *rc);
|
||||||
|
void rencache_show_debug(RenCache *rc, bool enable);
|
||||||
|
void rencache_set_clip_rect(RenCache *rc, RenRect rect);
|
||||||
|
void rencache_draw_rect(RenCache *rc, RenRect rect, RenColor color);
|
||||||
|
int rencache_draw_text(RenCache *rc, lua_State *L, FontDesc *font_desc, int font_index, const char *text, int x, int y, RenColor color,
|
||||||
bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color);
|
bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color);
|
||||||
void rencache_invalidate(void);
|
void rencache_invalidate(RenCache *rc);
|
||||||
void rencache_begin_frame(lua_State *L);
|
void rencache_begin_frame(RenCache *rc, RenSurface *ren, lua_State *L);
|
||||||
void rencache_end_frame(lua_State *L);
|
void rencache_end_frame(RenCache *rc, lua_State *L);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
125
src/renderer.c
125
src/renderer.c
|
@ -33,6 +33,7 @@ struct RenFont {
|
||||||
};
|
};
|
||||||
|
|
||||||
static RenWindow window_renderer = {0};
|
static RenWindow window_renderer = {0};
|
||||||
|
RenSurface window_ren_surface[1] = {{SurfaceWindow, &window_renderer}};
|
||||||
|
|
||||||
static void* check_alloc(void *ptr) {
|
static void* check_alloc(void *ptr) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
|
@ -59,6 +60,26 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
|
||||||
return p + 1;
|
return p + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ren_surface_scale(RenSurface *ren) {
|
||||||
|
if (ren->type == SurfaceTexture) {
|
||||||
|
return ((RenTexture *) ren->data)->surface_scale;
|
||||||
|
}
|
||||||
|
return renwin_surface_scale((RenWindow *) ren->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_Surface *ren_surface_get_surface(RenSurface *ren) {
|
||||||
|
if (ren->type == SurfaceTexture) {
|
||||||
|
return ((RenTexture *) ren->data)->surface;
|
||||||
|
}
|
||||||
|
return renwin_get_surface((RenWindow *) ren->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RenRect ren_surface_clip(RenSurface *ren) {
|
||||||
|
if (ren->type == SurfaceTexture) {
|
||||||
|
return ((RenTexture *) ren->data)->clip;
|
||||||
|
}
|
||||||
|
return ((RenWindow *) ren->data)->clip;
|
||||||
|
}
|
||||||
|
|
||||||
void ren_cp_replace_init(CPReplaceTable *rep_table) {
|
void ren_cp_replace_init(CPReplaceTable *rep_table) {
|
||||||
rep_table->size = 0;
|
rep_table->size = 0;
|
||||||
|
@ -97,35 +118,66 @@ void ren_free_window_resources() {
|
||||||
void ren_init(SDL_Window *win) {
|
void ren_init(SDL_Window *win) {
|
||||||
assert(win);
|
assert(win);
|
||||||
window_renderer.window = win;
|
window_renderer.window = win;
|
||||||
|
window_renderer.initial_frame = true;
|
||||||
renwin_init_surface(&window_renderer);
|
renwin_init_surface(&window_renderer);
|
||||||
renwin_clip_to_surface(&window_renderer);
|
renwin_clip_to_surface(&window_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_resize_window() {
|
void ren_resize_window() {
|
||||||
renwin_resize_surface(&window_renderer);
|
renwin_resize_surface(&window_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: all this stuff. */
|
||||||
|
#define IMAGE_CELL_SIZE 96
|
||||||
|
#define IMAGE_CELL_X 80
|
||||||
|
|
||||||
void ren_update_rects(RenRect *rects, int count) {
|
static inline int image_cell_idx(int x, int y) {
|
||||||
static bool initial_frame = true;
|
return x + y * IMAGE_CELLS_X;
|
||||||
if (initial_frame) {
|
}
|
||||||
renwin_show_window(&window_renderer);
|
|
||||||
initial_frame = false;
|
void ren_update_rects(RenSurface *ren, RenRect *rects, int count) {
|
||||||
|
if (ren->type == SurfaceTexture) {
|
||||||
|
RenTexture *rentex = (RenTexture *) ren->data;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
RenRect irect = image_rect_to_index(rects[i]);
|
||||||
|
/* Increment the revision number for all cells that needs to be updated,
|
||||||
|
i.e. those that overlaps with one of the update rectangles. */
|
||||||
|
for (int x = irect.x; x <= irect.x + irect.width; x++) {
|
||||||
|
for (int y = irect.y; y <= irect.y + irect.height; y++) {
|
||||||
|
int idx = image_cell_idx(x, y);
|
||||||
|
rentex->revisions[idx] += 1:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RenWindow *renwin = (RenWindow *) ren->data;
|
||||||
|
if (renwin->initial_frame) {
|
||||||
|
renwin_show_window(renwin);
|
||||||
|
renwin->initial_frame = false;
|
||||||
|
}
|
||||||
|
renwin_update_rects(renwin, rects, count);
|
||||||
}
|
}
|
||||||
renwin_update_rects(&window_renderer, rects, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_set_clip_rect(RenRect rect) {
|
// FIXME: duplicated from renwindow.c
|
||||||
renwin_set_clip_rect(&window_renderer, rect);
|
static RenRect scaled_rect(const RenRect rect, const int scale) {
|
||||||
|
return (RenRect) {rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ren_set_clip_rect(RenSurface *ren, RenRect rect) {
|
||||||
|
if (ren->type == SurfaceTexture) {
|
||||||
|
RenTexture *rentex = (RenTexture *) ren->data;
|
||||||
|
rentex->clip = scaled_rect(rect, rentex->surface_scale);
|
||||||
|
} else {
|
||||||
|
renwin_set_clip_rect((RenWindow *) ren->data, rect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_get_size(int *x, int *y) {
|
void ren_get_size(RenSurface *ren, int *x, int *y) {
|
||||||
RenWindow *ren = &window_renderer;
|
const int scale = ren_surface_scale(ren);
|
||||||
const int scale = renwin_surface_scale(ren);
|
SDL_Surface *surface = ren_surface_get_surface(ren);
|
||||||
SDL_Surface *surface = renwin_get_surface(ren);
|
|
||||||
*x = surface->w / scale;
|
*x = surface->w / scale;
|
||||||
*y = surface->h / scale;
|
*y = surface->h / scale;
|
||||||
}
|
}
|
||||||
|
@ -237,11 +289,11 @@ int ren_get_font_tab_size(RenFont *font) {
|
||||||
|
|
||||||
/* Important: if subpixel_scale is NULL we will return width in points. Otherwise we will
|
/* Important: if subpixel_scale is NULL we will return width in points. Otherwise we will
|
||||||
return width in subpixels. */
|
return width in subpixels. */
|
||||||
int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale) {
|
int ren_get_font_width(RenSurface *ren, FontDesc *font_desc, const char *text, int *subpixel_scale) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
while (*p) {
|
while (*p) {
|
||||||
p = utf8_to_codepoint(p, &codepoint);
|
p = utf8_to_codepoint(p, &codepoint);
|
||||||
|
@ -259,8 +311,8 @@ int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ren_get_font_height(FontDesc *font_desc) {
|
int ren_get_font_height(RenSurface *ren, FontDesc *font_desc) {
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
return (font->height + surface_scale / 2) / surface_scale;
|
return (font->height + surface_scale / 2) / surface_scale;
|
||||||
}
|
}
|
||||||
|
@ -284,10 +336,10 @@ static inline RenColor blend_pixel(RenColor dst, RenColor src) {
|
||||||
d += dr; \
|
d += dr; \
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_draw_rect(RenRect rect, RenColor color) {
|
void ren_draw_rect(RenSurface *ren, RenRect rect, RenColor color) {
|
||||||
if (color.a == 0) { return; }
|
if (color.a == 0) { return; }
|
||||||
|
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
|
|
||||||
/* transforms coordinates in pixels. */
|
/* transforms coordinates in pixels. */
|
||||||
rect.x *= surface_scale;
|
rect.x *= surface_scale;
|
||||||
|
@ -295,7 +347,7 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
rect.width *= surface_scale;
|
rect.width *= surface_scale;
|
||||||
rect.height *= surface_scale;
|
rect.height *= surface_scale;
|
||||||
|
|
||||||
const RenRect clip = window_renderer.clip;
|
const RenRect clip = ren_surface_clip(ren);
|
||||||
int x1 = rect.x < clip.x ? clip.x : rect.x;
|
int x1 = rect.x < clip.x ? clip.x : rect.x;
|
||||||
int y1 = rect.y < clip.y ? clip.y : rect.y;
|
int y1 = rect.y < clip.y ? clip.y : rect.y;
|
||||||
int x2 = rect.x + rect.width;
|
int x2 = rect.x + rect.width;
|
||||||
|
@ -303,7 +355,7 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
x2 = x2 > clip.x + clip.width ? clip.x + clip.width : x2;
|
x2 = x2 > clip.x + clip.width ? clip.x + clip.width : x2;
|
||||||
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
|
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
|
||||||
|
|
||||||
SDL_Surface *surface = renwin_get_surface(&window_renderer);
|
SDL_Surface *surface = ren_surface_get_surface(ren);
|
||||||
RenColor *d = (RenColor*) surface->pixels;
|
RenColor *d = (RenColor*) surface->pixels;
|
||||||
d += x1 + y1 * surface->w;
|
d += x1 + y1 * surface->w;
|
||||||
int dr = surface->w - (x2 - x1);
|
int dr = surface->w - (x2 - x1);
|
||||||
|
@ -333,11 +385,11 @@ static FR_Clip_Area clip_area_from_rect(const RenRect r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void draw_text_impl(RenFont *font, const char *text, int x_subpixel, int y_pixel, RenColor color,
|
static void draw_text_impl(RenSurface *ren, RenFont *font, const char *text, int x_subpixel, int y_pixel, RenColor color,
|
||||||
CPReplaceTable *replacements, RenColor replace_color)
|
CPReplaceTable *replacements, RenColor replace_color)
|
||||||
{
|
{
|
||||||
SDL_Surface *surf = renwin_get_surface(&window_renderer);
|
SDL_Surface *surf = ren_surface_get_surface(ren);
|
||||||
FR_Clip_Area clip = clip_area_from_rect(window_renderer.clip);
|
FR_Clip_Area clip = clip_area_from_rect(ren_surface_clip(ren));
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
||||||
|
@ -364,21 +416,21 @@ static void draw_text_impl(RenFont *font, const char *text, int x_subpixel, int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_draw_text_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color,
|
void ren_draw_text_subpixel(RenSurface *ren, FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color,
|
||||||
CPReplaceTable *replacements, RenColor replace_color)
|
CPReplaceTable *replacements, RenColor replace_color)
|
||||||
{
|
{
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
draw_text_impl(font, text, x_subpixel, surface_scale * y, color, replacements, replace_color);
|
draw_text_impl(ren, font, text, x_subpixel, surface_scale * y, color, replacements, replace_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color,
|
void ren_draw_text(RenSurface *ren, FontDesc *font_desc, const char *text, int x, int y, RenColor color,
|
||||||
CPReplaceTable *replacements, RenColor replace_color)
|
CPReplaceTable *replacements, RenColor replace_color)
|
||||||
{
|
{
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
const int subpixel_scale = surface_scale * FR_Subpixel_Scale(font->renderer);
|
const int subpixel_scale = surface_scale * FR_Subpixel_Scale(font->renderer);
|
||||||
draw_text_impl(font, text, subpixel_scale * x, surface_scale * y, color, replacements, replace_color);
|
draw_text_impl(ren, font, text, subpixel_scale * x, surface_scale * y, color, replacements, replace_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Could be declared as static inline
|
// Could be declared as static inline
|
||||||
|
@ -395,8 +447,17 @@ int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ren_get_font_subpixel_scale(FontDesc *font_desc) {
|
int ren_get_font_subpixel_scale(RenSurface *ren, FontDesc *font_desc) {
|
||||||
const int surface_scale = renwin_surface_scale(&window_renderer);
|
const int surface_scale = ren_surface_scale(ren);
|
||||||
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
return FR_Subpixel_Scale(font->renderer) * surface_scale;
|
return FR_Subpixel_Scale(font->renderer) * surface_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ren_draw_image(RenSurface *ren, uint32_t image_id, int image_x, int image_y, RenRect rect) {
|
||||||
|
SDL_Rect image_rect;
|
||||||
|
SDL_Surface *image_surf = image_get(image_id, &image_rect, image_x, image_y);
|
||||||
|
SDL_Surface *surface = ren_surface_get_surface(ren);
|
||||||
|
SDL_Rect dst_rect = {rect.x, rect.y, 0, 0};
|
||||||
|
SDL_BlitSurface(image_surf,image_rect, surface, &dst_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,23 @@ enum {
|
||||||
typedef struct { uint8_t b, g, r, a; } RenColor;
|
typedef struct { uint8_t b, g, r, a; } RenColor;
|
||||||
typedef struct { int x, y, width, height; } RenRect;
|
typedef struct { int x, y, width, height; } RenRect;
|
||||||
|
|
||||||
|
// FIXME: ensure this Max is okay or use dynamic allocation.
|
||||||
|
#define TEXTURE_REVS_MAX 256
|
||||||
|
struct RenTexture {
|
||||||
|
SDL_Surface *surface;
|
||||||
|
int surface_scale;
|
||||||
|
RenRect clip; /* Clipping rect in pixel coordinates. */
|
||||||
|
int revisions[TEXTURE_REVS_MAX];
|
||||||
|
};
|
||||||
|
typedef struct RenTexture RenTexture;
|
||||||
|
|
||||||
|
enum { SurfaceTexture, SurfaceWindow };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int type; /* Type of surface, RenSurfaceTexture or RenSurfaceWindow. */
|
||||||
|
void *data; /* Can be a RenTexture or RenWindow pointer based on type. */
|
||||||
|
} RenSurface;
|
||||||
|
|
||||||
struct CPReplace {
|
struct CPReplace {
|
||||||
unsigned codepoint_src;
|
unsigned codepoint_src;
|
||||||
unsigned codepoint_dst;
|
unsigned codepoint_dst;
|
||||||
|
@ -34,14 +51,14 @@ struct CPReplaceTable {
|
||||||
};
|
};
|
||||||
typedef struct CPReplaceTable CPReplaceTable;
|
typedef struct CPReplaceTable CPReplaceTable;
|
||||||
|
|
||||||
|
|
||||||
void ren_init(SDL_Window *win);
|
void ren_init(SDL_Window *win);
|
||||||
void ren_resize_window();
|
void ren_resize_window();
|
||||||
void ren_update_rects(RenRect *rects, int count);
|
|
||||||
void ren_set_clip_rect(RenRect rect);
|
|
||||||
void ren_get_size(int *x, int *y); /* Reports the size in points. */
|
|
||||||
void ren_free_window_resources();
|
void ren_free_window_resources();
|
||||||
|
|
||||||
|
void ren_update_rects(RenSurface *ren, RenRect *rects, int count);
|
||||||
|
void ren_set_clip_rect(RenSurface *ren, RenRect rect);
|
||||||
|
void ren_get_size(RenSurface *ren, int *x, int *y); /* Reports the size in points. */
|
||||||
|
|
||||||
RenImage* ren_new_image(int width, int height);
|
RenImage* ren_new_image(int width, int height);
|
||||||
void ren_free_image(RenImage *image);
|
void ren_free_image(RenImage *image);
|
||||||
|
|
||||||
|
@ -51,18 +68,21 @@ void ren_free_font(RenFont *font);
|
||||||
void ren_set_font_tab_size(RenFont *font, int n);
|
void ren_set_font_tab_size(RenFont *font, int n);
|
||||||
int ren_get_font_tab_size(RenFont *font);
|
int ren_get_font_tab_size(RenFont *font);
|
||||||
|
|
||||||
int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale);
|
int ren_get_font_width(RenSurface *ren, FontDesc *font_desc, const char *text, int *subpixel_scale);
|
||||||
int ren_get_font_height(FontDesc *font_desc);
|
int ren_get_font_height(RenSurface *ren, FontDesc *font_desc);
|
||||||
int ren_get_font_subpixel_scale(FontDesc *font_desc);
|
int ren_get_font_subpixel_scale(RenSurface *ren, FontDesc *font_desc);
|
||||||
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation);
|
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation);
|
||||||
|
|
||||||
void ren_draw_rect(RenRect rect, RenColor color);
|
void ren_draw_rect(RenSurface *ren, RenRect rect, RenColor color);
|
||||||
void ren_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
|
void ren_draw_text(RenSurface *ren, FontDesc *font_desc, const char *text, int x, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
|
||||||
void ren_draw_text_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
|
void ren_draw_text_subpixel(RenSurface *ren, FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
|
||||||
|
void ren_draw_image(RenSurface *ren, uint32_t image_id, int image_x, int image_y, RenRect rect);
|
||||||
|
|
||||||
void ren_cp_replace_init(CPReplaceTable *rep_table);
|
void ren_cp_replace_init(CPReplaceTable *rep_table);
|
||||||
void ren_cp_replace_free(CPReplaceTable *rep_table);
|
void ren_cp_replace_free(CPReplaceTable *rep_table);
|
||||||
void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *dst);
|
void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *dst);
|
||||||
void ren_cp_replace_clear(CPReplaceTable *rep_table);
|
void ren_cp_replace_clear(CPReplaceTable *rep_table);
|
||||||
|
|
||||||
|
extern RenSurface window_ren_surface[1];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
struct RenWindow {
|
struct RenWindow {
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
RenRect clip; /* Clipping rect in pixel coordinates. */
|
RenRect clip; /* Clipping rect in pixel coordinates. */
|
||||||
|
bool initial_frame;
|
||||||
#ifdef LITE_USE_SDL_RENDERER
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
|
|
Loading…
Reference in New Issue