Progress on fonts

This commit is contained in:
2022-10-23 09:56:26 -07:00
parent f486caddd2
commit 2764a2ac42
8 changed files with 426 additions and 9 deletions

View File

@ -7,6 +7,7 @@
target_link_libraries(${DAWN_TARGET_NAME}
PUBLIC
glm
stb
)
# Includes

View File

@ -28,6 +28,7 @@ extern "C" {
#include <thread>
#include <map>
#include <array>
#include <stb_truetype.h>
// #include <iterator>
// #include <algorithm>
// #include <string>

View File

@ -6,5 +6,5 @@
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Font.cpp
TrueTypeFont.cpp
)

View File

@ -1,8 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Font.hpp"
using namespace Dawn;

View File

@ -7,7 +7,12 @@
#pragma once
#include "display/mesh/Mesh.hpp"
#include "util/mathutils.hpp"
#include "display/Texture.hpp"
#include "display/mesh/QuadMesh.hpp"
#define FONT_NEWLINE '\n'
#define FONT_SPACE ' '
namespace Dawn {
class FontMeasure {

View File

@ -0,0 +1,196 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "TrueTypeFont.hpp"
using namespace Dawn;
void TrueTypeFont::bakeQuad(truetypequad_t *quad,float_t *x,float_t *y,char c){
stbtt_GetBakedQuad(
this->characterData,
this->texture.getWidth(), this->texture.getHeight(),
((int32_t)c) - TRUETYPE_FIRST_CHAR,
x, y, quad,
TRUETYPE_FILL_MODE
);
}
float_t TrueTypeFont::getScale(float_t scale) {
return scale / this->fontSize;
}
float_t TrueTypeFont::getSpaceSize(float_t fontSize) {
return mathRoundFloat(this->fontSize * 0.3f);
}
float_t TrueTypeFont::getInitialLineHeight(float_t fontSize) {
return mathRoundFloat(this->getScale(fontSize) * 11.0f);
}
void TrueTypeFont::buffer(
std::string text,
float_t fontSize,
float_t maxWidth,
Mesh &mesh,
FontMeasure &measure
) {
// truetypequad_t *quads;
// int32_t stringLength, wordStart, i, j;
// float_t x, y, wordX;
// float_t scale;
// char c;
// truetypequad_t *quad;
auto stringLength = text.length();
if(stringLength == 0) {
info->length = 0;
info->realLength = 0;
info->lineCount = 0;
info->lines[0].start = 0;
info->lines[0].length = 0;
info->height = 0;
info->width = 0;
mesh.createBuffers(0, 0);
return;
}
auto quads = new truetypequad_t[stringLength];
// Get the font scale
auto scale = this->getScale(fontSize);
// Adjust the max width to match the scale, and allow "no max width".
maxWidth = maxWidth == -1 ? 9999999 : maxWidth * (1 / scale);
// Which index in the original text var is the current word from
int32_t wordStart = 0;
// Setup Scales
info->length = 0;
info->realLength = 0;
info->lineCount = 0;
// Prepare the line counters
info->lines[0].start = 0;
info->lines[0].length = 0;
// Reset Dimensions
info->width = info->height = 0;
// Setup the initial loop state, and X/Y coords for the quad.
int32_t i = 0;
float_t x = 0;
float_t y = this->getInitialLineHeight(fontSize);
float_t wordX = 0;
char c;
while(c = text[i++]) {
info->length++;
// When space, start of new word about to begin
if(c == FONT_SPACE) {
x += this->getSpaceSize(fontSize);
// Did this space cause a newline?
if(x > maxWidth) {
trueTypeTextBufferAddLine(info, info->realLength, 0);
y += this->getLineHeight(fontSize);
x = 0;
}
wordX = x;
wordStart = info->realLength;
continue;
}
// New line.
if(c == FONT_NEWLINE) {
trueTypeTextBufferAddLine(info, info->realLength, 0);
wordStart = info->realLength;
y += this->getLineHeight(fontSize);
x = 0;
continue;
}
// Generate the quad.
auto quad = quads + info->realLength;
this->bakeQuad(quad, &x, &y, c);
// Now measure the width of the line (take the right side of that quad)
if(quad->x1 > maxWidth) {
// We've exceeded the edge, go back to the start of the word and newline.
x = quad->x1 - wordX;
for(auto j = wordStart; j <= info->realLength; j++) {
quad = quads + j;
quad->x0 -= wordX;
quad->x1 -= wordX;
quad->y0 += this->getLineHeight(fontSize);
quad->y1 += this->getLineHeight(fontSize);
}
// Go back to the previous (still current) line and remove the chars
info->lines[info->lineCount].length -= info->realLength - wordStart;
// Next line begins with this word
y += this->getLineHeight(fontSize);
trueTypeTextBufferAddLine(info, wordStart, info->realLength-wordStart);
wordX = 0;
}
info->lines[info->lineCount].length++;
info->realLength++;
}
info->lineCount++;
// Initialize primitive
mesh.createBuffers(
QUAD_VERTICE_COUNT * info->realLength,
QUAD_INDICE_COUNT * info->realLength
);
for(auto j = 0; j < info->realLength; j++) {
auto quad = quads + j;
// Scale the Quad
if(scale != 1.0) {
quad->x0 *= scale;
quad->x1 *= scale;
quad->y0 *= scale;
quad->y1 *= scale;
}
// Update the dimensions.
info->width = mathMax<float_t>(info->width, quad->x1);
info->height = mathMax<float_t>(info->height, quad->y1);
// Buffer the quad.
QuadMesh::bufferQuadMesh(mesh,
glm::vec2(quad->x0, quad->y0), glm::vec2(quad->s0, quad->t0),
glm::vec2(quad->x1, quad->y1), glm::vec2(quad->s1, quad->t1),
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
);
}
delete quads;
}
Texture & TrueTypeFont::getTexture() {
return this->texture;
}
void TrueTypeFont::draw(Mesh &mesh, int32_t startchar, int32_t length) {
mesh.draw(
MESH_DRAW_MODE_TRIANGLES,
startchar * QUAD_INDICE_COUNT,
length == -1 ? length : length * QUAD_INDICE_COUNT
);
}
float_t TrueTypeFont::getLineHeight(float_t fontSize) {
return mathRoundFloat(this->getScale(fontSize) * 14.0f);
}
float_t TrueTypeFont::getDefaultFontSize() {
return this->fontSize;
}

View File

@ -0,0 +1,117 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "Font.hpp"
#ifndef STB_TRUETYPE_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.h>
#endif
namespace Dawn {
/** Which character (ASCII) to start the font from */
#define TRUETYPE_FIRST_CHAR 32
/** How many characters (after the first char) to generate */
#define TRUETYPE_NUM_CHARS 96
/** Refer to STBTT docs for OpenGL Fill Mode v d3d Fill Modes */
#define TRUETYPE_FILL_MODE 1
typedef stbtt_bakedchar truetypechar_t;
typedef stbtt_aligned_quad truetypequad_t;
class TrueTypeFontMeasure : public FontMeasure {
public:
// typedef struct {
// /** What (real character) index the line starts at */
// int32_t start;
// /** How many (real) characters the line is in length */
// int32_t length;
// } truetypefontinfoline_t;
// typedef struct {
// /** How many raw chars are in the string */
// int32_t length;
// /** How many real characters (non whitespace) are in the string */
// int32_t realLength;
// /** How many lines is the string? Trailing newlines will count */
// int32_t lineCount;
// /** The real character info for each line */
// truetypefontinfoline_t lines[256];
// /** Dimensions of the string */
// float_t width, height;
// } truetypefontinfo_t;
};
class TrueTypeFont : public Font {
protected:
/**
* Calculate the quad information for a given character.
*
* @param font Font to get the character from.
* @param quad Pointer to the quad to store the quad information in.
* @param x Pointer to the X position for the quad.
* @param y Pointer to the Y position for the quad.
* @param c Character to get the quad and position information for.
*/
void bakeQuad(truetypequad_t *quad, float_t *x, float_t *y, char c);
/**
* Returns the font scale to use for rendering your desired font size at a
* font size that is different than the precompiled font size for this
* true type font. For example, let's say you render your font size at 36
* when you are precompiling it, but rather than creating a new font just
* to add a size 24, you can instead use this method to get the scale to
* use to downscale your font to match.
*
* @param font TrueType font to get the scale of.
* @param fontSize Font size you desire.
* @return The scale used to get the font size that will match.
*/
float_t getScale(float_t fontSize);
/**
* Returns the size of a space character for a given font.
*
* @param fontSize Font size of the font to get the space size for.
* @return The size of the space character.
*/
float_t getSpaceSize(float_t fontSize);
/**
* Returns the initial line height of a font.
*
* @param fontSize Font size for the font to get the line height of.
* @return The line height initial value.
*/
float_t getInitialLineHeight(float_t fontSize);
public:
Texture texture;
float_t fontSize;
truetypechar_t characterData[TRUETYPE_NUM_CHARS];
void init() override;
void buffer(
std::string text,
float_t fontSize,
float_t maxWidth,
Mesh &mesh,
FontMeasure &measure
) override;
Texture & getTexture() override;
void draw(Mesh &mesh, int32_t startCharacter, int32_t length) override;
float_t getLineHeight(float_t fontSize) override;
float_t getDefaultFontSize() override;
};
}

105
src/dawn/util/mathutils.hpp Normal file
View File

@ -0,0 +1,105 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawnlibs.hpp"
#define MATH_PI 3.1415926535897f
/**
* Returns the largest of the two provided int32 numbers.
*
* @param left Left number to get the largest of.
* @param right Right number to get the largest of.
* @return The larger of the two numbers
*/
template<typename T>
static inline T mathMax(T left, T right) {
return left < right ? right : left;
}
/**
* Returns the smallest of two provided int32 numbers.
*
* @param left Left number to get the smallest of.
* @param right Right number to get the smallest of.
* @return Smaller of the two numbers.
*/
template<typename T>
static inline T mathMin(T left, T right) {
return left < right ? left : right;
}
/**
* Returns the input value, constrained between the min and max values, so that
* the value cannot underceed the min, and cannot exceed the max.
*
* @param val Value to get the clamp for.
* @param min Minimum clamping value.
* @param max Maximum clamping value.
* @return The value, or the closest clamped value.
*/
template<typename T>
static inline T mathClamp(T val, T min, T max) {
return mathMin<T>(mathMax<T>(val, min), max);
}
/**
* Returns the absolute value (the non-negative representation of) for the given
* int32 number.Abs values will be -value if value < 0.
*
* @param value Value to get the absolute value for.
* @return The absolute value (-value if value < 0)
*/
template<typename T>
static inline T mathAbs(T value) {
return value < 0 ? -value : value;
}
template<typename T>
static inline int32_t mathMod(T value, T modulo) {
return ((value % modulo) + modulo) % modulo;
}
// Float-specific
/**
* Convert degrees to radians.
*
* @param n Degrees to convert.
* @returns The number in radians.
*/
static inline float_t mathDeg2Rad(float_t degrees) {
return degrees * (MATH_PI / 180.0f);
}
/**
* Convert radians to degrees.
* @param n Radians to convert.
* @returns The number in degrees.
*/
static inline float_t mathRad2Deg(float_t n) {
return (n * 180.0f) / MATH_PI;
}
/**
* Round a number to the nearest whole number.
* @param n Number to round.
* @return Rounded number.
*/
static inline float_t mathRoundFloat(float_t n) {
return roundf(n);
}
/**
* Rounds the number down to the nearest whole number.
* @param n Number to round down.
* @return Rounded number.
*/
static inline float_t mathFloorFloat(float_t n) {
return floorf(n);
}