From ee42a08fb805a573dfefe775d4975ed5ef873b6b Mon Sep 17 00:00:00 2001 From: lachrymaL Date: Sat, 27 Aug 2022 03:04:39 -0400 Subject: [PATCH] some parser bugs, srell supports lookbehind, imagetrack abstraction --- .gitignore | 4 +- ADVect/ADVect.cpp | 151 +++++++++++------ ADVect/ADVect.h | 2 +- ADVect/Graphics.cpp | 398 ++++++++++++++++++++++++-------------------- ADVect/Graphics.h | 17 +- NVL/CMakeLists.txt | 2 +- NVL/Common.h | 2 + NVL/Environment.cpp | 3 +- NVL/NouVeL.cpp | 12 -- NVL/Parser.cpp | 94 +++++------ NVL/dante_ch.nvl | 35 ++++ NVL/dante_de.nvl | 52 ++++++ NVL/nobom.nvl | 8 + 13 files changed, 473 insertions(+), 307 deletions(-) delete mode 100644 NVL/NouVeL.cpp create mode 100644 NVL/dante_ch.nvl create mode 100644 NVL/dante_de.nvl create mode 100644 NVL/nobom.nvl diff --git a/.gitignore b/.gitignore index 159daad..868fc63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .vs out +build NVL/.vs -NVL/out \ No newline at end of file +NVL/out +.cache diff --git a/ADVect/ADVect.cpp b/ADVect/ADVect.cpp index fcaeadc..b79e26e 100644 --- a/ADVect/ADVect.cpp +++ b/ADVect/ADVect.cpp @@ -4,15 +4,16 @@ #include #include #include +#include -#include #include +#include namespace { SDL_Window* window; std::string m_name; - bool running = false; + volatile bool running = false; u16 m_width = 1280; u16 m_height = 720; @@ -25,23 +26,49 @@ namespace { NVL::String speaker; u32 scene_pos = 0; + struct ImageTrack { + std::string name; + ADVect::Graphics::ImageTexture* current = nullptr; + i32 pos_x = 0, pos_y = 0; + }; + + std::vector tracks_img{}; + ImageTrack* 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) { + ImageTrack 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 { - void Init(std::string name, const std::vector& sc) { + 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)) { - std::cerr << "Failed to init SDL: " << SDL_GetError() << std::endl; - return; + std::cerr << "ADV: Failed to init SDL: " << SDL_GetError() << std::endl; + return false; } - window = SDL_CreateWindow(m_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_width, m_height, SDL_WINDOW_SHOWN); + window = SDL_CreateWindow(m_name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_width, m_height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (window == NULL) { std::cerr << "ADV: Failed to create window: " << SDL_GetError() << std::endl; - return; + return false; } + bgfx::Init bgfxInit; bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer. bgfxInit.resolution.width = m_width; @@ -68,25 +95,25 @@ namespace ADVect { if (!bgfx::init(bgfxInit)) { std::cerr << "ADV: Failed bgfx initialization" << std::endl; - return; + return false; }; 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::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); + bgfx::setViewTransform(0, view, proj); - ADVect::Graphics::Init(m_width, m_height); + if (!ADVect::Graphics::Init(m_width, m_height)) { + std::cerr << "ADV: Graphics init failed" << std::endl; + return false; + } - NVL::Environment::ENVIRONMENT.enter(u"Say", NVL::Environment::Variable([&](std::vector args) { - m_text = args; - return NVL::Environment::Type::Nil; - }, 2)); - - NVL::Environment::ENVIRONMENT.enter(u"SwitchSpeaker", NVL::Environment::Variable([&](std::vector args) { - speaker = std::get(NVL::Environment::Variable(args[0]).value); - return NVL::Environment::Type::Nil; - }, 1)); Advance(); + return true; } void Shutdown() { @@ -98,39 +125,22 @@ namespace ADVect { void Advance() { size_t curr_size = scenes[current_scene].get().size(); - while (scene_pos < curr_size) { - if (std::get(scenes[current_scene].get()[scene_pos][0].value) == u"Say") { - NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]); - scene_pos++; - return; - } - else { - NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]); - scene_pos++; - } - switch (curr_size - scene_pos) { - case 0: - current_scene = -1; - return; - case 1: - return; - default: - if (std::get(scenes[current_scene].get()[scene_pos + 1][0].value) == u"Say") { - NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]); - scene_pos++; - return; - } - break; - } + while (scene_pos < curr_size && std::get(scenes[current_scene].get()[scene_pos][0].value) != u"Say") { + NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]); + scene_pos++; + } + if (curr_size == scene_pos) { + running = false; + return; + } + if (std::get(scenes[current_scene].get()[scene_pos][0].value) == u"Say") { + NVL::Environment::Apply(scenes[current_scene].get()[scene_pos]); + scene_pos++; } } void Update() { if (m_keys[SDL_SCANCODE_SPACE]) { - if (current_scene == -1) { - running = false; - return; - } Advance(); m_keys[SDL_SCANCODE_SPACE] = false; } @@ -139,18 +149,22 @@ namespace ADVect { void Render() { bgfx::touch(0); - ADVect::Graphics::DrawRandomShit(); +// ADVect::Graphics::DrawFunkyAhhShit(); + for (auto& t : tracks_img) { + if (t.current != nullptr) + ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); + } ADVect::Graphics::RenderString(speaker, 100, 150, 0xFFFFFFFF, ADVect::Graphics::TEXT_BOLD); ADVect::Graphics::RenderStringMarkup(m_text, 300, 90, 0xFFFFFFFF); bgfx::dbgTextClear(); - bgfx::dbgTextPrintf(0, 44, 0xF0, "NouVeL x ADVect :: %s %s", __DATE__, __TIME__); - bgfx::dbgTextPrintf(0, 43, 0xF0, "Current Position: %u", scene_pos); - bgfx::dbgTextPrintf(0, 42, 0xF0, "Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str()); + bgfx::dbgTextPrintf(0, 44, 0xF0, "NouVeL x ADVect :: %s :: %s %s", BX_COMPILER_NAME, __DATE__, __TIME__); + bgfx::dbgTextPrintf(0, 43, 0xF0, "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, 0xF0, "Current Position: %u", scene_pos); + bgfx::dbgTextPrintf(0, 41, 0xF0, "Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str()); bgfx::frame(); - } void Run() { @@ -178,11 +192,40 @@ namespace ADVect { int main(int argc, char* argv[]) { const std::string PJ_DIR = "..\\..\\..\\..\\NVL\\"; - std::vector SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl"); - ADVect::Init("ADV", SCENES); + NVL::Environment::ENVIRONMENT.enter(u"Say", NVL::Environment::Variable([](std::vector args) { + m_text = args; + return NVL::Environment::Type::Nil; + }, 2)); + + NVL::Environment::ENVIRONMENT.enter(u"SwitchSpeaker", NVL::Environment::Variable([](std::vector args) { + speaker = std::get(NVL::Environment::Variable(args[0]).value); + return NVL::Environment::Type::Nil; + }, 1)); + + NVL::Environment::ENVIRONMENT.enter(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)); + + NVL::Environment::ENVIRONMENT.enter(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); + if (t == nullptr) { + std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; + } + else { + t->current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(NVL::Environment::Variable(args[1]).value))); + } + return NVL::Environment::Type::Nil; + }, 2)); + + std::vector SCENES = NVL::Parse::ParseFile(PJ_DIR + "dante_de.nvl"); + if (SCENES.empty()) return EXIT_FAILURE; + + if (!ADVect::Init("ADV", SCENES)) return EXIT_FAILURE; ADVect::Run(); ADVect::Shutdown(); - return 0; + return EXIT_SUCCESS; } diff --git a/ADVect/ADVect.h b/ADVect/ADVect.h index 391fb3d..c89cf40 100644 --- a/ADVect/ADVect.h +++ b/ADVect/ADVect.h @@ -8,7 +8,7 @@ #include namespace ADVect { - void Init(std::string name, const std::vector& sc); + bool Init(std::string name, const std::vector& sc); void Shutdown(); void Run(); diff --git a/ADVect/Graphics.cpp b/ADVect/Graphics.cpp index f6dacb1..d80488c 100644 --- a/ADVect/Graphics.cpp +++ b/ADVect/Graphics.cpp @@ -5,37 +5,15 @@ #include #include +#include #define STB_IMAGE_IMPLEMENTATION #include namespace { - FT_Library library; - FT_Error error; - FT_Face face_regular, face_bold; + using namespace ADVect::Graphics; - struct PosUVVertex { - f32 x; - f32 y; - f32 z; - f32 u; - f32 v; - }; - static PosUVVertex quad_vert[] = - { - { 0.f, 0.f, 0.0f, 0.0f, 0.0f }, - { 0.f, 1.f, 0.0f, 0.0f, 1.0f }, - { 1.f, 0.f, 0.0f, 1.0f, 0.0f }, - { 1.f, 1.f, 0.0f, 1.0f, 1.0f } - }; - - static const uint16_t quad_indices[] = - { - 0, 2, 1, - 1, 2, 3 - }; - - bgfx::ShaderHandle loadShader(const char* FILENAME) + bgfx::ShaderHandle loadShader(const std::string& FILENAME) { std::string shaderPath{}; @@ -67,171 +45,47 @@ namespace { return bgfx::createShader(mem); } - bgfx::ShaderHandle a_vsh, img_vsh; - bgfx::ShaderHandle a_fsh, img_fsh; - bgfx::ProgramHandle a_program, img_program; - bgfx::IndexBufferHandle ibh; - bgfx::VertexBufferHandle vbh; - bgfx::UniformHandle s_texColor; - bgfx::VertexLayout pcvDecl; + struct PosUVVertex { + f32 x; + f32 y; + f32 z; + f32 u; + f32 v; + }; - std::unordered_map cache_regular {}; - std::unordered_map cache_bold {}; + static PosUVVertex quad_vert[] = + { + { 0.f, 0.f, 0.0f, 0.0f, 0.0f }, + { 0.f, 1.f, 0.0f, 0.0f, 1.0f }, + { 1.f, 0.f, 0.0f, 1.0f, 0.0f }, + { 1.f, 1.f, 0.0f, 1.0f, 1.0f } + }; - int w, h, channels; - u8* img; - bgfx::TextureHandle tx; -} + static const uint16_t quad_indices[] = + { + 0, 2, 1, + 1, 2, 3 + }; -namespace ADVect::Graphics { - i16 Init(u16 width, u16 height) { - error = FT_Init_FreeType(&library); - if (error) { - std::cerr << "ADV: FreeType init error: " << error << std::endl; - return -1; - } + FT_Library library; + FT_Error error; - error = FT_New_Face(library, "SourceHanSans-Regular.ttc", 0, &face_regular); - error = FT_New_Face(library, "SourceHanSans-Bold.ttc", 0, &face_bold); - if (error == FT_Err_Unknown_File_Format) { - std::cerr << "ADV: FreeType Unknown_File_Format: " << error << std::endl; - return -1; - } - else if (error) { - std::cerr << "ADV: FreeType font loading error: " << error << std::endl; - return -1; - } + struct Font { + FT_Face face = nullptr; + std::unordered_map cache{}; - error = FT_Set_Char_Size(face_regular, 0, 20 * 64, 72, 72); - error = FT_Set_Char_Size(face_bold, 0, 20 * 64, 72, 72); - if (error == FT_Err_Unknown_File_Format) { - std::cerr << "ADV: FreeType Set_Char_Size error: " << error << std::endl; - return -1; - } + void cache_char(NVL::Char c) { + FT_GlyphSlot slot = face->glyph; - float view[16]; - bx::mtxTranslate(view, 0.f, 0.f, 1.0f); - float proj[16]; - bx::mtxOrtho(proj, 0.0f, width, 0.0f, height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); - bgfx::setViewTransform(0, view, proj); + error = FT_Load_Char(face, c, FT_LOAD_RENDER); + if (error) { + std::cerr << "ADV: Failed to load character" << std::endl; + } - pcvDecl.begin() - .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) - .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) - .end(); - ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices))); - vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl); - - img_vsh = loadShader("test.vert.bin"); - img_fsh = loadShader("test.frag.bin"); - img_program = bgfx::createProgram(img_vsh, img_fsh, true); - - a_vsh = loadShader("swizzle_aaaa.vert.bin"); - a_fsh = loadShader("swizzle_aaaa.frag.bin"); - a_program = bgfx::createProgram(a_vsh, a_fsh, true); - - s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler); - - - img = stbi_load("image.png", &w, &h, &channels, 0); - if (img == NULL) { - std::cerr << "ADV: STB IMAGE loading failed" << std::endl; - return -1; - } - const bgfx::Memory* buf = bgfx::makeRef(img, w * h * channels * sizeof(u8)); - tx = bgfx::createTexture2D( - w, - h, - false, - 1, - bgfx::TextureFormat::RGBA8, - BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP, - buf - ); - - return 0; - } - - void Shutdown() { - FT_Done_Face(face_regular); - FT_Done_Face(face_bold); - FT_Done_FreeType(library); - - - bgfx::destroy(a_vsh); - bgfx::destroy(a_fsh); - bgfx::destroy(img_vsh); - bgfx::destroy(img_fsh); - bgfx::destroy(a_program); - bgfx::destroy(img_program); - bgfx::destroy(ibh); - bgfx::destroy(vbh); - bgfx::destroy(s_texColor); - for (auto it = cache_regular .begin(); it != cache_regular.end(); it++) { - bgfx::destroy(it->second); - } - for (auto it = cache_bold.begin(); it != cache_bold.end(); it++) { - bgfx::destroy(it->second); - } - bgfx::destroy(tx); - } - - // Draws quad with texture on Z = 0 - void DrawTexture(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h) { - float 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); - - bgfx::setTransform(mtx3); - - bgfx::setVertexBuffer(0, vbh); - bgfx::setIndexBuffer(ibh); - - bgfx::setTexture(0, s_texColor, tex); - - bgfx::setState(BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_NORMAL); - bgfx::submit(0, img_program); - } - - void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h) { - float 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); - - bgfx::setTransform(mtx3); - - bgfx::setVertexBuffer(0, vbh); - bgfx::setIndexBuffer(ibh); - - bgfx::setTexture(0, s_texColor, tex); - - bgfx::setState((BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_ALPHA) & ~(BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS)); - bgfx::submit(0, a_program); - } - - void RenderString(const NVL::String& s, u32& pos_x, u32& pos_y, u32 col, u32 style_flags) { - FT_Face active = face_regular; - std::unordered_map* cache = &cache_regular; - switch (style_flags) { - case TEXT_NONE: break; - case TEXT_BOLD: active = face_bold; cache = &cache_bold; break; - case TEXT_ITALIC: break; - case TEXT_ITALIC | TEXT_BOLD: break; - } - - - FT_GlyphSlot slot = active->glyph; - - for (const auto& c : s) { - error = FT_Load_Char(active, c, FT_LOAD_RENDER); - if (error) continue; - - if (cache->find(c) == cache->end() && slot->bitmap.width != 0) { + if (cache.find(c) == cache.end() && slot->bitmap.width != 0) { const bgfx::Memory* buf = bgfx::copy(slot->bitmap.buffer, slot->bitmap.pitch * slot->bitmap.rows); - cache->emplace(c, bgfx::createTexture2D( + cache.emplace(c, bgfx::createTexture2D( slot->bitmap.width, slot->bitmap.rows, false, @@ -241,12 +95,187 @@ namespace ADVect::Graphics { buf )); } + } + }; + + std::optional init_font(const char* path) { + Font f; + + error = FT_New_Face(library, path, 0, &f.face); + if (error == FT_Err_Unknown_File_Format) { + std::cerr << "ADV: FreeType Unknown_File_Format: " << error << std::endl; + return std::nullopt; + } + else if (error) { + std::cerr << "ADV: FreeType font loading error: " << error << std::endl; + return std::nullopt; + } + + error = FT_Set_Char_Size(f.face, 0, 20 * 64, 72, 72); + if (error) { + std::cerr << "ADV: FreeType Set_Char_Size error: " << error << std::endl; + return std::nullopt; + } + + return f; + } + + void destroy_font(Font& f) { + FT_Done_Face(f.face); + for (auto it = f.cache.begin(); it != f.cache.end(); it++) { + bgfx::destroy(it->second); + } + } + + inline bgfx::ProgramHandle load_shader_program(const std::string& shader) { + return bgfx::createProgram(loadShader(shader + ".vert.bin"), loadShader(shader + ".frag.bin"), true); + } + + std::optional get_image_texture(const std::string& file) { + ImageTexture i; + i.buffer = stbi_load("image.png", &i.w, &i.h, &i.channels, 0); + if (i.buffer == NULL) { + std::cerr << "ADV: STB IMAGE loading failed" << std::endl; + return std::nullopt; + } + const bgfx::Memory* buf = bgfx::makeRef(i.buffer, i.w * i.h * i.channels * sizeof(u8)); + i.tx = bgfx::createTexture2D( + i.w, + i.h, + false, + 1, + bgfx::TextureFormat::RGBA8, + BGFX_TEXTURE_NONE | BGFX_SAMPLER_UVW_CLAMP, + buf + ); + return i; + } + + void destroy_image_texture(ImageTexture& i) { + stbi_image_free(i.buffer); + bgfx::destroy(i.tx); + } + + Font regular, bold; + ImageTexture bg; + bgfx::ProgramHandle a_program, img_program; + bgfx::UniformHandle s_texColor; + + bgfx::IndexBufferHandle ibh; + bgfx::VertexBufferHandle vbh; + bgfx::VertexLayout pcvDecl; + + std::unordered_map imgs; +} + +namespace ADVect::Graphics { + bool Init(u16 width, u16 height) { + error = FT_Init_FreeType(&library); + if (error) { + std::cerr << "ADV: FreeType init error: " << error << std::endl; + 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; + + pcvDecl.begin() + .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) + .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float) + .end(); + 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"); + + s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler); + + if (auto i = get_image_texture("image.png")) bg = *i; else return false; + + return true; + } + + void Shutdown() { + destroy_font(regular); + destroy_font(bold); + FT_Done_FreeType(library); + + destroy_image_texture(bg); + + for (auto it = imgs.begin(); it != imgs.end(); it++) { + destroy_image_texture(it->second); + } + + bgfx::destroy(a_program); + bgfx::destroy(img_program); + + bgfx::destroy(ibh); + bgfx::destroy(vbh); + + bgfx::destroy(s_texColor); + } + + // 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]; + bx::mtxTranslate(mtx1, pos_x, pos_y, 0.0f); + bx::mtxScale(mtx2, w, h, 1.0f); + bx::mtxMul(mtx3, mtx2, mtx1); + + bgfx::setTransform(mtx3); + + bgfx::setVertexBuffer(0, vbh); + bgfx::setIndexBuffer(ibh); + + bgfx::setTexture(0, s_texColor, tex); + + bgfx::setState(state); + bgfx::submit(0, pg); + } + + void DrawTextureImage(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h) { + DrawTexture(tex, pos_x, pos_y, w, h, BGFX_STATE_DEFAULT | BGFX_STATE_BLEND_NORMAL, img_program); + } + + void DrawTextureImage(const ImageTexture& img, i32 pos_x, i32 pos_y) { + DrawTextureImage(img.tx, pos_x, pos_y, img.w, img.h); + } + + ImageTexture* GetImageTextureFromFile(const std::string& file) { + if (imgs.find(file) == imgs.end()) { + ImageTexture img; + if (auto i = get_image_texture(file)) { + img = *i; + imgs[file] = std::move(img); + return &imgs[file]; + } + } + return nullptr; + } + + void DrawTextureStencilAlpha(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h) { + 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) { + Font* f = ®ular; + switch (style_flags) { + case TEXT_NONE: break; + case TEXT_BOLD: f = &bold; break; + case TEXT_ITALIC: break; + case TEXT_ITALIC | TEXT_BOLD: break; + } + + FT_GlyphSlot& slot = f->face->glyph; + for (const auto& c : s) { + f->cache_char(c); pos_x += slot->bitmap_left; float ypos = pos_y - (slot->bitmap.rows - slot->bitmap_top); if (slot->bitmap.width != 0) { - DrawTextureStencilAlpha((*cache)[c], pos_x, ypos, slot->bitmap.width, slot->bitmap.rows); + DrawTextureStencilAlpha((f->cache)[c], pos_x, ypos, slot->bitmap.width, slot->bitmap.rows); } pos_x += slot->advance.x >> 6; @@ -308,8 +337,7 @@ namespace ADVect::Graphics { RenderString(str.substr(ms.back().end), pos_x, pos_y, col, TEXT_NONE); } - void DrawRandomShit() { - - DrawTexture(tx, 0, -40, w, h); + void DrawFunkyAhhShit() { + DrawTextureImage(bg, 0, -40); } } diff --git a/ADVect/Graphics.h b/ADVect/Graphics.h index 8cfd2e6..4b687b4 100644 --- a/ADVect/Graphics.h +++ b/ADVect/Graphics.h @@ -6,7 +6,7 @@ #include namespace ADVect::Graphics { - i16 Init(u16 width, u16 height); + bool Init(u16 width, u16 height); void Shutdown(); enum MarkupStyle { @@ -18,12 +18,21 @@ namespace ADVect::Graphics { TEXT_OVERLINE = 1 << 4 }; - void DrawTexture(const bgfx::TextureHandle& tex, i32 pos_x, i32 pos_y, u32 w, u32 h); + struct ImageTexture { + i32 w, h, channels; + u8* buffer; + bgfx::TextureHandle tx; + }; + ImageTexture* GetImageTextureFromFile(const std::string& file); + + 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 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 DrawRandomShit(); + + void DrawFunkyAhhShit(); } diff --git a/NVL/CMakeLists.txt b/NVL/CMakeLists.txt index 7926c16..f4d118a 100644 --- a/NVL/CMakeLists.txt +++ b/NVL/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required (VERSION 3.8) project (NVL) include_directories("include") -add_library (NVL STATIC "NouVeL.cpp" "Parser.cpp" "Environment.cpp" "Environment.h" "Common.h") +add_library (NVL STATIC "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. diff --git a/NVL/Common.h b/NVL/Common.h index f6b4232..47e1869 100644 --- a/NVL/Common.h +++ b/NVL/Common.h @@ -1,6 +1,8 @@ #pragma once #include +static_assert(sizeof(float) == 4); +static_assert(sizeof(double) == 8); typedef float f32; typedef double f64; typedef int8_t i8; diff --git a/NVL/Environment.cpp b/NVL/Environment.cpp index cba2bd0..ada3e73 100644 --- a/NVL/Environment.cpp +++ b/NVL/Environment.cpp @@ -29,9 +29,8 @@ namespace NVL::Environment { } void Environment::enter(const String& name, Variable p) { - if (env.find(name) != env.end()) + if (!env.emplace(name, p).second) throw std::runtime_error("Redefinition of symbol in environment"); - env.emplace(name, p); } void Environment::set(const String& name, Variable p) { diff --git a/NVL/NouVeL.cpp b/NVL/NouVeL.cpp deleted file mode 100644 index 1ec6e8f..0000000 --- a/NVL/NouVeL.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#if 0 -#include -#include -#include -#include "Parser.h" - -int main() { - const std::string PJ_DIR = "E:\\Archive\\Projects\\NouVeL\\NVL\\"; - std::vector SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl"); -} - -#endif diff --git a/NVL/Parser.cpp b/NVL/Parser.cpp index 1a2d27c..aac6ff2 100644 --- a/NVL/Parser.cpp +++ b/NVL/Parser.cpp @@ -15,20 +15,20 @@ namespace { using namespace NVL; struct ParseGroup { - String accept; + const String accept; - constexpr operator String() const { + operator String() const { return accept; } - constexpr bool operator== (const String& other) const { + bool operator== (const String& other) const { return accept == other; } }; struct Match { - String accept; - - constexpr operator Char() const { + const String accept; + + operator Char() const { if (accept.length() == 1) return accept[0]; else { @@ -36,28 +36,28 @@ namespace { return '\0'; } } - constexpr bool operator== (const String& other) const { + bool operator== (const String& other) const { return accept == other; } }; - const ParseGroup NUMERIC = { u"1234567890" }; - const Match DECIMAL_DOT = { u"." }; - const Match NEGATIVE = { u"-" }; - const ParseGroup ALPHA = { u"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" }; - const Match ARRAY_OPEN = { u"[" }; - const Match ARRAY_CLOSE = { u"]" }; - const Match ARRAY_DELIM = { u"," }; - const Match GROUP_OPEN = { u"(" }; - const Match GROUP_CLOSE = { u")" }; - const Match QUOTE = { u"\"" }; - const Match COMMENT_BEGIN = { u"//" }; - const Match DIALOGUE_OPEN = { u"<<-" }; - const Match DIALOGUE_CLOSE = { u"->>" }; - const Match BEGIN = { u"BEGIN" }; - const Match END = { u"END" }; - const ParseGroup SYMBOL = { ALPHA.accept + NUMERIC.accept + u"_"}; - const Match SPECIAL_SYMBOLS[] = { + const ParseGroup NUMERIC { u"1234567890" }; + const Match DECIMAL_DOT { u"." }; + const Match NEGATIVE { u"-" }; + const ParseGroup ALPHA { u"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" }; + const Match ARRAY_OPEN { u"[" }; + const Match ARRAY_CLOSE { u"]" }; + const Match ARRAY_DELIM { u"," }; + const Match GROUP_OPEN { u"(" }; + const Match GROUP_CLOSE { u")" }; + const Match QUOTE { u"\"" }; + const Match COMMENT_BEGIN { u"//" }; + const Match DIALOGUE_OPEN { u"<<-" }; + const Match DIALOGUE_CLOSE { u"->>" }; + const Match BEGIN { u"BEGIN" }; + const Match END { u"END" }; + const ParseGroup SYMBOL { ALPHA.accept + NUMERIC.accept + u"_"}; + const Match SPECIAL_SYMBOLS[] { { u"+" }, { u"-" }, { u"*" }, @@ -68,34 +68,35 @@ namespace { { u"<=?" }, { u">=?" } }; - const ParseGroup WS = { u" \t\v\f\r\n" }; - const ParseGroup SEPARATOR = { + const ParseGroup WS { u" \t\v\f\r\n" }; + const ParseGroup SEPARATOR { WS.accept + Char(ARRAY_OPEN) + Char(ARRAY_CLOSE) + Char(GROUP_OPEN) + Char(GROUP_CLOSE) + Char(ARRAY_DELIM) + - COMMENT_BEGIN.accept[0] + COMMENT_BEGIN.accept[0] + + u'\0' }; - const Match NEWLINE = { u"\n" }; - const ParseGroup ESCAPED = { u"\\\"" }; + const Match NEWLINE { u"\n" }; + const ParseGroup ESCAPED { u"\\\"" }; - const Match ESCAPE = { u"\\" }; + const Match ESCAPE { u"\\" }; // Dialogue mode matches - const Match MARKUP_OPEN = { u"[" }; - const Match MARKUP_CLOSE = { u"]" }; - const Match SPEAKER_OPEN = { u"[" }; - const Match SPEAKER_CLOSE = { u"]" }; - const Match MARKUP_TEXT_OPEN = { u"{" }; - const Match MARKUP_TEXT_CLOSE = { u"}" }; - const Match TEMPLATE_IND = { u"$" }; - const Match TEMPLATE_OPEN = { u"{" }; - const Match TEMPLATE_CLOSE = { u"}" }; + const Match MARKUP_OPEN { u"[" }; + const Match MARKUP_CLOSE { u"]" }; + const Match SPEAKER_OPEN { u"[" }; + const Match SPEAKER_CLOSE { u"]" }; + const Match MARKUP_TEXT_OPEN { u"{" }; + const Match MARKUP_TEXT_CLOSE { u"}" }; + const Match TEMPLATE_IND { u"$" }; + const Match TEMPLATE_OPEN { u"{" }; + const Match TEMPLATE_CLOSE { u"}" }; - const Match COMMAND_ESCAPE = { u"*!" }; - const ParseGroup DIALOGUE_ESCAPED_SINGLE = { + const Match COMMAND_ESCAPE { u"*!" }; + const ParseGroup DIALOGUE_ESCAPED_SINGLE { ESCAPE.accept + Char(MARKUP_OPEN) + Char(MARKUP_CLOSE) + @@ -344,15 +345,13 @@ namespace { */ Parse::Object MatchMarkup(String& s) { static const srell::basic_regex - typer(uR"((?:^|[^\\])\[([^\]]+)\]\s*\{([^\}]+)\})"), // G1 -> Specifiers, G2 -> Contents + 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; - srell::match_results effects_match; - srell::match_results params_match; + srell::match_results tags_match, effects_match, params_match; String reconstruction{}; @@ -365,9 +364,9 @@ namespace { 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, std::next(tags_match[0].first, 1)); // match will overmatch behind by 1 + 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 - std::next(tags_match[0].first, 1); + running_offset += tags_match[2].first - tags_match[0].first; size_t begin = tags_match[2].first - s.cbegin() - running_offset; @@ -452,6 +451,7 @@ namespace { bool dialogue_mode = false; + SkipComments(f, pos); while (PeekToken(f, pos) != END.accept) { if (!dialogue_mode) if (PeekToken(f, pos) == DIALOGUE_OPEN.accept) { diff --git a/NVL/dante_ch.nvl b/NVL/dante_ch.nvl new file mode 100644 index 0000000..7d11c69 --- /dev/null +++ b/NVL/dante_ch.nvl @@ -0,0 +1,35 @@ +BEGIN Inferno +ImageTrack BG +Show BG "image.png" +<<- +[但丁] +由我这里,直通[b]{悲惨之城}。 +由我这里,直通[b]{无尽之苦}。 +由我这里,直通[b]{堕落众生}。 +圣裁于高天激发造我的君主; +造我的大能是[b, rb("C")]{神}的力量,是无上的[b, rb(" L L V M")]{智慧与众爱}所自出。 +我永远不朽;在我之前,万象 未形,只有永恒的事物存在。 +来者呀,快把一切希望弃扬。 +我所见到的文字,毫无光彩, 用暗色刻在地狱之门的高处。 +老师呀,讲得真可骇。 +[维吉尔] +一切疑虑,必须在这里摆脱。 +一切怯懦,必须在这里结束。 +这个地方,我已经向你解说。 +悲惨的群伦,你会在这里看见。 +他们都享受不到心智的成果。 +[] +维吉尔说完,就按着我的手,其和颜使我放心。 +然后,他把我带到 凡眸不能目睹的景物之前。 +那里,叹息、恸哭、凄厉的嚎咷 在星光全无的空中回荡旋涌。 +起先,这景象使我哭泣哀号。 +陌生的语言、可怕的话声、各种充满痛苦的言辞、愤怒的腔调、尖厉而沙哑的嗓子和众手乱动乱打的巨响,在骚然涡转咆哮,在无始无终的幽冥中永不休止,就像风沙在回飙里疾旋急搅。 +[但丁] +老师呀,这是什么声音? 听起来好像有人在受着凌迟。 +[维吉尔] +这些人处境可悯,他们都是可怜的亡魂,在世上不招闲言,也无令誉可矜。 +他们跟一群卑鄙的天使同党。 +这些天使,不是上帝的叛徒或信徒;他们为私利而自成一帮。 +天穹嫌他们不够好,把他们放逐; 深坑呢,又不愿给他们栖身之地,怕坏人因此而显得光荣突出。 +->> +END \ No newline at end of file diff --git a/NVL/dante_de.nvl b/NVL/dante_de.nvl new file mode 100644 index 0000000..ad2e18d --- /dev/null +++ b/NVL/dante_de.nvl @@ -0,0 +1,52 @@ +BEGIN Inferno + +ImageTrack BG +Show BG "image.png" + +<<- +[] +Durch mich geht’s ein zur Stadt der Qualerkornen, +Durch mich geht’s ein zum ew’gen Weheschlund, +Durch mich geht’s ein zum Volke der Verlornen. +Das Recht war meines hohen Schöpfers Grund; +Die Allmacht wollt’ in mir sich offenbaren; +Allweisheit ward und erste Liebe kund. +Die schon vor mir erschaffnen Dinge waren +Nur ewige; und ewig daur’ auch ich. +[b]{Laßt}, die ihr eingeht jede [b, rb(" H o p e")]{Hoffnung} fahren. +Die Inschrift zeigt’ in dunkler Farbe sich +Geschrieben dort am Gipfel einer Pforte. +[Dante] +Hart, Meister, ist ihr Sinn für mich. +[Virgil] +Hier sei jedweder Argwohn weggebannt, +Und jede Feigheit sterb’ an diesem Orte. +Wir sind zur Stelle, die ich dir genannt, +Hier wirst du jene Jammervollen schauen, +Für die das Heil des wahren Lichtes schwand. +[] +Er faßte meine Hand, daher Vertrauen +Durch sein Gesicht voll Mut auch ich gewann. +Drauf führt’ er mich in das geheime Grauen. +Dort hob Geächz, Geschrei und Klagen an, +Laut durch die sternenlose Luft ertönend, +So daß ich selber weinte, da’s begann. +Verschiedne Sprachen, Worte, gräßlich dröhnend, +Handschläge, Klänge heiseren Geschreis, +Die Wut, aufkreischend, und der Schmerz, erstöhnend – +Und, ich vom Wahn umstrickt und bang im Herzen +[Dante] +Meister, welch Geschrei, das sich erhebt? +Wer ist doch hier so ganz besiegt von Schmerzen? +[Virgil] +Der Klang, der durch die Lüfte bebt, +Kommt von den Jammerseelen jener Wesen, +Die ohne Schimpf und ohne Lob gelebt. +Gemischt sind die Nicht-Guten und Nicht-Bösen +Den Engeln, die nicht Gott getreu im Strauß, +Auch Meutrer nicht und nur für sich gewesen. +Die Himmel trieben sie als Mißzier aus, +Und da durch sie der Sünder Stolz erstünde, +Nimmt sie nicht ein der tiefen Hölle Graus. +->> +END \ No newline at end of file diff --git a/NVL/nobom.nvl b/NVL/nobom.nvl new file mode 100644 index 0000000..3b57ecc --- /dev/null +++ b/NVL/nobom.nvl @@ -0,0 +1,8 @@ +BEGIN NOBOM +<<- +[Test] +This shouldn't throw. +Honestly!! +fix it +->> +END \ No newline at end of file