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 .vs
.vscode
out out
build build
NVL/.vs NVL/.vs

View file

@ -1,38 +1,176 @@
#include "ADVect.h" #include "ADVect.h"
#include "Common.h"
#include "Environment.h"
#include "Graphics.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 <SDL2/SDL_syswm.h>
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
#include <bgfx/platform.h> #include <bgfx/platform.h>
#include <bx/math.h>
#include <cstddef>
#include <functional>
#include <iostream> #include <iostream>
#include <list>
namespace { 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; SDL_Window* window;
u16 window_width = 1280;
std::string m_name; u16 window_height = 720;
bool running = false; bool running = false;
u16 m_width = 1280;
u16 m_height = 720;
bool m_keys[65536]{}; bool m_keys[65536]{};
std::vector<NVL::Parse::Scene> scenes; u64 init_time, last_time, current_time, delta_t;
u32 current_scene = 0;
std::vector<NVL::Environment::Variable> m_text{};
NVL::String speaker;
u32 scene_pos = 0;
struct ImageTrack { template <typename T>
std::string name; struct Varying {
ADVect::Graphics::ImageTexture* current = nullptr; u64 begin, duration;
i32 pos_x = 0, pos_y = 0; 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{}; struct NamedImageTransitionTrack : NamedImageTrack {
ImageTrack* find_image_track(const std::string& s) { 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) for (auto& t : tracks_img)
if (t.name == s) { if (t.name == s) {
return &t; return &t;
@ -42,7 +180,7 @@ namespace {
} }
bool add_image_track(const std::string& s) { bool add_image_track(const std::string& s) {
if (find_image_track(s) == nullptr) { if (find_image_track(s) == nullptr) {
ImageTrack t; NamedImageTrack t;
t.name = s; t.name = s;
tracks_img.push_back(std::move(t)); tracks_img.push_back(std::move(t));
return true; return true;
@ -50,11 +188,12 @@ namespace {
std::cerr << "ADV: Redefinition of ImageTrack " << s << std::endl; std::cerr << "ADV: Redefinition of ImageTrack " << s << std::endl;
return false; return false;
} }
*/
} }
namespace ADVect { namespace ADVect {
bool 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 scenes = sc; // sure make a copy whatever
if (SDL_Init(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO)) {
@ -62,7 +201,7 @@ namespace ADVect {
return false; 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) { if (window == NULL) {
std::cerr << "ADV: Failed to create window: " << SDL_GetError() << std::endl; std::cerr << "ADV: Failed to create window: " << SDL_GetError() << std::endl;
return false; return false;
@ -70,8 +209,8 @@ namespace ADVect {
bgfx::Init bgfxInit; bgfx::Init bgfxInit;
bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer. bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer.
bgfxInit.resolution.width = m_width; bgfxInit.resolution.width = window_width;
bgfxInit.resolution.height = m_height; bgfxInit.resolution.height = window_height;
bgfxInit.resolution.reset = BGFX_RESET_VSYNC; bgfxInit.resolution.reset = BGFX_RESET_VSYNC;
#if !BX_PLATFORM_EMSCRIPTEN #if !BX_PLATFORM_EMSCRIPTEN
@ -98,19 +237,22 @@ namespace ADVect {
}; };
bgfx::setDebug(BGFX_DEBUG_TEXT); bgfx::setDebug(BGFX_DEBUG_TEXT);
bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443322ff, 1.0f, 0); 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); bgfx::setViewMode(0, bgfx::ViewMode::Sequential);
float view[16]; float view[16];
bx::mtxTranslate(view, 0.f, 0.f, 1.0f); bx::mtxTranslate(view, 0.f, 0.f, 1.0f);
float proj[16]; 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); 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; std::cerr << "ADV: Graphics init failed" << std::endl;
return false; return false;
} }
bg.draw = draw_image_transition_fade;
avatar.draw = draw_image_transition_crossfade;
Advance(); Advance();
return true; return true;
} }
@ -143,31 +285,45 @@ namespace ADVect {
Advance(); Advance();
m_keys[SDL_SCANCODE_SPACE] = false; m_keys[SDL_SCANCODE_SPACE] = false;
} }
bg.check();
avatar.check();
m_text.check();
} }
void Render() { void Render() {
bgfx::touch(0); bgfx::touch(0);
/*
for (auto& t : tracks_img) { for (auto& t : tracks_img) {
if (t.current != nullptr) if (t.current != nullptr)
ADVect::Graphics::DrawTextureImage(*t.current, t.pos_x, t.pos_y); 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::dbgTextClear();
bgfx::dbgTextPrintf(0, 44, 0xF8, "NouVeL x ADVect :: %s :: %s %s", BX_COMPILER_NAME, __DATE__, __TIME__); bgfx::dbgTextPrintf(0, 0, 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, 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, 42, 0xF8, "Current Position: %u", scene_pos); bgfx::dbgTextPrintf(0, 2, 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, 3, 0xf8, "Current Scene: %s", NVL::to_std_string(scenes[current_scene].name).c_str());
bgfx::frame(); bgfx::frame();
} }
void Run() { void Run() {
last_time = init_time = SDL_GetTicks64();
running = true; running = true;
while (running) { while (running) {
current_time = SDL_GetTicks64();
delta_t = current_time - last_time;
for (SDL_Event event; SDL_PollEvent(&event);) { for (SDL_Event event; SDL_PollEvent(&event);) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
@ -184,40 +340,42 @@ namespace ADVect {
} }
Update(); Update();
Render(); Render();
last_time = current_time;
} }
} }
} }
int main(int argc, char* argv[]) { 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({ NVL::Environment::ENVIRONMENT.enter({
{ {
u"Say", u"Say",
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { 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; return NVL::Environment::Type::Nil;
}, 2) }, 2)
}, },
{ {
u"SwitchSpeaker", u"SwitchSpeaker",
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { 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; return NVL::Environment::Type::Nil;
}, 1) }, 1)
}, },
{ /* {
u"ImageTrack", u"ImageTrack",
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { 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))); add_image_track(NVL::to_std_string(std::get<NVL::String>(NVL::Environment::Variable(args[0]).value)));
return NVL::Environment::Type::Nil; return NVL::Environment::Type::Nil;
}, 1) }, 1)
}, },*/
{ {
u"Show", u"Show",
NVL::Environment::Variable([](std::vector<NVL::Environment::Variable> args) { 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)); 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) { if (t == nullptr) {
std::cerr << "ADV: Cannot find ImageTrack " << name << std::endl; 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 s = std::get<NVL::String>(NVL::Environment::Variable(args[1]).value);
auto s2 = NVL::to_std_string(s); auto s2 = NVL::to_std_string(s);
t->current = ADVect::Graphics::GetImageTextureFromFile(s2); 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; return NVL::Environment::Type::Nil;
}, 2) }, 2)
} }
}); });
std::vector<NVL::Parse::Scene> SCENES = NVL::Parse::ParseFile(PJ_DIR + "dialogue.nvl"); 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::Run();
ADVect::Shutdown(); ADVect::Shutdown();

View file

@ -1,9 +1,9 @@
#pragma once
#include <vector> #include <vector>
#include <string> #include <string>
#include <Parser.h> #include <Parser.h>
#include <SDL2/SDL.h>
#include <Environment.h> #include <Environment.h>
#include <Common.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) 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. # TODO: Add tests and install targets if needed.
include_directories ("include" "../NVL/") include_directories ("include" "../NVL/")

View file

@ -1,6 +1,7 @@
#include "Graphics.h"
#include "Environment.h"
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include "Graphics.h"
#include <bx/math.h> #include <bx/math.h>
@ -61,7 +62,7 @@ namespace {
{ 1.f, 1.f, 0.0f, 1.0f, 1.0f } { 1.f, 1.f, 0.0f, 1.0f, 1.0f }
}; };
static const uint16_t quad_indices[] = static const u16 quad_indices[] =
{ {
0, 2, 1, 0, 2, 1,
1, 2, 3 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; Font f;
error = FT_New_Face(library, path, 0, &f.face); error = FT_New_Face(library, path, 0, &f.face);
@ -135,7 +136,7 @@ namespace {
ImageTexture i; ImageTexture i;
i.buffer = stbi_load(file.c_str(), &i.w, &i.h, &i.channels, 0); i.buffer = stbi_load(file.c_str(), &i.w, &i.h, &i.channels, 0);
if (i.buffer == NULL) { 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; return std::nullopt;
} }
const bgfx::Memory* buf = bgfx::makeRef(i.buffer, i.w * i.h * i.channels * sizeof(u8)); const bgfx::Memory* buf = bgfx::makeRef(i.buffer, i.w * i.h * i.channels * sizeof(u8));
@ -157,8 +158,10 @@ namespace {
} }
Font regular, bold; Font regular, bold;
bgfx::ProgramHandle a_program, img_program; bgfx::ProgramHandle a_program, img_program, imga_program;
bgfx::UniformHandle s_texColor; bgfx::UniformHandle s_texColor;
bgfx::UniformHandle imga_opacity;
bgfx::IndexBufferHandle ibh; bgfx::IndexBufferHandle ibh;
bgfx::VertexBufferHandle vbh; bgfx::VertexBufferHandle vbh;
@ -175,8 +178,8 @@ namespace ADVect::Graphics {
return false; return false;
} }
if (auto f = init_font("SourceHanSerif-Regular.ttc")) regular = *f; else return false; if (auto f = get_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-Heavy.ttc")) bold = *f; else return false;
pcvDecl.begin() pcvDecl.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .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))); ibh = bgfx::createIndexBuffer(bgfx::makeRef(quad_indices, sizeof(quad_indices)));
vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl); vbh = bgfx::createVertexBuffer(bgfx::makeRef(quad_vert, sizeof(quad_vert)), pcvDecl);
img_program = load_shader_program("test"); img_program = load_shader_program("test"); // RGBA
a_program = load_shader_program("swizzle_aaaa"); 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); s_texColor = bgfx::createUniform("s_texColor", bgfx::UniformType::Sampler);
return true; return true;
@ -204,16 +209,18 @@ namespace ADVect::Graphics {
bgfx::destroy(a_program); bgfx::destroy(a_program);
bgfx::destroy(img_program); bgfx::destroy(img_program);
bgfx::destroy(imga_program);
bgfx::destroy(ibh); bgfx::destroy(ibh);
bgfx::destroy(vbh); bgfx::destroy(vbh);
bgfx::destroy(s_texColor); bgfx::destroy(s_texColor);
bgfx::destroy(imga_opacity);
} }
// Draws quad with texture on Z = 0 // 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) { 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::mtxTranslate(mtx1, pos_x, pos_y, 0.0f);
bx::mtxScale(mtx2, w, h, 1.0f); bx::mtxScale(mtx2, w, h, 1.0f);
bx::mtxMul(mtx3, mtx2, mtx1); bx::mtxMul(mtx3, mtx2, mtx1);
@ -237,6 +244,13 @@ namespace ADVect::Graphics {
DrawTextureImage(img.tx, pos_x, pos_y, img.w, img.h); 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) { ImageTexture* GetImageTextureFromFile(const std::string& file) {
if (imgs.find(file) == imgs.end()) { if (imgs.find(file) == imgs.end()) {
ImageTexture img; 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); 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; Font* f = &regular;
switch (style_flags) { switch (style_flags) {
case TEXT_NONE: break; case TEXT_NONE: break;
@ -267,7 +281,7 @@ namespace ADVect::Graphics {
f->cache_char(c); f->cache_char(c);
pos_x += slot->bitmap_left; 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) { if (slot->bitmap.width != 0) {
DrawTextureStencilAlpha((f->cache)[c], pos_x, ypos, slot->bitmap.width, slot->bitmap.rows); 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); RenderString(s, x, y, col, 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& ms, 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);
// We assume markups are already sorted // 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; u32 style_flags = TEXT_NONE;
const NVL::String* ruby = nullptr; 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; } if (e.first == u"b") { style_flags |= TEXT_BOLD; }
else if (e.first == u"i") { style_flags |= TEXT_ITALIC; } else if (e.first == u"i") { style_flags |= TEXT_ITALIC; }
else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; } else if (e.first == u"u") { style_flags |= TEXT_UNDERLINE; }
@ -318,17 +317,10 @@ namespace ADVect::Graphics {
if (ruby != nullptr) { if (ruby != nullptr) {
u32 temp_x = pos_x, temp_y = pos_y + 20; 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); RenderString(s.str, 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);
} }
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 <SDL2/SDL.h>
#include <bgfx/bgfx.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 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 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 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 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 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 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 = [ plats = [
{ 'location': 'glsl', 'frag': '140', 'vert': '140' }, P('glsl', '140', '140'),
{ 'location': 'dx11', 'frag': 'ps_5_0', 'vert': 'vs_5_0' }, P('dx11', 'ps_5_0', 'vs_5_0'),
{ 'location': 'spirv', 'frag': 'spirv', 'vert': 'spirv' } P('spirv', 'spirv', 'spirv')
] ]
for root, dirs, _ in os.walk('shaders'): for root, dirs, _ in os.walk('shaders'):
for name in dirs: for name in dirs:
for config in plats: 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" "--type", "fragment"
"--platform", "windows", "--platform", "windows",
"--profile", config['frag'], "--profile", config['frag'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"), "--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "ext\\bgfx\\bgfx\\examples\\common",
"-i", "ext\\bgfx\\bgfx\\src", "-i", "ext\\bgfx\\bgfx\\src",
"-o", "..\\out\\build\\x64-Debug\\ADVect\\shaders\\" + config['location'] + "\\" + name + ".frag.bin"]) "-o", OUT + config['location'] + "\\" + name + ".frag.bin"])
subprocess.run(["..\\out\\install\\x64-Debug\\bin\\shaderc", "-f", os.path.join(root, name, name + '.vert'), subprocess.run([SHADERC, "-f", os.path.join(root, name, name + '.vert'),
"--type", "vertex" "--type", "vertex"
"--platform", "windows", "--platform", "windows",
"--profile", config['vert'], "--profile", config['vert'],
"--varyingdef", os.path.join(root, name, "varying.def.sc"), "--varyingdef", os.path.join(root, name, "varying.def.sc"),
"-i", "ext\\bgfx\\bgfx\\examples\\common", "-i", "ext\\bgfx\\bgfx\\examples\\common",
"-i", "ext\\bgfx\\bgfx\\src", "-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 <bgfx_shader.sh>
#include <shaderlib.sh> #include <shaderlib.sh>
uniform vec4 f_opacity;
SAMPLER2D(s_texColor, 0); SAMPLER2D(s_texColor, 0);
void main() void main()
{ {
vec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y); 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", "name": "x64-Release",
"generator": "Ninja", "generator": "Ninja",
"configurationType": "RelWithDebInfo", "configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}", "buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "", "cmakeCommandArgs": "",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ], "inheritEnvironments": [ "clang_cl_x64" ]
"variables": []
} }
] ]
} }

View file

@ -86,26 +86,55 @@ namespace NVL::Environment {
Apply(c); Apply(c);
} }
// Check ParseMarkup for more information // Check MatchMarkup for more information
Markup UnpackMarkupVariable(const Variable& m) { MarkupString UnpackMarkupVariable(const std::vector<Variable>& v) {
const auto& range = std::get<std::vector<Variable>>(std::get<std::vector<Variable>>(m.value)[0].value); MarkupString ms{};
const u32 begin = std::get<Number>(range[0].value), end = std::get<Number>(range[1].value); 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; 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) { if (combination.type == Type::String) {
const String ef = std::get<String>(combination.value); const String ef = std::get<String>(combination.value);
efs.push_back({ ef, {} }); efs.push_back({ ef, {} });
}
else if (combination.type == Type::Array) {
const std::vector<Variable>& ef_t = std::get<std::vector<Variable>>(combination.value);
const String& ef = std::get<String>(ef_t[0].value);
const std::vector<Variable>& args = std::get<std::vector<Variable>>(ef_t[1].value);
std::vector<String> ss{};
for (const auto& s : args) { ss.push_back(std::get<String>(s.value)); }
efs.push_back({ ef, ss });
}
} }
else if (combination.type == Type::Array) { ms.segments.push_back({ s, efs });
const std::vector<Variable>& ef_t = std::get<std::vector<Variable>>(combination.value); }
const String& ef = std::get<String>(ef_t[0].value); return ms;
const std::vector<Variable>& args = std::get<std::vector<Variable>>(ef_t[1].value); }
std::vector<String> ss{};
for (const auto& s : args) { ss.push_back(std::get<String>(s.value)); } size_t MarkupString::length() const {
efs.push_back({ ef, ss }); size_t r = 0;
for (const auto& s : segments)
r += s.str.length();
return r;
}
MarkupString MarkupString::substr(size_t i) const {
size_t r = 0;
MarkupString res;
for (const auto& s : segments) {
size_t last_r = r;
r += s.str.length();
if (r <= i)
res.segments.push_back(s);
else {
auto copy = s;
copy.str = copy.str.substr(0, i - last_r);
res.segments.push_back(copy);
break;
} }
} }
return { begin, end, efs }; return res;
} }
} }

View file

@ -39,9 +39,14 @@ namespace NVL::Environment {
Variable Apply(const Parse::Command& c); Variable Apply(const Parse::Command& c);
void EvalScene(const Parse::Scene & s); void EvalScene(const Parse::Scene & s);
struct Markup { struct MarkupSegment {
u32 begin, end; String str;
std::vector<std::pair<String, std::vector<String>>> efs; 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

@ -328,63 +328,54 @@ namespace {
} }
/* /*
* NVL Markup Parsetree * NVL Markup Parsetree
* *
* * - Vec:2 - Num: Markup begin * * - Vec:N - Vec:2 - Str: Str segment contents
* | |
* | - Num: Markup end
* |
* - Vec:N - Str: T of Markup
* |
* OR
* |
* - Vec:2 - Str: T of Markup
* | * |
* - Vec: Params * - Vec:N - Str: T of Markup
* |
* OR
* |
* - Vec:2 - Str: T of Markup
* |
* - Vec: Params
*/ */
Parse::Object MatchMarkup(String& s) { Parse::Object MatchMarkup(const String& s) {
static const srell::basic_regex<Char> 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 effect(uR"(\s*(?:([^,\(\)]+?)\s*\(\s*([^\(\)]+?)\s*\)|([^,\(\)]+?))\s*(?:,\s*|$))"), // G1 & G2 -> Func, G3 -> Attr
param(uR"(([^,]+?)\s*(?:,\s*|$))"); // Comma split of func args 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; srell::match_results<String::const_iterator> tags_match, effects_match, params_match;
String reconstruction{}; bool has_markup = false;
size_t running_offset = 0; // to account for characters removed
bool has_markup{};
// Match tags // Match tags
std::vector<Parse::Object> segments;
String::const_iterator tags_start(s.cbegin()); String::const_iterator tags_start(s.cbegin());
while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) { while (srell::regex_search(tags_start, s.cend(), tags_match, typer)) {
has_markup = true; 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>{ String inner = tags_match[2].str(); // markupped
{ static_cast<Number>(begin) },
{ static_cast<Number>(begin + (tags_match[2].second - tags_match[2].first)) }
}
} };
std::vector<Parse::Object> effects{};
// Match markup options // Match markup options
std::vector<Parse::Object> effects{};
String::const_iterator effects_start(tags_match[1].first); String::const_iterator effects_start(tags_match[1].first);
while (srell::regex_search(effects_start, tags_match[1].second, effects_match, effect)) { 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() }); effects.push_back({ Parse::Type::String, effects_match[3].str() });
} }
else { else { // no params
// Comma split
std::vector<Parse::Object> args; std::vector<Parse::Object> args;
String::const_iterator params_start(effects_match[2].first); String::const_iterator params_start(effects_match[2].first);
while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) { while (srell::regex_search(params_start, effects_match[2].second, params_match, param)) {
@ -396,20 +387,26 @@ namespace {
} }
effects_start = effects_match.suffix().first; effects_start = effects_match.suffix().first;
} }
running_offset += tags_match[0].second - tags_match[2].second;
tags_start = tags_match.suffix().first; 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) { 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, segments };
return { Parse::Type::Array, tags };
} }
else { 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"); throw std::runtime_error("Malformed speaker command");
} }
String copy{ s }; return { { Parse::Type::Symbol, u"Say" }, MatchMarkup(s) };
Parse::Object tags = MatchMarkup(copy); // THIS WILL MODIFY COPY
return { { Parse::Type::Symbol, u"Say" }, { Parse::Type::String, copy }, tags };
} }
Parse::Scene ParseScene(const String& f, size_t& pos) { Parse::Scene ParseScene(const String& f, size_t& pos) {

View file

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

View file

@ -1,19 +1,57 @@
BEGIN Scene1 BEGIN Scene1
ImageTrack BG Show BGDialogue "grad.png"
ImageTrack Avatar
Show BG "image.png"
<<- <<-
*!Show Avatar "mmaker.png" *!Show Avatar "mmaker.png"
[MMaker] [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" *! Show BG "image2.jpg"
Commencing JS hypnosis... Commencing JS hypnosis...
*! Show BG "image3.png" *! Show BG "image.png"
*!Show Avatar "terrio.png" *!Show Avatar "terrio.png"
[Terrio] [Terrio]