diff --git a/text_rendering/box_fragshader.glsl b/text_rendering/box_fragshader.glsl new file mode 100644 index 0000000..5c1120c --- /dev/null +++ b/text_rendering/box_fragshader.glsl @@ -0,0 +1,8 @@ +#version 330 core + +in vec4 col; + +void main() +{ + gl_FragColor = col; +} \ No newline at end of file diff --git a/text_rendering/box_vertshader.glsl b/text_rendering/box_vertshader.glsl new file mode 100644 index 0000000..468665a --- /dev/null +++ b/text_rendering/box_vertshader.glsl @@ -0,0 +1,19 @@ +#version 330 core + +uniform ivec2 viewsize; + +layout(location = 0) in vec2 position; +layout(location = 2) in vec4 color; + +out vec4 col; + + +void main() +{ + vec2 v = vec2(float(viewsize.x), float(viewsize.y)); + vec2 p = vec2(position.x*2.0/v.x - 1.0, 1.0 - position.y*2.0/v.y); + vec4 pos = vec4(p.x, p.y, 0.0f, 1.0f); + + gl_Position = pos; + col = color; +} \ No newline at end of file diff --git a/text_rendering/main.c b/text_rendering/main.c index 7cccae0..a25d306 100644 --- a/text_rendering/main.c +++ b/text_rendering/main.c @@ -8,13 +8,26 @@ #include "util.h" +const char *str = "Ciao Mamma!\nprova: òçà°ù§|¬³¼$£ì\t"; +SDL_Window *win; + + +void draw(void) +{ + ren_clear(); + ren_render_text(str, 0, 0, 200, 100, 12); + ren_render_box(100, 300, 50, 50, 0xffff0000); + SDL_GL_SwapWindow(win); +} + + int main(void) { SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); - SDL_Window *win = SDL_CreateWindow( + win = SDL_CreateWindow( "test render", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, @@ -26,7 +39,6 @@ int main(void) return 1; } - const char *str = "Ciao Mamma!\nprova: òçà°ù§|¬³¼$£ì\t"; SDL_Event e; while(1) { @@ -38,12 +50,10 @@ int main(void) case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED: ren_update_viewport(e.window.data1, e.window.data2); - ren_render_text(str, 0, 0, 200, 100, 12); - SDL_GL_SwapWindow(win); + draw(); break; case SDL_WINDOWEVENT_EXPOSED: - ren_render_text(str, 0, 0, 200, 100, 12); - SDL_GL_SwapWindow(win); + draw(); break; default: break; } diff --git a/text_rendering/ren.c b/text_rendering/ren.c index d92bb60..303b1e9 100644 --- a/text_rendering/ren.c +++ b/text_rendering/ren.c @@ -81,7 +81,9 @@ struct { GLuint font_prog; GLuint box_prog; GLuint font_buffer; + GLuint box_buffer; GLint viewsize_loc; + GLint box_viewsize_loc; GLint texturesize_loc; struct vtstack font_stack; struct vcstack box_stack; @@ -322,13 +324,13 @@ static int update_font_texture(void) // TODO: push window size uniforms int ren_init(SDL_Window *w) { + // Initialize OpenGL if (!w) REN_RET(-1, REN_INVAL) ren.gl = SDL_GL_CreateContext(w); if (!ren.gl) REN_RET(-1, REN_CONTEXT) - - // select some features + GL(glEnable(GL_BLEND)) GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)) GL(glDisable(GL_CULL_FACE)) @@ -341,11 +343,12 @@ int ren_init(SDL_Window *w) if (glew_err != GLEW_OK) REN_RET(glew_err, REN_GLEW); + // Load font ren.font = font_init(); if (!ren.font) REN_RET(-1, REN_FONT) if (font_load(ren.font, FONT_PATH, 20)) REN_RET(-1, REN_FONT) font_dump(ren.font, "./atlas.png"); - + // load font texture (atlas) ren.font_texture = ren_texturer_rect( (const char *)ren.font->atlas, ren.font->width, @@ -353,16 +356,18 @@ int ren_init(SDL_Window *w) GL_LINEAR, GL_LINEAR); if (!ren.font_texture) return -1; - ren.font_prog = ren_compile_program(FONT_VERSHADER, FONT_FRAGSHADER); - if (!ren.font_prog) return -1; - + // Create stacks ren.font_stack = vtstack_init(); - ren.box_stack = vcstack_init(); - + ren.box_stack = vcstack_init(); // generate the font buffer object GL(glGenBuffers(1, &ren.font_buffer)) if (!ren.font_buffer) REN_RET(-1, REN_BUFFER) + GL(glGenBuffers(1, &ren.box_buffer)) + if (!ren.box_buffer) REN_RET(-1, REN_BUFFER) + // Compile font shaders + ren.font_prog = ren_compile_program(FONT_VERSHADER, FONT_FRAGSHADER); + if (!ren.font_prog) return -1; // create the uniforms, if the returned value is -1 then the uniform may have // been optimized away, in any case do not return, just give a warning ren.viewsize_loc = GL(glGetUniformLocation(ren.font_prog, "viewsize")) @@ -372,6 +377,14 @@ int ren_init(SDL_Window *w) if (ren.texturesize_loc == -1) printf("uniform %s was optimized away\n", "texturesize"); + // Compile box shaders + ren.box_prog = ren_compile_program(BOX_VERSHADER, BOX_FRAGSHADER); + if (!ren.box_prog) return -1; + ren.box_viewsize_loc = GL(glGetUniformLocation(ren.box_prog, "viewsize")) + if (ren.box_viewsize_loc == -1) + printf("uniform %s was optimized away\n", "viewsize"); + + // Finishing touches int width, height; SDL_GetWindowSize(w, &width, &height); ren_update_viewport(width, height); @@ -382,14 +395,20 @@ int ren_init(SDL_Window *w) } +int ren_clear(void) +{ + GL(glScissor(0, 0, ren.width, ren.height)) + GL(glClear(GL_COLOR_BUFFER_BIT)); + return 0; +} + + static int ren_draw_font_stack(void) { GL(glUseProgram(ren.font_prog)) GL(glBindBuffer(GL_ARRAY_BUFFER, ren.font_buffer)) GL(glViewport(0, 0, ren.width, ren.height)) - GL(glScissor(0, 0, ren.width, ren.height)) - GL(glClear(GL_COLOR_BUFFER_BIT)); // this has caused me some trouble, convert from image coordiates to viewport GL(glScissor(ren.s_x, ren.height-ren.s_y-ren.s_h, ren.s_w, ren.s_h)) GL(glUniform2i(ren.viewsize_loc, ren.width, ren.height)) @@ -425,6 +444,54 @@ static int ren_draw_font_stack(void) GL(glDisableVertexAttribArray(REN_UV_IDX)) GL(glBindBuffer(GL_ARRAY_BUFFER, 0)) GL(glUseProgram(0)) + + vtstack_clear(&ren.font_stack); + return 0; +} + + +static int ren_draw_box_stack(void) +{ + GL(glUseProgram(ren.box_prog)) + GL(glBindBuffer(GL_ARRAY_BUFFER, ren.box_buffer)) + + GL(glViewport(0, 0, ren.width, ren.height)) + GL(glScissor(0, 0, ren.width, ren.height)) + GL(glUniform2i(ren.box_viewsize_loc, ren.width, ren.height)) + + GL(glEnableVertexAttribArray(REN_VERTEX_IDX)) + GL(glEnableVertexAttribArray(REN_COLOR_IDX)) + // when passing ints to glVertexAttribPointer they are automatically + // converted to floats + GL(glVertexAttribPointer( + REN_VERTEX_IDX, + 2, + GL_INT, + GL_FALSE, + sizeof(struct v_col), + 0)) + // the color gets normalized + GL(glVertexAttribPointer( + REN_COLOR_IDX, + 4, + GL_INT, + GL_TRUE, + sizeof(struct v_col), + (void*)sizeof(vec2_i))) + // TODO: implement size and damage tracking on stacks + GL(glBufferData( + GL_ARRAY_BUFFER, + ren.box_stack.idx*sizeof(struct v_col), + ren.box_stack.items, + GL_DYNAMIC_DRAW)) + GL(glDrawArrays(GL_TRIANGLES, 0, ren.box_stack.idx)) + + GL(glDisableVertexAttribArray(REN_VERTEX_IDX)) + GL(glDisableVertexAttribArray(REN_COLOR_IDX)) + GL(glBindBuffer(GL_ARRAY_BUFFER, 0)) + GL(glUseProgram(0)) + + vcstack_clear(&ren.box_stack); return 0; } @@ -552,16 +619,63 @@ int ren_render_text(const char *str, int x, int y, int w, int h, int size) // inefficient but is simpler and allows for individual scissors ren_set_scissor(x, y, w, h); ren_draw_font_stack(); - vtstack_clear(&ren.font_stack); return 0; } +// re-normalize color from 0-255 to 0-0x7fffffff, technically i'm dividing by 256 here +#define RENORM(x) (((unsigned long long)(x)*0x7fffffff)>>8) +#define R(x) (x&0xff) +#define G(x) ((x>>8)&0xff) +#define B(x) ((x>>16)&0xff) +#define A(x) ((x>>24)&0xff) +static int ren_push_box(int x, int y, int w, int h, unsigned int color) +{ + struct v_col v; + vec4_i c = { + .r = RENORM(R(color)), + .g = RENORM(G(color)), + .b = RENORM(B(color)), + .a = RENORM(A(color)), + }; + // x1, y1 + v = (struct v_col){ .pos = { .x = x, .y = y+h }, .col = c }; + vcstack_push(&ren.box_stack, &v); + // x2, y2 + v = (struct v_col){ .pos = { .x = x+w, .y = y+h }, .col = c }; + vcstack_push(&ren.box_stack, &v); + // x3, y3 + v = (struct v_col){ .pos = { .x = x+w, .y = y }, .col = c }; + vcstack_push(&ren.box_stack, &v); + // x1, y1 + v = (struct v_col){ .pos = { .x = x, .y = y+h }, .col = c }; + vcstack_push(&ren.box_stack, &v); + // x3, y3 + v = (struct v_col){ .pos = { .x = x+w, .y = y }, .col = c }; + vcstack_push(&ren.box_stack, &v); + // x4, y4 + v = (struct v_col){ .pos = { .x = x, .y = y }, .col = c }; + vcstack_push(&ren.box_stack, &v); + + return 0; +} + + +int ren_render_box(int x, int y, int w, int h, unsigned int color) +{ + ren_push_box(x, y, w, h, color); + ren_draw_box_stack(); + return 0; +} + + int ren_free(void) { GL(glUseProgram(0)) GL(glBindBuffer(GL_ARRAY_BUFFER, 0)) + GL(glDeleteProgram(ren.box_prog)); + GL(glDeleteProgram(ren.font_prog)); GL(glDeleteTextures(1, &ren.font_texture)) GL(glDeleteBuffers(1, &ren.font_buffer)) SDL_GL_DeleteContext(ren.gl); diff --git a/text_rendering/ren.h b/text_rendering/ren.h index 62b3aa6..66a8b60 100644 --- a/text_rendering/ren.h +++ b/text_rendering/ren.h @@ -7,6 +7,8 @@ #define FONT_PATH "./monospace.ttf" #define FONT_VERSHADER "./font_vertshader.glsl" #define FONT_FRAGSHADER "./font_fragshader.glsl" +#define BOX_VERSHADER "./box_vertshader.glsl" +#define BOX_FRAGSHADER "./box_fragshader.glsl" #define REN_VERTEX_IDX 0 #define REN_UV_IDX 1 #define REN_COLOR_IDX 2 @@ -33,7 +35,7 @@ struct v_text { // colored vertex struct v_col { vec2_i pos; - vec2_i col; + vec4_i col; }; @@ -42,6 +44,9 @@ int ren_free(void); const char * ren_strerror(void); int ren_update_viewport(int w, int h); int ren_render_text(const char *str, int x, int y, int w, int h, int size); +int ren_set_scissor(int x, int y, int w, int h); +int ren_render_box(int x, int y, int w, int h, unsigned int color); +int ren_clear(void); #endif