#include "ADVect.h" #include "Environment.h" #include "Graphics.h" #include "Track.h" #include "Compiler.h" #include "Director.h" #include #include #include #include #include #include #include #include #include #include #include namespace { SDL_Window* window; u16 window_width = 1920; u16 window_height = 1080; u64 init_time, last_time, current_time, delta_t; bool running = false, rolling = true; bool draw_ui = true; bool m_keys[65536]{}; // terrible bool mouse[256]{ true }; // terrible std::unique_ptr director; ADVect::MarkupTextTransitionTrack m_text{ .current{}, .pos_x = 280, .pos_y = 90, .w = 1500, .h = 500, .opacity = 1.0f, .fill = 0xFFFFFFFF }; ADVect::TextTrack speaker = { .current{}, .pos_x = 250, .pos_y = 150, .w = 500, .h = 500, .opacity = 1.0f, .fill = 0xFFFFFFFF }; ADVect::ImageTransitionTrack bg = { .current{}, .pos_x = 0, .pos_y = 0, .w = 500, .h = 500 }, avatar = { .current{}, .pos_x = 10, .pos_y = 0, .w = 500, .h = 500 }; ADVect::ImageTrack dialogue_bg = { .current{}, .pos_x = 0, .pos_y = 0, .w = 500, .h = 500 }; std::vector> track_updaters; } namespace ADVect { bool Init(std::string name, const NVL::Compiler::NVLGraph& g) { director = std::make_unique(g); if (SDL_Init(SDL_INIT_VIDEO)) { std::cerr << "ADV: Failed to init SDL: " << SDL_GetError() << std::endl; return false; } 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; } bgfx::Init bgfxInit; bgfxInit.type = bgfx::RendererType::OpenGL; // Automatically choose a renderer. bgfxInit.resolution.width = window_width; bgfxInit.resolution.height = window_height; bgfxInit.resolution.reset = BGFX_RESET_VSYNC; #if !BX_PLATFORM_EMSCRIPTEN SDL_SysWMinfo wmi; SDL_VERSION(&wmi.version); if (!SDL_GetWindowWMInfo(window, &wmi)) { std::cerr << "ADV: SDL_SysWMinfo could not be retrieved: " << SDL_GetError() << std::endl; } #endif #if BX_PLATFORM_WINDOWS bgfxInit.platformData.nwh = wmi.info.win.window; #elif BX_PLATFORM_OSX bgfxInit.platformData.nwh = wmi.info.cocoa.window; bgfx::renderFrame(); #elif BX_PLATFORM_LINUX bgfxInit.platformData.ndt = wmi.info.x11.display; bgfxInit.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window; #elif BX_PLATFORM_EMSCRIPTEN bgfxInit.platformData.nwh = (void*)"#canvas"; #endif if (!bgfx::init(bgfxInit)) { std::cerr << "ADV: Failed bgfx initialization" << std::endl; 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, 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, window_width, 0.0f, window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); bgfx::setViewTransform(0, view, proj); if (!ADVect::Graphics::Init(window_width, window_height)) { std::cerr << "ADV: Graphics init failed" << std::endl; return false; } track_updaters.push_back(std::bind(&decltype(bg)::check, &bg, std::placeholders::_1)); track_updaters.push_back(std::bind(&decltype(avatar)::check, &avatar, std::placeholders::_1)); track_updaters.push_back(std::bind(&decltype(m_text)::check, &m_text, std::placeholders::_1)); Advance(); return true; } void Shutdown() { Graphics::Shutdown(); bgfx::shutdown(); SDL_DestroyWindow(window); SDL_Quit(); } void Advance() { if (!m_text.transition.done) m_text.transition.done = true; else if (director->active) { rolling = true; director->Advance(); } else running = false; if (running && rolling) Advance(); } void Update() { if (m_keys[SDL_SCANCODE_RETURN]) { if (draw_ui) Advance(); else draw_ui ^= true; m_keys[SDL_SCANCODE_RETURN] = false; } if (m_keys[SDL_SCANCODE_SPACE]) { draw_ui ^= true; m_keys[SDL_SCANCODE_SPACE] = false; } if (!mouse[SDL_BUTTON_LEFT]) { if (draw_ui) Advance(); else draw_ui ^= true; mouse[SDL_BUTTON_LEFT] = true; } if (m_keys[SDL_SCANCODE_LCTRL]) { if (draw_ui) Advance(); } for (const auto& x : track_updaters) { x(current_time); } } void Render() { bgfx::touch(0); draw_image_transition_crossfade(current_time, bg); if (draw_ui) { if (dialogue_bg.current != nullptr) ADVect::Graphics::DrawTextureImageAlpha(*dialogue_bg.current, dialogue_bg.pos_x, dialogue_bg.pos_y, 1.0f); draw_image_transition_crossfade(current_time, avatar); ADVect::Graphics::RenderString(speaker.current, speaker.pos_x, speaker.pos_y, speaker.fill, ADVect::Graphics::TEXT_BOLD); draw_typewriter(current_time, m_text); } const bgfx::Stats* stat = bgfx::getStats(); bgfx::dbgTextClear(); bgfx::dbgTextPrintf(0, 0, 0xf8, " %u FPS", stat->cpuTimerFreq / stat->cpuTimeFrame); bgfx::dbgTextPrintf(0, 1, 0xf8, " NouVeL x ADVect :: %s :: Build %s %s", BX_COMPILER_NAME, __DATE__, __TIME__); bgfx::dbgTextPrintf(0, 2, 0xf8, " SDL %i.%i.%2i :: bgfx 1.%i :: %s", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL, BGFX_API_VERSION, bgfx::getRendererName(bgfx::getRendererType())); bgfx::dbgTextPrintf(0, 3, 0xf8, " NVL Director State: %s", NVL::to_std_string(director->description).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: running = false; break; case SDL_KEYDOWN: if (!event.key.repeat) m_keys[event.key.keysym.scancode] = true; break; case SDL_KEYUP: if (!event.key.repeat) m_keys[event.key.keysym.scancode] = false; break; case SDL_MOUSEBUTTONDOWN: mouse[event.button.button] = true; break; case SDL_MOUSEBUTTONUP: mouse[event.button.button] = false; break; } } Update(); Render(); last_time = current_time; } } } int main(int argc, char* argv[]) { std::filesystem::current_path("../../ADVect/runtime"); //std::filesystem::current_path("/Users/lachrymal/Projects/NouVeL/ADVect/runtime/"); NVL::Environment::ENVIRONMENT.enter({ { u"Say", NVL::Environment::Variable([](std::vector args) { NVL::Environment::MarkupString str = NVL::Environment::UnpackMarkupVariable(std::get>(args[0].value)); size_t len = str.length(); m_text.change(current_time, str, len * 10, [len](NVL::Number x) { return static_cast(x * len); }); rolling = false; return NVL::Environment::Type::Nil; }, 1) }, { u"SwitchSpeaker", NVL::Environment::Variable([](std::vector args) { speaker.current = std::get(args[0].value); return NVL::Environment::Type::Nil; }, 1) }, { u"BG", NVL::Environment::Variable([](std::vector args) { bg.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(args[0].value))), 200); return NVL::Environment::Type::Nil; }, 1) }, { u"Avatar", NVL::Environment::Variable([](std::vector args) { avatar.change(current_time, ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(args[0].value))), 200); return NVL::Environment::Type::Nil; }, 1) }, { u"BGDialogue", NVL::Environment::Variable([](std::vector args) { dialogue_bg.current = ADVect::Graphics::GetImageTextureFromFile(NVL::to_std_string(std::get(args[0].value))); return NVL::Environment::Type::Nil; }, 1) }, { u"Show", NVL::Environment::Variable([](std::vector args) { std::get)>>(args[0].value)({args[1]}); return NVL::Environment::Type::Nil; }, 2) } }); std::vector scenes = NVL::Parse::ParseFile("dialogue.nvl"); if (scenes.empty()) { std::cerr << "Main: Empty NVL parse, check file" << std::endl; return EXIT_FAILURE; } auto e = NVL::Compiler::Compile(scenes, 0); // auto b = NVL::Compiler::Serialize(a); // std::ifstream f; // f.open("mmoker.nvlb", std::ios::binary); // std::stringstream c; // c << f.rdbuf(); // f.close(); // std::istringstream d(c.str()); // auto e = NVL::Compiler::Deserialize(d); if (!ADVect::Init("ADV Test", e)) return EXIT_FAILURE; ADVect::Run(); ADVect::Shutdown(); return EXIT_SUCCESS; }