s
This commit is contained in:
parent
0b6096afd5
commit
629f1075a0
8 changed files with 203 additions and 180 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,3 +5,5 @@ build
|
||||||
NVL/.vs
|
NVL/.vs
|
||||||
NVL/out
|
NVL/out
|
||||||
.cache
|
.cache
|
||||||
|
vs
|
||||||
|
**/.DS_STORE
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace {
|
||||||
|
|
||||||
ADVect::MarkupTextTransitionTrack m_text{
|
ADVect::MarkupTextTransitionTrack m_text{
|
||||||
.current{},
|
.current{},
|
||||||
.pos_x = 280, .pos_y = 90, .w = 900, .h = 500,
|
.pos_x = 280, .pos_y = 90, .w = 800, .h = 500,
|
||||||
.opacity = 1.0f, .fill = 0xFFFFFFFF
|
.opacity = 1.0f, .fill = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
ADVect::TextTrack speaker = {
|
ADVect::TextTrack speaker = {
|
||||||
|
@ -50,7 +50,7 @@ namespace {
|
||||||
.w = 500, .h = 500
|
.w = 500, .h = 500
|
||||||
}, avatar = {
|
}, avatar = {
|
||||||
.current{},
|
.current{},
|
||||||
.pos_x = 10, .pos_y = 0,
|
.pos_x = 0, .pos_y = 0,
|
||||||
.w = 500, .h = 500
|
.w = 500, .h = 500
|
||||||
};
|
};
|
||||||
ADVect::ImageTrack dialogue_bg = {
|
ADVect::ImageTrack dialogue_bg = {
|
||||||
|
@ -58,28 +58,7 @@ namespace {
|
||||||
.pos_x = 0, .pos_y = 0,
|
.pos_x = 0, .pos_y = 0,
|
||||||
.w = 500, .h = 500
|
.w = 500, .h = 500
|
||||||
};
|
};
|
||||||
/*
|
std::vector<std::function<void(u64)>> track_updaters;
|
||||||
std::list<NamedImageTrack> tracks_img{}; // instead of vector because we need pointers to members; prevent use after free
|
|
||||||
NamedImageTrack* find_image_track(const std::string& s) {
|
|
||||||
for (auto& t : tracks_img)
|
|
||||||
if (t.name == s) {
|
|
||||||
return &t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool add_image_track(const std::string& s) {
|
|
||||||
if (find_image_track(s) == nullptr) {
|
|
||||||
NamedImageTrack t;
|
|
||||||
t.name = s;
|
|
||||||
tracks_img.push_back(std::move(t));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
std::cerr << "ADV: Redefinition of ImageTrack " << s << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ADVect {
|
namespace ADVect {
|
||||||
|
@ -140,6 +119,10 @@ namespace ADVect {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track_updaters.push_back(std::bind(&decltype(bg)::check, &bg, std::placeholders::_1));
|
||||||
|
track_updaters.push_back(std::bind(&decltype(avatar)::check, &avatar, std::placeholders::_1));
|
||||||
|
track_updaters.push_back(std::bind(&decltype(m_text)::check, &m_text, std::placeholders::_1));
|
||||||
|
|
||||||
Advance();
|
Advance();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -195,20 +178,15 @@ namespace ADVect {
|
||||||
Advance();
|
Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
bg.check(current_time);
|
for (const auto& x : track_updaters) {
|
||||||
avatar.check(current_time);
|
x(current_time);
|
||||||
m_text.check(current_time);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render() {
|
void Render() {
|
||||||
bgfx::touch(0);
|
bgfx::touch(0);
|
||||||
|
|
||||||
/*
|
|
||||||
for (auto& t : tracks_img) {
|
|
||||||
if (t.current != nullptr)
|
|
||||||
ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
draw_image_transition_fade(current_time, bg);
|
draw_image_transition_fade(current_time, bg);
|
||||||
|
|
||||||
if (draw_ui) {
|
if (draw_ui) {
|
||||||
|
@ -216,7 +194,7 @@ namespace ADVect {
|
||||||
ADVect::Graphics::DrawTextureImage(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y);
|
ADVect::Graphics::DrawTextureImage(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y);
|
||||||
draw_image_transition_crossfade(current_time, avatar);
|
draw_image_transition_crossfade(current_time, avatar);
|
||||||
|
|
||||||
ADVect::Graphics::RenderString(speaker.current, speaker.pos_x, speaker.pos_y, speaker.fill, ADVect::Graphics::TEXT_BOLD);
|
ADVect::Graphics::RenderString<true, false>(speaker.current, speaker.pos_x, speaker.pos_y, speaker.fill, ADVect::Graphics::TEXT_BOLD);
|
||||||
draw_typewriter(current_time, m_text);
|
draw_typewriter(current_time, m_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,47 +254,44 @@ int main(int argc, char* argv[]) {
|
||||||
{
|
{
|
||||||
u"Say",
|
u"Say",
|
||||||
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
NVL::Environment::MarkupString str = NVL::Environment::UnpackMarkupVariable(std::get<std::vector<NVL::Environment::Variable>>(NVL::Environment::Variable(args[0]).value));
|
NVL::Environment::MarkupString str = NVL::Environment::UnpackMarkupVariable(std::get<std::vector<NVL::Environment::Variable>>(args[0].value));
|
||||||
size_t len = str.length();
|
size_t len = str.length();
|
||||||
m_text.change(current_time, str, len * 10, [len](NVL::Number x) { return static_cast<size_t>(x * len); });
|
m_text.change(current_time, str, len * 10, [len](NVL::Number x) { return static_cast<size_t>(x * len); });
|
||||||
return NVL::Environment::Type::Nil;
|
return NVL::Environment::Type::Nil;
|
||||||
}, 2)
|
}, 1)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
u"SwitchSpeaker",
|
u"SwitchSpeaker",
|
||||||
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
speaker.current = std::get<NVL::String>(NVL::Environment::Variable(args[0]).value);
|
speaker.current = std::get<NVL::String>(args[0].value);
|
||||||
return NVL::Environment::Type::Nil;
|
return NVL::Environment::Type::Nil;
|
||||||
}, 1)
|
}, 1)
|
||||||
},
|
},
|
||||||
/* {
|
{
|
||||||
u"ImageTrack",
|
u"BG",
|
||||||
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
add_image_track(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value)));
|
bg.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value))), 200);
|
||||||
return NVL::Environment::Type::Nil;
|
return NVL::Environment::Type::Nil;
|
||||||
}, 1)
|
}, 1)
|
||||||
},*/
|
},
|
||||||
|
{
|
||||||
|
u"Avatar",
|
||||||
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
|
avatar.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value))), 200);
|
||||||
|
return NVL::Environment::Type::Nil;
|
||||||
|
}, 1)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u"BGDialogue",
|
||||||
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
|
dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value)));
|
||||||
|
return NVL::Environment::Type::Nil;
|
||||||
|
}, 1)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
u"Show",
|
u"Show",
|
||||||
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
|
||||||
std::string name = NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value));
|
std::get<std::function<NVL::Environment::Variable(std::vector<NVL::Environment::Variable>)>>(args[0].value)({args[1]});
|
||||||
/* NamedImageTrack* t = find_image_track(name);
|
|
||||||
if (t == nullptr) {
|
|
||||||
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto s = std::get<NVL::String>(NVL::Environment::Variable(args[1]).value);
|
|
||||||
auto s2 = NVL::to_std_string(s);
|
|
||||||
t->current = ADVect::Graphics::GetImageTextureFromFile(s2);
|
|
||||||
}*/
|
|
||||||
if (name == "BG")
|
|
||||||
bg.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value))), 200);
|
|
||||||
else if (name == "Avatar")
|
|
||||||
avatar.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value))), 200);
|
|
||||||
else if (name == "BGDialogue")
|
|
||||||
dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value)));
|
|
||||||
else
|
|
||||||
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl;
|
|
||||||
return NVL::Environment::Type::Nil;
|
return NVL::Environment::Type::Nil;
|
||||||
}, 2)
|
}, 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.8)
|
||||||
|
|
||||||
project (ADVect)
|
project (ADVect)
|
||||||
|
|
||||||
add_executable (Game "ADVect.cpp" "Graphics.cpp" "Track.h")
|
add_executable (Game "ADVect.cpp" "Graphics.cpp" "Track.h" "Audio.cpp" "Audio.h")
|
||||||
|
|
||||||
# TODO: Add tests and install targets if needed.
|
# TODO: Add tests and install targets if needed.
|
||||||
include_directories ("include" "../NVL/")
|
include_directories ("include" "../NVL/")
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "Environment.h"
|
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
@ -7,6 +6,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
|
@ -73,29 +73,48 @@ namespace {
|
||||||
|
|
||||||
struct Font {
|
struct Font {
|
||||||
FT_Face face = nullptr;
|
FT_Face face = nullptr;
|
||||||
std::unordered_map<NVL::Char, bgfx::TextureHandle> cache{};
|
std::unordered_map<NVL::Char, std::tuple<std::optional<bgfx::TextureHandle>, u32, u32, i32, i32, i32, i32>> cache{};
|
||||||
|
|
||||||
void cache_char(NVL::Char c) {
|
std::tuple<std::optional<bgfx::TextureHandle>, u32, u32, i32, i32, i32, i32>& get_char(NVL::Char c) {
|
||||||
FT_GlyphSlot slot = face->glyph;
|
if (cache.find(c) == cache.end()) {
|
||||||
|
FT_GlyphSlot slot = face->glyph;
|
||||||
|
|
||||||
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
|
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
|
||||||
if (error) {
|
if (error) {
|
||||||
std::cerr << "ADV: Failed to load character" << std::endl;
|
std::cerr << "ADV: Failed to load character" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache.find(c) == cache.end() && slot->bitmap.width != 0) {
|
if (slot->bitmap.width != 0) {
|
||||||
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
|
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
|
||||||
|
|
||||||
cache.emplace(c, bgfx::createTexture2D(
|
cache.emplace(c, std::make_tuple(
|
||||||
slot->bitmap.width,
|
bgfx::createTexture2D(
|
||||||
slot->bitmap.rows,
|
slot->bitmap.width,
|
||||||
false,
|
slot->bitmap.rows,
|
||||||
1,
|
false,
|
||||||
bgfx::TextureFormat::A8,
|
1,
|
||||||
BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP,
|
bgfx::TextureFormat::A8,
|
||||||
buf
|
BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP,
|
||||||
));
|
buf
|
||||||
|
),
|
||||||
|
slot->bitmap.width,
|
||||||
|
slot->bitmap.rows,
|
||||||
|
slot->bitmap_left,
|
||||||
|
slot->bitmap_top,
|
||||||
|
slot->advance.x,
|
||||||
|
slot->advance.y
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else cache.emplace(c, std::make_tuple(
|
||||||
|
std::nullopt,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
slot->advance.x,
|
||||||
|
slot->advance.y));
|
||||||
}
|
}
|
||||||
|
return cache[c];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,7 +143,8 @@ namespace {
|
||||||
void destroy_font(Font& f) {
|
void destroy_font(Font& f) {
|
||||||
FT_Done_Face(f.face);
|
FT_Done_Face(f.face);
|
||||||
for (auto it = f.cache.begin(); it != f.cache.end(); it++) {
|
for (auto it = f.cache.begin(); it != f.cache.end(); it++) {
|
||||||
bgfx::destroy(it->second);
|
if(auto& tx = std::get<0>(it->second))
|
||||||
|
bgfx::destroy(*tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +199,20 @@ namespace {
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void HandleMarkupFlags(const NVL::Environment::MarkupSegment& s, u32& style_flags, const NVL::String*& ruby) {
|
||||||
|
for (const auto& e : s.efs) {
|
||||||
|
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
|
||||||
|
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
|
||||||
|
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
|
||||||
|
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; }
|
||||||
|
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; }
|
||||||
|
else if (e.first == u"rb") { ruby = &e.second[0]; }
|
||||||
|
else {
|
||||||
|
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ADVect::Graphics {
|
namespace ADVect::Graphics {
|
||||||
|
@ -279,113 +312,119 @@ namespace ADVect::Graphics {
|
||||||
DrawTexture(tex, pos_x, pos_y, w, h, (BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS), a_program);
|
DrawTexture(tex, pos_x, pos_y, w, h, (BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS), a_program);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderStringWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
template <bool DoRender, bool Walk>
|
||||||
|
void RenderGlyph(NVL::Char c, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
||||||
Font* f = ResolveStyleFlags(style_flags);
|
Font* f = ResolveStyleFlags(style_flags);
|
||||||
|
|
||||||
FT_GlyphSlot& slot = f->face->glyph;
|
auto& [tx, w, h, l, t, x, y] = f->get_char(c);
|
||||||
|
|
||||||
|
pos_x += l;
|
||||||
|
|
||||||
|
if (auto& buf = tx; DoRender && tx && w != 0) {
|
||||||
|
DrawTextureStencilAlpha(*buf, pos_x, pos_y - (h - t), w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
pos_x += x >> 6;
|
||||||
|
pos_y += y >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool DoRender, bool Walk>
|
||||||
|
void RenderString(const NVL::String& s, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
||||||
for (const auto& c : s) {
|
for (const auto& c : s) {
|
||||||
f->cache_char(c);
|
RenderGlyph<DoRender>(c, pos_x, pos_y, col, style_flags);
|
||||||
|
|
||||||
pos_x += slot->bitmap_left;
|
|
||||||
f32 ypos = pos_y - (slot->bitmap.rows - slot->bitmap_top);
|
|
||||||
|
|
||||||
if (slot->bitmap.width != 0) {
|
|
||||||
DrawTextureStencilAlpha((f->cache)[c], pos_x, ypos, slot->bitmap.width, slot->bitmap.rows);
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_x += slot->advance.x >> 6;
|
|
||||||
pos_y += slot->advance.y >> 6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringWalk(const NVL::String& s, i32& pos_x, u32 style_flags = TEXT_NONE) {
|
template <bool DoRender, bool Walk>
|
||||||
Font* f = ResolveStyleFlags(style_flags);
|
void RenderString(NVL::String::const_iterator cbegin, NVL::String::const_iterator cend, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
||||||
|
while (cbegin < cend) {
|
||||||
FT_GlyphSlot& slot = f->face->glyph;
|
RenderGlyph<DoRender>(*cbegin++, pos_x, pos_y, col, style_flags);
|
||||||
for (const auto& c : s) {
|
|
||||||
f->cache_char(c);
|
|
||||||
pos_x += slot->bitmap_left;
|
|
||||||
pos_x += slot->advance.x >> 6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
void RenderStringCentered(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
||||||
RenderStringWalk(s, pos_x, pos_y, col, style_flags);
|
i32 copy_x = 0, copy_y = 0;
|
||||||
|
RenderString<false, true>(s, copy_x, copy_y, col, style_flags);
|
||||||
|
RenderString<true, false>(s, pos_x - copy_x / 2, pos_y, col, style_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags = TEXT_NONE) {
|
// I cannot reason this function, returns where the string would end if it was not halted
|
||||||
|
i32 RenderSubstringBox(const NVL::String& s, i32& pos_x, i32& pos_y, i32 reset_x, u32 w, u32 col, u32 style_flags, size_t s_end) {
|
||||||
Font* f = ResolveStyleFlags(style_flags);
|
Font* f = ResolveStyleFlags(style_flags);
|
||||||
|
|
||||||
i32 init_x = pos_x;
|
NVL::String::const_iterator last = s.cbegin(), end = s.cend(), pos = std::find(last, end, u' '),
|
||||||
size_t last = 0, pos = s.find(u' ');
|
halt = s_end > s.length() ? end : last + s_end;
|
||||||
if (pos == NVL::String::npos)
|
if (pos == end) { // Render the entire thing with hard break if we don't split at all
|
||||||
RenderStringWalk(s, pos_x, pos_y, col, style_flags);
|
NVL::String::const_iterator last_copy = last;
|
||||||
else {
|
i32 copy_x = pos_x, copy_y = pos_y;
|
||||||
while (last != NVL::String::npos) {
|
while (last != std::min(pos, halt)) {
|
||||||
NVL::String sub = s.substr(last, pos - last);
|
RenderGlyph(*last++, pos_x, pos_y, col, style_flags);
|
||||||
i32 copy_x = pos_x;
|
if (pos_x - reset_x > w) {
|
||||||
StringWalk(sub, copy_x, style_flags);
|
pos_x = reset_x;
|
||||||
if (copy_x - init_x > w) {
|
|
||||||
pos_x = init_x;
|
|
||||||
pos_y -= f->face->size->metrics.height / 64;
|
pos_y -= f->face->size->metrics.height / 64;
|
||||||
sub.erase(sub.begin());
|
|
||||||
}
|
}
|
||||||
RenderStringWalk(sub, pos_x, pos_y, col, style_flags);
|
if (last >= halt) {
|
||||||
last = pos;
|
RenderString<false>(last_copy, pos, copy_x, copy_y, col, style_flags);
|
||||||
pos = s.find(u' ', pos + 1);
|
return copy_x;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else while (last != end) { // Loop through all segments
|
||||||
|
i32 copy_x = pos_x, old_x = pos_x, copy_y = pos_y;
|
||||||
|
RenderString<false>(last, pos, copy_x, copy_y, col, style_flags);
|
||||||
|
if (copy_x - reset_x > w) { // if walk exceeded max w
|
||||||
|
copy_x = reset_x, copy_y = pos_y; // try walk again from leftmost of box, see if a soft break works; reset y from last walk
|
||||||
|
RenderString<false>(last, pos, copy_x, copy_y, col, style_flags);
|
||||||
|
if (copy_x - reset_x > w) { // soft break won't work, go back to old x and hard break
|
||||||
|
pos_x = old_x;
|
||||||
|
while (last != pos) {
|
||||||
|
RenderGlyph(*last++, pos_x, pos_y, col, style_flags);
|
||||||
|
if (pos_x - reset_x > w) {
|
||||||
|
pos_x = reset_x;
|
||||||
|
pos_y -= f->face->size->metrics.height / 64;
|
||||||
|
}
|
||||||
|
if (last >= halt) return copy_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // soft break and kill beginning space
|
||||||
|
pos_x = reset_x;
|
||||||
|
pos_y -= f->face->size->metrics.height / 64;
|
||||||
|
last++;
|
||||||
|
RenderString(last, std::min(pos, halt), pos_x, pos_y, col, style_flags);
|
||||||
|
if (last >= halt) return copy_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RenderString(last, std::min(pos, halt), pos_x, pos_y, col, style_flags);
|
||||||
|
if (last >= halt) return copy_x;
|
||||||
|
}
|
||||||
|
|
||||||
void RenderStringMarkup(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 col) {
|
last = pos;
|
||||||
|
if (pos != end)
|
||||||
|
pos = std::find(std::next(pos), end, u' ');
|
||||||
|
}
|
||||||
|
return pos_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSubstringMarkupBox(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col, size_t end) {
|
||||||
|
i32 init_x = pos_x;
|
||||||
|
size_t acc_length = 0;
|
||||||
// We assume markups are already sorted
|
// We assume markups are already sorted
|
||||||
for (const NVL::Environment::MarkupSegment& s : ms.segments) {
|
for (const NVL::Environment::MarkupSegment& s : ms.segments) {
|
||||||
u32 style_flags = TEXT_NONE;
|
u32 style_flags = TEXT_NONE;
|
||||||
const NVL::String* ruby = nullptr;
|
const NVL::String* ruby = nullptr;
|
||||||
|
HandleMarkupFlags(s, style_flags, ruby);
|
||||||
|
|
||||||
for (const auto& e : s.efs) {
|
i32 last_x = pos_x,
|
||||||
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
|
|
||||||
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
|
segment_end = RenderSubstringBox(s.str, pos_x, pos_y, init_x, w, col, style_flags, end - acc_length);
|
||||||
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
|
|
||||||
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; }
|
if (ruby != nullptr && segment_end != last_x) {
|
||||||
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; }
|
RenderStringCentered(*ruby, segment_end / 2 + last_x / 2, i32(pos_y + 20), col);
|
||||||
else if (e.first == u"rb") { ruby = &e.second[0]; }
|
|
||||||
else {
|
|
||||||
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ruby != nullptr) {
|
acc_length += s.str.length();
|
||||||
RenderString(*ruby, pos_x, pos_y + 20, col);
|
if (acc_length > end) return;
|
||||||
}
|
|
||||||
|
|
||||||
RenderStringWalk(s.str, pos_x, pos_y, col, style_flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderStringMarkupWrap(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col) {
|
|
||||||
// We assume markups are already sorted
|
|
||||||
for (const NVL::Environment::MarkupSegment& s : ms.segments) {
|
|
||||||
u32 style_flags = TEXT_NONE;
|
|
||||||
const NVL::String* ruby = nullptr;
|
|
||||||
|
|
||||||
for (const auto& e : s.efs) {
|
|
||||||
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
|
|
||||||
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
|
|
||||||
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
|
|
||||||
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; }
|
|
||||||
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; }
|
|
||||||
else if (e.first == u"rb") { ruby = &e.second[0]; }
|
|
||||||
else {
|
|
||||||
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ruby != nullptr) {
|
|
||||||
RenderString(*ruby, pos_x, pos_y + 20, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderStringWrapWalk(s.str, pos_x, pos_y, w, col, style_flags);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,14 @@ namespace ADVect::Graphics {
|
||||||
void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y);
|
void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y);
|
||||||
void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha);
|
void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha);
|
||||||
void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h);
|
void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h);
|
||||||
|
|
||||||
|
template <bool DoRender = true, bool Walk = true>
|
||||||
|
void RenderGlyph(NVL::Char c, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags);
|
||||||
|
template <bool DoRender = true, bool Walk = true>
|
||||||
|
void RenderString(const NVL::String& s, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags);
|
||||||
|
template <bool DoRender = true, bool Walk = true>
|
||||||
|
void RenderString(NVL::String::const_iterator cbegin, NVL::String::const_iterator cend, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags);
|
||||||
|
|
||||||
void RenderStringWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 col, u32 style_flags);
|
i32 RenderSubstringBox(const NVL::String& s, i32& pos_x, i32& pos_y, i32 reset_x, u32 w, u32 col, u32 style_flags = TEXT_NONE, size_t s_end = NVL::String::npos);
|
||||||
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags);
|
void RenderSubstringMarkupBox(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col, size_t end = NVL::String::npos);
|
||||||
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags);
|
|
||||||
void RenderStringMarkup(const NVL::Environment::MarkupString& s, i32 pos_x, i32 pos_y, u32 col);
|
|
||||||
void RenderStringMarkupWrap(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ namespace ADVect {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO maybe make this cleaner (packing?)
|
|
||||||
template <typename T, bool UsePointer, bool IsNamed, bool IsVisual, bool IsVisualFill, bool HasTransition>
|
template <typename T, bool UsePointer, bool IsNamed, bool IsVisual, bool IsVisualFill, bool HasTransition>
|
||||||
struct Track {
|
struct Track {
|
||||||
std::conditional_t<UsePointer, T*, T> current{};
|
std::conditional_t<UsePointer, T*, T> current{};
|
||||||
|
@ -103,9 +102,9 @@ namespace ADVect {
|
||||||
|
|
||||||
void draw_typewriter(u64 current_time, const MarkupTextTransitionTrack& t) {
|
void draw_typewriter(u64 current_time, const MarkupTextTransitionTrack& t) {
|
||||||
if (t.transition.done)
|
if (t.transition.done)
|
||||||
ADVect::Graphics::RenderStringMarkupWrap(t.current, t.pos_x, t.pos_y, t.w, t.fill);
|
ADVect::Graphics::RenderSubstringMarkupBox(t.current, t.pos_x, t.pos_y, t.w, t.fill);
|
||||||
else
|
else
|
||||||
ADVect::Graphics::RenderStringMarkupWrap(t.next.substr(t.transition.get(current_time)), t.pos_x, t.pos_y, t.w, t.fill);
|
ADVect::Graphics::RenderSubstringMarkupBox(t.next, t.pos_x, t.pos_y, t.w, t.fill, t.transition.get(current_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_image_transition_fade(u64 current_time, const ImageTransitionTrack& t) {
|
void draw_image_transition_fade(u64 current_time, const ImageTransitionTrack& t) {
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
BEGIN Inferno
|
BEGIN Inferno
|
||||||
ImageTrack BG
|
|
||||||
Show BG "image.png"
|
Show BG "image.png"
|
||||||
|
Show BGDialogue "grad.png"
|
||||||
<<-
|
<<-
|
||||||
[]
|
[]
|
||||||
由我这里,直通[b]{悲惨之城}。
|
由我这里,直通[b]{悲惨之城}。
|
||||||
由我这里,直通[b]{无尽之苦}。
|
由我这里,直通[b]{无尽之苦}。
|
||||||
由我这里,直通[b]{堕落众生}。
|
由我这里,直通[b]{堕落众生}。
|
||||||
圣裁于高天激发造我的君主;
|
圣裁于高天激发造我的君主;
|
||||||
造我的大能是[b, rb("C")]{神}的力量,是无上的[b, rb(" L L V M")]{智慧与众爱}所自出。
|
造我的大能是[b, rb("C")]{神}的力量,是无上的[b, rb("L L V M")]{智慧与众爱}所自出。
|
||||||
我永远不朽;在我之前,万象 未形,只有永恒的事物存在。
|
我永远不朽;在我之前,万象 未形,只有永恒的事物存在。
|
||||||
来者呀,快把一切希望弃扬。
|
来者呀,快把一切希望弃扬。
|
||||||
我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。
|
我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。
|
||||||
老师呀,讲得真可骇。
|
|
||||||
[维吉尔]
|
[维吉尔]
|
||||||
一切疑虑,必须在这里摆脱。
|
一切疑虑,必须在这里摆脱。
|
||||||
一切怯懦,必须在这里结束。
|
一切怯懦,必须在这里结束。
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace NVL::Environment {
|
||||||
Variable Eval(const Parse::Object& obj) {
|
Variable Eval(const Parse::Object& obj) {
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case Parse::Type::Symbol:
|
case Parse::Type::Symbol:
|
||||||
return std::get<String>(obj.value);
|
return ENVIRONMENT.get(std::get<String>(obj.value));
|
||||||
case Parse::Type::Number:
|
case Parse::Type::Number:
|
||||||
return Variable(std::get<Number>(obj.value));
|
return Variable(std::get<Number>(obj.value));
|
||||||
case Parse::Type::String:
|
case Parse::Type::String:
|
||||||
|
@ -76,9 +76,14 @@ namespace NVL::Environment {
|
||||||
|
|
||||||
Variable Apply(const Parse::Command& c) {
|
Variable Apply(const Parse::Command& c) {
|
||||||
std::vector<Variable> args{};
|
std::vector<Variable> args{};
|
||||||
for (u32 i = 1; i < c.size(); i++)
|
|
||||||
args.push_back(Eval(c[i]));
|
Variable f = Eval(c[0]);
|
||||||
return std::get<std::function<Variable(std::vector<Variable>)>>(ENVIRONMENT.get(std::get<String>(c[0].value)).value)(args);
|
u32 i = 1;
|
||||||
|
while (i < c.size()) {
|
||||||
|
args.push_back(Eval(c[i++]));
|
||||||
|
}
|
||||||
|
if (f.length != -1 && f.length != i - 1) throw std::runtime_error("Function arity mismatch");
|
||||||
|
return std::get<std::function<Variable(std::vector<Variable>)>>(f.value)(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EvalScene(const Parse::Scene& s) {
|
void EvalScene(const Parse::Scene& s) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue