Progress on fonts
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
target_link_libraries(${DAWN_TARGET_NAME}
|
||||
PUBLIC
|
||||
glm
|
||||
stb
|
||||
)
|
||||
|
||||
# Includes
|
||||
|
@ -28,6 +28,7 @@ extern "C" {
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include <stb_truetype.h>
|
||||
// #include <iterator>
|
||||
// #include <algorithm>
|
||||
// #include <string>
|
||||
|
@ -6,5 +6,5 @@
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Font.cpp
|
||||
TrueTypeFont.cpp
|
||||
)
|
@ -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;
|
@ -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 {
|
||||
|
196
src/dawn/display/font/TrueTypeFont.cpp
Normal file
196
src/dawn/display/font/TrueTypeFont.cpp
Normal 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;
|
||||
}
|
117
src/dawn/display/font/TrueTypeFont.hpp
Normal file
117
src/dawn/display/font/TrueTypeFont.hpp
Normal 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
105
src/dawn/util/mathutils.hpp
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user