diff --git a/Makefile b/Makefile index 4a75195..151c32e 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,8 @@ LDFLAGS += $(shell pkg-config --libs glfw3) OBJS = \ src/gl.o \ src/opengl.o \ - src/test.o + src/test.o \ + src/font.o all: test.so diff --git a/font/terminus_128x128_8x16.data b/font/terminus_128x128_8x16.data new file mode 100644 index 0000000..00b0555 Binary files /dev/null and b/font/terminus_128x128_8x16.data differ diff --git a/font/terminus_128x64_6x12.data b/font/terminus_128x64_6x12.data new file mode 100644 index 0000000..1639010 Binary files /dev/null and b/font/terminus_128x64_6x12.data differ diff --git a/font/terminus_256x128_10x18.data b/font/terminus_256x128_10x18.data new file mode 100644 index 0000000..246d05a Binary files /dev/null and b/font/terminus_256x128_10x18.data differ diff --git a/font/terminus_256x128_12x24.data b/font/terminus_256x128_12x24.data new file mode 100644 index 0000000..b597181 Binary files /dev/null and b/font/terminus_256x128_12x24.data differ diff --git a/include/font.h b/include/font.h new file mode 100644 index 0000000..718f912 --- /dev/null +++ b/include/font.h @@ -0,0 +1,56 @@ +#pragma once + +namespace font { + + struct font_desc { + char const * const path; + int const texture_width; + int const texture_height; + int const glyph_width; + int const glyph_height; + }; + + font_desc const ter_6x12 = { + .path = "font/terminus_128x64_6x12.data", + .texture_width = 128, + .texture_height = 64, + .glyph_width = 6, + .glyph_height = 12, + }; + font_desc const ter_8x16 = { + .path = "font/terminus_128x128_8x16.data", + .texture_width = 128, + .texture_height = 128, + .glyph_width = 8, + .glyph_height = 16, + }; + font_desc const ter_10x18 = { + .path = "font/terminus_256x128_10x18.data", + .texture_width = 256, + .texture_height = 128, + .glyph_width = 10, + .glyph_height = 18, + }; + font_desc const ter_12x24 = { + .path = "font/terminus_256x128_12x24.data", + .texture_width = 256, + .texture_height = 128, + .glyph_width = 12, + .glyph_height = 24, + }; + + struct font { + font_desc const * desc; + unsigned int texture; + int stride; + struct { + float width; + float height; + } cell; + }; + + void load_element_buffer(); + void load_shader(); + font load_font(font_desc const& desc); + void draw_string(font const& font, char const * const s, int x, int y); +} diff --git a/main.lua b/main.lua index 9bf1941..4f7a2d7 100644 --- a/main.lua +++ b/main.lua @@ -58,6 +58,6 @@ function love.run() love.graphics.present() love.timer.sleep(0.001) local fps = love.timer.getFPS( ) - print(fps) + --print(fps) end end diff --git a/minecraft/gen/mc.sh b/minecraft/gen/mc.sh index 3ab7461..7d30bd2 100644 --- a/minecraft/gen/mc.sh +++ b/minecraft/gen/mc.sh @@ -1,6 +1,7 @@ set -eux cd ./minecraft/gen -python mc.py ~/Love2DWorld/region/r.0.0.mcr ../region.0.0 & -python mc.py ~/Love2DWorld/region/r.-1.-1.mcr ../region.-1.-1 & -python mc.py ~/Love2DWorld/region/r.0.-1.mcr ../region.0.-1 & -python mc.py ~/Love2DWorld/region/r.-1.0.mcr ../region.-1.0 & +PYTHON=pypy3.11 +$PYTHON mc.py ~/Love2DWorld/region/r.0.0.mcr ../region.0.0 & +$PYTHON mc.py ~/Love2DWorld/region/r.-1.-1.mcr ../region.-1.-1 & +$PYTHON mc.py ~/Love2DWorld/region/r.0.-1.mcr ../region.0.-1 & +$PYTHON mc.py ~/Love2DWorld/region/r.-1.0.mcr ../region.-1.0 & diff --git a/shader/font.frag b/shader/font.frag new file mode 100644 index 0000000..af8d1db --- /dev/null +++ b/shader/font.frag @@ -0,0 +1,18 @@ +#version 330 core + +uniform sampler2D TextureSampler; + +uniform vec2 Cell; +uniform vec2 Glyph; + +out vec4 g_color; + +in vec4 PixelTexture; + +void main() +{ + vec4 sample = texture(TextureSampler, PixelTexture.xy * Cell + Cell * Glyph); + float px = sample.x == 0.0 ? 0.0 : 1.0; + + g_color = vec4(vec3(px), 1.0); +} diff --git a/shader/font.vert b/shader/font.vert new file mode 100644 index 0000000..3b8b299 --- /dev/null +++ b/shader/font.vert @@ -0,0 +1,39 @@ +#version 330 core + +const vec2 vtx[4] = vec2[](vec2(-1.0, 1.0), // tl + vec2( 1.0, 1.0), // tr + vec2( 1.0, -1.0), // br + vec2(-1.0, -1.0)); // bl + +/* +tl tr + br + +0 1 2 +tr tl br +1 0 2 + +tl +bl br + +2 1 3 +br tl bl +2 0 3 + +1 0 2 3 +*/ + +uniform mat4 Transform; + +out vec4 PixelTexture; + +void main() +{ + vec2 vertex = vtx[gl_VertexID]; + + PixelTexture = vec4(vertex * vec2(0.5, -0.5) + 0.5, 0, 0); + + vertex = vertex * vec2(0.5, 0.5) + vec2(0.5, -0.5); + + gl_Position = Transform * vec4(vertex, 0.0, 1.0); +} diff --git a/src/font.cpp b/src/font.cpp new file mode 100644 index 0000000..6eb2adf --- /dev/null +++ b/src/font.cpp @@ -0,0 +1,152 @@ +#include +#include +#include + +#include "directxmath/directxmath.h" +#include "glad/gl.h" +#include "opengl.h" + +#include "font.h" + +namespace font { + + struct location { + struct { + unsigned int transform; + unsigned int texture_sampler; + unsigned int cell; + unsigned int glyph; + } uniform; + }; + + static location location; + + static unsigned int font_program = -1; + + static unsigned int vertex_array_object = -1; + static unsigned int index_buffer = -1; + + void load_element_buffer() + { + uint8_t const data[] = { + 1, 0, 2, 3, + }; + int const data_size = (sizeof (data)); + + glGenBuffers(1, &index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data_size, data, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glGenVertexArrays(1, &vertex_array_object); + } + + void load_shader() + { + unsigned int program = compile_from_files("shader/font.vert", + NULL, // geom + "shader/font.frag"); + + location.uniform.transform = glGetUniformLocation(program, "Transform"); + location.uniform.texture_sampler = glGetUniformLocation(program, "TextureSampler"); + location.uniform.cell = glGetUniformLocation(program, "Cell"); + location.uniform.glyph = glGetUniformLocation(program, "Glyph"); + printf("font uniforms:\n transform %u\n texture_sampler %u\n cell %u\n glyph %u\n", + location.uniform.transform, + location.uniform.texture_sampler, + location.uniform.cell, + location.uniform.glyph + ); + + font_program = program; + } + + font load_font(font_desc const& desc) + { + unsigned int texture; + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + int texture_data_size; + void * texture_data = read_file(desc.path, &texture_data_size); + assert(texture_data != nullptr); + + int width = desc.texture_width; + int height = desc.texture_height; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, texture_data); + + free(texture_data); + + glBindTexture(GL_TEXTURE_2D, 0); + + return (font){ + .desc = &desc, + .texture = texture, + .stride = desc.texture_width / desc.glyph_width, + .cell = { (float)desc.glyph_width / (float)desc.texture_width, + (float)desc.glyph_height / (float)desc.texture_height }, + }; + } + + inline static XMFLOAT2 glyph_coordinate(font const& font, int ord) + { + int c = ord - 32; + int x = c % font.stride; + int y = c / font.stride; + XMVECTOR coord = XMVectorSet(x, y, 0, 0); + XMFLOAT2 coordf; + XMStoreFloat2(&coordf, coord); + return coordf; + } + + inline static XMFLOAT4X4 glyph_transform(font const& font, int x, int y) + { + XMMATRIX transform = + XMMatrixScaling(font.desc->glyph_width, font.desc->glyph_height, 0) + * XMMatrixTranslation(x, -y, 0) + * XMMatrixScaling(2.0f / 1024.0f, 2.0f / 1024.0f, 0) + * XMMatrixTranslation(-1, 1, 0); + XMFLOAT4X4 transformf; + XMStoreFloat4x4(&transformf, transform); + return transformf; + } + + void draw_string(font const& font, char const * const s, int x, int y) + { + glUseProgram(font_program); + glDepthFunc(GL_ALWAYS); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, font.texture); + + glUniform1i(location.uniform.texture_sampler, 0); + glUniform2fv(location.uniform.cell, 1, (float *)&font.cell); + + glBindVertexArray(vertex_array_object); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + int i = 0; + while (s[i] != 0) { + char c = s[i]; + if (c <= 0x20 || c > 0x7f) + continue; + + XMFLOAT4X4 transform = glyph_transform(font, x, y); + glUniformMatrix4fv(location.uniform.transform, 1, GL_FALSE, (float *)&transform); + XMFLOAT2 glyph = glyph_coordinate(font, c); + glUniform2fv(location.uniform.glyph, 1, (float *)&glyph); + + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0); + + x += font.desc->glyph_width; + + i += 1; + } + } +} diff --git a/src/test.cpp b/src/test.cpp index 752468e..ab334f4 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -6,6 +6,7 @@ #include "opengl.h" #include "directxmath/directxmath.h" #include "test.h" +#include "font.h" #include "data.inc" @@ -246,6 +247,8 @@ struct view_state { view_state view_state; +font::font ter_8x16 = {}; + void load() { fprintf(stderr, "getproc %p\n", SDL_GL_GetProcAddress); @@ -266,6 +269,14 @@ void load() //unsigned int textures_layout = glGetUniformBlockIndex(test_program, "TexturesLayout"); //glUniformBlockBinding(test_program, textures_layout, 0); //printf("textures_layout %d\n", textures_layout); + + ////////////////////////////////////////////////////////////////////// + // font + ////////////////////////////////////////////////////////////////////// + + font::load_element_buffer(); + font::load_shader(); + ter_8x16 = font::load_font(font::ter_8x16); } void update(float lx, float ly, float rx, float ry, float tl, float tr, @@ -357,4 +368,6 @@ void draw() glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_BYTE, indices, instance_count, base_instance); } } + + font::draw_string(ter_8x16, "test", 10, 10); }