summaryrefslogtreecommitdiff
path: root/source/main.cpp
diff options
context:
space:
mode:
authortalha <talha@talhaamir.xyz>2024-04-28 15:48:28 +0500
committertalha <talha@talhaamir.xyz>2024-04-28 15:48:28 +0500
commitba43db84ce7e80449c505c1381b33786cc047131 (patch)
tree00df517ef5f5f86df126e32fc27e91f94ce55ac7 /source/main.cpp
parent708b6e523d7f57f4eb4eb8395530be9ddf67986a (diff)
Basic text rendering is now working
Diffstat (limited to 'source/main.cpp')
-rw-r--r--source/main.cpp314
1 files changed, 272 insertions, 42 deletions
diff --git a/source/main.cpp b/source/main.cpp
index 7deb893..6df5451 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -3,6 +3,7 @@
#include <SDL2/SDL.h>
#include <glad/glad.h>
#include <vector>
+#include <map>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
@@ -50,6 +51,8 @@ typedef u8 b8;
// =========== Shader Loading =============
+#define GL2D_UScale(x) (Vec2{(x), (x)})
+
enum Texture_Filtering { TF_NEAREST, TF_LINEAR };
struct GlTexturedQuad {
@@ -211,7 +214,7 @@ s32 gl_load_texture(u32 texture_id, char *path, enum Texture_Filtering filter)
return 0;
}
-GlTexturedQuad gl_setup_textured_quad(char* texture_path, enum Texture_Filtering filter)
+GlTexturedQuad gl2d_setup_textured_quad(char* texture_path, enum Texture_Filtering filter)
{
// rendering is clock-wise
r32 quad_vertices[] = {
@@ -247,11 +250,32 @@ GlTexturedQuad gl_setup_textured_quad(char* texture_path, enum Texture_Filtering
return tex_quad;
}
-void gl_draw_tex_quad(u32 shader_program, GlTexturedQuad tex_quad)
+void gl2d_draw_tex_quad(GlShader shader, GlTexturedQuad tex_quad, Vec3 position, Vec2 scale, r32 angle)
{
- glUseProgram(shader_program);
- s32 tex_id_loc = glGetUniformLocation(shader_program, "Texture");
+ glUseProgram(shader.id);
+ s32 tex_id_loc = glGetUniformLocation(shader.id, "Texture");
glUniform1i(tex_id_loc, 0);
+
+ // 1. Rotation
+ Mat4 model = init_value4m(1.0f);
+ if (angle)
+ {
+ Mat4 rotation = rotation_matrix4m(angle, Vec3{0.0f, 0.0f, 1.0f});
+ model = multiply4m(rotation, model);
+ }
+ // 2. Scale
+ if (scale.x != 1.0f || scale.y != 1.0f)
+ {
+ Mat4 scaling = scaling_matrix4m(scale.x, scale.y, 1.0f);
+ model = multiply4m(scaling, model);
+ }
+ // 3. Translation
+ Mat4 translation = translation_matrix4m(position.x, position.y, position.z);
+ model = multiply4m(translation, model);
+
+ // sending model to the shader
+ glUniformMatrix4fv(shader.model_loc, 1, GL_TRUE, model.buffer);
+
glBindVertexArray(tex_quad.vao);
glBindTexture(GL_TEXTURE_2D, tex_quad.texture_id);
glDrawArrays(GL_TRIANGLES, 0, 6);
@@ -285,20 +309,76 @@ Vec3 camera_look_around(r32 angle_pitch, r32 angle_yaw)
return camera_look;
}
+struct TextChar {
+ u32 texture_id;
+ Vec2 size;
+ Vec2 bearing;
+ s64 advance;
+};
+
+struct CameraOrtho {
+ r32 left;
+ r32 right;
+ r32 bottom;
+ r32 top;
+ r32 near;
+ r32 far;
+ Vec2 resolution;
+ Vec2 dimensions;
+ Mat4 projection;
+};
+
+CameraOrtho camera_orthographic(r32 height, Vec2 resolution, r32 near, r32 far)
+{
+ CameraOrtho camera = { 0 };
+
+ r32 aspect_ratio = resolution.x / resolution.y;
+ r32 width = height * aspect_ratio;
+
+ r32 left = -width/2.0f;
+ r32 right = width/2.0f;
+
+ r32 bottom = -height/2.0f;
+ r32 top = height/2.0f;
+
+ camera.resolution = resolution;
+ camera.dimensions = Vec2{width, height};
+ camera.left = left;
+ camera.right = right;
+ camera.bottom = bottom;
+ camera.top = top;
+ camera.near = near;
+ camera.far = far;
+
+ camera.projection = orthographic_projection4m(left, right, bottom, top, near, far);
+
+ return camera;
+}
+
+Vec2 camera_from_screen(CameraOrtho camera, Vec2 position)
+{
+ Vec2 camera_space = { 0 };
+
+ camera_space.x = camera.left + position.x * (camera.dimensions.x/camera.resolution.x);
+ camera_space.y = camera.top - position.y * (camera.dimensions.y/camera.resolution.y);
+
+ return camera_space;
+}
+
int main(int argc, char* argv[])
{
// Load freetype
- FT_Library library;
+ FT_Library ft_lib;
FT_Face face;
- if (FT_Init_FreeType(&library))
+ if (FT_Init_FreeType(&ft_lib))
{
printf("Error: Could not init freetype library\n");
return -1;
}
- FT_Error error = FT_New_Face(library, "assets/fonts/Arial.ttf", 0, &face);
+ FT_Error error = FT_New_Face(ft_lib, "assets/fonts/Arial.ttf", 0, &face);
if (error == FT_Err_Unknown_File_Format)
{
printf("Error: Font Loading Failed. The font format is unsupported.\n");
@@ -310,8 +390,6 @@ int main(int argc, char* argv[])
return -1;
}
- FT_Set_Pixel_Sizes(face, 0, 48);
-
int width = 1024;
int height = 768;
@@ -353,7 +431,7 @@ int main(int argc, char* argv[])
}
// vsync controls: 0 = OFF | 1 = ON (Default)
- // SDL_GL_SetSwapInterval(0);
+ SDL_GL_SetSwapInterval(1);
// filesystem playground stuff
size_t read_count;
@@ -361,20 +439,83 @@ int main(int argc, char* argv[])
tex_quad_shader.id = gl_shader_program_from_path("./source/shaders/textured_quad.vs.glsl", "./source/shaders/textured_quad.fs.glsl");
gl_shader_load_locations(&tex_quad_shader);
- GlTexturedQuad tex_quad1 = gl_setup_textured_quad("./assets/smiling.png", TF_LINEAR);
- GlTexturedQuad tex_quad2 = gl_setup_textured_quad("./assets/container.jpg", TF_LINEAR);
+ u32 ui_text_sp = gl_shader_program_from_path("./source/shaders/ui_text_shader.vs.glsl", "./source/shaders/ui_text_shader.fs.glsl");
+
+ GlTexturedQuad tex_quad1 = gl2d_setup_textured_quad("./assets/smiling.png", TF_LINEAR);
+ GlTexturedQuad tex_quad2 = gl2d_setup_textured_quad("./assets/container.jpg", TF_LINEAR);
- // objects
- Vec3 model_translations[] = {
- Vec3{ 0.5, 0.0, 0.0}, // 0: origin square
- Vec3{ -1.0, 0.0, -1.0}, // 1: plane
- Vec3{ -1.0, 0.0, -0.5}, // 2: window between squares
- Vec3{ 0.0, 0.0, 3.0}, // 3: window infront of origin square
- Vec3{ -2.5, 0.0, -0.5}, // 4: square to the left
- Vec3{ -1.0, 0.0, -1.5}, // 5: random square behind window between squares
- Vec3{ -1.0, 0.0, -8.0}, // 6: reflective plane
- Vec3{ -1.0, 2.0, -8.0}, // 6: refractive "window"
- };
+ // ====================
+ // setup_text
+ // debug only
+ std::map<char, TextChar> all_text_chars;
+
+ FT_Set_Pixel_Sizes(face, 0, 48);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // generate characters
+ for (unsigned char c = 0; c < 128; c++)
+ {
+ if (FT_Load_Char(face, c, FT_LOAD_RENDER))
+ {
+ printf("Error: Freetype failed to load glyph: %c", c);
+ }
+ else
+ {
+ // generate texture
+ u32 texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(
+ GL_TEXTURE_2D,
+ 0,
+ GL_RED,
+ face->glyph->bitmap.width,
+ face->glyph->bitmap.rows,
+ 0,
+ GL_RED,
+ GL_UNSIGNED_BYTE,
+ face->glyph->bitmap.buffer
+ );
+ // set texture options
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ TextChar tc = {
+ texture,
+ Vec2{(r32)face->glyph->bitmap.width, (r32)face->glyph->bitmap.rows},
+ Vec2{(r32)face->glyph->bitmap_left, (r32)face->glyph->bitmap_top},
+ face->glyph->advance.x
+ };
+
+ all_text_chars.insert(std::pair<char, TextChar>(c, tc));
+ }
+
+ }
+ r32 vertices[] = {
+ 0.0f, 0.0f,
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+
+ 0.0f, 0.0f,
+ 1.0f, 1.0f,
+ 1.0f, 0.0f
+ };
+
+ u32 vao, vbo;
+ glGenVertexArrays(1, &vao);
+ glGenBuffers(1, &vbo);
+ glBindVertexArray(vao);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferData(GL_ARRAY_BUFFER, 6*5*sizeof(r32), NULL, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(r32), 0);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(r32), (void*)(3*sizeof(r32)));
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ // ==================== END setup_text
r32 FOV = 90.0;
r32 time_curr;
@@ -396,13 +537,37 @@ int main(int argc, char* argv[])
Mat4 view = camera_create4m(camera_pos, camera_look, preset_up_dir);
Mat4 proj = perspective4m((r32)To_Radian(90.0), (r32)width / (r32)height, 0.1f, 1000.0f);
+ Vec2 camera_res = {1024.0f, 768.0f};
+ r32 ortho_cam_height = 2.0f;
+ // CameraOrtho ortho_cam = camera_orthographic(ortho_cam_height, Vec2{camera_res.x, camera_res.y}, 0.1f, 1000.0f);
+ Mat4 ortho_proj = orthographic_projection4m(0.0f, 1024.0f, 0.0f, 768.0f, 0.1f, 1000.0f);
+
+ // objects
+ Vec3 model_translations[] = {
+ Vec3{ 0.0, 0.0, 0.0}, // 0: origin square
+ Vec3{ -1.0, 0.0, -1.0}, // 1: plane
+ Vec3{ -1.0, 0.0, -0.5}, // 2: window between squares
+ Vec3{ 0.0, 0.0, 3.0}, // 3: window infront of origin square
+ Vec3{ -2.5, 0.0, -0.5}, // 4: square to the left
+ Vec3{ -1.0, 0.0, -1.5}, // 5: random square behind window between squares
+ Vec3{ -1.0, 0.0, -8.0}, // 6: reflective plane
+ Vec3{ -1.0, 2.0, -8.0}, // 6: refractive "window"
+ };
s32 proj_loc;
- glUniformMatrix4fv(tex_quad_shader.proj_loc, 1, GL_TRUE, proj.buffer);
+ glUseProgram(ui_text_sp);
+ proj_loc = glGetUniformLocation(ui_text_sp, "Projection");
+ // glUniformMatrix4fv(proj_loc, 1, GL_TRUE, ortho_cam.projection.buffer);
+ glUniformMatrix4fv(proj_loc, 1, GL_TRUE, ortho_proj.buffer);
+
+ //glUseProgram(tex_quad_shader.id);
+ //glUniformMatrix4fv(tex_quad_shader.proj_loc, 1, GL_TRUE, ortho_cam.projection.buffer);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
u8 game_running = true;
@@ -481,6 +646,7 @@ int main(int argc, char* argv[])
} break;
case (SDL_MOUSEMOTION):
{
+ #if 0
SDL_MouseMotionEvent mouse_event = ev.motion;
r32 x_motion = (r32)mouse_event.xrel;
r32 y_motion = (r32)mouse_event.yrel;
@@ -491,6 +657,7 @@ int main(int argc, char* argv[])
camera_look = camera_look_around(angle_pitch, angle_yaw);
}
+ #endif
} break;
default:
{
@@ -503,47 +670,107 @@ int main(int argc, char* argv[])
if (move_w)
{
camera_pos = add3v(camera_pos, camera_look_increment);
+ //model_translations[0].y += 0.25f;
}
if (move_s)
{
camera_pos = subtract3v(camera_pos, camera_look_increment);
+ //model_translations[0].y -= 0.25f;
}
if (move_a)
{
Vec3 camera_right = normalize3v(cross_multiply3v(preset_up_dir, camera_look));
Vec3 camera_right_scaled = scaler_multiply3v(camera_right, camera_speed_adjusted);
camera_pos = add3v(camera_pos, camera_right_scaled);
+ //model_translations[0].x -= 0.25f;
}
if (move_d)
{
Vec3 camera_right = normalize3v(cross_multiply3v(preset_up_dir, camera_look));
Vec3 camera_right_scaled = scaler_multiply3v(camera_right, camera_speed_adjusted);
camera_pos = subtract3v(camera_pos, camera_right_scaled);
+ //model_translations[0].x += 0.25f;
}
view = camera_create4m(camera_pos, add3v(camera_pos, camera_look), preset_up_dir);
// object shader program stuff
time_prev = time_curr;
- glUniformMatrix4fv(tex_quad_shader.view_loc, 1, GL_TRUE, view.buffer);
+ //glUseProgram(tex_quad_shader.id);
+ //glUniformMatrix4fv(tex_quad_shader.view_loc, 1, GL_TRUE, view.buffer);
// OUTPUT
glClearColor(1.0f, 0.6f, .6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ // glDisable(GL_BLEND);
+ //gl2d_draw_tex_quad(tex_quad_shader, tex_quad1, model_translations[1], GL2D_UScale(3.0f), To_Radian(-5.0f));
+ //gl2d_draw_tex_quad(tex_quad_shader, tex_quad2, model_translations[0], GL2D_UScale(1.0f), 0.0f);
+ // gl_text_render(ui_tex_sp, // shader program
+ // Vec3{startx, starty, zindex}, // coords
+ // "hello, sailor!\nhow do you do?"); // text to render
{
- glUseProgram(tex_quad_shader.id);
- Vec3 pos = model_translations[0];
- Mat4 translation = translation_matrix4m(pos.x, pos.y, pos.z);
- glUniformMatrix4fv(tex_quad_shader.model_loc, 1, GL_TRUE, translation.buffer);
- gl_draw_tex_quad(tex_quad_shader.id, tex_quad1);
- }
- {
- glUseProgram(tex_quad_shader.id);
- Vec3 pos = model_translations[1];
- Mat4 translation = translation_matrix4m(pos.x, pos.y, pos.z);
- glUniformMatrix4fv(tex_quad_shader.model_loc, 1, GL_TRUE, translation.buffer);
- gl_draw_tex_quad(tex_quad_shader.id, tex_quad2);
+ // render ui text
+ glUseProgram(ui_text_sp);
+ s32 text_color_loc = glGetUniformLocation(ui_text_sp, "TextColor");
+ glUniform3f(text_color_loc, 0.0f, 0.8f, 0.0f);
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindVertexArray(vao);
+
+ const char text_to_render[] = "hello, sailor!\nhow does your journey go?";
+ r32 startx = 512.0f;
+ r32 starty = 700.0f;
+ r32 linex = startx;
+ r32 zindex = 3.0f;
+ r32 scale = 1.0f;
+ r32 max_size = 0.0f;
+ for (u32 i = 0; i < sizeof(text_to_render) - 1; i++)
+ {
+ char c = text_to_render[i];
+ TextChar rc = all_text_chars[c];
+ if (rc.size.y > max_size)
+ {
+ max_size = rc.size.y;
+ }
+ if (c == '\n')
+ {
+ linex = startx;
+ starty = starty - (rc.size.y * 1.5 * scale); // line_height: 1.5;
+ continue;
+ }
+ else if (c == ' ')
+ {
+ linex += (rc.advance >> 6) * scale;
+ continue;
+ }
+ r32 xpos = linex + (scale * rc.bearing.x);
+ r32 ypos = starty - (rc.size.y - rc.bearing.y) * scale;
+
+ r32 w = scale * rc.size.x;
+ r32 h = scale * rc.size.y;
+
+ // update VBO for each character
+ float vertices[6][5] = {
+ // z-index to render on (part of layering)
+ { xpos, ypos + h, -zindex, 0.0f, 0.0f },
+ { xpos, ypos, -zindex, 0.0f, 1.0f },
+ { xpos + w, ypos, -zindex, 1.0f, 1.0f },
+
+ { xpos, ypos + h, -zindex, 0.0f, 0.0f },
+ { xpos + w, ypos, -zindex, 1.0f, 1.0f },
+ { xpos + w, ypos + h, -zindex, 1.0f, 0.0f }
+ };
+
+ glBindTexture(GL_TEXTURE_2D, rc.texture_id);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ linex += (rc.advance >> 6) * scale;
+ }
+ r32 test = 1;
}
SDL_GL_SwapWindow(window);
@@ -552,11 +779,14 @@ int main(int argc, char* argv[])
// opengl free calls
// it is up to the renderer to free everything here
// of course I have not bothered to set that up so it does not matter
- glDeleteVertexArrays(1, &tex_quad1.vao);
- glDeleteVertexArrays(1, &tex_quad2.vao);
- glDeleteBuffers(1, &tex_quad1.vao);
- glDeleteBuffers(1, &tex_quad2.vao);
-
+ // glDeleteVertexArrays(1, &tex_quad1.vao);
+ // glDeleteVertexArrays(1, &tex_quad2.vao);
+ // glDeleteBuffers(1, &tex_quad1.vao);
+ // glDeleteBuffers(1, &tex_quad2.vao);
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(ft_lib);
+
// sdl free calls
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);