Compare commits
2 Commits
044b405289
...
65b0a40006
Author | SHA1 | Date |
---|---|---|
Jill | 65b0a40006 | |
Jill | 2998463350 |
|
@ -6,14 +6,16 @@ class Funfriend::ChatterContext < Funfriend::WindowContext
|
||||||
WINDOW_SIZE = {width: 256, height: 32}
|
WINDOW_SIZE = {width: 256, height: 32}
|
||||||
DEFAULT_DURATION = 10.0
|
DEFAULT_DURATION = 10.0
|
||||||
|
|
||||||
|
PADDING = 10
|
||||||
|
|
||||||
def initialize(text : String, position : NamedTuple(x: Int32, y: Int32), duration : Float64 = DEFAULT_DURATION)
|
def initialize(text : String, position : NamedTuple(x: Int32, y: Int32), duration : Float64 = DEFAULT_DURATION)
|
||||||
sheet = FontMan.parse_bm(File.read "assets/fonts/SpaceMono.fnt")
|
sheet = FontMan.parse_bm(File.read "assets/fonts/SpaceMono.fnt")
|
||||||
|
|
||||||
position_data = FontMan.position_text(text, sheet)
|
position_data = FontMan.position_text(text, sheet)
|
||||||
|
|
||||||
@window_size = {
|
@window_size = {
|
||||||
width: position_data[:width],
|
width: position_data[:width] + PADDING * 2,
|
||||||
height: position_data[:height]
|
height: position_data[:height] + PADDING * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
super(
|
super(
|
||||||
|
@ -26,7 +28,7 @@ class Funfriend::ChatterContext < Funfriend::WindowContext
|
||||||
window.make_context_current
|
window.make_context_current
|
||||||
|
|
||||||
@timer = duration
|
@timer = duration
|
||||||
@renderer = TextRenderer.new(text, sheet)
|
@renderer = TextRenderer.new(text, sheet, window_size[:width], window_size[:height])
|
||||||
|
|
||||||
window.position = {
|
window.position = {
|
||||||
x: position[:x] - window_size[:width]//2,
|
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_color(0.0, 0.0, 0.0, 1.0)
|
||||||
LibGL.clear(Buffer::Bit::Color)
|
LibGL.clear(Buffer::Bit::Color)
|
||||||
|
|
||||||
renderer.render(dt, window_size[:width], window_size[:height])
|
renderer.render(dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(dt : Float64)
|
def update(dt : Float64)
|
||||||
|
|
|
@ -79,6 +79,14 @@ module Funfriend::FontMan
|
||||||
}
|
}
|
||||||
end
|
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
|
# TODO: kerning
|
||||||
def position_text(text : String, sheet : BMSheet)
|
def position_text(text : String, sheet : BMSheet)
|
||||||
positions = [] of NamedTuple(x: Int32, y: Int32, char: BMChar)
|
positions = [] of NamedTuple(x: Int32, y: Int32, char: BMChar)
|
||||||
|
@ -100,4 +108,72 @@ module Funfriend::FontMan
|
||||||
positions: positions,
|
positions: positions,
|
||||||
}
|
}
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -53,14 +53,15 @@ class Funfriend::FunfriendContext < Funfriend::WindowContext
|
||||||
|
|
||||||
Funfriend.contexts.each do |context|
|
Funfriend.contexts.each do |context|
|
||||||
if context.is_a?(ChatterContext)
|
if context.is_a?(ChatterContext)
|
||||||
context.window.position = {
|
window = context.window
|
||||||
x: context.window.position[:x],
|
window.position = {
|
||||||
y: context.window.position[:y] - 30
|
x: window.position[:x],
|
||||||
|
y: window.position[:y] - context.window_size[:height] - 10
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
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,
|
x: window.position[:x] + WINDOW_SIZE[:width] // 2,
|
||||||
y: window.position[:y] + WINDOW_SIZE[:height] // 2 - 70
|
y: window.position[:y] + WINDOW_SIZE[:height] // 2 - 70
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
class Funfriend::TextRenderer
|
class Funfriend::TextRenderer
|
||||||
getter text : String
|
getter text : String
|
||||||
|
getter sheet : FontMan::BMSheet
|
||||||
|
getter width : Int32
|
||||||
|
getter height : Int32
|
||||||
|
|
||||||
getter shader_program : Program
|
getter shader_program : Program
|
||||||
getter vertex_array : VertexArray
|
getter vertex_array : VertexArray
|
||||||
getter vertex_buffer : Buffer
|
getter vertex_buffer : Buffer
|
||||||
getter font_texture : Texture
|
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
|
@text = text
|
||||||
@sheet = sheet
|
@sheet = sheet
|
||||||
|
@width = width
|
||||||
|
@height = height
|
||||||
|
|
||||||
@shader_program = init_shaders
|
@shader_program = init_shaders
|
||||||
@vertex_array, @vertex_buffer = init_buffers
|
@vertex_array, @vertex_buffer = init_buffers
|
||||||
@font_texture = init_textures
|
@font_texture = init_textures
|
||||||
|
@ -24,77 +29,14 @@ class Funfriend::TextRenderer
|
||||||
})[:tex]
|
})[:tex]
|
||||||
end
|
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
|
def init_buffers
|
||||||
vertices = [] of Float32
|
text_width, text_height = FontMan.text_width(text, sheet), sheet[:common][:line_height]
|
||||||
indices = [] of Int32
|
FontMan.get_text_mesh(text, sheet, width // 2 - text_width // 2, height // 2 - text_height // 2, width, height)
|
||||||
|
|
||||||
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}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def init_shaders
|
def init_shaders
|
||||||
vertex_shader_source = File.read "src/glsl/nop.vert"
|
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)
|
vertex_shader = VertexShader.create(vertex_shader_source)
|
||||||
fragment_shader = FragmentShader.create(fragment_shader_source)
|
fragment_shader = FragmentShader.create(fragment_shader_source)
|
||||||
|
@ -103,7 +45,7 @@ class Funfriend::TextRenderer
|
||||||
return Program.create(shaders)
|
return Program.create(shaders)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render(dt : Float64, window_width : Int32, window_height : Int32)
|
def render(dt : Float64)
|
||||||
font_texture.bind(Texture::Target::Texture2D) do
|
font_texture.bind(Texture::Target::Texture2D) do
|
||||||
shader_program.use do |p|
|
shader_program.use do |p|
|
||||||
p.set_uniform("texture1", 0)
|
p.set_uniform("texture1", 0)
|
||||||
|
|
Loading…
Reference in New Issue