font: font_print_rect -> font_clip + scissor test

main
Dominik Madarász 2024-02-10 17:05:45 +01:00
parent 65b57039a2
commit 3a853d09d7
7 changed files with 88 additions and 49 deletions

View File

@ -680,7 +680,7 @@ typedef struct font_metrics_t {
vec2 font_xy(); vec2 font_xy();
void font_goto(float x, float y); void font_goto(float x, float y);
vec2 font_print(const char *text); vec2 font_print(const char *text);
vec2 font_print_rect(const char *text, vec4 rect); vec2 font_clip(const char *text, vec4 rect);
vec2 font_rect(const char *text); vec2 font_rect(const char *text);
font_metrics_t font_metrics(const char *text); font_metrics_t font_metrics(const char *text);
void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords); void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords);

View File

@ -133,19 +133,37 @@ int main() {
vec2 size=font_rect(txt); vec2 size=font_rect(txt);
font_metrics_t m=font_metrics(txt); font_metrics_t m=font_metrics(txt);
ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y-m.descent+m.linegap+100,0)); ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y-m.descent+m.linegap+100,0));
font_print_rect(txt, vec4(pos.x, pos.y, size.x, size.y+100)); font_clip(txt, vec4(pos.x, pos.y, size.x, size.y+100));
ddraw_pop_2d();
}
{
vec2 pos = vec2(1490,240);
ddraw_push_2d();
char *txt = "This is the first line.\nAnd now the second line.\nYou can do a third great line, too!\nNow this is a very long line aaaaaaaaaa!\n";
font_goto(pos.x, pos.y);
vec2 size=font_rect(txt);
size.y -= 20; // artifically shrink textbox to test clipping
font_metrics_t m=font_metrics(txt);
ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y-m.descent+m.linegap,0));
font_clip(txt, vec4(pos.x, pos.y, size.x, size.y));
ddraw_pop_2d(); ddraw_pop_2d();
} }
{ {
vec2 pos = vec2(1990,820); vec2 pos = vec2(1990,820);
ddraw_push_2d(); ddraw_push_2d();
char *txt = FONT_RIGHT FONT_BOTTOM FONT_WHITE "This is the first line.\n" FONT_LIME "And now the second line.\n" FONT_WHITE "You can do a third" FONT_ORANGE " great" FONT_WHITE " line, too!\n"; char *txt = FONT_RIGHT FONT_BOTTOM
FONT_WHITE "This is the first line.\n"
FONT_LIME "And now the second line.\n"
FONT_WHITE "You can do a third"
FONT_ORANGE " great"
FONT_WHITE " line, too!\n";
font_goto(pos.x, pos.y); font_goto(pos.x, pos.y);
vec2 size=font_rect(txt); vec2 size=font_rect(txt);
font_metrics_t m=font_metrics(txt); font_metrics_t m=font_metrics(txt);
ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y-m.descent+m.linegap+100,0)); ddraw_aabb(vec3(pos.x,pos.y,0), vec3(pos.x+size.x,pos.y+size.y-m.descent+m.linegap+100,0));
font_print_rect(txt, vec4(pos.x, pos.y, size.x, size.y+100)); font_clip(txt, vec4(pos.x, pos.y, size.x, size.y+100));
ddraw_pop_2d(); ddraw_pop_2d();
} }

View File

@ -16146,10 +16146,9 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect); API vec2 font_clip(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright);
// void font_wrap(vec2 topleft, vec2 bottomright); // void font_wrap(vec2 topleft, vec2 bottomright);
// syntax highlighting // syntax highlighting
@ -363522,7 +363521,7 @@ void font_face(const char *tag, const char *filename_ttf, float font_size, unsig
} }
static static
void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset) { void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset, vec4 rect) {
// Backup GL state // Backup GL state
GLint last_program, last_vertex_array; GLint last_program, last_vertex_array;
GLint last_texture0, last_texture1, last_texture2; GLint last_texture0, last_texture1, last_texture2;
@ -363546,12 +363545,17 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup render state: alpha-blending enabled, no depth testing and bind textures // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// @fixme: store existing scissor test setup
glEnable(GL_SCISSOR_TEST);
glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@ -363597,13 +363601,14 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
(last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST));
(last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND));
(last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST));
} }
// 1. call font_face() if it's the first time it's called. // 1. call font_face() if it's the first time it's called.
// 1. parse the string and update the instance vbo, then upload it // 1. parse the string and update the instance vbo, then upload it
// 1. draw the string // 1. draw the string
static static
vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2)) { vec2 font_draw_ex(const char *text, vec2 offset, vec4 rect, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2,vec4)) {
font_init(); font_init();
// sanity checks // sanity checks
@ -363643,7 +363648,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
} }
if( ch >= 1 && ch <= 6 ) { if( ch >= 1 && ch <= 6 ) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// reposition offset to align new baseline // reposition offset to align new baseline
@ -363664,7 +363669,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
if( ch >= 0x10 && ch <= 0x19 ) { if( ch >= 0x10 && ch <= 0x19 ) {
if( fonts[ ch - 0x10 ].initialized) { if( fonts[ ch - 0x10 ].initialized) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// change face // change face
@ -363691,7 +363696,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
X += f->cdata[cp].xadvance*f->scale[S]; X += f->cdata[cp].xadvance*f->scale[S];
} }
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
//if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist); //if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist);
return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL)); return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL));
@ -363932,7 +363937,7 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print_rect(const char *text, vec4 rect) { vec2 font_clip(const char *text, vec4 rect) {
int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0; int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0;
while ( text[0] == FONT_LEFT[0] ) { while ( text[0] == FONT_LEFT[0] ) {
@ -363998,14 +364003,14 @@ vec2 font_print_rect(const char *text, vec4 rect) {
int gaps = array_count(words) - 1; int gaps = array_count(words) - 1;
float space_offset = gaps > 0 ? extra_space / (float)gaps : 0; float space_offset = gaps > 0 ? extra_space / (float)gaps : 0;
for (int k = 0; k < array_count(words); ++k) { for (int k = 0; k < array_count(words); ++k) {
vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, rect, NULL, font_draw_cmd);
gotoxy.x += dims.x + space_offset; gotoxy.x += dims.x + space_offset;
} }
gotoxy.x = rect.x; gotoxy.x = rect.x;
} }
if (!j) { if (!j) {
font_draw_ex(line, gotoxy, NULL, font_draw_cmd); font_draw_ex(line, gotoxy, rect, NULL, font_draw_cmd);
} }
gotoxy.y += text_rect.y; gotoxy.y += text_rect.y;
@ -364020,7 +364025,7 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 text_rect = font_rect(text); vec2 text_rect = font_rect(text);
gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
} }
vec2 dims = font_draw_ex(text, gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, rect, NULL, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x;
return dims; return dims;
@ -364029,12 +364034,13 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 font_print(const char *text) { vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()}; vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims); return font_clip(text, dims);
} }
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec4 screen_dim = {0, 0, window_width(), window_height()};
vec2 dims = font_draw_ex(text, gotoxy, screen_dim, (const char *)colors, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x;
return dims; return dims;
@ -364042,7 +364048,8 @@ vec2 font_highlight(const char *text, const void *colors) {
// Calculate the size of a string, in the pixel size specified. Count stray newlines too. // Calculate the size of a string, in the pixel size specified. Count stray newlines too.
vec2 font_rect(const char *str) { vec2 font_rect(const char *str) {
return font_draw_ex(str, gotoxy, NULL, NULL); vec4 dims = {0, 0, window_width(), window_height()};
return font_draw_ex(str, gotoxy, dims, NULL, NULL);
} }
font_metrics_t font_metrics(const char *text) { font_metrics_t font_metrics(const char *text) {

View File

@ -1964,7 +1964,7 @@ void font_face(const char *tag, const char *filename_ttf, float font_size, unsig
} }
static static
void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset) { void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset, vec4 rect) {
// Backup GL state // Backup GL state
GLint last_program, last_vertex_array; GLint last_program, last_vertex_array;
GLint last_texture0, last_texture1, last_texture2; GLint last_texture0, last_texture1, last_texture2;
@ -1988,12 +1988,17 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup render state: alpha-blending enabled, no depth testing and bind textures // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// @fixme: store existing scissor test setup
glEnable(GL_SCISSOR_TEST);
glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@ -2039,13 +2044,14 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
(last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST));
(last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND));
(last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST));
} }
// 1. call font_face() if it's the first time it's called. // 1. call font_face() if it's the first time it's called.
// 1. parse the string and update the instance vbo, then upload it // 1. parse the string and update the instance vbo, then upload it
// 1. draw the string // 1. draw the string
static static
vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2)) { vec2 font_draw_ex(const char *text, vec2 offset, vec4 rect, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2,vec4)) {
font_init(); font_init();
// sanity checks // sanity checks
@ -2085,7 +2091,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
} }
if( ch >= 1 && ch <= 6 ) { if( ch >= 1 && ch <= 6 ) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// reposition offset to align new baseline // reposition offset to align new baseline
@ -2106,7 +2112,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
if( ch >= 0x10 && ch <= 0x19 ) { if( ch >= 0x10 && ch <= 0x19 ) {
if( fonts[ ch - 0x10 ].initialized) { if( fonts[ ch - 0x10 ].initialized) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// change face // change face
@ -2133,7 +2139,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
X += f->cdata[cp].xadvance*f->scale[S]; X += f->cdata[cp].xadvance*f->scale[S];
} }
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
//if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist); //if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist);
return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL)); return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL));
@ -2374,7 +2380,7 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print_rect(const char *text, vec4 rect) { vec2 font_clip(const char *text, vec4 rect) {
int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0; int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0;
while ( text[0] == FONT_LEFT[0] ) { while ( text[0] == FONT_LEFT[0] ) {
@ -2440,14 +2446,14 @@ vec2 font_print_rect(const char *text, vec4 rect) {
int gaps = array_count(words) - 1; int gaps = array_count(words) - 1;
float space_offset = gaps > 0 ? extra_space / (float)gaps : 0; float space_offset = gaps > 0 ? extra_space / (float)gaps : 0;
for (int k = 0; k < array_count(words); ++k) { for (int k = 0; k < array_count(words); ++k) {
vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, rect, NULL, font_draw_cmd);
gotoxy.x += dims.x + space_offset; gotoxy.x += dims.x + space_offset;
} }
gotoxy.x = rect.x; gotoxy.x = rect.x;
} }
if (!j) { if (!j) {
font_draw_ex(line, gotoxy, NULL, font_draw_cmd); font_draw_ex(line, gotoxy, rect, NULL, font_draw_cmd);
} }
gotoxy.y += text_rect.y; gotoxy.y += text_rect.y;
@ -2462,7 +2468,7 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 text_rect = font_rect(text); vec2 text_rect = font_rect(text);
gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
} }
vec2 dims = font_draw_ex(text, gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, rect, NULL, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x;
return dims; return dims;
@ -2471,12 +2477,13 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 font_print(const char *text) { vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()}; vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims); return font_clip(text, dims);
} }
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec4 screen_dim = {0, 0, window_width(), window_height()};
vec2 dims = font_draw_ex(text, gotoxy, screen_dim, (const char *)colors, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x;
return dims; return dims;
@ -2484,7 +2491,8 @@ vec2 font_highlight(const char *text, const void *colors) {
// Calculate the size of a string, in the pixel size specified. Count stray newlines too. // Calculate the size of a string, in the pixel size specified. Count stray newlines too.
vec2 font_rect(const char *str) { vec2 font_rect(const char *str) {
return font_draw_ex(str, gotoxy, NULL, NULL); vec4 dims = {0, 0, window_width(), window_height()};
return font_draw_ex(str, gotoxy, dims, NULL, NULL);
} }
font_metrics_t font_metrics(const char *text) { font_metrics_t font_metrics(const char *text) {

View File

@ -89,10 +89,9 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect); API vec2 font_clip(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright);
// void font_wrap(vec2 topleft, vec2 bottomright); // void font_wrap(vec2 topleft, vec2 bottomright);
// syntax highlighting // syntax highlighting

View File

@ -10662,7 +10662,7 @@ void font_face(const char *tag, const char *filename_ttf, float font_size, unsig
} }
static static
void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset) { void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float factor, vec2 offset, vec4 rect) {
// Backup GL state // Backup GL state
GLint last_program, last_vertex_array; GLint last_program, last_vertex_array;
GLint last_texture0, last_texture1, last_texture2; GLint last_texture0, last_texture1, last_texture2;
@ -10686,12 +10686,17 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
// Setup render state: alpha-blending enabled, no depth testing and bind textures // Setup render state: alpha-blending enabled, no depth testing, enable clipping and bind textures
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// @fixme: store existing scissor test setup
glEnable(GL_SCISSOR_TEST);
glScissor(rect.x, window_height() - (rect.y+rect.w), rect.z, rect.w);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@ -10737,13 +10742,14 @@ void font_draw_cmd(font_t *f, const float *glyph_data, int glyph_idx, float fact
(last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); (last_enable_depth_test ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST));
(last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); (last_enable_blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND));
(last_scissor_test ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST));
} }
// 1. call font_face() if it's the first time it's called. // 1. call font_face() if it's the first time it's called.
// 1. parse the string and update the instance vbo, then upload it // 1. parse the string and update the instance vbo, then upload it
// 1. draw the string // 1. draw the string
static static
vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2)) { vec2 font_draw_ex(const char *text, vec2 offset, vec4 rect, const char *col, void (*draw_cmd)(font_t *,const float *,int,float,vec2,vec4)) {
font_init(); font_init();
// sanity checks // sanity checks
@ -10783,7 +10789,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
} }
if( ch >= 1 && ch <= 6 ) { if( ch >= 1 && ch <= 6 ) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// reposition offset to align new baseline // reposition offset to align new baseline
@ -10804,7 +10810,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
if( ch >= 0x10 && ch <= 0x19 ) { if( ch >= 0x10 && ch <= 0x19 ) {
if( fonts[ ch - 0x10 ].initialized) { if( fonts[ ch - 0x10 ].initialized) {
// flush previous state // flush previous state
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
t = text_glyph_data; t = text_glyph_data;
// change face // change face
@ -10831,7 +10837,7 @@ vec2 font_draw_ex(const char *text, vec2 offset, const char *col, void (*draw_cm
X += f->cdata[cp].xadvance*f->scale[S]; X += f->cdata[cp].xadvance*f->scale[S];
} }
if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset); if(draw_cmd) draw_cmd(f, text_glyph_data, (t - text_glyph_data)/4, f->scale[S], offset, rect);
//if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist); //if(strstr(text, "fps")) printf("(%f,%f) (%f) L:%f LINEDIST:%f\n", X, Y, W, L, f->linedist);
return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL)); return abs2(vec2(W*W > X*X ? W : X, Y*Y > LL*LL ? Y : LL));
@ -11072,7 +11078,7 @@ void font_goto(float x, float y) {
} }
// Print and linefeed. Text may include markup code // Print and linefeed. Text may include markup code
vec2 font_print_rect(const char *text, vec4 rect) { vec2 font_clip(const char *text, vec4 rect) {
int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0; int l=0,c=0,r=0,j=0,t=0,b=0,m=0,B=0;
while ( text[0] == FONT_LEFT[0] ) { while ( text[0] == FONT_LEFT[0] ) {
@ -11138,14 +11144,14 @@ vec2 font_print_rect(const char *text, vec4 rect) {
int gaps = array_count(words) - 1; int gaps = array_count(words) - 1;
float space_offset = gaps > 0 ? extra_space / (float)gaps : 0; float space_offset = gaps > 0 ? extra_space / (float)gaps : 0;
for (int k = 0; k < array_count(words); ++k) { for (int k = 0; k < array_count(words); ++k) {
vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(va("%s%s", tags, words[k]), gotoxy, rect, NULL, font_draw_cmd);
gotoxy.x += dims.x + space_offset; gotoxy.x += dims.x + space_offset;
} }
gotoxy.x = rect.x; gotoxy.x = rect.x;
} }
if (!j) { if (!j) {
font_draw_ex(line, gotoxy, NULL, font_draw_cmd); font_draw_ex(line, gotoxy, rect, NULL, font_draw_cmd);
} }
gotoxy.y += text_rect.y; gotoxy.y += text_rect.y;
@ -11160,7 +11166,7 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 text_rect = font_rect(text); vec2 text_rect = font_rect(text);
gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1; gotoxy.y = t ? rect.y : b ? ((rect.y+rect.w) - text_rect.y) : m ? rect.y+rect.w/2.-text_rect.y/2. : rect.y+rect.w/2.-text_rect.y/1;
} }
vec2 dims = font_draw_ex(text, gotoxy, NULL, font_draw_cmd); vec2 dims = font_draw_ex(text, gotoxy, rect, NULL, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? rect.x : gotoxy.x + dims.x;
return dims; return dims;
@ -11169,12 +11175,13 @@ vec2 font_print_rect(const char *text, vec4 rect) {
vec2 font_print(const char *text) { vec2 font_print(const char *text) {
vec4 dims = {0, 0, window_width(), window_height()}; vec4 dims = {0, 0, window_width(), window_height()};
return font_print_rect(text, dims); return font_clip(text, dims);
} }
// Print a code snippet with syntax highlighting // Print a code snippet with syntax highlighting
vec2 font_highlight(const char *text, const void *colors) { vec2 font_highlight(const char *text, const void *colors) {
vec2 dims = font_draw_ex(text, gotoxy, (const char *)colors, font_draw_cmd); vec4 screen_dim = {0, 0, window_width(), window_height()};
vec2 dims = font_draw_ex(text, gotoxy, screen_dim, (const char *)colors, font_draw_cmd);
gotoxy.y += strchr(text, '\n') ? dims.y : 0; gotoxy.y += strchr(text, '\n') ? dims.y : 0;
gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x; gotoxy.x = strchr(text, '\n') ? 0 : gotoxy.x + dims.x;
return dims; return dims;
@ -11182,7 +11189,8 @@ vec2 font_highlight(const char *text, const void *colors) {
// Calculate the size of a string, in the pixel size specified. Count stray newlines too. // Calculate the size of a string, in the pixel size specified. Count stray newlines too.
vec2 font_rect(const char *str) { vec2 font_rect(const char *str) {
return font_draw_ex(str, gotoxy, NULL, NULL); vec4 dims = {0, 0, window_width(), window_height()};
return font_draw_ex(str, gotoxy, dims, NULL, NULL);
} }
font_metrics_t font_metrics(const char *text) { font_metrics_t font_metrics(const char *text) {

View File

@ -2213,10 +2213,9 @@ API void font_color(const char *color_tag, uint32_t color);
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_print_rect(const char *text, vec4 rect); API vec2 font_clip(const char *text, vec4 rect);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// void font_clip(vec2 topleft, vec2 bottomright);
// void font_wrap(vec2 topleft, vec2 bottomright); // void font_wrap(vec2 topleft, vec2 bottomright);
// syntax highlighting // syntax highlighting