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/.vs
NVL/out NVL/out
.cache .cache
vs
**/.DS_STORE

View file

@ -2,18 +2,22 @@
#include "Environment.h" #include "Environment.h"
#include "Graphics.h" #include "Graphics.h"
#include "Track.h" #include "Track.h"
#include "Compiler.h"
#include "Director.h"
#include <SDL2/SDL.h> #include <SDL.h>
#include <SDL2/SDL_main.h> #include <SDL_main.h>
#include <SDL2/SDL_timer.h> #include <SDL_timer.h>
#include <bx/math.h> #include <bx/math.h>
#include <SDL2/SDL_syswm.h> #include <SDL_syswm.h>
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <bgfx/platform.h> #include <bgfx/platform.h>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <fstream>
#include <filesystem> #include <filesystem>
namespace { namespace {
@ -22,23 +26,21 @@ namespace {
u16 window_height = 720; u16 window_height = 720;
u64 init_time, last_time, current_time, delta_t; u64 init_time, last_time, current_time, delta_t;
bool running = false; bool running = false, rolling = true;
bool draw_ui = true; bool draw_ui = true;
bool m_keys[65536]{}; // terrible bool m_keys[65536]{}; // terrible
bool mouse[256]{ true }; // terrible bool mouse[256]{ true }; // terrible
std::vector<NVL::Parse::Scene> scenes; std::unique_ptr<NVL::Director::Director> director;
u32 current_scene = 0;
u32 scene_pos = 0;
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 = {
.current{}, .current{},
.pos_x = 250, .pos_y = 150, .pos_x = 250, .pos_y = 150,
.w = 500, .h = 500, .w = 500, .h = 500,
@ -58,33 +60,12 @@ 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 {
bool Init(std::string name, const std::vector<NVL::Parse::Scene>& sc) { bool Init(std::string name, const NVL::Compiler::NVLGraph& g) {
scenes = sc; // sure make a copy whatever director = std::make_unique<NVL::Director::Director>(g);
if (SDL_Init(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "ADV: Failed to init SDL: " << SDL_GetError() << std::endl; std::cerr << "ADV: Failed to init SDL: " << SDL_GetError() << std::endl;
@ -114,6 +95,7 @@ namespace ADVect {
bgfxInit.platformData.nwh = wmi.info.win.window; bgfxInit.platformData.nwh = wmi.info.win.window;
#elif BX_PLATFORM_OSX #elif BX_PLATFORM_OSX
bgfxInit.platformData.nwh = wmi.info.cocoa.window; bgfxInit.platformData.nwh = wmi.info.cocoa.window;
bgfx::renderFrame();
#elif BX_PLATFORM_LINUX #elif BX_PLATFORM_LINUX
bgfxInit.platformData.ndt = wmi.info.x11.display; bgfxInit.platformData.ndt = wmi.info.x11.display;
bgfxInit.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window; bgfxInit.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window;
@ -140,6 +122,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;
} }
@ -153,21 +139,15 @@ namespace ADVect {
void Advance() { void Advance() {
if (!m_text.transition.done) m_text.transition.done = true; if (!m_text.transition.done) m_text.transition.done = true;
else { else if (director->active) {
size_t curr_size = scenes[current_scene].get().size(); rolling = true;
while (scene_pos < curr_size && std::get<NVL::String>(scenes[current_scene].get()[scene_pos][0].value) != u"Say") { director->Advance();
NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]);
scene_pos++;
}
if (curr_size == scene_pos) {
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++;
}
} }
else
running = false;
if (running && rolling)
Advance();
} }
void Update() { void Update() {
@ -195,28 +175,23 @@ 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);
/* draw_image_transition_crossfade(current_time, bg);
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) { if (draw_ui) {
if (dialogue_bg.current != nullptr) 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); 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);
} }
@ -225,8 +200,7 @@ namespace ADVect {
bgfx::dbgTextPrintf(0, 0, 0xf8, " %u FPS", stat->cpuTimerFreq / stat->cpuTimeFrame); 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, 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, 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, 3, 0xf8, " NVL Director State: %s", NVL::to_std_string(director->description).c_str());
bgfx::dbgTextPrintf(0, 4, 0xf8, " Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str());
bgfx::frame(); bgfx::frame();
} }
@ -271,66 +245,79 @@ namespace ADVect {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
std::filesystem::current_path("E:\\Archive\\Projects\\NouVeL\\ADVect\\runtime"); std::filesystem::current_path("E:\\Archive\\Projects\\NouVeL\\ADVect\\runtime");
//std::filesystem::current_path("/Users/lachrymal/Projects/NouVeL/ADVect/runtime/");
NVL::Environment::ENVIRONMENT.enter({ NVL::Environment::ENVIRONMENT.enter({
{ {
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; rolling = false;
}, 2) return NVL::Environment::Type::Nil;
}, }, 1)
{ },
u"SwitchSpeaker", {
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { u"SwitchSpeaker",
speaker.current = std::get<NVL::String>(NVL::Environment::Variable(args[0]).value); NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
return NVL::Environment::Type::Nil; speaker.current = std::get<NVL::String>(args[0].value);
}, 1) return NVL::Environment::Type::Nil;
}, }, 1)
/* { },
u"ImageTrack", {
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { u"BG",
add_image_track(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value))); NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
return NVL::Environment::Type::Nil; bg.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value))), 200);
}, 1) return NVL::Environment::Type::Nil;
},*/ }, 1)
{ },
u"Show", {
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { u"Avatar",
std::string name = NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value)); NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
/* NamedImageTrack* t = find_image_track(name); avatar.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value))), 200);
if (t == nullptr) { return NVL::Environment::Type::Nil;
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; }, 1)
} },
else { {
auto s = std::get<NVL::String>(NVL::Environment::Variable(args[1]).value); u"BGDialogue",
auto s2 = NVL::to_std_string(s); NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
t->current = ADVect::Graphics::GetImageTextureFromFile(s2); dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(args[0].value)));
}*/ return NVL::Environment::Type::Nil;
if (name == "BG") }, 1)
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); u"Show",
else if (name == "BGDialogue") NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value))); std::get<std::function<NVL::Environment::Variable(std::vector<NVL::Environment::Variable>)>>(args[0].value)({args[1]});
else return NVL::Environment::Type::Nil;
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; }, 2)
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;
} }
});
if (!ADVect::Init("ADV Test", SCENES)) 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;
//}
//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::Run();
ADVect::Shutdown(); ADVect::Shutdown();
return EXIT_SUCCESS; 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,16 +5,20 @@ 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/")
add_subdirectory("ext/freetype") add_subdirectory("ext/freetype")
add_subdirectory("ext/bgfx") add_subdirectory("ext/bgfx")
if (WIN32) 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) 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 () else ()
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
target_link_libraries (Game PRIVATE NVL freetype bgfx bx SDL2::SDL2 SDL2::SDL2main) target_link_libraries (Game PRIVATE NVL freetype bgfx bx SDL2::SDL2 SDL2::SDL2main)
endif () endif ()

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,29 +73,48 @@ namespace {
struct Font { struct Font {
FT_Face face = nullptr; FT_Face face = nullptr;
std::unordered_map<NVL::Char, bgfx::TextureHandle> cache{}; std::unordered_map<NVL::Char, std::tuple<std::optional<bgfx::TextureHandle>, u32, u32, i32, i32, i32, i32>> cache{};
void cache_char(NVL::Char c) { std::tuple<std::optional<bgfx::TextureHandle>, u32, u32, i32, i32, i32, i32>& get_char(NVL::Char c) {
FT_GlyphSlot slot = face->glyph; if (cache.find(c) == cache.end()) {
FT_GlyphSlot slot = face->glyph;
error = FT_Load_Char(face, c, FT_LOAD_RENDER); error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if (error) { if (error) {
std::cerr << "ADV: Failed to load character" << std::endl; std::cerr << "ADV: Failed to load character" << std::endl;
} }
if (cache.find(c) == cache.end() && slot->bitmap.width != 0) { if (slot->bitmap.width != 0) {
const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows); const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows);
cache.emplace(c, bgfx::createTexture2D( cache.emplace(c, std::make_tuple(
slot->bitmap.width, bgfx::createTexture2D(
slot->bitmap.rows, slot->bitmap.width,
false, slot->bitmap.rows,
1, false,
bgfx::TextureFormat::A8, 1,
BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP, bgfx::TextureFormat::A8,
buf BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP,
)); buf
),
slot->bitmap.width,
slot->bitmap.rows,
slot->bitmap_left,
slot->bitmap_top,
slot->advance.x,
slot->advance.y
));
}
else cache.emplace(c, std::make_tuple(
std::nullopt,
0,
0,
0,
0,
slot->advance.x,
slot->advance.y));
} }
return cache[c];
} }
}; };
@ -124,12 +143,13 @@ 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);
} }
} }
inline bgfx::ProgramHandle load_shader_program(const std::string& shader) { 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) { std::optional<ImageTexture> get_image_texture(const std::string& file) {
@ -179,7 +199,20 @@ namespace {
} }
return f; return f;
} }
inline void HandleMarkupFlags(const NVL::Environment::MarkupSegment& s, u32& style_flags, const NVL::String*& ruby) {
for (const auto& e : s.efs) {
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; }
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; }
else if (e.first == u"rb") { ruby = &e.second[0]; }
else {
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
}
}
}
} }
namespace ADVect::Graphics { namespace ADVect::Graphics {
@ -200,7 +233,7 @@ namespace ADVect::Graphics {
ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices))); ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices)));
vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl); 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 imga_program = load_shader_program("ImageAlpha"); // RGBA + Opacity
a_program = load_shader_program("AlphaStencil"); // A -> FFFA a_program = load_shader_program("AlphaStencil"); // A -> FFFA
@ -220,7 +253,7 @@ namespace ADVect::Graphics {
} }
bgfx::destroy(a_program); bgfx::destroy(a_program);
bgfx::destroy(img_program); //bgfx::destroy(img_program);
bgfx::destroy(imga_program); bgfx::destroy(imga_program);
bgfx::destroy(ibh); 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); 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); 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) { for (const auto& c : s) {
f->cache_char(c); RenderGlyph<DoRender>(c, pos_x, pos_y, col, style_flags);
pos_x += slot->bitmap_left;
f32 ypos = pos_y - (slot->bitmap.rows - slot->bitmap_top);
if (slot->bitmap.width != 0) {
DrawTextureStencilAlpha((f->cache)[c], pos_x, ypos, slot->bitmap.width, slot->bitmap.rows);
}
pos_x += slot->advance.x >> 6;
pos_y += slot->advance.y >> 6;
} }
} }
void StringWalk(const NVL::String& s, i32& pos_x, u32 style_flags = TEXT_NONE) { template <bool DoRender, bool Walk>
Font* f = ResolveStyleFlags(style_flags); void RenderString(NVL::String::const_iterator cbegin, NVL::String::const_iterator cend, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags) {
while (cbegin < cend) {
FT_GlyphSlot& slot = f->face->glyph; RenderGlyph<DoRender>(*cbegin++, pos_x, pos_y, col, style_flags);
for (const auto& c : s) {
f->cache_char(c);
pos_x += slot->bitmap_left;
pos_x += slot->advance.x >> 6;
} }
} }
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) { void RenderStringCentered(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags = TEXT_NONE) {
RenderStringWalk(s, pos_x, pos_y, col, style_flags); i32 copy_x = 0, copy_y = 0;
RenderString<false, true>(s, copy_x, copy_y, col, style_flags);
RenderString<true, false>(s, pos_x - copy_x / 2, pos_y, col, style_flags);
} }
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags = TEXT_NONE) { // I cannot reason this function, returns where the string would end if it was not halted
i32 RenderSubstringBox(const NVL::String& s, i32& pos_x, i32& pos_y, i32 reset_x, u32 w, u32 col, u32 style_flags, size_t s_end) {
Font* f = ResolveStyleFlags(style_flags); Font* f = ResolveStyleFlags(style_flags);
i32 init_x = pos_x; NVL::String::const_iterator last = s.cbegin(), end = s.cend(), pos = std::find(last, end, u' '),
size_t last = 0, pos = s.find(u' '); halt = s_end > s.length() ? end : last + s_end;
if (pos == NVL::String::npos) if (pos == end) { // Render the entire thing with hard break if we don't split at all
RenderStringWalk(s, pos_x, pos_y, col, style_flags); NVL::String::const_iterator last_copy = last;
else { i32 copy_x = pos_x, copy_y = pos_y;
while (last != NVL::String::npos) { while (last != std::min(pos, halt)) {
NVL::String sub = s.substr(last, pos - last); RenderGlyph(*last++, pos_x, pos_y, col, style_flags);
i32 copy_x = pos_x; if (pos_x - reset_x > w) {
StringWalk(sub, copy_x, style_flags); pos_x = reset_x;
if (copy_x - init_x > w) {
pos_x = init_x;
pos_y -= f->face->size->metrics.height / 64; pos_y -= f->face->size->metrics.height / 64;
sub.erase(sub.begin());
} }
RenderStringWalk(sub, pos_x, pos_y, col, style_flags); if (last >= halt) {
last = pos; RenderString<false>(last_copy, pos, copy_x, copy_y, col, style_flags);
pos = s.find(u' ', pos + 1); return copy_x;
};
} }
} }
} else while (last != end) { // Loop through all segments
i32 copy_x = pos_x, old_x = pos_x, copy_y = pos_y;
RenderString<false>(last, pos, copy_x, copy_y, col, style_flags);
if (copy_x - reset_x > w) { // if walk exceeded max w
copy_x = reset_x, copy_y = pos_y; // try walk again from leftmost of box, see if a soft break works; reset y from last walk
RenderString<false>(last, pos, copy_x, copy_y, col, style_flags);
if (copy_x - reset_x > w) { // soft break won't work, go back to old x and hard break
pos_x = old_x;
while (last != pos) {
RenderGlyph(*last++, pos_x, pos_y, col, style_flags);
if (pos_x - reset_x > w) {
pos_x = reset_x;
pos_y -= f->face->size->metrics.height / 64;
}
if (last >= halt) return copy_x;
}
}
else { // soft break and kill beginning space
pos_x = reset_x;
pos_y -= f->face->size->metrics.height / 64;
last++;
RenderString(last, std::min(pos, halt), pos_x, pos_y, col, style_flags);
if (last >= halt) return copy_x;
}
}
else {
RenderString(last, std::min(pos, halt), pos_x, pos_y, col, style_flags);
if (last >= halt) return copy_x;
}
void RenderStringMarkup(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 col) { last = pos;
if (pos != end)
pos = std::find(std::next(pos), end, u' ');
}
return pos_x;
}
void RenderSubstringMarkupBox(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col, size_t end) {
i32 init_x = pos_x;
size_t acc_length = 0;
// We assume markups are already sorted // We assume markups are already sorted
for (const NVL::Environment::MarkupSegment& s : ms.segments) { for (const NVL::Environment::MarkupSegment& s : ms.segments) {
u32 style_flags = TEXT_NONE; u32 style_flags = TEXT_NONE;
const NVL::String* ruby = nullptr; const NVL::String* ruby = nullptr;
HandleMarkupFlags(s, style_flags, ruby);
for (const auto& e : s.efs) { i32 last_x = pos_x,
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; } segment_end = RenderSubstringBox(s.str, pos_x, pos_y, init_x, w, col, style_flags, end - acc_length);
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; } if (ruby != nullptr && segment_end != last_x) {
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; } RenderStringCentered(*ruby, segment_end / 2 + last_x / 2, i32(pos_y + 20), col);
else if (e.first == u"rb") { ruby = &e.second[0]; }
else {
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
}
} }
if (ruby != nullptr) { acc_length += s.str.length();
RenderString(*ruby, pos_x, pos_y + 20, col); if (acc_length > end) return;
}
RenderStringWalk(s.str, pos_x, pos_y, col, style_flags);
}
}
void RenderStringMarkupWrap(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col) {
// We assume markups are already sorted
for (const NVL::Environment::MarkupSegment& s : ms.segments) {
u32 style_flags = TEXT_NONE;
const NVL::String* ruby = nullptr;
for (const auto& e : s.efs) {
if (e.first == u"b") { style_flags |= TEXT_BOLD; }
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
else if (e.first == u"s") { style_flags |= TEXT_STRIKETHROUGH; }
else if (e.first == u"o") { style_flags |= TEXT_OVERLINE; }
else if (e.first == u"rb") { ruby = &e.second[0]; }
else {
std::cerr << "ADV: Unrecognized text markup: " << NVL::to_std_string(e.first) << std::endl;
}
}
if (ruby != nullptr) {
RenderString(*ruby, pos_x, pos_y + 20, col);
}
RenderStringWrapWalk(s.str, pos_x, pos_y, w, col, style_flags);
} }
} }

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <SDL2/SDL.h> #include <SDL.h>
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
@ -32,10 +32,14 @@ namespace ADVect::Graphics {
void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y); void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y);
void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha); void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha);
void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h); void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h);
template <bool DoRender = true, bool Walk = true>
void RenderGlyph(NVL::Char c, std::conditional_t<Walk, i32&, i32> pos_x, std::conditional_t<Walk, i32&, i32> pos_y, u32 col, u32 style_flags = 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);
void RenderStringWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 col, u32 style_flags); i32 RenderSubstringBox(const NVL::String& s, i32& pos_x, i32& pos_y, i32 reset_x, u32 w, u32 col, u32 style_flags = TEXT_NONE, size_t s_end = NVL::String::npos);
void RenderStringWrapWalk(const NVL::String& s, i32& pos_x, i32& pos_y, u32 w, u32 col, u32 style_flags); void RenderSubstringMarkupBox(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col, size_t end = NVL::String::npos);
void RenderString(const NVL::String& s, i32 pos_x, i32 pos_y, u32 col, u32 style_flags);
void RenderStringMarkup(const NVL::Environment::MarkupString& s, i32 pos_x, i32 pos_y, u32 col);
void RenderStringMarkupWrap(const NVL::Environment::MarkupString& ms, i32 pos_x, i32 pos_y, u32 w, u32 col);
} }

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> 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{};
[[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 // Visual
[[no_unique_address]] std::conditional_t<IsVisual, i32, std::monostate> pos_x{}, pos_y{}; // [[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, u32, std::monostate> w{}, h{};
[[no_unique_address]] std::conditional_t<IsVisual, f32, std::monostate> opacity{}; // [[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 // TODO other transforms
// Fill // Fill
static_assert(IsVisual || !IsVisualFill, "Track cannot have fill unless visual"); 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{}; // Transition, with assumption that we need to access the original when transition is underway
[[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 { void check(u64 current_time) requires HasTransition {
if constexpr (UsePointer) { if constexpr (UsePointer) {
if (next != nullptr && transition.check(current_time)) { if (next != nullptr && transition.check(current_time)) {
@ -103,9 +109,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) {
@ -126,7 +132,7 @@ namespace ADVect {
ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.transition.get(current_time)); ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.transition.get(current_time));
} }
else { 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,17 +1,16 @@
BEGIN Inferno BEGIN Inferno
ImageTrack BG
Show BG "image.png" Show BG "image.png"
Show BGDialogue "grad.png"
<<- <<-
[] []
由我这里,直通[b]{悲惨之城}。 由我这里,直通[b]{悲惨之城}。
由我这里,直通[b]{无尽之苦}。 由我这里,直通[b]{无尽之苦}。
由我这里,直通[b]{堕落众生}。 由我这里,直通[b]{堕落众生}。
圣裁于高天激发造我的君主; 圣裁于高天激发造我的君主;
造我的大能是[b, rb("C")]{神}的力量,是无上的[b, rb(" L L V M")]{智慧与众爱}所自出。 造我的大能是[b, rb("C")]{神}的力量,是无上的[b, rb("L L V M")]{智慧与众爱}所自出。
我永远不朽;在我之前,万象 未形,只有永恒的事物存在。 我永远不朽;在我之前,万象 未形,只有永恒的事物存在。
来者呀,快把一切希望弃扬。 来者呀,快把一切希望弃扬。
我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。 我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。
老师呀,讲得真可骇。
[维吉尔] [维吉尔]
一切疑虑,必须在这里摆脱。 一切疑虑,必须在这里摆脱。
一切怯懦,必须在这里结束。 一切怯懦,必须在这里结束。
@ -32,4 +31,4 @@ Show BG "image.png"
这些天使,不是上帝的叛徒或信徒;他们为私利而自成一帮。 这些天使,不是上帝的叛徒或信徒;他们为私利而自成一帮。
天穹嫌他们不够好,把他们放逐; 深坑呢,又不愿给他们栖身之地,怕坏人因此而显得光荣突出。 天穹嫌他们不够好,把他们放逐; 深坑呢,又不愿给他们栖身之地,怕坏人因此而显得光荣突出。
->> ->>
END END

View file

@ -1,6 +1,6 @@
BEGIN Inferno BEGIN Inferno
ImageTrack BG // ImageTrack BG
Show BG "image.png" Show BG "image.png"
<<- <<-
@ -49,4 +49,4 @@ Die Himmel trieben sie als Mißzier aus,
Und da durch sie der Sünder Stolz erstünde, Und da durch sie der Sünder Stolz erstünde,
Nimmt sie nicht ein der tiefen Hölle Graus. Nimmt sie nicht ein der tiefen Hölle Graus.
->> ->>
END END

View file

@ -1,4 +1,4 @@
BEGIN Scene1 BEGIN Scene1
Show BG "image.png" Show BG "image.png"
Show BGDialogue "grad.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. When the system reboots, you will see a prompt asking you to install a new program.
Type "Y" and press ENTER. Type "Y" and press ENTER.
The Google search engine will come up. Type in "www.yahoo.com" and hit 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 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 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. Go to your inbox and click on the link to download the latest version of Google Chrome.
Install the update. 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 import subprocess, os
SHADERC = "..\\out\\install\\x64-Debug\\bin\\shaderc" #SHADERC = "..\\out\\install\\x64-Debug\\bin\\shaderc"
OUT = "..\\out\\build\\x64-Debug\\ADVect\\shaders\\" SHADERC = "/Users/lachrymal/Projects/NouVeL/build/ADVect/ext/bgfx/Debug/shaderc"
#OUT = "..\\out\\build\\x64-Debug\\ADVect\\shaders\\"
# OUT = "..\\build\\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 = [ plats = [
P('glsl', '140', '140'), # P('glsl', 'windows', '140', '140'),
P('dx11', 'ps_5_0', 'vs_5_0'), # P('dx11', 'windows', 'ps_5_0', 'vs_5_0'),
P('spirv', 'spirv', 'spirv') # P('spirv', 'windows', 'spirv', 'spirv'),
P('metal', 'osx', 'metal', 'metal')
] ]
for root, dirs, _ in os.walk('shaders'): for root, dirs, _ in os.walk('shaders'):
for name in dirs: for name in dirs:
for config in plats: for config in plats:
subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.frag'), subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.frag'),
"--type", "fragment" "--type", "fragment",
"--platform", "windows", "--platform", config['platform'],
"--profile", config['frag'], "--profile", config['frag'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"), "--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/examples/common",
"-i", "ext\\bgfx\\bgfx\\src", "-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/src",
"-o", OUT + config['location'] + "\\" + name + ".frag.bin"]) "-o", OUT + config['location'] + "\\" + name + ".frag.bin"])
subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.vert'), subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.vert'),
"--type", "vertex" "--type", "vertex",
"--platform", "windows", "--platform", config['platform'],
"--profile", config['vert'], "--profile", config['vert'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"), "--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/examples/common",
"-i", "ext\\bgfx\\bgfx\\src", "-i", "/Users/lachrymal/Projects/NouVeL/ADVect/ext/bgfx/bgfx/src",
"-o", OUT + config['location'] + "\\" + name + ".vert.bin"]) "-o", OUT + config['location'] + "\\" + name + ".vert.bin"])

View file

@ -17,7 +17,9 @@
}, },
"vendor": { "vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [ "Windows" ] "hostOS": [
"Windows"
]
} }
} }
}, },
@ -33,12 +35,23 @@
}, },
"vendor": { "vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": { "microsoft.com/VisualStudioSettings/CMake/1.0": {
"hostOS": [ "Linux" ] "hostOS": [
"Linux"
]
}, },
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" "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) project (NVL)
include_directories("include") 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" ) # add_executable (NVL "NouVeL.cpp" "Parser.cpp" "Environment.cpp" "Environment.h" "Common.h" )
# TODO: Add tests and install targets if needed. # TODO: Add tests and install targets if needed.

View file

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

View file

@ -6,20 +6,20 @@
#include "Common.h" #include "Common.h"
namespace NVL::Environment { namespace NVL::Environment {
enum class Type { Procedure, Number, String, Array, Nil }; enum class Type { Nil, StaticReference, Procedure, Number, String, Array };
struct Variable { struct Variable {
Type type; 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 // Most things will have length 1 (including string); this is mostly for function arity and array length
u32 length; u32 length;
bool operator==(const Variable& other) const; bool operator==(const Variable& other) const;
Variable(); // Makes Nil, length 0 Variable(); // Makes Nil, length 0
Variable(Type t); // Reserved for Nil Variable(Type t); // Reserved for Nil
Variable(const Number& v); Variable(const Number& v, bool is_ref = false);
Variable(const String& v); Variable(const String& v);
Variable(const std::vector<Variable>& v); Variable(const Vector<Variable>& v);
Variable(const std::function<Variable(std::vector<Variable>)>& v, u32 l); Variable(const std::function<Variable(Vector<Variable>)>& v, u32 l);
}; };
class Environment { class Environment {
@ -29,7 +29,7 @@ namespace NVL::Environment {
void enter(const String& name, Variable p); void enter(const String& name, Variable p);
void enter(std::initializer_list<std::pair<String, Variable>> p); void enter(std::initializer_list<std::pair<String, Variable>> p);
void set(const String& name, 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); bool exists(const String& name);
}; };
@ -41,15 +41,15 @@ namespace NVL::Environment {
struct MarkupSegment { struct MarkupSegment {
String str; String str;
std::vector<std::pair<String, std::vector<String>>> efs; Vector<std::pair<String, Vector<String>>> efs;
}; };
struct MarkupString { struct MarkupString {
private: private:
mutable i32 mem_length = -1; mutable i32 mem_length = -1;
public: public:
std::vector<MarkupSegment> segments{}; Vector<MarkupSegment> segments{};
size_t length() const; size_t length() const;
MarkupString substr(size_t idx) 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()); return to_NVL_string(buffer.str());
} }
std::vector<String> split_string_by_lines(const String& str) { Vector<String> split_string_by_lines(const String& str) {
std::vector<String> lines; Vector<String> lines;
size_t pos = 0; size_t pos = 0;
size_t prev = 0; size_t prev = 0;
while ((pos = str.find(NEWLINE, prev)) != String::npos) { while ((pos = str.find(NEWLINE, prev)) != String::npos) {
@ -230,7 +230,7 @@ namespace {
Parse::Object ParseArray(const String& f, size_t& pos, u32 layer) { Parse::Object ParseArray(const String& f, size_t& pos, u32 layer) {
SkipComments(f, pos); SkipComments(f, pos);
std::vector<Parse::Object> array{}; Vector<Parse::Object> array{};
array.push_back(ParseExpression(f, pos)); array.push_back(ParseExpression(f, pos));
while (PeekToken(f, pos)[0] != ARRAY_CLOSE) { while (PeekToken(f, pos)[0] != ARRAY_CLOSE) {
@ -246,7 +246,7 @@ namespace {
String ParseString(const String& f, size_t& pos) { String ParseString(const String& f, size_t& pos) {
SkipComments(f, pos); SkipComments(f, pos);
std::vector<size_t> discards{}; Vector<size_t> discards{};
auto start = ++pos; // skip opening quote auto start = ++pos; // skip opening quote
do { do {
if (f[pos] == QUOTE) { if (f[pos] == QUOTE) {
@ -352,7 +352,7 @@ namespace {
bool has_markup = false; bool has_markup = false;
// Match tags // Match tags
std::vector<Parse::Object> segments; Vector<Parse::Object> segments;
String::const_iterator tags_start(s.cbegin()); String::const_iterator tags_start(s.cbegin());
while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) { while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) {
has_markup = true; has_markup = true;
@ -361,13 +361,13 @@ namespace {
if (!before.empty()) if (!before.empty())
segments.push_back({ Parse::Type::Array, { segments.push_back({ Parse::Type::Array, {
{ Parse::Type::String, before }, { Parse::Type::String, before },
{ Parse::Type::Array, std::vector<Parse::Object>{} } { Parse::Type::Array, Vector<Parse::Object>{} }
}}); }});
String inner = tags_match[2].str(); // markupped String inner = tags_match[2].str(); // markupped
// Match markup options // Match markup options
std::vector<Parse::Object> effects{}; Vector<Parse::Object> effects{};
String::const_iterator effects_start(tags_match[1].first); String::const_iterator effects_start(tags_match[1].first);
while (srell::regex_search(effects_start, tags_match[1].second, effects_match, effect)) { while (srell::regex_search(effects_start, tags_match[1].second, effects_match, effect)) {
if (effects_match[3].matched) { // no params if (effects_match[3].matched) { // no params
@ -376,19 +376,19 @@ namespace {
else { // no params else { // no params
// Comma split // Comma split
std::vector<Parse::Object> args; Vector<Parse::Object> args;
String::const_iterator params_start(effects_match[2].first); String::const_iterator params_start(effects_match[2].first);
while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) { while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) {
size_t temp = 0; 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 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; 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; effects_start = effects_match.suffix().first;
} }
tags_start = tags_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) { if (has_markup) {
@ -396,15 +396,15 @@ namespace {
if (!end.empty()) if (!end.empty())
segments.push_back({ Parse::Type::Array, { segments.push_back({ Parse::Type::Array, {
{ Parse::Type::String, end }, { Parse::Type::String, end },
{ Parse::Type::Array, std::vector<Parse::Object>{} } { Parse::Type::Array, Vector<Parse::Object>{} }
}}); }});
return { Parse::Type::Array, segments }; return { Parse::Type::Array, segments };
} }
else { else {
return { Parse::Type::Array, std::vector<Parse::Object>{ return { Parse::Type::Array, Vector<Parse::Object>{
{ Parse::Type::Array, { { 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!"); 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!"); 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!"); 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!"); 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); 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++) { for (size_t i = 0; i < f.length(); i++) {
list.push_back(ParseScene(f, i)); list.push_back(ParseScene(f, i));
} }

View file

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