graphics overhaul; parser bugs, many things i forgot to commit

This commit is contained in:
lachrymaL 2022-08-28 09:40:27 -04:00
parent 324ff7e7b5
commit 94515b0620
No known key found for this signature in database
GPG key ID: F3640ACFA174B1C1
21 changed files with 403 additions and 187 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
.vs
.vscode
out
build
NVL/.vs

View file

@ -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 <SDL2/SDL.h>
#include <bx/math.h>
#include <SDL2/SDL_syswm.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <bx/math.h>
#include <cstddef>
#include <functional>
#include <iostream>
#include <list>
namespace {
template <typename T>
struct Track {
T current;
};
template <typename TR, typename T>
concept IsTrack = requires (const TR& t) {
std::is_same_v<T, decltype(t.current)>;
};
template <typename TR, typename T>
concept IsNamedTrack = IsTrack<TR, T> && requires (const TR& t) {
std::is_same_v<std::string, decltype(t.name)>;
};
template<typename T, typename TR> requires(!IsNamedTrack<TR, T>)
struct NamedTrack : TR {
std::string name;
};
template<typename T, IsTrack<T> TR>
struct VisualTrack : TR {
i32 pos_x = 0, pos_y = 0;
u32 w = 500, h = 500;
f32 opacity = 1.0f;
// TODO other transforms
};
template<typename T, IsTrack<T> 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<NVL::String, Track<NVL::String>>;
using MarkupTextTrack = FillTrack<NVL::Environment::MarkupString, Track<NVL::Environment::MarkupString>>;
using NamedImageTrack = VisualTrack<ADVect::Graphics::ImageTexture*, NamedTrack<ADVect::Graphics::ImageTexture*, Track<ADVect::Graphics::ImageTexture*>>>;
/* TODO VideoTrack */
SDL_Window* window;
u16 window_width = 1280;
u16 window_height = 720;
std::string m_name;
bool running = false;
u16 m_width = 1280;
u16 m_height = 720;
bool m_keys[65536]{};
std::vector<NVL::Parse::Scene> scenes;
u32 current_scene = 0;
std::vector<NVL::Environment::Variable> 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 <typename T>
struct Varying {
u64 begin, duration;
std::function<T(NVL::Number)> interp;
bool done = true;
T get() const {
if (done)
return interp(1.f);
else
return interp((current_time - begin) / static_cast<f32>(duration));
}
void kickoff(u64 dur, const std::function<T(NVL::Number)>& f = [](NVL::Number x) { return static_cast<T>(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<ImageTrack> tracks_img{};
ImageTrack* find_image_track(const std::string& s) {
struct NamedImageTransitionTrack : NamedImageTrack {
ADVect::Graphics::ImageTexture* next = nullptr;
Varying<f32> anim;
std::function<void(const NamedImageTransitionTrack&)> draw;
void check() {
if (next != nullptr && anim.check()) {
current = next;
next = nullptr;
}
}
void change(ADVect::Graphics::ImageTexture* n, u64 dur, const std::function<f32(NVL::Number)>& 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<u32> 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<size_t>(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<NVL::Parse::Scene> 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<NamedImageTrack> tracks_img{}; // instead of vector because we need pointers to members; prevent use after free
NamedImageTrack* find_image_track(const std::string& s) {
for (auto& t : tracks_img)
if (t.name == s) {
return &t;
@ -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<NVL::Parse::Scene>& 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<NVL::Environment::Variable> args) {
m_text = args;
m_text.change(NVL::Environment::UnpackMarkupVariable(std::get<std::vector<NVL::Environment::Variable>>(NVL::Environment::Variable(args[0]).value)), 10);
return NVL::Environment::Type::Nil;
}, 2)
},
{
u"SwitchSpeaker",
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) {
speaker = std::get<NVL::String>(NVL::Environment::Variable(args[0]).value);
speaker.current = std::get<NVL::String>(NVL::Environment::Variable(args[0]).value);
return NVL::Environment::Type::Nil;
}, 1)
},
{
/* {
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)
},
},*/
{
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);
/* 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::String>(NVL::Environment::Variable(args[1]).value);
auto s2 = NVL::to_std_string(s);
t->current = ADVect::Graphics::GetImageTextureFromFile(s2);
}
}*/
if (name == "BG")
bg.change(ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value))), 200);
else if (name == "Avatar")
avatar.change(ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value))), 200);
else if (name == "BGDialogue")
dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[1]).value)));
else
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl;
return NVL::Environment::Type::Nil;
}, 2)
}
});
std::vector<NVL::Parse::Scene> 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();

View file

@ -1,9 +1,9 @@
#pragma once
#include <vector>
#include <string>
#include <Parser.h>
#include <SDL2/SDL.h>
#include <Environment.h>
#include <Common.h>

View file

@ -1,19 +0,0 @@
#include <Environment.h>
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 });
}
}

View file

@ -1,3 +0,0 @@
namespace ADVect {
void bind_NVL();
}

View file

@ -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/")

View file

@ -1,6 +1,7 @@
#include "Graphics.h"
#include "Environment.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include "Graphics.h"
#include <bx/math.h>
@ -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<Font> init_font(const char* path) {
std::optional<Font> 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 = &regular;
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<NVL::Environment::Variable>& s, u32 pos_x, u32 pos_y, u32 col) {
const NVL::String& str = std::get<NVL::String>(s[0].value);
std::vector<NVL::Environment::Markup> ms{};
for (const NVL::Environment::Variable& markup : std::get<std::vector<NVL::Environment::Variable>>(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);
}
}

View file

@ -1,3 +1,5 @@
#pragma once
#include <SDL2/SDL.h>
#include <bgfx/bgfx.h>
@ -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<NVL::Environment::Variable>& s, u32 pos_x, u32 pos_y, u32 col);
void RenderStringMarkup(const NVL::Environment::MarkupString& s, u32 pos_x, u32 pos_y, u32 col);
}

View file

@ -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"])

View file

@ -3,10 +3,13 @@ $input v_texcoord0
#include <bgfx_shader.sh>
#include <shaderlib.sh>
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);
}

View file

@ -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" ]
}
]
}

View file

@ -86,13 +86,15 @@ namespace NVL::Environment {
Apply(c);
}
// Check ParseMarkup for more information
Markup UnpackMarkupVariable(const Variable& m) {
const auto& range = std::get<std::vector<Variable>>(std::get<std::vector<Variable>>(m.value)[0].value);
const u32 begin = std::get<Number>(range[0].value), end = std::get<Number>(range[1].value);
// Check MatchMarkup for more information
MarkupString UnpackMarkupVariable(const std::vector<Variable>& v) {
MarkupString ms{};
for (const Variable& segment : v) {
const auto& pair = std::get<std::vector<Variable>>(segment.value);
const String s = std::get<String>(pair[0].value);
std::vector<std::pair<String, std::vector<String>>> efs;
for (const Variable& combination : std::get<std::vector<Variable>>(std::get<std::vector<Variable>>(m.value)[1].value)) {
for (const Variable& combination : std::get<std::vector<Variable>>(pair[1].value)) {
if (combination.type == Type::String) {
const String ef = std::get<String>(combination.value);
efs.push_back({ ef, {} });
@ -106,6 +108,33 @@ namespace NVL::Environment {
efs.push_back({ ef, ss });
}
}
return { begin, end, efs };
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 res;
}
}

View file

@ -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<std::pair<String, std::vector<String>>> efs;
};
Markup UnpackMarkupVariable(const Variable& m);
struct MarkupString {
std::vector<MarkupSegment> segments{};
size_t length() const;
MarkupString substr(size_t idx) const;
};
MarkupString UnpackMarkupVariable(const std::vector<Variable>& v);
}

View file

@ -331,9 +331,7 @@ namespace {
/*
* NVL Markup Parsetree
*
* * - Vec:2 - Num: Markup begin
* | |
* | - Num: Markup end
* * - Vec:N - Vec:2 - Str: Str segment contents
* |
* - Vec:N - Str: T of Markup
* |
@ -343,48 +341,41 @@ namespace {
* |
* - Vec: Params
*/
Parse::Object MatchMarkup(String& s) {
Parse::Object MatchMarkup(const String& s) {
static const srell::basic_regex<Char>
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, 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<Parse::Object> 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<Parse::Object>{} };
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>{} }
}});
Parse::Object range{ Parse::Type::Array, { std::vector<Parse::Object>{
{ static_cast<Number>(begin) },
{ static_cast<Number>(begin + (tags_match[2].second - tags_match[2].first)) }
}
} };
std::vector<Parse::Object> effects{};
String inner = tags_match[2].str(); // markupped
// Match markup options
std::vector<Parse::Object> effects{};
String::const_iterator effects_start(tags_match[1].first);
while (srell::regex_search(effects_start, tags_match[1].second, effects_match, effect)) {
if (effects_match[3].matched) {
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<Parse::Object> args;
String::const_iterator params_start(effects_match[2].first);
while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) {
@ -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<Parse::Object>{ range, { Parse::Type::Array, effects } } });
segments.push_back({ Parse::Type::Array, std::vector<Parse::Object>{ { 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<Parse::Object>{} }
}});
s = reconstruction;
return { Parse::Type::Array, tags };
return { Parse::Type::Array, segments };
}
else {
return { Parse::Type::Array, std::vector<Parse::Object>{} };
return { Parse::Type::Array, std::vector<Parse::Object>{
{ Parse::Type::Array, {
{ Parse::Type::String, s} , { Parse::Type::Array, std::vector<Parse::Object>{} }
} } }
};
}
}
@ -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) {

View file

@ -2,7 +2,7 @@
ImageTrack BG
Show BG "image.png"
<<-
[但丁]
[]
由我这里,直通[b]{悲惨之城}。
由我这里,直通[b]{无尽之苦}。
由我这里,直通[b]{堕落众生}。

View file

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