some parser bugs, srell supports lookbehind, imagetrack abstraction

This commit is contained in:
lachrymaL 2022-08-27 03:04:39 -04:00
parent 19e7374ac4
commit ee42a08fb8
No known key found for this signature in database
GPG key ID: F3640ACFA174B1C1
13 changed files with 473 additions and 307 deletions

2
.gitignore vendored
View file

@ -1,4 +1,6 @@
.vs
out
build
NVL/.vs
NVL/out
.cache

View file

@ -4,15 +4,16 @@
#include <SDL2/SDL_syswm.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <bx/math.h>
#include <chrono>
#include <iostream>
#include <map>
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<ImageTrack> 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<NVL::Parse::Scene>& sc) {
bool Init(std::string name, const std::vector<NVL::Parse::Scene>& 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<NVL::Environment::Variable> args) {
m_text = args;
return NVL::Environment::Type::Nil;
}, 2));
NVL::Environment::ENVIRONMENT.enter(u"SwitchSpeaker", NVL::Environment::Variable([&](std::vector<NVL::Environment::Variable> args) {
speaker = std::get<NVL::String>(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<NVL::String>(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<NVL::String>(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<NVL::String>(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<NVL::String>(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<NVL::Parse::Scene> SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl");
ADVect::Init("ADV", SCENES);
NVL::Environment::ENVIRONMENT.enter(u"Say", NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
m_text = args;
return NVL::Environment::Type::Nil;
}, 2));
NVL::Environment::ENVIRONMENT.enter(u"SwitchSpeaker", NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
speaker = std::get<NVL::String>(NVL::Environment::Variable(args[0]).value);
return NVL::Environment::Type::Nil;
}, 1));
NVL::Environment::ENVIRONMENT.enter(u"ImageTrack", NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
add_image_track(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value)));
return NVL::Environment::Type::Nil;
}, 1));
NVL::Environment::ENVIRONMENT.enter(u"Show", NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
std::string name = NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value));
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::String>(NVL::Environment::Variable(args[1]).value)));
}
return NVL::Environment::Type::Nil;
}, 2));
std::vector<NVL::Parse::Scene> 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;
}

View file

@ -8,7 +8,7 @@
#include <Common.h>
namespace ADVect {
void Init(std::string name, const std::vector<NVL::Parse::Scene>& sc);
bool Init(std::string name, const std::vector<NVL::Parse::Scene>& sc);
void Shutdown();
void Run();

View file

@ -5,37 +5,15 @@
#include <bx/math.h>
#include <iostream>
#include <optional>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
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<NVL::Char, bgfx::TextureHandle> cache_regular {};
std::unordered_map<NVL::Char, bgfx::TextureHandle> 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<NVL::Char, bgfx::TextureHandle> 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<NVL::Char, bgfx::TextureHandle>* 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<Font> 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<ImageTexture> 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<std::string, ImageTexture> 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 = &regular;
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);
}
}

View file

@ -6,7 +6,7 @@
#include <Environment.h>
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<NVL::Environment::Variable>& s, u32 pos_x, u32 pos_y, u32 col);
void DrawRandomShit();
void DrawFunkyAhhShit();
}

View file

@ -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.

View file

@ -1,6 +1,8 @@
#pragma once
#include <cstdint>
static_assert(sizeof(float) == 4);
static_assert(sizeof(double) == 8);
typedef float f32;
typedef double f64;
typedef int8_t i8;

View file

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

View file

@ -1,12 +0,0 @@
#if 0
#include <string>
#include <iostream>
#include <sstream>
#include "Parser.h"
int main() {
const std::string PJ_DIR = "E:\\Archive\\Projects\\NouVeL\\NVL\\";
std::vector<NVL::Parse::Scene> SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl");
}
#endif

View file

@ -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;
const String accept;
constexpr operator Char() const {
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<Char>
typer(uR"((?:^|[^\\])\[([^\]]+)\]\s*\{([^\}]+)\})"), // G1 -> Specifiers, G2 -> Contents
typer(uR"((?<!\\)\[([^\]]+)\]\s*\{([^\}]+)\})"), // G1 -> 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<Parse::Object> tags;
srell::match_results<String::const_iterator> tags_match;
srell::match_results<String::const_iterator> effects_match;
srell::match_results<String::const_iterator> params_match;
srell::match_results<String::const_iterator> 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<Parse::Object>{} };
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) {

35
NVL/dante_ch.nvl Normal file
View file

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

52
NVL/dante_de.nvl Normal file
View file

@ -0,0 +1,52 @@
BEGIN Inferno
ImageTrack BG
Show BG "image.png"
<<-
[]
Durch mich gehts ein zur Stadt der Qualerkornen,
Durch mich gehts ein zum ewgen Weheschlund,
Durch mich gehts 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, das 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

8
NVL/nobom.nvl Normal file
View file

@ -0,0 +1,8 @@
BEGIN NOBOM
<<-
[Test]
This shouldn't throw.
Honestly!!
fix it
->>
END