Font round 1

This commit is contained in:
2023-06-02 21:04:35 -07:00
parent af75bb546a
commit 19eabe6e76
12 changed files with 258 additions and 40 deletions

View File

@ -7,7 +7,12 @@
#include "dawnlibs.hpp"
namespace Dawn {
struct Color {
struct ColorU8 {
uint8_t r, g, b, a;
};
#pragma pack(push, 1)
struct __attribute__ ((packed)) Color {
float_t r, g, b, a;
struct Color operator * (const float_t &x) {
@ -36,7 +41,17 @@ namespace Dawn {
a + color.a
};
}
operator struct ColorU8() const {
return {
(uint8_t)(r * 255),
(uint8_t)(g * 255),
(uint8_t)(b * 255),
(uint8_t)(a * 255)
};
}
};
#pragma pack(pop)
#define COLOR_WHITE { 1.0f, 1.0f, 1.0f, 1.0f }
#define COLOR_RED { 1.0f, 0, 0, 1.0f }

View File

@ -99,7 +99,7 @@ namespace Dawn {
* @param pixels Array of pixels you're trying to buffer.
* @return The amount of bytes buffered to the texture.
*/
virtual void buffer(struct Color pixels[]) = 0;
virtual void buffer(struct ColorU8 pixels[]) = 0;
virtual void buffer(uint8_t pixels[]) = 0;
};
}

View File

@ -8,37 +8,185 @@
using namespace Dawn;
void _uiLabelBake(
struct UILabelFontDef &fontDef,
FT_Face &face,
uint32_t fontSize
) {
fontDef.face = &face;
fontDef.fontSize = fontSize;
if(FT_Set_Pixel_Sizes(face, 0, fontSize)) {
assertUnreachable();
}
size_t w = 0, h = 0;
FT_ULong c;
for(c = NEW_LABEL_CHAR_BEGIN; c < NEW_LABEL_CHAR_END; c++) {
// Load the character
if(FT_Load_Char(face, c, FT_LOAD_RENDER | FT_LOAD_MONOCHROME)) {
assertUnreachable();
}
// Update the width and height
w = mathMax<size_t>(w, face->glyph->bitmap.width);
h += face->glyph->bitmap.rows;
}
// Now buffer pixels to the texture
float_t y = 0;
// I'd love to just buffer straight to the GPU, but it seems that is a bit
// unstable right now.
uint8_t *buffer = (uint8_t *)memoryAllocate(w * h * sizeof(uint8_t));
memorySet(buffer, 0x00, sizeof(uint8_t) * w * h);
size_t offset = 0;
for(c = NEW_LABEL_CHAR_BEGIN; c < NEW_LABEL_CHAR_END; c++) {
// Load the character
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
assertUnreachable();
}
// Store the character information
struct UILabelChar info;
info.advanceX = face->glyph->advance.x;
info.advanceY = face->glyph->advance.y;
info.bitmapSize = glm::vec2(face->glyph->bitmap.width, face->glyph->bitmap.rows);
info.bitmapPosition = glm::vec2(face->glyph->bitmap_left, -face->glyph->bitmap_top);
info.textureY = y;
fontDef.charStore[c] = info;
// Buffer the pixels, oh dear GOD there has to be a more efficient way.
for(int32_t i = 0; i < face->glyph->bitmap.rows; i++) {
memoryCopy(
(void *)(face->glyph->bitmap.buffer + (i * face->glyph->bitmap.width)),
(void *)(buffer + offset),
face->glyph->bitmap.width * sizeof(uint8_t)
);
offset += w * sizeof(uint8_t);
}
y += face->glyph->bitmap.rows;
}
fontDef.texture.setSize(w, h, TEXTURE_FORMAT_R);
fontDef.texture.buffer(buffer);
memoryFree(buffer);
}
int32_t _uiLabelQuad(
std::string text,
Mesh *mesh,
struct FontShaderBufferData &bufferData,
struct UILabelFontDef &fontDef,
glm::vec2 &position,
int32_t quadStart,
int32_t partIndex
) {
int32_t len = text.length();
if(mesh == nullptr) return len;
// Loop each char
glm::vec2 wh = glm::vec2(fontDef.texture.getWidth(), fontDef.texture.getHeight());
for(int32_t i = 0; i < len; i++) {
int32_t j = quadStart + i;
FT_ULong c = text[i];
auto &charInfo = fontDef.charStore[c];
glm::vec2 uv0 = glm::vec2(0.0f, charInfo.textureY) / wh;
glm::vec2 uv1 = uv0 + (charInfo.bitmapSize / wh);
QuadMesh::bufferQuadMeshWithZ(mesh,
position + charInfo.bitmapPosition, uv0,
position + charInfo.bitmapPosition + charInfo.bitmapSize, uv1,
0.0f,
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
);
position.x += (float_t)(charInfo.advanceX >> 6);
position.y += (float_t)(charInfo.advanceY >> 6);
bufferData.fontQuadParts[j] = partIndex;
}
return len;
}
UILabelNew::UILabelNew(SceneItem *item) : UIComponentRenderable(item) {
}
void UILabelNew::onStart() {
std::cout << "Hello new Label" << std::endl;
this->shaderBuffer.init();
if(FT_New_Face(
getGame()->renderManager.getFontManager()->fontLibrary,
"/usr/share/fonts/TTF/arial.ttf",
0,
&face
)) {
assertUnreachable();
}
_uiLabelBake(defFace, face, 32);
if(FT_New_Face(
getGame()->renderManager.getFontManager()->fontLibrary,
"/usr/share/fonts/TTF/arialbd.ttf",
0,
&faceBold
)) {
assertUnreachable();
}
_uiLabelBake(defFaceBold, faceBold, 32);
if(FT_New_Face(
getGame()->renderManager.getFontManager()->fontLibrary,
"/usr/share/fonts/TTF/ariali.ttf",
0,
&faceItalics
)) {
assertUnreachable();
}
_uiLabelBake(defFaceItalics, faceItalics, 32);
struct FontShaderBufferData fontData;
int32_t n = 4 * 4;
this->mesh.createBuffers(n * QUAD_VERTICE_COUNT, n * QUAD_INDICE_COUNT);
for(int32_t i = 0; i < n; i++) {
glm::vec2 size = glm::vec2(32, 32);
glm::vec2 pos = glm::vec2(size.x * i, 0) + glm::vec2(2 * i, 0);
QuadMesh::bufferQuadMeshWithZ(&this->mesh,
pos, glm::vec2(0, 0),
pos + size, glm::vec2(1, 1),
0.0f, i * QUAD_VERTICE_COUNT, i * QUAD_INDICE_COUNT
);
fontData.fontQuadParts[i] = i / 4;
}
glm::vec2 position = glm::vec2(0, defFace.fontSize);
fontData.fontParts[0].color = COLOR_RED;
fontData.fontParts[1].color = COLOR_GREEN;
fontData.fontParts[2].color = COLOR_BLUE;
fontData.fontParts[3].color = COLOR_MAGENTA;
fontData.fontParts[4].color = COLOR_BLACK;
fontData.fontParts[5].color = COLOR_WHITE;
testMesh.createBuffers(QUAD_VERTICE_COUNT * 96, QUAD_INDICE_COUNT * 96);
auto x = _uiLabelQuad(
"Hello",
&this->testMesh,
fontData,
defFace,
position,
0,
0
);
x += _uiLabelQuad(
"World",
&this->testMesh,
fontData,
defFaceItalics,
position,
x,
1
);
fontData.fontParts[0].color = COLOR_BLUE;
fontData.fontParts[0].texture = 0;
fontData.fontParts[1].color = COLOR_RED;
fontData.fontParts[1].texture = 1;
shaderBuffer.buffer(&fontData);
}
@ -48,10 +196,15 @@ std::vector<struct ShaderPassItem> UILabelNew::getUIRenderPasses() {
struct ShaderPassItem item;
item.shader = shader;
item.mesh = &mesh;
item.mesh = &testMesh;
item.matrixValues[shader->paramModel] = transform->getWorldTransform();
item.parameterBuffers[shader->bufferUiCanvas] = &canvas->shaderBuffer;
item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer;
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
item.textureSlots[0] = &defFace.texture;
item.textureSlots[1] = &defFaceItalics.texture;
item.textureValues[shader->paramTexture0] = 0;
item.textureValues[shader->paramTexture1] = 1;
return { item };
}

View File

@ -7,11 +7,45 @@
#include "scene/components/ui/UIComponentRenderable.hpp"
#include "display/mesh/QuadMesh.hpp"
#define NEW_LABEL_CHAR_BEGIN 0x00
#define NEW_LABEL_CHAR_END 0xFF
namespace Dawn {
struct UILabelChar {
int32_t advanceX;
int32_t advanceY;
glm::vec2 bitmapSize;
glm::vec2 bitmapPosition;
float_t textureY;
};
struct UILabelFontDef {
Texture texture;
uint32_t fontSize;
FT_Face *face;
std::map<FT_ULong, struct UILabelChar> charStore;
};
struct UILabelPart {
UILabelFontDef *fontDef;
std::string text;
};
class UILabelNew : public UIComponentRenderable {
protected:
Mesh mesh;
FontShaderBuffer shaderBuffer;
FontShaderBuffer shaderBuffer;
Mesh testMesh;
FT_Face face;
FT_Face faceBold;
FT_Face faceItalics;
struct UILabelFontDef defFace;
struct UILabelFontDef defFaceBold;
struct UILabelFontDef defFaceItalics;
public:
UILabelNew(SceneItem *item);

View File

@ -11,6 +11,7 @@
#include "scene/components/physics/3d/CubeCollider.hpp"
#include "scene/components/physics/2d/Collider2D.hpp"
#include "scene/components/physics/2d/BoxCollider.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
@ -26,14 +27,12 @@ struct ShaderPassItem SceneDebugLine::createShaderItem(
assertNotNull(shader);
struct ShaderPassItem item;
item.shader = shader;
item.priority = this->priority;
item.shaderProgram = &shader->program;
item.colorValues[shader->program.paramColor] = this->color;
item.matrixValues[shader->program.paramModel] = this->transform;
item.matrixValues[shader->program.paramView] = camera->transform->getWorldTransform();
item.matrixValues[shader->program.paramProjection] = camera->getProjection();
item.boolValues[shader->program.paramHasTexture] = false;
item.colorValues[shader->paramColor] = this->color;
item.matrixValues[shader->paramModel] = this->transform;
item.parameterBuffers[shader->bufferRenderPipeline] = &camera->getGame()->renderManager.getRenderPipeline()->shaderBuffer;
item.boolValues[shader->paramHasTexture] = false;
auto i = *lineIndex;
item.mesh = mesh;

View File

@ -7,6 +7,7 @@
#include "display/Color.hpp"
#include "display/mesh/Mesh.hpp"
#include "display/shader/ShaderManager.hpp"
#include "display/shader/ShaderPass.hpp"
#define SCENE_DEBUG_LINE_VERTICE_COUNT 2
#define SCENE_DEBUG_LINE_INDICE_COUNT 2

View File

@ -184,7 +184,7 @@ void Texture::bufferRaw(void *data) {
this->texturePropertiesNeedUpdating = true;
}
void Texture::buffer(struct Color pixels[]) {
void Texture::buffer(struct ColorU8 pixels[]) {
this->bufferRaw((void*)pixels);
}

View File

@ -32,7 +32,7 @@ namespace Dawn {
void fill(struct Color) override;
void fill(uint8_t) override;
bool_t isReady() override;
void buffer(struct Color pixels[]) override;
void buffer(struct ColorU8 pixels[]) override;
void buffer(uint8_t pixels[]) override;
/**

View File

@ -22,7 +22,6 @@ namespace Dawn {
void init() {
assertTrue(this->id == -1);
this->size = sizeof(T);
glGenBuffers(1, &this->id);
glBindBuffer(GL_UNIFORM_BUFFER, this->id);

View File

@ -19,24 +19,22 @@ void FontShader::compile() {
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"layout (std140) uniform ub_UICanvas {\n"
"mat4 u_View;\n"
"mat4 u_Projection;\n"
"};"
"struct FontShaderPart {\n"
"vec4 color;\n"
"int texture;\n"
"};\n"
"layout (std140) uniform ub_Font {\n"
"layout (shared) uniform ub_Font {\n"
"FontShaderPart u_FontParts[" MACRO_STRINGIFY(FONT_SHADER_PARTS_MAX) "];\n"
"int u_FontQuadParts[" MACRO_STRINGIFY(FONT_SHADER_QUADS_MAX) "];\n"
"};\n"
"uniform mat4 u_Model;\n"
"out vec2 o_TextCoord;\n"
"out vec4 o_VertColor;\n"
"flat out int o_TextIndex;\n"
"void main() {\n"
"gl_Position = u_Projection * u_View * u_Model * vec4(aPos.xy, 0, 1.0);\n"
@ -44,16 +42,27 @@ void FontShader::compile() {
"int quadIndex = gl_VertexID / " MACRO_STRINGIFY(QUAD_VERTICE_COUNT) ";\n"
"int partIndex = u_FontQuadParts[quadIndex];\n"
"o_VertColor = u_FontParts[partIndex].color;\n"
"o_TextIndex = u_FontParts[partIndex].texture;\n"
"}",
// Fragment Shader
"#version 330 core\n"
"in vec2 o_TextCoord;\n"
"in vec4 o_VertColor;\n"
"flat in int o_TextIndex;\n"
"out vec4 o_Color;\n"
"uniform sampler2D u_Text0;\n"
"uniform sampler2D u_Text1;\n"
"void main() {\n"
"o_Color = o_VertColor;\n"
"vec4 textColor;\n"
"if(o_TextIndex == 0) {\n"
"textColor = texture(u_Text0, o_TextCoord);"
"} else {\n"
"textColor = texture(u_Text1, o_TextCoord);"
"}\n"
"o_Color.a *= textColor.r;\n"
"}\n"
);
#else
@ -63,4 +72,6 @@ void FontShader::compile() {
this->paramModel = this->getParameterByName("u_Model");
this->bufferUiCanvas = this->getBufferLocationByName("ub_UICanvas");
this->bufferFont = this->getBufferLocationByName("ub_Font");
this->paramTexture0 = this->getParameterByName("u_Text0");
this->paramTexture1 = this->getParameterByName("u_Text1");
}

View File

@ -7,12 +7,14 @@
#include "UIShader.hpp"
#include "util/macro.hpp"
#define FONT_SHADER_PARTS_MAX 16
#define FONT_SHADER_QUADS_MAX 16
#define FONT_SHADER_PARTS_MAX 6
#define FONT_SHADER_QUADS_MAX 64
#define FONT_SHADER_TEXTURE_MAX 8
namespace Dawn {
struct FontShaderPart {
struct Color color;
int32_t texture;
};
struct FontShaderBufferData {
@ -27,6 +29,8 @@ namespace Dawn {
class FontShader : public Shader {
public:
shaderparameter_t paramModel;
shaderparameter_t paramTexture0;
shaderparameter_t paramTexture1;
shaderbufferlocation_t bufferUiCanvas;
shaderbufferlocation_t bufferFont;

View File

@ -44,6 +44,8 @@ void UIShader::compile() {
"void main() {\n"
"if(u_HasTexture) {\n"
"o_Color = texture(u_Text, o_TextCoord) * u_Color;\n"
// "o_Color = u_Color;\n"
// "o_Color.a = texture(u_Text, o_TextCoord).r;\n"
"} else {\n"
"o_Color = u_Color;"
"}\n"