cripsy new FT fonts in windows
This commit is contained in:
parent
e9c5f89575
commit
69349fd749
|
@ -8,10 +8,7 @@
|
|||
// 2^24 of them so don't be wasteful!
|
||||
enum My_Maps{
|
||||
my_code_map,
|
||||
// for testing
|
||||
my_html_map,
|
||||
my_empty_map1,
|
||||
my_empty_map2,
|
||||
|
||||
my_maps_count
|
||||
};
|
||||
|
||||
|
@ -115,7 +112,9 @@ CUSTOM_COMMAND_SIG(build_at_launch_location){
|
|||
|
||||
HOOK_SIG(my_start){
|
||||
exec_command(app, cmdid_open_panel_vsplit);
|
||||
exec_command(app, cmdid_hide_scrollbar);
|
||||
exec_command(app, cmdid_change_active_panel);
|
||||
exec_command(app, cmdid_hide_scrollbar);
|
||||
|
||||
app->change_theme(app, literal("4coder"));
|
||||
app->change_font(app, literal("liberation sans"));
|
||||
|
@ -146,10 +145,10 @@ HOOK_SIG(my_file_settings){
|
|||
unsigned int access = AccessProtected|AccessHidden;
|
||||
Buffer_Summary buffer = app->get_parameter_buffer(app, 0, access);
|
||||
assert(buffer.exists);
|
||||
|
||||
|
||||
int treat_as_code = 0;
|
||||
int wrap_lines = 1;
|
||||
|
||||
|
||||
if (buffer.file_name && buffer.size < (16 << 20)){
|
||||
String ext = file_extension(make_string(buffer.file_name, buffer.file_name_len));
|
||||
if (match(ext, make_lit_string("cpp"))) treat_as_code = 1;
|
||||
|
@ -157,14 +156,14 @@ HOOK_SIG(my_file_settings){
|
|||
else if (match(ext, make_lit_string("c"))) treat_as_code = 1;
|
||||
else if (match(ext, make_lit_string("hpp"))) treat_as_code = 1;
|
||||
}
|
||||
|
||||
|
||||
if (treat_as_code){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
if (buffer.file_name[0] == '*'){
|
||||
wrap_lines = 0;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(allen|a4.0.5): Unlike previous versions the command cmdid_set_settings
|
||||
// no longer automatically effects the active buffer. This command will actually be
|
||||
// phased out in favor of an app call soon.
|
||||
|
@ -207,14 +206,6 @@ default_keys(Bind_Helper *context){
|
|||
|
||||
end_map(context);
|
||||
|
||||
begin_map(context, my_empty_map1);
|
||||
inherit_map(context, mapid_nomap);
|
||||
end_map(context);
|
||||
|
||||
begin_map(context, my_empty_map2);
|
||||
inherit_map(context, mapid_nomap);
|
||||
end_map(context);
|
||||
|
||||
begin_map(context, my_code_map);
|
||||
|
||||
// NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to
|
||||
|
|
|
@ -233,15 +233,17 @@ clipboard_copy(Application_Links *app, int start, int end, Buffer_Summary *buffe
|
|||
Buffer_Summary buffer = app->get_buffer(app, view.buffer_id, access);
|
||||
int result = false;
|
||||
|
||||
if (0 <= start && start <= end && end <= buffer.size){
|
||||
int size = (end - start);
|
||||
char *str = (char*)app->memory;
|
||||
|
||||
if (size <= app->memory_size){
|
||||
app->buffer_read_range(app, &buffer, start, end, str);
|
||||
app->clipboard_post(app, str, size);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
result = true;
|
||||
if (buffer.exists){
|
||||
if (0 <= start && start <= end && end <= buffer.size){
|
||||
int size = (end - start);
|
||||
char *str = (char*)app->memory;
|
||||
|
||||
if (size <= app->memory_size){
|
||||
app->buffer_read_range(app, &buffer, start, end, str);
|
||||
app->clipboard_post(app, str, size);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,9 +256,11 @@ clipboard_cut(Application_Links *app, int start, int end, Buffer_Summary *buffer
|
|||
Buffer_Summary buffer = {0};
|
||||
int result = false;
|
||||
|
||||
if (clipboard_copy(app, start, end, &buffer, access)){
|
||||
app->buffer_replace_range(app, &buffer, start, end, 0, 0);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
if (buffer.exists){
|
||||
if (clipboard_copy(app, start, end, &buffer, access)){
|
||||
app->buffer_replace_range(app, &buffer, start, end, 0, 0);
|
||||
if (buffer_out){*buffer_out = buffer;}
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
|
@ -691,16 +695,16 @@ CUSTOM_COMMAND_SIG(if0_off){
|
|||
|
||||
View_Summary view;
|
||||
Buffer_Summary buffer;
|
||||
|
||||
|
||||
char text1[] = "\n#if 0";
|
||||
int size1 = sizeof(text1) - 1;
|
||||
|
||||
|
||||
char text2[] = "#endif\n";
|
||||
int size2 = sizeof(text2) - 1;
|
||||
|
||||
|
||||
Range range;
|
||||
int pos;
|
||||
|
||||
|
||||
view = app->get_active_view(app, access);
|
||||
buffer = app->get_buffer(app, view.buffer_id, access);
|
||||
|
||||
|
@ -1077,7 +1081,7 @@ CUSTOM_COMMAND_SIG(close_all_code){
|
|||
int buffers_to_close[2048];
|
||||
int buffers_to_close_count = 0;
|
||||
|
||||
unsigned int access = AccessProtected|AccessHidden;
|
||||
unsigned int access = AccessAll;
|
||||
for (buffer = app->get_buffer_first(app, access);
|
||||
buffer.exists;
|
||||
app->get_buffer_next(app, &buffer, access)){
|
||||
|
@ -1106,11 +1110,11 @@ CUSTOM_COMMAND_SIG(open_all_code){
|
|||
String dir = make_string(app->memory, 0, app->memory_size);
|
||||
dir.size = app->directory_get_hot(app, dir.str, dir.memory_size);
|
||||
int dir_size = dir.size;
|
||||
|
||||
|
||||
// NOTE(allen|a3.4.4): Here we get the list of files in this directory.
|
||||
// Notice that we free_file_list at the end.
|
||||
File_List list = app->get_file_list(app, dir.str, dir.size);
|
||||
|
||||
|
||||
for (int i = 0; i < list.count; ++i){
|
||||
File_Info *info = list.infos + i;
|
||||
if (!info->folder){
|
||||
|
@ -1150,14 +1154,9 @@ CUSTOM_COMMAND_SIG(execute_any_cli){
|
|||
hot_directory = make_fixed_width_string(hot_directory_space);
|
||||
hot_directory.size = app->directory_get_hot(app, hot_directory.str, hot_directory.memory_size);
|
||||
|
||||
unsigned int access = AccessProtected|AccessHidden;
|
||||
unsigned int access = AccessAll;
|
||||
View_Summary view = app->get_active_view(app, access);
|
||||
|
||||
// TODO(allen): Make this work without null terminators
|
||||
terminate_with_null(&bar_out.string);
|
||||
terminate_with_null(&bar_cmd.string);
|
||||
terminate_with_null(&hot_directory);
|
||||
|
||||
app->exec_system_command(app, &view,
|
||||
buffer_identifier(bar_out.string.str, bar_out.string.size),
|
||||
hot_directory.str, hot_directory.size,
|
||||
|
@ -1174,7 +1173,7 @@ CUSTOM_COMMAND_SIG(execute_previous_cli){
|
|||
hot_directory = make_string_slowly(hot_directory_space);
|
||||
|
||||
if (out_buffer.size > 0 && cmd.size > 0 && hot_directory.size > 0){
|
||||
unsigned int access = AccessProtected|AccessHidden;
|
||||
unsigned int access = AccessAll;
|
||||
View_Summary view = app->get_active_view(app, access);
|
||||
|
||||
app->exec_system_command(app, &view,
|
||||
|
@ -1194,15 +1193,15 @@ CUSTOM_COMMAND_SIG(execute_arbitrary_command){
|
|||
char space[1024];
|
||||
bar.prompt = make_lit_string("Command: ");
|
||||
bar.string = make_fixed_width_string(space);
|
||||
|
||||
|
||||
if (!query_user_string(app, &bar)) return;
|
||||
|
||||
|
||||
// NOTE(allen): Here I chose to end this query bar because when I call another
|
||||
// command it might ALSO have query bars and I don't want this one hanging
|
||||
// around at that point. Since the bar exists on my stack the result of the query
|
||||
// is still available in bar.string though.
|
||||
app->end_query_bar(app, &bar, 0);
|
||||
|
||||
|
||||
if (match(bar.string, make_lit_string("open all code"))){
|
||||
exec_command(app, open_all_code);
|
||||
}
|
||||
|
@ -1263,7 +1262,7 @@ CUSTOM_COMMAND_SIG(build_search){
|
|||
//
|
||||
// This doesn't actually change the hot directory of 4coder, it's only effect is to
|
||||
// modify the string you passed in to reflect the change in directory if that change was possible.
|
||||
|
||||
|
||||
int keep_going = 1;
|
||||
int old_size;
|
||||
int size = app->memory_size/2;
|
||||
|
@ -1272,41 +1271,35 @@ CUSTOM_COMMAND_SIG(build_search){
|
|||
dir.size = app->directory_get_hot(app, dir.str, dir.memory_size);
|
||||
|
||||
String command = make_string((char*)app->memory + size, 0, size);
|
||||
append(&command, '"');
|
||||
|
||||
while (keep_going){
|
||||
append(&command, dir);
|
||||
|
||||
old_size = dir.size;
|
||||
append(&dir, "build.bat");
|
||||
|
||||
if (app->file_exists(app, dir.str, dir.size)){
|
||||
dir.size = old_size;
|
||||
append(&command, "build");
|
||||
append(&command, '"');
|
||||
append(&command, dir);
|
||||
append(&command, "build\"");
|
||||
|
||||
unsigned int access = AccessOpen;
|
||||
unsigned int access = AccessAll;
|
||||
View_Summary view = app->get_active_view(app, access);
|
||||
|
||||
terminate_with_null(&dir);
|
||||
terminate_with_null(&command);
|
||||
|
||||
app->exec_system_command(app, &view,
|
||||
buffer_identifier(literal("*compilation*")),
|
||||
dir.str, dir.size,
|
||||
command.str, command.size,
|
||||
CLI_OverlapWithConflict);
|
||||
|
||||
return;
|
||||
break;
|
||||
}
|
||||
dir.size = old_size;
|
||||
|
||||
if (app->directory_cd(app, dir.str, &dir.size, dir.memory_size, literal("..")) == 0){
|
||||
keep_going = 0;
|
||||
app->print_message(app, literal("couldn't find build.bat\n"));
|
||||
}
|
||||
}
|
||||
|
||||
app->print_message(app, literal("couldn't find build.bat\n"));
|
||||
}
|
||||
|
||||
CUSTOM_COMMAND_SIG(auto_tab_line_at_cursor){
|
||||
|
|
|
@ -229,10 +229,7 @@ EXEC_SYSTEM_COMMAND_SIG(external_exec_system_command){
|
|||
|
||||
if (file){
|
||||
i32 proc_count = vars->cli_processes.count;
|
||||
View_Iter iter;
|
||||
i32 i;
|
||||
|
||||
for (i = 0; i < proc_count; ++i){
|
||||
for (i32 i = 0; i < proc_count; ++i){
|
||||
if (procs[i].out_file == file){
|
||||
if (flags & CLI_OverlapWithConflict){
|
||||
procs[i].out_file = 0;
|
||||
|
@ -249,7 +246,7 @@ EXEC_SYSTEM_COMMAND_SIG(external_exec_system_command){
|
|||
file->settings.unimportant = 1;
|
||||
|
||||
if (!(flags & CLI_AlwaysBindToView)){
|
||||
iter = file_view_iter_init(&models->layout, file, 0);
|
||||
View_Iter iter = file_view_iter_init(&models->layout, file, 0);
|
||||
if (file_view_iter_good(iter)){
|
||||
bind_to_new_view = 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Distribution Date: 11.6.2016 (dd.mm.yyyy)
|
||||
Distribution Date: 20.6.2016 (dd.mm.yyyy)
|
||||
|
||||
Thank you for contributing to the 4coder project!
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Distribution Date: 11.6.2016 (dd.mm.yyyy)
|
||||
Distribution Date: 20.6.2016 (dd.mm.yyyy)
|
||||
|
||||
Thank you for contributing to the 4coder project!
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ call "ctime" -begin 4ed_data.ctm
|
|||
|
||||
set OPTS=/W4 /wd4310 /wd4100 /wd4201 /wd4505 /wd4996 /wd4127 /wd4510 /wd4512 /wd4610 /wd4390 /WX
|
||||
set OPTS=%OPTS% /GR- /EHa- /nologo /FC
|
||||
set INCLUDES=/I..\foreign
|
||||
set INCLUDES=/I..\foreign /I..\foreign\freetype2
|
||||
set LIBS=user32.lib winmm.lib gdi32.lib opengl32.lib
|
||||
set LIBS=%LIBS% ..\foreign\freetype.lib
|
||||
set ICON=..\res\icon.res
|
||||
set DEFINES=
|
||||
set FirstError=0
|
||||
|
@ -31,7 +32,7 @@ set EXPORTS=/EXPORT:app_get_functions
|
|||
cl %OPTS% %INCLUDES% %DEFINES% ..\code\4ed_app_target.cpp %* /Fe4ed_app /LD /link /INCREMENTAL:NO /OPT:REF %EXPORTS%
|
||||
if %ERRORLEVEL% neq 0 (set FirstError=1)
|
||||
|
||||
cl %OPTS% %INCLUDES% %DEFINES% ..\code\win32_4ed.cpp %LIBS% %ICON% %* /Fe4ed
|
||||
cl %OPTS% %INCLUDES% %DEFINES% ..\code\win32_4ed.cpp %LIBS% %ICON% %* /Fe4ed /link /NODEFAULTLIB:library
|
||||
if %ERRORLEVEL% neq 0 (set FirstError=1)
|
||||
|
||||
call "print_size.bat" 4ed_app.dll
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// TOP
|
||||
|
||||
#define NO_BINDING
|
||||
#include "../4coder_default_bindings.cpp"
|
||||
#include "4coder_default_bindings.cpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include "system_shared.h"
|
||||
|
||||
#define SUPPORT_DPI 1
|
||||
#define USE_WIN32_FONTS 0
|
||||
#define USE_FT_FONTS 0
|
||||
#define USE_FT_FONTS 1
|
||||
|
||||
#define FPS 60
|
||||
#define frame_useconds (1000000 / FPS)
|
||||
|
@ -1170,6 +1171,7 @@ Font_Load_Sig(system_draw_font_load){
|
|||
}
|
||||
|
||||
i32 oversample = 2;
|
||||
AllowLocal(oversample);
|
||||
|
||||
#if SUPPORT_DPI
|
||||
pt_size = ROUND32(pt_size * size_change(win32vars.dpi_x, win32vars.dpi_y));
|
||||
|
@ -1189,7 +1191,11 @@ Font_Load_Sig(system_draw_font_load){
|
|||
|
||||
#elif USE_FT_FONTS
|
||||
|
||||
success = win32_ft_font_load();
|
||||
success = win32_ft_font_load(&win32vars.font_part,
|
||||
font_out,
|
||||
filename,
|
||||
pt_size,
|
||||
tab_width);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -1721,13 +1727,13 @@ Win32Callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
|||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
|
||||
typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, char * message, GLvoid * userParam);
|
||||
typedef GLDEBUGPROC_TYPE * GLDEBUGPROC;
|
||||
//typedef void GLDEBUGPROC_TYPE(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char * message, const GLvoid * userParam);
|
||||
//typedef GLDEBUGPROC_TYPE * GLDEBUGPROC;
|
||||
typedef void glDebugMessageControl_type(GLenum source, GLenum type, GLenum severity, GLsizei count, GLuint * ids, GLboolean enabled);
|
||||
typedef void glDebugMessageCallback_type(GLDEBUGPROC callback, void * userParam);
|
||||
|
||||
internal void
|
||||
OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, char *message, void *userParam)
|
||||
OpenGLDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, const void *userParam)
|
||||
{
|
||||
OutputDebugStringA(message);
|
||||
OutputDebugStringA("\n");
|
||||
|
|
|
@ -7,62 +7,11 @@
|
|||
|
||||
|
||||
#undef internal
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_LCD_FILTER_H
|
||||
#define internal static
|
||||
|
||||
//TODO(inso): put in linuxvars
|
||||
static FcConfig* fc;
|
||||
|
||||
internal char*
|
||||
linux_get_sys_font(char* name, i32 pt_size){
|
||||
char* result = 0;
|
||||
|
||||
if(!fc){
|
||||
fc = FcInitLoadConfigAndFonts();
|
||||
}
|
||||
|
||||
FcPattern* pat = FcPatternBuild(
|
||||
NULL,
|
||||
FC_POSTSCRIPT_NAME, FcTypeString, name,
|
||||
FC_SIZE, FcTypeDouble, (double)pt_size,
|
||||
FC_FONTFORMAT, FcTypeString, "TrueType",
|
||||
NULL
|
||||
);
|
||||
|
||||
FcConfigSubstitute(fc, pat, FcMatchPattern);
|
||||
FcDefaultSubstitute(pat);
|
||||
|
||||
FcResult res;
|
||||
FcPattern* font = FcFontMatch(fc, pat, &res);
|
||||
FcChar8* fname = 0;
|
||||
|
||||
if(font){
|
||||
FcPatternGetString(font, FC_FILE, 0, &fname);
|
||||
if(fname){
|
||||
result = strdup((char*)fname);
|
||||
fprintf(stderr, "Got system font from FontConfig: %s\n", result);
|
||||
}
|
||||
FcPatternDestroy(font);
|
||||
}
|
||||
|
||||
FcPatternDestroy(pat);
|
||||
|
||||
if(!result){
|
||||
char space[1024];
|
||||
String str = make_fixed_width_string(space);
|
||||
if(sysshared_to_binary_path(&str, name)){
|
||||
result = strdup(space);
|
||||
} else {
|
||||
result = strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal u32
|
||||
next_pow_of_2(u32 v){
|
||||
--v;
|
||||
|
@ -78,25 +27,23 @@ next_pow_of_2(u32 v){
|
|||
#define ENABLE_LCD_FILTER 0
|
||||
|
||||
internal b32
|
||||
win32_ft_font_load(Render_Font *rf, char *name, i32 pt_size, i32 tab_width){
|
||||
|
||||
#if 0
|
||||
char* filename = linux_get_sys_font(name, pt_size);
|
||||
#else
|
||||
char* filename = (char*)malloc(256);
|
||||
win32_ft_font_load(Partition *part, Render_Font *rf, char *name, i32 pt_size, i32 tab_width){
|
||||
|
||||
Temp_Memory temp = begin_temp_memory(part);
|
||||
|
||||
char* filename = push_array(part, char, 256);
|
||||
String str = make_string(filename, 0, 256);
|
||||
sysshared_to_binary_path(&str, name);
|
||||
#endif
|
||||
|
||||
|
||||
memset(rf, 0, sizeof(*rf));
|
||||
|
||||
|
||||
//TODO(inso): put stuff in linuxvars / init in main
|
||||
FT_Library ft;
|
||||
FT_Face face;
|
||||
b32 use_lcd_filter = 0;
|
||||
|
||||
|
||||
FT_Init_FreeType(&ft);
|
||||
|
||||
|
||||
//NOTE(inso): i'm not sure the LCD filter looks better, and it doesn't work perfectly with the coloring stuff
|
||||
#if ENABLE_LCD_FILTER
|
||||
if(FT_Library_SetLcdFilter(ft, FT_LCD_FILTER_DEFAULT) == 0){
|
||||
|
@ -105,138 +52,147 @@ win32_ft_font_load(Render_Font *rf, char *name, i32 pt_size, i32 tab_width){
|
|||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
FT_New_Face(ft, filename, 0, &face);
|
||||
|
||||
|
||||
// set size & metrics
|
||||
FT_Size_RequestRec_ size = {};
|
||||
size.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
|
||||
size.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
||||
size.height = pt_size << 6;
|
||||
FT_Request_Size(face, &size);
|
||||
|
||||
|
||||
rf->loaded = 1;
|
||||
rf->ascent = face->size->metrics.ascender / 64.0f;
|
||||
rf->descent = face->size->metrics.descender / 64.0f;
|
||||
rf->advance = face->size->metrics.max_advance / 64.0f;
|
||||
rf->height = face->size->metrics.height / 64.0f;
|
||||
rf->ascent = CEIL32 (face->size->metrics.ascender / 64.0f);
|
||||
rf->descent = FLOOR32 (face->size->metrics.descender / 64.0f);
|
||||
rf->advance = CEIL32 (face->size->metrics.max_advance / 64.0f);
|
||||
rf->height = CEIL32 (face->size->metrics.height / 64.0f);
|
||||
rf->line_skip = rf->height - (rf->ascent - rf->descent);
|
||||
|
||||
|
||||
rf->height -= rf->line_skip;
|
||||
rf->line_skip = 0;
|
||||
|
||||
int max_glyph_w = face->size->metrics.x_ppem;
|
||||
int max_glyph_h = rf->height;
|
||||
int tex_width = 64;
|
||||
int tex_height = 0;
|
||||
|
||||
|
||||
// estimate upper bound on texture width
|
||||
do {
|
||||
tex_width *= 2;
|
||||
float glyphs_per_row = ceilf(tex_width / (float) max_glyph_w);
|
||||
float rows = ceilf(NUM_GLYPHS / glyphs_per_row);
|
||||
tex_height = rows * (max_glyph_h + 2);
|
||||
tex_height = CEIL32(rows * (max_glyph_h + 2));
|
||||
} while(tex_height > tex_width);
|
||||
|
||||
|
||||
tex_height = next_pow_of_2(tex_height);
|
||||
|
||||
|
||||
int pen_x = 0;
|
||||
int pen_y = 0;
|
||||
|
||||
u32* pixels = (u32*) calloc(tex_width * tex_height, sizeof(u32));
|
||||
|
||||
|
||||
u32* pixels = push_array(part, u32, tex_width * tex_height);
|
||||
memset(pixels, 0, tex_width * tex_height * sizeof(u32));
|
||||
|
||||
// XXX: test if AUTOHINT looks better or not
|
||||
const u32 ft_extra_flags = use_lcd_filter ? FT_LOAD_TARGET_LCD : FT_LOAD_FORCE_AUTOHINT;
|
||||
|
||||
|
||||
for(int i = 0; i < NUM_GLYPHS; ++i){
|
||||
if(FT_Load_Char(face, i, FT_LOAD_RENDER | ft_extra_flags) != 0) continue;
|
||||
|
||||
|
||||
int w = face->glyph->bitmap.width;
|
||||
int h = face->glyph->bitmap.rows;
|
||||
|
||||
|
||||
// lcd filter produces RGB bitmaps, need to account for the extra components
|
||||
if(use_lcd_filter){
|
||||
w /= 3;
|
||||
}
|
||||
|
||||
|
||||
// move to next line if necessary
|
||||
if(pen_x + w >= tex_width){
|
||||
pen_x = 0;
|
||||
pen_y += (max_glyph_h + 2);
|
||||
}
|
||||
|
||||
|
||||
// set all this stuff the renderer needs
|
||||
stbtt_packedchar* c = rf->chardata + i;
|
||||
|
||||
c->x0 = pen_x;
|
||||
c->y0 = pen_y;
|
||||
c->x1 = pen_x + w;
|
||||
c->y1 = pen_y + h + 1;
|
||||
|
||||
c->xoff = face->glyph->bitmap_left;
|
||||
c->yoff = -face->glyph->bitmap_top;
|
||||
|
||||
Glyph_Data* c = rf->glyphs + i;
|
||||
|
||||
c->x0 = (f32)(pen_x);
|
||||
c->y0 = (f32)(pen_y);
|
||||
c->x1 = (f32)(pen_x + w);
|
||||
c->y1 = (f32)(pen_y + h + 1);
|
||||
|
||||
c->xoff = (f32)(face->glyph->bitmap_left);
|
||||
c->yoff = (f32)(rf->ascent - face->glyph->bitmap_top);
|
||||
|
||||
c->xoff2 = w + c->xoff;
|
||||
c->yoff2 = h + c->yoff + 1;
|
||||
|
||||
c->xadvance = face->glyph->advance.x >> 6;
|
||||
|
||||
rf->advance_data[i] = c->xadvance;
|
||||
|
||||
rf->advance_data[i] = (f32)(face->glyph->advance.x >> 6);
|
||||
|
||||
rf->glyphs[i].exists = 1;
|
||||
|
||||
|
||||
|
||||
|
||||
int pitch = face->glyph->bitmap.pitch;
|
||||
|
||||
|
||||
// write to texture atlas
|
||||
for(int j = 0; j < h; ++j){
|
||||
for(int i = 0; i < w; ++i){
|
||||
int x = pen_x + i;
|
||||
int y = pen_y + j;
|
||||
|
||||
|
||||
if(use_lcd_filter){
|
||||
u8 r = face->glyph->bitmap.buffer[j * pitch + i * 3];
|
||||
u8 g = face->glyph->bitmap.buffer[j * pitch + i * 3 + 1];
|
||||
u8 b = face->glyph->bitmap.buffer[j * pitch + i * 3 + 2];
|
||||
u8 a = (r + g + b) / 3.0f;
|
||||
|
||||
u8 a = (u8)ROUND32((r + g + b) / 3.0f);
|
||||
|
||||
pixels[y * tex_width + x] = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
} else {
|
||||
pixels[y * tex_width + x] = face->glyph->bitmap.buffer[j * pitch + i] * 0x1010101;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pen_x = c->x1 + 1;
|
||||
|
||||
pen_x = CEIL32(c->x1 + 1);
|
||||
}
|
||||
|
||||
rf->chardata['\r'] = rf->chardata[' '];
|
||||
rf->chardata['\n'] = rf->chardata[' '];
|
||||
rf->chardata['\t'] = rf->chardata[' '];
|
||||
rf->chardata['\t'].xadvance *= tab_width;
|
||||
|
||||
|
||||
Glyph_Data space_glyph = rf->glyphs[' '];
|
||||
f32 space_width = rf->advance_data[' '];
|
||||
|
||||
rf->glyphs['\r'] = space_glyph;
|
||||
rf->advance_data['\r'] = space_width*tab_width;
|
||||
|
||||
rf->glyphs['\n'] = space_glyph;
|
||||
rf->advance_data['\n'] = space_width*tab_width;
|
||||
|
||||
rf->glyphs['\t'] = space_glyph;
|
||||
rf->advance_data['\t'] = space_width*tab_width;
|
||||
|
||||
FT_Done_FreeType(ft);
|
||||
|
||||
|
||||
tex_height = next_pow_of_2(pen_y + max_glyph_h + 2);
|
||||
|
||||
|
||||
rf->tex_width = tex_width;
|
||||
rf->tex_height = tex_height;
|
||||
|
||||
|
||||
// upload texture
|
||||
glGenTextures(1, &rf->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, rf->tex);
|
||||
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
|
||||
if(use_lcd_filter){
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tex_width, tex_height, 0, GL_ALPHA, GL_UNSIGNED_INT, pixels);
|
||||
}
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
free(pixels);
|
||||
free(filename);
|
||||
|
||||
|
||||
end_temp_memory(temp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue