/******************************************************************************
* 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 <core/core.h>
# include <gui/gui.h>
# include <utils/helpers.h>
# include <utils/logger.h>
# include <renderer/texture.h>
# include <renderer/frame_buffer.h>
# include <renderer/orthographic_camera.h>
# include <input/input_manager.h>
# include <utils/stb/std_image_write.h>
# include <utils/stb/stb_image.h>
# include <thread>
# include <chrono>
# include <cstdlib>
# include <ctime>
namespace lunarium
{
SimpleRenderScene : : SimpleRenderScene ( uint32_t logCat )
: BaseScene ( logCat ) , mTestMode ( TestMode : : Basic ) , mShapeMode ( ShapeMode : : Lines ) , 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
LoadImages ( ) ;
GenerateQuads ( ) ;
GenerateLines ( ) ;
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 : : Q ) )
{
DoFrameBufferSaveTest ( ) ;
}
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 ;
case TestMode : : Shapes : RenderShapesTest ( 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));
}
/////////////////////////////////////////////////////////////////////
// RENDER METHODS RENDER METHODS
/////////////////////////////////////////////////////////////////////
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 : : RenderShapesTest ( Renderer2D & g )
{
switch ( mShapeMode )
{
case ShapeMode : : Boxes :
{
} break ;
case ShapeMode : : Lines :
{
g . DrawLine ( glm : : vec2 ( 30.0f , 200.0f ) , glm : : vec2 ( 400.0f , 400.0f ) , Color : : Green ( ) , 3.0f , box_angle * 3.0f ) ;
for ( auto iter = mLines . begin ( ) ; iter ! = mLines . end ( ) ; iter + + )
{
g . DrawLine ( iter - > Position1 , iter - > Position2 , iter - > Color , iter - > Thickness , iter - > Angle ) ;
iter - > Angle + = iter - > RotSpeed ;
}
} break ;
case ShapeMode : : Ellipses :
{
} break ;
}
}
/////////////////////////////////////////////////////////////////////
// GUI DRAWING GUI DRAWING
/////////////////////////////////////////////////////////////////////
void SimpleRenderScene : : DrawStatsGUI ( )
{
const char * mode_names [ 4 ] = { " Basic " , " Stress " , " String " , " Shapes " } ;
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 , 4 ) ;
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 ) ;
}
}
else if ( mTestMode = = TestMode : : Shapes )
{
const char * shape_types [ 3 ] = { " Lines " , " Boxes " , " Ellipses " } ;
ImGui : : Combo ( " Shape Type " , ( int * ) & mShapeMode , shape_types , 3 ) ;
ImGui : : Separator ( ) ;
ImGui : : DragInt ( " Number of Lines " , & mNumLines ) ;
if ( ImGui : : Button ( " Regenerate Shapes " ) )
{
GenerateLines ( ) ;
GenerateEllipses ( ) ;
}
}
ImGui : : EndChild ( ) ;
ImGui : : End ( ) ;
mNumQuadsToRender = Math : : ClampI ( mNumQuadsToRender , 0 , NUM_QUADS ) ;
}
/////////////////////////////////////////////////////////////////////
// HELPERS HELPERS
/////////////////////////////////////////////////////////////////////
void SimpleRenderScene : : LoadImages ( )
{
// Test Image 1
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 ;
// Debug texture
stbi_set_flip_vertically_on_load ( 0 ) ;
buffer = stbi_load ( " debug_texture.jpeg " , & 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 ;
// Text testing texture
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 ;
}
void SimpleRenderScene : : GenerateLines ( )
{
mLines . clear ( ) ;
int window_width = 0 ;
int window_height = 0 ;
Core : : MainWindow ( ) . GetFramebufferSize ( & window_width , & window_height ) ;
for ( int i = 0 ; i < mNumLines ; i + + )
{
mLines . push_back ( LineData
{
glm : : vec2 ( rand ( ) % window_width , rand ( ) % window_height ) ,
glm : : vec2 ( rand ( ) % window_width , rand ( ) % window_height ) ,
Color ( ( ( float ) ( rand ( ) % 10000 ) ) / 10000.0f ,
( ( float ) ( rand ( ) % 10000 ) ) / 10000.0f ,
( ( float ) ( rand ( ) % 10000 ) ) / 10000.0f ,
1.0f ) ,
( ( float ) ( rand ( ) % 180 ) ) ,
( ( float ) ( rand ( ) % 100 ) ) / 100.0f + 0.01f ,
( ( float ) ( rand ( ) % 100 ) ) / 10.0f + 0.5f
} ) ;
}
}
void SimpleRenderScene : : GenerateEllipses ( )
{
}
void SimpleRenderScene : : GenerateQuads ( )
{
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 ;
}
}
void SimpleRenderScene : : DoFrameBufferSaveTest ( )
{
// 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, "")
}
}