Render outlined text with dft.
This commit is contained in:
parent
b396fa8419
commit
072abd788c
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
|||||||
[submodule "modules/glamour"]
|
[submodule "modules/glamour"]
|
||||||
path = modules/glamour
|
path = modules/glamour
|
||||||
url = git://github.com/Dav1dde/glamour
|
url = git://github.com/Dav1dde/glamour
|
||||||
|
[submodule "modules/dft"]
|
||||||
|
path = modules/dft
|
||||||
|
url = ../../dft.git
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
configure do
|
configure do
|
||||||
check_d_compiler
|
check_d_compiler
|
||||||
|
check_cfg package: "freetype2"
|
||||||
end
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
@ -12,8 +13,9 @@ build do
|
|||||||
"modules/DerelictGL3/source",
|
"modules/DerelictGL3/source",
|
||||||
"modules/gl3n/gl3n",
|
"modules/gl3n/gl3n",
|
||||||
"modules/glamour/glamour",
|
"modules/glamour/glamour",
|
||||||
|
"modules/dft/src",
|
||||||
].each do |dir|
|
].each do |dir|
|
||||||
sources += glob("#{dir}/**/*.d")
|
sources += glob("#{dir}/**/*.{d,c}")
|
||||||
end
|
end
|
||||||
env["D_IMPORT_PATH"] += [
|
env["D_IMPORT_PATH"] += [
|
||||||
"modules/DerelictUtil/source",
|
"modules/DerelictUtil/source",
|
||||||
@ -21,6 +23,7 @@ build do
|
|||||||
"modules/DerelictGL3/source",
|
"modules/DerelictGL3/source",
|
||||||
"modules/gl3n",
|
"modules/gl3n",
|
||||||
"modules/glamour",
|
"modules/glamour",
|
||||||
|
"modules/dft/src",
|
||||||
]
|
]
|
||||||
env["DFLAGS"] += ["-fversion=Derelict3", "-fversion=gl3n", "-fversion=SDLImage2"]
|
env["DFLAGS"] += ["-fversion=Derelict3", "-fversion=gl3n", "-fversion=SDLImage2"]
|
||||||
env["LDFLAGS"] += ["-static-libgcc"]
|
env["LDFLAGS"] += ["-static-libgcc"]
|
||||||
|
BIN
assets/FreeSans.ttf
Normal file
BIN
assets/FreeSans.ttf
Normal file
Binary file not shown.
1
modules/dft
Submodule
1
modules/dft
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4a0727b535bb3164e48c6bb57194f737dfeb0aab
|
214
src/app.d
214
src/app.d
@ -1,24 +1,142 @@
|
|||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
import core.stdc.string;
|
||||||
import derelict.sdl2.sdl;
|
import derelict.sdl2.sdl;
|
||||||
import derelict.opengl3.gl3;
|
import derelict.opengl3.gl3;
|
||||||
import glamour.vao;
|
import glamour.vao;
|
||||||
import glamour.shader;
|
import glamour.shader;
|
||||||
import glamour.vbo;
|
import glamour.vbo;
|
||||||
|
import glamour.texture;
|
||||||
import gl3n.linalg;
|
import gl3n.linalg;
|
||||||
|
static import dft;
|
||||||
|
|
||||||
enum int WIDTH = 800;
|
enum int WIDTH = 800;
|
||||||
enum int HEIGHT = 600;
|
enum int HEIGHT = 600;
|
||||||
|
|
||||||
|
Shader spinny_program;
|
||||||
GLint position_idx;
|
GLint position_idx;
|
||||||
GLint color_idx;
|
GLint color_idx;
|
||||||
GLint view_idx;
|
GLint view_idx;
|
||||||
|
Shader font_program;
|
||||||
|
GLint font_coords_idx;
|
||||||
|
GLint font_viewport_size_idx;
|
||||||
|
GLint font_position_idx;
|
||||||
|
GLint font_texture_idx;
|
||||||
|
GLint font_color_idx;
|
||||||
mat4 view_matrix;
|
mat4 view_matrix;
|
||||||
|
|
||||||
|
private uint next_power_of_2(uint n)
|
||||||
|
{
|
||||||
|
n--;
|
||||||
|
n |= n >> 1u;
|
||||||
|
n |= n >> 2u;
|
||||||
|
n |= n >> 4u;
|
||||||
|
n |= n >> 8u;
|
||||||
|
n |= n >> 16u;
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Glyph
|
||||||
|
{
|
||||||
|
Texture2D m_texture;
|
||||||
|
VAO m_vao;
|
||||||
|
Buffer m_vbo;
|
||||||
|
int m_advance;
|
||||||
|
|
||||||
|
this(dft.Font font, uint char_code, int outline_size)
|
||||||
|
{
|
||||||
|
dft.Font.Glyph dft_glyph = font.get_glyph(char_code, outline_size);
|
||||||
|
m_advance = dft_glyph.advance;
|
||||||
|
|
||||||
|
m_texture = new Texture2D();
|
||||||
|
uint rwidth = next_power_of_2(dft_glyph.width);
|
||||||
|
uint rheight = next_power_of_2(dft_glyph.height);
|
||||||
|
ubyte[] texture_data = new ubyte[rwidth * rheight];
|
||||||
|
for (uint row = 0u; row < dft_glyph.height; row++)
|
||||||
|
{
|
||||||
|
memcpy(&texture_data[row * rwidth],
|
||||||
|
&dft_glyph.bitmap[(dft_glyph.height - row - 1) * dft_glyph.width],
|
||||||
|
dft_glyph.width);
|
||||||
|
}
|
||||||
|
m_texture.bind();
|
||||||
|
m_texture.set_parameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
m_texture.set_parameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
m_texture.set_parameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
m_texture.set_parameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
m_texture.set_data(texture_data, GL_ALPHA, rwidth, rheight, GL_ALPHA, GL_UNSIGNED_BYTE, false);
|
||||||
|
|
||||||
|
m_vao = new VAO();
|
||||||
|
m_vao.bind();
|
||||||
|
|
||||||
|
int left = dft_glyph.left;
|
||||||
|
int top = dft_glyph.top;
|
||||||
|
float s_max = dft_glyph.width / cast(float)rwidth;
|
||||||
|
float t_max = dft_glyph.height / cast(float)rheight;
|
||||||
|
GLfloat[] data = [
|
||||||
|
cast(GLfloat)left, cast(GLfloat)(top - dft_glyph.height), 0.0, 0.0,
|
||||||
|
cast(GLfloat)(left + dft_glyph.width), cast(GLfloat)(top - dft_glyph.height), s_max, 0.0,
|
||||||
|
cast(GLfloat)left, cast(GLfloat)top, 0.0, t_max,
|
||||||
|
cast(GLfloat)(left + dft_glyph.width), cast(GLfloat)top, s_max, t_max,
|
||||||
|
];
|
||||||
|
m_vbo = new Buffer(data);
|
||||||
|
m_vbo.bind();
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render()
|
||||||
|
{
|
||||||
|
m_vao.bind();
|
||||||
|
m_texture.bind();
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property int advance()
|
||||||
|
{
|
||||||
|
return m_advance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OutlinedGlyph
|
||||||
|
{
|
||||||
|
Glyph m_outline_glyph;
|
||||||
|
Glyph m_inner_glyph;
|
||||||
|
|
||||||
|
this(dft.Font font, uint char_code, int outline_size)
|
||||||
|
{
|
||||||
|
m_outline_glyph = new Glyph(font, char_code, outline_size);
|
||||||
|
m_inner_glyph = new Glyph(font, char_code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render()
|
||||||
|
{
|
||||||
|
glUniform4f(font_color_idx, 0.0, 0.0, 0.0, 1.0);
|
||||||
|
m_outline_glyph.render();
|
||||||
|
glUniform4f(font_color_idx, 1.0, 1.0, 1.0, 1.0);
|
||||||
|
m_inner_glyph.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
@property int advance()
|
||||||
|
{
|
||||||
|
return m_inner_glyph.advance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dft.Font font;
|
||||||
|
VAO spinny_vao;
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glClearColor (1.0, 0.7, 0.0, 0.0);
|
glClearColor (1.0, 0.7, 0.0, 0.0);
|
||||||
glViewport(0, 0, WIDTH, HEIGHT);
|
glViewport(0, 0, WIDTH, HEIGHT);
|
||||||
immutable string shader_src = `
|
immutable string shader_src = `
|
||||||
|
#version 130
|
||||||
|
|
||||||
vertex:
|
vertex:
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
in vec2 position;
|
in vec2 position;
|
||||||
@ -36,11 +154,12 @@ fragment:
|
|||||||
gl_FragColor = vec4(color_i, 1.0);
|
gl_FragColor = vec4(color_i, 1.0);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
VAO vao = new VAO();
|
spinny_vao = new VAO();
|
||||||
Shader program = new Shader("program", shader_src);
|
spinny_vao.bind();
|
||||||
program.bind();
|
spinny_program = new Shader("spinny_program", shader_src);
|
||||||
position_idx = program.get_attrib_location("position");
|
spinny_program.bind();
|
||||||
color_idx = program.get_attrib_location("color");
|
position_idx = spinny_program.get_attrib_location("position");
|
||||||
|
color_idx = spinny_program.get_attrib_location("color");
|
||||||
float[] vertices = [0.4, 0.4, -0.4, 0.4, -0.4, -0.4, 0.4, -0.4];
|
float[] vertices = [0.4, 0.4, -0.4, 0.4, -0.4, -0.4, 0.4, -0.4];
|
||||||
float[] colors = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0];
|
float[] colors = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0];
|
||||||
ushort[] indices = [0, 1, 2, 3];
|
ushort[] indices = [0, 1, 2, 3];
|
||||||
@ -54,19 +173,102 @@ fragment:
|
|||||||
glVertexAttribPointer(color_idx, 3, GL_FLOAT, GL_FALSE, 0, null);
|
glVertexAttribPointer(color_idx, 3, GL_FLOAT, GL_FALSE, 0, null);
|
||||||
ElementBuffer ibo = new ElementBuffer(indices);
|
ElementBuffer ibo = new ElementBuffer(indices);
|
||||||
ibo.bind();
|
ibo.bind();
|
||||||
view_idx = program.get_uniform_location("view");
|
view_idx = spinny_program.get_uniform_location("view");
|
||||||
|
|
||||||
|
font = new dft.Font("assets/FreeSans.ttf", 60);
|
||||||
|
immutable string font_shader_src = `
|
||||||
|
#version 130
|
||||||
|
|
||||||
|
vertex:
|
||||||
|
/* Viewport width and height */
|
||||||
|
uniform ivec2 viewport_size;
|
||||||
|
/* Position of lower left corner of glyph */
|
||||||
|
uniform ivec2 position;
|
||||||
|
|
||||||
|
/* Vertex coordinates: x, y, s, t */
|
||||||
|
in vec4 coords;
|
||||||
|
|
||||||
|
/* Output texture coordinate: s, t */
|
||||||
|
out vec2 texture_coord_v;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map coordinates such that:
|
||||||
|
* (0 .. viewport_size.[xy]) => (-1.0 .. 1.0)
|
||||||
|
*/
|
||||||
|
vec2 map_to_screen(vec2 position)
|
||||||
|
{
|
||||||
|
return 2.0 * position / viewport_size - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
gl_Position = vec4(map_to_screen(vec2(position) + coords.xy), 0, 1);
|
||||||
|
texture_coord_v = coords.zw;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment:
|
||||||
|
/* Texture coordinate: s, t */
|
||||||
|
in vec2 texture_coord_v;
|
||||||
|
|
||||||
|
/* Texture unit */
|
||||||
|
uniform sampler2D texture;
|
||||||
|
uniform vec4 color;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
frag_color = vec4(1, 1, 1, texture2D(texture, texture_coord_v).a) * color;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
font_program = new Shader("fontshader", font_shader_src);
|
||||||
|
font_program.bind();
|
||||||
|
font_coords_idx = font_program.get_attrib_location("coords");
|
||||||
|
font_viewport_size_idx = font_program.get_uniform_location("viewport_size");
|
||||||
|
font_position_idx = font_program.get_uniform_location("position");
|
||||||
|
font_texture_idx = font_program.get_uniform_location("texture");
|
||||||
|
font_color_idx = font_program.get_uniform_location("color");
|
||||||
|
glUniform2i(font_viewport_size_idx, WIDTH, HEIGHT);
|
||||||
|
glUniform1i(font_texture_idx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlinedGlyph[uint] outlined_glyphs;
|
||||||
|
|
||||||
|
OutlinedGlyph get_glyph(uint char_code)
|
||||||
|
{
|
||||||
|
if (char_code in outlined_glyphs)
|
||||||
|
{
|
||||||
|
return outlined_glyphs[char_code];
|
||||||
|
}
|
||||||
|
return outlined_glyphs[char_code] = new OutlinedGlyph(font, char_code, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_string(int x, int y, string s)
|
||||||
|
{
|
||||||
|
foreach (c; s)
|
||||||
|
{
|
||||||
|
glUniform2i(font_position_idx, x, y);
|
||||||
|
OutlinedGlyph outlined_glyph = get_glyph(c);
|
||||||
|
outlined_glyph.render();
|
||||||
|
x += outlined_glyph.advance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void display(SDL_Window * window)
|
void display(SDL_Window * window)
|
||||||
{
|
{
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
spinny_program.bind();
|
||||||
|
spinny_vao.bind();
|
||||||
view_matrix.make_identity();
|
view_matrix.make_identity();
|
||||||
view_matrix.rotatez(SDL_GetTicks() / 500.0);
|
view_matrix.rotatez(SDL_GetTicks() / 500.0);
|
||||||
view_matrix.scale(HEIGHT / cast(float)WIDTH, 1.0, 1.0);
|
view_matrix.scale(HEIGHT / cast(float)WIDTH, 1.0, 1.0);
|
||||||
glUniformMatrix4fv(view_idx, 1, GL_TRUE, view_matrix.value_ptr);
|
glUniformMatrix4fv(view_idx, 1, GL_TRUE, view_matrix.value_ptr);
|
||||||
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, null);
|
glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, null);
|
||||||
|
|
||||||
|
font_program.bind();
|
||||||
|
draw_string(40, 40, "Hello world!");
|
||||||
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user