This commit is contained in:
lachrymaL 2023-04-06 19:56:40 -04:00
parent 0b6096afd5
commit 629f1075a0
No known key found for this signature in database
GPG key ID: F3640ACFA174B1C1
8 changed files with 203 additions and 180 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@ build
NVL/.vs NVL/.vs
NVL/out NVL/out
.cache .cache
vs
**/.DS_STORE

View file

@ -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)
} }

View file

@ -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/")

View file

@ -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,9 +73,10 @@ 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) {
if (cache.find(c) == cache.end()) {
FT_GlyphSlot slot = face->glyph; FT_GlyphSlot slot = face->glyph;
error = FT_Load_Char(face, c, FT_LOAD_RENDER); error = FT_Load_Char(face, c, FT_LOAD_RENDER);
@ -83,10 +84,11 @@ namespace {
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(
bgfx::createTexture2D(
slot->bitmap.width, slot->bitmap.width,
slot->bitmap.rows, slot->bitmap.rows,
false, false,
@ -94,8 +96,25 @@ namespace {
bgfx::TextureFormat::A8, bgfx::TextureFormat::A8,
BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP, BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP,
buf 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);
} }
} }
@ -180,6 +200,19 @@ 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>
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 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);
}
// 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);
FT_GlyphSlot& slot = f->face->glyph; NVL::String::const_iterator last = s.cbegin(), end = s.cend(), pos = std::find(last, end, u' '),
for (const auto& c : s) { halt = s_end > s.length() ? end : last + s_end;
f->cache_char(c); if (pos == end) { // Render the entire thing with hard break if we don't split at all
pos_x += slot->bitmap_left; NVL::String::const_iterator last_copy = last;
pos_x += slot->advance.x >> 6; 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) {
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) { pos_x = reset_x;
RenderStringWalk(s, pos_x, 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) {
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;
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) {
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;
}
last = pos; last = pos;
pos = s.find(u' ', pos + 1); if (pos != end)
} pos = std::find(std::next(pos), end, u' ');
} }
return pos_x;
} }
void RenderStringMarkup(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 col) { 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);
} }
} }

View file

@ -33,9 +33,13 @@ namespace ADVect::Graphics {
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);
void RenderStringWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 col, u32 style_flags); template <bool DoRender = true, bool Walk = true>
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags); 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);
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags); template <bool DoRender = true, bool Walk = true>
void RenderStringMarkup(const NVL::Environment::MarkupString& s, i32 pos_x, i32 pos_y, u32 col); 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);
void RenderStringMarkupWrap(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col); 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);
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);
} }

View file

@ -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) {

View file

@ -1,6 +1,6 @@
BEGIN Inferno BEGIN Inferno
ImageTrack BG
Show BG "image.png" Show BG "image.png"
Show BGDialogue "grad.png"
<<- <<-
[] []
由我这里,直通[b]{悲惨之城}。 由我这里,直通[b]{悲惨之城}。
@ -11,7 +11,6 @@ Show BG "image.png"
我永远不朽;在我之前,万象 未形,只有永恒的事物存在。 我永远不朽;在我之前,万象 未形,只有永恒的事物存在。
来者呀,快把一切希望弃扬。 来者呀,快把一切希望弃扬。
我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。 我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。
老师呀,讲得真可骇。
[维吉尔] [维吉尔]
一切疑虑,必须在这里摆脱。 一切疑虑,必须在这里摆脱。
一切怯懦,必须在这里结束。 一切怯懦,必须在这里结束。

View file

@ -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) {