aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graphics.c151
-rw-r--r--graphics.h2
-rw-r--r--main.c2
-rw-r--r--shader.c44
-rw-r--r--shader.h8
-rw-r--r--state.h21
6 files changed, 196 insertions, 32 deletions
diff --git a/graphics.c b/graphics.c
index 7846f6c..9aeb41f 100644
--- a/graphics.c
+++ b/graphics.c
@@ -1,5 +1,46 @@
#include "graphics.h"
-#include "array.h"
+#include "shader.h"
+
+void GLAPIENTRY
+MessageCallback( GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam )
+{
+ fprintf( stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
+ ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
+ type, severity, message );
+}
+
+const char* vertexShader = "#version 330 core\n\
+layout (location = 0) in vec2 pos;\n\
+layout (location = 1) in vec2 uv;\n\
+\n\
+uniform vec2 u_screen_size;\n\
+uniform vec2 u_offset;\n\
+\n\
+out vec2 o_uv;\n\
+\n\
+void main() {\n\
+ o_uv = uv;\n\
+ gl_Position = vec4((((pos + u_offset) / u_screen_size) - vec2(0.5, 0.5)) * 2.0, 0.0, 1.0);\n\
+}";
+
+const char* fragmentShader = "#version 330 core\n\
+uniform sampler2D u_texture;\n\
+in vec2 uv;\n\
+\n\
+layout (location = 0) out vec4 frag_color;\n\
+\n\
+void main() {\n\
+ float d = texture(u_texture, uv).r;\n\
+ float aaf = fwidth(d);\n\
+ float alpha = smoothstep(0.5 - aaf, 0.5 + aaf, d);\n\
+ frag_color = vec4(0.0, 0.0, 0.0, alpha);\n\
+}";
bool init_gl(client_state* state) {
EGLint attrs[] = {
@@ -19,7 +60,6 @@ bool init_gl(client_state* state) {
return false;
}
-
state->egl_display = eglGetDisplay(state->display);
if (state->egl_display == EGL_NO_DISPLAY) {
fprintf(stderr, "edisplay\n");
@@ -70,6 +110,13 @@ bool init_gl(client_state* state) {
printf("GL version %u.%u\n", major, minor);
}
+ glEnable ( GL_DEBUG_OUTPUT );
+ glDebugMessageCallback( MessageCallback, 0 );
+
+ state->text_shader = createShader(vertexShader, fragmentShader);
+ state->screen_size_uniform = glGetUniformLocation(state->text_shader, "u_screen_size");
+ state->offset_uniform = glGetUniformLocation(state->text_shader, "u_offset");
+
return true;
}
@@ -77,38 +124,90 @@ void render_frame(client_state *state) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
- glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, state->atlas.texture);
- // set up matrices
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0, (double)state->width, (double)state->height, 0.0, -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- // draw text
- glBegin(GL_QUADS);
- float pen_x = 300;
- float pen_y = 200;
- // TODO for unicode - check for missing characters, iterate over "unicode characters"
- for ( int n = 0; n < array_size(state->input_buffer); n++ )
+ glUseProgram(state->text_shader);
+ glUniform2f(state->screen_size_uniform, state->width, state->height);
+ glUniform2f(state->offset_uniform, 200.0f, 200.0f);
+ glBindVertexArray(state->input_buffer_text.vao);
+ glDrawElements(GL_TRIANGLES, state->input_buffer_text.numElements, GL_UNSIGNED_INT, 0);
+
+ eglSwapBuffers(state->egl_display, state->egl_surface);
+}
+
+typedef struct {
+ float x, y, u, v;
+} vert_t;
+
+void initTextBuffer(client_state* state, text_buffer_t* buffer, char* text, size_t text_len) {
+ // generate openg bullshit
+ glGenVertexArrays(1, &buffer->vao);
+ glGenBuffers(1, &buffer->vbo);
+ glGenBuffers(1, &buffer->ebo);
+ glBindVertexArray(buffer->vao);
+
+ // TODO for unicode - check for missing characters, iterate over "unicode characters" not chars
+ // TODO for all fonts - possibly kerning
+ // generate vertices
+ vert_t vertices[text_len * 4];
+ uint32_t indices[text_len * 6];
+ buffer->numElements = text_len * 6;
+ float pen_x = 0;
+ for (int n = 0; n < text_len; n++ )
{
- char c = state->input_buffer[n];
+ char c = text[n];
metric_t* m = &state->atlas.metrics[(int)c];
float start_x = pen_x + m->bearing_x;
- float start_y = pen_y - m->bearing_y;
- glTexCoord2f(m->texture_x_start, 0.0f); glVertex2f(start_x, start_y);
- glTexCoord2f(m->texture_x_start, 1.0f); glVertex2f(start_x, start_y + m->bitmap_height);
- glTexCoord2f(m->texture_x_end, 1.0f); glVertex2f(start_x + m->bitmap_width, start_y + m->bitmap_height);
- glTexCoord2f(m->texture_x_end, 0.0f); glVertex2f(start_x + m->bitmap_width, start_y);
-
+ float start_y = -m->bearing_y;
+ uint32_t base_vert = n * 4;
+ uint32_t base_idx = n * 6;
+
+ // top left vert
+ vert_t v = { .x=start_x, .y=start_y, .u=m->texture_x_start, .v=1.0f};
+ vertices[base_vert + 0] = v;
+ // bottom left vert
+ v.y += m->bitmap_height;
+ v.v = 0.0f;
+ vertices[base_vert + 1] = v;
+ // bottom right vert
+ v.x += m->bitmap_width;
+ v.u = m->texture_x_end;
+ vertices[base_vert + 2] = v;
+ // top right vert
+ v.y = start_y;
+ v.v = 1;
+ vertices[base_vert + 3] = v;
+
+ // indices
+ indices[base_idx + 0] = base_vert + 0;
+ indices[base_idx + 1] = base_vert + 1;
+ indices[base_idx + 2] = base_vert + 2;
+ indices[base_idx + 3] = base_vert + 0;
+ indices[base_idx + 4] = base_vert + 2;
+ indices[base_idx + 5] = base_vert + 3;
+
+ // go forward
pen_x += m->advance_x;
}
- glEnd();
- glDisable(GL_TEXTURE_2D);
+ for (int i = 0; i < sizeof(vertices) / sizeof(vert_t); ++i) {
+ vert_t v = vertices[i];
+ printf("(%f, %f, %f, %f)\n", v.x, v.y, v.u, v.v);
+ }
+
+ // vertex buffer
+ glBindBuffer(GL_ARRAY_BUFFER, buffer->vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- eglSwapBuffers(state->egl_display, state->egl_surface);
+ // index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
+
+ // vertex attributes
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+ glEnableVertexAttribArray(1);
}
diff --git a/graphics.h b/graphics.h
index 8889bf7..fc46ee8 100644
--- a/graphics.h
+++ b/graphics.h
@@ -6,4 +6,6 @@
bool init_gl(client_state* state);
void render_frame(client_state* state);
+void initTextBuffer(client_state* state, text_buffer_t* buffer, char* text, size_t text_len);
+
#endif
diff --git a/main.c b/main.c
index e487a34..430ae45 100644
--- a/main.c
+++ b/main.c
@@ -74,6 +74,8 @@ int main() {
// create font altas textures
atlas_create_texture(&state);
+ initTextBuffer(&state, &state.input_buffer_text, "a g dadsd s", 19);
+
// event loop
while (state.running) {
poll_events(&state);
diff --git a/shader.c b/shader.c
new file mode 100644
index 0000000..8cc3926
--- /dev/null
+++ b/shader.c
@@ -0,0 +1,44 @@
+#include "shader.h"
+
+#include <stdio.h>
+
+GLuint createShader(const char *vertexCode, const char *fragmentCode) {
+ GLuint vertex, fragment;
+ int success;
+ char infoLog[512];
+
+ vertex = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vertex, 1, &vertexCode, NULL);
+ glCompileShader(vertex);
+
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(vertex, 512, NULL, infoLog);
+ printf("ERROR: Failed to compile vertex shader: %s\n", infoLog);
+ }
+
+ fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fragment, 1, &fragmentCode, NULL);
+ glCompileShader(fragment);
+
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(fragment, 512, NULL, infoLog);
+ printf("ERROR: Failed to compile fragment shader: %s\n", infoLog);
+ }
+
+ GLuint ShaderProgram = glCreateProgram();
+ glAttachShader(ShaderProgram, vertex);
+ glAttachShader(ShaderProgram, fragment);
+ glLinkProgram(ShaderProgram);
+
+ glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &success);
+ if (!success) {
+ printf("Failed to link shaders\n");
+ }
+
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+
+ return ShaderProgram;
+}
diff --git a/shader.h b/shader.h
new file mode 100644
index 0000000..f748519
--- /dev/null
+++ b/shader.h
@@ -0,0 +1,8 @@
+#ifndef SHADER_H_
+#define SHADER_H_
+
+#include "./glad/glad.h"
+
+GLuint createShader(const char *vertexCode, const char *fragmentCode);
+
+#endif // SHADER_H_
diff --git a/state.h b/state.h
index d75bac2..4226711 100644
--- a/state.h
+++ b/state.h
@@ -19,6 +19,11 @@
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
typedef struct {
+ GLuint vbo, ebo, vao;
+ uint32_t numElements;
+} text_buffer_t;
+
+typedef struct {
float advance_x, advance_y;
uint32_t bitmap_width, bitmap_height;
int32_t bearing_x, bearing_y;
@@ -67,19 +72,23 @@ typedef struct {
EGLConfig egl_config;
EGLContext egl_context;
- // state
- char* input_buffer;
- uint32_t width, height;
+ // graphics
+ GLuint text_shader;
+ GLuint screen_size_uniform;
+ GLuint offset_uniform;
+ text_buffer_t input_buffer_text;
+ // fonts
FT_Library ft_library;
FT_Face ft_face;
FT_Int32 load_flags;
-
atlas_t atlas;
- bool running;
-
+ // state
+ char* input_buffer;
+ uint32_t width, height;
item_t* items;
+ bool running;
} client_state;