diff --git a/.gitignore b/.gitignore index 868fc63..6405e25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vs +.vscode out build NVL/.vs diff --git a/ADVect/ADVect.cpp b/ADVect/ADVect.cpp index 8373258..6f79a90 100644 --- a/ADVect/ADVect.cpp +++ b/ADVect/ADVect.cpp @@ -1,38 +1,176 @@ #include "ADVect.h" +#include "Common.h" +#include "Environment.h" #include "Graphics.h" +#include "SDL2/SDL_thread.h" +#include "SDL2/SDL_timer.h" +#include +#include #include #include #include -#include +#include +#include #include +#include namespace { + template + struct Track { + T current; + }; + + template + concept IsTrack = requires (const TR& t) { + std::is_same_v; + }; + + template + concept IsNamedTrack = IsTrack && requires (const TR& t) { + std::is_same_v; + }; + + template requires(!IsNamedTrack) + struct NamedTrack : TR { + std::string name; + }; + + template TR> + struct VisualTrack : TR { + i32 pos_x = 0, pos_y = 0; + u32 w = 500, h = 500; + f32 opacity = 1.0f; + // TODO other transforms + }; + + template TR> + struct FillTrack : TR { + i32 pos_x = 0, pos_y = 0; + u32 w = 500, h = 500; + f32 opacity = 1.0f; + u32 fill = 0xFFFFFFFF; + }; + + /* TODO impl + struct AudioTrack {}; + */ + + using TextTrack = FillTrack>; + using MarkupTextTrack = FillTrack>; + using NamedImageTrack = VisualTrack>>; + /* TODO VideoTrack */ + SDL_Window* window; - - std::string m_name; + u16 window_width = 1280; + u16 window_height = 720; + bool running = false; - u16 m_width = 1280; - u16 m_height = 720; - bool m_keys[65536]{}; - std::vector scenes; - u32 current_scene = 0; - std::vector m_text{}; - NVL::String speaker; - u32 scene_pos = 0; + u64 init_time, last_time, current_time, delta_t; - struct ImageTrack { - std::string name; - ADVect::Graphics::ImageTexture* current = nullptr; - i32 pos_x = 0, pos_y = 0; + template + struct Varying { + u64 begin, duration; + std::function interp; + bool done = true; + + T get() const { + if (done) + return interp(1.f); + else + return interp((current_time - begin) / static_cast(duration)); + } + void kickoff(u64 dur, const std::function& f = [](NVL::Number x) { return static_cast(x); }) { + begin = current_time; + done = false; + duration = dur; + interp = f; + } + bool check() { + if (done) return true; + else if (current_time >= begin + duration) { + done = true; + return true; + } + else return false; + } }; - std::vector tracks_img{}; - ImageTrack* find_image_track(const std::string& s) { + struct NamedImageTransitionTrack : NamedImageTrack { + ADVect::Graphics::ImageTexture* next = nullptr; + Varying anim; + std::function draw; + + void check() { + if (next != nullptr && anim.check()) { + current = next; + next = nullptr; + } + } + void change(ADVect::Graphics::ImageTexture* n, u64 dur, const std::function& f = [](NVL::Number x) { return x; }) { + if (current == nullptr) + current = n; + else if (n == nullptr) current = n; + else { + next = n; + anim.kickoff(dur, f); + } + } + }; + + struct TypewriterMarkupTextTrack : MarkupTextTrack { + Varying anim; + void check() { anim.check(); } + void change(const NVL::Environment::MarkupString& n, u16 speed) { + current = n; + anim.kickoff(speed * n.length(), [n](NVL::Number x) { return static_cast(x * n.length()); }); + } + void draw() { + if (anim.done) + ADVect::Graphics::RenderStringMarkup(current, pos_x, pos_y, fill); + else + ADVect::Graphics::RenderStringMarkup(current.substr(anim.get()), pos_x, pos_y, fill); + } + }; + + void draw_image_transition_fade(const NamedImageTransitionTrack& t) { + if (t.current != nullptr) { + if (t.next != nullptr) { + ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); + ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.anim.get()); + } + else { + ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); + } + } + } + void draw_image_transition_crossfade(const NamedImageTransitionTrack& t) { + if (t.current != nullptr) { + if (t.next != nullptr) { + ADVect::Graphics::DrawTextureImageAlpha(*t.current, t.pos_x, t.pos_y, 1.0f - t.anim.get()); + ADVect::Graphics::DrawTextureImageAlpha(*t.next, t.pos_x, t.pos_y, t.anim.get()); + } + else { + ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); + } + } + } + + std::vector scenes; + u32 current_scene = 0; + u32 scene_pos = 0; + + TypewriterMarkupTextTrack m_text{ { {}, 280, 90 } }; + TextTrack speaker { u"", 250, 150 }; + NamedImageTransitionTrack bg, avatar; + NamedImageTrack dialogue_bg; + /* + std::list 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; @@ -42,7 +180,7 @@ namespace { } bool add_image_track(const std::string& s) { if (find_image_track(s) == nullptr) { - ImageTrack t; + NamedImageTrack t; t.name = s; tracks_img.push_back(std::move(t)); return true; @@ -50,11 +188,12 @@ namespace { std::cerr << "ADV: Redefinition of ImageTrack " << s << std::endl; return false; } + */ + } namespace ADVect { bool Init(std::string name, const std::vector& sc) { - m_name = name; scenes = sc; // sure make a copy whatever if (SDL_Init(SDL_INIT_VIDEO)) { @@ -62,7 +201,7 @@ namespace ADVect { return false; } - window = SDL_CreateWindow(m_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_width, m_height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); + window = SDL_CreateWindow(name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_width, window_height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (window == NULL) { std::cerr << "ADV: Failed to create window: " << SDL_GetError() << std::endl; return false; @@ -70,8 +209,8 @@ namespace ADVect { bgfx::Init bgfxInit; bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer. - bgfxInit.resolution.width = m_width; - bgfxInit.resolution.height = m_height; + bgfxInit.resolution.width = window_width; + bgfxInit.resolution.height = window_height; bgfxInit.resolution.reset = BGFX_RESET_VSYNC; #if !BX_PLATFORM_EMSCRIPTEN @@ -98,19 +237,22 @@ namespace ADVect { }; bgfx::setDebug(BGFX_DEBUG_TEXT); bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443322ff, 1.0f, 0); - bgfx::setViewRect(0, 0, 0, m_width, m_height); + bgfx::setViewRect(0, 0, 0, window_width, window_height); bgfx::setViewMode(0, bgfx::ViewMode::Sequential); float view[16]; bx::mtxTranslate(view, 0.f, 0.f, 1.0f); float proj[16]; - bx::mtxOrtho(proj, 0.0f, m_width, 0.0f, m_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); + bx::mtxOrtho(proj, 0.0f, window_width, 0.0f, window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); bgfx::setViewTransform(0, view, proj); - if (!ADVect::Graphics::Init(m_width, m_height)) { + if (!ADVect::Graphics::Init(window_width, window_height)) { std::cerr << "ADV: Graphics init failed" << std::endl; return false; } + bg.draw = draw_image_transition_fade; + avatar.draw = draw_image_transition_crossfade; + Advance(); return true; } @@ -143,31 +285,45 @@ namespace ADVect { Advance(); m_keys[SDL_SCANCODE_SPACE] = false; } + bg.check(); + avatar.check(); + m_text.check(); } 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); } - ADVect::Graphics::RenderString(speaker, 250, 150, 0xFFFFFFFF, ADVect::Graphics::TEXT_BOLD); - ADVect::Graphics::RenderStringMarkup(m_text, 300, 90, 0xFFFFFFFF); + */ + bg.draw(bg); + if (dialogue_bg.current != nullptr) + ADVect::Graphics::DrawTextureImage(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y); + avatar.draw(avatar); + ADVect::Graphics::RenderString(speaker.current, speaker.pos_x, speaker.pos_y, speaker.fill, ADVect::Graphics::TEXT_BOLD); + m_text.draw(); bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 44, 0xF8, "NouVeL x ADVect :: %s :: %s %s", BX_COMPILER_NAME, __DATE__, __TIME__); - bgfx::dbgTextPrintf(0, 43, 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, 42, 0xF8, "Current Position: %u", scene_pos); - bgfx::dbgTextPrintf(0, 41, 0xF8, "Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str()); + bgfx::dbgTextPrintf(0, 0, 0xf8, "NouVeL x ADVect :: %s :: %s %s", BX_COMPILER_NAME, __DATE__, __TIME__); + bgfx::dbgTextPrintf(0, 1, 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, "Current Position: %u", scene_pos); + bgfx::dbgTextPrintf(0, 3, 0xf8, "Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str()); bgfx::frame(); } void Run() { + last_time = init_time = SDL_GetTicks64(); + running = true; while (running) { + current_time = SDL_GetTicks64(); + delta_t = current_time - last_time; + for (SDL_Event event; SDL_PollEvent(&event);) { switch (event.type) { case SDL_QUIT: @@ -184,40 +340,42 @@ namespace ADVect { } Update(); Render(); + + last_time = current_time; } } } int main(int argc, char* argv[]) { - const std::string PJ_DIR = "..\\..\\..\\..\\NVL\\"; + const std::string PJ_DIR = "E:\\Archive\\Projects\\NouVeL\\NVL\\"; NVL::Environment::ENVIRONMENT.enter({ { u"Say", NVL::Environment::Variable([](std::vector args) { - m_text = args; + m_text.change(NVL::Environment::UnpackMarkupVariable(std::get>(NVL::Environment::Variable(args[0]).value)), 10); return NVL::Environment::Type::Nil; }, 2) }, { u"SwitchSpeaker", NVL::Environment::Variable([](std::vector args) { - speaker = std::get(NVL::Environment::Variable(args[0]).value); + speaker.current = std::get(NVL::Environment::Variable(args[0]).value); return NVL::Environment::Type::Nil; }, 1) }, - { +/* { u"ImageTrack", NVL::Environment::Variable([](std::vector args) { add_image_track(NVL::to_std_string(std::get(NVL::Environment::Variable(args[0]).value))); return NVL::Environment::Type::Nil; }, 1) - }, + },*/ { u"Show", NVL::Environment::Variable([](std::vector args) { std::string name = NVL::to_std_string(std::get(NVL::Environment::Variable(args[0]).value)); - ImageTrack* t = find_image_track(name); +/* NamedImageTrack* t = find_image_track(name); if (t == nullptr) { std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; } @@ -225,16 +383,27 @@ int main(int argc, char* argv[]) { auto s = std::get(NVL::Environment::Variable(args[1]).value); auto s2 = NVL::to_std_string(s); t->current = ADVect::Graphics::GetImageTextureFromFile(s2); - } + }*/ + if (name == "BG") + bg.change(ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(NVL::Environment::Variable(args[1]).value))), 200); + else if (name == "Avatar") + avatar.change(ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(NVL::Environment::Variable(args[1]).value))), 200); + else if (name == "BGDialogue") + dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(NVL::Environment::Variable(args[1]).value))); + else + std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; return NVL::Environment::Type::Nil; }, 2) - } + } }); std::vector SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl"); - if (SCENES.empty()) return EXIT_FAILURE; + if (SCENES.empty()) { + std::cerr << "ADV: Empty NVL parse, check file" << std::endl; + return EXIT_FAILURE; + } - if (!ADVect::Init("ADV", SCENES)) return EXIT_FAILURE; + if (!ADVect::Init("ADV Test", SCENES)) return EXIT_FAILURE; ADVect::Run(); ADVect::Shutdown(); diff --git a/ADVect/ADVect.h b/ADVect/ADVect.h index c89cf40..d20d537 100644 --- a/ADVect/ADVect.h +++ b/ADVect/ADVect.h @@ -1,9 +1,9 @@ +#pragma once + #include #include #include -#include - #include #include diff --git a/ADVect/Bindings.cpp b/ADVect/Bindings.cpp deleted file mode 100644 index 497142d..0000000 --- a/ADVect/Bindings.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -namespace ADVect { - void bind_NVL() { - auto f = [](NVL::Environment::Variable x) { - return NVL::Environment::Variable(NVL::Environment::Type::Nil); - }; - NVL::Environment::ENVIRONMENT.enter(u"Hello", { f, 1 }); - NVL::Environment::ENVIRONMENT.enter(u"Command", { f, 1 }); - NVL::Environment::ENVIRONMENT.enter(u"Do", { f, 2 }); - NVL::Environment::ENVIRONMENT.enter(u"Set", { f, 2 }); - NVL::Environment::ENVIRONMENT.enter(u"This", { f, 1 }); - NVL::Environment::ENVIRONMENT.enter(u"ClearDialog", { f, 0 }); - NVL::Environment::ENVIRONMENT.enter(u"Choice", { f, 2 }); - NVL::Environment::ENVIRONMENT.enter(u"=?", { f, 2 }); - NVL::Environment::ENVIRONMENT.enter(u"+", { f, 2 }); - NVL::Environment::ENVIRONMENT.enter(u"switch", { f, 2 }); - } -} \ No newline at end of file diff --git a/ADVect/Bindings.h b/ADVect/Bindings.h deleted file mode 100644 index 137231f..0000000 --- a/ADVect/Bindings.h +++ /dev/null @@ -1,3 +0,0 @@ -namespace ADVect { - void bind_NVL(); -} diff --git a/ADVect/CMakeLists.txt b/ADVect/CMakeLists.txt index d2aed14..f5a1948 100644 --- a/ADVect/CMakeLists.txt +++ b/ADVect/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.8) project (ADVect) -add_executable (Game "ADVect.cpp" "Graphics.cpp" "Bindings.cpp") +add_executable (Game "ADVect.cpp" "Graphics.cpp" ) # TODO: Add tests and install targets if needed. include_directories ("include" "../NVL/") diff --git a/ADVect/Graphics.cpp b/ADVect/Graphics.cpp index cc02605..8e2b4c6 100644 --- a/ADVect/Graphics.cpp +++ b/ADVect/Graphics.cpp @@ -1,6 +1,7 @@ +#include "Graphics.h" +#include "Environment.h" #include #include FT_FREETYPE_H -#include "Graphics.h" #include @@ -61,7 +62,7 @@ namespace { { 1.f, 1.f, 0.0f, 1.0f, 1.0f } }; - static const uint16_t quad_indices[] = + static const u16 quad_indices[] = { 0, 2, 1, 1, 2, 3 @@ -98,7 +99,7 @@ namespace { } }; - std::optional init_font(const char* path) { + std::optional get_font(const char* path) { Font f; error = FT_New_Face(library, path, 0, &f.face); @@ -135,7 +136,7 @@ namespace { ImageTexture i; i.buffer = stbi_load(file.c_str(), &i.w, &i.h, &i.channels, 0); if (i.buffer == NULL) { - std::cerr << "ADV: STB IMAGE loading failed" << std::endl; + std::cerr << "ADV: STB IMAGE loading failed for " << file << std::endl; return std::nullopt; } const bgfx::Memory* buf = bgfx::makeRef(i.buffer, i.w * i.h * i.channels * sizeof(u8)); @@ -157,8 +158,10 @@ namespace { } Font regular, bold; - bgfx::ProgramHandle a_program, img_program; + bgfx::ProgramHandle a_program, img_program, imga_program; + bgfx::UniformHandle s_texColor; + bgfx::UniformHandle imga_opacity; bgfx::IndexBufferHandle ibh; bgfx::VertexBufferHandle vbh; @@ -175,8 +178,8 @@ namespace ADVect::Graphics { return false; } - if (auto f = init_font("SourceHanSerif-Regular.ttc")) regular = *f; else return false; - if (auto f = init_font("SourceHanSerif-Heavy.ttc")) bold = *f; else return false; + if (auto f = get_font("SourceHanSerif-Regular.ttc")) regular = *f; else return false; + if (auto f = get_font("SourceHanSerif-Heavy.ttc")) bold = *f; else return false; pcvDecl.begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) @@ -185,9 +188,11 @@ 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"); - a_program = load_shader_program("swizzle_aaaa"); + img_program = load_shader_program("test"); // RGBA + imga_program = load_shader_program("ImageAlpha"); // RGBA + Opacity + a_program = load_shader_program("AlphaStencil"); // A -> FFFA + imga_opacity = bgfx::createUniform("f_opacity", bgfx::UniformType::Vec4); // x -> alpha, yzw are dummies s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler); return true; @@ -204,16 +209,18 @@ namespace ADVect::Graphics { bgfx::destroy(a_program); bgfx::destroy(img_program); + bgfx::destroy(imga_program); bgfx::destroy(ibh); bgfx::destroy(vbh); bgfx::destroy(s_texColor); + bgfx::destroy(imga_opacity); } // Draws quad with texture on Z = 0 void DrawTexture(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h, u64 state, const bgfx::ProgramHandle& pg) { - float mtx1[16], mtx2[16], mtx3[16]; + f32 mtx1[16], mtx2[16], mtx3[16]; bx::mtxTranslate(mtx1, pos_x, pos_y, 0.0f); bx::mtxScale(mtx2, w, h, 1.0f); bx::mtxMul(mtx3, mtx2, mtx1); @@ -237,6 +244,13 @@ namespace ADVect::Graphics { DrawTextureImage(img.tx, pos_x, pos_y, img.w, img.h); } + void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha) { + f32 pack[4]{}; + pack[0] = alpha; + bgfx::setUniform(imga_opacity, pack); + DrawTexture(img.tx, pos_x, pos_y, img.w, img.h, (BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS), imga_program); + } + ImageTexture* GetImageTextureFromFile(const std::string& file) { if (imgs.find(file) == imgs.end()) { ImageTexture img; @@ -253,7 +267,7 @@ 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 RenderString(const NVL::String& s, u32& pos_x, u32& pos_y, u32 col, u32 style_flags) { + void RenderString(const NVL::String& s, u32& pos_x, u32& pos_y, u32 col, u32 style_flags = TEXT_NONE) { Font* f = ®ular; switch (style_flags) { case TEXT_NONE: break; @@ -267,7 +281,7 @@ namespace ADVect::Graphics { f->cache_char(c); pos_x += slot->bitmap_left; - float ypos = pos_y - (slot->bitmap.rows - slot->bitmap_top); + 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); @@ -283,28 +297,13 @@ namespace ADVect::Graphics { RenderString(s, x, y, col, style_flags); } - void RenderStringMarkup(const std::vector& s, u32 pos_x, u32 pos_y, u32 col) { - const NVL::String& str = std::get(s[0].value); - - std::vector ms{}; - for (const NVL::Environment::Variable& markup : std::get>(s[1].value)) { - ms.push_back(NVL::Environment::UnpackMarkupVariable(markup)); - } - - if (ms.empty()) { - RenderString(str, pos_x, pos_y, col, TEXT_NONE); - return; - } - - if (ms[0].begin != 0) - RenderString(str.substr(0, ms[0].begin), pos_x, pos_y, col, TEXT_NONE); - + void RenderStringMarkup(const NVL::Environment::MarkupString& ms, u32 pos_x, u32 pos_y, u32 col) { // We assume markups are already sorted - for (size_t i = 0; i < ms.size(); i++) { + for (const NVL::Environment::MarkupSegment& s : ms.segments) { u32 style_flags = TEXT_NONE; const NVL::String* ruby = nullptr; - for (const auto& e : ms[i].efs) { + 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; } @@ -318,17 +317,10 @@ namespace ADVect::Graphics { if (ruby != nullptr) { u32 temp_x = pos_x, temp_y = pos_y + 20; - RenderString(*ruby, temp_x, temp_y, col, TEXT_NONE); + RenderString(*ruby, temp_x, temp_y, col); } - RenderString(str.substr(ms[i].begin, ms[i].end - ms[i].begin), pos_x, pos_y, col, style_flags); - - if (i != ms.size() - 1 && ms[i + 1].begin - 1 != ms[i].end) - RenderString(str.substr(ms[i].end, ms[i + 1].begin - ms[i].end), pos_x, pos_y, col, TEXT_NONE); - + RenderString(s.str, pos_x, pos_y, col, style_flags); } - - if (ms.back().end != str.length()) - RenderString(str.substr(ms.back().end), pos_x, pos_y, col, TEXT_NONE); } } diff --git a/ADVect/Graphics.h b/ADVect/Graphics.h index 015959f..d25cdff 100644 --- a/ADVect/Graphics.h +++ b/ADVect/Graphics.h @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -28,9 +30,10 @@ namespace ADVect::Graphics { void DrawTexture(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h, u64 state, const bgfx::ProgramHandle& pg); void DrawTextureImage(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h); void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y); + void DrawTextureImageAlpha(const ImageTexture& img, i32 pos_x, i32 pos_y, f32 alpha); void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h); void RenderString(const NVL::String& s, u32& pos_x, u32& pos_y, u32 col, u32 style_flags); void RenderString(const NVL::String& s, u32&& pos_x, u32&& pos_y, u32 col, u32 style_flags); - void RenderStringMarkup(const std::vector& s, u32 pos_x, u32 pos_y, u32 col); + void RenderStringMarkup(const NVL::Environment::MarkupString& s, u32 pos_x, u32 pos_y, u32 col); } diff --git a/ADVect/shader.py b/ADVect/shader.py index 8961612..4a637ed 100644 --- a/ADVect/shader.py +++ b/ADVect/shader.py @@ -1,28 +1,33 @@ import subprocess, os +SHADERC = "..\\out\\install\\x64-Debug\\bin\\shaderc" +OUT = "..\\out\\build\\x64-Debug\\ADVect\\shaders\\" +# OUT = "..\\build\\ADVect\\shaders\\" + +P = lambda location, frag, vert: { 'location': location, 'frag': frag, 'vert': vert } plats = [ - { 'location': 'glsl', 'frag': '140', 'vert': '140' }, - { 'location': 'dx11', 'frag': 'ps_5_0', 'vert': 'vs_5_0' }, - { 'location': 'spirv', 'frag': 'spirv', 'vert': 'spirv' } + P('glsl', '140', '140'), + P('dx11', 'ps_5_0', 'vs_5_0'), + P('spirv', 'spirv', 'spirv') ] for root, dirs, _ in os.walk('shaders'): for name in dirs: for config in plats: - subprocess.run(["..\\out\\install\\x64-Debug\\bin\\shaderc", "-f", os.path.join(root, name, name + '.frag'), + subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.frag'), "--type", "fragment" "--platform", "windows", "--profile", config['frag'], "--varyingdef", os.path.join(root, name, "varying.def.sc"), "-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "ext\\bgfx\\bgfx\\src", - "-o", "..\\out\\build\\x64-Debug\\ADVect\\shaders\\" + config['location'] + "\\" + name + ".frag.bin"]) - subprocess.run(["..\\out\\install\\x64-Debug\\bin\\shaderc", "-f", os.path.join(root, name, name + '.vert'), + "-o", OUT + config['location'] + "\\" + name + ".frag.bin"]) + subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.vert'), "--type", "vertex" "--platform", "windows", "--profile", config['vert'], "--varyingdef", os.path.join(root, name, "varying.def.sc"), "-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "ext\\bgfx\\bgfx\\src", - "-o", "..\\out\\build\\x64-Debug\\ADVect\\shaders\\" + config['location'] + "\\" + name + ".vert.bin"]) + "-o", OUT + config['location'] + "\\" + name + ".vert.bin"]) \ No newline at end of file diff --git a/ADVect/shaders/swizzle_aaaa/swizzle_aaaa.frag b/ADVect/shaders/AlphaStencil/AlphaStencil.frag similarity index 100% rename from ADVect/shaders/swizzle_aaaa/swizzle_aaaa.frag rename to ADVect/shaders/AlphaStencil/AlphaStencil.frag diff --git a/ADVect/shaders/swizzle_aaaa/swizzle_aaaa.vert b/ADVect/shaders/AlphaStencil/AlphaStencil.vert similarity index 100% rename from ADVect/shaders/swizzle_aaaa/swizzle_aaaa.vert rename to ADVect/shaders/AlphaStencil/AlphaStencil.vert diff --git a/ADVect/shaders/swizzle_aaaa/varying.def.sc b/ADVect/shaders/AlphaStencil/varying.def.sc similarity index 100% rename from ADVect/shaders/swizzle_aaaa/varying.def.sc rename to ADVect/shaders/AlphaStencil/varying.def.sc diff --git a/ADVect/shaders/test/test.frag b/ADVect/shaders/ImageAlpha/ImageAlpha.frag similarity index 59% rename from ADVect/shaders/test/test.frag rename to ADVect/shaders/ImageAlpha/ImageAlpha.frag index 04671ca..e317c61 100644 --- a/ADVect/shaders/test/test.frag +++ b/ADVect/shaders/ImageAlpha/ImageAlpha.frag @@ -3,10 +3,13 @@ $input v_texcoord0 #include #include +uniform vec4 f_opacity; SAMPLER2D(s_texColor, 0); + void main() { vec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y); - gl_FragColor = texture2D(s_texColor, uv); + vec4 tx = texture2D(s_texColor, uv); + gl_FragColor = vec4(tx.rgb, f_opacity.x * tx.a); } diff --git a/ADVect/shaders/test/test.vert b/ADVect/shaders/ImageAlpha/ImageAlpha.vert similarity index 100% rename from ADVect/shaders/test/test.vert rename to ADVect/shaders/ImageAlpha/ImageAlpha.vert diff --git a/ADVect/shaders/test/varying.def.sc b/ADVect/shaders/ImageAlpha/varying.def.sc similarity index 100% rename from ADVect/shaders/test/varying.def.sc rename to ADVect/shaders/ImageAlpha/varying.def.sc diff --git a/CMakeSettings.json b/CMakeSettings.json index c756a11..aa44a2f 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -15,14 +15,13 @@ { "name": "x64-Release", "generator": "Ninja", - "configurationType": "RelWithDebInfo", + "configurationType": "Release", "buildRoot": "${projectDir}\\out\\build\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}", "cmakeCommandArgs": "", "buildCommandArgs": "", "ctestCommandArgs": "", - "inheritEnvironments": [ "msvc_x64_x64" ], - "variables": [] + "inheritEnvironments": [ "clang_cl_x64" ] } ] } \ No newline at end of file diff --git a/NVL/Environment.cpp b/NVL/Environment.cpp index e04dd44..4eac86f 100644 --- a/NVL/Environment.cpp +++ b/NVL/Environment.cpp @@ -86,26 +86,55 @@ namespace NVL::Environment { Apply(c); } - // Check ParseMarkup for more information - Markup UnpackMarkupVariable(const Variable& m) { - const auto& range = std::get>(std::get>(m.value)[0].value); - const u32 begin = std::get(range[0].value), end = std::get(range[1].value); + // Check MatchMarkup for more information + MarkupString UnpackMarkupVariable(const std::vector& v) { + MarkupString ms{}; + for (const Variable& segment : v) { + const auto& pair = std::get>(segment.value); + const String s = std::get(pair[0].value); - std::vector>> efs; - for (const Variable& combination : std::get>(std::get>(m.value)[1].value)) { - if (combination.type == Type::String) { - const String ef = std::get(combination.value); - efs.push_back({ ef, {} }); + std::vector>> efs; + for (const Variable& combination : std::get>(pair[1].value)) { + if (combination.type == Type::String) { + const String ef = std::get(combination.value); + efs.push_back({ ef, {} }); + } + else if (combination.type == Type::Array) { + const std::vector& ef_t = std::get>(combination.value); + const String& ef = std::get(ef_t[0].value); + const std::vector& args = std::get>(ef_t[1].value); + std::vector ss{}; + for (const auto& s : args) { ss.push_back(std::get(s.value)); } + efs.push_back({ ef, ss }); + } } - else if (combination.type == Type::Array) { - const std::vector& ef_t = std::get>(combination.value); - const String& ef = std::get(ef_t[0].value); - const std::vector& args = std::get>(ef_t[1].value); - std::vector ss{}; - for (const auto& s : args) { ss.push_back(std::get(s.value)); } - efs.push_back({ ef, ss }); + ms.segments.push_back({ s, efs }); + } + return ms; + } + + size_t MarkupString::length() const { + size_t r = 0; + for (const auto& s : segments) + r += s.str.length(); + return r; + } + + MarkupString MarkupString::substr(size_t i) const { + size_t r = 0; + MarkupString res; + for (const auto& s : segments) { + size_t last_r = r; + r += s.str.length(); + if (r <= i) + res.segments.push_back(s); + else { + auto copy = s; + copy.str = copy.str.substr(0, i - last_r); + res.segments.push_back(copy); + break; } } - return { begin, end, efs }; + return res; } } diff --git a/NVL/Environment.h b/NVL/Environment.h index 7cbe3ca..e693f1f 100644 --- a/NVL/Environment.h +++ b/NVL/Environment.h @@ -39,9 +39,14 @@ namespace NVL::Environment { Variable Apply(const Parse::Command& c); void EvalScene(const Parse::Scene & s); - struct Markup { - u32 begin, end; + struct MarkupSegment { + String str; std::vector>> efs; }; - Markup UnpackMarkupVariable(const Variable& m); + struct MarkupString { + std::vector segments{}; + size_t length() const; + MarkupString substr(size_t idx) const; + }; + MarkupString UnpackMarkupVariable(const std::vector& v); } diff --git a/NVL/Parser.cpp b/NVL/Parser.cpp index e83a501..bcdeecd 100644 --- a/NVL/Parser.cpp +++ b/NVL/Parser.cpp @@ -328,63 +328,54 @@ namespace { } - /* + /* * NVL Markup Parsetree * - * * - Vec:2 - Num: Markup begin - * | | - * | - Num: Markup end - * | - * - Vec:N - Str: T of Markup - * | - * OR - * | - * - Vec:2 - Str: T of Markup + * * - Vec:N - Vec:2 - Str: Str segment contents * | - * - Vec: Params + * - Vec:N - Str: T of Markup + * | + * OR + * | + * - Vec:2 - Str: T of Markup + * | + * - Vec: Params */ - Parse::Object MatchMarkup(String& s) { + Parse::Object MatchMarkup(const String& s) { static const srell::basic_regex typer(uR"((? Specifiers, G2 -> Contents effect(uR"(\s*(?:([^,\(\)]+?)\s*\(\s*([^\(\)]+?)\s*\)|([^,\(\)]+?))\s*(?:,\s*|$))"), // G1 & G2 -> Func, G3 -> Attr param(uR"(([^,]+?)\s*(?:,\s*|$))"); // Comma split of func args - std::vector tags; - srell::match_results tags_match, effects_match, params_match; - String reconstruction{}; - - size_t running_offset = 0; // to account for characters removed - - bool has_markup{}; + bool has_markup = false; // Match tags + std::vector segments; String::const_iterator tags_start(s.cbegin()); while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) { has_markup = true; - Parse::Object m{ Parse::Type::Array, std::vector{} }; - reconstruction.append(tags_match.prefix().first, tags_match[0].first); - reconstruction.append(tags_match[2].first, tags_match[2].second); - running_offset += tags_match[2].first - tags_match[0].first; - size_t begin = tags_match[2].first - s.cbegin() - running_offset; + String before {tags_match.prefix().first, tags_match[0].first}; + if (!before.empty()) + segments.push_back({ Parse::Type::Array, { + { Parse::Type::String, before }, + { Parse::Type::Array, std::vector{} } + }}); - Parse::Object range{ Parse::Type::Array, { std::vector{ - { static_cast(begin) }, - { static_cast(begin + (tags_match[2].second - tags_match[2].first)) } - } - } }; - - std::vector effects{}; + String inner = tags_match[2].str(); // markupped // Match markup options + std::vector 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) { + if (effects_match[3].matched) { // no params effects.push_back({ Parse::Type::String, effects_match[3].str() }); } - else { + else { // no params + + // Comma split std::vector args; String::const_iterator params_start(effects_match[2].first); while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) { @@ -396,20 +387,26 @@ namespace { } effects_start = effects_match.suffix().first; } - running_offset += tags_match[0].second - tags_match[2].second; tags_start = tags_match.suffix().first; - tags.push_back({ Parse::Type::Array, std::vector{ range, { Parse::Type::Array, effects } } }); + segments.push_back({ Parse::Type::Array, std::vector{ { Parse::Type::String, inner }, { Parse::Type::Array, effects } } }); } if (has_markup) { - reconstruction.append(tags_match.suffix().first, tags_match.suffix().second); + String end {tags_match.suffix().first, tags_match.suffix().second}; + if (!end.empty()) + segments.push_back({ Parse::Type::Array, { + { Parse::Type::String, end }, + { Parse::Type::Array, std::vector{} } + }}); - s = reconstruction; - - return { Parse::Type::Array, tags }; + return { Parse::Type::Array, segments }; } else { - return { Parse::Type::Array, std::vector{} }; + return { Parse::Type::Array, std::vector{ + { Parse::Type::Array, { + { Parse::Type::String, s} , { Parse::Type::Array, std::vector{} } + } } } + }; } } @@ -433,10 +430,7 @@ namespace { throw std::runtime_error("Malformed speaker command"); } - String copy{ s }; - Parse::Object tags = MatchMarkup(copy); // THIS WILL MODIFY COPY - - return { { Parse::Type::Symbol, u"Say" }, { Parse::Type::String, copy }, tags }; + return { { Parse::Type::Symbol, u"Say" }, MatchMarkup(s) }; } Parse::Scene ParseScene(const String& f, size_t& pos) { diff --git a/NVL/dante_ch.nvl b/NVL/dante_ch.nvl index 7d11c69..49e7245 100644 --- a/NVL/dante_ch.nvl +++ b/NVL/dante_ch.nvl @@ -2,7 +2,7 @@ ImageTrack BG Show BG "image.png" <<- -[但丁] +[] 由我这里,直通[b]{悲惨之城}。 由我这里,直通[b]{无尽之苦}。 由我这里,直通[b]{堕落众生}。 diff --git a/NVL/dialogue.nvl b/NVL/dialogue.nvl index 7786ac3..77e5cdf 100644 --- a/NVL/dialogue.nvl +++ b/NVL/dialogue.nvl @@ -1,19 +1,57 @@ BEGIN Scene1 -ImageTrack BG -ImageTrack Avatar -Show BG "image.png" +Show BGDialogue "grad.png" <<- *!Show Avatar "mmaker.png" [MMaker] -Hi I'm Electric [b, rb("Programmer")] {プログラマー} from Michigan. +*!Show BG "googleplex/1.png" +Park your car in a place that allows you to walk on the sidewalk. +*!Show BG "googleplex/2.jpg" +Wait until everyone is asleep. +*!Show BG "googleplex/3.jpg" +Sneak into the building and head towards the front door. +*!Show BG "googleplex/4.png" +Go through the security gate and walk around the perimeter of the grounds. +*!Show BG "googleplex/5.jpg" +Enter the building using the main entrance. +*!Show BG "googleplex/6.jpg" +Walk to the elevator and take it up to the sixth floor. +*!Show BG "googleplex/7.png" +Enter the stairwell leading to the roof and climb all the way to the top. +*!Show BG "googleplex/8.jpg" +Break open the skylight and enter the room containing the Google logo. +*!Show BG "googleplex/9.jpg" +Find the main server room. +*!Show BG "googleplex/10.jpg" +Kill the power to the server room. +*!Show BG "googleplex/11.jpg" +Search the room for a computer with a USB port. +*!Show BG "googleplex/12.jpg" +Plug the USB cable into the computer. +*!Show BG "googleplex/13.jpg" +Start typing in the password for the administrator account. +*!Show BG "googleplex/14.png" +After the login screen comes up, type in the password "G00gle." +*!Show BG "googleplex/15.png" +When the system reboots, you will see a prompt asking you to install a new program. +Type "Y" and press ENTER. +*!Show BG "googleplex/16.jpg" +The Google search engine will come up. Type in "www.yahoo.com" and hit ENTER. +*!Show BG "googleplex/17.png" +A window will appear saying "You have successfully installed Google Chrome." Click OK. +*!Show BG "googleplex/18.jpg" +A new browser will open. Log in to your Yahoo mail account. +*!Show BG "image3.png" +Go to your inbox and click on the link to download the latest version of Google Chrome. +*!Show BG "googleplex/20.jpg" +Install the update. *! Show BG "image2.jpg" Commencing JS hypnosis... -*! Show BG "image3.png" +*! Show BG "image.png" *!Show Avatar "terrio.png" [Terrio]