Renderer now supports multiple arbitrarily sized frame buffers

Gui_Panel_Refactor
Joeyrp 4 years ago
parent ca9d25073e
commit 7039b1e26b

@ -24,7 +24,7 @@ Core:
✔ Test rotation of images @done (11/1/2021, 2:11:13 PM) ✔ Test rotation of images @done (11/1/2021, 2:11:13 PM)
☐ Fix line rotation @low ☐ Fix line rotation @low
✔ Add Roboto-Regular.ttf as an internal font @high @done (11/3/2021, 8:35:51 PM) ✔ Add Roboto-Regular.ttf as an internal font @high @done (11/3/2021, 8:35:51 PM)
Allow an image size to be passed in for rendering to an image @high Allow an image size to be passed in for rendering to an image @high @done (2/3/2022, 4:07:33 PM)
GUI: GUI:

@ -368,7 +368,7 @@ namespace lunarium
} }
} }
OpRes Core::BeginRenderToTexture() OpRes Core::BeginRenderToTexture(int id)
{ {
if (mbMidRender) if (mbMidRender)
{ {
@ -376,7 +376,7 @@ namespace lunarium
} }
mbMidTextureRender = true; mbMidTextureRender = true;
mpGraphics->BeginDraw(RenderTarget::RT_IMAGE); mpGraphics->BeginDraw(id);
return OpRes::OK(); return OpRes::OK();
} }

@ -41,7 +41,7 @@ namespace lunarium
void RunGameLoop(); void RunGameLoop();
OpRes BeginRenderToTexture(); OpRes BeginRenderToTexture(int id);
Image* EndRenderToTexture(); Image* EndRenderToTexture();

@ -30,16 +30,16 @@ namespace lunarium
protected: // Interface methods for use only by the engine protected: // Interface methods for use only by the engine
friend Core; friend Core;
IGraphics() : mbIsInit(false), mpFBTexture(nullptr) {} IGraphics() : mbIsInit(false) {}
virtual OpRes Initialize(Window* pWindow, bool enableDebugMessages = true) = 0; virtual OpRes Initialize(Window* pWindow, bool enableDebugMessages = true) = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void ResizeCanvas() = 0; virtual void ResizeCanvas() = 0;
// If render target is set to image the image will be the same // framebuffer is the ID of the texture/framebuffer to render to
// size as the window // -1 means draw to the default (most likely the main window) buffer
virtual void BeginDraw(RenderTarget rt = RenderTarget::RT_WINDOW) = 0; virtual void BeginDraw(int framebuffer = -1) = 0;
virtual Image* EndDraw() = 0; virtual Image* EndDraw() = 0;
public: // public: //
@ -47,6 +47,8 @@ namespace lunarium
virtual void SetClearColor(Color c) = 0; virtual void SetClearColor(Color c) = 0;
virtual Color GetClearColor() const = 0; virtual Color GetClearColor() const = 0;
virtual int CreateRenderTexture(int width, int height, int channels) = 0;
// Draw Methods // Draw Methods
virtual void DrawFilledPolygon(float* pVerts, int numVerts, Color color, glm::vec2 position, float angle = 0.0f) = 0; virtual void DrawFilledPolygon(float* pVerts, int numVerts, Color color, glm::vec2 position, float angle = 0.0f) = 0;
virtual void DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle = 0.0f) = 0; virtual void DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle = 0.0f) = 0;
@ -71,7 +73,6 @@ namespace lunarium
bool mbIsInit; bool mbIsInit;
int mDefaultFont; int mDefaultFont;
Color mClearColor; Color mClearColor;
Image* mpFBTexture;
}; };
} }

@ -29,6 +29,10 @@ namespace lunarium
void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam) GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{ {
if (type == GL_DEBUG_TYPE_ERROR)
{
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "OPENGL ERROR");
}
Logger::Log(LogCategory::GRAPHICS, LogLevel::OGL_DEBUG, Logger::Log(LogCategory::GRAPHICS, LogLevel::OGL_DEBUG,
"%s (type: %s, source: %s, severity: %s), message: %s", "%s (type: %s, source: %s, severity: %s), message: %s",
@ -60,7 +64,6 @@ namespace lunarium
} }
mpWindow = pWindow; mpWindow = pWindow;
mpFBTexture = new Image;
ResizeCanvas(); // Also calls InitTextureFrameBuffer ResizeCanvas(); // Also calls InitTextureFrameBuffer
glEnable(GL_BLEND); glEnable(GL_BLEND);
@ -100,41 +103,41 @@ namespace lunarium
void OglGraphics::Shutdown() void OglGraphics::Shutdown()
{ {
// Nothing to clean up at this point // TODO: Clean up frame buffers
} }
void OglGraphics::ResizeCanvas() void OglGraphics::ResizeCanvas()
{ {
// Get viewport size from glfw window // NOTE: METHOD IS NO LONGER NEEDED
glfwGetFramebufferSize(mpWindow->GetWindow(), &mFBWidth, &mFBHeight);
glViewport(0, 0, mFBWidth, mFBHeight);
mProjection = glm::ortho(0.0f, (GLfloat)mFBWidth, (GLfloat)mFBHeight, 0.0f, -1.0f, 1.0f);
// mProjection = glm::ortho(0.0f, (GLfloat)mFBWidth, 0.0f, (GLfloat)mFBHeight, -1.0f, 1.0f);
Logger::Log(LogCategory::GRAPHICS, LogLevel::INFO_VERBOSE,
"glViewport set to %d, %d", mFBWidth, mFBHeight);
InitTextureFrameBuffer();
} }
void OglGraphics::BeginDraw(RenderTarget rt) void OglGraphics::BeginDraw(int framebuffer)
{
mActiveFrameBuffer = framebuffer;
if (mActiveFrameBuffer > -1)
{ {
mRT = rt; mFBWidth = mFrameBuffers[mActiveFrameBuffer]->Texture.GetWidth();
mFBHeight = mFrameBuffers[mActiveFrameBuffer]->Texture.GetHeight();
glViewport(0, 0, mFBWidth, mFBHeight);
mProjection = glm::ortho(0.0f, (GLfloat)mFBWidth, (GLfloat)mFBHeight, 0.0f, -1.0f, 1.0f);
glBindFramebuffer(GL_FRAMEBUFFER, mFrameBuffers[mActiveFrameBuffer]->FBO);
}
else
{
int width = 0, height = 0; int width = 0, height = 0;
mpWindow->GetFramebufferSize(&width, &height); mpWindow->GetFramebufferSize(&width, &height);
if (mFBWidth != width || mFBHeight != height) if (mFBWidth != width || mFBHeight != height)
{ {
ResizeCanvas(); mFBWidth = width;
mFBHeight = height;
glViewport(0, 0, mFBWidth, mFBHeight);
mProjection = glm::ortho(0.0f, (GLfloat)mFBWidth, (GLfloat)mFBHeight, 0.0f, -1.0f, 1.0f);
} }
if (mRT == RenderTarget::RT_IMAGE)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
} }
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -142,27 +145,26 @@ namespace lunarium
Image* OglGraphics::EndDraw() Image* OglGraphics::EndDraw()
{ {
if (mRT == RenderTarget::RT_IMAGE) if (mActiveFrameBuffer > -1)
{ {
FrameBuffer* fb = mFrameBuffers[mActiveFrameBuffer];
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, mpFBTexture->GetGLTextureID()); glBindTexture(GL_TEXTURE_2D, fb->Texture.GetGLTextureID());
// Buffer width and height (in pixels) is the same as the screen size if (fb->Texture.GetFormat() == ImageFormat::RGBA)
// Need to multiply these by the number bytes per pixel {
int bufferSize = mFBWidth * mFBHeight * 4; // NOTE: Assuming 4 channels for now glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)fb->Buffer);
// TODO: Preallocate the buffer so we don't call new every frame! Logger::Log(LogCategory::GRAPHICS, LogLevel::INFO, "RGBA ID: %d", mActiveFrameBuffer);
unsigned char* buffer = new unsigned char[bufferSize]; }
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)buffer); else if (fb->Texture.GetFormat() == ImageFormat::RGB)
{
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, (void*)fb->Buffer);
Logger::Log(LogCategory::GRAPHICS, LogLevel::INFO, "RGB ID: %d", mActiveFrameBuffer);
}
// FlipImageVertically(buffer, mFBWidth, mFBHeight, 1); fb->Texture.SetData(fb->Buffer);
// mpFBTexture->FreeRawData();
mpFBTexture->SetData(buffer);
mpFBTexture->SetWidth(mFBWidth);
mpFBTexture->SetHeight(mFBHeight);
mpFBTexture->SetFormat(ImageFormat::RGBA);
// return a copy of the image return &fb->Texture;
return mpFBTexture;
} }
else else
{ {
@ -188,6 +190,74 @@ namespace lunarium
return mClearColor; return mClearColor;
} }
int OglGraphics::CreateRenderTexture(int width, int height, int channels)
{
FrameBuffer* fb = new FrameBuffer;
fb->Texture.SetWidth(width);
fb->Texture.SetHeight(height);
GLint format = -1;
if (3 == channels)
{
fb->Texture.SetFormat(ImageFormat::RGB);
format = GL_RGB;
}
else if (4 == channels)
{
fb->Texture.SetFormat(ImageFormat::RGBA);
format = GL_RGBA;
}
else
{
Logger::Log(LogCategory::GRAPHICS, LogLevel::ERROR, "OglGraphics::CreateRenderTexture failed - invalid channels value: %n", channels);
return -1;
}
// Frame buffer
glGenFramebuffers(1, &fb->FBO);
glBindFramebuffer(GL_FRAMEBUFFER, fb->FBO);
// Texture
unsigned int id = -1;
glGenTextures(1, &id);
fb->Texture.SetGLTextureID(id);
glBindTexture(GL_TEXTURE_2D, fb->Texture.GetGLTextureID());
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Attach texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->Texture.GetGLTextureID(), 0);
// Render Buffer for depth/stencil testing
glGenRenderbuffers(1, &fb->RBO);
glBindRenderbuffer(GL_RENDERBUFFER, fb->RBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Atach the render buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->RBO);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
Logger::Log(LogCategory::GRAPHICS, LogLevel::WARNING, "Unable to initialize framebuffer for rendering to a texture");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return -1;
}
// finalize the FrameBuffer object
fb->Buffer = new unsigned char[width * height * channels];
fb->Texture.SetData(nullptr);
int next_id = mFrameBuffers.size();
mFrameBuffers[next_id] = fb;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return next_id;
}
// Draw Methods // Draw Methods
void OglGraphics::DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle) void OglGraphics::DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle)
{ {
@ -585,38 +655,41 @@ namespace lunarium
void OglGraphics::InitTextureFrameBuffer() void OglGraphics::InitTextureFrameBuffer()
{ {
// NOTE: METHOD IS NO LONGER NEEDED
// Frame buffer // Frame buffer
glGenFramebuffers(1, &mFBO); // glGenFramebuffers(1, &mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO); // glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
// Texture // // Texture
unsigned int id = -1; // unsigned int id = -1;
glGenTextures(1, &id); // glGenTextures(1, &id);
mpFBTexture->SetGLTextureID(id); // mpFBTexture->SetGLTextureID(id);
glBindTexture(GL_TEXTURE_2D, mpFBTexture->GetGLTextureID()); // glBindTexture(GL_TEXTURE_2D, mpFBTexture->GetGLTextureID());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mFBWidth, mFBHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mFBWidth, mFBHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0); // glBindTexture(GL_TEXTURE_2D, 0);
// Attach texture // // Attach texture
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpFBTexture->GetGLTextureID(), 0); // glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mpFBTexture->GetGLTextureID(), 0);
// Render Buffer for depth/stencil testing // // Render Buffer for depth/stencil testing
glGenRenderbuffers(1, &mRBO); // glGenRenderbuffers(1, &mRBO);
glBindRenderbuffer(GL_RENDERBUFFER, mRBO); // glBindRenderbuffer(GL_RENDERBUFFER, mRBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mFBWidth, mFBHeight); // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mFBWidth, mFBHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0); // glBindRenderbuffer(GL_RENDERBUFFER, 0);
// Atach the render buffer // // Atach the render buffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mRBO); // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mRBO);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) // if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{ // {
Logger::Log(LogCategory::GRAPHICS, LogLevel::WARNING, "Unable to initialize framebuffer for rendering to a texture"); // Logger::Log(LogCategory::GRAPHICS, LogLevel::WARNING, "Unable to initialize framebuffer for rendering to a texture");
} // }
glBindFramebuffer(GL_FRAMEBUFFER, 0); // glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
} }

@ -13,6 +13,7 @@
#include <glad/gl.h> #include <glad/gl.h>
#include "glShader.h" #include "glShader.h"
#include "glText.h" #include "glText.h"
#include <assets/types/image.h>
#include <map> #include <map>
#include <string> #include <string>
@ -31,7 +32,7 @@ namespace lunarium
virtual void ResizeCanvas(); virtual void ResizeCanvas();
virtual void BeginDraw(RenderTarget rt = RenderTarget::RT_WINDOW); virtual void BeginDraw(int framebuffer = -1); // -1 means draw to the window/default frame buffer
/// The image returned by this method is dynamic /// The image returned by this method is dynamic
/// and needs to be cleaned up /// and needs to be cleaned up
@ -42,6 +43,8 @@ namespace lunarium
virtual void SetClearColor(Color c); virtual void SetClearColor(Color c);
virtual Color GetClearColor() const; virtual Color GetClearColor() const;
virtual int CreateRenderTexture(int width, int height, int channels);
// Draw Methods // Draw Methods
virtual void DrawFilledPolygon(float* pVerts, int numVerts, Color color, glm::vec2 position, float angle = 0.0f); virtual void DrawFilledPolygon(float* pVerts, int numVerts, Color color, glm::vec2 position, float angle = 0.0f);
virtual void DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle = 0.0f); virtual void DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle = 0.0f);
@ -70,9 +73,15 @@ namespace lunarium
int mFBHeight; int mFBHeight;
// Objects for rendering to texture // Objects for rendering to texture
unsigned int mFBO; struct FrameBuffer
unsigned int mRBO; // for depth and stencil {
RenderTarget mRT; Image Texture;
unsigned char* Buffer;
unsigned int FBO;
unsigned int RBO; // for depth and stencil
};
std::map<int, FrameBuffer*> mFrameBuffers;
int mActiveFrameBuffer;
// TEXT // TEXT
glText mText; glText mText;

@ -38,6 +38,10 @@ namespace lunarium
mImageSize.Width = 1280; mImageSize.Width = 1280;
mImageSize.Height = 720; mImageSize.Height = 720;
// Create the render textures
mFrameBufferOne = Core::Graphics().CreateRenderTexture(mImageSize.Width, mImageSize.Height, 4);
mFrameBufferTwo = Core::Graphics().CreateRenderTexture(1024, 1024, 4);
angle = 0.0f; angle = 0.0f;
box_angle = 0.0f; box_angle = 0.0f;
@ -94,7 +98,7 @@ namespace lunarium
IGraphics& g = Core::Graphics(); IGraphics& g = Core::Graphics();
Color prev = g.GetClearColor(); Color prev = g.GetClearColor();
g.SetClearColor(Color(0.0f, 0.0f, 0.0f, 0.0f)); g.SetClearColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
OpRes result = Core::GetInstance().BeginRenderToTexture(); OpRes result = Core::GetInstance().BeginRenderToTexture(mFrameBufferTwo);
if (Failed(result)) if (Failed(result))
{ {
Logger::Log(mLogCat, LogLevel::WARNING, "Unable to render to texture: %s", result.Description.c_str()); Logger::Log(mLogCat, LogLevel::WARNING, "Unable to render to texture: %s", result.Description.c_str());
@ -119,7 +123,7 @@ namespace lunarium
mImageSize.Height = Math::ClampI(mImageSize.Height, 180, 720); mImageSize.Height = Math::ClampI(mImageSize.Height, 180, 720);
// Render to texture testing // Render to texture testing
OpRes result = Core::GetInstance().BeginRenderToTexture(); OpRes result = Core::GetInstance().BeginRenderToTexture(mFrameBufferOne);
if (Failed(result)) if (Failed(result))
{ {
Logger::Log(mLogCat, LogLevel::WARNING, "Unable to render to texture: %s", result.Description.c_str()); Logger::Log(mLogCat, LogLevel::WARNING, "Unable to render to texture: %s", result.Description.c_str());
@ -144,10 +148,10 @@ namespace lunarium
g->DrawImage(*mpRenderedImage, Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mpRenderedImage->GetWidth(), (float)mpRenderedImage->GetHeight()), g->DrawImage(*mpRenderedImage, Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mpRenderedImage->GetWidth(), (float)mpRenderedImage->GetHeight()),
Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mImageSize.Width, (float)mImageSize.Height), Color(1.0f, 1.0f, 1.0f, 1.0f), angle); Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mImageSize.Width, (float)mImageSize.Height), Color(1.0f, 1.0f, 1.0f, 1.0f), angle);
// g->DrawBox(Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mImageSize.Width, (float)mImageSize.Height), Color(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, angle); g->DrawBox(Rectangle::MakeFromTopLeft(0.0f, 0.0f, (float)mImageSize.Width, (float)mImageSize.Height), Color(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, angle);
// g->DrawBox(Rectangle(400, 400, 128.0f, 128.0f), Color(0.0f, 1.0f, 0.0f, 1.0f), 2.0f, box_angle); g->DrawBox(Rectangle(400, 400, 128.0f, 128.0f), Color(0.0f, 1.0f, 0.0f, 1.0f), 2.0f, box_angle);
// g->DrawString((*mGrid[{-2, 0,}])->msg.c_str(), Rectangle::MakeFromTopLeft(200.0f, 500.0f, 500.0f, 200.0f), Color(0.5f, 0.0f, 0.75f, 1.0f)); g->DrawString((*mGrid[{-2, 0,}])->msg.c_str(), Rectangle::MakeFromTopLeft(200.0f, 500.0f, 500.0f, 200.0f), Color(0.5f, 0.0f, 0.75f, 1.0f));
} }
} }

@ -31,6 +31,8 @@ namespace lunarium
int mTextBoxWidth; int mTextBoxWidth;
Sizei mImageSize; Sizei mImageSize;
Image* mpRenderedImage; Image* mpRenderedImage;
int mFrameBufferOne;
int mFrameBufferTwo;
float angle; float angle;
float box_angle; float box_angle;

@ -30,9 +30,9 @@ namespace lunarium
mLogCat = Logger::RegisterCategory("TESTER"); mLogCat = Logger::RegisterCategory("TESTER");
#if BUILD_NO_EDITOR #if BUILD_NO_EDITOR
Logger::Log(mLogCat, LogLevel::INFO, "BUILDING NO EDITOR!"); Logger::Log(mLogCat, LogLevel::INFO, "NO EDITOR!");
#else #else
Logger::Log(mLogCat, LogLevel::INFO, "BUILDING WITH THE EDITOR!"); Logger::Log(mLogCat, LogLevel::INFO, "EDITOR DETECTED!");
#endif #endif
mpScene = new SimpleRenderScene(mLogCat); mpScene = new SimpleRenderScene(mLogCat);

Loading…
Cancel
Save