center text

master
Alessandro Mauri 1 year ago
parent 0a18bfc951
commit 2ada5113a1
Signed by: alema
GPG Key ID: 2B7BF9531FF03BE8
  1. 23
      text_rendering/font.c
  2. 17
      text_rendering/main.c
  3. 76
      text_rendering/ren.c

@ -107,8 +107,8 @@ int font_free(struct font_atlas *atlas)
// errors height and width must be equal // errors height and width must be equal
const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code, int *updated) const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsigned int code, int *updated)
{ {
int u = 0; int _u = 0;
if (!updated) updated = &u; if (!updated) updated = &_u;
const struct font_glyph *r; const struct font_glyph *r;
if ((r = cache_search(&PRIV(atlas)->c, code)) != NULL) { if ((r = cache_search(&PRIV(atlas)->c, code)) != NULL) {
@ -120,7 +120,8 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig
// generate the sdf and put it into the cache // generate the sdf and put it into the cache
// TODO: generate the whole block at once // TODO: generate the whole block at once
int idx = stbtt_FindGlyphIndex(&PRIV(atlas)->stb, code); int idx = stbtt_FindGlyphIndex(&PRIV(atlas)->stb, code);
int x0,y0,x1,y1,gw,gh,l,off_x,off_y,adv; int x0,y0,x1,y1,gw,gh,l,off_x,off_y,adv,base;
base = atlas->glyph_max_h - PRIV(atlas)->baseline;
stbtt_GetGlyphBitmapBoxSubpixel( stbtt_GetGlyphBitmapBoxSubpixel(
&PRIV(atlas)->stb, &PRIV(atlas)->stb,
idx, idx,
@ -149,19 +150,19 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig
// TODO: bounds check usign atlas height // TODO: bounds check usign atlas height
// TODO: clear spot area in the atlas before writing on it // TODO: clear spot area in the atlas before writing on it
unsigned int spot = cache_get(&PRIV(atlas)->c); unsigned int spot = cache_get(&PRIV(atlas)->c);
unsigned int oy = ((atlas->glyph_max_w * spot) / atlas->width) * atlas->glyph_max_h; unsigned int ty = ((atlas->glyph_max_w * spot) / atlas->width) * atlas->glyph_max_h;
unsigned int ox = (atlas->glyph_max_w * spot) % atlas->width; unsigned int tx = (atlas->glyph_max_w * spot) % atlas->width;
unsigned int w = atlas->width; unsigned int w = atlas->width;
unsigned char *a = (void *)atlas->atlas; unsigned char *a = (void *)atlas->atlas;
//printf("max:%d %d spot:%d : %d %d %d %d\n", atlas->glyph_max_w, atlas->glyph_max_h, spot, ox, oy, off_x, off_y); //printf("max:%d %d spot:%d : %d %d %d %d\n", atlas->glyph_max_w, atlas->glyph_max_h, spot, tx, ty, off_x, off_y);
for (int y = 0; y < gh; y++) { for (int y = 0; y < gh; y++) {
for (int x = 0; x < gw; x++) { for (int x = 0; x < gw; x++) {
int c, r; int c, r;
r = (oy+y)*w; r = (ty+y)*w;
c = ox+x; c = tx+x;
a[r+c] = PRIV(atlas)->bitmap[y*atlas->glyph_max_w+x]; a[r+c] = PRIV(atlas)->bitmap[y*atlas->glyph_max_w+x];
} }
} }
@ -169,12 +170,12 @@ const struct font_glyph * font_get_glyph_texture(struct font_atlas *atlas, unsig
// FIXME: get the advance // FIXME: get the advance
struct font_glyph g = { struct font_glyph g = {
.codepoint = code, .codepoint = code,
.u = ox, .u = tx,
.v = oy, .v = ty,
.w = gw, .w = gw,
.h = gh, .h = gh,
.x = off_x, .x = off_x,
.y = off_y, .y = off_y-base,
.a = adv, .a = adv,
}; };
return cache_insert(&PRIV(atlas)->c, &g, g.codepoint, spot); return cache_insert(&PRIV(atlas)->c, &g, g.codepoint, spot);

@ -8,7 +8,9 @@
#include "util.h" #include "util.h"
const char *str = "Ciao Mamma!\nprova: òçà°ù§|¬³¼$£ì\t"; //const char *str1 = "Ciao Mamma!\nprova: òçà°ù§|¬³¼$£ì\t";
const char *str1 = "j";
const char *str2 = "gmt";
SDL_Window *win; SDL_Window *win;
@ -17,10 +19,14 @@ void draw(void)
static unsigned int frame = 0; static unsigned int frame = 0;
printf("frame: %d\n", frame++); printf("frame: %d\n", frame++);
ren_clear(); ren_clear();
if (ren_render_text(str, 10, 10, 100, 50, 20)) ren_render_box(10, 10, 100, 50, 0xffff0000);
if (ren_render_text(str1, 10, 10, 100, 50, 20))
printf("text: %s\n", ren_strerror()); printf("text: %s\n", ren_strerror());
ren_render_text("altro font", 200, 40, 300, 300, 40); int w, h;
ren_render_box(100, 300, 50, 50, 0xffff0000); ren_get_text_box(str2, &w, &h, 40);
printf("box for: %s -> (%d, %d)\n", str2, w, h);
ren_render_box(200, 40, w, h, 0xffff0000);
ren_render_text(str2, 200, 40, 300, 300, 40);
SDL_GL_SwapWindow(win); SDL_GL_SwapWindow(win);
} }
@ -30,6 +36,7 @@ int main(void)
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
win = SDL_CreateWindow( win = SDL_CreateWindow(
"test render", "test render",
@ -37,7 +44,7 @@ int main(void)
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
500, 500,
500, 500,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
if (ren_init(win)) { if (ren_init(win)) {
printf("renderer init error: %s\n", ren_strerror()); printf("renderer init error: %s\n", ren_strerror());
return 1; return 1;

@ -1,7 +1,6 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <SDL2/SDL_opengl.h> #include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_video.h>
#include <ctype.h> #include <ctype.h>
#include <grapheme.h> #include <grapheme.h>
#include <stdio.h> #include <stdio.h>
@ -19,6 +18,7 @@
__FILE__, __LINE__, __func__, x, a, glerr[a]); \ __FILE__, __LINE__, __func__, x, a, glerr[a]); \
} }
#define GL(f) f; GLERR(#f) #define GL(f) f; GLERR(#f)
#define REN_RET(a,b) {ren_errno = b; return a;}
enum REN_ERR { enum REN_ERR {
@ -101,29 +101,29 @@ static int ren_errno;
// print shader compilation errors // print shader compilation errors
static int shader_compile_error(GLuint shader) static int shader_compile_error(GLuint shader, const char *path)
{ {
GLint status; GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &status))
if (status != GL_FALSE) if (status != GL_FALSE)
return 0; return 0;
GLint log_length; GLint log_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); GL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length))
GLchar *log_str = emalloc((log_length + 1)*sizeof(GLchar)); GLchar *log_str = emalloc((log_length + 1)*sizeof(GLchar));
glGetShaderInfoLog(shader, log_length, NULL, log_str); GL(glGetShaderInfoLog(shader, log_length, NULL, log_str))
const char *shader_type_str = NULL; const char *shader_type_str = NULL;
GLint shader_type; GLint shader_type;
glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type); GL(glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type))
switch(shader_type) { switch(shader_type) {
case GL_VERTEX_SHADER: shader_type_str = "vertex"; break; case GL_VERTEX_SHADER: shader_type_str = "vertex"; break;
case GL_GEOMETRY_SHADER: shader_type_str = "geometry"; break; case GL_GEOMETRY_SHADER: shader_type_str = "geometry"; break;
case GL_FRAGMENT_SHADER: shader_type_str = "fragment"; break; case GL_FRAGMENT_SHADER: shader_type_str = "fragment"; break;
} }
fprintf(stderr, "Compile failure in %s shader:\n%s\n", shader_type_str, log_str); fprintf(stderr, "Compile failure in %s shader %s:\n%s\n", shader_type_str, path, log_str);
efree(log_str); efree(log_str);
return -1; return -1;
} }
@ -133,15 +133,15 @@ static int shader_compile_error(GLuint shader)
static int shader_link_error(GLuint prog) static int shader_link_error(GLuint prog)
{ {
GLint status; GLint status;
glGetProgramiv (prog, GL_LINK_STATUS, &status); GL(glGetProgramiv(prog, GL_LINK_STATUS, &status))
if (status != GL_FALSE) if (status != GL_FALSE)
return 0; return 0;
GLint log_length; GLint log_length;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length); GL(glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length))
GLchar *log_str = emalloc((log_length + 1)*sizeof(GLchar)); GLchar *log_str = emalloc((log_length + 1)*sizeof(GLchar));
glGetProgramInfoLog(prog, log_length, NULL, log_str); GL(glGetProgramInfoLog(prog, log_length, NULL, log_str))
fprintf(stderr, "Linker failure: %s\n", log_str); fprintf(stderr, "Linker failure: %s\n", log_str);
efree(log_str); efree(log_str);
@ -149,8 +149,7 @@ static int shader_link_error(GLuint prog)
} }
#define REN_RET(a,b) {ren_errno = b; return a;} static GLuint shader_compile(const char *path, const char *shader, GLuint type)
static GLuint shader_compile(const char *shader, GLuint type)
{ {
GLuint s; GLuint s;
// initialize the vertex shader and get the corresponding id // initialize the vertex shader and get the corresponding id
@ -159,7 +158,7 @@ static GLuint shader_compile(const char *shader, GLuint type)
// get the shader into opengl // get the shader into opengl
GL(glShaderSource(s, 1, &shader, NULL)) GL(glShaderSource(s, 1, &shader, NULL))
GL(glCompileShader(s)) GL(glCompileShader(s))
if (shader_compile_error(s)) if (shader_compile_error(s, path))
REN_RET(0, REN_COMPILE) REN_RET(0, REN_COMPILE)
return s; return s;
} }
@ -184,14 +183,14 @@ static GLuint ren_compile_program(const char *vs_path, const char *fs_path)
dump_file(vs_path, &str, NULL); dump_file(vs_path, &str, NULL);
if (!str) REN_RET(0, REN_ERRNO) if (!str) REN_RET(0, REN_ERRNO)
gl_vertshader = shader_compile(str, GL_VERTEX_SHADER); gl_vertshader = shader_compile(vs_path, str, GL_VERTEX_SHADER);
efree(str); efree(str);
if (!gl_vertshader) if (!gl_vertshader)
return 0; return 0;
dump_file(fs_path, &str, NULL); dump_file(fs_path, &str, NULL);
if (!str) REN_RET(0, REN_ERRNO) if (!str) REN_RET(0, REN_ERRNO)
gl_fragshader = shader_compile(str, GL_FRAGMENT_SHADER); gl_fragshader = shader_compile(fs_path, str, GL_FRAGMENT_SHADER);
efree(str); efree(str);
if (!gl_fragshader) if (!gl_fragshader)
return 0; return 0;
@ -218,6 +217,15 @@ static GLuint ren_compile_program(const char *vs_path, const char *fs_path)
} }
static void set_texture_parameters(GLuint type, GLuint wrap_s, GLuint wrap_t, GLuint upscale, GLuint downscale)
{
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, upscale))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscale))
}
static GLuint ren_texturergb_2d(const char *buf, int w, int h, int upscale, int downscale) static GLuint ren_texturergb_2d(const char *buf, int w, int h, int upscale, int downscale)
{ {
GLuint t; GLuint t;
@ -231,24 +239,12 @@ static GLuint ren_texturergb_2d(const char *buf, int w, int h, int upscale, int
GL(glBindTexture(GL_TEXTURE_2D, t)) GL(glBindTexture(GL_TEXTURE_2D, t))
GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, buf)) GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, buf))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)) set_texture_parameters(GL_TEXTURE_2D, GL_REPEAT, GL_REPEAT, upscale, downscale);
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscale))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, upscale))
return t; return t;
} }
static void set_texture_parameters(GLuint type, GLuint wrap_s, GLuint wrap_t, GLuint upscale, GLuint downscale)
{
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, upscale))
GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, downscale))
}
static GLuint ren_texturergba_2d(const char *buf, int w, int h, int upscale, int downscale) static GLuint ren_texturergba_2d(const char *buf, int w, int h, int upscale, int downscale)
{ {
GLuint t; GLuint t;
@ -374,17 +370,27 @@ int ren_init(SDL_Window *w)
// Initialize OpenGL // Initialize OpenGL
if (!w) if (!w)
REN_RET(-1, REN_INVAL) REN_RET(-1, REN_INVAL)
// using version 3 does not allow to use glVertexAttribPointer() without
// vertex buffer objects
// TODO: make the switch to opengl 3.3 to go with the shader versions
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
ren.gl = SDL_GL_CreateContext(w); ren.gl = SDL_GL_CreateContext(w);
if (!ren.gl) if (!ren.gl) {
printf("SDL: %s\n", SDL_GetError());
REN_RET(-1, REN_CONTEXT) REN_RET(-1, REN_CONTEXT)
}
GL(glEnable(GL_BLEND)) GL(glEnable(GL_BLEND))
GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)) GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA))
GL(glDisable(GL_CULL_FACE)) GL(glDisable(GL_CULL_FACE))
GL(glDisable(GL_DEPTH_TEST)) GL(glDisable(GL_DEPTH_TEST))
GL(glEnable(GL_SCISSOR_TEST)) GL(glEnable(GL_SCISSOR_TEST))
GL(glEnable(GL_TEXTURE_2D)) // GL(glEnable(GL_TEXTURE_2D))
GL(glEnable(GL_TEXTURE_RECTANGLE)) // GL(glEnable(GL_TEXTURE_RECTANGLE))
GLenum glew_err = glewInit(); GLenum glew_err = glewInit();
if (glew_err != GLEW_OK) if (glew_err != GLEW_OK)
@ -492,6 +498,7 @@ static int ren_draw_font_stack(int idx)
GL(glDisableVertexAttribArray(REN_VERTEX_IDX)) GL(glDisableVertexAttribArray(REN_VERTEX_IDX))
GL(glDisableVertexAttribArray(REN_UV_IDX)) GL(glDisableVertexAttribArray(REN_UV_IDX))
GL(glBindBuffer(GL_ARRAY_BUFFER, 0)) GL(glBindBuffer(GL_ARRAY_BUFFER, 0))
GL(glBindTexture(GL_TEXTURE_RECTANGLE, 0))
GL(glUseProgram(0)) GL(glUseProgram(0))
vtstack_clear(&ren.font_stack); vtstack_clear(&ren.font_stack);
@ -576,7 +583,7 @@ int ren_set_scissor(int x, int y, int w, int h)
static int ren_push_glyph(const struct font_glyph *g, int gx, int gy) static int ren_push_glyph(const struct font_glyph *g, int gx, int gy)
{ {
/* x4,y4 x3,y3 /* x4,y4 x3,y3
* +-------------+ * o-------------+
* |(x,y) /| * |(x,y) /|
* | / | * | / |
* | 2 / | * | 2 / |
@ -589,7 +596,7 @@ static int ren_push_glyph(const struct font_glyph *g, int gx, int gy)
struct v_text v; struct v_text v;
struct font_glyph c; struct font_glyph c;
c = *g; c = *g;
//printf("g: u=%d v=%d w=%d h=%d a=%d x=%d y=%d\n", c.u, c.v, c.w, c.h, c.a, c.x, c.y); printf("g: u=%d v=%d w=%d h=%d a=%d x=%d y=%d\n", c.u, c.v, c.w, c.h, c.a, c.x, c.y);
//printf("v: x=%d y=%d u=%d v=%d\n", v.pos.x, v.pos.y, v.uv.u, v.uv.v); //printf("v: x=%d y=%d u=%d v=%d\n", v.pos.x, v.pos.y, v.uv.u, v.uv.v);
// x1,y1 // x1,y1
v = (struct v_text){ v = (struct v_text){
@ -643,6 +650,7 @@ int ren_get_text_box(const char *str, int *rw, int *rh, int size)
if (idx < 0) if (idx < 0)
return -1; return -1;
h = y = ren.fonts[idx].font->glyph_max_h;
for (off = 0; (ret = grapheme_decode_utf8(str+off, SIZE_MAX, &cp)) > 0 && cp != 0; off += ret) { for (off = 0; (ret = grapheme_decode_utf8(str+off, SIZE_MAX, &cp)) > 0 && cp != 0; off += ret) {
if (iscntrl(cp)) goto skip_get; if (iscntrl(cp)) goto skip_get;
g = font_get_glyph_texture(ren.fonts[idx].font, cp, &updated); g = font_get_glyph_texture(ren.fonts[idx].font, cp, &updated);
@ -736,7 +744,7 @@ int ren_render_text(const char *str, int x, int y, int w, int h, int size)
static int ren_push_box(int x, int y, int w, int h, unsigned int color) static int ren_push_box(int x, int y, int w, int h, unsigned int color)
{ {
/* x4,y4 x3,y3 /* x4,y4 x3,y3
* +-------------+ * o-------------+
* |(x,y) /| * |(x,y) /|
* | / | * | / |
* | 2 / | * | 2 / |

Loading…
Cancel
Save