Merge pull request #96 from enduro2d/feature/label

close #55
This commit is contained in:
2019-08-22 09:44:18 +07:00
committed by GitHub
62 changed files with 3498 additions and 50 deletions

View File

@@ -11,6 +11,7 @@
#include "assets/atlas_asset.hpp"
#include "assets/binary_asset.hpp"
#include "assets/flipbook_asset.hpp"
#include "assets/font_asset.hpp"
#include "assets/image_asset.hpp"
#include "assets/json_asset.hpp"
#include "assets/material_asset.hpp"
@@ -29,12 +30,14 @@
#include "components/camera.hpp"
#include "components/flipbook_player.hpp"
#include "components/flipbook_source.hpp"
#include "components/label.hpp"
#include "components/model_renderer.hpp"
#include "components/renderer.hpp"
#include "components/scene.hpp"
#include "components/sprite_renderer.hpp"
#include "systems/flipbook_system.hpp"
#include "systems/label_system.hpp"
#include "systems/render_system.hpp"
#include "address.hpp"

View File

@@ -23,6 +23,7 @@ namespace e2d
class atlas_asset;
class binary_asset;
class flipbook_asset;
class font_asset;
class image_asset;
class json_asset;
class material_asset;
@@ -41,12 +42,14 @@ namespace e2d
class camera;
class flipbook_player;
class flipbook_source;
class label;
class model_renderer;
class renderer;
class scene;
class sprite_renderer;
class flipbook_system;
class label_system;
class render_system;
template < typename Asset, typename Content >

View File

@@ -0,0 +1,20 @@
/*******************************************************************************
* 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 "../_high.hpp"
#include "../library.hpp"
namespace e2d
{
class font_asset final : public content_asset<font_asset, font> {
public:
static const char* type_name() noexcept { return "font_asset"; }
static load_async_result load_async(const library& library, str_view address);
};
}

View File

@@ -0,0 +1,281 @@
/*******************************************************************************
* 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 "../_high.hpp"
#include "../factory.hpp"
#include "../assets/font_asset.hpp"
namespace e2d
{
class label final {
public:
class dirty final {
};
public:
enum class haligns {
left,
center,
right
};
enum class valigns {
top,
center,
bottom,
baseline
};
public:
label() = default;
label(const font_asset::ptr& font);
label(label&& other) noexcept;
label& operator=(label&& other) noexcept;
label(const label& other);
label& operator=(const label& other);
label& text(str value) noexcept;
[[nodiscard]] const str& text() const noexcept;
label& font(const font_asset::ptr& value) noexcept;
[[nodiscard]] const font_asset::ptr& font() const noexcept;
label& tint(const color32& value) noexcept;
[[nodiscard]] const color32& tint() const noexcept;
label& haligh(haligns value) noexcept;
[[nodiscard]] haligns halign() const noexcept;
label& valigh(valigns value) noexcept;
[[nodiscard]] valigns valign() const noexcept;
label& leading(f32 value) noexcept;
[[nodiscard]] f32 leading() const noexcept;
label& tracking(f32 value) noexcept;
[[nodiscard]] f32 tracking() const noexcept;
label& text_width(f32 value) noexcept;
[[nodiscard]] f32 text_width() const noexcept;
label& glyph_dilate(f32 value) noexcept;
[[nodiscard]] f32 glyph_dilate() const noexcept;
label& outline_width(f32 value) noexcept;
[[nodiscard]] f32 outline_width() const noexcept;
label& outline_color(const color32& value) noexcept;
[[nodiscard]] const color32& outline_color() const noexcept;
private:
str text_;
font_asset::ptr font_;
color32 tint_ = color32::white();
haligns halign_ = haligns::center;
valigns valign_ = valigns::baseline;
f32 leading_ = 1.f;
f32 tracking_ = 0.f;
f32 text_width_ = 0.f;
f32 glyph_dilate_ = 0.f;
f32 outline_width_ = 0.f;
color32 outline_color_ = color32::white();
};
template <>
class factory_loader<label> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
label& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
template <>
class factory_loader<label::dirty> final : factory_loader<> {
public:
static const char* schema_source;
bool operator()(
label::dirty& component,
const fill_context& ctx) const;
bool operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const;
};
}
namespace e2d
{
inline label::label(const font_asset::ptr& value)
: font_(value) {}
inline label::label(label&& other) noexcept
: text_(std::move(other.text_))
, font_(std::move(other.font_))
, tint_(other.tint_)
, halign_(other.halign_)
, valign_(other.valign_)
, leading_(other.leading_)
, tracking_(other.tracking_)
, text_width_(other.text_width_)
, glyph_dilate_(other.glyph_dilate_)
, outline_width_(other.outline_width_)
, outline_color_(other.outline_color_) {}
inline label& label::operator=(label&& other) noexcept {
if ( this != &other ) {
text_ = std::move(other.text_);
font_ = std::move(other.font_);
tint_ = other.tint_;
halign_ = other.halign_;
valign_ = other.valign_;
leading_ = other.leading_;
tracking_ = other.tracking_;
text_width_ = other.text_width_;
glyph_dilate_ = other.glyph_dilate_;
outline_width_ = other.outline_width_;
outline_color_ = other.outline_color_;
}
return *this;
}
inline label::label(const label& other)
: text_(other.text_)
, font_(other.font_)
, tint_(other.tint_)
, halign_(other.halign_)
, valign_(other.valign_)
, leading_(other.leading_)
, tracking_(other.tracking_)
, text_width_(other.text_width_)
, glyph_dilate_(other.glyph_dilate_)
, outline_width_(other.outline_width_)
, outline_color_(other.outline_color_) {}
inline label& label::operator=(const label& other) {
if ( this != &other ) {
text_ = other.text_;
font_ = other.font_;
tint_ = other.tint_;
halign_ = other.halign_;
valign_ = other.valign_;
leading_ = other.leading_;
tracking_ = other.tracking_;
text_width_ = other.text_width_;
glyph_dilate_ = other.glyph_dilate_;
outline_width_ = other.outline_width_;
outline_color_ = other.outline_color_;
}
return *this;
}
inline label& label::text(str value) noexcept {
text_ = std::move(value);
return *this;
}
inline const str& label::text() const noexcept {
return text_;
}
inline label& label::font(const font_asset::ptr& value) noexcept {
font_ = value;
return *this;
}
inline const font_asset::ptr& label::font() const noexcept {
return font_;
}
inline label& label::tint(const color32& value) noexcept {
tint_ = value;
return *this;
}
inline const color32& label::tint() const noexcept {
return tint_;
}
inline label& label::haligh(haligns value) noexcept {
halign_ = value;
return *this;
}
inline label::haligns label::halign() const noexcept {
return halign_;
}
inline label& label::valigh(valigns value) noexcept {
valign_ = value;
return *this;
}
inline label::valigns label::valign() const noexcept {
return valign_;
}
inline label& label::leading(f32 value) noexcept {
leading_ = value;
return *this;
}
inline f32 label::leading() const noexcept {
return leading_;
}
inline label& label::tracking(f32 value) noexcept {
tracking_ = value;
return *this;
}
inline f32 label::tracking() const noexcept {
return tracking_;
}
inline label& label::text_width(f32 value) noexcept {
text_width_ = value;
return *this;
}
inline f32 label::text_width() const noexcept {
return text_width_;
}
inline label& label::glyph_dilate(f32 value) noexcept {
glyph_dilate_ = value;
return *this;
}
inline f32 label::glyph_dilate() const noexcept {
return glyph_dilate_;
}
inline label& label::outline_width(f32 value) noexcept {
outline_width_ = value;
return *this;
}
inline f32 label::outline_width() const noexcept {
return outline_width_;
}
inline label& label::outline_color(const color32& value) noexcept {
outline_color_ = value;
return *this;
}
inline const color32& label::outline_color() const noexcept {
return outline_color_;
}
}

View File

@@ -0,0 +1,22 @@
/*******************************************************************************
* 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 "../_high.hpp"
namespace e2d
{
class label_system final : public ecs::system {
public:
label_system();
~label_system() noexcept final;
void process(ecs::registry& owner) override;
private:
class internal_state;
std::unique_ptr<internal_state> state_;
};
}

View File

@@ -14,6 +14,7 @@
#include "color32.hpp"
#include "filesystem.hpp"
#include "filesystem.inl"
#include "font.hpp"
#include "image.hpp"
#include "intrusive_list.hpp"
#include "intrusive_ptr.hpp"

View File

@@ -17,6 +17,7 @@ namespace e2d
class color32;
class read_file;
class write_file;
class font;
class image;
class mesh;
class shape;
@@ -66,7 +67,7 @@ namespace e2d
using milliseconds = unit<T, milliseconds_tag>;
template < typename T >
using microseconds = unit<T, microseconds_tag>;
using secf = seconds<f32>;
}

View File

@@ -55,6 +55,9 @@ namespace e2d
namespace e2d
{
vec3<f32> make_vec3(const color& c) noexcept;
vec4<f32> make_vec4(const color& c) noexcept;
bool operator<(const color& l, const color& r) noexcept;
bool operator==(const color& l, const color& r) noexcept;
bool operator!=(const color& l, const color& r) noexcept;

View File

@@ -55,6 +55,9 @@ namespace e2d
namespace e2d
{
vec3<u8> make_vec3(const color32& c) noexcept;
vec4<u8> make_vec4(const color32& c) noexcept;
bool operator<(const color32& l, const color32& r) noexcept;
bool operator==(const color32& l, const color32& r) noexcept;
bool operator!=(const color32& l, const color32& r) noexcept;

View File

@@ -0,0 +1,88 @@
/*******************************************************************************
* 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 "_utils.hpp"
#include "buffer.hpp"
#include "buffer_view.hpp"
#include "streams.hpp"
namespace e2d
{
class font final {
public:
struct font_info {
str atlas_file;
v2u atlas_size;
u32 font_size{0};
u32 line_height{0};
u32 glyph_ascent{0};
};
struct glyph_info {
v2i offset;
b2u tex_rect;
i32 advance{0};
};
struct content {
font_info info;
flat_map<u64, i32> kernings;
flat_map<u32, glyph_info> glyphs;
};
public:
font() = default;
font(font&& other) noexcept;
font& operator=(font&& other) noexcept;
font(const font& other);
font& operator=(const font& other);
font(content&& content) noexcept;
font(const content& content);
font& assign(font&& other) noexcept;
font& assign(const font& other);
font& assign(content&& content) noexcept;
font& assign(const content& content);
void swap(font& other) noexcept;
void clear() noexcept;
bool empty() 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;
i32 get_kerning(u32 first, u32 second) const noexcept;
const glyph_info* find_glyph(u32 code_point) const noexcept;
private:
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==(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,
buffer_view src) noexcept;
bool try_load_font(
font& dst,
const input_stream_uptr& src) noexcept;
}

View File

@@ -36,3 +36,4 @@ add_e2d_sample(02)
add_e2d_sample(03)
add_e2d_sample(04)
add_e2d_sample(05)

View File

@@ -0,0 +1,713 @@
info face="Arial" size=50 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=1,1 outline=3
common lineHeight=50 base=40 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=1 greenChnl=3 blueChnl=3
page id=0 file="arial_bm.png"
chars count=161
char id=32 x=0 y=395 width=11 height=9 xoffset=-5 yoffset=45 xadvance=12 page=0 chnl=15
char id=33 x=350 y=255 width=14 height=40 xoffset=0 yoffset=4 xadvance=14 page=0 chnl=15
char id=34 x=343 y=361 width=21 height=19 xoffset=-3 yoffset=4 xadvance=16 page=0 chnl=15
char id=35 x=68 y=216 width=33 height=40 xoffset=-5 yoffset=4 xadvance=24 page=0 chnl=15
char id=36 x=446 y=0 width=30 height=46 xoffset=-3 yoffset=2 xadvance=24 page=0 chnl=15
char id=37 x=347 y=49 width=43 height=40 xoffset=-2 yoffset=4 xadvance=39 page=0 chnl=15
char id=38 x=229 y=132 width=36 height=40 xoffset=-3 yoffset=4 xadvance=29 page=0 chnl=15
char id=39 x=494 y=323 width=14 height=19 xoffset=-3 yoffset=4 xadvance=8 page=0 chnl=15
char id=40 x=225 y=0 width=20 height=49 xoffset=-2 yoffset=4 xadvance=15 page=0 chnl=15
char id=41 x=246 y=0 width=20 height=49 xoffset=-2 yoffset=4 xadvance=15 page=0 chnl=15
char id=42 x=319 y=361 width=23 height=21 xoffset=-3 yoffset=4 xadvance=17 page=0 chnl=15
char id=43 x=167 y=363 width=30 height=30 xoffset=-2 yoffset=10 xadvance=26 page=0 chnl=15
char id=44 x=365 y=361 width=14 height=19 xoffset=-1 yoffset=32 xadvance=12 page=0 chnl=15
char id=45 x=466 y=358 width=21 height=12 xoffset=-3 yoffset=23 xadvance=15 page=0 chnl=15
char id=46 x=488 y=358 width=14 height=12 xoffset=-1 yoffset=32 xadvance=12 page=0 chnl=15
char id=47 x=267 y=255 width=22 height=40 xoffset=-5 yoffset=4 xadvance=12 page=0 chnl=15
char id=48 x=326 y=214 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=49 x=313 y=255 width=21 height=40 xoffset=0 yoffset=4 xadvance=24 page=0 chnl=15
char id=50 x=93 y=257 width=29 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=51 x=295 y=214 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=52 x=168 y=215 width=31 height=40 xoffset=-4 yoffset=4 xadvance=24 page=0 chnl=15
char id=53 x=357 y=214 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=54 x=419 y=212 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=55 x=450 y=212 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=56 x=481 y=211 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=57 x=0 y=257 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=58 x=497 y=252 width=14 height=31 xoffset=-1 yoffset=13 xadvance=12 page=0 chnl=15
char id=59 x=447 y=253 width=14 height=38 xoffset=-1 yoffset=13 xadvance=12 page=0 chnl=15
char id=60 x=198 y=362 width=30 height=29 xoffset=-2 yoffset=10 xadvance=26 page=0 chnl=15
char id=61 x=288 y=361 width=30 height=21 xoffset=-2 yoffset=14 xadvance=26 page=0 chnl=15
char id=62 x=229 y=362 width=30 height=29 xoffset=-2 yoffset=10 xadvance=26 page=0 chnl=15
char id=63 x=388 y=213 width=30 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=64 x=0 y=0 width=50 height=49 xoffset=-2 yoffset=4 xadvance=45 page=0 chnl=15
char id=65 x=286 y=91 width=39 height=40 xoffset=-5 yoffset=4 xadvance=29 page=0 chnl=15
char id=66 x=315 y=173 width=33 height=40 xoffset=-2 yoffset=4 xadvance=29 page=0 chnl=15
char id=67 x=444 y=88 width=38 height=40 xoffset=-3 yoffset=4 xadvance=32 page=0 chnl=15
char id=68 x=376 y=131 width=35 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=69 x=102 y=216 width=32 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=70 x=232 y=215 width=31 height=40 xoffset=-1 yoffset=4 xadvance=27 page=0 chnl=15
char id=71 x=405 y=89 width=38 height=40 xoffset=-2 yoffset=4 xadvance=34 page=0 chnl=15
char id=72 x=245 y=173 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=73 x=335 y=255 width=14 height=40 xoffset=-1 yoffset=4 xadvance=12 page=0 chnl=15
char id=74 x=485 y=165 width=26 height=40 xoffset=-3 yoffset=4 xadvance=22 page=0 chnl=15
char id=75 x=340 y=132 width=35 height=40 xoffset=-2 yoffset=4 xadvance=29 page=0 chnl=15
char id=76 x=123 y=257 width=29 height=40 xoffset=-2 yoffset=4 xadvance=24 page=0 chnl=15
char id=77 x=166 y=92 width=39 height=40 xoffset=-1 yoffset=4 xadvance=37 page=0 chnl=15
char id=78 x=140 y=174 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=79 x=84 y=92 width=40 height=40 xoffset=-3 yoffset=4 xadvance=34 page=0 chnl=15
char id=80 x=0 y=216 width=33 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=81 x=0 y=50 width=40 height=42 xoffset=-3 yoffset=4 xadvance=34 page=0 chnl=15
char id=82 x=115 y=133 width=37 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=83 x=448 y=129 width=34 height=40 xoffset=-3 yoffset=4 xadvance=29 page=0 chnl=15
char id=84 x=0 y=175 width=34 height=40 xoffset=-4 yoffset=4 xadvance=26 page=0 chnl=15
char id=85 x=35 y=175 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=86 x=0 y=134 width=38 height=40 xoffset=-4 yoffset=4 xadvance=29 page=0 chnl=15
char id=87 x=194 y=50 width=52 height=40 xoffset=-4 yoffset=4 xadvance=44 page=0 chnl=15
char id=88 x=39 y=134 width=37 height=40 xoffset=-4 yoffset=4 xadvance=29 page=0 chnl=15
char id=89 x=303 y=132 width=36 height=40 xoffset=-4 yoffset=4 xadvance=28 page=0 chnl=15
char id=90 x=412 y=130 width=35 height=40 xoffset=-4 yoffset=4 xadvance=27 page=0 chnl=15
char id=91 x=306 y=0 width=18 height=49 xoffset=-2 yoffset=4 xadvance=12 page=0 chnl=15
char id=92 x=290 y=255 width=22 height=40 xoffset=-5 yoffset=4 xadvance=12 page=0 chnl=15
char id=93 x=287 y=0 width=18 height=49 xoffset=-4 yoffset=4 xadvance=12 page=0 chnl=15
char id=94 x=260 y=362 width=27 height=25 xoffset=-4 yoffset=4 xadvance=19 page=0 chnl=15
char id=95 x=431 y=361 width=34 height=12 xoffset=-5 yoffset=41 xadvance=24 page=0 chnl=15
char id=96 x=413 y=361 width=17 height=14 xoffset=-2 yoffset=4 xadvance=15 page=0 chnl=15
char id=97 x=144 y=298 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=98 x=264 y=214 width=30 height=40 xoffset=-2 yoffset=4 xadvance=25 page=0 chnl=15
char id=99 x=268 y=296 width=29 height=32 xoffset=-3 yoffset=12 xadvance=22 page=0 chnl=15
char id=100 x=213 y=256 width=29 height=40 xoffset=-3 yoffset=4 xadvance=24 page=0 chnl=15
char id=101 x=82 y=298 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=102 x=243 y=256 width=23 height=40 xoffset=-4 yoffset=4 xadvance=13 page=0 chnl=15
char id=103 x=134 y=50 width=29 height=41 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=15
char id=104 x=483 y=83 width=28 height=40 xoffset=-2 yoffset=4 xadvance=24 page=0 chnl=15
char id=105 x=380 y=255 width=14 height=40 xoffset=-2 yoffset=4 xadvance=10 page=0 chnl=15
char id=106 x=267 y=0 width=19 height=49 xoffset=-7 yoffset=4 xadvance=10 page=0 chnl=15
char id=107 x=483 y=124 width=28 height=40 xoffset=-2 yoffset=4 xadvance=22 page=0 chnl=15
char id=108 x=365 y=255 width=14 height=40 xoffset=-2 yoffset=4 xadvance=10 page=0 chnl=15
char id=109 x=0 y=298 width=42 height=32 xoffset=-2 yoffset=12 xadvance=38 page=0 chnl=15
char id=110 x=387 y=296 width=28 height=32 xoffset=-2 yoffset=12 xadvance=24 page=0 chnl=15
char id=111 x=206 y=297 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=112 x=72 y=50 width=30 height=41 xoffset=-2 yoffset=12 xadvance=25 page=0 chnl=15
char id=113 x=41 y=50 width=30 height=41 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=15
char id=114 x=443 y=293 width=22 height=32 xoffset=-2 yoffset=12 xadvance=15 page=0 chnl=15
char id=115 x=358 y=296 width=28 height=32 xoffset=-3 yoffset=12 xadvance=22 page=0 chnl=15
char id=116 x=426 y=253 width=20 height=39 xoffset=-4 yoffset=5 xadvance=12 page=0 chnl=15
char id=117 x=29 y=363 width=28 height=31 xoffset=-2 yoffset=13 xadvance=24 page=0 chnl=15
char id=118 x=221 y=330 width=31 height=31 xoffset=-4 yoffset=13 xadvance=23 page=0 chnl=15
char id=119 x=466 y=291 width=41 height=31 xoffset=-4 yoffset=13 xadvance=33 page=0 chnl=15
char id=120 x=284 y=329 width=30 height=31 xoffset=-4 yoffset=13 xadvance=22 page=0 chnl=15
char id=121 x=153 y=256 width=29 height=40 xoffset=-4 yoffset=13 xadvance=21 page=0 chnl=15
char id=122 x=315 y=329 width=30 height=31 xoffset=-4 yoffset=13 xadvance=22 page=0 chnl=15
char id=123 x=178 y=0 width=23 height=49 xoffset=-4 yoffset=4 xadvance=15 page=0 chnl=15
char id=124 x=325 y=0 width=13 height=49 xoffset=-1 yoffset=4 xadvance=11 page=0 chnl=15
char id=125 x=202 y=0 width=22 height=49 xoffset=-4 yoffset=4 xadvance=15 page=0 chnl=15
char id=126 x=380 y=361 width=32 height=16 xoffset=-3 yoffset=17 xadvance=26 page=0 chnl=15
char id=1025 x=413 y=0 width=32 height=46 xoffset=-1 yoffset=-2 xadvance=29 page=0 chnl=15
char id=1040 x=326 y=91 width=39 height=40 xoffset=-5 yoffset=4 xadvance=29 page=0 chnl=15
char id=1041 x=34 y=216 width=33 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=1042 x=451 y=170 width=33 height=40 xoffset=-2 yoffset=4 xadvance=29 page=0 chnl=15
char id=1043 x=31 y=257 width=30 height=40 xoffset=-1 yoffset=4 xadvance=24 page=0 chnl=15
char id=1044 x=374 y=0 width=38 height=47 xoffset=-5 yoffset=4 xadvance=30 page=0 chnl=15
char id=1045 x=135 y=215 width=32 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=1046 x=247 y=50 width=50 height=40 xoffset=-4 yoffset=4 xadvance=41 page=0 chnl=15
char id=1047 x=383 y=172 width=33 height=40 xoffset=-3 yoffset=4 xadvance=27 page=0 chnl=15
char id=1048 x=210 y=174 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=1049 x=339 y=0 width=34 height=48 xoffset=-1 yoffset=-4 xadvance=32 page=0 chnl=15
char id=1050 x=200 y=215 width=31 height=40 xoffset=-1 yoffset=4 xadvance=26 page=0 chnl=15
char id=1051 x=70 y=175 width=34 height=40 xoffset=-4 yoffset=4 xadvance=29 page=0 chnl=15
char id=1052 x=206 y=91 width=39 height=40 xoffset=-1 yoffset=4 xadvance=37 page=0 chnl=15
char id=1053 x=105 y=174 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=1054 x=125 y=92 width=40 height=40 xoffset=-3 yoffset=4 xadvance=34 page=0 chnl=15
char id=1055 x=175 y=174 width=34 height=40 xoffset=-1 yoffset=4 xadvance=32 page=0 chnl=15
char id=1056 x=478 y=42 width=33 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=1057 x=366 y=90 width=38 height=40 xoffset=-3 yoffset=4 xadvance=32 page=0 chnl=15
char id=1058 x=280 y=173 width=34 height=40 xoffset=-4 yoffset=4 xadvance=26 page=0 chnl=15
char id=1059 x=266 y=132 width=36 height=40 xoffset=-4 yoffset=4 xadvance=28 page=0 chnl=15
char id=1060 x=246 y=91 width=39 height=40 xoffset=-3 yoffset=4 xadvance=33 page=0 chnl=15
char id=1061 x=77 y=133 width=37 height=40 xoffset=-4 yoffset=4 xadvance=29 page=0 chnl=15
char id=1062 x=140 y=0 width=37 height=49 xoffset=-1 yoffset=4 xadvance=33 page=0 chnl=15
char id=1063 x=349 y=173 width=33 height=40 xoffset=-3 yoffset=4 xadvance=29 page=0 chnl=15
char id=1064 x=435 y=47 width=42 height=40 xoffset=-1 yoffset=4 xadvance=40 page=0 chnl=15
char id=1065 x=51 y=0 width=45 height=49 xoffset=-1 yoffset=4 xadvance=41 page=0 chnl=15
char id=1066 x=391 y=48 width=43 height=40 xoffset=-5 yoffset=4 xadvance=35 page=0 chnl=15
char id=1067 x=42 y=92 width=41 height=40 xoffset=-1 yoffset=4 xadvance=39 page=0 chnl=15
char id=1068 x=417 y=171 width=33 height=40 xoffset=-1 yoffset=4 xadvance=29 page=0 chnl=15
char id=1069 x=153 y=133 width=37 height=40 xoffset=-3 yoffset=4 xadvance=32 page=0 chnl=15
char id=1070 x=298 y=50 width=48 height=40 xoffset=-1 yoffset=4 xadvance=44 page=0 chnl=15
char id=1071 x=191 y=133 width=37 height=40 xoffset=-4 yoffset=4 xadvance=32 page=0 chnl=15
char id=1072 x=237 y=297 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=1073 x=477 y=0 width=31 height=41 xoffset=-3 yoffset=3 xadvance=25 page=0 chnl=15
char id=1074 x=465 y=326 width=28 height=31 xoffset=-2 yoffset=13 xadvance=23 page=0 chnl=15
char id=1075 x=143 y=363 width=23 height=31 xoffset=-2 yoffset=13 xadvance=16 page=0 chnl=15
char id=1076 x=462 y=253 width=34 height=37 xoffset=-5 yoffset=13 xadvance=26 page=0 chnl=15
char id=1077 x=175 y=297 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=1078 x=40 y=331 width=39 height=31 xoffset=-5 yoffset=13 xadvance=29 page=0 chnl=15
char id=1079 x=416 y=294 width=26 height=32 xoffset=-3 yoffset=12 xadvance=20 page=0 chnl=15
char id=1080 x=377 y=329 width=29 height=31 xoffset=-2 yoffset=13 xadvance=25 page=0 chnl=15
char id=1081 x=164 y=50 width=29 height=41 xoffset=-2 yoffset=3 xadvance=25 page=0 chnl=15
char id=1082 x=116 y=363 width=26 height=31 xoffset=-2 yoffset=13 xadvance=19 page=0 chnl=15
char id=1083 x=188 y=330 width=32 height=31 xoffset=-4 yoffset=13 xadvance=26 page=0 chnl=15
char id=1084 x=153 y=331 width=34 height=31 xoffset=-2 yoffset=13 xadvance=30 page=0 chnl=15
char id=1085 x=58 y=363 width=28 height=31 xoffset=-2 yoffset=13 xadvance=24 page=0 chnl=15
char id=1086 x=113 y=298 width=30 height=32 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=15
char id=1087 x=87 y=363 width=28 height=31 xoffset=-2 yoffset=13 xadvance=24 page=0 chnl=15
char id=1088 x=103 y=50 width=30 height=41 xoffset=-2 yoffset=12 xadvance=25 page=0 chnl=15
char id=1089 x=298 y=296 width=29 height=32 xoffset=-3 yoffset=12 xadvance=22 page=0 chnl=15
char id=1090 x=436 y=327 width=28 height=31 xoffset=-4 yoffset=13 xadvance=20 page=0 chnl=15
char id=1091 x=183 y=256 width=29 height=40 xoffset=-4 yoffset=13 xadvance=21 page=0 chnl=15
char id=1092 x=97 y=0 width=42 height=49 xoffset=-3 yoffset=4 xadvance=36 page=0 chnl=15
char id=1093 x=253 y=330 width=30 height=31 xoffset=-4 yoffset=13 xadvance=22 page=0 chnl=15
char id=1094 x=62 y=257 width=30 height=40 xoffset=-2 yoffset=13 xadvance=25 page=0 chnl=15
char id=1095 x=407 y=329 width=28 height=31 xoffset=-3 yoffset=13 xadvance=23 page=0 chnl=15
char id=1096 x=0 y=331 width=39 height=31 xoffset=-2 yoffset=13 xadvance=35 page=0 chnl=15
char id=1097 x=0 y=93 width=41 height=40 xoffset=-2 yoffset=13 xadvance=36 page=0 chnl=15
char id=1098 x=117 y=331 width=35 height=31 xoffset=-4 yoffset=13 xadvance=28 page=0 chnl=15
char id=1099 x=80 y=331 width=36 height=31 xoffset=-2 yoffset=13 xadvance=32 page=0 chnl=15
char id=1100 x=0 y=363 width=28 height=31 xoffset=-2 yoffset=13 xadvance=23 page=0 chnl=15
char id=1101 x=328 y=296 width=29 height=32 xoffset=-4 yoffset=12 xadvance=22 page=0 chnl=15
char id=1102 x=43 y=298 width=38 height=32 xoffset=-2 yoffset=12 xadvance=33 page=0 chnl=15
char id=1103 x=346 y=329 width=30 height=31 xoffset=-4 yoffset=13 xadvance=24 page=0 chnl=15
char id=1105 x=395 y=254 width=30 height=39 xoffset=-3 yoffset=5 xadvance=24 page=0 chnl=15
kernings count=547
kerning first=32 second=65 amount=-2
kerning first=32 second=84 amount=-1
kerning first=32 second=89 amount=-1
kerning first=1102 second=1095 amount=-1
kerning first=1102 second=1093 amount=-1
kerning first=1102 second=1090 amount=-1
kerning first=1102 second=1084 amount=-1
kerning first=1102 second=1083 amount=-1
kerning first=1102 second=1078 amount=-1
kerning first=1102 second=1076 amount=-1
kerning first=49 second=49 amount=-3
kerning first=65 second=32 amount=-2
kerning first=65 second=84 amount=-3
kerning first=65 second=86 amount=-3
kerning first=65 second=87 amount=-2
kerning first=65 second=89 amount=-3
kerning first=65 second=118 amount=-1
kerning first=65 second=119 amount=-1
kerning first=65 second=121 amount=-1
kerning first=1101 second=1103 amount=-1
kerning first=70 second=44 amount=-5
kerning first=70 second=46 amount=-5
kerning first=70 second=65 amount=-2
kerning first=76 second=32 amount=-2
kerning first=76 second=84 amount=-3
kerning first=76 second=86 amount=-3
kerning first=76 second=87 amount=-3
kerning first=76 second=89 amount=-3
kerning first=76 second=121 amount=-2
kerning first=1101 second=1093 amount=-1
kerning first=80 second=32 amount=-1
kerning first=80 second=44 amount=-6
kerning first=80 second=46 amount=-6
kerning first=80 second=65 amount=-3
kerning first=82 second=84 amount=-1
kerning first=82 second=86 amount=-1
kerning first=82 second=87 amount=-1
kerning first=82 second=89 amount=-1
kerning first=84 second=32 amount=-1
kerning first=84 second=44 amount=-5
kerning first=84 second=45 amount=-2
kerning first=84 second=46 amount=-5
kerning first=84 second=58 amount=-5
kerning first=1101 second=1090 amount=-1
kerning first=84 second=65 amount=-3
kerning first=84 second=79 amount=-1
kerning first=84 second=97 amount=-5
kerning first=84 second=99 amount=-5
kerning first=84 second=101 amount=-5
kerning first=84 second=105 amount=-2
kerning first=84 second=111 amount=-5
kerning first=84 second=114 amount=-2
kerning first=84 second=115 amount=-5
kerning first=84 second=117 amount=-2
kerning first=84 second=119 amount=-2
kerning first=84 second=121 amount=-2
kerning first=86 second=44 amount=-4
kerning first=86 second=45 amount=-2
kerning first=86 second=46 amount=-4
kerning first=86 second=58 amount=-2
kerning first=1101 second=1086 amount=1
kerning first=86 second=65 amount=-3
kerning first=86 second=97 amount=-3
kerning first=86 second=101 amount=-2
kerning first=86 second=105 amount=-1
kerning first=86 second=111 amount=-2
kerning first=86 second=114 amount=-2
kerning first=86 second=117 amount=-2
kerning first=86 second=121 amount=-2
kerning first=87 second=44 amount=-2
kerning first=87 second=45 amount=-1
kerning first=87 second=46 amount=-2
kerning first=87 second=58 amount=-1
kerning first=1101 second=1083 amount=-1
kerning first=87 second=65 amount=-2
kerning first=87 second=97 amount=-2
kerning first=87 second=101 amount=-1
kerning first=1101 second=1079 amount=-1
kerning first=87 second=111 amount=-1
kerning first=87 second=114 amount=-1
kerning first=87 second=117 amount=-1
kerning first=1101 second=1077 amount=1
kerning first=89 second=32 amount=-1
kerning first=89 second=44 amount=-6
kerning first=89 second=45 amount=-4
kerning first=89 second=46 amount=-6
kerning first=89 second=58 amount=-2
kerning first=1101 second=1076 amount=-1
kerning first=89 second=65 amount=-3
kerning first=89 second=97 amount=-3
kerning first=89 second=101 amount=-4
kerning first=89 second=105 amount=-2
kerning first=89 second=111 amount=-4
kerning first=89 second=112 amount=-3
kerning first=89 second=113 amount=-4
kerning first=89 second=117 amount=-2
kerning first=89 second=118 amount=-2
kerning first=102 second=102 amount=-1
kerning first=1100 second=1095 amount=-3
kerning first=114 second=44 amount=-2
kerning first=114 second=46 amount=-2
kerning first=1100 second=1090 amount=-3
kerning first=118 second=44 amount=-3
kerning first=118 second=46 amount=-3
kerning first=119 second=44 amount=-2
kerning first=119 second=46 amount=-2
kerning first=121 second=44 amount=-3
kerning first=121 second=46 amount=-3
kerning first=1097 second=1091 amount=1
kerning first=1097 second=1086 amount=-1
kerning first=1097 second=1077 amount=-1
kerning first=1094 second=1089 amount=-1
kerning first=1094 second=1086 amount=-1
kerning first=1094 second=1079 amount=-1
kerning first=1094 second=1077 amount=-1
kerning first=1093 second=1095 amount=-1
kerning first=1093 second=1092 amount=-1
kerning first=1093 second=1090 amount=-1
kerning first=1093 second=1089 amount=-1
kerning first=1093 second=1086 amount=-1
kerning first=1093 second=1079 amount=-1
kerning first=1093 second=1077 amount=-1
kerning first=1093 second=1073 amount=-1
kerning first=1093 second=1072 amount=-1
kerning first=1092 second=1103 amount=-1
kerning first=1092 second=1095 amount=-1
kerning first=1092 second=1091 amount=-1
kerning first=1092 second=1090 amount=-1
kerning first=1092 second=1083 amount=-1
kerning first=1092 second=1076 amount=-1
kerning first=1092 second=1073 amount=-1
kerning first=1091 second=1103 amount=-1
kerning first=1091 second=1101 amount=-1
kerning first=1091 second=1092 amount=-1
kerning first=1091 second=1089 amount=-1
kerning first=1091 second=1088 amount=-1
kerning first=1091 second=1086 amount=-1
kerning first=1091 second=1084 amount=-1
kerning first=1091 second=1083 amount=-1
kerning first=1091 second=1078 amount=1
kerning first=1091 second=1077 amount=-1
kerning first=1091 second=1076 amount=-1
kerning first=1091 second=1073 amount=1
kerning first=1091 second=1072 amount=-1
kerning first=1091 second=46 amount=-4
kerning first=1091 second=44 amount=-4
kerning first=1090 second=1091 amount=1
kerning first=1090 second=1089 amount=-1
kerning first=1090 second=1086 amount=-1
kerning first=1090 second=1083 amount=-1
kerning first=1090 second=1078 amount=1
kerning first=1090 second=1077 amount=-1
kerning first=1090 second=1076 amount=-1
kerning first=1090 second=1072 amount=-1
kerning first=1090 second=46 amount=-5
kerning first=1090 second=44 amount=-5
kerning first=1089 second=1101 amount=1
kerning first=1089 second=1095 amount=-1
kerning first=1089 second=1086 amount=1
kerning first=1089 second=1078 amount=1
kerning first=1088 second=1103 amount=-1
kerning first=1088 second=1095 amount=-1
kerning first=1088 second=1093 amount=-1
kerning first=1088 second=1091 amount=-1
kerning first=1088 second=1090 amount=-1
kerning first=1088 second=1083 amount=-2
kerning first=1088 second=1079 amount=-1
kerning first=1088 second=1076 amount=-1
kerning first=1086 second=1095 amount=-1
kerning first=1086 second=1093 amount=-1
kerning first=1086 second=1091 amount=-1
kerning first=1086 second=1090 amount=-1
kerning first=1086 second=1083 amount=-1
kerning first=1086 second=1079 amount=-1
kerning first=1086 second=1078 amount=-1
kerning first=1086 second=1076 amount=-1
kerning first=1084 second=1091 amount=1
kerning first=1084 second=1079 amount=-1
kerning first=1084 second=1073 amount=-1
kerning first=1083 second=1095 amount=-1
kerning first=1083 second=1086 amount=1
kerning first=1082 second=1101 amount=1
kerning first=1082 second=1091 amount=1
kerning first=1082 second=1090 amount=1
kerning first=1082 second=1089 amount=1
kerning first=1082 second=1086 amount=1
kerning first=1082 second=1083 amount=1
kerning first=1082 second=1079 amount=1
kerning first=1082 second=1077 amount=1
kerning first=1082 second=1073 amount=1
kerning first=1082 second=1072 amount=1
kerning first=1079 second=1098 amount=-1
kerning first=1079 second=1095 amount=-1
kerning first=1079 second=1092 amount=-1
kerning first=1079 second=1091 amount=-1
kerning first=1079 second=1089 amount=-1
kerning first=1079 second=1086 amount=-1
kerning first=1079 second=1083 amount=-1
kerning first=1079 second=1079 amount=-1
kerning first=1079 second=1077 amount=-1
kerning first=1079 second=1076 amount=-1
kerning first=1079 second=1073 amount=-1
kerning first=1078 second=1098 amount=1
kerning first=1078 second=1095 amount=-1
kerning first=1078 second=1091 amount=1
kerning first=1078 second=1073 amount=1
kerning first=1077 second=1095 amount=-1
kerning first=1077 second=1093 amount=-1
kerning first=1077 second=1091 amount=-1
kerning first=1077 second=1090 amount=-1
kerning first=1077 second=1083 amount=-1
kerning first=1077 second=1079 amount=-1
kerning first=1077 second=1078 amount=-1
kerning first=1077 second=1076 amount=-1
kerning first=1077 second=1073 amount=-1
kerning first=1076 second=1101 amount=1
kerning first=1076 second=1098 amount=-1
kerning first=1075 second=1103 amount=-1
kerning first=1075 second=1089 amount=-1
kerning first=1075 second=1086 amount=-1
kerning first=1075 second=1083 amount=-1
kerning first=1075 second=1079 amount=-1
kerning first=1075 second=1077 amount=-1
kerning first=1075 second=1076 amount=-2
kerning first=1075 second=1072 amount=-1
kerning first=1075 second=46 amount=-5
kerning first=1075 second=44 amount=-5
kerning first=1074 second=1103 amount=-1
kerning first=1074 second=1098 amount=-1
kerning first=1074 second=1095 amount=-2
kerning first=1074 second=1092 amount=-1
kerning first=1074 second=1091 amount=-1
kerning first=1074 second=1090 amount=-1
kerning first=1074 second=1089 amount=-1
kerning first=1074 second=1086 amount=-1
kerning first=1074 second=1084 amount=-1
kerning first=1074 second=1083 amount=-1
kerning first=1074 second=1079 amount=-1
kerning first=1074 second=1078 amount=-1
kerning first=1074 second=1077 amount=-1
kerning first=1074 second=1076 amount=-1
kerning first=1074 second=1073 amount=-1
kerning first=1074 second=1072 amount=-1
kerning first=1073 second=1103 amount=-1
kerning first=1073 second=1101 amount=-1
kerning first=1073 second=1098 amount=-1
kerning first=1073 second=1095 amount=-1
kerning first=1073 second=1093 amount=-1
kerning first=1073 second=1092 amount=-1
kerning first=1073 second=1091 amount=-1
kerning first=1073 second=1089 amount=-1
kerning first=1073 second=1084 amount=-1
kerning first=1073 second=1083 amount=-2
kerning first=1073 second=1079 amount=-1
kerning first=1073 second=1078 amount=-1
kerning first=1073 second=1077 amount=-1
kerning first=1073 second=1076 amount=-2
kerning first=1073 second=1072 amount=-1
kerning first=1072 second=1095 amount=-1
kerning first=1072 second=1091 amount=-1
kerning first=1072 second=1090 amount=-1
kerning first=1072 second=1079 amount=-1
kerning first=1070 second=1084 amount=-1
kerning first=1070 second=1083 amount=-2
kerning first=1070 second=1076 amount=-2
kerning first=1070 second=1063 amount=-1
kerning first=1070 second=1061 amount=-2
kerning first=1070 second=1058 amount=-3
kerning first=1070 second=1057 amount=-1
kerning first=1070 second=1054 amount=-1
kerning first=1070 second=1051 amount=-2
kerning first=1070 second=1046 amount=-1
kerning first=1070 second=1044 amount=-2
kerning first=1070 second=1040 amount=-1
kerning first=1069 second=1103 amount=-1
kerning first=1069 second=1084 amount=-1
kerning first=1069 second=1083 amount=-1
kerning first=1069 second=1078 amount=1
kerning first=1069 second=1076 amount=-1
kerning first=1069 second=1071 amount=-1
kerning first=1069 second=1061 amount=-2
kerning first=1069 second=1051 amount=-1
kerning first=1069 second=1047 amount=-1
kerning first=1069 second=1046 amount=-1
kerning first=1069 second=1044 amount=-1
kerning first=1068 second=1071 amount=-2
kerning first=1068 second=1069 amount=-1
kerning first=1068 second=1063 amount=-3
kerning first=1068 second=1061 amount=-2
kerning first=1068 second=1058 amount=-4
kerning first=1068 second=1057 amount=-1
kerning first=1068 second=1054 amount=-1
kerning first=1068 second=1052 amount=-1
kerning first=1068 second=1051 amount=-2
kerning first=1068 second=1047 amount=-1
kerning first=1068 second=1046 amount=-1
kerning first=1068 second=1044 amount=-1
kerning first=1068 second=1040 amount=-1
kerning first=1066 second=1071 amount=-1
kerning first=1065 second=1091 amount=1
kerning first=1065 second=1072 amount=1
kerning first=1062 second=1072 amount=1
kerning first=1062 second=1054 amount=-1
kerning first=1061 second=1091 amount=-1
kerning first=1061 second=1086 amount=-1
kerning first=1061 second=1069 amount=-2
kerning first=1061 second=1060 amount=-1
kerning first=1061 second=1057 amount=-1
kerning first=1061 second=1054 amount=-1
kerning first=1061 second=1047 amount=-1
kerning first=1060 second=1083 amount=-1
kerning first=1060 second=1071 amount=-2
kerning first=1060 second=1063 amount=-1
kerning first=1060 second=1059 amount=-2
kerning first=1060 second=1058 amount=-3
kerning first=1060 second=1051 amount=-1
kerning first=1060 second=1044 amount=-1
kerning first=1060 second=1040 amount=-1
kerning first=1059 second=1103 amount=-3
kerning first=1059 second=1102 amount=-2
kerning first=1059 second=1097 amount=-2
kerning first=1059 second=1096 amount=-2
kerning first=1059 second=1094 amount=-2
kerning first=1059 second=1093 amount=-2
kerning first=1059 second=1089 amount=-3
kerning first=1059 second=1088 amount=-2
kerning first=1059 second=1087 amount=-2
kerning first=1059 second=1086 amount=-3
kerning first=1059 second=1085 amount=-2
kerning first=1059 second=1084 amount=-2
kerning first=1059 second=1083 amount=-3
kerning first=1059 second=1082 amount=-2
kerning first=1059 second=1081 amount=-1
kerning first=1059 second=1080 amount=-2
kerning first=1059 second=1079 amount=-3
kerning first=1059 second=1078 amount=-1
kerning first=1059 second=1077 amount=-3
kerning first=1059 second=1076 amount=-3
kerning first=1059 second=1075 amount=-2
kerning first=1059 second=1074 amount=-3
kerning first=1059 second=1073 amount=-1
kerning first=1059 second=1071 amount=-1
kerning first=1059 second=1069 amount=-1
kerning first=1059 second=1060 amount=-1
kerning first=1059 second=1054 amount=-1
kerning first=1059 second=1051 amount=-1
kerning first=1059 second=1047 amount=-1
kerning first=1059 second=1044 amount=-2
kerning first=1059 second=1040 amount=-3
kerning first=1059 second=58 amount=-1
kerning first=1059 second=46 amount=-6
kerning first=1059 second=44 amount=-6
kerning first=1058 second=1103 amount=-3
kerning first=1058 second=1102 amount=-2
kerning first=1058 second=1100 amount=-2
kerning first=1058 second=1099 amount=-2
kerning first=1058 second=1097 amount=-2
kerning first=1058 second=1093 amount=-2
kerning first=1058 second=1091 amount=-3
kerning first=1058 second=1089 amount=-3
kerning first=1058 second=1088 amount=-3
kerning first=1058 second=1087 amount=-2
kerning first=1058 second=1086 amount=-3
kerning first=1058 second=1084 amount=-2
kerning first=1058 second=1083 amount=-2
kerning first=1058 second=1082 amount=-2
kerning first=1058 second=1080 amount=-2
kerning first=1058 second=1077 amount=-3
kerning first=1058 second=1074 amount=-2
kerning first=1058 second=1072 amount=-2
kerning first=1058 second=1071 amount=-1
kerning first=1058 second=1060 amount=-1
kerning first=1058 second=1054 amount=-2
kerning first=1058 second=1051 amount=-1
kerning first=1058 second=1047 amount=-1
kerning first=1058 second=1046 amount=1
kerning first=1058 second=1044 amount=-1
kerning first=1058 second=1040 amount=-1
kerning first=1058 second=46 amount=-5
kerning first=1058 second=44 amount=-5
kerning first=1057 second=1095 amount=-1
kerning first=1057 second=1078 amount=1
kerning first=1057 second=1072 amount=1
kerning first=1057 second=1069 amount=-1
kerning first=1057 second=1066 amount=-2
kerning first=1057 second=1063 amount=-1
kerning first=1057 second=1061 amount=-3
kerning first=1057 second=1059 amount=-1
kerning first=1057 second=1058 amount=-1
kerning first=1057 second=1054 amount=-1
kerning first=1057 second=1052 amount=-1
kerning first=1057 second=1051 amount=-1
kerning first=1057 second=1047 amount=-1
kerning first=1057 second=1044 amount=-1
kerning first=1057 second=1040 amount=-1
kerning first=1056 second=1103 amount=-1
kerning first=1056 second=1101 amount=-1
kerning first=1056 second=1086 amount=-2
kerning first=1056 second=1077 amount=-2
kerning first=1056 second=1076 amount=-3
kerning first=1056 second=1072 amount=-1
kerning first=1056 second=1071 amount=-1
kerning first=1056 second=1061 amount=-2
kerning first=1056 second=1060 amount=-1
kerning first=1056 second=1059 amount=-1
kerning first=1056 second=1058 amount=-2
kerning first=1056 second=1057 amount=-1
kerning first=1056 second=1054 amount=-1
kerning first=1056 second=1052 amount=-1
kerning first=1056 second=1051 amount=-3
kerning first=1056 second=1047 amount=-1
kerning first=1056 second=1046 amount=-1
kerning first=1056 second=1044 amount=-3
kerning first=1056 second=1040 amount=-3
kerning first=1056 second=58 amount=-1
kerning first=1056 second=46 amount=-8
kerning first=1056 second=44 amount=-8
kerning first=1054 second=1093 amount=-1
kerning first=1054 second=1083 amount=-1
kerning first=1054 second=1076 amount=-1
kerning first=1040 second=1044 amount=1
kerning first=1040 second=1047 amount=-1
kerning first=1040 second=1051 amount=1
kerning first=1040 second=1054 amount=-1
kerning first=1040 second=1055 amount=-1
kerning first=1040 second=1057 amount=-1
kerning first=1040 second=1058 amount=-3
kerning first=1040 second=1059 amount=-2
kerning first=1040 second=1060 amount=-1
kerning first=1040 second=1063 amount=-3
kerning first=1040 second=1069 amount=-1
kerning first=1040 second=1072 amount=1
kerning first=1040 second=1090 amount=-1
kerning first=1040 second=1091 amount=-1
kerning first=1040 second=1092 amount=1
kerning first=1040 second=1101 amount=1
kerning first=1041 second=1040 amount=-1
kerning first=1041 second=1047 amount=-1
kerning first=1041 second=1054 amount=-1
kerning first=1041 second=1057 amount=-1
kerning first=1041 second=1058 amount=-2
kerning first=1041 second=1059 amount=-1
kerning first=1041 second=1060 amount=-1
kerning first=1041 second=1061 amount=-1
kerning first=1041 second=1063 amount=-2
kerning first=1041 second=1066 amount=-1
kerning first=1041 second=1069 amount=-1
kerning first=1041 second=1071 amount=-1
kerning first=1041 second=1083 amount=-1
kerning first=1041 second=1091 amount=-1
kerning first=1042 second=1040 amount=-1
kerning first=1042 second=1044 amount=-1
kerning first=1042 second=1046 amount=-1
kerning first=1042 second=1047 amount=-1
kerning first=1042 second=1051 amount=-1
kerning first=1042 second=1054 amount=-1
kerning first=1042 second=1057 amount=-1
kerning first=1042 second=1058 amount=-3
kerning first=1042 second=1059 amount=-1
kerning first=1042 second=1060 amount=-1
kerning first=1042 second=1061 amount=-2
kerning first=1042 second=1063 amount=-2
kerning first=1042 second=1066 amount=-3
kerning first=1042 second=1071 amount=-1
kerning first=1042 second=1076 amount=-1
kerning first=1042 second=1084 amount=-1
kerning first=1042 second=1090 amount=-1
kerning first=1042 second=1091 amount=-1
kerning first=1042 second=1093 amount=-1
kerning first=1042 second=1095 amount=-1
kerning first=1042 second=1103 amount=-1
kerning first=1043 second=44 amount=-5
kerning first=1043 second=46 amount=-5
kerning first=1054 second=1071 amount=-1
kerning first=1054 second=1063 amount=-1
kerning first=1054 second=1061 amount=-2
kerning first=1043 second=1040 amount=-3
kerning first=1043 second=1044 amount=-3
kerning first=1043 second=1047 amount=-1
kerning first=1043 second=1051 amount=-3
kerning first=1043 second=1052 amount=-1
kerning first=1043 second=1054 amount=-3
kerning first=1043 second=1057 amount=-2
kerning first=1043 second=1071 amount=-1
kerning first=1043 second=1072 amount=-3
kerning first=1043 second=1074 amount=-3
kerning first=1043 second=1076 amount=-3
kerning first=1043 second=1077 amount=-3
kerning first=1043 second=1080 amount=-3
kerning first=1043 second=1083 amount=-3
kerning first=1043 second=1084 amount=-3
kerning first=1043 second=1085 amount=-3
kerning first=1043 second=1086 amount=-3
kerning first=1043 second=1088 amount=-3
kerning first=1043 second=1091 amount=-3
kerning first=1043 second=1099 amount=-3
kerning first=1043 second=1100 amount=-3
kerning first=1043 second=1102 amount=-3
kerning first=1043 second=1103 amount=-3
kerning first=1044 second=1059 amount=1
kerning first=1044 second=1060 amount=-1
kerning first=1044 second=1063 amount=-2
kerning first=1044 second=1079 amount=1
kerning first=1044 second=1086 amount=1
kerning first=1044 second=1091 amount=1
kerning first=1045 second=1047 amount=-1
kerning first=1045 second=1089 amount=-1
kerning first=1046 second=1047 amount=-1
kerning first=1046 second=1054 amount=-1
kerning first=1046 second=1057 amount=-1
kerning first=1046 second=1058 amount=1
kerning first=1046 second=1059 amount=1
kerning first=1046 second=1066 amount=1
kerning first=1046 second=1072 amount=1
kerning first=1046 second=1077 amount=-1
kerning first=1046 second=1086 amount=-1
kerning first=1046 second=1091 amount=-1
kerning first=1047 second=1051 amount=-1
kerning first=1047 second=1054 amount=-1
kerning first=1047 second=1057 amount=-1
kerning first=1047 second=1058 amount=-1
kerning first=1047 second=1059 amount=-1
kerning first=1047 second=1060 amount=-1
kerning first=1047 second=1063 amount=-1
kerning first=1047 second=1071 amount=-1
kerning first=1050 second=1047 amount=-1
kerning first=1050 second=1054 amount=-1
kerning first=1050 second=1057 amount=-1
kerning first=1050 second=1059 amount=1
kerning first=1050 second=1060 amount=-2
kerning first=1051 second=1060 amount=-1
kerning first=1051 second=1073 amount=1
kerning first=1051 second=1091 amount=1
kerning first=1052 second=1060 amount=-1
kerning first=1052 second=1063 amount=-1
kerning first=1052 second=1072 amount=1
kerning first=1052 second=1077 amount=1
kerning first=1052 second=1086 amount=1
kerning first=1052 second=1089 amount=1
kerning first=1052 second=1091 amount=1
kerning first=1052 second=1095 amount=-1
kerning first=1052 second=1101 amount=1
kerning first=1054 second=1040 amount=-1
kerning first=1054 second=1044 amount=-1
kerning first=1054 second=1046 amount=-1
kerning first=1054 second=1051 amount=-1
kerning first=1054 second=1059 amount=-1

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cdd1e2d175c5109ec5840ea37093e7f745fbf618b709ee334b7459ef1567960a
size 61729

View File

@@ -0,0 +1,720 @@
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=51 base=41 scaleW=512 scaleH=512 pages=1 packed=0 alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0
page id=0 file="arial_sdf.png"
chars count=161
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=41 xadvance=12 page=0 chnl=8
char id=33 x=225 y=312 width=16 height=43 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=8
char id=34 x=131 y=423 width=22 height=23 xoffset=-3 yoffset=3 xadvance=16 page=0 chnl=8
char id=35 x=156 y=96 width=35 height=44 xoffset=-5 yoffset=3 xadvance=25 page=0 chnl=8
char id=36 x=422 y=0 width=32 height=50 xoffset=-4 yoffset=1 xadvance=25 page=0 chnl=8
char id=37 x=386 y=50 width=46 height=45 xoffset=-3 yoffset=3 xadvance=40 page=0 chnl=8
char id=38 x=349 y=95 width=38 height=44 xoffset=-4 yoffset=3 xadvance=30 page=0 chnl=8
char id=39 x=153 y=423 width=16 height=23 xoffset=-4 yoffset=3 xadvance=9 page=0 chnl=8
char id=40 x=120 y=0 width=22 height=53 xoffset=-3 yoffset=3 xadvance=15 page=0 chnl=8
char id=41 x=98 y=0 width=22 height=53 xoffset=-3 yoffset=3 xadvance=15 page=0 chnl=8
char id=42 x=408 y=422 width=25 height=25 xoffset=-4 yoffset=3 xadvance=17 page=0 chnl=8
char id=43 x=347 y=422 width=32 height=32 xoffset=-3 yoffset=9 xadvance=26 page=0 chnl=8
char id=44 x=169 y=423 width=16 height=22 xoffset=-2 yoffset=31 xadvance=12 page=0 chnl=8
char id=45 x=239 y=423 width=23 height=15 xoffset=-4 yoffset=22 xadvance=15 page=0 chnl=8
char id=46 x=262 y=423 width=15 height=15 xoffset=-1 yoffset=31 xadvance=12 page=0 chnl=8
char id=47 x=156 y=140 width=23 height=44 xoffset=-5 yoffset=3 xadvance=12 page=0 chnl=8
char id=48 x=96 y=97 width=32 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=49 x=179 y=312 width=23 height=43 xoffset=-1 yoffset=3 xadvance=25 page=0 chnl=8
char id=50 x=0 y=270 width=32 height=43 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=51 x=64 y=97 width=32 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=52 x=278 y=269 width=33 height=43 xoffset=-5 yoffset=3 xadvance=25 page=0 chnl=8
char id=53 x=311 y=269 width=33 height=43 xoffset=-4 yoffset=4 xadvance=25 page=0 chnl=8
char id=54 x=32 y=97 width=32 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=55 x=286 y=312 width=31 height=42 xoffset=-3 yoffset=4 xadvance=25 page=0 chnl=8
char id=56 x=0 y=97 width=32 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=57 x=292 y=96 width=32 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=58 x=52 y=417 width=15 height=34 xoffset=-1 yoffset=12 xadvance=12 page=0 chnl=8
char id=59 x=458 y=312 width=16 height=41 xoffset=-2 yoffset=12 xadvance=12 page=0 chnl=8
char id=60 x=67 y=417 width=32 height=33 xoffset=-3 yoffset=9 xadvance=26 page=0 chnl=8
char id=61 x=99 y=423 width=32 height=24 xoffset=-3 yoffset=13 xadvance=26 page=0 chnl=8
char id=62 x=315 y=422 width=32 height=33 xoffset=-3 yoffset=9 xadvance=26 page=0 chnl=8
char id=63 x=441 y=269 width=32 height=43 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=64 x=0 y=0 width=52 height=53 xoffset=-3 yoffset=3 xadvance=45 page=0 chnl=8
char id=65 x=283 y=140 width=41 height=43 xoffset=-6 yoffset=3 xadvance=30 page=0 chnl=8
char id=66 x=477 y=226 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=67 x=117 y=53 width=39 height=44 xoffset=-3 yoffset=3 xadvance=32 page=0 chnl=8
char id=68 x=78 y=184 width=37 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=69 x=70 y=227 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=70 x=344 y=269 width=33 height=43 xoffset=-2 yoffset=3 xadvance=27 page=0 chnl=8
char id=71 x=267 y=52 width=41 height=44 xoffset=-3 yoffset=3 xadvance=35 page=0 chnl=8
char id=72 x=441 y=226 width=36 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=73 x=271 y=312 width=15 height=43 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=8
char id=74 x=128 y=97 width=28 height=44 xoffset=-4 yoffset=3 xadvance=22 page=0 chnl=8
char id=75 x=152 y=226 width=37 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=76 x=63 y=270 width=31 height=43 xoffset=-2 yoffset=3 xadvance=25 page=0 chnl=8
char id=77 x=221 y=183 width=41 height=43 xoffset=-2 yoffset=3 xadvance=37 page=0 chnl=8
char id=78 x=369 y=226 width=36 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=79 x=226 y=52 width=41 height=44 xoffset=-3 yoffset=3 xadvance=35 page=0 chnl=8
char id=80 x=0 y=227 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=81 x=454 y=49 width=43 height=46 xoffset=-4 yoffset=3 xadvance=35 page=0 chnl=8
char id=82 x=39 y=184 width=39 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=83 x=387 y=95 width=36 height=44 xoffset=-3 yoffset=3 xadvance=30 page=0 chnl=8
char id=84 x=225 y=226 width=36 height=43 xoffset=-4 yoffset=3 xadvance=27 page=0 chnl=8
char id=85 x=459 y=95 width=36 height=44 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=86 x=384 y=183 width=40 height=43 xoffset=-5 yoffset=3 xadvance=30 page=0 chnl=8
char id=87 x=179 y=140 width=52 height=43 xoffset=-5 yoffset=3 xadvance=42 page=0 chnl=8
char id=88 x=464 y=183 width=40 height=43 xoffset=-5 yoffset=3 xadvance=30 page=0 chnl=8
char id=89 x=344 y=183 width=40 height=43 xoffset=-5 yoffset=3 xadvance=30 page=0 chnl=8
char id=90 x=115 y=184 width=37 height=43 xoffset=-5 yoffset=3 xadvance=27 page=0 chnl=8
char id=91 x=328 y=0 width=19 height=52 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=8
char id=92 x=482 y=139 width=23 height=44 xoffset=-5 yoffset=3 xadvance=12 page=0 chnl=8
char id=93 x=308 y=0 width=20 height=52 xoffset=-5 yoffset=3 xadvance=12 page=0 chnl=8
char id=94 x=379 y=422 width=29 height=28 xoffset=-4 yoffset=3 xadvance=21 page=0 chnl=8
char id=95 x=277 y=423 width=37 height=13 xoffset=-6 yoffset=42 xadvance=25 page=0 chnl=8
char id=96 x=219 y=423 width=20 height=17 xoffset=-4 yoffset=3 xadvance=15 page=0 chnl=8
char id=97 x=33 y=348 width=32 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=98 x=388 y=139 width=32 height=44 xoffset=-3 yoffset=3 xadvance=25 page=0 chnl=8
char id=99 x=380 y=353 width=31 height=35 xoffset=-4 yoffset=12 xadvance=22 page=0 chnl=8
char id=100 x=420 y=139 width=31 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
char id=101 x=474 y=347 width=33 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=102 x=155 y=312 width=24 height=43 xoffset=-5 yoffset=3 xadvance=12 page=0 chnl=8
char id=103 x=451 y=139 width=31 height=44 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=104 x=125 y=312 width=30 height=43 xoffset=-3 yoffset=3 xadvance=25 page=0 chnl=8
char id=105 x=256 y=312 width=15 height=43 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=8
char id=106 x=142 y=0 width=20 height=53 xoffset=-8 yoffset=3 xadvance=10 page=0 chnl=8
char id=107 x=94 y=270 width=31 height=43 xoffset=-3 yoffset=3 xadvance=22 page=0 chnl=8
char id=108 x=241 y=312 width=15 height=43 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=8
char id=109 x=125 y=355 width=43 height=34 xoffset=-3 yoffset=12 xadvance=37 page=0 chnl=8
char id=110 x=475 y=416 width=30 height=34 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=111 x=40 y=313 width=33 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=112 x=409 y=269 width=32 height=43 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=113 x=32 y=270 width=31 height=43 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=114 x=28 y=417 width=24 height=34 xoffset=-3 yoffset=12 xadvance=15 page=0 chnl=8
char id=115 x=442 y=353 width=30 height=35 xoffset=-4 yoffset=12 xadvance=22 page=0 chnl=8
char id=116 x=202 y=312 width=23 height=43 xoffset=-5 yoffset=4 xadvance=12 page=0 chnl=8
char id=117 x=286 y=354 width=30 height=35 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=118 x=413 y=388 width=32 height=34 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=119 x=168 y=355 width=42 height=34 xoffset=-5 yoffset=12 xadvance=32 page=0 chnl=8
char id=120 x=316 y=388 width=33 height=34 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=121 x=324 y=139 width=32 height=44 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=122 x=349 y=388 width=32 height=34 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=123 x=52 y=0 width=23 height=53 xoffset=-4 yoffset=3 xadvance=15 page=0 chnl=8
char id=124 x=162 y=0 width=14 height=53 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=8
char id=125 x=75 y=0 width=23 height=53 xoffset=-4 yoffset=3 xadvance=15 page=0 chnl=8
char id=126 x=185 y=423 width=34 height=18 xoffset=-4 yoffset=16 xadvance=26 page=0 chnl=8
char id=1025 x=454 y=0 width=35 height=49 xoffset=-2 yoffset=-3 xadvance=30 page=0 chnl=8
char id=1040 x=262 y=183 width=41 height=43 xoffset=-6 yoffset=3 xadvance=30 page=0 chnl=8
char id=1041 x=140 y=269 width=35 height=43 xoffset=-2 yoffset=3 xadvance=29 page=0 chnl=8
char id=1042 x=175 y=269 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=1043 x=473 y=269 width=32 height=43 xoffset=-2 yoffset=3 xadvance=24 page=0 chnl=8
char id=1044 x=347 y=0 width=39 height=51 xoffset=-5 yoffset=3 xadvance=30 page=0 chnl=8
char id=1045 x=210 y=269 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=1046 x=231 y=140 width=52 height=43 xoffset=-5 yoffset=3 xadvance=41 page=0 chnl=8
char id=1047 x=191 y=96 width=35 height=44 xoffset=-4 yoffset=3 xadvance=27 page=0 chnl=8
char id=1048 x=333 y=226 width=36 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=1049 x=386 y=0 width=36 height=50 xoffset=-2 yoffset=-4 xadvance=32 page=0 chnl=8
char id=1050 x=245 y=269 width=33 height=43 xoffset=-2 yoffset=3 xadvance=26 page=0 chnl=8
char id=1051 x=423 y=95 width=36 height=44 xoffset=-5 yoffset=3 xadvance=29 page=0 chnl=8
char id=1052 x=303 y=183 width=41 height=43 xoffset=-2 yoffset=3 xadvance=37 page=0 chnl=8
char id=1053 x=261 y=226 width=36 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=1054 x=308 y=52 width=41 height=44 xoffset=-3 yoffset=3 xadvance=35 page=0 chnl=8
char id=1055 x=405 y=226 width=36 height=43 xoffset=-2 yoffset=3 xadvance=32 page=0 chnl=8
char id=1056 x=105 y=227 width=35 height=43 xoffset=-2 yoffset=3 xadvance=30 page=0 chnl=8
char id=1057 x=78 y=53 width=39 height=44 xoffset=-3 yoffset=3 xadvance=32 page=0 chnl=8
char id=1058 x=189 y=226 width=36 height=43 xoffset=-4 yoffset=3 xadvance=27 page=0 chnl=8
char id=1059 x=39 y=53 width=39 height=44 xoffset=-5 yoffset=3 xadvance=28 page=0 chnl=8
char id=1060 x=179 y=183 width=42 height=43 xoffset=-4 yoffset=3 xadvance=34 page=0 chnl=8
char id=1061 x=424 y=183 width=40 height=43 xoffset=-5 yoffset=3 xadvance=30 page=0 chnl=8
char id=1062 x=269 y=0 width=39 height=52 xoffset=-2 yoffset=3 xadvance=33 page=0 chnl=8
char id=1063 x=297 y=226 width=36 height=43 xoffset=-4 yoffset=3 xadvance=30 page=0 chnl=8
char id=1064 x=0 y=141 width=45 height=43 xoffset=-2 yoffset=3 xadvance=41 page=0 chnl=8
char id=1065 x=176 y=0 width=48 height=52 xoffset=-2 yoffset=3 xadvance=42 page=0 chnl=8
char id=1066 x=45 y=141 width=44 height=43 xoffset=-5 yoffset=3 xadvance=35 page=0 chnl=8
char id=1067 x=89 y=141 width=43 height=43 xoffset=-2 yoffset=3 xadvance=40 page=0 chnl=8
char id=1068 x=35 y=227 width=35 height=43 xoffset=-2 yoffset=3 xadvance=29 page=0 chnl=8
char id=1069 x=0 y=53 width=39 height=44 xoffset=-4 yoffset=3 xadvance=32 page=0 chnl=8
char id=1070 x=176 y=52 width=50 height=44 xoffset=-2 yoffset=3 xadvance=45 page=0 chnl=8
char id=1071 x=0 y=184 width=39 height=43 xoffset=-5 yoffset=3 xadvance=32 page=0 chnl=8
char id=1072 x=348 y=353 width=32 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=1073 x=259 y=96 width=33 height=44 xoffset=-4 yoffset=3 xadvance=26 page=0 chnl=8
char id=1074 x=108 y=389 width=31 height=34 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=8
char id=1075 x=290 y=389 width=25 height=34 xoffset=-3 yoffset=12 xadvance=16 page=0 chnl=8
char id=1076 x=391 y=312 width=35 height=41 xoffset=-5 yoffset=12 xadvance=26 page=0 chnl=8
char id=1077 x=0 y=348 width=33 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=1078 x=210 y=355 width=42 height=34 xoffset=-6 yoffset=12 xadvance=30 page=0 chnl=8
char id=1079 x=97 y=348 width=28 height=35 xoffset=-4 yoffset=12 xadvance=21 page=0 chnl=8
char id=1080 x=139 y=389 width=31 height=34 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=1081 x=317 y=312 width=31 height=42 xoffset=-3 yoffset=4 xadvance=25 page=0 chnl=8
char id=1082 x=0 y=417 width=28 height=34 xoffset=-3 yoffset=12 xadvance=20 page=0 chnl=8
char id=1083 x=474 y=312 width=34 height=35 xoffset=-5 yoffset=12 xadvance=26 page=0 chnl=8
char id=1084 x=73 y=383 width=35 height=34 xoffset=-2 yoffset=12 xadvance=31 page=0 chnl=8
char id=1085 x=260 y=389 width=30 height=34 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=1086 x=73 y=313 width=33 height=35 xoffset=-4 yoffset=12 xadvance=25 page=0 chnl=8
char id=1087 x=445 y=416 width=30 height=34 xoffset=-3 yoffset=12 xadvance=24 page=0 chnl=8
char id=1088 x=377 y=269 width=32 height=43 xoffset=-3 yoffset=12 xadvance=25 page=0 chnl=8
char id=1089 x=411 y=353 width=31 height=35 xoffset=-4 yoffset=12 xadvance=22 page=0 chnl=8
char id=1090 x=200 y=389 width=30 height=34 xoffset=-5 yoffset=12 xadvance=20 page=0 chnl=8
char id=1091 x=356 y=139 width=32 height=44 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=1092 x=224 y=0 width=45 height=52 xoffset=-4 yoffset=3 xadvance=37 page=0 chnl=8
char id=1093 x=252 y=355 width=33 height=34 xoffset=-5 yoffset=12 xadvance=22 page=0 chnl=8
char id=1094 x=426 y=312 width=32 height=41 xoffset=-2 yoffset=12 xadvance=26 page=0 chnl=8
char id=1095 x=170 y=389 width=30 height=34 xoffset=-4 yoffset=12 xadvance=23 page=0 chnl=8
char id=1096 x=472 y=382 width=40 height=34 xoffset=-2 yoffset=12 xadvance=36 page=0 chnl=8
char id=1097 x=348 y=312 width=43 height=41 xoffset=-2 yoffset=12 xadvance=37 page=0 chnl=8
char id=1098 x=0 y=383 width=37 height=34 xoffset=-5 yoffset=12 xadvance=28 page=0 chnl=8
char id=1099 x=37 y=383 width=36 height=34 xoffset=-2 yoffset=12 xadvance=32 page=0 chnl=8
char id=1100 x=230 y=389 width=30 height=34 xoffset=-3 yoffset=12 xadvance=23 page=0 chnl=8
char id=1101 x=65 y=348 width=32 height=35 xoffset=-5 yoffset=12 xadvance=23 page=0 chnl=8
char id=1102 x=0 y=313 width=40 height=35 xoffset=-3 yoffset=12 xadvance=34 page=0 chnl=8
char id=1103 x=381 y=388 width=32 height=34 xoffset=-5 yoffset=12 xadvance=24 page=0 chnl=8
char id=1105 x=226 y=96 width=33 height=44 xoffset=-4 yoffset=3 xadvance=25 page=0 chnl=8
kernings count=554
kerning first=32 second=65 amount=-5
kerning first=32 second=84 amount=-2
kerning first=32 second=89 amount=-2
kerning first=49 second=49 amount=-7
kerning first=65 second=32 amount=-5
kerning first=65 second=84 amount=-7
kerning first=65 second=86 amount=-7
kerning first=65 second=87 amount=-3
kerning first=65 second=89 amount=-7
kerning first=65 second=118 amount=-2
kerning first=65 second=119 amount=-2
kerning first=65 second=121 amount=-2
kerning first=70 second=44 amount=-10
kerning first=70 second=46 amount=-10
kerning first=70 second=65 amount=-5
kerning first=76 second=32 amount=-3
kerning first=76 second=84 amount=-7
kerning first=76 second=86 amount=-7
kerning first=76 second=87 amount=-7
kerning first=76 second=89 amount=-7
kerning first=76 second=121 amount=-3
kerning first=80 second=32 amount=-2
kerning first=80 second=44 amount=-12
kerning first=80 second=46 amount=-12
kerning first=80 second=65 amount=-7
kerning first=82 second=84 amount=-2
kerning first=82 second=86 amount=-2
kerning first=82 second=87 amount=-2
kerning first=82 second=89 amount=-2
kerning first=84 second=32 amount=-2
kerning first=84 second=44 amount=-10
kerning first=84 second=45 amount=-5
kerning first=84 second=46 amount=-10
kerning first=84 second=58 amount=-10
kerning first=84 second=59 amount=-10
kerning first=84 second=65 amount=-7
kerning first=84 second=79 amount=-2
kerning first=84 second=97 amount=-10
kerning first=84 second=99 amount=-10
kerning first=84 second=101 amount=-10
kerning first=84 second=105 amount=-3
kerning first=84 second=111 amount=-10
kerning first=84 second=114 amount=-3
kerning first=84 second=115 amount=-10
kerning first=84 second=117 amount=-3
kerning first=84 second=119 amount=-5
kerning first=84 second=121 amount=-5
kerning first=86 second=44 amount=-8
kerning first=86 second=45 amount=-5
kerning first=86 second=46 amount=-8
kerning first=86 second=58 amount=-3
kerning first=86 second=59 amount=-3
kerning first=86 second=65 amount=-7
kerning first=86 second=97 amount=-7
kerning first=86 second=101 amount=-5
kerning first=86 second=105 amount=-2
kerning first=86 second=111 amount=-5
kerning first=86 second=114 amount=-3
kerning first=86 second=117 amount=-3
kerning first=86 second=121 amount=-3
kerning first=87 second=44 amount=-5
kerning first=87 second=45 amount=-2
kerning first=87 second=46 amount=-5
kerning first=87 second=58 amount=-2
kerning first=87 second=59 amount=-2
kerning first=87 second=65 amount=-3
kerning first=87 second=97 amount=-3
kerning first=87 second=101 amount=-2
kerning first=87 second=111 amount=-2
kerning first=87 second=114 amount=-2
kerning first=87 second=117 amount=-2
kerning first=87 second=121 amount=-1
kerning first=89 second=32 amount=-2
kerning first=89 second=44 amount=-12
kerning first=89 second=45 amount=-8
kerning first=89 second=46 amount=-12
kerning first=89 second=58 amount=-5
kerning first=89 second=59 amount=-6
kerning first=89 second=65 amount=-7
kerning first=89 second=97 amount=-7
kerning first=89 second=101 amount=-8
kerning first=89 second=105 amount=-3
kerning first=89 second=111 amount=-8
kerning first=89 second=112 amount=-7
kerning first=89 second=113 amount=-8
kerning first=89 second=117 amount=-5
kerning first=89 second=118 amount=-5
kerning first=102 second=102 amount=-2
kerning first=114 second=44 amount=-5
kerning first=114 second=46 amount=-5
kerning first=118 second=44 amount=-7
kerning first=118 second=46 amount=-7
kerning first=119 second=44 amount=-5
kerning first=119 second=46 amount=-5
kerning first=121 second=44 amount=-7
kerning first=121 second=46 amount=-7
kerning first=1040 second=1044 amount=3
kerning first=1040 second=1047 amount=-1
kerning first=1040 second=1051 amount=2
kerning first=1040 second=1054 amount=-2
kerning first=1040 second=1055 amount=-1
kerning first=1040 second=1057 amount=-2
kerning first=1040 second=1058 amount=-7
kerning first=1040 second=1059 amount=-4
kerning first=1040 second=1060 amount=-3
kerning first=1040 second=1063 amount=-7
kerning first=1040 second=1069 amount=-2
kerning first=1040 second=1072 amount=1
kerning first=1040 second=1090 amount=-2
kerning first=1040 second=1091 amount=-1
kerning first=1040 second=1092 amount=1
kerning first=1040 second=1101 amount=2
kerning first=1041 second=1040 amount=-2
kerning first=1041 second=1047 amount=-1
kerning first=1041 second=1054 amount=-1
kerning first=1041 second=1057 amount=-1
kerning first=1041 second=1058 amount=-4
kerning first=1041 second=1059 amount=-2
kerning first=1041 second=1060 amount=-1
kerning first=1041 second=1061 amount=-2
kerning first=1041 second=1063 amount=-4
kerning first=1041 second=1066 amount=-3
kerning first=1041 second=1069 amount=-1
kerning first=1041 second=1071 amount=-1
kerning first=1041 second=1083 amount=-1
kerning first=1041 second=1091 amount=-2
kerning first=1042 second=1040 amount=-3
kerning first=1042 second=1044 amount=-2
kerning first=1042 second=1046 amount=-2
kerning first=1042 second=1047 amount=-3
kerning first=1042 second=1051 amount=-1
kerning first=1042 second=1054 amount=-3
kerning first=1042 second=1057 amount=-3
kerning first=1042 second=1058 amount=-6
kerning first=1042 second=1059 amount=-3
kerning first=1042 second=1060 amount=-3
kerning first=1042 second=1061 amount=-4
kerning first=1042 second=1063 amount=-4
kerning first=1042 second=1066 amount=-5
kerning first=1042 second=1071 amount=-3
kerning first=1042 second=1076 amount=-1
kerning first=1042 second=1084 amount=-1
kerning first=1042 second=1090 amount=-3
kerning first=1042 second=1091 amount=-1
kerning first=1042 second=1093 amount=-1
kerning first=1042 second=1095 amount=-3
kerning first=1042 second=1103 amount=-1
kerning first=1043 second=44 amount=-11
kerning first=1043 second=46 amount=-11
kerning first=1043 second=1040 amount=-6
kerning first=1043 second=1044 amount=-6
kerning first=1043 second=1047 amount=-2
kerning first=1043 second=1051 amount=-5
kerning first=1043 second=1052 amount=-2
kerning first=1043 second=1054 amount=-5
kerning first=1043 second=1057 amount=-4
kerning first=1043 second=1071 amount=-3
kerning first=1043 second=1072 amount=-5
kerning first=1043 second=1074 amount=-5
kerning first=1043 second=1076 amount=-6
kerning first=1043 second=1077 amount=-6
kerning first=1043 second=1080 amount=-5
kerning first=1043 second=1083 amount=-5
kerning first=1043 second=1084 amount=-5
kerning first=1043 second=1085 amount=-5
kerning first=1043 second=1086 amount=-6
kerning first=1043 second=1088 amount=-5
kerning first=1043 second=1091 amount=-6
kerning first=1043 second=1099 amount=-5
kerning first=1043 second=1100 amount=-5
kerning first=1043 second=1102 amount=-5
kerning first=1043 second=1103 amount=-6
kerning first=1044 second=1059 amount=1
kerning first=1044 second=1060 amount=-2
kerning first=1044 second=1063 amount=-3
kerning first=1044 second=1079 amount=3
kerning first=1044 second=1086 amount=1
kerning first=1044 second=1091 amount=2
kerning first=1045 second=1047 amount=-2
kerning first=1045 second=1089 amount=-1
kerning first=1046 second=1047 amount=-1
kerning first=1046 second=1054 amount=-2
kerning first=1046 second=1057 amount=-1
kerning first=1046 second=1058 amount=1
kerning first=1046 second=1059 amount=2
kerning first=1046 second=1066 amount=2
kerning first=1046 second=1072 amount=1
kerning first=1046 second=1077 amount=-1
kerning first=1046 second=1086 amount=-1
kerning first=1046 second=1091 amount=-1
kerning first=1047 second=1051 amount=-1
kerning first=1047 second=1054 amount=-1
kerning first=1047 second=1057 amount=-1
kerning first=1047 second=1058 amount=-2
kerning first=1047 second=1059 amount=-1
kerning first=1047 second=1060 amount=-1
kerning first=1047 second=1063 amount=-2
kerning first=1047 second=1071 amount=-1
kerning first=1050 second=1047 amount=-1
kerning first=1050 second=1054 amount=-1
kerning first=1050 second=1057 amount=-1
kerning first=1050 second=1059 amount=1
kerning first=1050 second=1060 amount=-3
kerning first=1051 second=1060 amount=-1
kerning first=1051 second=1073 amount=1
kerning first=1051 second=1091 amount=1
kerning first=1052 second=1060 amount=-1
kerning first=1052 second=1063 amount=-1
kerning first=1052 second=1072 amount=1
kerning first=1052 second=1077 amount=1
kerning first=1052 second=1086 amount=1
kerning first=1052 second=1089 amount=1
kerning first=1052 second=1091 amount=1
kerning first=1052 second=1095 amount=-1
kerning first=1052 second=1101 amount=1
kerning first=1054 second=1040 amount=-2
kerning first=1054 second=1044 amount=-2
kerning first=1054 second=1046 amount=-2
kerning first=1054 second=1051 amount=-1
kerning first=1054 second=1059 amount=-2
kerning first=1054 second=1061 amount=-4
kerning first=1054 second=1063 amount=-2
kerning first=1054 second=1071 amount=-2
kerning first=1054 second=1076 amount=-2
kerning first=1054 second=1083 amount=-1
kerning first=1054 second=1093 amount=-1
kerning first=1056 second=44 amount=-17
kerning first=1056 second=46 amount=-17
kerning first=1056 second=58 amount=-2
kerning first=1056 second=59 amount=-2
kerning first=1056 second=1040 amount=-6
kerning first=1056 second=1044 amount=-6
kerning first=1056 second=1046 amount=-1
kerning first=1056 second=1047 amount=-2
kerning first=1056 second=1051 amount=-5
kerning first=1056 second=1052 amount=-1
kerning first=1056 second=1054 amount=-2
kerning first=1056 second=1057 amount=-1
kerning first=1056 second=1058 amount=-4
kerning first=1056 second=1059 amount=-2
kerning first=1056 second=1060 amount=-1
kerning first=1056 second=1061 amount=-4
kerning first=1056 second=1071 amount=-2
kerning first=1056 second=1072 amount=-3
kerning first=1056 second=1076 amount=-7
kerning first=1056 second=1077 amount=-4
kerning first=1056 second=1086 amount=-4
kerning first=1056 second=1101 amount=-2
kerning first=1056 second=1103 amount=-3
kerning first=1057 second=1040 amount=-2
kerning first=1057 second=1044 amount=-2
kerning first=1057 second=1047 amount=-1
kerning first=1057 second=1051 amount=-3
kerning first=1057 second=1052 amount=-1
kerning first=1057 second=1054 amount=-2
kerning first=1057 second=1058 amount=-3
kerning first=1057 second=1059 amount=-3
kerning first=1057 second=1061 amount=-5
kerning first=1057 second=1063 amount=-3
kerning first=1057 second=1066 amount=-3
kerning first=1057 second=1069 amount=-1
kerning first=1057 second=1072 amount=1
kerning first=1057 second=1078 amount=2
kerning first=1057 second=1095 amount=-1
kerning first=1058 second=44 amount=-10
kerning first=1058 second=46 amount=-10
kerning first=1058 second=1040 amount=-3
kerning first=1058 second=1044 amount=-3
kerning first=1058 second=1046 amount=1
kerning first=1058 second=1047 amount=-1
kerning first=1058 second=1051 amount=-2
kerning first=1058 second=1054 amount=-4
kerning first=1058 second=1060 amount=-3
kerning first=1058 second=1071 amount=-2
kerning first=1058 second=1072 amount=-4
kerning first=1058 second=1074 amount=-4
kerning first=1058 second=1077 amount=-5
kerning first=1058 second=1080 amount=-4
kerning first=1058 second=1082 amount=-4
kerning first=1058 second=1083 amount=-4
kerning first=1058 second=1084 amount=-4
kerning first=1058 second=1086 amount=-7
kerning first=1058 second=1087 amount=-4
kerning first=1058 second=1088 amount=-5
kerning first=1058 second=1089 amount=-5
kerning first=1058 second=1091 amount=-5
kerning first=1058 second=1093 amount=-4
kerning first=1058 second=1097 amount=-4
kerning first=1058 second=1099 amount=-4
kerning first=1058 second=1100 amount=-4
kerning first=1058 second=1102 amount=-4
kerning first=1058 second=1103 amount=-5
kerning first=1059 second=44 amount=-12
kerning first=1059 second=46 amount=-12
kerning first=1059 second=58 amount=-2
kerning first=1059 second=59 amount=-2
kerning first=1059 second=1040 amount=-6
kerning first=1059 second=1044 amount=-4
kerning first=1059 second=1047 amount=-2
kerning first=1059 second=1051 amount=-3
kerning first=1059 second=1054 amount=-3
kerning first=1059 second=1060 amount=-3
kerning first=1059 second=1069 amount=-2
kerning first=1059 second=1071 amount=-2
kerning first=1059 second=1073 amount=-2
kerning first=1059 second=1074 amount=-5
kerning first=1059 second=1075 amount=-4
kerning first=1059 second=1076 amount=-7
kerning first=1059 second=1077 amount=-6
kerning first=1059 second=1078 amount=-3
kerning first=1059 second=1079 amount=-5
kerning first=1059 second=1080 amount=-4
kerning first=1059 second=1081 amount=-3
kerning first=1059 second=1082 amount=-4
kerning first=1059 second=1083 amount=-6
kerning first=1059 second=1084 amount=-4
kerning first=1059 second=1085 amount=-4
kerning first=1059 second=1086 amount=-6
kerning first=1059 second=1087 amount=-4
kerning first=1059 second=1088 amount=-4
kerning first=1059 second=1089 amount=-6
kerning first=1059 second=1093 amount=-4
kerning first=1059 second=1094 amount=-4
kerning first=1059 second=1096 amount=-4
kerning first=1059 second=1097 amount=-4
kerning first=1059 second=1102 amount=-4
kerning first=1059 second=1103 amount=-6
kerning first=1060 second=1040 amount=-2
kerning first=1060 second=1044 amount=-3
kerning first=1060 second=1051 amount=-3
kerning first=1060 second=1058 amount=-5
kerning first=1060 second=1059 amount=-4
kerning first=1060 second=1063 amount=-2
kerning first=1060 second=1071 amount=-3
kerning first=1060 second=1083 amount=-3
kerning first=1061 second=1047 amount=-2
kerning first=1061 second=1054 amount=-3
kerning first=1061 second=1057 amount=-3
kerning first=1061 second=1060 amount=-3
kerning first=1061 second=1069 amount=-3
kerning first=1061 second=1086 amount=-1
kerning first=1061 second=1091 amount=-2
kerning first=1062 second=1054 amount=-2
kerning first=1062 second=1072 amount=2
kerning first=1065 second=1072 amount=1
kerning first=1065 second=1091 amount=2
kerning first=1066 second=1071 amount=-3
kerning first=1068 second=1040 amount=-2
kerning first=1068 second=1044 amount=-2
kerning first=1068 second=1046 amount=-3
kerning first=1068 second=1047 amount=-1
kerning first=1068 second=1051 amount=-3
kerning first=1068 second=1052 amount=-2
kerning first=1068 second=1054 amount=-2
kerning first=1068 second=1057 amount=-2
kerning first=1068 second=1058 amount=-9
kerning first=1068 second=1061 amount=-4
kerning first=1068 second=1063 amount=-7
kerning first=1068 second=1069 amount=-1
kerning first=1068 second=1071 amount=-4
kerning first=1069 second=1044 amount=-3
kerning first=1069 second=1046 amount=-1
kerning first=1069 second=1047 amount=-1
kerning first=1069 second=1051 amount=-3
kerning first=1069 second=1061 amount=-3
kerning first=1069 second=1071 amount=-2
kerning first=1069 second=1076 amount=-3
kerning first=1069 second=1078 amount=1
kerning first=1069 second=1083 amount=-3
kerning first=1069 second=1084 amount=-1
kerning first=1069 second=1103 amount=-1
kerning first=1070 second=1040 amount=-3
kerning first=1070 second=1044 amount=-4
kerning first=1070 second=1046 amount=-2
kerning first=1070 second=1051 amount=-4
kerning first=1070 second=1054 amount=-1
kerning first=1070 second=1057 amount=-1
kerning first=1070 second=1058 amount=-5
kerning first=1070 second=1061 amount=-4
kerning first=1070 second=1063 amount=-3
kerning first=1070 second=1076 amount=-4
kerning first=1070 second=1083 amount=-4
kerning first=1070 second=1084 amount=-1
kerning first=1072 second=1079 amount=-1
kerning first=1072 second=1090 amount=-2
kerning first=1072 second=1091 amount=-1
kerning first=1072 second=1095 amount=-2
kerning first=1073 second=1072 amount=-2
kerning first=1073 second=1076 amount=-4
kerning first=1073 second=1077 amount=-1
kerning first=1073 second=1078 amount=-1
kerning first=1073 second=1079 amount=-2
kerning first=1073 second=1083 amount=-4
kerning first=1073 second=1084 amount=-2
kerning first=1073 second=1089 amount=-1
kerning first=1073 second=1091 amount=-2
kerning first=1073 second=1092 amount=-1
kerning first=1073 second=1093 amount=-3
kerning first=1073 second=1095 amount=-3
kerning first=1073 second=1098 amount=-3
kerning first=1073 second=1101 amount=-1
kerning first=1073 second=1103 amount=-2
kerning first=1074 second=1072 amount=-1
kerning first=1074 second=1073 amount=-1
kerning first=1074 second=1076 amount=-1
kerning first=1074 second=1077 amount=-1
kerning first=1074 second=1078 amount=-1
kerning first=1074 second=1079 amount=-1
kerning first=1074 second=1083 amount=-2
kerning first=1074 second=1084 amount=-1
kerning first=1074 second=1086 amount=-1
kerning first=1074 second=1089 amount=-1
kerning first=1074 second=1090 amount=-2
kerning first=1074 second=1091 amount=-2
kerning first=1074 second=1092 amount=-1
kerning first=1074 second=1095 amount=-4
kerning first=1074 second=1098 amount=-3
kerning first=1074 second=1103 amount=-1
kerning first=1075 second=44 amount=-11
kerning first=1075 second=46 amount=-11
kerning first=1075 second=1072 amount=-2
kerning first=1075 second=1076 amount=-4
kerning first=1075 second=1077 amount=-2
kerning first=1075 second=1079 amount=-1
kerning first=1075 second=1083 amount=-2
kerning first=1075 second=1086 amount=-2
kerning first=1075 second=1089 amount=-2
kerning first=1075 second=1103 amount=-1
kerning first=1076 second=1098 amount=-2
kerning first=1076 second=1101 amount=1
kerning first=1077 second=1073 amount=-1
kerning first=1077 second=1076 amount=-2
kerning first=1077 second=1078 amount=-1
kerning first=1077 second=1079 amount=-2
kerning first=1077 second=1083 amount=-3
kerning first=1077 second=1090 amount=-3
kerning first=1077 second=1091 amount=-1
kerning first=1077 second=1093 amount=-2
kerning first=1077 second=1095 amount=-3
kerning first=1078 second=1073 amount=1
kerning first=1078 second=1091 amount=1
kerning first=1078 second=1095 amount=-1
kerning first=1078 second=1098 amount=2
kerning first=1079 second=1073 amount=-1
kerning first=1079 second=1076 amount=-2
kerning first=1079 second=1077 amount=-1
kerning first=1079 second=1079 amount=-1
kerning first=1079 second=1083 amount=-1
kerning first=1079 second=1086 amount=-1
kerning first=1079 second=1089 amount=-1
kerning first=1079 second=1091 amount=-1
kerning first=1079 second=1092 amount=-1
kerning first=1079 second=1095 amount=-3
kerning first=1079 second=1098 amount=-2
kerning first=1082 second=1072 amount=2
kerning first=1082 second=1073 amount=2
kerning first=1082 second=1077 amount=1
kerning first=1082 second=1079 amount=1
kerning first=1082 second=1083 amount=1
kerning first=1082 second=1086 amount=1
kerning first=1082 second=1089 amount=1
kerning first=1082 second=1090 amount=1
kerning first=1082 second=1091 amount=1
kerning first=1082 second=1101 amount=1
kerning first=1083 second=1086 amount=1
kerning first=1083 second=1095 amount=-2
kerning first=1084 second=1073 amount=-1
kerning first=1084 second=1079 amount=-1
kerning first=1084 second=1091 amount=1
kerning first=1086 second=1076 amount=-2
kerning first=1086 second=1078 amount=-1
kerning first=1086 second=1079 amount=-1
kerning first=1086 second=1083 amount=-2
kerning first=1086 second=1090 amount=-2
kerning first=1086 second=1091 amount=-1
kerning first=1086 second=1093 amount=-1
kerning first=1086 second=1095 amount=-2
kerning first=1088 second=1076 amount=-2
kerning first=1088 second=1079 amount=-1
kerning first=1088 second=1083 amount=-3
kerning first=1088 second=1090 amount=-2
kerning first=1088 second=1091 amount=-1
kerning first=1088 second=1093 amount=-1
kerning first=1088 second=1095 amount=-2
kerning first=1088 second=1103 amount=-1
kerning first=1089 second=1078 amount=1
kerning first=1089 second=1086 amount=1
kerning first=1089 second=1095 amount=-1
kerning first=1089 second=1101 amount=1
kerning first=1090 second=44 amount=-10
kerning first=1090 second=46 amount=-10
kerning first=1090 second=1072 amount=-1
kerning first=1090 second=1076 amount=-3
kerning first=1090 second=1077 amount=-1
kerning first=1090 second=1078 amount=3
kerning first=1090 second=1083 amount=-2
kerning first=1090 second=1086 amount=-1
kerning first=1090 second=1089 amount=-1
kerning first=1090 second=1091 amount=1
kerning first=1091 second=44 amount=-9
kerning first=1091 second=46 amount=-9
kerning first=1091 second=1072 amount=-1
kerning first=1091 second=1073 amount=1
kerning first=1091 second=1076 amount=-3
kerning first=1091 second=1077 amount=-1
kerning first=1091 second=1078 amount=1
kerning first=1091 second=1083 amount=-2
kerning first=1091 second=1084 amount=-1
kerning first=1091 second=1086 amount=-1
kerning first=1091 second=1088 amount=-1
kerning first=1091 second=1089 amount=-1
kerning first=1091 second=1092 amount=-1
kerning first=1091 second=1101 amount=-1
kerning first=1091 second=1103 amount=-1
kerning first=1092 second=1073 amount=-1
kerning first=1092 second=1076 amount=-2
kerning first=1092 second=1083 amount=-2
kerning first=1092 second=1090 amount=-2
kerning first=1092 second=1091 amount=-1
kerning first=1092 second=1095 amount=-2
kerning first=1092 second=1103 amount=-1
kerning first=1093 second=1072 amount=-1
kerning first=1093 second=1073 amount=-1
kerning first=1093 second=1077 amount=-1
kerning first=1093 second=1079 amount=-1
kerning first=1093 second=1086 amount=-1
kerning first=1093 second=1089 amount=-1
kerning first=1093 second=1090 amount=-1
kerning first=1093 second=1092 amount=-1
kerning first=1093 second=1095 amount=-2
kerning first=1094 second=1077 amount=-1
kerning first=1094 second=1079 amount=-1
kerning first=1094 second=1086 amount=-1
kerning first=1094 second=1089 amount=-1
kerning first=1097 second=1077 amount=-1
kerning first=1097 second=1086 amount=-1
kerning first=1097 second=1091 amount=1
kerning first=1100 second=1090 amount=-7
kerning first=1100 second=1095 amount=-6
kerning first=1101 second=1076 amount=-2
kerning first=1101 second=1077 amount=1
kerning first=1101 second=1079 amount=-1
kerning first=1101 second=1083 amount=-2
kerning first=1101 second=1086 amount=1
kerning first=1101 second=1090 amount=-2
kerning first=1101 second=1093 amount=-1
kerning first=1101 second=1103 amount=-1
kerning first=1102 second=1076 amount=-2
kerning first=1102 second=1078 amount=-1
kerning first=1102 second=1083 amount=-2
kerning first=1102 second=1084 amount=-1
kerning first=1102 second=1090 amount=-2
kerning first=1102 second=1093 amount=-1
kerning first=1102 second=1095 amount=-2

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ca1ca296c9b96cfccc469e1fa19f83019b95c77c564119db697595f418820440
size 89901

View File

@@ -0,0 +1,14 @@
{
"passes" : [{
"shader" : "font_bm_shader.json",
"state_block" : {
"blending_state" : {
"src_factor" : "one",
"dst_factor" : "one_minus_src_alpha"
},
"capabilities_state" : {
"blending" : true
}
}
}]
}

View File

@@ -0,0 +1,26 @@
uniform sampler2D u_texture;
uniform float u_glyph_dilate;
uniform float u_outline_width;
uniform vec4 u_outline_color;
varying vec2 v_st0;
varying vec4 v_color0;
void main() {
vec4 t = texture2D(u_texture, v_st0);
float glyph_alpha = t.a;
float outline_alpha = t.r;
vec4 glyph_color = vec4(v_color0.rgb * v_color0.a, v_color0.a);
vec4 outline_color = vec4(u_outline_color.rgb * u_outline_color.a, u_outline_color.a);
vec2 layers_mask = vec2(
step(0.0001, v_color0.a),
step(0.0001, u_outline_color.a * u_outline_width));
gl_FragColor =
layers_mask.x * glyph_alpha * glyph_color +
layers_mask.y * outline_alpha * outline_color * (1.0 - glyph_alpha);
}

View File

@@ -0,0 +1,4 @@
{
"vertex" : "font_bm_shader.vert",
"fragment" : "font_bm_shader.frag"
}

View File

@@ -0,0 +1,39 @@
uniform vec2 u_screen_s;
uniform mat4 u_matrix_m;
uniform mat4 u_matrix_vp;
attribute vec3 a_vertex;
attribute vec2 a_st0;
attribute vec4 a_color0;
varying vec2 v_st0;
varying vec4 v_color0;
#define VERTEX_SNAPPING_ON
vec2 round(vec2 v) {
return vec2(
floor(v.x + 0.5),
floor(v.y + 0.5));
}
vec4 pixel_snap(vec4 pos) {
vec2 hpc = u_screen_s * 0.5;
vec2 pixel_pos = round((pos.xy / pos.w) * hpc);
pos.xy = pixel_pos / hpc * pos.w;
return pos;
}
vec4 vertex_to_homo(vec3 pos) {
return vec4(pos, 1.0) * u_matrix_m * u_matrix_vp;
}
void main() {
v_st0 = vec2(a_st0.s, 1.0 - a_st0.t);
v_color0 = a_color0;
#ifndef VERTEX_SNAPPING_ON
gl_Position = vertex_to_homo(a_vertex);
#else
gl_Position = pixel_snap(vertex_to_homo(a_vertex));
#endif
}

View File

@@ -0,0 +1,14 @@
{
"passes" : [{
"shader" : "font_sdf_shader.json",
"state_block" : {
"blending_state" : {
"src_factor" : "one",
"dst_factor" : "one_minus_src_alpha"
},
"capabilities_state" : {
"blending" : true
}
}
}]
}

View File

@@ -0,0 +1,34 @@
#ifdef GL_OES_standard_derivatives
# extension GL_OES_standard_derivatives : require
#endif
uniform sampler2D u_texture;
uniform float u_glyph_dilate;
uniform float u_outline_width;
uniform vec4 u_outline_color;
varying vec2 v_st0;
varying vec4 v_color0;
void main() {
float distance = texture2D(u_texture, v_st0).a;
float width = fwidth(distance);
float glyph_center = 0.5 - u_glyph_dilate * 0.5;
float outline_center = glyph_center - u_outline_width * 0.5;
float glyph_alpha = smoothstep(glyph_center - width, glyph_center + width, distance);
float outline_alpha = smoothstep(outline_center - width, outline_center + width, distance);
vec4 glyph_color = vec4(v_color0.rgb * v_color0.a, v_color0.a);
vec4 outline_color = vec4(u_outline_color.rgb * u_outline_color.a, u_outline_color.a);
vec2 layers_mask = vec2(
step(0.0001, v_color0.a),
step(0.0001, u_outline_color.a * u_outline_width));
gl_FragColor =
layers_mask.x * glyph_alpha * glyph_color +
layers_mask.y * outline_alpha * outline_color * (1.0 - glyph_alpha);
}

View File

@@ -0,0 +1,4 @@
{
"vertex" : "font_sdf_shader.vert",
"fragment" : "font_sdf_shader.frag"
}

View File

@@ -0,0 +1,39 @@
uniform vec2 u_screen_s;
uniform mat4 u_matrix_m;
uniform mat4 u_matrix_vp;
attribute vec3 a_vertex;
attribute vec2 a_st0;
attribute vec4 a_color0;
varying vec2 v_st0;
varying vec4 v_color0;
#define VERTEX_SNAPPING_ON
vec2 round(vec2 v) {
return vec2(
floor(v.x + 0.5),
floor(v.y + 0.5));
}
vec4 pixel_snap(vec4 pos) {
vec2 hpc = u_screen_s * 0.5;
vec2 pixel_pos = round((pos.xy / pos.w) * hpc);
pos.xy = pixel_pos / hpc * pos.w;
return pos;
}
vec4 vertex_to_homo(vec3 pos) {
return vec4(pos, 1.0) * u_matrix_m * u_matrix_vp;
}
void main() {
v_st0 = vec2(a_st0.s, 1.0 - a_st0.t);
v_color0 = a_color0;
#ifndef VERTEX_SNAPPING_ON
gl_Position = vertex_to_homo(a_vertex);
#else
gl_Position = pixel_snap(vertex_to_homo(a_vertex));
#endif
}

View File

@@ -0,0 +1,15 @@
{
"components" : {
"renderer" : {
"materials" : [
"font_bm_material.json"
]
},
"model_renderer" : {},
"label" : {
"font" : "arial_bm.fnt",
"text" : "Hello World!"
},
"label.dirty" : {}
}
}

View File

@@ -0,0 +1,15 @@
{
"components" : {
"renderer" : {
"materials" : [
"font_sdf_material.json"
]
},
"model_renderer" : {},
"label" : {
"font" : "arial_sdf.fnt",
"text" : "Hello World!"
},
"label.dirty" : {}
}
}

View File

@@ -3,6 +3,5 @@ uniform sampler2D u_texture;
varying vec2 v_st0;
void main() {
vec2 st = vec2(v_st0.s, 1.0 - v_st0.t);
gl_FragColor = texture2D(u_texture, st);
gl_FragColor = texture2D(u_texture, v_st0);
}

View File

@@ -6,7 +6,11 @@ attribute vec2 a_st0;
varying vec2 v_st0;
void main() {
v_st0 = a_st0;
gl_Position = vec4(a_vertex, 1.0) * u_matrix_m * u_matrix_vp;
vec4 vertex_to_homo(vec3 pos) {
return vec4(pos, 1.0) * u_matrix_m * u_matrix_vp;
}
void main() {
v_st0 = vec2(a_st0.s, 1.0 - a_st0.t);
gl_Position = vertex_to_homo(a_vertex);
}

View File

@@ -8,7 +8,7 @@
"prototype" : "gnome_prefab.json",
"components" : {
"actor" : {
"translation" : [0,50,0],
"translation" : [0,0,0],
"scale" : 20
}
}
@@ -22,9 +22,40 @@
}, {
"prototype" : "ship_prefab.json",
"components" : {
"sprite_renderer" : {
"tint" : [255,0,0,255]
},
"actor" : {
"translation" : [50,-50,0]
}
}
}, {
"prototype" : "label_bm_prefab.json",
"components" : {
"label" : {
"text" : "bm font",
"valign" : "center",
"outline_width" : 0.5,
"outline_color" : [0,0,0,255]
},
"actor" : {
"translation" : [0,180,0],
"scale" : 3
}
}
}, {
"prototype" : "label_sdf_prefab.json",
"components" : {
"label" : {
"text" : "sdf font",
"valign" : "center",
"outline_width" : 0.5,
"outline_color" : [0,0,0,255]
},
"actor" : {
"translation" : [0.5,-180.5,0],
"scale" : 3
}
}
}]
}

View File

@@ -3,7 +3,7 @@
"shader" : "sprite_shader.json",
"state_block" : {
"blending_state" : {
"src_factor" : "src_alpha",
"src_factor" : "one",
"dst_factor" : "one_minus_src_alpha"
},
"capabilities_state" : {

View File

@@ -1,9 +1,10 @@
uniform sampler2D u_texture;
varying vec4 v_tint;
varying vec2 v_st;
varying vec2 v_st0;
varying vec4 v_color0;
void main() {
vec2 st = vec2(v_st.s, 1.0 - v_st.t);
gl_FragColor = texture2D(u_texture, st) * v_tint;
vec4 c = texture2D(u_texture, v_st0) * v_color0;
c.rgb *= c.a;
gl_FragColor = c;
}

View File

@@ -1,14 +1,36 @@
uniform vec2 u_screen_s;
uniform mat4 u_matrix_vp;
attribute vec3 a_vertex;
attribute vec4 a_tint;
attribute vec2 a_st;
attribute vec2 a_st0;
attribute vec4 a_color0;
varying vec4 v_tint;
varying vec2 v_st;
varying vec2 v_st0;
varying vec4 v_color0;
vec2 round(vec2 v) {
return vec2(
floor(v.x + 0.5),
floor(v.y + 0.5));
}
vec4 pixel_snap(vec4 pos) {
vec2 hpc = u_screen_s * 0.5;
vec2 pixel_pos = round((pos.xy / pos.w) * hpc);
pos.xy = pixel_pos / hpc * pos.w;
return pos;
}
vec4 vertex_to_homo(vec3 pos) {
return vec4(pos, 1.0) * u_matrix_vp;
}
void main() {
v_st = a_st;
v_tint = a_tint;
gl_Position = vec4(a_vertex, 1.0) * u_matrix_vp;
v_st0 = vec2(a_st0.s, 1.0 - a_st0.t);
v_color0 = a_color0;
#ifndef VERTEX_SNAPPING_ON
gl_Position = vertex_to_homo(a_vertex);
#else
gl_Position = pixel_snap(vertex_to_homo(a_vertex));
#endif
}

View File

@@ -1,3 +1,4 @@
#pragma once
#define MINIZ_EXPORT
#define MINIZ_NO_STDIO

View File

@@ -0,0 +1,63 @@
/*******************************************************************************
* 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 <enduro2d/high/assets/font_asset.hpp>
#include <enduro2d/high/assets/binary_asset.hpp>
#include <enduro2d/high/assets/texture_asset.hpp>
namespace
{
using namespace e2d;
class font_asset_loading_exception final : public asset_loading_exception {
const char* what() const noexcept final {
return "font asset loading exception";
}
};
}
namespace e2d
{
font_asset::load_async_result font_asset::load_async(
const library& library, str_view address)
{
return library.load_asset_async<binary_asset>(address)
.then([](const binary_asset::load_result& font_data){
return the<deferrer>().do_in_worker_thread([font_data](){
font content;
if ( !fonts::try_load_font(content, font_data->content()) ) {
throw font_asset_loading_exception();
}
return content;
});
})
.then([
&library,
parent_address = path::parent_path(address)
](const font& content){
return stdex::make_tuple_promise(std::make_tuple(
stdex::make_resolved_promise(content),
library.load_asset_async<texture_asset>(
path::combine(parent_address, content.info().atlas_file))
));
})
.then([](const std::tuple<
font,
texture_asset::load_result
>& results){
font content = std::get<0>(results);
texture_asset::load_result texture_res = std::get<1>(results);
if ( content.info().atlas_size != texture_res->content()->size() ) {
throw font_asset_loading_exception();
}
nested_content ncontent{{
make_hash(content.info().atlas_file),
std::move(texture_res)}};
return font_asset::create(std::move(content), std::move(ncontent));
});
}
}

View File

@@ -164,7 +164,7 @@ namespace
},
"sampler" : {
"type" : "object",
"required" : [ "name" ],
"required" : [ "name", "texture" ],
"additionalProperties" : false,
"properties" : {
"name" : {
@@ -201,7 +201,7 @@ namespace
},
"property" : {
"type" : "object",
"required" : [ "name", "type" ],
"required" : [ "name", "type", "value" ],
"additionalProperties" : false,
"properties" : {
"name" : { "$ref" : "#/common_definitions/name" },
@@ -514,11 +514,10 @@ namespace
render::sampler_state content;
E2D_ASSERT(root.HasMember("name") && root["name"].IsString());
auto name_hash = make_hash(root["name"].GetString());
E2D_ASSERT(root.HasMember("texture") && root["texture"].IsString());
auto texture_p = root.HasMember("texture")
? parse_texture_block(library, parent_address, root["texture"])
: stdex::make_resolved_promise<texture_ptr>(nullptr);
auto name_hash = make_hash(root["name"].GetString());
auto texture_p = parse_texture_block(library, parent_address, root["texture"]);
if ( root.HasMember("wrap") ) {
const auto& wrap_json = root["wrap"];
@@ -609,15 +608,14 @@ namespace
E2D_ASSERT(property_json.HasMember("name") && property_json["name"].IsString());
E2D_ASSERT(property_json.HasMember("type") && property_json["type"].IsString());
E2D_ASSERT(property_json.HasMember("value"));
#define DEFINE_CASE(x)\
if ( 0 == std::strcmp(property_json["type"].GetString(), #x) ) {\
x value;\
if ( property_json.HasMember("value") ) {\
if ( !json_utils::try_parse_value(property_json["value"], value) ) {\
E2D_ASSERT_MSG(false, "unexpected property value");\
return false;\
}\
if ( !json_utils::try_parse_value(property_json["value"], value) ) {\
E2D_ASSERT_MSG(false, "unexpected property value");\
return false;\
}\
props.property(property_json["name"].GetString(), value);\
continue;\

View File

@@ -0,0 +1,221 @@
/*******************************************************************************
* 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 <enduro2d/high/components/label.hpp>
namespace
{
using namespace e2d;
bool parse_halign(str_view str, label::haligns& align) noexcept {
#define DEFINE_IF(x) if ( str == #x ) { align = label::haligns::x; return true; }
DEFINE_IF(left);
DEFINE_IF(center);
DEFINE_IF(right);
#undef DEFINE_IF
return false;
}
bool parse_valign(str_view str, label::valigns& align) noexcept {
#define DEFINE_IF(x) if ( str == #x ) { align = label::valigns::x; return true; }
DEFINE_IF(top);
DEFINE_IF(center);
DEFINE_IF(bottom);
DEFINE_IF(baseline);
#undef DEFINE_IF
return false;
}
}
namespace e2d
{
const char* factory_loader<label>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {
"text" : { "type" : "string" },
"font" : { "$ref": "#/common_definitions/address" },
"tint" : { "$ref": "#/common_definitions/color" },
"halign" : { "$ref": "#/definitions/haligns" },
"valign" : { "$ref": "#/definitions/valigns" },
"leading" : { "type" : "number" },
"tracking" : { "type" : "number" },
"text_width" : { "type" : "number" },
"glyph_dilate" : { "type" : "number" },
"outline_width" : { "type" : "number" },
"outline_color" : { "$ref": "#/common_definitions/color" }
},
"definitions" : {
"haligns" : {
"type" : "string",
"enum" : [
"left",
"center",
"right"
]
},
"valigns" : {
"type" : "string",
"enum" : [
"top",
"center",
"bottom",
"baseline"
]
}
}
})json";
bool factory_loader<label>::operator()(
label& component,
const fill_context& ctx) const
{
if ( ctx.root.HasMember("text") ) {
str text = component.text();
if ( !json_utils::try_parse_value(ctx.root["text"], text) ) {
the<debug>().error("LABEL: Incorrect formatting of 'text' property");
return false;
}
component.text(std::move(text));
}
if ( ctx.root.HasMember("font") ) {
auto font = ctx.dependencies.find_asset<font_asset>(
path::combine(ctx.parent_address, ctx.root["font"].GetString()));
if ( !font ) {
the<debug>().error("LABEL: Dependency 'font' is not found:\n"
"--> Parent address: %0\n"
"--> Dependency address: %1",
ctx.parent_address,
ctx.root["font"].GetString());
return false;
}
component.font(font);
}
if ( ctx.root.HasMember("tint") ) {
color32 tint = component.tint();
if ( !json_utils::try_parse_value(ctx.root["tint"], tint) ) {
the<debug>().error("LABEL: Incorrect formatting of 'tint' property");
return false;
}
component.tint(tint);
}
if ( ctx.root.HasMember("halign") ) {
label::haligns halign = component.halign();
if ( !parse_halign(ctx.root["halign"].GetString(), halign) ) {
the<debug>().error("LABEL: Incorrect formatting of 'halign' property");
return false;
}
component.haligh(halign);
}
if ( ctx.root.HasMember("valign") ) {
label::valigns valign = component.valign();
if ( !parse_valign(ctx.root["valign"].GetString(), valign) ) {
the<debug>().error("LABEL: Incorrect formatting of 'valign' property");
return false;
}
component.valigh(valign);
}
if ( ctx.root.HasMember("leading") ) {
f32 leading = component.leading();
if ( !json_utils::try_parse_value(ctx.root["leading"], leading) ) {
the<debug>().error("LABEL: Incorrect formatting of 'leading' property");
return false;
}
component.leading(leading);
}
if ( ctx.root.HasMember("tracking") ) {
f32 tracking = component.tracking();
if ( !json_utils::try_parse_value(ctx.root["tracking"], tracking) ) {
the<debug>().error("LABEL: Incorrect formatting of 'tracking' property");
return false;
}
component.tracking(tracking);
}
if ( ctx.root.HasMember("text_width") ) {
f32 text_width = component.text_width();
if ( !json_utils::try_parse_value(ctx.root["text_width"], text_width) ) {
the<debug>().error("LABEL: Incorrect formatting of 'text_width' property");
return false;
}
component.text_width(text_width);
}
if ( ctx.root.HasMember("glyph_dilate") ) {
f32 glyph_dilate = component.glyph_dilate();
if ( !json_utils::try_parse_value(ctx.root["glyph_dilate"], glyph_dilate) ) {
the<debug>().error("LABEL: Incorrect formatting of 'glyph_dilate' property");
return false;
}
component.glyph_dilate(glyph_dilate);
}
if ( ctx.root.HasMember("outline_width") ) {
f32 outline_width = component.outline_width();
if ( !json_utils::try_parse_value(ctx.root["outline_width"], outline_width) ) {
the<debug>().error("LABEL: Incorrect formatting of 'outline_width' property");
return false;
}
component.outline_width(outline_width);
}
if ( ctx.root.HasMember("outline_color") ) {
color32 outline_color = component.outline_color();
if ( !json_utils::try_parse_value(ctx.root["outline_color"], outline_color) ) {
the<debug>().error("LABEL: Incorrect formatting of 'outline_color' property");
return false;
}
component.outline_color(outline_color);
}
return true;
}
bool factory_loader<label>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
if ( ctx.root.HasMember("font") ) {
dependencies.add_dependency<font_asset>(
path::combine(ctx.parent_address, ctx.root["font"].GetString()));
}
return true;
}
}
namespace e2d
{
const char* factory_loader<label::dirty>::schema_source = R"json({
"type" : "object",
"required" : [],
"additionalProperties" : false,
"properties" : {}
})json";
bool factory_loader<label::dirty>::operator()(
label::dirty& component,
const fill_context& ctx) const
{
E2D_UNUSED(component, ctx);
return true;
}
bool factory_loader<label::dirty>::operator()(
asset_dependencies& dependencies,
const collect_context& ctx) const
{
E2D_UNUSED(dependencies, ctx);
return true;
}
}

View File

@@ -14,12 +14,14 @@
#include <enduro2d/high/components/camera.hpp>
#include <enduro2d/high/components/flipbook_player.hpp>
#include <enduro2d/high/components/flipbook_source.hpp>
#include <enduro2d/high/components/label.hpp>
#include <enduro2d/high/components/model_renderer.hpp>
#include <enduro2d/high/components/renderer.hpp>
#include <enduro2d/high/components/scene.hpp>
#include <enduro2d/high/components/sprite_renderer.hpp>
#include <enduro2d/high/systems/flipbook_system.hpp>
#include <enduro2d/high/systems/label_system.hpp>
#include <enduro2d/high/systems/render_system.hpp>
namespace
@@ -41,6 +43,7 @@ namespace
bool initialize() final {
ecs::registry_filler(the<world>().registry())
.system<flipbook_system>(world::priority_update)
.system<label_system>(world::priority_update)
.system<render_system>(world::priority_render);
return !application_ || application_->initialize();
}
@@ -130,6 +133,8 @@ namespace e2d
.register_component<camera>("camera")
.register_component<flipbook_player>("flipbook_player")
.register_component<flipbook_source>("flipbook_source")
.register_component<label>("label")
.register_component<label::dirty>("label.dirty")
.register_component<model_renderer>("model_renderer")
.register_component<renderer>("renderer")
.register_component<scene>("scene")

View File

@@ -0,0 +1,386 @@
/*******************************************************************************
* 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 <enduro2d/high/systems/label_system.hpp>
#include <enduro2d/high/assets/font_asset.hpp>
#include <enduro2d/high/assets/texture_asset.hpp>
#include <enduro2d/high/components/label.hpp>
#include <enduro2d/high/components/renderer.hpp>
#include <enduro2d/high/components/model_renderer.hpp>
namespace
{
using namespace e2d;
class geometry_builder {
public:
geometry_builder() = default;
void add_quad(
const b2f& rect,
const b2f& texrect,
const color32& color)
{
const std::size_t start_vertex = vertices_.size();
// Y
// ^
// | 3 - 2
// | | / |
// | 0 - 1
// +------> X
{
const v2f& gp = rect.position;
const v2f& gs = rect.size;
vertices_.emplace_back(gp.x + 0.0f, gp.y + 0.0f, 0.f);
vertices_.emplace_back(gp.x + gs.x, gp.y + 0.0f, 0.f);
vertices_.emplace_back(gp.x + gs.x, gp.y + gs.y, 0.f);
vertices_.emplace_back(gp.x + 0.0f, gp.y + gs.y, 0.f);
}
{
const v2f& tp = texrect.position;
const v2f& ts = texrect.size;
uvs_.emplace_back(tp.x + 0.0f, tp.y + 0.0f);
uvs_.emplace_back(tp.x + ts.x, tp.y + 0.0f);
uvs_.emplace_back(tp.x + ts.x, tp.y + ts.y);
uvs_.emplace_back(tp.x + 0.0f, tp.y + ts.y);
}
{
indices_.emplace_back(start_vertex + 0u);
indices_.emplace_back(start_vertex + 1u);
indices_.emplace_back(start_vertex + 2u);
indices_.emplace_back(start_vertex + 2u);
indices_.emplace_back(start_vertex + 3u);
indices_.emplace_back(start_vertex + 0u);
}
{
colors_.emplace_back(color);
colors_.emplace_back(color);
colors_.emplace_back(color);
colors_.emplace_back(color);
}
}
void update_model(model_renderer& mr) {
mesh new_mesh;
new_mesh.set_vertices(vertices_);
new_mesh.set_indices(0, indices_);
new_mesh.set_uvs(0, uvs_);
new_mesh.set_colors(0, colors_);
model new_model;
new_model.set_mesh(mesh_asset::create(std::move(new_mesh)));
new_model.regenerate_geometry(the<render>());
if ( mr.model() ) {
mr.model()->fill(std::move(new_model));
} else {
mr.model(model_asset::create(std::move(new_model)));
}
}
void clear() noexcept {
vertices_.clear();
uvs_.clear();
indices_.clear();
colors_.clear();
}
private:
vector<v3f> vertices_;
vector<v2f> uvs_;
vector<u32> indices_;
vector<color32> colors_;
};
}
namespace
{
using namespace e2d;
f32 calculate_halign_offset(
label::haligns halign,
f32 string_width) noexcept
{
switch ( halign ) {
case label::haligns::left:
return 0.0f;
case label::haligns::center:
return -0.5f * string_width;
case label::haligns::right:
return -1.0f * string_width;
default:
E2D_ASSERT_MSG(false, "unexpected label halign");
return 0.f;
}
}
f32 calculate_valign_offset(
label::valigns valign,
f32 leading,
u32 glyph_ascent,
u32 line_height,
std::size_t string_count) noexcept
{
const f32 label_height = string_count > 1u
? line_height + line_height * leading * (string_count - 1u)
: line_height;
switch ( valign ) {
case label::valigns::top:
return 0.f;
case label::valigns::center:
return 0.5f * label_height;
case label::valigns::bottom:
return 1.0f * label_height;
case label::valigns::baseline:
return 1.0f * glyph_ascent;
default:
E2D_ASSERT_MSG(false, "unexpected label valign");
return 0.f;
}
}
std::size_t calculate_string_count(str32_view text) noexcept {
std::size_t count{0u};
for ( std::size_t i = 0; i < text.size(); ++i ) {
if ( text[i] == '\n' ) {
++count;
}
}
return count;
}
}
namespace
{
using namespace e2d;
void update_label_material(const label& l, renderer& r) {
auto texture_res = l.font() && !l.font()->content().empty()
? l.font()->find_nested_asset<texture_asset>(l.font()->content().info().atlas_file)
: nullptr;
auto texture = texture_res
? texture_res->content()
: nullptr;
const f32 glyph_dilate = math::clamp(l.glyph_dilate(), -1.f, 1.0f);
const f32 outline_width = math::clamp(l.outline_width(), 0.f, 1.f - glyph_dilate);
const v4f outline_color = make_vec4(color(l.outline_color()));
r.properties(render::property_block()
.sampler("u_texture", render::sampler_state()
.texture(texture)
.min_filter(render::sampler_min_filter::linear)
.mag_filter(render::sampler_mag_filter::linear))
.property("u_glyph_dilate", glyph_dilate)
.property("u_outline_width", outline_width)
.property("u_outline_color", outline_color));
}
void update_label_geometry(const label& l, model_renderer& mr, geometry_builder& gb) {
if ( !l.font() || l.font()->content().empty() || l.text().empty() ) {
gb.update_model(mr);
return;
}
const font& f = l.font()->content();
const str32& text = make_utf32(l.text());
//
// update glyphs
//
struct glyph_desc {
const font::glyph_info* glyph{nullptr};
f32 kerning{0.f};
};
vector<glyph_desc> glyphs;
glyphs.reserve(text.size());
for ( std::size_t i = 0, e = text.size(); i < e; ++i ) {
glyph_desc desc;
desc.glyph = f.find_glyph(text[i]);
desc.kerning = i > 0
? f.get_kerning(text[i-1], text[i])
: 0.f;
glyphs.push_back(std::move(desc));
if ( !desc.glyph && text[i] != '\n' ) {
the<debug>().warning("LABEL: Missing font glyph:\n"
"--> Code Point: %0",
text[i]);
}
}
f32 tracking_width = 0.f;
if ( const font::glyph_info* sp = f.find_glyph(' '); sp ) {
tracking_width = sp->advance * l.tracking();
}
//
// update strings
//
struct string_desc {
f32 width{0.f};
std::size_t start{0};
std::size_t length{0};
string_desc(std::size_t start)
: start(start) {}
};
vector<string_desc> strings;
strings.reserve(calculate_string_count(text));
f32 last_space_width = 0.f;
std::size_t last_space_index = std::size_t(-1);
strings.push_back(string_desc(0u));
for ( std::size_t i = 0, e = text.size(); i < e; ++i ) {
const u32 code_point = text[i];
const glyph_desc& glyph = glyphs[i];
if ( code_point == ' ' ) {
last_space_width = strings.back().width;
last_space_index = i;
}
bool new_line = false;
if ( code_point == '\n' ) {
new_line = true;
strings.back().length = i - strings.back().start;
} else if ( glyph.glyph ) {
strings.back().width +=
glyph.kerning +
glyph.glyph->advance +
tracking_width;
const bool break_line =
l.text_width() > 0.f &&
last_space_index != std::size_t(-1) &&
strings.back().width > l.text_width();
if ( break_line ) {
new_line = true;
strings.back().width = last_space_width;
strings.back().length = last_space_index - strings.back().start;
i = last_space_index;
}
}
if ( i == e - 1 ) {
new_line = true;
strings.back().length = i + 1 - strings.back().start;
}
if ( new_line ) {
if ( i < e - 1 ) {
strings.push_back(string_desc(i + 1u));
}
last_space_width = 0.f;
last_space_index = std::size_t(-1);
}
}
//
// update geometry
//
v2f cursor = v2f::unit_y() * calculate_valign_offset(
l.valign(),
l.leading(),
f.info().glyph_ascent,
f.info().line_height,
strings.size());
for ( std::size_t i = 0, ie = strings.size(); i < ie; ++i ) {
cursor.x = calculate_halign_offset(l.halign(), strings[i].width);
for ( std::size_t j = strings[i].start, je = strings[i].start + strings[i].length; j < je; ++j ) {
const glyph_desc& glyph = glyphs[j];
if ( !glyph.glyph ) {
continue;
}
cursor.x += glyph.kerning;
b2f rect = make_rect(cursor, glyph.glyph->tex_rect.size.cast_to<f32>());
rect.position += glyph.glyph->offset.cast_to<f32>();
b2f texrect = glyph.glyph->tex_rect.cast_to<f32>();
texrect.position /= f.info().atlas_size.cast_to<f32>();
texrect.size /= f.info().atlas_size.cast_to<f32>();
gb.add_quad(rect, texrect, l.tint());
cursor.x += glyph.glyph->advance + tracking_width;
}
cursor.y -= f.info().line_height * l.leading();
}
//
// update model
//
gb.update_model(mr);
}
void update_dirty_labels(ecs::registry& owner) {
geometry_builder gb;
owner.for_joined_components<label::dirty, label, renderer, model_renderer>([&gb](
const ecs::const_entity&,
const label::dirty&,
const label& l,
renderer& r,
model_renderer& mr
){
update_label_material(l, r);
update_label_geometry(l, mr, gb);
gb.clear();
});
owner.remove_all_components<label::dirty>();
}
}
namespace e2d
{
//
// label_system::internal_state
//
class label_system::internal_state final : private noncopyable {
public:
internal_state() = default;
~internal_state() noexcept = default;
void process(ecs::registry& owner) {
update_dirty_labels(owner);
}
};
//
// label_system
//
label_system::label_system()
: state_(new internal_state()) {}
label_system::~label_system() noexcept = default;
void label_system::process(ecs::registry& owner) {
state_->process(owner);
}
}

View File

@@ -99,7 +99,7 @@ namespace e2d
class render_system::internal_state final : private noncopyable {
public:
internal_state()
: drawer_(the<engine>(), the<debug>(), the<render>()) {}
: drawer_(the<engine>(), the<debug>(), the<render>(), the<window>()) {}
~internal_state() noexcept = default;
void process(ecs::registry& owner) {

View File

@@ -40,8 +40,8 @@ namespace e2d::render_system_impl
static vertex_declaration decl() noexcept {
return vertex_declaration()
.add_attribute<v3f>("a_vertex")
.add_attribute<v2f>("a_st")
.add_attribute<color32>("a_tint").normalized();
.add_attribute<v2f>("a_st0")
.add_attribute<color32>("a_color0").normalized();
}
};
}

View File

@@ -14,6 +14,7 @@ namespace
{
using namespace e2d;
const str_hash screen_s_property_hash = "u_screen_s";
const str_hash matrix_v_property_hash = "u_matrix_v";
const str_hash matrix_p_property_hash = "u_matrix_p";
const str_hash matrix_vp_property_hash = "u_matrix_vp";
@@ -32,6 +33,7 @@ namespace e2d::render_system_impl
const const_node_iptr& cam_n,
engine& engine,
render& render,
window& window,
batcher_type& batcher)
: render_(render)
, batcher_(batcher)
@@ -47,6 +49,9 @@ namespace e2d::render_system_impl
const m4f& m_p = cam.projection();
batcher_.flush()
.property(screen_s_property_hash, cam.target()
? cam.target()->size().cast_to<f32>()
: window.framebuffer_size().cast_to<f32>())
.property(matrix_v_property_hash, m_v)
.property(matrix_p_property_hash, m_p)
.property(matrix_vp_property_hash, m_v * m_p)
@@ -219,8 +224,9 @@ namespace e2d::render_system_impl
// drawer
//
drawer::drawer(engine& e, debug& d, render& r)
drawer::drawer(engine& e, debug& d, render& r, window& w)
: engine_(e)
, render_(r)
, window_(w)
, batcher_(d, r) {}
}

View File

@@ -36,6 +36,7 @@ namespace e2d::render_system_impl
const const_node_iptr& cam_n,
engine& engine,
render& render,
window& window,
batcher_type& batcher);
~context() noexcept;
@@ -59,13 +60,14 @@ namespace e2d::render_system_impl
render::property_block property_cache_;
};
public:
drawer(engine& e, debug& d, render& r);
drawer(engine& e, debug& d, render& r, window& w);
template < typename F >
void with(const camera& cam, const const_node_iptr& cam_n, F&& f);
private:
engine& engine_;
render& render_;
window& window_;
batcher_type batcher_;
};
}
@@ -74,7 +76,7 @@ namespace e2d::render_system_impl
{
template < typename F >
void drawer::with(const camera& cam, const const_node_iptr& cam_n, F&& f) {
context ctx{cam, cam_n, engine_, render_, batcher_};
context ctx{cam, cam_n, engine_, render_, window_, batcher_};
std::forward<F>(f)(ctx);
ctx.flush();
}

View File

@@ -139,6 +139,14 @@ namespace e2d
namespace e2d
{
vec3<f32> make_vec3(const color& c) noexcept {
return make_vec3(c.r, c.g, c.b);
}
vec4<f32> make_vec4(const color& c) noexcept {
return make_vec4(c.r, c.g, c.b, c.a);
}
//
// color (<,==,!=) color
//

View File

@@ -139,6 +139,14 @@ namespace e2d
namespace e2d
{
vec3<u8> make_vec3(const color32& c) noexcept {
return make_vec3(c.r, c.g, c.b);
}
vec4<u8> make_vec4(const color32& c) noexcept {
return make_vec4(c.r, c.g, c.b, c.a);
}
//
// color32 (<,==,!=) color32
//

View File

@@ -0,0 +1,170 @@
/*******************************************************************************
* 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/font_impl.hpp"
namespace
{
using namespace e2d;
u64 make_kerning_key(u32 first, u32 second) noexcept {
return (static_cast<u64>(first) << 32) | static_cast<u64>(second);
}
}
namespace e2d
{
font::font(font&& other) noexcept {
assign(std::move(other));
}
font& font::operator=(font&& other) noexcept {
return assign(std::move(other));
}
font::font(const font& other) {
assign(other);
}
font& font::operator=(const font& other) {
return assign(other);
}
font::font(content&& content) noexcept {
assign(std::move(content));
}
font::font(const content& content) {
assign(content);
}
font& font::assign(font&& other) noexcept {
if ( this != &other ) {
swap(other);
other.clear();
}
return *this;
}
font& font::assign(const font& other) {
if ( this != &other ) {
content_ = other.content_;
}
return *this;
}
font& font::assign(content&& content) noexcept {
content_ = std::move(content);
return *this;
}
font& font::assign(const content& content) {
content_ = content;
return *this;
}
void font::swap(font& other) noexcept {
using std::swap;
swap(content_.info, other.content_.info);
swap(content_.kernings, other.content_.kernings);
swap(content_.glyphs, other.content_.glyphs);
}
void font::clear() noexcept {
content_ = content();
}
bool font::empty() const noexcept {
return !content_.info.font_size;
}
const font::font_info& font::info() const noexcept {
return content_.info;
}
const flat_map<u64, i32>& font::kernings() const noexcept {
return content_.kernings;
}
const flat_map<u32, font::glyph_info>& font::glyphs() const noexcept {
return content_.glyphs;
}
i32 font::get_kerning(u32 first, u32 second) const noexcept {
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
{
void swap(font& l, font& r) noexcept {
l.swap(r);
}
bool operator==(const font& l, const font& r) noexcept {
return l.info() == r.info()
&& l.kernings() == r.kernings()
&& l.glyphs() == r.glyphs();
}
bool operator!=(const font& l, const font& r) noexcept {
return !(l == r);
}
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::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::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,
buffer_view src) noexcept
{
try {
return impl::load_font_bmfont(dst, src);
} catch (...) {
return false;
}
}
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);
}
}

View 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);
}

View File

@@ -0,0 +1,363 @@
/*******************************************************************************
* 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.offset.y =
0 -
glyph.second.offset.y -
glyph.second.tex_rect.size.y;
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;
}
}

View File

@@ -48,7 +48,7 @@ namespace
image_data_format image_format_from_stb_channels(u32 channels) noexcept {
switch ( channels ) {
case 1: return image_data_format::l8;
case 1: return image_data_format::a8;
case 2: return image_data_format::la8;
case 3: return image_data_format::rgb8;
case 4: return image_data_format::rgba8;

View File

@@ -44,7 +44,7 @@ namespace
bool stb_check_save_image_format(image_data_format format) noexcept {
switch ( format ) {
case image_data_format::l8:
case image_data_format::a8:
case image_data_format::la8:
case image_data_format::rgb8:
case image_data_format::rgba8:
@@ -56,7 +56,7 @@ namespace
int stb_channels_from_image_format(image_data_format format) noexcept {
switch ( format ) {
case image_data_format::l8: return 1;
case image_data_format::a8: return 1;
case image_data_format::la8: return 2;
case image_data_format::rgb8: return 3;
case image_data_format::rgba8: return 4;

View File

@@ -48,6 +48,10 @@ TEST_CASE("color") {
c /= color(0.1f,0.2f,0.3f,0.4f);
REQUIRE(c == color(0.5f,0.6f,0.7f,0.8f));
}
{
REQUIRE(make_vec3(color(0.1f,0.2f,0.3f,0.4f)) == v3f(0.1f,0.2f,0.3f));
REQUIRE(make_vec4(color(0.1f,0.2f,0.3f,0.4f)) == v4f(0.1f,0.2f,0.3f, 0.4f));
}
{
REQUIRE(color(0.1f,0.2f,0.3f,0.4f) + 0.1f == color(0.2f,0.3f,0.4f,0.5f));
REQUIRE(color(0.1f,0.2f,0.3f,0.4f) - 0.1f == color(0.0f,0.1f,0.2f,0.3f));

View File

@@ -50,6 +50,10 @@ TEST_CASE("color32") {
c /= color32(2,3,6,7);
REQUIRE(c == color32(40,50,40,20));
}
{
REQUIRE(make_vec3(color32(10,20,30,40)) == vec3<u8>(10,20,30));
REQUIRE(make_vec4(color32(10,20,30,40)) == vec4<u8>(10,20,30,40));
}
{
REQUIRE(color32(10,20,30,40) + 10 == color32(20,30,40,50));
REQUIRE(color32(10,20,30,40) - 10 == color32(0,10,20,30));

View File

@@ -0,0 +1,66 @@
/*******************************************************************************
* 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 "_utils.hpp"
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
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
)fnt";
const char* const mini_bad_fnt = R"fnt(
info face="Arial" size=HELLO bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0
)fnt";
}
TEST_CASE("font") {
{
font f;
REQUIRE_FALSE(fonts::try_load_font(f, buffer(mini_bad_fnt, std::strlen(mini_bad_fnt))));
REQUIRE_FALSE(fonts::try_load_font(f, make_memory_stream(buffer(mini_bad_fnt, std::strlen(mini_bad_fnt)))));
}
{
font f, f2;
REQUIRE(fonts::try_load_font(f, buffer(mini_fnt, std::strlen(mini_fnt))));
REQUIRE(fonts::try_load_font(f2, make_memory_stream(buffer(mini_fnt, std::strlen(mini_fnt)))));
REQUIRE(f == f2);
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.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::glyph_info c;
c.offset = v2i(5, -50);
c.tex_rect = b2u(448, 86, 10, 40);
c.advance = 14;
REQUIRE(*f.find_glyph(33) == c);
}
REQUIRE(f.kernings().size() == 2);
REQUIRE(f.get_kerning(1059, 1081) == -1);
REQUIRE(f.get_kerning(1059, 100500) == 0);
}
}