Merge branch with support for retina display
This commit is contained in:
commit
a72431ace7
|
@ -85,10 +85,10 @@ lite_build_package_windows () {
|
||||||
echo "created package $package_name"
|
echo "created package $package_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
lite_build_package_macosx () {
|
lite_build_package_macos () {
|
||||||
local build="$1"
|
local build="$1"
|
||||||
local arch="$2"
|
local arch="$2"
|
||||||
local os="macosx"
|
local os="macos"
|
||||||
|
|
||||||
local appdir=".package-build/lite-xl.app"
|
local appdir=".package-build/lite-xl.app"
|
||||||
local bindir="$appdir/Contents/MacOS"
|
local bindir="$appdir/Contents/MacOS"
|
||||||
|
@ -110,10 +110,7 @@ lite_build_package_macosx () {
|
||||||
mv "$package_name" ..
|
mv "$package_name" ..
|
||||||
popd
|
popd
|
||||||
rm -fr ".package-build"
|
rm -fr ".package-build"
|
||||||
local dmg_name="lite-xl-$os-$arch.dmg"
|
|
||||||
rm -f "$dmg_name" && hdiutil create -volname lite-xl -srcfolder lite-xl.app -ov -format UDBZ "$dmg_name"
|
|
||||||
echo "created package $package_name"
|
echo "created package $package_name"
|
||||||
echo "created disk image $dmg_name"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lite_build_package_linux () {
|
lite_build_package_linux () {
|
||||||
|
@ -161,7 +158,7 @@ lite_build_package () {
|
||||||
if [[ "$OSTYPE" == msys || "$OSTYPE" == win32 ]]; then
|
if [[ "$OSTYPE" == msys || "$OSTYPE" == win32 ]]; then
|
||||||
lite_build_package_windows "$@"
|
lite_build_package_windows "$@"
|
||||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
lite_build_package_macosx "$@"
|
lite_build_package_macos "$@"
|
||||||
elif [[ "$OSTYPE" == "linux"* || "$OSTYPE" == "freebsd"* ]]; then
|
elif [[ "$OSTYPE" == "linux"* || "$OSTYPE" == "freebsd"* ]]; then
|
||||||
lite_build_package_linux "$@"
|
lite_build_package_linux "$@"
|
||||||
else
|
else
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
## Window creation for Retina displays
|
||||||
|
|
||||||
|
The file info.plist sets NSHighResolutionCapable to true. This is fine for High-DPI
|
||||||
|
and retina displays.
|
||||||
|
|
||||||
|
The `SDL_CreateWindow` is called with the flag `SDL_WINDOW_ALLOW_HIGHDPI`.
|
||||||
|
On Mac OS it means that, in source file `video/cocoa/SDL_cocoawindow.m`, from
|
||||||
|
function `Cocoa_CreateWindow`, SDL calls:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
/* highdpi will be TRUE below */
|
||||||
|
BOOL highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0;
|
||||||
|
[contentView setWantsBestResolutionOpenGLSurface:highdpi]
|
||||||
|
```
|
||||||
|
|
||||||
|
Documentation for `setWantsBestResolutionOpenGLSurface`:
|
||||||
|
|
||||||
|
https://developer.apple.com/documentation/appkit/nsview/1414938-wantsbestresolutionopenglsurface
|
||||||
|
|
||||||
|
with more details in "OpenGL Programming Guide for Mac", chapter
|
||||||
|
"Optimizing OpenGL for High Resolution":
|
||||||
|
|
||||||
|
https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/EnablingOpenGLforHighResolution/EnablingOpenGLforHighResolution.html#//apple_ref/doc/uid/TP40001987-CH1001-SW4
|
||||||
|
|
||||||
|
Citation from the official documentation:
|
||||||
|
|
||||||
|
You can opt in to high resolution by calling the method
|
||||||
|
`setWantsBestResolutionOpenGLSurface:` when you initialize the view, and
|
||||||
|
supplying YES as an argument:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don’t opt in, the system magnifies the rendered results.
|
||||||
|
|
||||||
|
The wantsBestResolutionOpenGLSurface property is relevant only for views to
|
||||||
|
which an NSOpenGLContext object is bound. Its value does not affect the behavior
|
||||||
|
of other views. For compatibility, wantsBestResolutionOpenGLSurface defaults to
|
||||||
|
NO, providing a 1-pixel-per-point framebuffer regardless of the backing scale
|
||||||
|
factor for the display the view occupies. Setting this property to YES for a
|
||||||
|
given view causes AppKit to allocate a higher-resolution framebuffer when
|
||||||
|
appropriate for the backing scale factor and target display.
|
||||||
|
|
||||||
|
To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view
|
||||||
|
must perform correct conversions between view units (points) and pixel units as
|
||||||
|
needed. For example, the common practice of passing the width and height of
|
||||||
|
[self bounds] to glViewport() will yield incorrect results at high resolution,
|
||||||
|
because the parameters passed to the glViewport() function must be in pixels. As
|
||||||
|
a result, you’ll get only partial instead of complete coverage of the render
|
||||||
|
surface. Instead, use the backing store bounds:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self convertRectToBacking:[self bounds]];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coordinates
|
||||||
|
|
||||||
|
The SDL function `SDL_GL_GetDrawableSize` will provide the size of the underlying drawable
|
||||||
|
in pixels. From the `SDL_video.h` header.
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* \brief Get the size of a window's underlying drawable in pixels (for use
|
||||||
|
* with glViewport).
|
||||||
|
*
|
||||||
|
* \param window Window from which the drawable size should be queried
|
||||||
|
* \param w Pointer to variable for storing the width in pixels, may be NULL
|
||||||
|
* \param h Pointer to variable for storing the height in pixels, may be NULL
|
||||||
|
*
|
||||||
|
* This may differ from SDL_GetWindowSize() if we're rendering to a high-DPI
|
||||||
|
* drawable, i.e. the window was created with SDL_WINDOW_ALLOW_HIGHDPI on a
|
||||||
|
* platform with high-DPI support (Apple calls this "Retina"), and not disabled
|
||||||
|
* by the SDL_HINT_VIDEO_HIGHDPI_DISABLED hint.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetWindowSize()
|
||||||
|
* \sa SDL_CreateWindow()
|
||||||
|
*/
|
||||||
|
extern DECLSPEC void SDLCALL SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
|
||||||
|
int *h);
|
||||||
|
```
|
||||||
|
|
||||||
|
In turns it calls `Cocoa_GL_GetDrawableSize` from source file
|
||||||
|
`video/cocoa/SDL_cocoaopengl.m`. The function use the method
|
||||||
|
`[contentView convertRectToBacking:viewport]`:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
|
||||||
|
/* This gives us the correct viewport for a Retina-enabled view, only
|
||||||
|
* supported on 10.7+. */
|
||||||
|
if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
|
||||||
|
viewport = [contentView convertRectToBacking:viewport];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
to give back the sizes in pixels.
|
|
@ -40,6 +40,11 @@ if host_machine.system() == 'windows'
|
||||||
lite_rc += windows.compile_resources('res.rc')
|
lite_rc += windows.compile_resources('res.rc')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# On macos we need to use the SDL renderer to support retina displays
|
||||||
|
if get_option('renderer') or host_machine.system() == 'darwin'
|
||||||
|
lite_cargs += '-DLITE_USE_SDL_RENDERER'
|
||||||
|
endif
|
||||||
|
|
||||||
subdir('lib/font_renderer')
|
subdir('lib/font_renderer')
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
option('portable', type : 'boolean', value : false, description: 'Portable install')
|
option('portable', type : 'boolean', value : false, description: 'Portable install')
|
||||||
|
option('renderer', type : 'boolean', value : false, description: 'Use SDL renderer')
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,9 @@ static int f_draw_rect(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) {
|
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);
|
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. */
|
Otherwise it will be in pixels. */
|
||||||
int x_subpixel = luaL_checknumber(L, 3);
|
int x_subpixel = luaL_checknumber(L, 3);
|
||||||
int y = luaL_checknumber(L, 4);
|
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};
|
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);
|
lua_pushnumber(L, x_subpixel);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ static const luaL_Reg lib[] = {
|
||||||
{ "draw_rect", f_draw_rect },
|
{ "draw_rect", f_draw_rect },
|
||||||
{ "draw_text", f_draw_text },
|
{ "draw_text", f_draw_text },
|
||||||
{ "draw_text_subpixel", f_draw_text_subpixel },
|
{ "draw_text_subpixel", f_draw_text_subpixel },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
|
#include "fontdesc.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "rencache.h"
|
#include "rencache.h"
|
||||||
|
|
||||||
|
|
||||||
static int f_load(lua_State *L) {
|
static int f_load(lua_State *L) {
|
||||||
const char *filename = luaL_checkstring(L, 1);
|
const char *filename = luaL_checkstring(L, 1);
|
||||||
float size = luaL_checknumber(L, 2);
|
float size = luaL_checknumber(L, 2);
|
||||||
|
@ -40,57 +40,63 @@ static int f_load(lua_State *L) {
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
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, font_desc_alloc_size(filename));
|
||||||
|
font_desc_init(font_desc, filename, size, font_options);
|
||||||
luaL_setmetatable(L, API_TYPE_FONT);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_set_tab_size(lua_State *L) {
|
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);
|
int n = luaL_checknumber(L, 2);
|
||||||
ren_set_font_tab_size(*self, n);
|
font_desc_set_tab_size(self, n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_gc(lua_State *L) {
|
static int f_gc(lua_State *L) {
|
||||||
RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
|
||||||
if (*self) { rencache_free_font(*self); }
|
rencache_free_font(self);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_get_width(lua_State *L) {
|
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);
|
const char *text = luaL_checkstring(L, 2);
|
||||||
int subpixel_scale;
|
/* By calling ren_get_font_width with NULL as third arguments
|
||||||
int w = ren_get_font_width(*self, text, &subpixel_scale);
|
we will obtain the width in points. */
|
||||||
lua_pushnumber(L, ren_font_subpixel_round(w, subpixel_scale, 0));
|
int w = ren_get_font_width(self, text, NULL);
|
||||||
|
lua_pushnumber(L, w);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_subpixel_scale(lua_State *L) {
|
static int f_subpixel_scale(lua_State *L) {
|
||||||
RenFont **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(self));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_get_width_subpixel(lua_State *L) {
|
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);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int f_get_height(lua_State *L) {
|
static int f_get_height(lua_State *L) {
|
||||||
RenFont **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(self) );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,9 @@ top:
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
if (e.window.event == SDL_WINDOWEVENT_RESIZED) {
|
if (e.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
|
ren_resize_window();
|
||||||
lua_pushstring(L, "resized");
|
lua_pushstring(L, "resized");
|
||||||
|
/* The size below will be in points. */
|
||||||
lua_pushnumber(L, e.window.data1);
|
lua_pushnumber(L, e.window.data1);
|
||||||
lua_pushnumber(L, e.window.data2);
|
lua_pushnumber(L, e.window.data2);
|
||||||
return 3;
|
return 3;
|
||||||
|
@ -316,6 +318,7 @@ static int f_set_window_size(lua_State *L) {
|
||||||
double y = luaL_checknumber(L, 4);
|
double y = luaL_checknumber(L, 4);
|
||||||
SDL_SetWindowSize(window, w, h);
|
SDL_SetWindowSize(window, w, h);
|
||||||
SDL_SetWindowPosition(window, x, y);
|
SDL_SetWindowPosition(window, x, y);
|
||||||
|
ren_resize_window();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "fontdesc.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int font_desc_alloc_size(const char *filename) {
|
||||||
|
return offsetof(FontDesc, filename) + strlen(filename) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_desc_init(FontDesc *font_desc, const char *filename, float size, unsigned int font_options) {
|
||||||
|
memcpy(font_desc->filename, filename, strlen(filename) + 1);
|
||||||
|
font_desc->size = size;
|
||||||
|
font_desc->options = font_options;
|
||||||
|
font_desc->tab_size = 4;
|
||||||
|
font_desc->cache_length = 0;
|
||||||
|
font_desc->cache_last_index = 0; /* Normally no need to initialize. */
|
||||||
|
}
|
||||||
|
|
||||||
|
void font_desc_free(FontDesc *font_desc) {
|
||||||
|
for (int i = 0; i < font_desc->cache_length; i++) {
|
||||||
|
ren_free_font(font_desc->cache[i].font);
|
||||||
|
}
|
||||||
|
font_desc->cache_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->cache_length; i++) {
|
||||||
|
ren_set_font_tab_size(font_desc->cache[i].font, tab_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int font_desc_get_tab_size(FontDesc *font_desc) {
|
||||||
|
return font_desc->tab_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!font) {
|
||||||
|
/* The font was able to load when initially loaded using renderer.load.font.
|
||||||
|
If now is no longer available we just abort the application. */
|
||||||
|
fprintf(stderr, "Fatal error: unable to load font %s. Application will abort.\n",
|
||||||
|
font_desc->filename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
font_desc->cache[index].font = font;
|
||||||
|
font_desc->cache[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->cache_length; i++) {
|
||||||
|
if (font_desc->cache[i].scale == scale) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index < 0) {
|
||||||
|
index = font_desc->cache_length;
|
||||||
|
if (index < FONT_CACHE_ARRAY_MAX) {
|
||||||
|
load_scaled_font(font_desc, index, scale);
|
||||||
|
font_desc->cache_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->cache_last_index == 0 ? 1 : 0);
|
||||||
|
ren_free_font(font_desc->cache[index].font);
|
||||||
|
load_scaled_font(font_desc, index, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font_desc->cache_last_index = index;
|
||||||
|
return font_desc->cache[index].font;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef FONT_DESC_H
|
||||||
|
#define FONT_DESC_H
|
||||||
|
|
||||||
|
typedef struct RenFont RenFont;
|
||||||
|
|
||||||
|
struct FontInstance {
|
||||||
|
RenFont *font;
|
||||||
|
short int scale;
|
||||||
|
};
|
||||||
|
typedef struct FontInstance FontInstance;
|
||||||
|
|
||||||
|
#define FONT_CACHE_ARRAY_MAX 2
|
||||||
|
|
||||||
|
struct FontDesc {
|
||||||
|
float size;
|
||||||
|
unsigned int options;
|
||||||
|
short int tab_size;
|
||||||
|
FontInstance cache[FONT_CACHE_ARRAY_MAX];
|
||||||
|
short int cache_length;
|
||||||
|
short int cache_last_index; /* More recently used instance. */
|
||||||
|
char filename[0];
|
||||||
|
};
|
||||||
|
typedef struct FontDesc FontDesc;
|
||||||
|
|
||||||
|
void font_desc_init(FontDesc *font_desc, const char *filename, float size, unsigned int font_options);
|
||||||
|
int font_desc_alloc_size(const char *filename);
|
||||||
|
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
|
||||||
|
|
|
@ -200,7 +200,7 @@ init_lua:
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
SDL_DestroyWindow(window);
|
ren_free_window_resources();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ lite_sources = [
|
||||||
'api/renderer_font.c',
|
'api/renderer_font.c',
|
||||||
'api/system.c',
|
'api/system.c',
|
||||||
'renderer.c',
|
'renderer.c',
|
||||||
|
'renwindow.c',
|
||||||
|
'fontdesc.c',
|
||||||
'rencache.c',
|
'rencache.c',
|
||||||
'main.c',
|
'main.c',
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,7 +24,7 @@ typedef struct {
|
||||||
int32_t size;
|
int32_t size;
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
RenColor color;
|
RenColor color;
|
||||||
RenFont *font;
|
FontDesc *font_desc;
|
||||||
CPReplaceTable *replacements;
|
CPReplaceTable *replacements;
|
||||||
RenColor replace_color;
|
RenColor replace_color;
|
||||||
char text[0];
|
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);
|
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,
|
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, text, &subpixel_scale);
|
int w_subpixel = ren_get_font_width(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);
|
rect.height = ren_get_font_height(font_desc);
|
||||||
|
|
||||||
if (rects_overlap(screen_rect, rect)) {
|
if (rects_overlap(screen_rect, rect)) {
|
||||||
int sz = strlen(text) + 1;
|
int sz = strlen(text) + 1;
|
||||||
|
@ -154,11 +154,11 @@ int rencache_draw_text(RenFont *font,
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
memcpy(cmd->text, text, sz);
|
memcpy(cmd->text, text, sz);
|
||||||
cmd->color = color;
|
cmd->color = color;
|
||||||
cmd->font = font;
|
cmd->font_desc = font_desc;
|
||||||
cmd->rect = rect;
|
cmd->rect = rect;
|
||||||
cmd->subpixel_scale = (draw_subpixel ? subpixel_scale : 1);
|
cmd->subpixel_scale = (draw_subpixel ? subpixel_scale : 1);
|
||||||
cmd->x_subpixel_offset = x - subpixel_scale * rect.x;
|
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->replacements = replacements;
|
||||||
cmd->replace_color = replace_color;
|
cmd->replace_color = replace_color;
|
||||||
}
|
}
|
||||||
|
@ -272,13 +272,13 @@ void rencache_end_frame(void) {
|
||||||
ren_draw_rect(cmd->rect, cmd->color);
|
ren_draw_rect(cmd->rect, cmd->color);
|
||||||
break;
|
break;
|
||||||
case DRAW_TEXT:
|
case DRAW_TEXT:
|
||||||
ren_set_font_tab_size(cmd->font, cmd->tab_size);
|
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
||||||
ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color,
|
ren_draw_text(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:
|
||||||
ren_set_font_tab_size(cmd->font, cmd->tab_size);
|
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
|
||||||
ren_draw_text_subpixel(cmd->font, cmd->text,
|
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->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;
|
||||||
|
@ -301,7 +301,7 @@ void rencache_end_frame(void) {
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
while (next_command(&cmd)) {
|
while (next_command(&cmd)) {
|
||||||
if (cmd->type == FREE_FONT) {
|
if (cmd->type == FREE_FONT) {
|
||||||
ren_free_font(cmd->font);
|
font_desc_free(cmd->font_desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
void rencache_show_debug(bool enable);
|
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_set_clip_rect(RenRect rect);
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color);
|
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_invalidate(void);
|
||||||
void rencache_begin_frame(void);
|
void rencache_begin_frame(void);
|
||||||
void rencache_end_frame(void);
|
void rencache_end_frame(void);
|
||||||
|
|
171
src/renderer.c
171
src/renderer.c
|
@ -2,8 +2,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "renderer.h"
|
|
||||||
#include "font_renderer.h"
|
#include "font_renderer.h"
|
||||||
|
#include "renderer.h"
|
||||||
|
#include "renwindow.h"
|
||||||
|
|
||||||
#define MAX_GLYPHSET 256
|
#define MAX_GLYPHSET 256
|
||||||
#define REPLACEMENT_CHUNK_SIZE 8
|
#define REPLACEMENT_CHUNK_SIZE 8
|
||||||
|
@ -31,9 +32,7 @@ struct RenFont {
|
||||||
FR_Renderer *renderer;
|
FR_Renderer *renderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static RenWindow window_renderer = {0};
|
||||||
static SDL_Window *window;
|
|
||||||
static FR_Clip_Area clip;
|
|
||||||
|
|
||||||
static void* check_alloc(void *ptr) {
|
static void* check_alloc(void *ptr) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
|
@ -91,37 +90,44 @@ void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *
|
||||||
rep_table->size = table_size + 1;
|
rep_table->size = table_size + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ren_free_window_resources() {
|
||||||
|
renwin_free(&window_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
void ren_init(SDL_Window *win) {
|
void ren_init(SDL_Window *win) {
|
||||||
assert(win);
|
assert(win);
|
||||||
window = win;
|
window_renderer.window = win;
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
renwin_init_surface(&window_renderer);
|
||||||
ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
|
renwin_clip_to_surface(&window_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ren_resize_window() {
|
||||||
|
renwin_resize_surface(&window_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_update_rects(RenRect *rects, int count) {
|
void ren_update_rects(RenRect *rects, int count) {
|
||||||
SDL_UpdateWindowSurfaceRects(window, (SDL_Rect*) rects, count);
|
|
||||||
static bool initial_frame = true;
|
static bool initial_frame = true;
|
||||||
if (initial_frame) {
|
if (initial_frame) {
|
||||||
SDL_ShowWindow(window);
|
renwin_show_window(&window_renderer);
|
||||||
initial_frame = false;
|
initial_frame = false;
|
||||||
}
|
}
|
||||||
|
renwin_update_rects(&window_renderer, rects, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_set_clip_rect(RenRect rect) {
|
void ren_set_clip_rect(RenRect rect) {
|
||||||
clip.left = rect.x;
|
renwin_set_clip_rect(&window_renderer, rect);
|
||||||
clip.top = rect.y;
|
|
||||||
clip.right = rect.x + rect.width;
|
|
||||||
clip.bottom = rect.y + rect.height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_get_size(int *x, int *y) {
|
void ren_get_size(int *x, int *y) {
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
RenWindow *ren = &window_renderer;
|
||||||
*x = surf->w;
|
const int scale = renwin_surface_scale(ren);
|
||||||
*y = surf->h;
|
SDL_Surface *surface = renwin_get_surface(ren);
|
||||||
|
*x = surface->w / scale;
|
||||||
|
*y = surface->h / scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,6 +164,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* ren_load_font(const char *filename, float size, unsigned int renderer_flags) {
|
||||||
RenFont *font = NULL;
|
RenFont *font = NULL;
|
||||||
|
|
||||||
|
@ -218,25 +235,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;
|
int x = 0;
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
|
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);
|
||||||
GlyphSet *set = get_glyphset(font, codepoint);
|
GlyphSet *set = get_glyphset(font, codepoint);
|
||||||
FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff];
|
FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff];
|
||||||
x += g->xadvance;
|
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) {
|
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) {
|
int ren_get_font_height(FontDesc *font_desc) {
|
||||||
return font->height;
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
|
return (font->height + surface_scale / 2) / surface_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,16 +275,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) \
|
#define rect_draw_loop(expr) \
|
||||||
for (int j = y1; j < y2; j++) { \
|
for (int j = y1; j < y2; j++) { \
|
||||||
for (int i = x1; i < x2; i++) { \
|
for (int i = x1; i < x2; i++) { \
|
||||||
|
@ -271,17 +287,26 @@ static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color)
|
||||||
void ren_draw_rect(RenRect rect, RenColor color) {
|
void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
if (color.a == 0) { return; }
|
if (color.a == 0) { return; }
|
||||||
|
|
||||||
int x1 = rect.x < clip.left ? clip.left : rect.x;
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
int y1 = rect.y < clip.top ? clip.top : rect.y;
|
|
||||||
|
/* transforms coordinates in pixels. */
|
||||||
|
rect.x *= surface_scale;
|
||||||
|
rect.y *= surface_scale;
|
||||||
|
rect.width *= surface_scale;
|
||||||
|
rect.height *= surface_scale;
|
||||||
|
|
||||||
|
const RenRect clip = window_renderer.clip;
|
||||||
|
int x1 = rect.x < clip.x ? clip.x : rect.x;
|
||||||
|
int y1 = rect.y < clip.y ? clip.y : rect.y;
|
||||||
int x2 = rect.x + rect.width;
|
int x2 = rect.x + rect.width;
|
||||||
int y2 = rect.y + rect.height;
|
int y2 = rect.y + rect.height;
|
||||||
x2 = x2 > clip.right ? clip.right : x2;
|
x2 = x2 > clip.x + clip.width ? clip.x + clip.width : x2;
|
||||||
y2 = y2 > clip.bottom ? clip.bottom : y2;
|
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
|
||||||
|
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surface = renwin_get_surface(&window_renderer);
|
||||||
RenColor *d = (RenColor*) surf->pixels;
|
RenColor *d = (RenColor*) surface->pixels;
|
||||||
d += x1 + y1 * surf->w;
|
d += x1 + y1 * surface->w;
|
||||||
int dr = surf->w - (x2 - x1);
|
int dr = surface->w - (x2 - x1);
|
||||||
|
|
||||||
if (color.a == 0xff) {
|
if (color.a == 0xff) {
|
||||||
rect_draw_loop(color);
|
rect_draw_loop(color);
|
||||||
|
@ -290,38 +315,6 @@ void ren_draw_rect(RenRect rect, RenColor color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
|
|
||||||
if (color.a == 0) { return; }
|
|
||||||
|
|
||||||
int n;
|
|
||||||
if ((n = clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; }
|
|
||||||
if ((n = clip.top - y) > 0) { sub->height -= n; sub->y += n; x += n; }
|
|
||||||
if ((n = x + sub->width - clip.right ) > 0) { sub->width -= n; }
|
|
||||||
if ((n = y + sub->height - clip.bottom) > 0) { sub->height -= n; }
|
|
||||||
|
|
||||||
if (sub->width <= 0 || sub->height <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* draw */
|
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
|
||||||
RenColor *s = image->pixels;
|
|
||||||
RenColor *d = (RenColor*) surf->pixels;
|
|
||||||
s += sub->x + sub->y * image->width;
|
|
||||||
d += x + y * surf->w;
|
|
||||||
int sr = image->width - sub->width;
|
|
||||||
int dr = surf->w - sub->width;
|
|
||||||
|
|
||||||
for (int j = 0; j < sub->height; j++) {
|
|
||||||
for (int i = 0; i < sub->width; i++) {
|
|
||||||
*d = blend_pixel2(*d, *s, color);
|
|
||||||
d++;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
d += dr;
|
|
||||||
s += sr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
|
static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
|
||||||
for (int i = 0; i < rep_table->size; i++) {
|
for (int i = 0; i < rep_table->size; i++) {
|
||||||
|
@ -335,12 +328,18 @@ static int codepoint_replace(CPReplaceTable *rep_table, unsigned *codepoint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int y, RenColor color,
|
static FR_Clip_Area clip_area_from_rect(const RenRect r) {
|
||||||
|
return (FR_Clip_Area) {r.x, r.y, r.x + r.width, r.y + r.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void draw_text_impl(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);
|
||||||
|
FR_Clip_Area clip = clip_area_from_rect(window_renderer.clip);
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
|
||||||
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 };
|
||||||
while (*p) {
|
while (*p) {
|
||||||
FR_Color color_rep;
|
FR_Color color_rep;
|
||||||
|
@ -358,17 +357,28 @@ void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int
|
||||||
}
|
}
|
||||||
if (color.a != 0) {
|
if (color.a != 0) {
|
||||||
FR_Blend_Glyph(font->renderer, &clip,
|
FR_Blend_Glyph(font->renderer, &clip,
|
||||||
x_subpixel, y, (uint8_t *) surf->pixels, surf->w, set->image, g, color_rep);
|
x_subpixel, y_pixel, (uint8_t *) surf->pixels, surf->w, set->image, g, color_rep);
|
||||||
}
|
}
|
||||||
x_subpixel += xadvance_original_cp;
|
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)
|
CPReplaceTable *replacements, RenColor replace_color)
|
||||||
{
|
{
|
||||||
const int subpixel_scale = FR_Subpixel_Scale(font->renderer);
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
ren_draw_text_subpixel(font, text, subpixel_scale * x, y, color, replacements, replace_color);
|
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 = renwin_surface_scale(&window_renderer);
|
||||||
|
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
|
// Could be declared as static inline
|
||||||
|
@ -385,7 +395,8 @@ int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ren_get_font_subpixel_scale(RenFont *font) {
|
int ren_get_font_subpixel_scale(FontDesc *font_desc) {
|
||||||
return FR_Subpixel_Scale(font->renderer);
|
const int surface_scale = renwin_surface_scale(&window_renderer);
|
||||||
|
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
|
||||||
|
return FR_Subpixel_Scale(font->renderer) * surface_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "fontdesc.h"
|
||||||
|
|
||||||
typedef struct RenImage RenImage;
|
typedef struct RenImage RenImage;
|
||||||
typedef struct RenFont RenFont;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RenFontAntialiasingMask = 1,
|
RenFontAntialiasingMask = 1,
|
||||||
|
@ -36,26 +36,29 @@ typedef struct CPReplaceTable CPReplaceTable;
|
||||||
|
|
||||||
|
|
||||||
void ren_init(SDL_Window *win);
|
void ren_init(SDL_Window *win);
|
||||||
|
void ren_resize_window();
|
||||||
void ren_update_rects(RenRect *rects, int count);
|
void ren_update_rects(RenRect *rects, int count);
|
||||||
void ren_set_clip_rect(RenRect rect);
|
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);
|
RenImage* ren_new_image(int width, int height);
|
||||||
void ren_free_image(RenImage *image);
|
void ren_free_image(RenImage *image);
|
||||||
|
|
||||||
RenFont* ren_load_font(const char *filename, float size, unsigned int renderer_flags);
|
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_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(RenFont *font, const char *text, int *subpixel_scale);
|
|
||||||
int ren_get_font_height(RenFont *font);
|
int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale);
|
||||||
int ren_get_font_subpixel_scale(RenFont *font);
|
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);
|
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation);
|
||||||
|
|
||||||
void ren_draw_rect(RenRect rect, RenColor color);
|
void ren_draw_rect(RenRect rect, RenColor color);
|
||||||
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, 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(RenFont *font, 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(RenFont *font, 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_init(CPReplaceTable *rep_table);
|
||||||
void ren_cp_replace_free(CPReplaceTable *rep_table);
|
void ren_cp_replace_free(CPReplaceTable *rep_table);
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include "renwindow.h"
|
||||||
|
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
static int query_surface_scale(RenWindow *ren) {
|
||||||
|
int w_pixels, h_pixels;
|
||||||
|
int w_points, h_points;
|
||||||
|
SDL_GL_GetDrawableSize(ren->window, &w_pixels, &h_pixels);
|
||||||
|
SDL_GetWindowSize(ren->window, &w_points, &h_points);
|
||||||
|
/* We consider that the ratio pixel/point will always be an integer and
|
||||||
|
it is the same along the x and the y axis. */
|
||||||
|
assert(w_pixels % w_points == 0 && h_pixels % h_points == 0 && w_pixels / w_points == h_pixels / h_points);
|
||||||
|
return w_pixels / w_points;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void renwin_init_surface(RenWindow *ren) {
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
if (ren->surface) {
|
||||||
|
SDL_FreeSurface(ren->surface);
|
||||||
|
}
|
||||||
|
int w, h;
|
||||||
|
SDL_GL_GetDrawableSize(ren->window, &w, &h);
|
||||||
|
ren->surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_BGRA32);
|
||||||
|
ren->surface_scale = query_surface_scale(ren);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int renwin_surface_scale(RenWindow *ren) {
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
return ren->surface_scale;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 renwin_clip_to_surface(RenWindow *ren) {
|
||||||
|
SDL_Surface *surface = renwin_get_surface(ren);
|
||||||
|
ren->clip = (RenRect) {0, 0, surface->w, surface->h};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void renwin_set_clip_rect(RenWindow *ren, RenRect rect) {
|
||||||
|
ren->clip = scaled_rect(rect, renwin_surface_scale(ren));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_Surface *renwin_get_surface(RenWindow *ren) {
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
return ren->surface;
|
||||||
|
#else
|
||||||
|
return SDL_GetWindowSurface(ren->window);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
static void setup_renderer(RenWindow *ren, 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 (ren->renderer) {
|
||||||
|
SDL_DestroyRenderer(ren->renderer);
|
||||||
|
SDL_DestroyTexture(ren->texture);
|
||||||
|
}
|
||||||
|
ren->renderer = SDL_CreateRenderer(ren->window, -1, 0);
|
||||||
|
ren->texture = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h);
|
||||||
|
ren->surface_scale = query_surface_scale(ren);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void renwin_resize_surface(RenWindow *ren) {
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
int new_w, new_h;
|
||||||
|
SDL_GL_GetDrawableSize(ren->window, &new_w, &new_h);
|
||||||
|
/* Note that (w, h) may differ from (new_w, new_h) on retina displays. */
|
||||||
|
if (new_w != ren->surface->w || new_h != ren->surface->h) {
|
||||||
|
renwin_init_surface(ren);
|
||||||
|
renwin_clip_to_surface(ren);
|
||||||
|
setup_renderer(ren, new_w, new_h);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void renwin_show_window(RenWindow *ren) {
|
||||||
|
SDL_ShowWindow(ren->window);
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
int w, h;
|
||||||
|
SDL_GL_GetDrawableSize(ren->window, &w, &h);
|
||||||
|
setup_renderer(ren, w, h);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void renwin_update_rects(RenWindow *ren, RenRect *rects, int count) {
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
const int scale = ren->surface_scale;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
const RenRect *r = &rects[i];
|
||||||
|
const int x = scale * r->x, y = scale * r->y;
|
||||||
|
const int w = scale * r->width, h = scale * r->height;
|
||||||
|
const SDL_Rect sr = {.x = x, .y = y, .w = w, .h = h};
|
||||||
|
int32_t *pixels = ((int32_t *) ren->surface->pixels) + x + ren->surface->w * y;
|
||||||
|
SDL_UpdateTexture(ren->texture, &sr, pixels, ren->surface->w * 4);
|
||||||
|
}
|
||||||
|
SDL_RenderCopy(ren->renderer, ren->texture, NULL, NULL);
|
||||||
|
SDL_RenderPresent(ren->renderer);
|
||||||
|
#else
|
||||||
|
SDL_UpdateWindowSurfaceRects(ren->window, (SDL_Rect*) rects, count);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void renwin_free(RenWindow *ren) {
|
||||||
|
SDL_DestroyWindow(ren->window);
|
||||||
|
ren->window = NULL;
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
SDL_DestroyRenderer(ren->renderer);
|
||||||
|
SDL_DestroyTexture(ren->texture);
|
||||||
|
SDL_FreeSurface(ren->surface);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <SDL.h>
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
struct RenWindow {
|
||||||
|
SDL_Window *window;
|
||||||
|
RenRect clip; /* Clipping rect in pixel coordinates. */
|
||||||
|
#ifdef LITE_USE_SDL_RENDERER
|
||||||
|
SDL_Renderer *renderer;
|
||||||
|
SDL_Texture *texture;
|
||||||
|
SDL_Surface *surface;
|
||||||
|
int surface_scale;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
typedef struct RenWindow RenWindow;
|
||||||
|
|
||||||
|
void renwin_init_surface(RenWindow *ren);
|
||||||
|
int renwin_surface_scale(RenWindow *ren);
|
||||||
|
void renwin_clip_to_surface(RenWindow *ren);
|
||||||
|
void renwin_set_clip_rect(RenWindow *ren, RenRect rect);
|
||||||
|
void renwin_resize_surface(RenWindow *ren);
|
||||||
|
void renwin_show_window(RenWindow *ren);
|
||||||
|
void renwin_update_rects(RenWindow *ren, RenRect *rects, int count);
|
||||||
|
void renwin_free(RenWindow *ren);
|
||||||
|
SDL_Surface *renwin_get_surface(RenWindow *ren);
|
||||||
|
|
Loading…
Reference in New Issue