/****************************************************************************** * File - simple_render_scene.cpp * Author - Joey Pollack * Date - 2021/10/27 (y/m/d) * Mod Date - 2021/10/27 (y/m/d) * Description - Displays a simple scene that tests basic render features. ******************************************************************************/ #include "simple_render_scene.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace lunarium { SimpleRenderScene::SimpleRenderScene(uint32_t logCat) : BaseScene(logCat), mTestMode(TestMode::Basic), mFrameTime(0.0), mNumFrames(0), mpTestImageLoad3(nullptr) { srand((u32)time(0)); } SimpleRenderScene::~SimpleRenderScene() { delete mpTestImageLoad; } void SimpleRenderScene::OnLoad() { Logger::Info(mLogCat, "Running Simple Render Test Scene"); mTextBoxWidth = 500; // Currently the full default window size mImageSize.Width = 1280; mImageSize.Height = 720; // Create the render textures mFrameBufferOne = FrameBuffer::Create(mImageSize.Width, mImageSize.Height); //Core::Graphics().CreateRenderTexture(mImageSize.Width, mImageSize.Height, 4); mFrameBufferTwo = FrameBuffer::Create(1024, 1024); //Core::Graphics().CreateRenderTexture(1024, 1024, 4); // Load test image int w, h, n; stbi_set_flip_vertically_on_load(0); unsigned char* buffer = stbi_load("LinkToThePast1_sized.png", &w, &h, &n, 0); TextureFormat format = TextureFormat::RGBA; if (n == 3) { format = TextureFormat::RGB; } mpTestImageLoad = Texture::Create(buffer, w, h, format, true); mSrcWidth = w; mSrcHeight = h; delete[] buffer; stbi_set_flip_vertically_on_load(0); buffer = stbi_load("debug_texture.jpeg", &w, &h, &n, 0); //buffer = stbi_load("lunarium_text_test.png", &w, &h, &n, 0); format = TextureFormat::RGBA; if (n == 3) { format = TextureFormat::RGB; } else if (n == 1) { format = TextureFormat::RED; } mpTestImageLoad2 = Texture::Create(buffer, w, h, format); delete[] buffer; stbi_set_flip_vertically_on_load(0); buffer = stbi_load("lunarium_text_test.png", &w, &h, &n, 0); format = TextureFormat::RGBA; if (n == 3) { format = TextureFormat::RGB; } else if (n == 1) { format = TextureFormat::RED; } mpTestImageLoad3 = Texture::Create(buffer, w, h, format); delete[] buffer; mQuads = new Rectangle[NUM_QUADS]; for (int i = 0; i < NUM_QUADS; i++) { float x = (rand() % 1000); float y = (rand() % 600); float w = (rand() % 200) + 10; float h = (rand() % 200) + 10; mQuads[i] = Rectangle(x, y, w, h); } mQuadColors = new Color[NUM_QUADS]; mQuadTexures = new Texture*[NUM_QUADS]; for (int i = 0; i < NUM_QUADS; i++) { mQuadTexures[i] = (i % 2 == 0) ? mpTestImageLoad : mpTestImageLoad2; mQuadColors[i].R = ((float)(rand() % 10000)) / 10000.0f; mQuadColors[i].G = ((float)(rand() % 10000)) / 10000.0f; mQuadColors[i].B = ((float)(rand() % 10000)) / 10000.0f; mQuadColors[i].A = 1.0f; } angle = 0.0f; box_angle = 0.0f; mTextDebugPosX = 200; mSubTex = Rectangle::MakeFromTopLeft(0, 0, 256, 256); } void SimpleRenderScene::OnTick(double delta) { if (Core::Input().IsKeyDown(KeyCode::ESCAPE)) { Core::GetInstance().SignalShutdown(); } // Textbox size adjustment if (Core::Input().IsKeyDown(KeyCode::LEFT)) { if (mTestMode == TestMode::Basic) mTextBoxWidth -= 10; if (mTestMode == TestMode::String) mTextDebugPosX -= 10; } if (Core::Input().IsKeyDown(KeyCode::RIGHT)) { mTextBoxWidth += 10; if (mTestMode == TestMode::Basic) mTextBoxWidth += 10; if (mTestMode == TestMode::String) mTextDebugPosX += 10; } if (Core::Input().IsKeyDown(KeyCode::R)) { mSrcWidth -= 10.0f; mSrcHeight -= 10.0f; } if (Core::Input().IsKeyDown(KeyCode::F)) { mSrcWidth += 10.0f; mSrcHeight += 10.0f; } mTextBoxWidth = Math::ClampI(mTextBoxWidth, 20, 500); // Image Size adjustment if (Core::Input().IsKeyDown(KeyCode::DOWN)) { mImageSize.Width -= 10; mImageSize.Height -= 10; } if (Core::Input().IsKeyDown(KeyCode::UP)) { mImageSize.Width += 10; mImageSize.Height += 10; } if (Core::Input().IsKeyDown(KeyCode::PAGE_UP)) { angle += 0.1f; } if (Core::Input().IsKeyDown(KeyCode::PAGE_DOWN)) { angle -= 0.1f; } if (Core::Input().IsKeyPressed(KeyCode::TAB)) { if (mTestMode == TestMode::Basic) mTestMode = TestMode::Stress; else if (mTestMode == TestMode::Stress) { mSubTex = Rectangle::MakeFromTopLeft(2858, 0, 32, 32); mTestMode = TestMode::String; } else if (mTestMode == TestMode::String) { mTestMode = TestMode::Basic; mSubTex = Rectangle::MakeFromTopLeft(0, 0, 256, 256); } } if (Core::Input().IsKeyPressed(KeyCode::Q)) { // Test writing out a rendered image with transparency Renderer2D& g = Core::Graphics(); Color prev = g.GetClearColor(); g.SetClearColor(Color(0.0f, 0.0f, 0.0f, 0.0f)); mFrameBufferTwo->Bind(); OrthographicCamera cam(Vec2f{0.0f, 0.0f}, Sizef{(float)mFrameBufferTwo->GetTexture()->GetWidth(), (float)mFrameBufferTwo->GetTexture()->GetHeight()}); g.BeginDraw(&cam); // if (Failed(result)) // { // Logger::Warn(mLogCat, "Unable to render to texture: %s", result.Description.c_str()); // return; // } Logger::Info(mLogCat, "Running transparent image test"); g.DrawQuad(Rectangle(500, 400, 300, 300), Color(0.5f, 0.0f, 0.75f, 1.0f)); g.DrawQuad(Rectangle(200, 300, 100, 100), Color(0.2f, 0.5f, 0.4f, 1.0f), nullptr, 45.0f); g.DrawString("This is a test of rendering an image with transparency", Rectangle::MakeFromTopLeft(50, 50, 600, 200), Color(0.0f, 1.0f, 0.2f, 1.0f), 0.5f); g.EndDraw(); mpRenderedImage = mFrameBufferTwo->GetTexture(); mFrameBufferTwo->Unbind(); //mpRenderedImage = Core::GetInstance().EndRenderToTexture(); g.SetClearColor(prev); stbi_flip_vertically_on_write(1); stbi_write_png("lunarium_test_image.png", mpRenderedImage->GetWidth(), mpRenderedImage->GetHeight(), 4, mpRenderedImage->GetPixels(), mpRenderedImage->GetWidth() * 4); //Logger::Info(mLogCat, "") } if (Core::Input().IsKeyPressed(KeyCode::T)) { Texture* dt = Core::Graphics().GetTextDebugTexture(); stbi_flip_vertically_on_write(0); stbi_write_png("lunarium_text_test.png", dt->GetWidth(), dt->GetHeight(), 1, dt->GetPixels(), dt->GetWidth() * 1); Logger::Info(mLogCat, "Saved Text test image"); } if (Core::Input().IsKeyPressed(KeyCode::F)) { flip_image = !flip_image; } mImageSize.Width = Math::ClampI(mImageSize.Width, 320, 1280); mImageSize.Height = Math::ClampI(mImageSize.Height, 180, 720); // Render to texture testing mFrameBufferOne->Bind(); OrthographicCamera cam(Vec2f{0.0f, 0.0f}, Sizef{(float)mFrameBufferOne->GetTexture()->GetWidth(), (float)mFrameBufferOne->GetTexture()->GetHeight()}); Renderer2D& g = Core::Graphics(); g.BeginDraw(&cam); g.DrawQuad(Rectangle(300, 300, 150, 150), Color::Red()); g.DrawQuad(Rectangle(200, 300, 100, 100), Color(0.2f, 0.5f, 0.4f, 1.0f), nullptr, 45.0f); //g.DrawFilledEllipse(glm::vec2(600, 300), glm::vec2(100, 150), Color(1.0f, 0.0f, 1.0f, 1.0f), 100); g.DrawString("This is a test of the text renderer!", Rectangle::MakeFromTopLeft(100, 200, mTextBoxWidth, 300), Color(0.0f, 1.0f, 1.0f, 1.0f), 0.5f); g.EndDraw(); mpRenderedImage = mFrameBufferOne->GetTexture(); if (flip_image) mpRenderedImage->FlipVertically(); mFrameBufferOne->Unbind(); box_angle += 0.01f; int w, h; Core::MainWindow().GetFramebufferSize(&w, &h); OrthographicCamera main_cam(Vec2f { 0.0f, 0.0f }, Sizef { (float)w, (float)h }); Core::GUI().NewFrame(); mTimer.Reset(); Core::Graphics().BeginDraw(&main_cam); switch (mTestMode) { case TestMode::Basic: RenderScene(Core::Graphics()); break; case TestMode::Stress: RenderBatchStressTest(Core::Graphics()); break; case TestMode::String: RenderStringTest(Core::Graphics()); break; } Core::Graphics().EndDraw(); // Graphics end draw must happen before GUI end frame DrawStatsGUI(); Core::GUI().EndFrame(); Core::MainWindow().SwapBuffers(); mFrameTime += mTimer.GetElapsedSeconds(); mNumFrames++; mRenderStats = Core::Graphics().GetFrameStats(); Core::Graphics().ResetFrameStats(); //std::this_thread::sleep_for (std::chrono::seconds(2)); } void SimpleRenderScene::RenderScene(Renderer2D& g) { Rectangle image_rect = Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mpRenderedImage->GetWidth(), (float)mpRenderedImage->GetHeight()); g.DrawQuad(image_rect, Color::White(), mpRenderedImage, angle); //g.DrawQuad(Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mImageSize.Width, (float)mImageSize.Height), Color(1.0f, 1.0f, 0.0f, 1.0f), nullptr, angle); g.DrawQuad(Rectangle(100, 100, 16, 16), Color::White(), mpTestImageLoad2, 0.0f, mSubTex); g.DrawSprite(mpTestImageLoad2, glm::vec2(600, 200), Rectangle::MakeFromTopLeft(255, 255, 255, 255)); //g->DrawImage(*mpTestImageLoad, glm::vec2(0.0f, 0.0f), Color::White()); //Rectangle src = Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mpTestImageLoad->GetWidth(), (float)mpTestImageLoad->GetHeight()); //Rectangle src = Rectangle::MakeFromTopLeft(0.0f, 0.0f, mSrcWidth, mSrcHeight); Rectangle src = Rectangle::MakeFromTopLeft(0.0f, 0.0f, 16, 16); Rectangle dest = Rectangle::MakeFromTopLeft(900.0f, 350.0f, 256.0f, 256.0f); g.DrawQuad(dest, Color::White(), mpTestImageLoad, 0.0f, src); // g->DrawImage(*mpTestImageLoad, src, // dest, Color(1.0f, 1.0f, 1.0f, 0.8f)); } void SimpleRenderScene::RenderBatchStressTest(Renderer2D& g) { for (int i = 0; i < mNumQuadsToRender; i++) { Texture* t = mUseTextures ? mQuadTexures[i] : nullptr; g.DrawQuad(mQuads[i], mQuadColors[i], t, box_angle + (i / 10.0f)); } } void SimpleRenderScene::RenderStringTest(Renderer2D& g) { Texture* dt = g.GetTextDebugTexture(); g.DrawQuad(Rectangle(mTextDebugPosX, 300, dt->GetWidth() , dt->GetHeight() ), Color::Blue(), dt); g.DrawQuad(Rectangle(200, 100, 32, 32), Color(0.25f, 0.75f, 0.6f, 1.0f), mpTestImageLoad3, 0.0f, mSubTex); g.DrawString("A", Rectangle(200, 170, 32, 32), Color(0.25f, 0.75f, 0.6f, 1.0f)); g.DrawString("This is a test string!", Rectangle::MakeFromTopLeft(100, 500, 500, 50), Color::Green()); g.DrawString("This is a very long string that should end up on more than one line when printed out test string!", Rectangle::MakeFromTopLeft(300, 50, 400, 500), Color::Red()); } void SimpleRenderScene::DrawStatsGUI() { const char* mode_names[3] = { "Basic", "Stress", "String" }; ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400, 800)); ImGui::Begin("RENDER INFO"); ImGui::BeginChild("Scene Info", ImVec2(ImGui::GetWindowSize().x - 15, ImGui::GetFrameHeightWithSpacing() * 3.5f), true); ImGui::Text("Scene Info"); ImGui::Separator(); ImGui::Combo("Scene Mode", (int*)&mTestMode, mode_names, 3); ImGui::EndChild(); ImGui::BeginChild("Per Frame", ImVec2(ImGui::GetWindowSize().x - 15, ImGui::GetFrameHeightWithSpacing() * 3.5f), true); ImGui::Text("Per Frame"); ImGui::Separator(); ImGui::Text("Number of triangles: %d", mRenderStats.NumTris); ImGui::Text("Draw calls: %d", mRenderStats.DrawCalls); ImGui::EndChild(); ImGui::BeginChild("General", ImVec2(ImGui::GetWindowSize().x - 15, ImGui::GetFrameHeightWithSpacing() * 4.5f), true); ImGui::Text("General Info"); ImGui::Separator(); ImGui::Text("Average Render time: %f", Core::GetInstance().GetFrameData().AverageFrameTime); ImGui::Text("FPS: %d", Core::GetInstance().GetFrameData().CurrentFPS); ImGui::Text("Frame Number: %d", mNumFrames); ImGui::EndChild(); ImGui::BeginChild("Settings", ImVec2(ImGui::GetWindowSize().x - 15, ImGui::GetFrameHeightWithSpacing() * 4.5f), true); ImGui::Text("Settings"); ImGui::Separator(); if (mTestMode == TestMode::Stress) { ImGui::InputInt("Number of Quads to draw", &mNumQuadsToRender); ImGui::Checkbox("Draw Textures", &mUseTextures); } else if (mTestMode == TestMode::Basic) { float vals[4] = {mSubTex.left(), mSubTex.top(), mSubTex.HalfWidth * 2, mSubTex.HalfHeight * 2 }; if (ImGui::DragFloat4("Sub Texture Rect", vals)) { mSubTex = Rectangle::MakeFromTopLeft(vals[0], vals[1], vals[2], vals[3]); } if (ImGui::Button("Reset")) { mSubTex = Rectangle::MakeFromTopLeft(0.0f, 0.0f, 256.0f, 256.0f); } } ImGui::EndChild(); ImGui::End(); mNumQuadsToRender = Math::ClampI(mNumQuadsToRender, 0, NUM_QUADS); } }