mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
rewrite bmfont parser, remove sample07
This commit is contained in:
2544
headers/3rdparty/ecs.hpp/ecs.hpp
vendored
2544
headers/3rdparty/ecs.hpp/ecs.hpp
vendored
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,6 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
|
||||
@@ -9,49 +9,31 @@
|
||||
#include "_utils.hpp"
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "buffer_view.hpp"
|
||||
#include "streams.hpp"
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
class font final {
|
||||
public:
|
||||
struct info_data {
|
||||
str face;
|
||||
u32 size{0};
|
||||
};
|
||||
|
||||
struct common_data {
|
||||
u32 line{0};
|
||||
u32 base{0};
|
||||
u32 pages{0};
|
||||
struct font_info {
|
||||
str atlas_file;
|
||||
v2u atlas_size;
|
||||
u32 font_size{0};
|
||||
u32 line_height{0};
|
||||
u32 glyph_ascent{0};
|
||||
};
|
||||
|
||||
struct page_data {
|
||||
u32 id{0};
|
||||
str file;
|
||||
struct glyph_info {
|
||||
v2i offset;
|
||||
b2u tex_rect;
|
||||
i32 advance{0};
|
||||
};
|
||||
|
||||
struct char_data {
|
||||
u32 id{0};
|
||||
b2hi rect;
|
||||
v2hi offset;
|
||||
i16 advance{0};
|
||||
u16 page{0};
|
||||
u16 chnl{0};
|
||||
};
|
||||
|
||||
struct kerning_data {
|
||||
std::pair<u32, u32> chars{0,0};
|
||||
i32 amount{0};
|
||||
};
|
||||
|
||||
struct data {
|
||||
info_data info;
|
||||
common_data common;
|
||||
flat_set<page_data> pages;
|
||||
flat_map<u32, char_data> chars;
|
||||
struct content {
|
||||
font_info info;
|
||||
flat_map<u64, i32> kernings;
|
||||
flat_map<u32, glyph_info> glyphs;
|
||||
};
|
||||
public:
|
||||
font() = default;
|
||||
@@ -62,60 +44,43 @@ namespace e2d
|
||||
font(const font& other);
|
||||
font& operator=(const font& other);
|
||||
|
||||
font(data&& data) noexcept;
|
||||
font(const data& data);
|
||||
font(content&& content) noexcept;
|
||||
font(const content& content);
|
||||
|
||||
font& assign(font&& other) noexcept;
|
||||
font& assign(const font& other);
|
||||
|
||||
font& assign(data&& data) noexcept;
|
||||
font& assign(const data& data);
|
||||
font& assign(content&& content) noexcept;
|
||||
font& assign(const content& content);
|
||||
|
||||
void swap(font& other) noexcept;
|
||||
void clear() noexcept;
|
||||
bool empty() const noexcept;
|
||||
|
||||
const info_data& info() const noexcept;
|
||||
const common_data& common() const noexcept;
|
||||
const flat_set<page_data>& pages() const noexcept;
|
||||
const flat_map<u32, char_data>& chars() const noexcept;
|
||||
const font_info& info() const noexcept;
|
||||
const flat_map<u64, i32>& kernings() const noexcept;
|
||||
const flat_map<u32, glyph_info>& glyphs() const noexcept;
|
||||
|
||||
const page_data* find_page(u32 id) const noexcept;
|
||||
const char_data* find_char(u32 id) const noexcept;
|
||||
i32 get_kerning(u32 first, u32 second) const noexcept;
|
||||
const glyph_info* find_glyph(u32 code_point) const noexcept;
|
||||
private:
|
||||
data data_;
|
||||
content content_;
|
||||
};
|
||||
|
||||
void swap(font& l, font& r) noexcept;
|
||||
bool operator==(const font& l, const font& r) noexcept;
|
||||
bool operator!=(const font& l, const font& r) noexcept;
|
||||
|
||||
bool operator<(u32 l, const font::page_data& r) noexcept;
|
||||
bool operator<(const font::page_data& l, u32 r) noexcept;
|
||||
bool operator<(const font::page_data& l, const font::page_data& r) noexcept;
|
||||
|
||||
bool operator<(u32 l, const font::char_data& r) noexcept;
|
||||
bool operator<(const font::char_data& l, u32 r) noexcept;
|
||||
bool operator<(const font::char_data& l, const font::char_data& r) noexcept;
|
||||
|
||||
bool operator<(const std::pair<u32,u32>& l, const font::kerning_data& r) noexcept;
|
||||
bool operator<(const font::kerning_data& l, const std::pair<u32,u32>& r) noexcept;
|
||||
bool operator<(const font::kerning_data& l, const font::kerning_data& r) noexcept;
|
||||
|
||||
bool operator==(const font::info_data& l, const font::info_data& r) noexcept;
|
||||
bool operator==(const font::common_data& l, const font::common_data& r) noexcept;
|
||||
bool operator==(const font::page_data& l, const font::page_data& r) noexcept;
|
||||
bool operator==(const font::char_data& l, const font::char_data& r) noexcept;
|
||||
bool operator==(const font::kerning_data& l, const font::kerning_data& r) noexcept;
|
||||
bool operator==(const font::font_info& l, const font::font_info& r) noexcept;
|
||||
bool operator==(const font::glyph_info& l, const font::glyph_info& r) noexcept;
|
||||
bool operator==(const font::content& l, const font::content& r) noexcept;
|
||||
}
|
||||
|
||||
namespace e2d::fonts
|
||||
{
|
||||
bool try_load_font(
|
||||
font& dst,
|
||||
const buffer& src) noexcept;
|
||||
buffer_view src) noexcept;
|
||||
|
||||
bool try_load_font(
|
||||
font& dst,
|
||||
|
||||
@@ -36,5 +36,4 @@ add_e2d_sample(02)
|
||||
add_e2d_sample(03)
|
||||
add_e2d_sample(04)
|
||||
add_e2d_sample(05)
|
||||
add_e2d_sample(07)
|
||||
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include "../common.hpp"
|
||||
using namespace e2d;
|
||||
|
||||
namespace
|
||||
{
|
||||
class game_system final : public ecs::system {
|
||||
public:
|
||||
void process(ecs::registry& owner) override {
|
||||
E2D_UNUSED(owner);
|
||||
const keyboard& k = the<input>().keyboard();
|
||||
|
||||
if ( k.is_key_just_released(keyboard_key::f12) ) {
|
||||
the<dbgui>().toggle_visible(!the<dbgui>().visible());
|
||||
}
|
||||
|
||||
if ( k.is_key_just_released(keyboard_key::escape) ) {
|
||||
the<window>().set_should_close(true);
|
||||
}
|
||||
|
||||
if ( k.is_key_pressed(keyboard_key::lsuper) && k.is_key_just_released(keyboard_key::enter) ) {
|
||||
the<window>().toggle_fullscreen(!the<window>().fullscreen());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class camera_system final : public ecs::system {
|
||||
public:
|
||||
void process(ecs::registry& owner) override {
|
||||
owner.for_joined_components<camera>(
|
||||
[](const ecs::const_entity&, camera& cam){
|
||||
if ( !cam.target() ) {
|
||||
cam.viewport(
|
||||
the<window>().real_size());
|
||||
cam.projection(math::make_orthogonal_lh_matrix4(
|
||||
the<window>().real_size().cast_to<f32>(), 0.f, 1000.f));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class game final : public starter::application {
|
||||
public:
|
||||
bool initialize() final {
|
||||
return create_scene()
|
||||
&& create_systems();
|
||||
}
|
||||
private:
|
||||
bool create_scene() {
|
||||
auto scene_prefab_res = the<library>().load_asset<prefab_asset>("scene_bmf_prefab.json");
|
||||
auto scene_go = scene_prefab_res
|
||||
? the<world>().instantiate(scene_prefab_res->content())
|
||||
: nullptr;
|
||||
return !!scene_go;
|
||||
}
|
||||
bool create_systems() {
|
||||
ecs::registry_filler(the<world>().registry())
|
||||
.system<game_system>(world::priority_update)
|
||||
.system<camera_system>(world::priority_pre_render);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int e2d_main(int argc, char *argv[]) {
|
||||
const auto starter_params = starter::parameters(
|
||||
engine::parameters("sample_07", "enduro2d")
|
||||
.timer_params(engine::timer_parameters()
|
||||
.maximal_framerate(100)));
|
||||
modules::initialize<starter>(argc, argv, starter_params).start<game>();
|
||||
modules::shutdown<starter>();
|
||||
return 0;
|
||||
}
|
||||
@@ -38,20 +38,20 @@ namespace
|
||||
|
||||
f32 get_top_pos(const label& l, u32 strings_count) {
|
||||
const auto& f = l.font()->content();
|
||||
f32 label_height = f.common().line * strings_count;
|
||||
f32 label_height = f.info().line_height * strings_count;
|
||||
f32 top{0};
|
||||
switch ( l.valign() ) {
|
||||
case label::valigns::top :
|
||||
case label::valigns::top:
|
||||
top = label_height;
|
||||
break;
|
||||
case label::valigns::center :
|
||||
case label::valigns::center:
|
||||
top = 0.5f * label_height;
|
||||
break;
|
||||
case label::valigns::bottom :
|
||||
case label::valigns::bottom:
|
||||
top = 0;
|
||||
break;
|
||||
case label::valigns::baseline :
|
||||
top = label_height - (f.common().line - f.common().base);
|
||||
case label::valigns::baseline:
|
||||
top = label_height - (f.info().line_height - f.info().glyph_ascent);
|
||||
break;
|
||||
default:
|
||||
E2D_ASSERT_MSG(false,"label_system: uncknow vertical align flag");
|
||||
@@ -94,8 +94,7 @@ namespace e2d
|
||||
return;
|
||||
}
|
||||
const auto& f = l.font()->content();
|
||||
auto common = f.common();
|
||||
v2f texture_size = common.atlas_size.cast_to<f32>();
|
||||
v2f texture_size = f.info().atlas_size.cast_to<f32>();
|
||||
|
||||
if ( l.width() != 0 ) {
|
||||
f32 word_width{0};
|
||||
@@ -108,13 +107,13 @@ namespace e2d
|
||||
string_width = 0;
|
||||
last_space = -1;
|
||||
} else {
|
||||
auto data = f.find_char(ch);
|
||||
if ( data ) {
|
||||
const font::glyph_info* glyph = f.find_glyph(ch);
|
||||
if ( glyph ) {
|
||||
prev_char != 0
|
||||
? kerning = f.get_kerning(prev_char, data->id)
|
||||
? kerning = f.get_kerning(prev_char, ch)
|
||||
: kerning = 0;
|
||||
prev_char = ch;
|
||||
f32 char_width = data->advance + kerning;
|
||||
f32 char_width = glyph->advance + kerning;
|
||||
if ( ch == ' ' ) {
|
||||
if ( string_width + word_width < l.width() ) {
|
||||
if ( string_width + word_width + char_width < l.width() ) {
|
||||
@@ -166,13 +165,13 @@ namespace e2d
|
||||
prev_char = 0;
|
||||
for ( size_t i = 0, string_ind = 0; i < text.size(); i++ ) {
|
||||
if ( text[i] != '\n' ) {
|
||||
auto data = f.find_char(text[i]);
|
||||
if ( data ) {
|
||||
const font::glyph_info* glyph = f.find_glyph(text[i]);
|
||||
if ( glyph ) {
|
||||
letters_size++;
|
||||
prev_char != 0
|
||||
? kerning = f.get_kerning(prev_char, data->id)
|
||||
? kerning = f.get_kerning(prev_char, text[i])
|
||||
: kerning = 0;
|
||||
strings_width[string_ind] += data->advance + kerning;
|
||||
strings_width[string_ind] += glyph->advance + kerning;
|
||||
}
|
||||
} else {
|
||||
string_ind++;
|
||||
@@ -190,49 +189,49 @@ namespace e2d
|
||||
for ( size_t i = 0, str_ind = 0; i < text.size(); i++ ) {
|
||||
if ( text[i] == '\n' ) {
|
||||
str_ind++;
|
||||
y_pos -= common.line;
|
||||
y_pos -= f.info().line_height;
|
||||
x_pos = get_x_pos(l, strings_width[str_ind]);
|
||||
prev_char = 0;
|
||||
continue;
|
||||
}
|
||||
auto data = f.find_char(text[i]);
|
||||
if ( data ) {
|
||||
offset = data->offset.cast_to<f32>();
|
||||
const font::glyph_info* glyph = f.find_glyph(text[i]);
|
||||
if ( glyph ) {
|
||||
offset = glyph->offset.cast_to<f32>();
|
||||
prev_char != 0
|
||||
? kerning = f.get_kerning(prev_char, data->id)
|
||||
? kerning = f.get_kerning(prev_char, text[i])
|
||||
: kerning = 0;
|
||||
offset.x += kerning;
|
||||
prev_char = data->id;
|
||||
prev_char = text[i];
|
||||
size_t start_vertices = letters_counter * 4;
|
||||
vertices[start_vertices] = v3f(
|
||||
x_pos + offset.x,
|
||||
y_pos - offset.y - data->rect.size.y,
|
||||
y_pos - offset.y - glyph->tex_rect.size.y,
|
||||
0);
|
||||
vertices[start_vertices + 1] = v3f(
|
||||
x_pos + offset.x,
|
||||
y_pos - offset.y,
|
||||
0);
|
||||
vertices[start_vertices + 2] = v3f(
|
||||
x_pos + data->rect.size.x + offset.x,
|
||||
x_pos + glyph->tex_rect.size.x + offset.x,
|
||||
y_pos - offset.y,
|
||||
0);
|
||||
vertices[start_vertices + 3] = v3f(
|
||||
x_pos + data->rect.size.x + offset.x,
|
||||
y_pos - offset.y - data->rect.size.y,
|
||||
x_pos + glyph->tex_rect.size.x + offset.x,
|
||||
y_pos - offset.y - glyph->tex_rect.size.y,
|
||||
0);
|
||||
|
||||
uvs[start_vertices] = v2f(
|
||||
data->rect.position.x / texture_size.x,
|
||||
data->rect.position.y / texture_size.y);
|
||||
glyph->tex_rect.position.x / texture_size.x,
|
||||
glyph->tex_rect.position.y / texture_size.y);
|
||||
uvs[start_vertices + 1] = v2f(
|
||||
data->rect.position.x / texture_size.x,
|
||||
(data->rect.position.y + data->rect.size.y) / texture_size.y);
|
||||
glyph->tex_rect.position.x / texture_size.x,
|
||||
(glyph->tex_rect.position.y + glyph->tex_rect.size.y) / texture_size.y);
|
||||
uvs[start_vertices + 2] = v2f(
|
||||
(data->rect.position.x + data->rect.size.x) / texture_size.x,
|
||||
(data->rect.position.y + data->rect.size.y) / texture_size.y);
|
||||
(glyph->tex_rect.position.x + glyph->tex_rect.size.x) / texture_size.x,
|
||||
(glyph->tex_rect.position.y + glyph->tex_rect.size.y) / texture_size.y);
|
||||
uvs[start_vertices + 3] = v2f(
|
||||
(data->rect.position.x + data->rect.size.x) / texture_size.x,
|
||||
data->rect.position.y / texture_size.y);
|
||||
(glyph->tex_rect.position.x + glyph->tex_rect.size.x) / texture_size.x,
|
||||
glyph->tex_rect.position.y / texture_size.y);
|
||||
|
||||
colors[start_vertices] = l.tint();
|
||||
colors[start_vertices + 1] = l.tint();
|
||||
@@ -247,7 +246,7 @@ namespace e2d
|
||||
indices[start_indices + 4] = start_vertices + 3;
|
||||
indices[start_indices + 5] = start_vertices;
|
||||
|
||||
x_pos += data->advance + kerning;
|
||||
x_pos += glyph->advance + kerning;
|
||||
letters_counter++;
|
||||
}
|
||||
}
|
||||
@@ -270,8 +269,7 @@ namespace e2d
|
||||
|
||||
if ( r.materials().size() > 0 &&
|
||||
r.materials().front()->content().properties().sampler_count() == 0 ) {
|
||||
str page_file = f.find_page(0)->file;
|
||||
auto texture_p = the<library>().load_asset<texture_asset>(page_file);
|
||||
auto texture_p = the<library>().load_asset<texture_asset>(f.info().atlas_file);
|
||||
if ( !texture_p ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,228 +4,15 @@
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include <enduro2d/utils/font.hpp>
|
||||
#include <enduro2d/utils/strings.hpp>
|
||||
#include "font_impl/font_impl.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
using namespace e2d::strings;
|
||||
|
||||
class bmfont_loading_exception : public exception {
|
||||
const char* what() const noexcept override {
|
||||
return "bmfont loading exception";
|
||||
}
|
||||
};
|
||||
|
||||
inline u64 make_kerning_key(u32 first, u32 second) noexcept {
|
||||
u64 make_kerning_key(u32 first, u32 second) noexcept {
|
||||
return (static_cast<u64>(first) << 32) | static_cast<u64>(second);
|
||||
}
|
||||
|
||||
str_view read_tag(str_view buf, u32& pos) {
|
||||
str_view res;
|
||||
auto end = buf.find(' ', pos);
|
||||
if ( end != str_view::npos ) {
|
||||
res = buf.substr(pos, end - pos);
|
||||
pos = end;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool read_key(str_view buf, u32& pos, str& key) {
|
||||
auto end = buf.find('=', pos);
|
||||
if ( end != str_view::npos ) {
|
||||
auto start = buf.rfind(' ', end);
|
||||
if ( start != str_view::npos ) {
|
||||
start++;
|
||||
key = buf.substr(start, end - start);
|
||||
pos = end + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
i32 read_int(str_view buf, u32& pos) {
|
||||
i32 res{0};
|
||||
auto end = buf.find(' ', pos);
|
||||
if ( end == str_view::npos ) {
|
||||
end = buf.find("\r\n", pos);
|
||||
if ( end == str_view::npos ) {
|
||||
end = buf.find('\n', pos);
|
||||
}
|
||||
}
|
||||
|
||||
if ( end == str_view::npos ) {
|
||||
throw bmfont_loading_exception();
|
||||
} else {
|
||||
if ( !try_parse(buf.substr(pos, end - pos), res) ) {
|
||||
throw bmfont_loading_exception();
|
||||
}
|
||||
pos = end;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
str_view read_string(const str_view& buf, u32& pos) {
|
||||
str_view res;
|
||||
auto start = buf.find('"', pos);
|
||||
if ( start == str_view::npos ) {
|
||||
throw bmfont_loading_exception();
|
||||
} else {
|
||||
start++;
|
||||
auto end = buf.find('"', start);
|
||||
if ( end == str_view::npos ) {
|
||||
throw bmfont_loading_exception();
|
||||
} else {
|
||||
res = buf.substr(start, end - start);
|
||||
pos = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
font::data load_font_data(str_view content) {
|
||||
u32 pos{0};
|
||||
str_view line;
|
||||
str_view tag;
|
||||
str key;
|
||||
font::data data;
|
||||
vector<font::char_data> chars;
|
||||
vector<font::kerning_data> kernings;
|
||||
|
||||
chars.reserve(120);
|
||||
kernings.reserve(120);
|
||||
size_t start_line{0};
|
||||
size_t end_line = content.find('\n', start_line);
|
||||
while ( end_line != str_view::npos ) {
|
||||
pos = 0;
|
||||
line = content.substr(start_line, end_line - start_line + 1);
|
||||
if ( !line.empty() ) {
|
||||
tag = read_tag(line, pos);
|
||||
if ( tag == "info" ) {
|
||||
// info face="Arial-Black" size=32 bold=0 italic=0 charset=""
|
||||
// unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "face" ) {
|
||||
data.info.face = read_string(line, pos);
|
||||
} else if ( key == "size" ) {
|
||||
data.info.size = read_int(line, pos);
|
||||
}
|
||||
}
|
||||
} else if ( tag == "common" ) {
|
||||
// common lineHeight=54 base=35 scaleW=512 scaleH=512 pages=1 packed=0
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "lineHeight" ) {
|
||||
data.common.line = read_int(line, pos);
|
||||
} else if ( key == "base" ) {
|
||||
data.common.base = read_int(line, pos);
|
||||
} else if ( key == "scaleW" ) {
|
||||
data.common.atlas_size.x = read_int(line, pos);
|
||||
} else if ( key == "scaleH" ) {
|
||||
data.common.atlas_size.y = read_int(line, pos);
|
||||
} else if ( key == "pages" ) {
|
||||
data.common.pages = read_int(line, pos);
|
||||
}
|
||||
}
|
||||
} else if ( tag == "page" ) {
|
||||
// page id=0 file="arial.png"
|
||||
font::page_data page_data;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "id" ) {
|
||||
page_data.id = read_int(line, pos);
|
||||
} else if ( key == "file" ) {
|
||||
page_data.file = read_string(line, pos);
|
||||
}
|
||||
}
|
||||
data.pages.insert(std::move(page_data));
|
||||
} else if ( tag == "chars" ) {
|
||||
// chars count=95
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "count" ) {
|
||||
chars.reserve(read_int(line, pos));
|
||||
}
|
||||
}
|
||||
} else if ( tag == "char" ) {
|
||||
// char id=123 x=2 y=2 width=38 height=54
|
||||
// xoffset=0 yoffset=-3 xadvance=12 page=0 chnl=0
|
||||
font::char_data c;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "id" ) {
|
||||
c.id = read_int(line, pos);
|
||||
} else if ( key == "x" ) {
|
||||
c.rect.position.x = read_int(line, pos);
|
||||
} else if ( key == "y" ) {
|
||||
c.rect.position.y = read_int(line, pos);
|
||||
} else if ( key == "width" ) {
|
||||
c.rect.size.x = read_int(line, pos);
|
||||
} else if ( key == "height" ) {
|
||||
c.rect.size.y = read_int(line, pos);
|
||||
c.rect.position.y =
|
||||
data.common.atlas_size.y -
|
||||
c.rect.position.y -
|
||||
c.rect.size.y;
|
||||
} else if ( key == "xoffset" ) {
|
||||
c.offset.x = read_int(line, pos);
|
||||
} else if ( key == "yoffset" ) {
|
||||
c.offset.y = read_int(line, pos);
|
||||
} else if ( key == "xadvance" ) {
|
||||
c.advance = read_int(line, pos);
|
||||
} else if ( key == "page" ) {
|
||||
c.page = read_int(line, pos);
|
||||
} else if ( key == "chnl" ) {
|
||||
c.chnl = read_int(line, pos);
|
||||
}
|
||||
}
|
||||
chars.push_back(std::move(c));
|
||||
} else if ( tag == "kernings" ) {
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "count" ) {
|
||||
kernings.reserve(read_int(line, pos));
|
||||
}
|
||||
}
|
||||
} else if ( tag == "kerning" ) {
|
||||
font::kerning_data k;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "first" ) {
|
||||
k.chars.first = read_int(line, pos);
|
||||
} else if ( key == "second" ) {
|
||||
k.chars.second = read_int(line, pos);
|
||||
} else if ( key == "amount" ) {
|
||||
k.amount = read_int(line, pos);
|
||||
}
|
||||
}
|
||||
kernings.push_back(std::move(k));
|
||||
}
|
||||
}
|
||||
start_line = content.find_first_not_of(' ', end_line + 1);
|
||||
end_line = content.find('\n', start_line);
|
||||
}
|
||||
|
||||
if (chars.empty()) {
|
||||
throw bmfont_loading_exception();
|
||||
}
|
||||
|
||||
data.chars.reserve(chars.size());
|
||||
for ( size_t i = 0; i < chars.size(); i++ ) {
|
||||
data.chars.insert(std::make_pair(chars[i].id, chars[i]));
|
||||
}
|
||||
|
||||
data.kernings.reserve(kernings.size());
|
||||
for ( size_t i = 0; i < kernings.size(); i++ ) {
|
||||
auto& k = kernings[i];
|
||||
data.kernings.insert(
|
||||
std::make_pair(
|
||||
make_kerning_key(k.chars.first, k.chars.second),
|
||||
k.amount));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
@@ -246,12 +33,12 @@ namespace e2d
|
||||
return assign(other);
|
||||
}
|
||||
|
||||
font::font(data&& data) noexcept {
|
||||
assign(std::move(data));
|
||||
font::font(content&& content) noexcept {
|
||||
assign(std::move(content));
|
||||
}
|
||||
|
||||
font::font(const data& data) {
|
||||
assign(data);
|
||||
font::font(const content& content) {
|
||||
assign(content);
|
||||
}
|
||||
|
||||
font& font::assign(font&& other) noexcept {
|
||||
@@ -264,79 +51,62 @@ namespace e2d
|
||||
|
||||
font& font::assign(const font& other) {
|
||||
if ( this != &other ) {
|
||||
data_ = other.data_;
|
||||
content_ = other.content_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
font& font::assign(data&& data) noexcept {
|
||||
data_ = std::move(data);
|
||||
font& font::assign(content&& content) noexcept {
|
||||
content_ = std::move(content);
|
||||
return *this;
|
||||
}
|
||||
|
||||
font& font::assign(const data& data) {
|
||||
data_ = data;
|
||||
font& font::assign(const content& content) {
|
||||
content_ = content;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void font::swap(font& other) noexcept {
|
||||
using std::swap;
|
||||
swap(data_.info, other.data_.info);
|
||||
swap(data_.common, other.data_.common);
|
||||
swap(data_.pages, other.data_.pages);
|
||||
swap(data_.chars, other.data_.chars);
|
||||
swap(data_.kernings, other.data_.kernings);
|
||||
swap(content_.info, other.content_.info);
|
||||
swap(content_.kernings, other.content_.kernings);
|
||||
swap(content_.glyphs, other.content_.glyphs);
|
||||
}
|
||||
|
||||
void font::clear() noexcept {
|
||||
data_ = data();
|
||||
content_ = content();
|
||||
}
|
||||
|
||||
bool font::empty() const noexcept {
|
||||
return data_.pages.empty();
|
||||
return !content_.info.font_size;
|
||||
}
|
||||
|
||||
const font::info_data& font::info() const noexcept {
|
||||
return data_.info;
|
||||
}
|
||||
|
||||
const font::common_data& font::common() const noexcept {
|
||||
return data_.common;
|
||||
}
|
||||
|
||||
const flat_set<font::page_data>& font::pages() const noexcept {
|
||||
return data_.pages;
|
||||
}
|
||||
|
||||
const flat_map<u32, font::char_data>& font::chars() const noexcept {
|
||||
return data_.chars;
|
||||
const font::font_info& font::info() const noexcept {
|
||||
return content_.info;
|
||||
}
|
||||
|
||||
const flat_map<u64, i32>& font::kernings() const noexcept {
|
||||
return data_.kernings;
|
||||
return content_.kernings;
|
||||
}
|
||||
|
||||
const font::page_data* font::find_page(u32 id) const noexcept {
|
||||
const auto iter = data_.pages.find(id);
|
||||
return iter != data_.pages.end()
|
||||
? &*iter
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
const font::char_data* font::find_char(u32 id) const noexcept {
|
||||
const auto iter = data_.chars.find(id);
|
||||
return iter != data_.chars.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
const flat_map<u32, font::glyph_info>& font::glyphs() const noexcept {
|
||||
return content_.glyphs;
|
||||
}
|
||||
|
||||
i32 font::get_kerning(u32 first, u32 second) const noexcept {
|
||||
u64 key = make_kerning_key(first, second);
|
||||
const auto iter = data_.kernings.find(key);
|
||||
return iter != data_.kernings.end()
|
||||
const u64 key = make_kerning_key(first, second);
|
||||
const auto iter = content_.kernings.find(key);
|
||||
return iter != content_.kernings.end()
|
||||
? iter->second
|
||||
: 0;
|
||||
}
|
||||
|
||||
const font::glyph_info* font::find_glyph(u32 code_point) const noexcept {
|
||||
const auto iter = content_.glyphs.find(code_point);
|
||||
return iter != content_.glyphs.end()
|
||||
? &iter->second
|
||||
: nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d
|
||||
@@ -347,98 +117,52 @@ namespace e2d
|
||||
|
||||
bool operator==(const font& l, const font& r) noexcept {
|
||||
return l.info() == r.info()
|
||||
&& l.common() == r.common()
|
||||
&& l.pages() == r.pages()
|
||||
&& l.chars() == r.chars()
|
||||
&& l.kernings() == r.kernings();
|
||||
&& l.kernings() == r.kernings()
|
||||
&& l.glyphs() == r.glyphs();
|
||||
}
|
||||
|
||||
bool operator!=(const font& l, const font& r) noexcept {
|
||||
return !(l == r);
|
||||
}
|
||||
|
||||
bool operator<(u32 l, const font::page_data& r) noexcept {
|
||||
return l < r.id;
|
||||
bool operator==(const font::font_info& l, const font::font_info& r) noexcept {
|
||||
return l.atlas_file == r.atlas_file
|
||||
&& l.atlas_size == r.atlas_size
|
||||
&& l.font_size == r.font_size
|
||||
&& l.line_height == r.line_height
|
||||
&& l.glyph_ascent == r.glyph_ascent;
|
||||
}
|
||||
|
||||
bool operator<(const font::page_data& l, u32 r) noexcept {
|
||||
return l.id < r;
|
||||
bool operator==(const font::glyph_info& l, const font::glyph_info& r) noexcept {
|
||||
return l.offset == r.offset
|
||||
&& l.tex_rect == r.tex_rect
|
||||
&& l.advance == r.advance;
|
||||
}
|
||||
|
||||
bool operator<(const font::page_data& l, const font::page_data& r) noexcept {
|
||||
return l.id < r.id;
|
||||
}
|
||||
|
||||
bool operator<(u32 l, const font::char_data& r) noexcept {
|
||||
return l < r.id;
|
||||
}
|
||||
|
||||
bool operator<(const font::char_data& l, u32 r) noexcept {
|
||||
return l.id < r;
|
||||
}
|
||||
|
||||
bool operator<(const font::char_data& l, const font::char_data& r) noexcept {
|
||||
return l.id < r.id;
|
||||
}
|
||||
|
||||
bool operator<(const std::pair<u32,u32>& l, const font::kerning_data& r) noexcept {
|
||||
return l < r.chars;
|
||||
}
|
||||
|
||||
bool operator<(const font::kerning_data& l, const std::pair<u32,u32>& r) noexcept {
|
||||
return l.chars < r;
|
||||
}
|
||||
|
||||
bool operator<(const font::kerning_data& l, const font::kerning_data& r) noexcept {
|
||||
return l.chars < r.chars;
|
||||
}
|
||||
|
||||
bool operator==(const font::info_data& l, const font::info_data& r) noexcept {
|
||||
return l.face == r.face
|
||||
&& l.size == r.size;
|
||||
}
|
||||
|
||||
bool operator==(const font::common_data& l, const font::common_data& r) noexcept {
|
||||
return l.line == r.line
|
||||
&& l.base == r.base
|
||||
&& l.pages == r.pages
|
||||
&& l.atlas_size == r.atlas_size;
|
||||
}
|
||||
|
||||
bool operator==(const font::page_data& l, const font::page_data& r) noexcept {
|
||||
return l.id == r.id
|
||||
&& l.file == r.file;
|
||||
}
|
||||
|
||||
bool operator==(const font::char_data& l, const font::char_data& r) noexcept {
|
||||
return l.id == r.id
|
||||
&& l.rect == r.rect
|
||||
&& l.offset == r.offset
|
||||
&& l.advance == r.advance
|
||||
&& l.page == r.page
|
||||
&& l.chnl == r.chnl;
|
||||
}
|
||||
|
||||
bool operator==(const font::kerning_data& l, const font::kerning_data& r) noexcept {
|
||||
return l.chars == r.chars
|
||||
&& l.amount == r.amount;
|
||||
bool operator==(const font::content& l, const font::content& r) noexcept {
|
||||
return l.info == r.info
|
||||
&& l.kernings == r.kernings
|
||||
&& l.glyphs == r.glyphs;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::fonts
|
||||
{
|
||||
bool try_load_font(font& dst, const buffer& src) noexcept {
|
||||
bool try_load_font(
|
||||
font& dst,
|
||||
buffer_view src) noexcept
|
||||
{
|
||||
try {
|
||||
dst = load_font_data(str_view{
|
||||
reinterpret_cast<const char*>(src.data()),
|
||||
src.size()});
|
||||
return true;
|
||||
return impl::load_font_bmfont(dst, src);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool try_load_font(font& dst, const input_stream_uptr& src) noexcept {
|
||||
bool try_load_font(
|
||||
font& dst,
|
||||
const input_stream_uptr& src) noexcept
|
||||
{
|
||||
buffer file_data;
|
||||
return streams::try_read_tail(file_data, src)
|
||||
&& try_load_font(dst, file_data);
|
||||
|
||||
17
sources/enduro2d/utils/font_impl/font_impl.hpp
Normal file
17
sources/enduro2d/utils/font_impl/font_impl.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <enduro2d/utils/font.hpp>
|
||||
#include <enduro2d/utils/buffer.hpp>
|
||||
#include <enduro2d/utils/strings.hpp>
|
||||
#include <enduro2d/utils/buffer_view.hpp>
|
||||
|
||||
namespace e2d::fonts::impl
|
||||
{
|
||||
bool load_font_bmfont(font& dst, buffer_view src);
|
||||
}
|
||||
359
sources/enduro2d/utils/font_impl/font_reader_bmfont.cpp
Normal file
359
sources/enduro2d/utils/font_impl/font_reader_bmfont.cpp
Normal file
@@ -0,0 +1,359 @@
|
||||
/*******************************************************************************
|
||||
* This file is part of the "Enduro2D"
|
||||
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
|
||||
******************************************************************************/
|
||||
|
||||
#include "font_impl.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
bool read_line(str_view content, std::size_t& pos, str_view& line) {
|
||||
if ( pos > content.size() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto end_of_line = content.find('\n', pos);
|
||||
if ( end_of_line == str_view::npos ) {
|
||||
end_of_line = content.size();
|
||||
}
|
||||
|
||||
line = content.substr(pos, end_of_line - pos);
|
||||
if ( !line.empty() && line.back() == '\r' ) {
|
||||
line.remove_suffix(1u);
|
||||
}
|
||||
|
||||
pos = end_of_line + 1u;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_tag(str_view line, std::size_t& pos, str_view& tag) {
|
||||
const auto start = line.find_first_not_of(' ', pos);
|
||||
if ( start == str_view::npos ) {
|
||||
return false;
|
||||
}
|
||||
const auto end = line.find(' ', start);
|
||||
if ( end == str_view::npos || end == line.size() ) {
|
||||
return false;
|
||||
}
|
||||
tag = line.substr(start, end - start);
|
||||
pos = end + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_key(str_view line, std::size_t& pos, str_view& key) {
|
||||
const auto eq = line.find('=', pos);
|
||||
if ( eq == str_view::npos || eq == 0u || eq == line.size() ) {
|
||||
return false;
|
||||
}
|
||||
const auto last = line.find_last_not_of(' ', eq - 1u);
|
||||
if ( last == str_view::npos ) {
|
||||
return false;
|
||||
}
|
||||
const auto prestart = line.rfind(' ', last);
|
||||
const auto start = prestart == str_view::npos
|
||||
? 0u
|
||||
: prestart + 1u;
|
||||
key = line.substr(start, last - prestart);
|
||||
pos = eq + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
bool read_value(str_view line, std::size_t& pos, T& value) {
|
||||
const auto start = line.find_first_not_of(' ', pos);
|
||||
if ( start == str_view::npos ) {
|
||||
return false;
|
||||
}
|
||||
auto end = line.find(' ', start);
|
||||
if ( end == str_view::npos ) {
|
||||
end = line.size();
|
||||
}
|
||||
if ( !strings::try_parse(line.substr(start, end - start), value) ) {
|
||||
return false;
|
||||
}
|
||||
pos = end + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_value(str_view line, std::size_t& pos, str& value) {
|
||||
const auto start = line.find("\"", pos);
|
||||
if ( start == str_view::npos || start == line.size() ) {
|
||||
return false;
|
||||
}
|
||||
const auto end = line.find("\"", start + 1u);
|
||||
if ( end == str_view::npos ) {
|
||||
return false;
|
||||
}
|
||||
value = line.substr(start + 1, end - start - 1u);
|
||||
pos = end + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// info face="Arial-Black" size=32 bold=0 italic=0 charset=""
|
||||
// unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=2,2
|
||||
bool parse_info_line(str_view line, font::content& font_content) {
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "size" ) {
|
||||
if ( !read_value(line, pos, font_content.info.font_size) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// common lineHeight=54 base=35 scaleW=512 scaleH=512 pages=1 packed=0
|
||||
bool parse_common_line(str_view line, font::content& font_content) {
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "lineHeight" ) {
|
||||
if ( !read_value(line, pos, font_content.info.line_height) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "base" ) {
|
||||
if ( !read_value(line, pos, font_content.info.glyph_ascent) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "scaleW" ) {
|
||||
if ( !read_value(line, pos, font_content.info.atlas_size.x) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "scaleH" ) {
|
||||
if ( !read_value(line, pos, font_content.info.atlas_size.y) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "pages" ) {
|
||||
u32 pages = 0u;
|
||||
if ( !read_value(line, pos, pages) || pages > 1u ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// page id=0 file="arial.png"
|
||||
bool parse_page_line(str_view line, font::content& font_content) {
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "id" ) {
|
||||
u32 id = 0u;
|
||||
if ( !read_value(line, pos, id) || id > 0 ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "file" ) {
|
||||
if ( !read_value(line, pos, font_content.info.atlas_file) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// chars count=95
|
||||
bool parse_chars_line(str_view line, font::content& font_content) {
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "count" ) {
|
||||
std::size_t count = 0u;
|
||||
if ( !read_value(line, pos, count) ) {
|
||||
return false;
|
||||
}
|
||||
font_content.glyphs.reserve(count);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// char id=123 x=2 y=2 width=38 height=54
|
||||
// xoffset=0 yoffset=-3 xadvance=12 page=0 chnl=0
|
||||
bool parse_char_line(str_view line, font::content& font_content) {
|
||||
u32 code_point = 0;
|
||||
font::glyph_info glyph;
|
||||
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "id" ) {
|
||||
if ( !read_value(line, pos, code_point) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "x" ) {
|
||||
if ( !read_value(line, pos, glyph.tex_rect.position.x) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "y" ) {
|
||||
if ( !read_value(line, pos, glyph.tex_rect.position.y) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "width" ) {
|
||||
if ( !read_value(line, pos, glyph.tex_rect.size.x) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "height" ) {
|
||||
if ( !read_value(line, pos, glyph.tex_rect.size.y) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "xoffset" ) {
|
||||
if ( !read_value(line, pos, glyph.offset.x) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "yoffset" ) {
|
||||
if ( !read_value(line, pos, glyph.offset.y) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "xadvance" ) {
|
||||
if ( !read_value(line, pos, glyph.advance) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "page" ) {
|
||||
u32 page = 0;
|
||||
if ( !read_value(line, pos, page) || page > 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font_content.glyphs.insert_or_assign(
|
||||
code_point,
|
||||
std::move(glyph));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// kernings count=343
|
||||
bool parse_kernings_line(str_view line, font::content& font_content) {
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "count" ) {
|
||||
std::size_t count = 0u;
|
||||
if ( !read_value(line, pos, count) ) {
|
||||
return false;
|
||||
}
|
||||
font_content.kernings.reserve(count);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// kerning first=1043 second=1071 amount=-1
|
||||
bool parse_kerning_line(str_view line, font::content& font_content) {
|
||||
u32 first = 0;
|
||||
u32 second = 0;
|
||||
i32 amount = 0;
|
||||
|
||||
str_view key;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_key(line, pos, key) ) {
|
||||
if ( key == "first" ) {
|
||||
if ( !read_value(line, pos, first) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "second" ) {
|
||||
if ( !read_value(line, pos, second) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( key == "amount" ) {
|
||||
if ( !read_value(line, pos, amount) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font_content.kernings.insert_or_assign(
|
||||
(static_cast<u64>(first) << 32) | static_cast<u64>(second),
|
||||
amount);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::fonts::impl
|
||||
{
|
||||
bool load_font_bmfont(font& dst, buffer_view src) {
|
||||
const auto text_src = str_view{
|
||||
reinterpret_cast<const char*>(src.data()),
|
||||
src.size()};
|
||||
|
||||
font::content font_content;
|
||||
|
||||
str_view line;
|
||||
std::size_t pos = 0u;
|
||||
while ( read_line(text_src, pos, line) ) {
|
||||
str_view tag;
|
||||
std::size_t tag_pos = 0u;
|
||||
if ( !read_tag(line, tag_pos, tag) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
line.remove_prefix(tag_pos);
|
||||
|
||||
if ( tag == "info" ) {
|
||||
if ( !parse_info_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "common" ) {
|
||||
if ( !parse_common_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "page" ) {
|
||||
if ( !parse_page_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "chars" ) {
|
||||
if ( !parse_chars_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "char" ) {
|
||||
if ( !parse_char_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "kernings" ) {
|
||||
if ( !parse_kernings_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( tag == "kerning" ) {
|
||||
if ( !parse_kerning_line(line, font_content) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( auto& glyph : font_content.glyphs ) {
|
||||
glyph.second.tex_rect.position.y =
|
||||
font_content.info.atlas_size.y -
|
||||
glyph.second.tex_rect.position.y -
|
||||
glyph.second.tex_rect.size.y;
|
||||
}
|
||||
|
||||
bool info_valid = !font_content.info.atlas_file.empty()
|
||||
&& font_content.info.atlas_size.x > 0u
|
||||
&& font_content.info.atlas_size.y > 0u
|
||||
&& font_content.info.font_size > 0u
|
||||
&& font_content.info.line_height > 0u
|
||||
&& font_content.info.font_size > 0u
|
||||
&& font_content.info.glyph_ascent > 0u;
|
||||
|
||||
bool glyphs_valid = true;
|
||||
for ( const auto& glyph : font_content.glyphs ) {
|
||||
const v2u& mst = glyph.second.tex_rect.position + glyph.second.tex_rect.size;
|
||||
glyphs_valid = glyphs_valid && math::inside(b2u(font_content.info.atlas_size), mst);
|
||||
}
|
||||
|
||||
if ( !info_valid || !glyphs_valid ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst = font(font_content);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,15 @@ using namespace e2d;
|
||||
namespace
|
||||
{
|
||||
const char* const mini_fnt = R"fnt(
|
||||
info face="Arial" size=50 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0
|
||||
common lineHeight=58 base=49 scaleW=512 scaleH=512 pages=1 packed=0
|
||||
info face ="Arial" size= 50 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0
|
||||
common lineHeight =58 base= 49 scaleW = 512 scaleH=512 pages=1 packed=0
|
||||
page id=0 file="arial.png"
|
||||
|
||||
chars count=3
|
||||
char id=32 x=342 y=38 width=0 height=0 xoffset=0 yoffset=46 xadvance=14 page=0 chnl=0
|
||||
char id=33 x=448 y=386 width=10 height=40 xoffset=5 yoffset=10 xadvance=14 page=0 chnl=0
|
||||
char id=34 x=394 y=306 width=18 height=18 xoffset=3 yoffset=8 xadvance=18 page=0 chnl=0
|
||||
|
||||
kernings count=2
|
||||
kerning first=1059 second=1081 amount=-1
|
||||
kerning first=1043 second=1071 amount=-1
|
||||
@@ -39,32 +41,22 @@ TEST_CASE("font") {
|
||||
REQUIRE(fonts::try_load_font(f2, make_memory_stream(buffer(mini_fnt, std::strlen(mini_fnt)))));
|
||||
REQUIRE(f == f2);
|
||||
|
||||
REQUIRE(f.info().face == "Arial");
|
||||
REQUIRE(f.info().size == 50);
|
||||
REQUIRE(f.info().atlas_file == "arial.png");
|
||||
REQUIRE(f.info().atlas_size == v2u(512,512));
|
||||
REQUIRE(f.info().font_size == 50);
|
||||
REQUIRE(f.info().line_height == 58);
|
||||
REQUIRE(f.info().glyph_ascent == 49);
|
||||
|
||||
REQUIRE(f.common().line == 58);
|
||||
REQUIRE(f.common().base == 49);
|
||||
REQUIRE(f.common().pages == 1);
|
||||
REQUIRE(f.common().atlas_size == v2u(512,512));
|
||||
|
||||
REQUIRE(f.pages().size() == 1);
|
||||
REQUIRE(f.find_page(0));
|
||||
REQUIRE(f.find_page(0)->id == 0);
|
||||
REQUIRE(f.find_page(0)->file == "arial.png");
|
||||
|
||||
REQUIRE(f.chars().size() == 3);
|
||||
REQUIRE_FALSE(f.find_char(100500));
|
||||
REQUIRE(f.find_char(33));
|
||||
REQUIRE(f.glyphs().size() == 3);
|
||||
REQUIRE_FALSE(f.find_glyph(100500));
|
||||
REQUIRE(f.find_glyph(33));
|
||||
{
|
||||
// char id=33 x=448 y=386 width=10 height=40 xoffset=5 yoffset=10 xadvance=14 page=0 chnl=0
|
||||
font::char_data c;
|
||||
c.id = 33;
|
||||
c.rect = b2hi(448, 86, 10, 40);
|
||||
c.offset = v2hi(5, 10);
|
||||
font::glyph_info c;
|
||||
c.offset = v2i(5, 10);
|
||||
c.tex_rect = b2u(448, 86, 10, 40);
|
||||
c.advance = 14;
|
||||
c.page = 0;
|
||||
c.chnl = 0;
|
||||
REQUIRE(*f.find_char(33) == c);
|
||||
REQUIRE(*f.find_glyph(33) == c);
|
||||
}
|
||||
|
||||
REQUIRE(f.kernings().size() == 2);
|
||||
|
||||
Reference in New Issue
Block a user