Compare commits

...

2 Commits

Author SHA1 Message Date
Jill 65b0a40006
typo 2023-05-30 20:18:06 +03:00
Jill 2998463350
text rendering refactors, proper padding 2023-05-30 18:34:07 +03:00
5 changed files with 98 additions and 77 deletions

View File

@ -6,14 +6,16 @@ class Funfriend::ChatterContext < Funfriend::WindowContext
WINDOW_SIZE = {width: 256, height: 32}
DEFAULT_DURATION = 10.0
PADDING = 10
def initialize(text : String, position : NamedTuple(x: Int32, y: Int32), duration : Float64 = DEFAULT_DURATION)
sheet = FontMan.parse_bm(File.read "assets/fonts/SpaceMono.fnt")
position_data = FontMan.position_text(text, sheet)
@window_size = {
width: position_data[:width],
height: position_data[:height]
width: position_data[:width] + PADDING * 2,
height: position_data[:height] + PADDING * 2
}
super(
@ -26,7 +28,7 @@ class Funfriend::ChatterContext < Funfriend::WindowContext
window.make_context_current
@timer = duration
@renderer = TextRenderer.new(text, sheet)
@renderer = TextRenderer.new(text, sheet, window_size[:width], window_size[:height])
window.position = {
x: position[:x] - window_size[:width]//2,
@ -41,7 +43,7 @@ class Funfriend::ChatterContext < Funfriend::WindowContext
LibGL.clear_color(0.0, 0.0, 0.0, 1.0)
LibGL.clear(Buffer::Bit::Color)
renderer.render(dt, window_size[:width], window_size[:height])
renderer.render(dt)
end
def update(dt : Float64)

View File

@ -79,6 +79,14 @@ module Funfriend::FontMan
}
end
# quick shorthand
def text_width(text : String, sheet : BMSheet)
text.chars.reduce 0 do |width, char|
bm_char = sheet[:chars].find! { |c| c[:letter] == char }
width + bm_char[:xadvance]
end
end
# TODO: kerning
def position_text(text : String, sheet : BMSheet)
positions = [] of NamedTuple(x: Int32, y: Int32, char: BMChar)
@ -100,4 +108,72 @@ module Funfriend::FontMan
positions: positions,
}
end
def get_letter_crop(char : BMChar, sheet : BMSheet)
x = (char[:x] / sheet[:common][:scale_w]).to_f32
y = (char[:y] / sheet[:common][:scale_h]).to_f32
w = (char[:width] / sheet[:common][:scale_w]).to_f32
h = (char[:height] / sheet[:common][:scale_h]).to_f32
return {x, y, w, h}
end
def get_text_mesh(text : String, sheet : BMSheet, offset_x : Int32, offset_y : Int32, width : Int32, height : Int32)
vertices = [] of Float32
indices = [] of Int32
position_data = FontMan.position_text(text, sheet)
i = 0
position_data[:positions].each do |letter|
char = letter[:char]
x, y, w, h = get_letter_crop(char, sheet)
pos_x = ((letter[:x] + offset_x) / width ).to_f32 * 2 - 1
pos_w = (char[:width] / width ).to_f32 * 2
pos_y = ((letter[:y] + offset_y) / height).to_f32 * 2 - 1
pos_h = (char[:height] / height).to_f32 * 2
vertices += [
# ------ positions ------- texture coordinates
pos_x + pos_w, pos_y + pos_h, 0.0f32, x + w, y, # top right
pos_x + pos_w, pos_y, 0.0f32, x + w, y + h, # bottom right
pos_x, pos_y, 0.0f32, x, y + h, # bottom left
pos_x, pos_y + pos_h, 0.0f32, x, y, # top left
]
# Indices used for indexed draw calls. Each is used as an index into the four vertices.
indices += [
0, 1, 3, # first triangle
1, 2, 3 # second triangle
].map &.+ (i * 4)
i = i + 1
end
vertex_buffer = Buffer.new
element_buffer = Buffer.new
vertex_array = VertexArray.new
vertex_array.bind do
vertex_buffer.bind(Buffer::Target::Array) do |buffer, target|
GL.buffer_data_array(target, vertices, Buffer::UsageHint::StaticDraw)
vertex_array.define_attributes do |va|
va.attribute(3, DataType::Float, false)
va.attribute(2, DataType::Float, false)
end
end
# bind the element buffer to GL_ELEMENT_ARRAY_BUFFER
element_buffer.bind(Buffer::Target::ElementArray)
# Send index data to the GPU.
GL.buffer_data_array(Buffer::Target::ElementArray, indices, Buffer::UsageHint::StaticDraw)
end
# unbind the element buffer.
element_buffer.unbind
return {vertex_array, vertex_buffer}
end
end

View File

@ -53,14 +53,15 @@ class Funfriend::FunfriendContext < Funfriend::WindowContext
Funfriend.contexts.each do |context|
if context.is_a?(ChatterContext)
context.window.position = {
x: context.window.position[:x],
y: context.window.position[:y] - 30
window = context.window
window.position = {
x: window.position[:x],
y: window.position[:y] - context.window_size[:height] - 10
}
end
end
Funfriend.add_context(ChatterContext.new(renderer.catmoding ? "HEWWO INTEWLOPEW" : "HELLO INTERLOPER", {
Funfriend.add_context(ChatterContext.new(renderer.catmoding ? "HEWWO INTEWWOPEW" : "HELLO INTERLOPER", {
x: window.position[:x] + WINDOW_SIZE[:width] // 2,
y: window.position[:y] + WINDOW_SIZE[:height] // 2 - 70
}))

View File

@ -1,15 +1,20 @@
class Funfriend::TextRenderer
getter text : String
getter sheet : FontMan::BMSheet
getter width : Int32
getter height : Int32
getter shader_program : Program
getter vertex_array : VertexArray
getter vertex_buffer : Buffer
getter font_texture : Texture
getter sheet : FontMan::BMSheet
def initialize(text : String, sheet : FontMan::BMSheet)
def initialize(text : String, sheet : FontMan::BMSheet, width : Int32, height : Int32)
@text = text
@sheet = sheet
@width = width
@height = height
@shader_program = init_shaders
@vertex_array, @vertex_buffer = init_buffers
@font_texture = init_textures
@ -24,77 +29,14 @@ class Funfriend::TextRenderer
})[:tex]
end
def get_letter_crop(char : FontMan::BMChar)
x = (char[:x] / sheet[:common][:scale_w]).to_f32
y = (char[:y] / sheet[:common][:scale_h]).to_f32
w = (char[:width] / sheet[:common][:scale_w]).to_f32
h = (char[:height] / sheet[:common][:scale_h]).to_f32
return {x, y, w, h}
end
def init_buffers
vertices = [] of Float32
indices = [] of Int32
position_data = FontMan.position_text(text, sheet)
i = 0
position_data[:positions].each do |letter|
char = letter[:char]
x, y, w, h = get_letter_crop(char)
pos_x = (letter[:x] / position_data[:width]).to_f32 * 2 - 1
pos_w = (char[:width] / position_data[:width]).to_f32 * 2
pos_y = (letter[:y] / position_data[:height]).to_f32 * 2 - 1
pos_h = (char[:height] / position_data[:height]).to_f32 * 2
vertices += [
# ------ positions ------- texture coordinates
pos_x + pos_w, pos_y + pos_h, 0.0f32, x + w, y, # top right
pos_x + pos_w, pos_y, 0.0f32, x + w, y + h, # bottom right
pos_x, pos_y, 0.0f32, x, y + h, # bottom left
pos_x, pos_y + pos_h, 0.0f32, x, y, # top left
]
# Indices used for indexed draw calls. Each is used as an index into the four vertices.
indices += [
0, 1, 3, # first triangle
1, 2, 3 # second triangle
].map &.+ (i * 4)
i = i + 1
end
vertex_buffer = Buffer.new
element_buffer = Buffer.new
vertex_array = VertexArray.new
vertex_array.bind do
vertex_buffer.bind(Buffer::Target::Array) do |buffer, target|
GL.buffer_data_array(target, vertices, Buffer::UsageHint::StaticDraw)
vertex_array.define_attributes do |va|
va.attribute(3, DataType::Float, false)
va.attribute(2, DataType::Float, false)
end
end
# bind the element buffer to GL_ELEMENT_ARRAY_BUFFER
element_buffer.bind(Buffer::Target::ElementArray)
# Send index data to the GPU.
GL.buffer_data_array(Buffer::Target::ElementArray, indices, Buffer::UsageHint::StaticDraw)
end
# unbind the element buffer.
element_buffer.unbind
return {vertex_array, vertex_buffer}
text_width, text_height = FontMan.text_width(text, sheet), sheet[:common][:line_height]
FontMan.get_text_mesh(text, sheet, width // 2 - text_width // 2, height // 2 - text_height // 2, width, height)
end
def init_shaders
vertex_shader_source = File.read "src/glsl/nop.vert"
fragment_shader_source = File.read "src/glsl/font.frag"
fragment_shader_source = File.read "src/glsl/bake_alpha.frag"
vertex_shader = VertexShader.create(vertex_shader_source)
fragment_shader = FragmentShader.create(fragment_shader_source)
@ -103,7 +45,7 @@ class Funfriend::TextRenderer
return Program.create(shaders)
end
def render(dt : Float64, window_width : Int32, window_height : Int32)
def render(dt : Float64)
font_texture.bind(Texture::Target::Texture2D) do
shader_program.use do |p|
p.set_uniform("texture1", 0)