mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-15 00:11:55 +07:00
rewrite label_system
This commit is contained in:
@@ -6,59 +6,352 @@
|
|||||||
|
|
||||||
#include <enduro2d/high/systems/label_system.hpp>
|
#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/label.hpp>
|
||||||
#include <enduro2d/high/components/renderer.hpp>
|
#include <enduro2d/high/components/renderer.hpp>
|
||||||
#include <enduro2d/high/components/model_renderer.hpp>
|
#include <enduro2d/high/components/model_renderer.hpp>
|
||||||
#include <enduro2d/high/assets/texture_asset.hpp>
|
|
||||||
#include <enduro2d/high/assets/shader_asset.hpp>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
using namespace e2d;
|
using namespace e2d;
|
||||||
|
|
||||||
f32 get_x_pos(const label& l, f32 string_width) {
|
class geometry_builder {
|
||||||
f32 x_pos{0};
|
public:
|
||||||
switch ( l.halign() ) {
|
geometry_builder() = default;
|
||||||
case label::haligns::left :
|
|
||||||
x_pos = 0;
|
void add_quad(
|
||||||
break;
|
const b2f& rect,
|
||||||
case label::haligns::center :
|
const b2f& texrect,
|
||||||
x_pos = -0.5f * string_width;
|
const color32& color)
|
||||||
break;
|
{
|
||||||
case label::haligns::right :
|
const std::size_t start_vertex = vertices_.size();
|
||||||
x_pos = -string_width;
|
|
||||||
break;
|
// Y
|
||||||
default:
|
// ^
|
||||||
E2D_ASSERT_MSG(false,"label_system: uncknow horizontal align flag");
|
// | 3 - 2
|
||||||
break;
|
// | | / |
|
||||||
|
// | 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x_pos;
|
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 get_top_pos(const label& l, u32 strings_count) {
|
f32 calculate_valign_offset(
|
||||||
const auto& f = l.font()->content();
|
label::valigns valign,
|
||||||
f32 label_height = f.info().line_height * strings_count;
|
f32 leading,
|
||||||
f32 top{0};
|
u32 glyph_ascent,
|
||||||
switch ( l.valign() ) {
|
u32 line_height,
|
||||||
case label::valigns::top:
|
std::size_t string_count) noexcept
|
||||||
top = label_height;
|
{
|
||||||
break;
|
const f32 label_height = string_count > 1u
|
||||||
case label::valigns::center:
|
? line_height + line_height * leading * (string_count - 1u)
|
||||||
top = 0.5f * label_height;
|
: line_height;
|
||||||
break;
|
|
||||||
case label::valigns::bottom:
|
switch ( valign ) {
|
||||||
top = 0;
|
case label::valigns::top:
|
||||||
break;
|
return 0.f;
|
||||||
case label::valigns::baseline:
|
case label::valigns::center:
|
||||||
top = label_height - (f.info().line_height - f.info().glyph_ascent);
|
return 0.5f * label_height;
|
||||||
break;
|
case label::valigns::bottom:
|
||||||
default:
|
return 1.0f * label_height;
|
||||||
E2D_ASSERT_MSG(false,"label_system: uncknow vertical align flag");
|
case label::valigns::baseline:
|
||||||
break;
|
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) {
|
||||||
|
if ( r.materials().empty() ) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return top;
|
auto texture_p = the<library>().load_asset<texture_asset>(
|
||||||
|
l.font()->content().info().atlas_file);
|
||||||
|
|
||||||
|
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_p->content())
|
||||||
|
.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 str32& text = l.text();
|
||||||
|
const font& f = l.font()->content();
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,222 +367,7 @@ namespace e2d
|
|||||||
~internal_state() noexcept = default;
|
~internal_state() noexcept = default;
|
||||||
|
|
||||||
void process(ecs::registry& owner) {
|
void process(ecs::registry& owner) {
|
||||||
owner.for_joined_components<label::dirty, label, renderer, model_renderer>([](
|
update_dirty_labels(owner);
|
||||||
const ecs::const_entity&,
|
|
||||||
const label::dirty&,
|
|
||||||
const label& l,
|
|
||||||
renderer& r,
|
|
||||||
model_renderer& mr)
|
|
||||||
{
|
|
||||||
vector<v3f> vertices;
|
|
||||||
vector<u32> indices;
|
|
||||||
vector<v2f> uvs;
|
|
||||||
vector<v3f> normals;
|
|
||||||
vector<color32> colors;
|
|
||||||
v2f offset;
|
|
||||||
f32 kerning{0};
|
|
||||||
u32 prev_char{0};
|
|
||||||
str32 text = l.text();
|
|
||||||
if (text.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto& f = l.font()->content();
|
|
||||||
v2f texture_size = f.info().atlas_size.cast_to<f32>();
|
|
||||||
|
|
||||||
if ( l.width() != 0 ) {
|
|
||||||
f32 word_width{0};
|
|
||||||
f32 string_width{0};
|
|
||||||
i32 last_space{-1};
|
|
||||||
for ( size_t i = 0; i < text.size(); i++ ) {
|
|
||||||
const auto& ch = text[i];
|
|
||||||
if ( ch == '\n' ) {
|
|
||||||
word_width = 0;
|
|
||||||
string_width = 0;
|
|
||||||
last_space = -1;
|
|
||||||
} else {
|
|
||||||
const font::glyph_info* glyph = f.find_glyph(ch);
|
|
||||||
if ( glyph ) {
|
|
||||||
prev_char != 0
|
|
||||||
? kerning = f.get_kerning(prev_char, ch)
|
|
||||||
: kerning = 0;
|
|
||||||
prev_char = ch;
|
|
||||||
f32 char_width = glyph->advance + kerning;
|
|
||||||
if ( ch == ' ' ) {
|
|
||||||
if ( string_width + word_width < l.width() ) {
|
|
||||||
if ( string_width + word_width + char_width < l.width() ) {
|
|
||||||
string_width += word_width + char_width;
|
|
||||||
word_width = 0;
|
|
||||||
last_space = i;
|
|
||||||
} else {
|
|
||||||
text[i] = '\n';
|
|
||||||
word_width = 0;
|
|
||||||
string_width = 0;
|
|
||||||
last_space = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ( last_space != -1 ) {
|
|
||||||
text[last_space] = '\n';
|
|
||||||
last_space = -1;
|
|
||||||
string_width = 0;
|
|
||||||
--i;
|
|
||||||
} else {
|
|
||||||
text[i] = '\n';
|
|
||||||
word_width = 0;
|
|
||||||
string_width = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
word_width += char_width;
|
|
||||||
if ( i == text.size() - 1) {
|
|
||||||
if ( string_width + word_width > l.width() ) {
|
|
||||||
if ( last_space != -1 ) {
|
|
||||||
text[last_space] = '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t strings_count{1};
|
|
||||||
for ( size_t i = 0; i < text.size(); i++ ) {
|
|
||||||
if ( text[i] == '\n' && i != text.size() - 1) {
|
|
||||||
strings_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size_t letters_size{0};
|
|
||||||
vector<f32> strings_width(strings_count);
|
|
||||||
std::fill(strings_width.begin(), strings_width.end(), 0);
|
|
||||||
prev_char = 0;
|
|
||||||
for ( size_t i = 0, string_ind = 0; i < text.size(); i++ ) {
|
|
||||||
if ( text[i] != '\n' ) {
|
|
||||||
const font::glyph_info* glyph = f.find_glyph(text[i]);
|
|
||||||
if ( glyph ) {
|
|
||||||
letters_size++;
|
|
||||||
prev_char != 0
|
|
||||||
? kerning = f.get_kerning(prev_char, text[i])
|
|
||||||
: kerning = 0;
|
|
||||||
strings_width[string_ind] += glyph->advance + kerning;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
string_ind++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vertices.resize(letters_size * 4);
|
|
||||||
uvs.resize(vertices.size());
|
|
||||||
colors.resize(vertices.size());
|
|
||||||
indices.resize(text.size() * 6);
|
|
||||||
f32 x_pos = get_x_pos(l, strings_width[0]);
|
|
||||||
f32 y_pos = get_top_pos(l, strings_count);
|
|
||||||
u32 letters_counter{0};
|
|
||||||
prev_char = 0;
|
|
||||||
for ( size_t i = 0, str_ind = 0; i < text.size(); i++ ) {
|
|
||||||
if ( text[i] == '\n' ) {
|
|
||||||
str_ind++;
|
|
||||||
y_pos -= f.info().line_height;
|
|
||||||
x_pos = get_x_pos(l, strings_width[str_ind]);
|
|
||||||
prev_char = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const font::glyph_info* glyph = f.find_glyph(text[i]);
|
|
||||||
if ( glyph ) {
|
|
||||||
offset = glyph->offset.cast_to<f32>();
|
|
||||||
prev_char != 0
|
|
||||||
? kerning = f.get_kerning(prev_char, text[i])
|
|
||||||
: kerning = 0;
|
|
||||||
offset.x += kerning;
|
|
||||||
prev_char = text[i];
|
|
||||||
size_t start_vertices = letters_counter * 4;
|
|
||||||
vertices[start_vertices] = v3f(
|
|
||||||
x_pos + offset.x,
|
|
||||||
y_pos - offset.y - glyph->tex_rect.size.y,
|
|
||||||
0);
|
|
||||||
vertices[start_vertices + 1] = v3f(
|
|
||||||
x_pos + offset.x,
|
|
||||||
y_pos - offset.y,
|
|
||||||
0);
|
|
||||||
vertices[start_vertices + 2] = v3f(
|
|
||||||
x_pos + glyph->tex_rect.size.x + offset.x,
|
|
||||||
y_pos - offset.y,
|
|
||||||
0);
|
|
||||||
vertices[start_vertices + 3] = v3f(
|
|
||||||
x_pos + glyph->tex_rect.size.x + offset.x,
|
|
||||||
y_pos - offset.y - glyph->tex_rect.size.y,
|
|
||||||
0);
|
|
||||||
|
|
||||||
uvs[start_vertices] = v2f(
|
|
||||||
glyph->tex_rect.position.x / texture_size.x,
|
|
||||||
glyph->tex_rect.position.y / texture_size.y);
|
|
||||||
uvs[start_vertices + 1] = v2f(
|
|
||||||
glyph->tex_rect.position.x / texture_size.x,
|
|
||||||
(glyph->tex_rect.position.y + glyph->tex_rect.size.y) / texture_size.y);
|
|
||||||
uvs[start_vertices + 2] = v2f(
|
|
||||||
(glyph->tex_rect.position.x + glyph->tex_rect.size.x) / texture_size.x,
|
|
||||||
(glyph->tex_rect.position.y + glyph->tex_rect.size.y) / texture_size.y);
|
|
||||||
uvs[start_vertices + 3] = v2f(
|
|
||||||
(glyph->tex_rect.position.x + glyph->tex_rect.size.x) / texture_size.x,
|
|
||||||
glyph->tex_rect.position.y / texture_size.y);
|
|
||||||
|
|
||||||
colors[start_vertices] = l.tint();
|
|
||||||
colors[start_vertices + 1] = l.tint();
|
|
||||||
colors[start_vertices + 2] = l.tint();
|
|
||||||
colors[start_vertices + 3] = l.tint();
|
|
||||||
|
|
||||||
size_t start_indices = i * 6;
|
|
||||||
indices[start_indices] = start_vertices;
|
|
||||||
indices[start_indices + 1] = start_vertices + 1;
|
|
||||||
indices[start_indices + 2] = start_vertices + 2;
|
|
||||||
indices[start_indices + 3] = start_vertices + 2;
|
|
||||||
indices[start_indices + 4] = start_vertices + 3;
|
|
||||||
indices[start_indices + 5] = start_vertices;
|
|
||||||
|
|
||||||
x_pos += glyph->advance + kerning;
|
|
||||||
letters_counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh m;
|
|
||||||
m.set_vertices(std::move(vertices));
|
|
||||||
m.set_indices(0, std::move(indices));
|
|
||||||
m.set_uvs(0, std::move(uvs));
|
|
||||||
m.set_colors(0, std::move(colors));
|
|
||||||
|
|
||||||
model content;
|
|
||||||
content.set_mesh(mesh_asset::create(m));
|
|
||||||
content.regenerate_geometry(the<render>());
|
|
||||||
|
|
||||||
if ( !mr.model() ) {
|
|
||||||
mr.model(model_asset::create(content));
|
|
||||||
} else {
|
|
||||||
mr.model()->fill(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( r.materials().size() > 0 &&
|
|
||||||
r.materials().front()->content().properties().sampler_count() == 0 ) {
|
|
||||||
auto texture_p = the<library>().load_asset<texture_asset>(f.info().atlas_file);
|
|
||||||
if ( !texture_p ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_p->content())
|
|
||||||
.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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
owner.remove_all_components<label::dirty>();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user