Multi-Sample-Anti-Alias.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m4s
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m4s
This commit is contained in:
@@ -82,8 +82,12 @@ namespace JGL {
|
||||
/// Draws a filled rectangle with rounded corners on the screen.
|
||||
void FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
|
||||
|
||||
void DrawRenderTargetAsSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
/// Draws a render target to the screen.
|
||||
void DrawRenderTarget(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const RenderTarget& render_target, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0 , 0),
|
||||
const Vector2& scale = Vector2(1, 1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
|
||||
/// @param texture
|
||||
/// @param position
|
||||
|
@@ -17,7 +17,7 @@ namespace JGL {
|
||||
return (u8)a & (u8)b;
|
||||
}
|
||||
|
||||
static std::string to_string(JGL::Direction direction) {
|
||||
static std::string to_string(const JGL::Direction& direction) {
|
||||
switch (direction) {
|
||||
case JGL::Direction::None:
|
||||
return "None";
|
||||
@@ -33,4 +33,40 @@ namespace JGL {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum class MSAA_SAMPLE_RATE : u8 {
|
||||
MSAA_NONE = 0,
|
||||
MSAA_2X = 1,
|
||||
MSAA_4X = 2,
|
||||
MSAA_8X = 3
|
||||
};
|
||||
|
||||
static std::string to_string(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return "No MSAA";
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return "MSAA 2x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return "MSAA 4x";
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return "MSAA 8x";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
static int to_int(const JGL::MSAA_SAMPLE_RATE& sample_rate) {
|
||||
switch (sample_rate) {
|
||||
case MSAA_SAMPLE_RATE::MSAA_NONE:
|
||||
return 0;
|
||||
case MSAA_SAMPLE_RATE::MSAA_2X:
|
||||
return 2;
|
||||
case MSAA_SAMPLE_RATE::MSAA_4X:
|
||||
return 4;
|
||||
case MSAA_SAMPLE_RATE::MSAA_8X:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,12 +3,14 @@
|
||||
#include <JGL/types/Texture.h>
|
||||
#include <Color4.hpp>
|
||||
#include <Colors.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
|
||||
namespace JGL {
|
||||
class RenderTarget;
|
||||
}
|
||||
|
||||
//TODO copy constructor for this. Copying this as it is and then that copy going out of scope will crash the program as it sits.
|
||||
//If you do copy it you're doing it wrong. But still.
|
||||
|
||||
class JGL::RenderTarget {
|
||||
private:
|
||||
@@ -20,19 +22,30 @@ private:
|
||||
GLuint framebuffer_object = 0;
|
||||
GLuint depth_buffer = 0;
|
||||
Texture* texture = nullptr;
|
||||
MSAA_SAMPLE_RATE msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
GLuint msaa_framebuffer_object = 0;
|
||||
GLuint msaa_depth_buffer = 0;
|
||||
GLuint msaa_render_buffer = 0;
|
||||
void Erase();
|
||||
public:
|
||||
static GLuint GetActiveGLFramebufferHandle();
|
||||
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
|
||||
|
||||
/** Change the size of the renderable area of the Render Target.
|
||||
* If the new size is larger than the non-renderable area the texture will be resized to fit. */
|
||||
/** Change the size of the renderable area of the Render Target. **/
|
||||
/// @param new_size new size in px.
|
||||
/// @param clear whether or not the data currently in the RenderTarget is to be kept.
|
||||
/// @note Clearing the FBO on Resize is *much* faster than keeping the data because we don't have to read back.
|
||||
void Resize(const Vector2& new_size);
|
||||
void SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
/// Blits the MSAA FBO onto the regular FBO if MSAA is enabled.
|
||||
/// Does nothing is MSAA is not enabled or if the color attachment is a texture not created by the RenderTarget.
|
||||
void Blit() const;
|
||||
[[nodiscard]] bool TextureCreatedByRenderTarget() const;
|
||||
public:
|
||||
[[nodiscard]] Vector2 GetDimensions() const;
|
||||
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
|
||||
/// Returns whether or not MSAA is enabled, If it is and you're not using J2D || J3D Begin / End,
|
||||
/// You need to run "Blit()" after rendering to your FBO before you show it.
|
||||
/// @note Also, If the texture wasn't made by the RenderTarget you don't want this. It would destroy the texture.
|
||||
[[nodiscard]] bool MSAAEnabled() const;
|
||||
[[nodiscard]] Texture* GetJGLTexture() const;
|
||||
[[nodiscard]] GLuint GetGLTextureHandle() const;
|
||||
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
|
||||
@@ -44,6 +57,6 @@ public:
|
||||
/// Create a render target for a texture that already exists. For adding to an existing texture.
|
||||
explicit RenderTarget(Texture* texture, const Color4& clear_color = Colors::Black);
|
||||
/// Create a Render Target with a brand new texture. Want to render JGL elements onto a texture and display it as a sprite?
|
||||
explicit RenderTarget(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false);
|
||||
explicit RenderTarget(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
~RenderTarget();
|
||||
};
|
@@ -37,7 +37,7 @@ namespace JGL {
|
||||
void load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
|
||||
public:
|
||||
/// Load a texture from a file,
|
||||
Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE, const TextureFlag& flags = TextureFlag::INVERT_Y);
|
||||
explicit Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE, const TextureFlag& flags = TextureFlag::INVERT_Y);
|
||||
Texture(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
|
||||
/* Initialize a texture filled with trash data
|
||||
this is primarily for the RenderTarget */
|
||||
|
16
main.cpp
16
main.cpp
@@ -118,14 +118,14 @@ public:
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR, JGL::TextureWrappingMode::CLAMP_TO_EDGE);
|
||||
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0});
|
||||
image2 = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::NEAREST);
|
||||
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
|
||||
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_8X);
|
||||
image2 = new Texture("assets/sprites/Re3D.png",TextureFilteringMode::BILINEAR);
|
||||
image2_render_target = new RenderTarget(image2);
|
||||
|
||||
J2D::Begin(image2_render_target);
|
||||
J2D::FillRect(Colors::Red, {0,0}, {4,4});
|
||||
J2D::DrawString(Colors::Red, "TEST", 0, 16, 1, 16, Jupiteroid);
|
||||
J2D::DrawString(Colors::Red, "TEST", 0, 16, 1, 16, FreeSans);
|
||||
J2D::End();
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
|
||||
J2D::Begin(j2d_render_target, true);
|
||||
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
||||
J2D::DrawSprite(*image2, {300, 300}, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawSprite(*image2, {300, 300}, 0, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawMirrorSprite(*image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawPartialSprite(*image, {225, 300}, image->GetDimensions() * 0.25, image->GetDimensions() * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
|
||||
@@ -204,8 +204,8 @@ public:
|
||||
//Draw the Render Target that we just drew all that stuff onto.
|
||||
|
||||
J2D::Begin();
|
||||
J2D::DrawRenderTargetAsSprite(*j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawRenderTargetAsSprite(*image2_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawSprite(*j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawSprite(*image2_render_target, {300, 500}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::End();
|
||||
|
||||
}
|
||||
@@ -253,7 +253,7 @@ int main(int argc, char** argv) {
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->setResizable(true);
|
||||
window->setVsyncEnabled(true);
|
||||
window->setVsyncEnabled(false);
|
||||
|
||||
while (window->isAlive()) {
|
||||
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
|
||||
|
18
src/JGL.cpp
18
src/JGL.cpp
@@ -127,7 +127,7 @@ namespace JGL {
|
||||
|
||||
if (!inJ3D)
|
||||
inJ2D = true;
|
||||
else { Logger::Error("Attempt to Begin J2D inside of J3D context."); }
|
||||
else { Logger::Error("Beginning J2D context inside of J3D context?"); }
|
||||
|
||||
if (rt != nullptr && clear_buffers) {
|
||||
glClearColor(rt->GetClearColor().R(), rt->GetClearColor().G(), rt->GetClearColor().B(), rt->GetClearColor().A());
|
||||
@@ -170,6 +170,7 @@ namespace JGL {
|
||||
glColor4fv(oldColor);
|
||||
|
||||
if (render_target != nullptr) {
|
||||
render_target->Blit();
|
||||
render_target = nullptr;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
@@ -299,8 +300,7 @@ namespace JGL {
|
||||
J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + size.y - radius}, radius, subdivisions);
|
||||
}
|
||||
|
||||
void
|
||||
J2D::DrawRenderTargetAsSprite(const JGL::RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
|
||||
void J2D::DrawSprite(const JGL::RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
|
||||
const Vector2& scale, const Color4& color, Direction inversion) {
|
||||
|
||||
//Correct for the render-target being upside-down.
|
||||
@@ -319,9 +319,13 @@ namespace JGL {
|
||||
}
|
||||
|
||||
//Change the blending mode such that the alpha doesn't get multiplied again.
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), rad_rotation, origin, scale, color, d);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (rt.TextureCreatedByRenderTarget())
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), rad_rotation, origin, scale, color, d);
|
||||
|
||||
if (rt.TextureCreatedByRenderTarget())
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
void J2D::DrawSprite(const Texture& texture, const Vector2& pos, float rad_rotation, const Vector2& origin,
|
||||
const Vector2& scale, const Color4& color, Direction inversion) {
|
||||
@@ -769,7 +773,7 @@ namespace JGL {
|
||||
if (!inJ2D)
|
||||
inJ3D = true;
|
||||
else
|
||||
Logger::Error("Can't begin J3D context inside J2D context.");
|
||||
Logger::Error("Beginning J3D context inside of J2D context?");
|
||||
}
|
||||
|
||||
void J3D::End() {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <ReTexture/Texture.h>
|
||||
#include <jlog/Logger.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <stdexcept>
|
||||
|
||||
JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
|
||||
@@ -26,7 +26,7 @@ GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, render_target.GetGLFramebufferObjectHandle());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, render_target.MSAAEnabled() ? render_target.msaa_framebuffer_object : render_target.GetGLFramebufferObjectHandle());
|
||||
glViewport(0,0, render_target.GetDimensions().x, render_target.GetDimensions().y);
|
||||
}
|
||||
|
||||
@@ -36,12 +36,15 @@ Vector2 JGL::RenderTarget::GetDimensions() const {
|
||||
|
||||
void JGL::RenderTarget::Erase() {
|
||||
if (GetActiveGLFramebufferHandle() == framebuffer_object)
|
||||
jlog::Warning("Deleting the framebuffer that's currently in use?");
|
||||
Logger::Warning("Deleting the framebuffer that's currently in use?");
|
||||
|
||||
if (using_depth)
|
||||
glDeleteRenderbuffers(1, &depth_buffer);
|
||||
|
||||
glDeleteFramebuffers(1, &framebuffer_object);
|
||||
|
||||
if (MSAAEnabled())
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
}
|
||||
|
||||
Color4 JGL::RenderTarget::GetClearColor() const {
|
||||
@@ -70,7 +73,7 @@ JGL::RenderTarget::RenderTarget(JGL::Texture* texture, const Color4& clear_color
|
||||
texture_created_by_us = false;
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth) {
|
||||
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint viewport[4] = {0, 0, 0, 0};
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
@@ -111,6 +114,9 @@ JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color,
|
||||
this->size = size;
|
||||
texture_created_by_us = true;
|
||||
this->texture->SetFlags(INVERT_Y);
|
||||
|
||||
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
SetMSAAEnabled(sample_rate);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::RenderTarget::GetData() const {
|
||||
@@ -125,6 +131,9 @@ std::vector<GLfloat> JGL::RenderTarget::GetData() const {
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Resize(const Vector2& new_size) {
|
||||
if (!texture_created_by_us)
|
||||
Logger::Fatal("Resizing a texture that already existed?");
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLfloat old_clear_color[4];
|
||||
GLint old_viewport[4] = {0, 0, 0, 0};
|
||||
@@ -182,3 +191,94 @@ JGL::RenderTarget::~RenderTarget() {
|
||||
if (texture_created_by_us)
|
||||
delete texture;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::TextureCreatedByRenderTarget() const {
|
||||
return texture_created_by_us;
|
||||
}
|
||||
|
||||
JGL::MSAA_SAMPLE_RATE JGL::RenderTarget::GetMSAASampleRate() const {
|
||||
return msaa_sample_rate;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::MSAAEnabled() const {
|
||||
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
// If we'd be setting the same sample_rate we already have.
|
||||
if (sample_rate == msaa_sample_rate)
|
||||
return;
|
||||
|
||||
// If we'd be rendering onto a texture and not a plain render target we don't want this.
|
||||
if (!TextureCreatedByRenderTarget())
|
||||
return;
|
||||
|
||||
// Remove it if they request no msaa or if what they requested is different than what they already have.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
|
||||
if(using_depth)
|
||||
glDeleteRenderbuffers(1, &msaa_depth_buffer);
|
||||
glDeleteRenderbuffers(1, &msaa_render_buffer);
|
||||
glDeleteFramebuffers(1, &msaa_framebuffer_object);
|
||||
|
||||
msaa_framebuffer_object = 0;
|
||||
msaa_depth_buffer = 0;
|
||||
msaa_render_buffer = 0;
|
||||
msaa_sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
|
||||
// Only return here if they specifically requested no MSAA. else continue to change mode.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
glGenFramebuffers(1, &msaa_framebuffer_object);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, msaa_framebuffer_object);
|
||||
|
||||
GLint current_renderbuffer = 0;
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, ¤t_renderbuffer);
|
||||
glGenRenderbuffers(1, &msaa_render_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_render_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_RGBA, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaa_render_buffer);
|
||||
|
||||
if (using_depth) {
|
||||
glGenRenderbuffers(1, &msaa_depth_buffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, JGL::to_int(sample_rate), GL_DEPTH_COMPONENT, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaa_depth_buffer);
|
||||
}
|
||||
|
||||
bool failure = false;
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
failure = true,
|
||||
Logger::Fatal("A new MSAA " + std::to_string(to_int(sample_rate)) + "x framebuffer couldn't be allocated.");
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, current_renderbuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
msaa_sample_rate = sample_rate;
|
||||
|
||||
if (failure)
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit() const {
|
||||
if (!MSAAEnabled() || !TextureCreatedByRenderTarget())
|
||||
return;
|
||||
|
||||
// Save the GL state.
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint current_draw_fbo = 0;
|
||||
GLint current_read_fbo = 0;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, ¤t_read_fbo);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_draw_fbo);
|
||||
|
||||
// Draw the contents of one into the other.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, msaa_framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, size.x, size.y, 0, 0, size.x, size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Put the GL state back.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_draw_fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
Reference in New Issue
Block a user