Compare commits

..

10 commits

Author SHA1 Message Date
6903c2d3ca
rudimentary serialization + NVL Director 2023-04-08 02:33:37 -04:00
3a40e5697d
fixed destroyprogram bug AND did serialization partially 2023-04-07 23:21:15 -04:00
38496209c0
thoughts about compiler 2023-04-07 16:04:30 -04:00
lachrymal
bdf80f37e6 macgit status 2023-04-07 14:32:19 -04:00
572ba4feb0
mixer init 2023-04-06 20:33:30 -04:00
f2f4889161
fix 2023-04-06 20:33:08 -04:00
1248defb9b
what 2023-04-06 20:05:18 -04:00
5391c47b88
resolve 2023-04-06 20:00:48 -04:00
629f1075a0
s 2023-04-06 19:56:40 -04:00
lachrymal
93b8864834 fruit moment 2023-04-06 19:50:37 -04:00
37 changed files with 3454 additions and 331 deletions

2
.gitignore vendored
View file

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

View file

@ -2,18 +2,22 @@
#include "Environment.h"
#include "Graphics.h"
#include "Track.h"
#include "Compiler.h"
#include "Director.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_main.h>
#include <SDL2/SDL_timer.h>
#include <SDL.h>
#include <SDL_main.h>
#include <SDL_timer.h>
#include <bx/math.h>
#include <SDL2/SDL_syswm.h>
#include <SDL_syswm.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <functional>
#include <iostream>
#include <fstream>
#include <filesystem>
namespace {
@ -22,20 +26,18 @@ namespace {
u16 window_height = 720;
u64 init_time, last_time, current_time, delta_t;
bool running = false;
bool running = false, rolling = true;
bool draw_ui = true;
bool m_keys[65536]{}; // terrible
bool mouse[256]{ true }; // terrible
std::vector<NVL::Parse::Scene> scenes;
u32 current_scene = 0;
u32 scene_pos = 0;
std::unique_ptr<NVL::Director::Director> director;
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 = {
@ -58,33 +60,12 @@ 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 {
bool Init(std::string name, const std::vector<NVL::Parse::Scene>& sc) {
scenes = sc; // sure make a copy whatever
bool Init(std::string name, const NVL::Compiler::NVLGraph& g) {
director = std::make_unique<NVL::Director::Director>(g);
if (SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "ADV: Failed to init SDL: " << SDL_GetError() << std::endl;
@ -114,6 +95,7 @@ namespace ADVect {
bgfxInit.platformData.nwh = wmi.info.win.window;
#elif BX_PLATFORM_OSX
bgfxInit.platformData.nwh = wmi.info.cocoa.window;
bgfx::renderFrame();
#elif BX_PLATFORM_LINUX
bgfxInit.platformData.ndt = wmi.info.x11.display;
bgfxInit.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window;
@ -140,6 +122,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;
}
@ -153,21 +139,15 @@ namespace ADVect {
void Advance() {
if (!m_text.transition.done) m_text.transition.done = true;
else {
size_t curr_size = scenes[current_scene].get().size();
while (scene_pos < curr_size && std::get<NVL::String>(scenes[current_scene].get()[scene_pos][0].value) != u"Say") {
NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]);
scene_pos++;
else if (director->active) {
rolling = true;
director->Advance();
}
if (curr_size == scene_pos) {
else
running = false;
return;
}
if (std::get<NVL::String>(scenes[current_scene].get()[scene_pos][0].value) == u"Say") {
NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]);
scene_pos++;
}
}
if (running && rolling)
Advance();
}
void Update() {
@ -195,28 +175,23 @@ 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);
draw_image_transition_crossfade(current_time, bg);
if (draw_ui) {
if (dialogue_bg.current != nullptr)
ADVect::Graphics::DrawTextureImage(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y);
ADVect::Graphics::DrawTextureImageAlpha(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y, 1.0f);
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);
}
@ -225,8 +200,7 @@ namespace ADVect {
bgfx::dbgTextPrintf(0, 0, 0xf8, " %u FPS", stat->cpuTimerFreq / stat->cpuTimeFrame);
bgfx::dbgTextPrintf(0, 1, 0xf8, " NouVeL x ADVect :: %s :: Build %s %s", BX_COMPILER_NAME, __DATE__, __TIME__);
bgfx::dbgTextPrintf(0, 2, 0xf8, " SDL %i.%i.%2i :: bgfx 1.%i :: %s", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL, BGFX_API_VERSION, bgfx::getRendererName(bgfx::getRendererType()));
bgfx::dbgTextPrintf(0, 3, 0xf8, " Current Position: %u", scene_pos);
bgfx::dbgTextPrintf(0, 4, 0xf8, " Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str());
bgfx::dbgTextPrintf(0, 3, 0xf8, " NVL Director State: %s", NVL::to_std_string(director->description).c_str());
bgfx::frame();
}
@ -271,66 +245,79 @@ namespace ADVect {
int main(int argc, char* argv[]) {
std::filesystem::current_path("E:\\Archive\\Projects\\NouVeL\\ADVect\\runtime");
//std::filesystem::current_path("/Users/lachrymal/Projects/NouVeL/ADVect/runtime/");
NVL::Environment::ENVIRONMENT.enter({
{
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); });
rolling = false;
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)
}
});
std::vector<NVL::Parse::Scene> SCENES = NVL::Parse::ParseFile("dialogue.nvl");
if (SCENES.empty()) {
std::cerr << "Main: Empty NVL parse, check file" << std::endl;
return EXIT_FAILURE;
}
//std::vector<NVL::Parse::Scene> scenes = NVL::Parse::ParseFile("dialogue.nvl");
//if (scenes.empty()) {
// std::cerr << "Main: Empty NVL parse, check file" << std::endl;
// return EXIT_FAILURE;
//}
if (!ADVect::Init("ADV Test", SCENES)) return EXIT_FAILURE;
//auto a = NVL::Compiler::Compile(scenes, 0);
//auto b = NVL::Compiler::Serialize(a);
std::ifstream f;
f.open("mmoker.nvlb", std::ios::binary);
std::stringstream c;
c << f.rdbuf();
f.close();
std::istringstream d(c.str());
auto e = NVL::Compiler::Deserialize(d);
if (!ADVect::Init("ADV Test", e)) return EXIT_FAILURE;
ADVect::Run();
ADVect::Shutdown();
return EXIT_SUCCESS;
}

0
ADVect/Audio.cpp Normal file
View file

2
ADVect/Audio.h Normal file
View file

@ -0,0 +1,2 @@
#pragma once
#include "SDL_mixer.h"

View file

@ -5,15 +5,19 @@ 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/")
add_subdirectory("ext/freetype")
add_subdirectory("ext/bgfx")
if (WIN32)
include_directories("include_windows")
include_directories("include_windows" "include_windows/SDL2")
target_link_libraries (Game PRIVATE ${PROJECT_SOURCE_DIR}/lib/SDL2.lib ${PROJECT_SOURCE_DIR}/lib/SDL2main.lib NVL freetype bgfx bx)
elseif (APPLE)
set_target_properties(Game PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "NO")
find_package(SDL2 REQUIRED)
target_link_libraries (Game PRIVATE NVL freetype bgfx bx SDL2::SDL2)
else ()
find_package(SDL2 REQUIRED)
target_link_libraries (Game PRIVATE NVL freetype bgfx bx SDL2::SDL2 SDL2::SDL2main)

View file

@ -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,9 +73,10 @@ 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) {
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);
@ -83,10 +84,11 @@ namespace {
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);
cache.emplace(c, bgfx::createTexture2D(
cache.emplace(c, std::make_tuple(
bgfx::createTexture2D(
slot->bitmap.width,
slot->bitmap.rows,
false,
@ -94,8 +96,25 @@ namespace {
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,12 +143,13 @@ 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);
}
}
inline bgfx::ProgramHandle load_shader_program(const std::string& shader) {
return bgfx::createProgram(loadShader(shader + ".vert.bin"), loadShader(shader + ".frag.bin"), true);
return bgfx::createProgram(loadShader(shader + ".vert.bin"), loadShader(shader + ".frag.bin"), false);
}
std::optional<ImageTexture> get_image_texture(const std::string& file) {
@ -180,6 +200,19 @@ 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 {
@ -200,7 +233,7 @@ namespace ADVect::Graphics {
ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices)));
vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl);
img_program = load_shader_program("test"); // RGBA
// img_program = load_shader_program("test"); // RGBA
imga_program = load_shader_program("ImageAlpha"); // RGBA + Opacity
a_program = load_shader_program("AlphaStencil"); // A -> FFFA
@ -220,7 +253,7 @@ namespace ADVect::Graphics {
}
bgfx::destroy(a_program);
bgfx::destroy(img_program);
//bgfx::destroy(img_program);
bgfx::destroy(imga_program);
bgfx::destroy(ibh);
@ -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) {
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) {
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) {
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) {
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);
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;
}
}
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 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;
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);
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;
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
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;
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include <SDL2/SDL.h>
#include <SDL.h>
#include <bgfx/bgfx.h>
@ -33,9 +33,13 @@ namespace ADVect::Graphics {
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 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);
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 = TEXT_NONE);
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 = TEXT_NONE);
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 = TEXT_NONE);
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,25 +32,31 @@ 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{};
[[no_unique_address]] std::conditional_t<IsNamed, std::string, std::monostate> name{};
// [[no_unique_address]] std::conditional_t<IsNamed, std::string, std::monostate> name{};
std::conditional_t<IsNamed, std::string, std::monostate> name{};
// Visual
[[no_unique_address]] std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{};
[[no_unique_address]] std::conditional_t<IsVisual, u32, std::monostate> w{}, h{};
[[no_unique_address]] std::conditional_t<IsVisual, f32, std::monostate> opacity{};
// [[no_unique_address]] std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{};
// [[no_unique_address]] std::conditional_t<IsVisual, u32, std::monostate> w{}, h{};
// [[no_unique_address]] std::conditional_t<IsVisual, f32, std::monostate> opacity{};
std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{};
std::conditional_t<IsVisual, u32, std::monostate> w{}, h{};
std::conditional_t<IsVisual, f32, std::monostate> opacity{};
// TODO other transforms
// Fill
static_assert(IsVisual || !IsVisualFill, "Track cannot have fill unless visual");
[[no_unique_address]] std::conditional_t<IsVisualFill, u32, std::monostate> fill{};
// [[no_unique_address]] std::conditional_t<IsVisualFill, u32, std::monostate> fill{};
std::conditional_t<IsVisualFill, u32, std::monostate> fill{};
// Transition, with assumption that we need to access the original when transition is underway
[[no_unique_address]] std::conditional_t<HasTransition, std::conditional_t<UsePointer, T*, T>, std::monostate> next{};
[[no_unique_address]] std::conditional_t<HasTransition, Varying<f32>, std::monostate> transition{};
// [[no_unique_address]] std::conditional_t<HasTransition, std::conditional_t<UsePointer, T*, T>, std::monostate> next{};
// [[no_unique_address]] std::conditional_t<HasTransition, Varying<f32>, std::monostate> transition{};
std::conditional_t<HasTransition, std::conditional_t<UsePointer, T*, T>, std::monostate> next{};
std::conditional_t<HasTransition, Varying<f32>, std::monostate> transition{};
void check(u64 current_time) requires HasTransition {
if constexpr (UsePointer) {
if (next != nullptr && transition.check(current_time)) {
@ -103,9 +109,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) {
@ -126,7 +132,7 @@ namespace ADVect {
ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.transition.get(current_time));
}
else {
ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y);
ADVect::Graphics::DrawTextureImageAlpha(*t.current, t.pos_x, t.pos_y, 1.0f);
}
}
}

File diff suppressed because it is too large Load diff

BIN
ADVect/lib/SDL2_mixer.dll Normal file

Binary file not shown.

BIN
ADVect/lib/SDL2_mixer.lib Normal file

Binary file not shown.

BIN
ADVect/lib/libmodplug-1.dll Normal file

Binary file not shown.

BIN
ADVect/lib/libogg-0.dll Normal file

Binary file not shown.

BIN
ADVect/lib/libopus-0.dll Normal file

Binary file not shown.

Binary file not shown.

View file

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

View file

@ -1,6 +1,6 @@
BEGIN Inferno
BEGIN Inferno
ImageTrack BG
// ImageTrack BG
Show BG "image.png"
<<-

View file

@ -1,4 +1,4 @@
BEGIN Scene1
BEGIN Scene1
Show BG "image.png"
Show BGDialogue "grad.png"
@ -23,8 +23,7 @@ After the login screen comes up, type in the password "G00gle."
When the system reboots, you will see a prompt asking you to install a new program.
Type "Y" and press ENTER.
The Google search engine will come up. Type in "www.yahoo.com" and hit ENTER.
A window will appear saying "You have successfully installed Google Chrome." Click OK.
A new browser will open. Log in to your Yahoo mail account.
A window will appear saying "You have successfully installed Google Chrome." Click OK. A new browser will open. Log in to your Yahoo mail account.
Go to your inbox and click on the link to download the latest version of Google Chrome.
Install the update.

BIN
ADVect/runtime/mmoker.nvlb Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ADVect/runtime/times.ttf Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1,33 +1,36 @@
import subprocess, os
SHADERC = "..\\out\\install\\x64-Debug\\bin\\shaderc"
OUT = "..\\out\\build\\x64-Debug\\ADVect\\shaders\\"
#SHADERC = "..\\out\\install\\x64-Debug\\bin\\shaderc"
SHADERC = "/Users/lachrymal/Projects/NouVeL/build/ADVect/ext/bgfx/Debug/shaderc"
#OUT = "..\\out\\build\\x64-Debug\\ADVect\\shaders\\"
# OUT = "..\\build\\ADVect\\shaders\\"
OUT = "/Users/lachrymal/Projects/NouVeL/ADVect/runtime/shaders/"
P = lambda location, frag, vert: { 'location': location, 'frag': frag, 'vert': vert }
P = lambda location, platform, frag, vert: { 'location': location, 'platform': platform, 'frag': frag, 'vert': vert }
plats = [
P('glsl', '140', '140'),
P('dx11', 'ps_5_0', 'vs_5_0'),
P('spirv', 'spirv', 'spirv')
# P('glsl', 'windows', '140', '140'),
# P('dx11', 'windows', 'ps_5_0', 'vs_5_0'),
# P('spirv', 'windows', 'spirv', 'spirv'),
P('metal', 'osx', 'metal', 'metal')
]
for root, dirs, _ in os.walk('shaders'):
for name in dirs:
for config in plats:
subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.frag'),
"--type", "fragment"
"--platform", "windows",
"--type", "fragment",
"--platform", config['platform'],
"--profile", config['frag'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common",
"-i", "ext\\bgfx\\bgfx\\src",
"-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/examples/common",
"-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/src",
"-o", OUT + config['location'] + "\\" + name + ".frag.bin"])
subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.vert'),
"--type", "vertex"
"--platform", "windows",
"--type", "vertex",
"--platform", config['platform'],
"--profile", config['vert'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common",
"-i", "ext\\bgfx\\bgfx\\src",
"-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/examples/common",
"-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/src",
"-o", OUT + config['location'] + "\\" + name + ".vert.bin"])

View file

@ -17,7 +17,9 @@
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [ "Windows" ]
"hostOS": [
"Windows"
]
}
}
},
@ -33,12 +35,23 @@
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [ "Linux" ]
"hostOS": [
"Linux"
]
},
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
},
{
"name": "x64-release",
"displayName": "x64 Release",
"inherits": "windows-default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded"
}
}
]
}

View file

@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.8)
project (NVL)
include_directories("include")
add_library (NVL STATIC "Parser.cpp" "Environment.cpp" "Environment.h" "Common.h")
add_library (NVL STATIC "Parser.cpp" "Environment.cpp" "Environment.h" "Common.h" "Compiler.cpp" "Compiler.h" "Director.h" "Director.cpp")
# add_executable (NVL "NouVeL.cpp" "Parser.cpp" "Environment.cpp" "Environment.h" "Common.h" )
# TODO: Add tests and install targets if needed.

View file

@ -15,6 +15,7 @@ typedef int64_t i64;
typedef uint64_t u64;
#include <string>
#include <vector>
#include <locale>
#include <codecvt>
@ -24,6 +25,8 @@ namespace NVL {
using Number = f32;
using Char = char16_t;
using String = std::u16string;
template <typename T>
using Vector = std::vector<T>;
static std::wstring_convert<std::codecvt_utf8_utf16<Char>, Char> str_converter;

177
NVL/Compiler.cpp Normal file
View file

@ -0,0 +1,177 @@
#include "Compiler.h"
namespace {
template <typename T>
void SerializeDirect(std::ostringstream& s, const T& v) {
s.write(reinterpret_cast<const char*>(&v), sizeof v);
}
void SerializeString(std::ostringstream& s, const NVL::String& st) {
u16 v = st.size() * sizeof NVL::Char;
s.write(reinterpret_cast<const char*>(&v), sizeof v);
s.write(reinterpret_cast<const char*>(st.c_str()), v);
}
void SerializeVariable(std::ostringstream& s, const NVL::Environment::Variable& v) {
using NVL::Environment::Type;
SerializeDirect(s, v.type);
switch (v.type) {
case Type::Array:
{
const auto& e = std::get<NVL::Vector<NVL::Environment::Variable>>(v.value);
SerializeDirect(s, static_cast<u16>(e.size()));
for (const auto& x : e) {
SerializeVariable(s, x);
}
return;
}
case Type::Nil:
return;
case Type::Number:
case Type::StaticReference:
SerializeDirect(s, std::get<NVL::Number>(v.value));
return;
case Type::String:
SerializeString(s, std::get<NVL::String>(v.value));
return;
}
}
template <typename T>
void DeserializeDirect(std::istringstream& s, T& v) {
s.read(reinterpret_cast<char*>(&v), sizeof v);
}
NVL::String DeserializeString(std::istringstream& s) {
u16 size{};
DeserializeDirect(s, size);
u8* str = new u8[size + sizeof NVL::Char];
s.read(reinterpret_cast<char*>(str), size);
reinterpret_cast<NVL::Char*>(str)[size / sizeof NVL::Char] = u'\0';
NVL::String st = NVL::String(reinterpret_cast<NVL::Char*>(str));
delete[] str;
return st;
}
NVL::Environment::Variable DeserializeVariable(std::istringstream& s) {
using NVL::Environment::Type;
NVL::Environment::Type t{};
DeserializeDirect(s, t);
switch (t) {
case Type::Array:
{
u16 size{};
NVL::Vector<NVL::Environment::Variable> vs{};
DeserializeDirect(s, size);
for (u16 i = 0; i < size; i++) {
vs.push_back(DeserializeVariable(s));
}
return vs;
}
case Type::Nil:
return {Type::Nil};
case Type::Number:
case Type::StaticReference:
{
NVL::Number n{};
DeserializeDirect(s, n);
return { n, t == Type::StaticReference };
}
case Type::String:
return DeserializeString(s);
}
}
}
namespace NVL::Compiler {
Environment::Variable StaticEval(Vector<String>& refs, const Parse::Object& obj) {
Environment::Variable actual = Environment::Eval(obj);
if (actual.type == Environment::Type::Procedure) {
u32 proc_index = -1; // lol
const String& proc = std::get<String>(obj.value);
for (u32 i = 0; i < refs.size(); i++) {
if (refs[i] == proc) {
proc_index = i;
break;
}
}
if (proc_index == -1) {
proc_index = refs.size();
refs.push_back(proc);
}
return Environment::Variable(proc_index, true);
}
return actual;
}
NVLGraph Compile(const Vector<Parse::Scene>& scenes, i32 entry_scene_index) {
std::vector<_DirectedGraphNode> nodes{};
Vector<String> procedure_names;
_DirectedGraphNode n{};
for (auto& c : scenes[entry_scene_index].get()) {
Vector<Environment::Variable> s{};
for (auto& v : c) {
s.push_back(StaticEval(procedure_names, v));
}
// TODO route nodes when JUMP
n.sequence.push_back(s);
n.description = scenes[entry_scene_index].name;
}
nodes.push_back(n);
return NVLGraph{ nodes, procedure_names };
}
std::ostringstream Serialize(const NVLGraph& g) {
std::ostringstream s;
SerializeDirect(s, static_cast<u16>(g.static_refs.size()));
for (const String& r : g.static_refs) {
SerializeString(s, r);
}
SerializeDirect(s, static_cast<u16>(g.nodes.size()));
for (const _DirectedGraphNode& n : g.nodes) {
SerializeString(s, n.description);
SerializeDirect(s, static_cast<u16>(n.sequence.size()));
for (const Vector<Environment::Variable>& c : n.sequence) {
SerializeDirect(s, static_cast<u16>(c.size()));
for (const Environment::Variable& v : c) {
SerializeVariable(s, v);
}
}
}
return s;
}
NVLGraph Deserialize(std::istringstream& buf) {
NVLGraph g{};
u16 size{};
DeserializeDirect(buf, size);
for (u16 i = 0; i < size; i++) {
g.static_refs.push_back(DeserializeString(buf));
}
DeserializeDirect(buf, size);
for (u16 i = 0; i < size; i++) {
_DirectedGraphNode n{};
n.description = DeserializeString(buf);
u16 size2{};
DeserializeDirect(buf, size2);
for (u16 j = 0; j < size2; j++) {
Vector<Environment::Variable> cmd{};
u16 size3{};
DeserializeDirect(buf, size3);
for (u16 k = 0; k < size3; k++) {
cmd.push_back(DeserializeVariable(buf));
}
n.sequence.push_back(cmd);
}
g.nodes.push_back(n);
}
return g;
}
}

26
NVL/Compiler.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "Common.h"
#include "Parser.h"
#include "Environment.h"
#include <sstream>
namespace NVL::Compiler {
struct _DirectedGraphNode {
String description;
Vector<Vector<Environment::Variable>> sequence;
};
struct NVLGraph {
Vector<_DirectedGraphNode> nodes;
Vector<String> static_refs;
};
Environment::Variable StaticEval(const Environment::Environment& env, Vector<String>& refs, const Parse::Object& obj);
NVLGraph Compile(const Vector<Parse::Scene>& scenes, i32 entry_scene_index);
std::ostringstream Serialize(const NVLGraph& g);
NVLGraph Deserialize(std::istringstream& buf);
}

46
NVL/Director.cpp Normal file
View file

@ -0,0 +1,46 @@
#include "Director.h"
namespace NVL::Director {
Director::Director(const Compiler::NVLGraph& g) :
g(g), current_position(0), active(true), description(g.nodes[0].description), current_node(g.nodes[0]) {
for (const String& s : g.static_refs)
resolve.push_back(Environment::ENVIRONMENT.get(s));
}
Environment::Variable Director::CollectVariable(const Environment::Variable& v) {
if (v.type == Environment::Type::StaticReference)
return this->resolve[static_cast<u16>(std::get<Number>(v.value))];
else if (v.type == Environment::Type::Array) {
Vector<Environment::Variable> a{};
for (const auto& x : std::get<Vector<Environment::Variable>>(v.value))
a.push_back(CollectVariable(x));
return Environment::Variable(a);
}
else
return v;
}
void Director::Advance() {
if (current_position >= current_node.sequence.size()) {
this->active = false;
return;
}
const auto& cmd = this->current_node.sequence[current_position];
Vector<Environment::Variable> args{};
for (u32 i = 1; i < cmd.size(); i++) {
args.push_back(CollectVariable(cmd[i]));
}
std::get<std::function<Environment::Variable(Vector<Environment::Variable>)>>(CollectVariable(cmd[0]).value)(args);
this->current_position++;
}
void Director::GetBacklog() {
}
void Director::Save() {
}
void Director::Load() {
}
void Director::Jump() {
}
}

25
NVL/Director.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include "Common.h"
#include "Compiler.h"
#include "Environment.h"
namespace NVL::Director {
class Director {
private:
u64 current_position{};
const Compiler::_DirectedGraphNode& current_node{};
const Compiler::NVLGraph& g{};
Vector<Environment::Variable> resolve{};
Environment::Variable CollectVariable(const Environment::Variable& v);
public:
const String& description;
bool active = false;
Director() = delete;
Director(const Compiler::NVLGraph& g);
void Advance();
void GetBacklog();
void Save();
void Load();
void Jump();
};
}

View file

@ -1,25 +1,26 @@
#include "Environment.h"
#include "Parser.h"
#include <stdexcept>
namespace NVL::Environment {
Environment ENVIRONMENT;
Variable::Variable() : type(Type::Nil), length(0) { }
Variable::Variable(Type t) : type(t), length(0) {
if (t != Type::Nil)
throw std::runtime_error("Cannot create non-nil object with type alone");
}
Variable::Variable(const Number& v) : type(Type::Number), value(v), length(1) {}
Variable::Variable(const Number& v, bool is_ref) : type(is_ref ? Type::StaticReference : Type::Number), value(v), length(1) {}
Variable::Variable(const String& v) : type(Type::String), value(v), length(1) {}
Variable::Variable(const std::vector<Variable>& v) : type(Type::Array), value(v), length(v.size()) {}
Variable::Variable(const std::function < Variable(std::vector<Variable>)>& v, u32 l) : type(Type::Procedure), value(v), length(l) {}
Variable::Variable(const Vector<Variable>& v) : type(Type::Array), value(v), length(v.size()) {}
Variable::Variable(const std::function < Variable(Vector<Variable>)>& v, u32 l) : type(Type::Procedure), value(v), length(l) {}
bool Variable::operator==(const Variable& other) const {
if (other.type != type)
return false;
switch (type) {
case Type::Number:
case Type::StaticReference: // Only used with serialization
return std::get<Number>(other.value) == std::get<Number>(value);
case Type::String:
return std::get<String>(other.value) == std::get<String>(value);
@ -44,7 +45,7 @@ namespace NVL::Environment {
env[name] = p;
}
Variable& Environment::get(const String& name) {
const Variable& Environment::get(const String& name) const {
return env.at(name);
}
@ -55,30 +56,34 @@ 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:
return Variable(std::get<String>(obj.value));
case Parse::Type::Array:
{
std::vector<Variable> v{};
for (const auto& x : std::get<std::vector<Parse::Object>>(obj.value))
Vector<Variable> v{};
for (const auto& x : std::get<Vector<Parse::Object>>(obj.value))
v.push_back(Eval(x));
return Variable(v);
}
case Parse::Type::Subexpression:
{
return Apply(std::get<std::vector<Parse::Object>>(obj.value));
return Apply(std::get<Vector<Parse::Object>>(obj.value));
}
}
}
Variable Apply(const Parse::Command& c) {
std::vector<Variable> args{};
for (u32 i = 1; i < c.size(); i++)
Vector<Variable> args{};
Variable f = Eval(c[0]);
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);
}
if (f.length != -1 && f.length != c.size() - 1) throw std::runtime_error("Function arity mismatch");
return std::get<std::function<Variable(Vector<Variable>)>>(f.value)(args);
}
void EvalScene(const Parse::Scene& s) {
@ -87,23 +92,23 @@ namespace NVL::Environment {
}
// Check MatchMarkup for more information
MarkupString UnpackMarkupVariable(const std::vector<Variable>& v) {
MarkupString UnpackMarkupVariable(const Vector<Variable>& v) {
MarkupString ms{};
for (const Variable& segment : v) {
const auto& pair = std::get<std::vector<Variable>>(segment.value);
const auto& pair = std::get<Vector<Variable>>(segment.value);
const String s = std::get<String>(pair[0].value);
std::vector<std::pair<String, std::vector<String>>> efs;
for (const Variable& combination : std::get<std::vector<Variable>>(pair[1].value)) {
Vector<std::pair<String, Vector<String>>> efs;
for (const Variable& combination : std::get<Vector<Variable>>(pair[1].value)) {
if (combination.type == Type::String) {
const String ef = std::get<String>(combination.value);
efs.push_back({ ef, {} });
}
else if (combination.type == Type::Array) {
const std::vector<Variable>& ef_t = std::get<std::vector<Variable>>(combination.value);
const Vector<Variable>& ef_t = std::get<Vector<Variable>>(combination.value);
const String& ef = std::get<String>(ef_t[0].value);
const std::vector<Variable>& args = std::get<std::vector<Variable>>(ef_t[1].value);
std::vector<String> ss{};
const Vector<Variable>& args = std::get<Vector<Variable>>(ef_t[1].value);
Vector<String> ss{};
for (const auto& s : args) { ss.push_back(std::get<String>(s.value)); }
efs.push_back({ ef, ss });
}

View file

@ -6,20 +6,20 @@
#include "Common.h"
namespace NVL::Environment {
enum class Type { Procedure, Number, String, Array, Nil };
enum class Type { Nil, StaticReference, Procedure, Number, String, Array };
struct Variable {
Type type;
std::variant<Number, String, std::vector<Variable>, std::function<Variable(std::vector<Variable>)>> value;
std::variant<Number, String, Vector<Variable>, std::function<Variable(Vector<Variable>)>> value;
// Most things will have length 1 (including string); this is mostly for function arity and array length
u32 length;
bool operator==(const Variable& other) const;
Variable(); // Makes Nil, length 0
Variable(Type t); // Reserved for Nil
Variable(const Number& v);
Variable(const Number& v, bool is_ref = false);
Variable(const String& v);
Variable(const std::vector<Variable>& v);
Variable(const std::function<Variable(std::vector<Variable>)>& v, u32 l);
Variable(const Vector<Variable>& v);
Variable(const std::function<Variable(Vector<Variable>)>& v, u32 l);
};
class Environment {
@ -29,7 +29,7 @@ namespace NVL::Environment {
void enter(const String& name, Variable p);
void enter(std::initializer_list<std::pair<String, Variable>> p);
void set(const String& name, Variable p);
Variable& get(const String& name);
const Variable& get(const String& name) const;
bool exists(const String& name);
};
@ -41,15 +41,15 @@ namespace NVL::Environment {
struct MarkupSegment {
String str;
std::vector<std::pair<String, std::vector<String>>> efs;
Vector<std::pair<String, Vector<String>>> efs;
};
struct MarkupString {
private:
mutable i32 mem_length = -1;
public:
std::vector<MarkupSegment> segments{};
Vector<MarkupSegment> segments{};
size_t length() const;
MarkupString substr(size_t idx) const;
};
MarkupString UnpackMarkupVariable(const std::vector<Variable>& v);
MarkupString UnpackMarkupVariable(const Vector<Variable>& v);
}

View file

@ -125,8 +125,8 @@ namespace {
return to_NVL_string(buffer.str());
}
std::vector<String> split_string_by_lines(const String& str) {
std::vector<String> lines;
Vector<String> split_string_by_lines(const String& str) {
Vector<String> lines;
size_t pos = 0;
size_t prev = 0;
while ((pos = str.find(NEWLINE, prev)) != String::npos) {
@ -230,7 +230,7 @@ namespace {
Parse::Object ParseArray(const String& f, size_t& pos, u32 layer) {
SkipComments(f, pos);
std::vector<Parse::Object> array{};
Vector<Parse::Object> array{};
array.push_back(ParseExpression(f, pos));
while (PeekToken(f, pos)[0] != ARRAY_CLOSE) {
@ -246,7 +246,7 @@ namespace {
String ParseString(const String& f, size_t& pos) {
SkipComments(f, pos);
std::vector<size_t> discards{};
Vector<size_t> discards{};
auto start = ++pos; // skip opening quote
do {
if (f[pos] == QUOTE) {
@ -352,7 +352,7 @@ namespace {
bool has_markup = false;
// Match tags
std::vector<Parse::Object> segments;
Vector<Parse::Object> segments;
String::const_iterator tags_start(s.cbegin());
while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) {
has_markup = true;
@ -361,13 +361,13 @@ namespace {
if (!before.empty())
segments.push_back({ Parse::Type::Array, {
{ Parse::Type::String, before },
{ Parse::Type::Array, std::vector<Parse::Object>{} }
{ Parse::Type::Array, Vector<Parse::Object>{} }
}});
String inner = tags_match[2].str(); // markupped
// Match markup options
std::vector<Parse::Object> effects{};
Vector<Parse::Object> effects{};
String::const_iterator effects_start(tags_match[1].first);
while (srell::regex_search(effects_start, tags_match[1].second, effects_match, effect)) {
if (effects_match[3].matched) { // no params
@ -376,19 +376,19 @@ namespace {
else { // no params
// Comma split
std::vector<Parse::Object> args;
Vector<Parse::Object> args;
String::const_iterator params_start(effects_match[2].first);
while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) {
size_t temp = 0;
args.push_back(ParseExpression(params_match[1].str() + SEPARATOR.accept[0], temp)); // PeekToken will freak out if I don't do this
params_start = params_match.suffix().first;
}
effects.push_back({ Parse::Type::Array, std::vector<Parse::Object>{ { Parse::Type::String, effects_match[1].str() }, { Parse::Type::Array, args } } });
effects.push_back({ Parse::Type::Array, Vector<Parse::Object>{ { Parse::Type::String, effects_match[1].str() }, { Parse::Type::Array, args } } });
}
effects_start = effects_match.suffix().first;
}
tags_start = tags_match.suffix().first;
segments.push_back({ Parse::Type::Array, std::vector<Parse::Object>{ { Parse::Type::String, inner }, { Parse::Type::Array, effects } } });
segments.push_back({ Parse::Type::Array, Vector<Parse::Object>{ { Parse::Type::String, inner }, { Parse::Type::Array, effects } } });
}
if (has_markup) {
@ -396,15 +396,15 @@ namespace {
if (!end.empty())
segments.push_back({ Parse::Type::Array, {
{ Parse::Type::String, end },
{ Parse::Type::Array, std::vector<Parse::Object>{} }
{ Parse::Type::Array, Vector<Parse::Object>{} }
}});
return { Parse::Type::Array, segments };
}
else {
return { Parse::Type::Array, std::vector<Parse::Object>{
return { Parse::Type::Array, Vector<Parse::Object>{
{ Parse::Type::Array, {
{ Parse::Type::String, s} , { Parse::Type::Array, std::vector<Parse::Object>{} }
{ Parse::Type::String, s} , { Parse::Type::Array, Vector<Parse::Object>{} }
} } }
};
}
@ -489,7 +489,7 @@ namespace NVL::Parse {
if (t != Type::String && t != Type::Symbol) throw std::runtime_error("Bad type when constructing object!");
}
Object::Object(Type t, const std::vector<Object>& v) : type(t), value(v) {
Object::Object(Type t, const Vector<Object>& v) : type(t), value(v) {
if (t != Type::Array && t != Type::Subexpression) throw std::runtime_error("Bad type when constructing object!");
}
@ -500,14 +500,14 @@ namespace NVL::Parse {
if (t != Type::String && t != Type::Symbol) throw std::runtime_error("Bad type when constructing object!");
}
Object::Object(Type t, std::vector<Object>&& v) : type(t), value(std::move(v)) {
Object::Object(Type t, Vector<Object>&& v) : type(t), value(std::move(v)) {
if (t != Type::Array && t != Type::Subexpression) throw std::runtime_error("Bad type when constructing object!");
}
std::vector<Scene> ParseFile(const std::string& path) {
Vector<Scene> ParseFile(const std::string& path) {
String f = read_file_to_string(path);
std::vector<Scene> list {}; // Vector of scenes which each contain a vector of Parses
Vector<Scene> list {}; // Vector of scenes which each contain a vector of Parses
for (size_t i = 0; i < f.length(); i++) {
list.push_back(ParseScene(f, i));
}

View file

@ -1,5 +1,4 @@
#pragma once
#include <vector>
#include <variant>
#include <string>
#include <utility>
@ -13,22 +12,22 @@ namespace NVL::Parse {
Object() = delete;
Object(const Number& v);
Object(Type t, const String& v);
Object(Type t, const std::vector<Object>& v);
Object(Type t, const Vector<Object>& v);
Object(Number&& v);
Object(Type t, String&& v);
Object(Type t, std::vector<Object>&& v);
Object(Type t, Vector<Object>&& v);
Type type;
std::variant<
Number,
String,
std::vector<Object>
Vector<Object>
> value;
};
using Command = std::vector<Object>;
using Command = Vector<Object>;
class Scene {
std::vector<Command> commands{};
Vector<Command> commands{};
public:
String name;
Scene(const String& name) : name(name) {}
@ -43,5 +42,5 @@ namespace NVL::Parse {
}
};
std::vector<Scene> ParseFile(const std::string& path);
Vector<Scene> ParseFile(const std::string& path);
}