From 46c3bdea677b096fd4cf2f834c54f7ad1e9b4db2 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 24 Apr 2021 10:21:34 +0200 Subject: [PATCH] First implementation of scaling for retina display Introduce a new approach that discriminate coordinates in points and pixels. Now all the logic from the Lua side and in rencache is to always use points. The coordinates are converted to pixels only within the renderer, in the file renderer.c. In this way the application logic does not need to care about the scaling of the retina displays. For non-retina display the scaling between points and pixels is equal to one so nothing will change. There is nevertheless a change that leak into the Lua side. The subpixel coordinates are in sub-pixel, not sub-points so they are scaled by the retina scaling factor. But no change in the code is required because the subpixel scaling factor take into account the retina scaling, when present. Because the retina scaling factor is not know when the application starts but only when a window is actually available we introduce a mechanism to render the font with a given scaling factor only from the renderer when they are needed. We use therefore FontDesc to describe the font information but without actually rasterizing the font at a given scale. --- src/api/renderer.c | 8 +- src/api/renderer_font.c | 55 +++++++----- src/api/system.c | 7 +- src/fontdesc.c | 53 +++++++++++ src/fontdesc.h | 33 +++++++ src/meson.build | 1 + src/rencache.c | 26 +++--- src/rencache.h | 5 +- src/renderer.c | 192 ++++++++++++++++++++++++---------------- src/renderer.h | 18 ++-- 10 files changed, 272 insertions(+), 126 deletions(-) create mode 100644 src/fontdesc.c create mode 100644 src/fontdesc.h diff --git a/src/api/renderer.c b/src/api/renderer.c index 6e4ebf40..c6883a95 100644 --- a/src/api/renderer.c +++ b/src/api/renderer.c @@ -72,9 +72,9 @@ static int f_draw_rect(lua_State *L) { } static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) { - RenFont **font = luaL_checkudata(L, 1, API_TYPE_FONT); + FontDesc *font_desc = luaL_checkudata(L, 1, API_TYPE_FONT); const char *text = luaL_checkstring(L, 2); - /* The coordinate below will be in subpixels iff draw_subpixel is true. + /* The coordinate below will be in subpixel iff draw_subpixel is true. Otherwise it will be in pixels. */ int x_subpixel = luaL_checknumber(L, 3); int y = luaL_checknumber(L, 4); @@ -90,7 +90,7 @@ static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) { replace_color = (RenColor) {0}; } - x_subpixel = rencache_draw_text(*font, text, x_subpixel, y, color, draw_subpixel, rep_table, replace_color); + x_subpixel = rencache_draw_text(font_desc, text, x_subpixel, y, color, draw_subpixel, rep_table, replace_color); lua_pushnumber(L, x_subpixel); return 1; } @@ -114,7 +114,7 @@ static const luaL_Reg lib[] = { { "draw_rect", f_draw_rect }, { "draw_text", f_draw_text }, { "draw_text_subpixel", f_draw_text_subpixel }, - { NULL, NULL } + { NULL, NULL } }; diff --git a/src/api/renderer_font.c b/src/api/renderer_font.c index dd5069bc..5cc8b400 100644 --- a/src/api/renderer_font.c +++ b/src/api/renderer_font.c @@ -1,8 +1,8 @@ #include "api.h" +#include "fontdesc.h" #include "renderer.h" #include "rencache.h" - static int f_load(lua_State *L) { const char *filename = luaL_checkstring(L, 1); float size = luaL_checknumber(L, 2); @@ -40,57 +40,72 @@ static int f_load(lua_State *L) { } lua_pop(L, 1); } - RenFont **self = lua_newuserdata(L, sizeof(*self)); + + if (ren_verify_font(filename)) { + luaL_error(L, "failed to load font"); + } + + FontDesc *font_desc = lua_newuserdata(L, sizeof(FontDesc)); + // FIXME: implement font_desc initialization in fontdesc.c + int filename_sz = strlen(filename) + 1; + font_desc->filename = malloc(filename_sz); + memcpy(font_desc->filename, filename, filename_sz); + font_desc->size = size; + font_desc->options = font_options; + font_desc->tab_size = 4; + font_desc->fonts_scale_length = 0; + font_desc->recent_font_scale_index = 0; /* No need to initialize. */ + luaL_setmetatable(L, API_TYPE_FONT); - *self = ren_load_font(filename, size, font_options); - if (!*self) { luaL_error(L, "failed to load font"); } return 1; } static int f_set_tab_size(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); int n = luaL_checknumber(L, 2); - ren_set_font_tab_size(*self, n); + font_desc_set_tab_size(self, n); return 0; } static int f_gc(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); - if (*self) { rencache_free_font(*self); } + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); + rencache_free_font(self); return 0; } - static int f_get_width(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); const char *text = luaL_checkstring(L, 2); - int subpixel_scale; - int w = ren_get_font_width(*self, text, &subpixel_scale); - lua_pushnumber(L, ren_font_subpixel_round(w, subpixel_scale, 0)); + /* By calling ren_get_font_width with NULL as third arguments + we will obtain the width in points. */ + int w = ren_get_font_width(self, text, NULL); + lua_pushnumber(L, w); return 1; } static int f_subpixel_scale(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); - lua_pushnumber(L, ren_get_font_subpixel_scale(*self)); + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); + lua_pushnumber(L, ren_get_font_subpixel_scale(self)); return 1; } - static int f_get_width_subpixel(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); const char *text = luaL_checkstring(L, 2); - lua_pushnumber(L, ren_get_font_width(*self, text, NULL)); + int subpixel_scale; + /* We need to pass a non-null subpixel_scale pointer to force + subpixel width calculation. */ + lua_pushnumber(L, ren_get_font_width(self, text, &subpixel_scale)); return 1; } static int f_get_height(lua_State *L) { - RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); - lua_pushnumber(L, ren_get_font_height(*self) ); + FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT); + lua_pushnumber(L, ren_get_font_height(self) ); return 1; } diff --git a/src/api/system.c b/src/api/system.c index 826ad5c1..8fd00056 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -109,10 +109,9 @@ top: case SDL_WINDOWEVENT: if (e.window.event == SDL_WINDOWEVENT_RESIZED) { - ren_resize(); + ren_setup_renderer(); lua_pushstring(L, "resized"); - /* The size below can be wrong on Retina display by a multiplicative factor - but the size reported below is not currently used. */ + /* The size below will be in points. */ lua_pushnumber(L, e.window.data1); lua_pushnumber(L, e.window.data2); return 3; @@ -319,7 +318,7 @@ static int f_set_window_size(lua_State *L) { double y = luaL_checknumber(L, 4); SDL_SetWindowSize(window, w, h); SDL_SetWindowPosition(window, x, y); - ren_resize(); + ren_setup_renderer(); return 0; } diff --git a/src/fontdesc.c b/src/fontdesc.c new file mode 100644 index 00000000..8414a73d --- /dev/null +++ b/src/fontdesc.c @@ -0,0 +1,53 @@ +#include "fontdesc.h" +#include "renderer.h" + +void font_desc_set_tab_size(FontDesc *font_desc, int tab_size) { + font_desc->tab_size = tab_size; + for (int i = 0; i < font_desc->fonts_scale_length; i++) { + ren_set_font_tab_size(font_desc->fonts_scale[i].font, tab_size); + } +} + +int font_desc_get_tab_size(FontDesc *font_desc) { + return font_desc->tab_size; +} + +void font_desc_free(FontDesc *font_desc) { + for (int i = 0; i < font_desc->fonts_scale_length; i++) { + ren_free_font(font_desc->fonts_scale[i].font); + } + font_desc->fonts_scale_length = 0; + free(font_desc->filename); +} + +static void load_scaled_font(FontDesc *font_desc, int index, int scale) { + RenFont *font = ren_load_font(font_desc->filename, scale * font_desc->size, font_desc->options); + font_desc->fonts_scale[index].font = font; + font_desc->fonts_scale[index].scale = scale; +} + +RenFont *font_desc_get_font_at_scale(FontDesc *font_desc, int scale) { + int index = -1; + for (int i = 0; i < font_desc->fonts_scale_length; i++) { + if (font_desc->fonts_scale[i].scale == scale) { + index = i; + break; + } + } + if (index < 0) { + index = font_desc->fonts_scale_length; + if (index < FONT_SCALE_ARRAY_MAX) { + load_scaled_font(font_desc, index, scale); + font_desc->fonts_scale_length = index + 1; + } else { + // FIXME: should not print into the stderr or stdout. + fprintf(stderr, "Warning: max array of font scale reached.\n"); + index = (font_desc->recent_font_scale_index == 0 ? 1 : 0); + ren_free_font(font_desc->fonts_scale[index].font); + load_scaled_font(font_desc, index, scale); + } + } + font_desc->recent_font_scale_index = index; + return font_desc->fonts_scale[index].font; +} + diff --git a/src/fontdesc.h b/src/fontdesc.h new file mode 100644 index 00000000..d0326ca4 --- /dev/null +++ b/src/fontdesc.h @@ -0,0 +1,33 @@ +#ifndef FONT_DESC_H +#define FONT_DESC_H + +typedef struct RenFont RenFont; + +// FIXME: find a better name for the struct below +struct FontScaled { + RenFont *font; + short int scale; +}; +typedef struct FontScaled FontScaled; + +#define FONT_SCALE_ARRAY_MAX 2 + +struct FontDesc { + char *filename; + float size; + unsigned int options; + short int tab_size; +// FIXME: find a better name for the array below + FontScaled fonts_scale[FONT_SCALE_ARRAY_MAX]; + short int fonts_scale_length; + short int recent_font_scale_index; /* More recently scale used. */ +}; +typedef struct FontDesc FontDesc; + +int font_desc_get_tab_size(FontDesc *font_desc); +void font_desc_set_tab_size(FontDesc *font_desc, int tab_size); +void font_desc_free(FontDesc *font_desc); +RenFont *font_desc_get_font_at_scale(FontDesc *font_desc, int scale); + +#endif + diff --git a/src/meson.build b/src/meson.build index 2800d3d4..ed287bb8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,6 +5,7 @@ lite_sources = [ 'api/renderer_font.c', 'api/system.c', 'renderer.c', + 'fontdesc.c', 'rencache.c', 'main.c', ] diff --git a/src/rencache.c b/src/rencache.c index 3d607094..36734b24 100644 --- a/src/rencache.c +++ b/src/rencache.c @@ -24,7 +24,7 @@ typedef struct { int32_t size; RenRect rect; RenColor color; - RenFont *font; + FontDesc *font_desc; CPReplaceTable *replacements; RenColor replace_color; char text[0]; @@ -115,9 +115,9 @@ void rencache_show_debug(bool enable) { } -void rencache_free_font(RenFont *font) { +void rencache_free_font(FontDesc *font_desc) { Command *cmd = push_command(FREE_FONT, COMMAND_BARE_SIZE); - if (cmd) { cmd->font = font; } + if (cmd) { cmd->font_desc = font_desc; } } @@ -136,17 +136,17 @@ void rencache_draw_rect(RenRect rect, RenColor color) { } } -int rencache_draw_text(RenFont *font, +int rencache_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color, bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color) { int subpixel_scale; - int w_subpixel = ren_get_font_width(font, text, &subpixel_scale); + int w_subpixel = ren_get_font_width(font_desc, text, &subpixel_scale); RenRect rect; rect.x = (draw_subpixel ? ren_font_subpixel_round(x, subpixel_scale, -1) : x); rect.y = y; rect.width = ren_font_subpixel_round(w_subpixel, subpixel_scale, 0); - rect.height = ren_get_font_height(font); + rect.height = ren_get_font_height(font_desc); if (rects_overlap(screen_rect, rect)) { int sz = strlen(text) + 1; @@ -154,11 +154,11 @@ int rencache_draw_text(RenFont *font, if (cmd) { memcpy(cmd->text, text, sz); cmd->color = color; - cmd->font = font; + cmd->font_desc = font_desc; cmd->rect = rect; cmd->subpixel_scale = (draw_subpixel ? subpixel_scale : 1); cmd->x_subpixel_offset = x - subpixel_scale * rect.x; - cmd->tab_size = ren_get_font_tab_size(font); + cmd->tab_size = font_desc_get_tab_size(font_desc); cmd->replacements = replacements; cmd->replace_color = replace_color; } @@ -272,13 +272,13 @@ void rencache_end_frame(void) { ren_draw_rect(cmd->rect, cmd->color); break; case DRAW_TEXT: - ren_set_font_tab_size(cmd->font, cmd->tab_size); - ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color, + 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, cmd->replacements, cmd->replace_color); break; case DRAW_TEXT_SUBPIXEL: - ren_set_font_tab_size(cmd->font, cmd->tab_size); - ren_draw_text_subpixel(cmd->font, cmd->text, + font_desc_set_tab_size(cmd->font_desc, cmd->tab_size); + ren_draw_text_subpixel(cmd->font_desc, cmd->text, cmd->subpixel_scale * cmd->rect.x + cmd->x_subpixel_offset, cmd->rect.y, cmd->color, cmd->replacements, cmd->replace_color); break; @@ -301,7 +301,7 @@ void rencache_end_frame(void) { cmd = NULL; while (next_command(&cmd)) { if (cmd->type == FREE_FONT) { - ren_free_font(cmd->font); + font_desc_free(cmd->font_desc); } } } diff --git a/src/rencache.h b/src/rencache.h index a532c9b5..b5c241ab 100644 --- a/src/rencache.h +++ b/src/rencache.h @@ -5,10 +5,11 @@ #include "renderer.h" void rencache_show_debug(bool enable); -void rencache_free_font(RenFont *font); +void rencache_free_font(FontDesc *font_desc); void rencache_set_clip_rect(RenRect rect); void rencache_draw_rect(RenRect rect, RenColor color); -int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color, bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color); +int rencache_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color, + bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color); void rencache_invalidate(void); void rencache_begin_frame(void); void rencache_end_frame(void); diff --git a/src/renderer.c b/src/renderer.c index b48bf3d2..e4e9dcbf 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -32,13 +32,16 @@ struct RenFont { }; -static SDL_Window *window; -static SDL_Renderer *window_renderer = NULL; -static SDL_Texture *window_texture = NULL; -static SDL_Surface *window_surface = NULL; -static int window_w = -1, window_h = -1; +struct Renderer { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + SDL_Surface *surface; + FR_Clip_Area clip; /* Clipping rect in pixel coordinates. */ + int surface_scale; +}; -static FR_Clip_Area clip; +static struct Renderer renderer = {0}; static void* check_alloc(void *ptr) { if (!ptr) { @@ -66,18 +69,30 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) { } -static void init_window_surface() { - if (window_surface) { - SDL_FreeSurface(window_surface); - } - SDL_GL_GetDrawableSize(window, &window_w, &window_h); - window_surface = SDL_CreateRGBSurfaceWithFormat(0, window_w, window_h, 32, SDL_PIXELFORMAT_BGRA32); - ren_set_clip_rect( (RenRect) { 0, 0, window_w, window_h } ); +static int get_surface_scale() { + int w_pixels, h_pixels; + int w_points, h_points; + SDL_GL_GetDrawableSize(renderer.window, &w_pixels, &h_pixels); + SDL_GetWindowSize(renderer.window, &w_points, &h_points); + // FIXME: this assert is too harsh. + assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points); + return w_pixels / w_points; } -static SDL_Surface *get_window_surface() { - return window_surface; +static FR_Clip_Area scaled_clip(const RenRect rect, const int scale) { + return (FR_Clip_Area) {rect.x * scale, rect.y * scale, (rect.x + rect.width) * scale, (rect.y + rect.height) * scale}; +} + + +static void init_window_surface() { + if (renderer.surface) { + SDL_FreeSurface(renderer.surface); + } + int w, h; + SDL_GL_GetDrawableSize(renderer.window, &w, &h); + renderer.surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_BGRA32); + renderer.clip = scaled_clip((RenRect) { 0, 0, w, h }, 1); } @@ -112,37 +127,39 @@ void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char * } void ren_free_window_resources() { - SDL_DestroyWindow(window); - SDL_DestroyRenderer(window_renderer); - SDL_DestroyTexture(window_texture); - window = NULL; - window_renderer = NULL; + SDL_DestroyWindow(renderer.window); + SDL_DestroyRenderer(renderer.renderer); + SDL_DestroyTexture(renderer.texture); + renderer.window = NULL; + renderer.renderer = NULL; } static void setup_renderer(int w, int h) { /* Note that w and h here should always be in pixels and obtained from a call to SDL_GL_GetDrawableSize(). */ - if (window_renderer) { - SDL_DestroyRenderer(window_renderer); - SDL_DestroyTexture(window_texture); + if (renderer.renderer) { + SDL_DestroyRenderer(renderer.renderer); + SDL_DestroyTexture(renderer.texture); } - window_renderer = SDL_CreateRenderer(window, -1, 0); + renderer.renderer = SDL_CreateRenderer(renderer.window, -1, 0); // May be we could use: SDL_CreateTextureFromSurface(sdlRenderer, mySurface); - window_texture = SDL_CreateTexture(window_renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h); + renderer.texture = SDL_CreateTexture(renderer.renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h); + renderer.surface_scale = get_surface_scale(); } void ren_init(SDL_Window *win) { assert(win); - window = win; + renderer.window = win; init_window_surface(); + renderer.surface_scale = get_surface_scale(); } -void ren_resize() { +void ren_setup_renderer() { int new_w, new_h; - SDL_GL_GetDrawableSize(window, &new_w, &new_h); + SDL_GL_GetDrawableSize(renderer.window, &new_w, &new_h); /* Note that (w, h) may differ from (new_w, new_h) on retina displays. */ - if (new_w != window_h || new_h != window_h) { + if (new_w != renderer.surface->w || new_h != renderer.surface->h) { init_window_surface(); setup_renderer(new_w, new_h); } @@ -153,31 +170,28 @@ void ren_update_rects(RenRect *rects, int count) { static bool initial_frame = true; if (initial_frame) { int w, h; - SDL_ShowWindow(window); - SDL_GL_GetDrawableSize(window, &w, &h); + SDL_ShowWindow(renderer.window); + SDL_GL_GetDrawableSize(renderer.window, &w, &h); setup_renderer(w, h); initial_frame = false; } // FIXME: we ignore the rects here. - SDL_UpdateTexture(window_texture, NULL, window_surface->pixels, window_w * 4); - SDL_RenderCopy(window_renderer, window_texture, NULL, NULL); - SDL_RenderPresent(window_renderer); + SDL_UpdateTexture(renderer.texture, NULL, renderer.surface->pixels, renderer.surface->w * 4); + SDL_RenderCopy(renderer.renderer, renderer.texture, NULL, NULL); + SDL_RenderPresent(renderer.renderer); } void ren_set_clip_rect(RenRect rect) { - clip.left = rect.x; - clip.top = rect.y; - clip.right = rect.x + rect.width; - clip.bottom = rect.y + rect.height; + renderer.clip = scaled_clip(rect, renderer.surface_scale); } void ren_get_size(int *x, int *y) { - SDL_Surface *surf = get_window_surface(); - *x = surf->w; - *y = surf->h; + const int scale = renderer.surface_scale; + *x = renderer.surface->w / scale; + *y = renderer.surface->h / scale; } @@ -214,6 +228,17 @@ static GlyphSet* get_glyphset(RenFont *font, int codepoint) { } +int ren_verify_font(const char *filename) { + RenFont font[1]; + font->renderer = FR_Renderer_New(0); + if (FR_Load_Font(font->renderer, filename)) { + return 1; + } + FR_Renderer_Free(font->renderer); + return 0; +} + + RenFont* ren_load_font(const char *filename, float size, unsigned int renderer_flags) { RenFont *font = NULL; @@ -274,25 +299,34 @@ int ren_get_font_tab_size(RenFont *font) { } -int ren_get_font_width(RenFont *font, const char *text, int *subpixel_scale) { +/* Important: if subpixel_scale is NULL we will return width in points. Otherwise we will + return width in subpixels. */ +int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale) { int x = 0; const char *p = text; unsigned codepoint; + const int surface_scale = renderer.surface_scale; + RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale); while (*p) { p = utf8_to_codepoint(p, &codepoint); GlyphSet *set = get_glyphset(font, codepoint); FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff]; x += g->xadvance; } + /* At this point here x is in subpixel units */ + const int x_scale_to_points = FR_Subpixel_Scale(font->renderer) * surface_scale; if (subpixel_scale) { - *subpixel_scale = FR_Subpixel_Scale(font->renderer); + *subpixel_scale = x_scale_to_points; + return x; } - return x; + return (x + x_scale_to_points / 2) / x_scale_to_points; } -int ren_get_font_height(RenFont *font) { - return font->height; +int ren_get_font_height(FontDesc *font_desc) { + const int surface_scale = renderer.surface_scale; + RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale); + return (font->height + surface_scale / 2) / surface_scale; } @@ -305,16 +339,6 @@ static inline RenColor blend_pixel(RenColor dst, RenColor src) { } -static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color) { - src.a = (src.a * color.a) >> 8; - int ia = 0xff - src.a; - dst.r = ((src.r * color.r * src.a) >> 16) + ((dst.r * ia) >> 8); - dst.g = ((src.g * color.g * src.a) >> 16) + ((dst.g * ia) >> 8); - dst.b = ((src.b * color.b * src.a) >> 16) + ((dst.b * ia) >> 8); - return dst; -} - - #define rect_draw_loop(expr) \ for (int j = y1; j < y2; j++) { \ for (int i = x1; i < x2; i++) { \ @@ -327,17 +351,24 @@ static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color) void ren_draw_rect(RenRect rect, RenColor color) { if (color.a == 0) { return; } - int x1 = rect.x < clip.left ? clip.left : rect.x; - int y1 = rect.y < clip.top ? clip.top : rect.y; + const int surface_scale = renderer.surface_scale; + + /* transforms coordinates in pixels. */ + rect.x *= surface_scale; + rect.y *= surface_scale; + rect.width *= surface_scale; + rect.height *= surface_scale; + + int x1 = rect.x < renderer.clip.left ? renderer.clip.left : rect.x; + int y1 = rect.y < renderer.clip.top ? renderer.clip.top : rect.y; int x2 = rect.x + rect.width; int y2 = rect.y + rect.height; - x2 = x2 > clip.right ? clip.right : x2; - y2 = y2 > clip.bottom ? clip.bottom : y2; + x2 = x2 > renderer.clip.right ? renderer.clip.right : x2; + y2 = y2 > renderer.clip.bottom ? renderer.clip.bottom : y2; - SDL_Surface *surf = get_window_surface(); - RenColor *d = (RenColor*) surf->pixels; - d += x1 + y1 * surf->w; - int dr = surf->w - (x2 - x1); + RenColor *d = (RenColor*) renderer.surface->pixels; + d += x1 + y1 * renderer.surface->w; + int dr = renderer.surface->w - (x2 - x1); if (color.a == 0xff) { rect_draw_loop(color); @@ -358,13 +389,12 @@ static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) { return 0; } - -void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int y, RenColor color, +static void draw_text_impl(RenFont *font, const char *text, int x_subpixel, int y_pixel, RenColor color, CPReplaceTable *replacements, RenColor replace_color) { + SDL_Surface *surf = renderer.surface; const char *p = text; unsigned codepoint; - SDL_Surface *surf = get_window_surface(); const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b }; while (*p) { FR_Color color_rep; @@ -381,18 +411,29 @@ void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int color_rep = color_fr; } if (color.a != 0) { - FR_Blend_Glyph(font->renderer, &clip, - x_subpixel, y, (uint8_t *) surf->pixels, surf->w, set->image, g, color_rep); + FR_Blend_Glyph(font->renderer, &renderer.clip, + x_subpixel, y_pixel, (uint8_t *) surf->pixels, surf->w, set->image, g, color_rep); } x_subpixel += xadvance_original_cp; } } -void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color, + +void ren_draw_text_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color) { - const int subpixel_scale = FR_Subpixel_Scale(font->renderer); - ren_draw_text_subpixel(font, text, subpixel_scale * x, y, color, replacements, replace_color); + const int surface_scale = renderer.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); +} + +void ren_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color, + CPReplaceTable *replacements, RenColor replace_color) +{ + const int surface_scale = renderer.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); + draw_text_impl(font, text, subpixel_scale * x, surface_scale * y, color, replacements, replace_color); } // Could be declared as static inline @@ -409,7 +450,8 @@ int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) { } -int ren_get_font_subpixel_scale(RenFont *font) { - return FR_Subpixel_Scale(font->renderer); +int ren_get_font_subpixel_scale(FontDesc *font_desc) { + const int surface_scale = renderer.surface_scale; + RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale); + return FR_Subpixel_Scale(font->renderer) * surface_scale; } - diff --git a/src/renderer.h b/src/renderer.h index f11d8e64..7638466b 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -3,9 +3,9 @@ #include #include +#include "fontdesc.h" typedef struct RenImage RenImage; -typedef struct RenFont RenFont; enum { RenFontAntialiasingMask = 1, @@ -36,27 +36,29 @@ typedef struct CPReplaceTable CPReplaceTable; void ren_init(SDL_Window *win); -void ren_resize(); +void ren_setup_renderer(); void ren_update_rects(RenRect *rects, int count); void ren_set_clip_rect(RenRect rect); -void ren_get_size(int *x, int *y); +void ren_get_size(int *x, int *y); /* Reports the size in points. */ void ren_free_window_resources(); RenImage* ren_new_image(int width, int height); void ren_free_image(RenImage *image); RenFont* ren_load_font(const char *filename, float size, unsigned int renderer_flags); +int ren_verify_font(const char *filename); void ren_free_font(RenFont *font); void ren_set_font_tab_size(RenFont *font, int n); int ren_get_font_tab_size(RenFont *font); -int ren_get_font_width(RenFont *font, const char *text, int *subpixel_scale); -int ren_get_font_height(RenFont *font); -int ren_get_font_subpixel_scale(RenFont *font); + +int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale); +int ren_get_font_height(FontDesc *font_desc); +int ren_get_font_subpixel_scale(FontDesc *font_desc); int ren_font_subpixel_round(int width, int subpixel_scale, int orientation); void ren_draw_rect(RenRect rect, RenColor color); -void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color); -void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_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_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color); void ren_cp_replace_init(CPReplaceTable *rep_table); void ren_cp_replace_free(CPReplaceTable *rep_table);