Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

try calling freetype #205

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions skia/viewer/build/premake5.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,24 @@ includedirs {"../include", "../../../include", "../../renderer/include", "../../
"../../dependencies/skia", "../../dependencies/skia/include/core",
"../../dependencies/skia/include/effects", "../../dependencies/skia/include/gpu",
"../../dependencies/skia/include/config", "../../dependencies/imgui", "../../dependencies",
"../../dependencies/gl3w/build/include"}
"../../dependencies/gl3w/build/include",
"/Users/mike/other/freetype/include"
}

links {"Cocoa.framework", "IOKit.framework", "CoreVideo.framework", "rive", "skia", "rive_skia_renderer", "glfw3"}
links {
"Cocoa.framework", "IOKit.framework", "CoreVideo.framework",
"rive", "skia", "rive_skia_renderer", "glfw3",
"freetype",
}
libdirs {"../../../build/%{cfg.system}/bin/%{cfg.buildcfg}", "../../dependencies/glfw_build/src",
"../../dependencies/skia/out/static", "../../renderer/build/%{cfg.system}/bin/%{cfg.buildcfg}"}
"../../dependencies/skia/out/static", "../../renderer/build/%{cfg.system}/bin/%{cfg.buildcfg}",}

files {"../src/**.cpp", "../../dependencies/gl3w/build/src/gl3w.c",
"../../dependencies/imgui/backends/imgui_impl_glfw.cpp",
"../../dependencies/imgui/backends/imgui_impl_opengl3.cpp", "../../dependencies/imgui/imgui_widgets.cpp",
"../../dependencies/imgui/imgui.cpp", "../../dependencies/imgui/imgui_tables.cpp",
"../../dependencies/imgui/imgui_draw.cpp"}
"../../dependencies/imgui/imgui_draw.cpp",
}

buildoptions {"-Wall", "-fno-exceptions", "-fno-rtti", "-flto=full"}
filter "configurations:debug"
Expand All @@ -40,7 +47,7 @@ filter "configurations:release"

defines {"RELEASE"}
defines {"NDEBUG"}
optimize "On"
symbols "On"

-- Clean Function --
newaction {
Expand Down
200 changes: 200 additions & 0 deletions skia/viewer/src/fonts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
#include "fonts.hpp"

#include <cmath>
#include <string>

template <typename T> T pin(T v, T mn, T mx) {
return std::min(std::max(v, mn), mx);
}

struct FTPathSinkCaller {
private:
PathSink* m_Sink;
// we have to manually close contours
bool m_ReadyToClose = false;

static inline float dot6tofloat(int32_t x) {
return x * (1.0f/64);
}

static int Move(const FT_Vector* pt, void* ctx) {
auto caller = (FTPathSinkCaller*)ctx;
if (caller->m_ReadyToClose) {
caller->m_Sink->close();
caller->m_ReadyToClose = false;
}
caller->m_Sink->move(dot6tofloat(pt->x), -dot6tofloat(pt->y));
return 0;
}

static int Line(const FT_Vector* pt, void* ctx) {
auto caller = (FTPathSinkCaller*)ctx;
caller->m_Sink->line(dot6tofloat(pt->x), -dot6tofloat(pt->y));
caller->m_ReadyToClose = true;
return 0;
}

static int Quad(const FT_Vector* pt0, const FT_Vector* pt1, void* ctx) {
auto caller = (FTPathSinkCaller*)ctx;
caller->m_Sink->quad(dot6tofloat(pt0->x), -dot6tofloat(pt0->y),
dot6tofloat(pt1->x), -dot6tofloat(pt1->y));
caller->m_ReadyToClose = true;
return 0;
}

static int Cubic(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* ctx) {
auto caller = (FTPathSinkCaller*)ctx;
caller->m_Sink->cubic(dot6tofloat(pt0->x), -dot6tofloat(pt0->y),
dot6tofloat(pt1->x), -dot6tofloat(pt1->y),
dot6tofloat(pt2->x), -dot6tofloat(pt2->y));
caller->m_ReadyToClose = true;
return 0;
}

public:
FTPathSinkCaller(PathSink* sink) : m_Sink(sink) {}

inline static constexpr const FT_Outline_Funcs Funcs{
FTPathSinkCaller::Move,
FTPathSinkCaller::Line,
FTPathSinkCaller::Quad,
FTPathSinkCaller::Cubic,
0, // shift
0, // delta
};
};

FTLib::FTLib() : m_Lib(nullptr) {
int err = FT_Init_FreeType(&m_Lib);
if (err) {
printf("FT_Init_FreeType returned %d\n", err);
return;
}

FT_Add_Default_Modules(m_Lib);
FT_Set_Default_Properties(m_Lib);
}

FTLib::~FTLib() {
if (m_Lib) {
FT_Done_Library(m_Lib);
}
}

FTFace::~FTFace() {
if (m_Face) {
FT_Done_Face(m_Face);
}
}

static std::string tagname(uint32_t x) {
std::string str("1234");
str[0] = (x >> 24) & 0xFF;
str[1] = (x >> 16) & 0xFF;
str[2] = (x >> 8) & 0xFF;
str[3] = (x >> 0) & 0xFF;
return str;
}

static float fixed2float(int32_t x) {
return x * (1.0f/65536);
}

static int32_t float2fixed(float x) {
return (int)std::floor(x * 65536 + 0.5f);
}

void FTFace::parseAxes(FT_Library lib) {
m_Axes.clear();

FT_MM_Var* var;
int err = FT_Get_MM_Var(m_Face, &var);
if (err) {
printf("failed getting variations %d\n", err);
return;
}

assert(m_Face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS);

printf("%d axes\n", var->num_axis);
for (unsigned i = 0; i < var->num_axis; ++i) {
m_Axes.push_back({
(uint32_t)var->axis[i].tag,
fixed2float(var->axis[i].minimum),
fixed2float(var->axis[i].def),
fixed2float(var->axis[i].maximum),
});
printf(" %s %g %g %g\n",
tagname(var->axis[i].tag).c_str(),
m_Axes[i].m_Min, m_Axes[i].m_Def, m_Axes[i].m_Max);
}
FT_Done_MM_Var(lib, var);
}

bool FTFace::load(FT_Library lib, sk_sp<SkData> data) {
int face_index = 0; // todo
int err = FT_New_Memory_Face(lib, (const FT_Byte*)data->data(),
data->size(), face_index, &m_Face);
if (err) {
printf("FT_New_Memory_Face returned %d\n", err);
return false;
}
m_Data = std::move(data);

this->parseAxes(lib);

return true;
}

void FTFace::setCoords(const FTCoord user[], int count) {
std::vector<FT_Fixed> ftc(m_Axes.size());
for (size_t i = 0; i < m_Axes.size(); ++i) {
const auto& a = m_Axes[i];
float value = a.m_Def;
for (int j = 0; j < count; ++j) {
if (a.m_Tag == user[j].m_Tag) {
value = user[j].m_Value;
}
}
ftc[i] = float2fixed(pin(value, a.m_Min, a.m_Max));
}

int err = FT_Set_Var_Design_Coordinates(m_Face, ftc.size(), ftc.data());
if (err) {
printf("set design coords failed %d\n", err);
}
}

int FTFace::upem() const {
assert(m_Face);
return m_Face->units_per_EM;
}

bool FTFace::setSize(int size) {
assert(m_Face);
int err = FT_Set_Char_Size(m_Face, size * 64, 0, 72, 72);
if (err) {
printf("failed to set size %d\n", size);
return false;
}
return true;
}

bool FTFace::getPath(uint16_t glyph, PathSink* sink) {
unsigned flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
flags &= ~FT_LOAD_RENDER;

int err = FT_Load_Glyph(m_Face, glyph, flags);
assert(err == 0);

FTPathSinkCaller caller(sink);
err = FT_Outline_Decompose(&m_Face->glyph->outline,
&FTPathSinkCaller::Funcs,
&caller);
if (err) {
printf("failed calling decompose %d\n", err);
return false;
}
sink->close();
return true;
}
110 changes: 110 additions & 0 deletions skia/viewer/src/fonts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#ifndef _RIVE_FONT_HPP_
#define _RIVE_FONT_HPP_

#include "rive/rive_types.hpp"
#include "SkData.h"

#include <vector>

#include <ft2build.h>
#include FT_FREETYPE_H

#include <freetype/ftadvanc.h>
#include <freetype/ftimage.h>
#include <freetype/ftbitmap.h>
#ifdef FT_COLOR_H // 2.10.0
# include <freetype/ftcolor.h>
#endif
#include <freetype/freetype.h>
#include <freetype/ftlcdfil.h>
#include <freetype/ftmodapi.h>
#include <freetype/ftmm.h>
#include <freetype/ftoutln.h>
#include <freetype/ftsizes.h>
#include <freetype/ftsystem.h>
#include <freetype/tttables.h>
#include <freetype/t1tables.h>
#include <freetype/ftfntfmt.h>

typedef struct FT_LibraryRec_* FT_Library;
typedef struct FT_FaceRec_* FT_Face;
typedef struct FT_StreamRec_* FT_Stream;
typedef signed long FT_Pos;
typedef struct FT_BBox_ FT_BBox;

struct PathSink {
virtual void move(float x, float y) = 0;
virtual void line(float x, float y) = 0;
virtual void quad(float x0, float y0, float x1, float y1) = 0;
virtual void cubic(float x0, float y0, float x1, float y1, float x2, float y2) = 0;
virtual void close() = 0;
};

struct FTLib {
FT_Library m_Lib;

FTLib();
~FTLib();

operator bool() const { return m_Lib != nullptr; }
};

constexpr uint32_t tag(unsigned a, unsigned b, unsigned c, unsigned d) {
assert(a <= 255 && b <= 255 && c <= 255 && d <= 255);
return (a << 24) | (b << 16) | (c << 8) | d;
}

struct FTAxis {
uint32_t m_Tag;
float m_Min, m_Def, m_Max;
};

struct FTCoord {
uint32_t m_Tag;
float m_Value;
};

struct FTFace {
sk_sp<SkData> m_Data;
FT_Face m_Face;
std::vector<FTAxis> m_Axes;

FTFace() : m_Face(nullptr) {}
~FTFace();

bool load(FT_Library lib, sk_sp<SkData> data);

int axisCount() const { return (int)m_Axes.size(); }
const FTAxis* axes() const { return m_Axes.data(); }

operator bool() const { return m_Face != nullptr; }

int upem() const;
bool setSize(int size);
void setCoords(const FTCoord[], int count);

bool getPath(uint16_t glyph, PathSink* sink);

private:
void parseAxes(FT_Library);
};

struct TestSink : public PathSink {
void move(float x, float y) override {
printf("Move %g %g\n", x, y);
}
void line(float x, float y) override {
printf("line %g %g\n", x, y);
}
void quad(float x0, float y0, float x1, float y1) override {
printf("quad %g %g %g %g\n", x0, y0, x1, y1);
}
void cubic(float x0, float y0, float x1, float y1, float x2, float y2) override {
printf("cube %g %g %g %g %g %g\n", x0, y0, x1, y1, x2, y2);
}
void close() override {
printf("close\n");
}
};

#endif
Loading