diff options
| author | talha <talha@talhaamir.xyz> | 2024-04-28 15:48:28 +0500 | 
|---|---|---|
| committer | talha <talha@talhaamir.xyz> | 2024-04-28 15:48:28 +0500 | 
| commit | ba43db84ce7e80449c505c1381b33786cc047131 (patch) | |
| tree | 00df517ef5f5f86df126e32fc27e91f94ce55ac7 /source/main.cpp | |
| parent | 708b6e523d7f57f4eb4eb8395530be9ddf67986a (diff) | |
Basic text rendering is now working
Diffstat (limited to 'source/main.cpp')
| -rw-r--r-- | source/main.cpp | 314 | 
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); | 
