Font rendering v1
This commit is contained in:
parent
7236465623
commit
5d555fd5a0
BIN
app/src/main/assets/Milky Honey.ttf
Normal file
BIN
app/src/main/assets/Milky Honey.ttf
Normal file
Binary file not shown.
|
@ -4,6 +4,9 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
AssetManager* AssetManager::ptr = nullptr;
|
||||
|
||||
bool AssetManager::loadTexture(const char* path, Texture* p_texture)
|
||||
|
@ -24,3 +27,63 @@ bool AssetManager::loadTexture(const char* path, Texture* p_texture)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetManager::loadFontData(const char* path, float char_height, FontData* p_font)
|
||||
{
|
||||
FileBuffer ttf_data = {};
|
||||
if (!loadFile(path, &ttf_data))
|
||||
return false;
|
||||
|
||||
static unsigned char bitmap_memory[512 * 512];;
|
||||
FontData font_data = {};
|
||||
auto* data = reinterpret_cast<const unsigned char*>(ttf_data.data);
|
||||
stbtt_BakeFontBitmap(data,
|
||||
0,
|
||||
char_height,
|
||||
bitmap_memory,
|
||||
512, 512,
|
||||
32, 225, // latin-1 printable characters range
|
||||
font_data.char_data);
|
||||
font_data.char_height = char_height;
|
||||
int off = stbtt_GetFontOffsetForIndex(data,0);
|
||||
if (off < 0) {
|
||||
releaseFileBuffer(ttf_data);
|
||||
return false;
|
||||
}
|
||||
stbtt_fontinfo info;
|
||||
if (!stbtt_InitFont(&info, data, off)) {
|
||||
releaseFileBuffer(ttf_data);
|
||||
return false;
|
||||
}
|
||||
font_data.scale_factor = stbtt_ScaleForPixelHeight(&info, char_height);
|
||||
stbtt_GetFontVMetrics(&info, &font_data.ascent, &font_data.descent, &font_data.line_gap);
|
||||
|
||||
int x0, y0, x1, y1;
|
||||
stbtt_GetFontBoundingBox(&info, &x0, &y0, &x1, &y1);
|
||||
font_data.baseline_adjust = font_data.scale_factor * static_cast<float>(-y0);
|
||||
|
||||
*p_font = font_data;
|
||||
|
||||
releaseFileBuffer(ttf_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetManager::loadFontBitmap(const char *path, float char_height, Texture* p_texture)
|
||||
{
|
||||
FileBuffer ttf_data = {};
|
||||
if (!loadFile(path, &ttf_data))
|
||||
return false;
|
||||
static unsigned char bitmap_memory[512 * 512];
|
||||
stbtt_bakedchar char_data[225];
|
||||
stbtt_BakeFontBitmap(reinterpret_cast<const unsigned char*>(ttf_data.data),
|
||||
0,
|
||||
char_height,
|
||||
bitmap_memory,
|
||||
512, 512,
|
||||
32, 225, // latin-1 printable characters range
|
||||
char_data);
|
||||
*p_texture = Texture(512, 512, bitmap_memory, GL_R8);
|
||||
releaseFileBuffer(ttf_data);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "Texture.h"
|
||||
#include "Renderer.h"
|
||||
#include "Font.h"
|
||||
|
||||
// Predefine, because that saves us from including android headers here
|
||||
struct AAssetManager;
|
||||
|
@ -51,6 +52,10 @@ public:
|
|||
/// \return @c true if the texture was loaded successfully, @c false otherwise
|
||||
bool loadTexture(const char* path, Texture* p_texture);
|
||||
|
||||
bool loadFontData(const char* path, float char_height, FontData* p_font);
|
||||
|
||||
bool loadFontBitmap(const char* path, float char_height, Texture* p_texture);
|
||||
|
||||
protected:
|
||||
AssetManager() = default;
|
||||
virtual ~AssetManager() = default;
|
||||
|
|
|
@ -13,7 +13,9 @@ set(kde_SRCS
|
|||
StringRepository.cpp
|
||||
Hash.h
|
||||
Hash.cpp
|
||||
GameState.h)
|
||||
GameState.h
|
||||
Font.cpp
|
||||
Font.h)
|
||||
|
||||
if (ANDROID)
|
||||
message(STATUS "Building for Android")
|
||||
|
|
1
app/src/main/cpp/Font.cpp
Normal file
1
app/src/main/cpp/Font.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "Font.h"
|
25
app/src/main/cpp/Font.h
Normal file
25
app/src/main/cpp/Font.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef KRIMI_DINNER_ENGINE_FONT_H
|
||||
#define KRIMI_DINNER_ENGINE_FONT_H
|
||||
|
||||
#include "stb_truetype.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "glad.h"
|
||||
#else
|
||||
#include <GLES3/gl3.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// Data that defines a font
|
||||
struct FontData
|
||||
{
|
||||
stbtt_bakedchar char_data[225];
|
||||
float char_height;
|
||||
float scale_factor;
|
||||
int ascent;
|
||||
int descent;
|
||||
int line_gap;
|
||||
float baseline_adjust;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -51,6 +51,7 @@ NativeEngine::NativeEngine(struct android_app *app)
|
|||
// BEISPIELCODE
|
||||
m_smiley = StringRepository::global->internString("smiley_PNG42.png");
|
||||
m_smiley_pos = { 100, 100 };
|
||||
AssetManager::ptr->loadFontData("Milky Honey.ttf", 24.f, &m_font);
|
||||
// ENDE VOM BEISPIELCODE
|
||||
}
|
||||
|
||||
|
@ -174,12 +175,12 @@ void NativeEngine::gameLoop()
|
|||
|
||||
|
||||
// BEISPIELCODE
|
||||
static float x = 1.f;
|
||||
static float t = 1.f;
|
||||
static float d = -0.01f;
|
||||
x += d;
|
||||
if ( x <= 0.f)
|
||||
t += d;
|
||||
if (t <= 0.f)
|
||||
d *= -1.f;
|
||||
else if (x >= 1.f)
|
||||
else if (t >= 1.f)
|
||||
d *= -1.f;
|
||||
|
||||
if (input_event_count > 0) {
|
||||
|
@ -189,7 +190,35 @@ void NativeEngine::gameLoop()
|
|||
}
|
||||
|
||||
Renderer::ptr->addRect(100, 100, 500, 500, 0.3f, 0.3f, 0.3f, 1.f);
|
||||
Renderer::ptr->addRect(m_smiley_pos.x, m_smiley_pos.y, 500, 500, 0.f, x*x, 1.f - x*x, 1.f, m_smiley);
|
||||
Renderer::ptr->addRect(m_smiley_pos.x, m_smiley_pos.y, 500, 500, 0.f, t*t, 1.f - t*t, 1.f, m_smiley);
|
||||
|
||||
|
||||
float x = 50;
|
||||
float y = 50;
|
||||
|
||||
float start_x = x;
|
||||
float start_y = y;
|
||||
y += m_font.baseline_adjust;
|
||||
const char* text = "Hallo Welt";
|
||||
for (const char* c = text; *c != '\0'; ++c) {
|
||||
if (*c >= 32) {
|
||||
stbtt_aligned_quad quad;
|
||||
stbtt_GetBakedQuad(m_font.char_data, 512, 512, (int)*c - 32, &x, &y, &quad, 1);
|
||||
float w = quad.x1 - quad.x0;
|
||||
float h = quad.y1 - quad.y0;
|
||||
|
||||
|
||||
Renderer::ptr->addFontRect(
|
||||
x, y,
|
||||
w, h,
|
||||
1.f, 1.f, 1.f, 1.f,
|
||||
24.f,
|
||||
StringRepository::global->internString("Milky Honey.ttf"),
|
||||
quad.s0, quad.t0,
|
||||
quad.s1, quad.t1);
|
||||
ALOGI("%f %f %f %f", quad.x0, quad.y0, quad.x1, quad.y1);
|
||||
}
|
||||
}
|
||||
// ENDE VOM BEISPIELCODE
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include "StringRepository.h"
|
||||
#include "GameState.h"
|
||||
|
||||
#include "Font.h"
|
||||
|
||||
#include <game-activity/native_app_glue/android_native_app_glue.h>
|
||||
#include <EGL/egl.h>
|
||||
|
||||
|
@ -61,6 +63,9 @@ private:
|
|||
StringHandle m_smiley;
|
||||
Position m_smiley_pos;
|
||||
|
||||
StringHandle m_font_bitmap;
|
||||
FontData m_font;
|
||||
|
||||
Position m_last_down;
|
||||
bool m_in_motion;
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@ static const char* g_vert_src = "#version 300 es
|
|||
"layout (location = 2) in vec2 v_src_p0; \n"
|
||||
"layout (location = 3) in vec2 v_src_p1; \n"
|
||||
"layout (location = 4) in vec4 v_color; // color \n"
|
||||
"layout (location = 5) in int v_expand_r; // \n"
|
||||
"out vec4 f_color; \n"
|
||||
"out vec2 f_uv; \n"
|
||||
"flat out int f_expand_r; \n"
|
||||
"const vec2 vertices[6] = vec2[6]( \n"
|
||||
" vec2(-1,-1), \n"
|
||||
" vec2(+1, -1), \n"
|
||||
|
@ -39,17 +41,21 @@ static const char* g_vert_src = "#version 300 es
|
|||
" 1.0); \n"
|
||||
" f_color = v_color; \n"
|
||||
" f_uv = src; \n"
|
||||
" f_expand_r = v_expand_r; \n"
|
||||
"} \n";
|
||||
|
||||
static const char* g_frag_src = "#version 300 es \n"
|
||||
"precision mediump float; \n"
|
||||
"in vec2 f_uv; \n"
|
||||
"in vec4 f_color; \n"
|
||||
"flat in int f_expand_r; \n"
|
||||
"layout (location = 0) out vec4 frag_color; \n"
|
||||
"uniform sampler2D s_texture; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
" vec4 tex_color = texture(s_texture, f_uv); \n"
|
||||
" if (f_expand_r == 1) \n"
|
||||
" tex_color = tex_color.rrrr; \n"
|
||||
" frag_color = tex_color * f_color; \n"
|
||||
"} \n";
|
||||
|
||||
|
@ -112,16 +118,19 @@ Renderer::Renderer()
|
|||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(4 * sizeof(float)));
|
||||
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(6 * sizeof(float)));
|
||||
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(Rect), (GLvoid*)(8 * sizeof(float)));
|
||||
glVertexAttribPointer(5, 1, GL_INT, GL_FALSE, sizeof(Rect), (GLvoid*)(12 * sizeof(float)));
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glEnableVertexAttribArray(3);
|
||||
glEnableVertexAttribArray(4);
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribDivisor(0, 1);
|
||||
glVertexAttribDivisor(1, 1);
|
||||
glVertexAttribDivisor(2, 1);
|
||||
glVertexAttribDivisor(3, 1);
|
||||
glVertexAttribDivisor(4, 1);
|
||||
glVertexAttribDivisor(5, 1);
|
||||
glBindVertexArray(0);
|
||||
|
||||
// Dummy texture (1x1px white)
|
||||
|
@ -203,16 +212,59 @@ void Renderer::addRect(float x,
|
|||
rect.dst_p1_y = y + h;
|
||||
rect.src_p0_x = src_x;
|
||||
rect.src_p0_y = src_y;
|
||||
rect.src_p1_x = src_w;
|
||||
rect.src_p1_x = src_x + src_w;
|
||||
rect.src_p1_y = src_y + src_h;
|
||||
rect.r = r;
|
||||
rect.g = g;
|
||||
rect.b = b;
|
||||
rect.a = a;
|
||||
rect.expand_r = 0;
|
||||
m_rects.push_back(rect);
|
||||
m_draw_textures.push_back(texture);
|
||||
}
|
||||
|
||||
void Renderer::addFontRect(float x,
|
||||
float y,
|
||||
float w,
|
||||
float h,
|
||||
float r,
|
||||
float g,
|
||||
float b,
|
||||
float a,
|
||||
float char_height,
|
||||
StringHandle font,
|
||||
float src_x0,
|
||||
float src_y0,
|
||||
float src_x1,
|
||||
float src_y1)
|
||||
{
|
||||
if (m_textures.find(font) == m_textures.end()) {
|
||||
Texture tex;
|
||||
if (!AssetManager::ptr->loadFontBitmap(StringRepository::global->getString(font), char_height, &tex)) {
|
||||
ALOGE("Failed to load texture");
|
||||
return;
|
||||
}
|
||||
m_textures.insert(std::make_pair(font, tex));
|
||||
}
|
||||
|
||||
Rect rect = {};
|
||||
rect.dst_p0_x = x;
|
||||
rect.dst_p0_y = y;
|
||||
rect.dst_p1_x = x + w;
|
||||
rect.dst_p1_y = y + h;
|
||||
rect.src_p0_x = src_x0;
|
||||
rect.src_p0_y = src_y0;
|
||||
rect.src_p1_x = src_x1;
|
||||
rect.src_p1_y = src_y1;
|
||||
rect.r = r;
|
||||
rect.g = g;
|
||||
rect.b = b;
|
||||
rect.a = a;
|
||||
rect.expand_r = 1;
|
||||
m_rects.push_back(rect);
|
||||
m_draw_textures.push_back(font);
|
||||
}
|
||||
|
||||
void Renderer::renderFrame(float width, float height)
|
||||
{
|
||||
assert(m_rects.size() == m_draw_textures.size());
|
||||
|
|
|
@ -114,6 +114,36 @@ public:
|
|||
float src_w,
|
||||
float src_h);
|
||||
|
||||
/// @brief Adds a tinted font rectangle to the screen
|
||||
/// \param x X-coordinate of the top-left corner
|
||||
/// \param y Y-coordinate of the top-left corner
|
||||
/// \param w width in pixels
|
||||
/// \param h height in pixels
|
||||
/// \param r red [0,1]
|
||||
/// \param g green [0,1]
|
||||
/// \param b blue [0,1]
|
||||
/// \param a alpha [0,1]
|
||||
/// \param char_height Height of characters in pixels
|
||||
/// \param font String handle in the global string repository of the ttf file name
|
||||
/// \param src_x top left corner of the source rectangle inside the texture [0, 1]
|
||||
/// \param src_y top left corner of the source rectangle inside the texture [0, 1]
|
||||
/// \param src_w width of the source rectangle inside the texture [0, 1]
|
||||
/// \param src_h height of the source rectangle inside the texture [0, 1]
|
||||
void addFontRect(float x,
|
||||
float y,
|
||||
float w,
|
||||
float h,
|
||||
float r,
|
||||
float g,
|
||||
float b,
|
||||
float a,
|
||||
float char_height,
|
||||
StringHandle font,
|
||||
float src_x,
|
||||
float src_y,
|
||||
float src_w,
|
||||
float src_h);
|
||||
|
||||
/// @brief Renders the frame
|
||||
///
|
||||
/// You don't need to call this.
|
||||
|
@ -135,6 +165,7 @@ private:
|
|||
float src_p0_x, src_p0_y;
|
||||
float src_p1_x, src_p1_y;
|
||||
float r, g, b, a;
|
||||
int expand_r;
|
||||
};
|
||||
|
||||
GLuint m_shader;
|
||||
|
|
|
@ -23,6 +23,29 @@ Texture::Texture(unsigned int width, unsigned int height, const void *data)
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
Texture::Texture(unsigned int width, unsigned int height, const void* data, GLint format)
|
||||
: m_texture(0)
|
||||
{
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glGenTextures(1, &m_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_R8,
|
||||
static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height),
|
||||
0,
|
||||
GL_RED,
|
||||
GL_UNSIGNED_BYTE,
|
||||
data);
|
||||
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_NEAREST);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void Texture::destroy()
|
||||
{
|
||||
glDeleteTextures(1, &m_texture);
|
||||
|
|
|
@ -18,6 +18,8 @@ class Texture
|
|||
public:
|
||||
Texture() : m_texture(0) {}
|
||||
Texture(unsigned int width, unsigned int height, const void* data);
|
||||
Texture(unsigned int width, unsigned int height, const void* data, GLint format);
|
||||
|
||||
Texture(const Texture&) = default;
|
||||
Texture(Texture&&) = default;
|
||||
Texture& operator=(const Texture&) = default;
|
||||
|
|
5017
app/src/main/cpp/stb_truetype.h
Normal file
5017
app/src/main/cpp/stb_truetype.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user