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/out
|
||||
.cache
|
||||
vs
|
||||
**/.DS_STORE
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace {
|
|||
|
||||
ADVect::MarkupTextTransitionTrack m_text{
|
||||
.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
|
||||
};
|
||||
ADVect::TextTrack speaker = {
|
||||
|
@ -50,7 +50,7 @@ namespace {
|
|||
.w = 500, .h = 500
|
||||
}, avatar = {
|
||||
.current{},
|
||||
.pos_x = 10, .pos_y = 0,
|
||||
.pos_x = 0, .pos_y = 0,
|
||||
.w = 500, .h = 500
|
||||
};
|
||||
ADVect::ImageTrack dialogue_bg = {
|
||||
|
@ -58,28 +58,7 @@ namespace {
|
|||
.pos_x = 0, .pos_y = 0,
|
||||
.w = 500, .h = 500
|
||||
};
|
||||
/*
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
||||
std::vector<std::function<void(u64)>> track_updaters;
|
||||
}
|
||||
|
||||
namespace ADVect {
|
||||
|
@ -140,6 +119,10 @@ namespace ADVect {
|
|||
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();
|
||||
return true;
|
||||
}
|
||||
|
@ -195,20 +178,15 @@ namespace ADVect {
|
|||
Advance();
|
||||
}
|
||||
|
||||
bg.check(current_time);
|
||||
avatar.check(current_time);
|
||||
m_text.check(current_time);
|
||||
for (const auto& x : track_updaters) {
|
||||
x(current_time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Render() {
|
||||
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);
|
||||
|
||||
if (draw_ui) {
|
||||
|
@ -216,7 +194,7 @@ namespace ADVect {
|
|||
ADVect::Graphics::DrawTextureImage(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -276,47 +254,44 @@ int main(int argc, char* argv[]) {
|
|||
{
|
||||
u"Say",
|
||||
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();
|
||||
m_text.change(current_time, str, len * 10, [len](NVL::Number x) { return static_cast<size_t>(x * len); });
|
||||
return NVL::Environment::Type::Nil;
|
||||
}, 2)
|
||||
}, 1)
|
||||
},
|
||||
{
|
||||
u"SwitchSpeaker",
|
||||
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;
|
||||
}, 1)
|
||||
},
|
||||
/* {
|
||||
u"ImageTrack",
|
||||
{
|
||||
u"BG",
|
||||
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;
|
||||
}, 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",
|
||||
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));
|
||||
/* 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;
|
||||
std::get<std::function<NVL::Environment::Variable(std::vector<NVL::Environment::Variable>)>>(args[0].value)({args[1]});
|
||||
return NVL::Environment::Type::Nil;
|
||||
}, 2)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.8)
|
|||
|
||||
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.
|
||||
include_directories ("include" "../NVL/")
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "Graphics.h"
|
||||
#include "Environment.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
|
@ -7,6 +6,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
@ -73,29 +73,48 @@ namespace {
|
|||
|
||||
struct Font {
|
||||
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) {
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
std::tuple<std::optional<bgfx::TextureHandle>, u32, u32, i32, i32, i32, i32>& get_char(NVL::Char c) {
|
||||
if (cache.find(c) == cache.end()) {
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
std::cerr << "ADV: Failed to load character" << std::endl;
|
||||
}
|
||||
|
||||
if (cache.find(c) == cache.end() && slot->bitmap.width != 0) {
|
||||
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
|
||||
|
||||
cache.emplace(c, bgfx::createTexture2D(
|
||||
slot->bitmap.width,
|
||||
slot->bitmap.rows,
|
||||
false,
|
||||
1,
|
||||
bgfx::TextureFormat::A8,
|
||||
BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP,
|
||||
buf
|
||||
));
|
||||
error = FT_Load_Char(face, c, FT_LOAD_RENDER);
|
||||
if (error) {
|
||||
std::cerr << "ADV: Failed to load character" << std::endl;
|
||||
}
|
||||
|
||||
if (slot->bitmap.width != 0) {
|
||||
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
|
||||
|
||||
cache.emplace(c, std::make_tuple(
|
||||
bgfx::createTexture2D(
|
||||
slot->bitmap.width,
|
||||
slot->bitmap.rows,
|
||||
false,
|
||||
1,
|
||||
bgfx::TextureFormat::A8,
|
||||
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) {
|
||||
FT_Done_Face(f.face);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
f->cache_char(c);
|
||||
|
||||
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;
|
||||
RenderGlyph<DoRender>(c, pos_x, pos_y, col, style_flags);
|
||||
}
|
||||
}
|
||||
|
||||
void StringWalk(const NVL::String& s, i32& pos_x, u32 style_flags = TEXT_NONE) {
|
||||
Font* f = ResolveStyleFlags(style_flags);
|
||||
|
||||
FT_GlyphSlot& slot = f->face->glyph;
|
||||
for (const auto& c : s) {
|
||||
f->cache_char(c);
|
||||
pos_x += slot->bitmap_left;
|
||||
pos_x += slot->advance.x >> 6;
|
||||
template <bool DoRender, bool Walk>
|
||||
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) {
|
||||
RenderGlyph<DoRender>(*cbegin++, pos_x, pos_y, col, style_flags);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderString(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);
|
||||
void RenderStringCentered(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) {
|
||||
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);
|
||||
|
||||
i32 init_x = pos_x;
|
||||
size_t last = 0, pos = s.find(u' ');
|
||||
if (pos == NVL::String::npos)
|
||||
RenderStringWalk(s, pos_x, pos_y, col, style_flags);
|
||||
else {
|
||||
while (last != NVL::String::npos) {
|
||||
NVL::String sub = s.substr(last, pos - last);
|
||||
i32 copy_x = pos_x;
|
||||
StringWalk(sub, copy_x, style_flags);
|
||||
if (copy_x - init_x > w) {
|
||||
pos_x = init_x;
|
||||
NVL::String::const_iterator last = s.cbegin(), end = s.cend(), pos = std::find(last, end, u' '),
|
||||
halt = s_end > s.length() ? end : last + s_end;
|
||||
if (pos == end) { // Render the entire thing with hard break if we don't split at all
|
||||
NVL::String::const_iterator last_copy = last;
|
||||
i32 copy_x = pos_x, copy_y = pos_y;
|
||||
while (last != std::min(pos, halt)) {
|
||||
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;
|
||||
sub.erase(sub.begin());
|
||||
}
|
||||
RenderStringWalk(sub, pos_x, pos_y, col, style_flags);
|
||||
last = pos;
|
||||
pos = s.find(u' ', pos + 1);
|
||||
if (last >= halt) {
|
||||
RenderString<false>(last_copy, pos, copy_x, copy_y, col, style_flags);
|
||||
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
|
||||
for (const NVL::Environment::MarkupSegment& s : ms.segments) {
|
||||
u32 style_flags = TEXT_NONE;
|
||||
const NVL::String* ruby = nullptr;
|
||||
HandleMarkupFlags(s, style_flags, 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;
|
||||
}
|
||||
i32 last_x = pos_x,
|
||||
|
||||
segment_end = RenderSubstringBox(s.str, pos_x, pos_y, init_x, w, col, style_flags, end - acc_length);
|
||||
|
||||
if (ruby != nullptr && segment_end != last_x) {
|
||||
RenderStringCentered(*ruby, segment_end / 2 + last_x / 2, i32(pos_y + 20), col);
|
||||
}
|
||||
|
||||
if (ruby != nullptr) {
|
||||
RenderString(*ruby, pos_x, pos_y + 20, col);
|
||||
}
|
||||
|
||||
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);
|
||||
acc_length += s.str.length();
|
||||
if (acc_length > end) return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,14 @@ namespace ADVect::Graphics {
|
|||
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 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);
|
||||
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags);
|
||||
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);
|
||||
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 RenderSubstringMarkupBox(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col, size_t end = NVL::String::npos);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
struct Track {
|
||||
std::conditional_t<UsePointer, T*, T> current{};
|
||||
|
@ -103,9 +102,9 @@ namespace ADVect {
|
|||
|
||||
void draw_typewriter(u64 current_time, const MarkupTextTransitionTrack& t) {
|
||||
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
|
||||
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) {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
BEGIN Inferno
|
||||
ImageTrack BG
|
||||
Show BG "image.png"
|
||||
Show BGDialogue "grad.png"
|
||||
<<-
|
||||
[]
|
||||
由我这里,直通[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) {
|
||||
switch (obj.type) {
|
||||
case Parse::Type::Symbol:
|
||||
return std::get<String>(obj.value);
|
||||
return ENVIRONMENT.get(std::get<String>(obj.value));
|
||||
case Parse::Type::Number:
|
||||
return Variable(std::get<Number>(obj.value));
|
||||
case Parse::Type::String:
|
||||
|
@ -76,9 +76,14 @@ namespace NVL::Environment {
|
|||
|
||||
Variable Apply(const Parse::Command& c) {
|
||||
std::vector<Variable> args{};
|
||||
for (u32 i = 1; i < c.size(); i++)
|
||||
args.push_back(Eval(c[i]));
|
||||
return std::get<std::function<Variable(std::vector<Variable>)>>(ENVIRONMENT.get(std::get<String>(c[0].value)).value)(args);
|
||||
|
||||
Variable f = Eval(c[0]);
|
||||
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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue