Compare commits

...

18 Commits

Author SHA1 Message Date
cc504c65ec copy construct RenderTarget.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m36s
2024-10-13 16:37:51 -04:00
bb4a80e36d Copy texture without readbacks.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m5s
2024-10-13 09:45:24 -04:00
5d981e64fc Merge remote-tracking branch 'origin/master'
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m6s
2024-10-11 13:29:59 -04:00
5b19d26b79 Implement rounding on DrawString input coordinates (Crisp text rendering even when users pass in non-integer values, however, still need to account for non-integer scaling). 2024-10-11 13:29:53 -04:00
8e834f9c5a glad update
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m51s
Only use the GL_ARB extension because it'll be more widely supported than EXT.
2024-10-10 22:09:21 -04:00
dbdb4f7ec1 I'll try this I guess idk.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m40s
2024-10-10 19:34:34 -04:00
39c7c7ac0d Fix using RenderTargets on a texture that has mipmaps.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m40s
Also better mipmap generation.
2024-10-10 13:12:18 -04:00
e155d272bb Update to latest everything
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m37s
2024-10-10 12:28:45 -04:00
2ee5015d61 Update RenderTarget.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
Whoopsies
2024-10-09 23:08:17 -04:00
4484fd482f Update JGL.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m47s
Fix memory error
2024-10-09 22:54:41 -04:00
97573e28a9 Multi-Sample-Anti-Alias.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m4s
2024-10-09 22:22:24 -04:00
0417c37460 Render Targets Update.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m54s
Allow rendering onto a texture that's been loaded already.

Make DrawSprite commands work regardless of if the texture was loaded in inverted or not.

You however cannot draw onto a texture which is upside-down in vram because your draw commands would be positioned incorrectly.
2024-10-08 18:25:31 -04:00
0a757407d8 Update CMakeLists.txt
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m5s
Don't link libJGL.so to event.
2024-10-08 12:13:42 -04:00
308b0dc854 Improve memory safety.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m44s
Also fixed a case where we didn't reset the GL state correctly 🤷
2024-10-06 23:03:50 -04:00
5f367efc28 Ability to resize render targets.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m48s
2024-10-06 00:01:06 -04:00
b4c29315f4 Improve memory safety of VRamList
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m5s
Copying it around is slow and you wouldn't do it. But incase some idiot actually does so it doesn't break everything.
2024-10-05 20:14:46 -04:00
Redacted
a568faa701 Update .gitea/workflows/buildtest.yml
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m35s
2024-10-04 23:30:47 -04:00
9d89abb2b8 UpdateData in VRamList & QOL changes.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m45s
2024-10-04 22:50:57 -04:00
13 changed files with 811 additions and 292 deletions

View File

@@ -17,6 +17,6 @@ jobs:
- run: echo "The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "The workflow is now ready to run your tests on the runner."
- run: echo "Install toolchain and run ReCI build test"
- run: apt-get update && apt-get install -y lua5.3 git && git clone $RECI_GIT $RECI
- run: apt-get update && apt-get install -y lua5.3 git libxrandr-dev && git clone $RECI_GIT $RECI
- run: lua $RECI/reci.lua -f $RECI/scripts/buildtools.reci -f reci/scripts/builddeps.reci -f $RECI/scripts/buildtest.reci
- run: echo "This job's status is ${{ job.status }}."

View File

@@ -22,32 +22,27 @@ CPMAddPackage(
CPMAddPackage(
NAME J3ML
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.1.zip
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.2.zip
)
CPMAddPackage(
NAME ReWindow
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-15.zip
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-21.zip
)
CPMAddPackage(
NAME GLAD
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo.zip
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fboV2.zip
)
CPMAddPackage(
NAME jlog
URL https://git.redacted.cc/josh/jlog/Prerelease-12.zip
URL https://git.redacted.cc/josh/jlog/Prerelease-16.zip
)
CPMAddPackage(
NAME Event
URL https://git.redacted.cc/josh/Event/archive/Release-6.zip
)
CPMAddPackage(
NAME ReTexture
URL https://git.redacted.cc/Redacted/ReTexture/archive/Release-1.2.zip
NAME ReImage
URL https://git.redacted.cc/Redacted/ReImage/archive/Release-2.0.zip
)
if (WIN32)
@@ -83,15 +78,17 @@ endif()
set_target_properties(JGL PROPERTIES LINKER_LANGUAGE CXX)
#Don't expose these ones.
include_directories(${ReWindow_SOURCE_DIR}/include)
include_directories(
${ReWindow_SOURCE_DIR}/include
${Event_SOURCE_DIR}/include
)
target_include_directories(JGL PUBLIC
${PROJECT_SOURCE_DIR}/include
${OPENGL_INCLUDE_DIRS}
${ReTexture_SOURCE_DIR}/include
${ReImage_SOURCE_DIR}/include
${mcolor_SOURCE_DIR}/include
${J3ML_SOURCE_DIR}/include
${Event_SOURCE_DIR}/include
${glad_SOURCE_DIR}/include
${jlog_SOURCE_DIR}/include
)
@@ -102,13 +99,13 @@ add_executable(JGL_Demo main.cpp)
if (UNIX AND NOT APPLE)
target_include_directories(JGL PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(JGL PRIVATE ${FREETYPE_LIBRARIES})
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog ReImage)
endif()
if (WIN32)
target_include_directories(JGL PRIVATE ${freetype_SOURCE_DIR}/include)
target_link_libraries(JGL PRIVATE freetype)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog ReImage)
endif()
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary)
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary Event)

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -1,11 +1,13 @@
#pragma once
#include <glad/glad.h>
#include <JGL/types/Texture.h>
#include <Color4.hpp>
#include <Colors.hpp>
#include <JGL/types/Enums.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
namespace JGL {
class RenderTarget;
class Texture; // Forward declare.
}
class JGL::RenderTarget {
@@ -14,15 +16,39 @@ private:
/// "Size" in this sense is the "Renderable Area" because OpenGL textures behave strangely if they're not square.
Vector2 size{0, 0};
bool using_depth = false;
bool texture_created_by_us = false;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
Texture* texture = nullptr;
const 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. **/
/// @param new_size new size in px.
void Resize(const Vector2& new_size);
void SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
/// If you're using raw OpenGL commands to draw to this outside of J2D or J3D don't forget to do this.
/// Blits the MSAA FBO onto the regular FBO if MSAA is enabled and or If you're rendering to a texture which uses mipmaps,
/// It regenerates them so what you drew doesn't disappear at a distance. Otherwise it does nothing.
void Blit() const;
/// Blit a render target onto another. Will break if they're not the same size.
static void Blit(const RenderTarget& source, RenderTarget* destination);
[[nodiscard]] bool TextureCreatedByRenderTarget() const;
public:
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] Texture* GetJGLTexture() 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]] const Texture* GetJGLTexture() const;
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
@@ -30,10 +56,11 @@ public:
/// Get the data back from the FBO. This is *not* async friendly.
[[nodiscard]] std::vector<GLfloat> GetData() const;
public:
/// Create a render target for a texture that already exists. For decals.
explicit RenderTarget(const Texture& texture, const Color4& clear_color = Colors::Black, bool use_depth = false);
/// Copy constructor. Will always set "texture_created_by_us" to true and use our own texture to avoid memleaks.
RenderTarget(const RenderTarget& rhs);
/// Create a render target for a texture that already exists. For adding to an existing texture.
explicit RenderTarget(const 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);
void Erase();
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();
};

View File

@@ -1,12 +1,12 @@
#pragma once
#include <ReTexture/Texture.h>
#include <ReImage/Image.h>
#include <J3ML/LinearAlgebra.hpp>
#include <Color3.hpp>
#include <Color4.hpp>
#include <glad/glad.h>
namespace JGL {
using namespace ReTexture;
using namespace ReImage;
enum class TextureFilteringMode : u8 {
NEAREST = 0, //Fastest for 2D, Sometimes causes graphical issues.
BILINEAR = 1, //Fast and pretty, The best for 2D.
@@ -25,22 +25,25 @@ namespace JGL {
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
class Texture {
private:
void Erase();
protected:
GLuint texture_handle = 0;
Vector2 texture_size = {0, 0};
ReTexture::TextureFlag texture_flags;
ReTexture::TextureFormat texture_format;
ReImage::TextureFlag texture_flags;
ReImage::TextureFormat texture_format;
TextureFilteringMode texture_filtering_mode;
TextureWrappingMode texture_wrapping_mode;
void load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
void load(Image* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
public:
///Load a texture from a file,
explicit Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE);
Texture(const std::string& file, const TextureFlag& flags, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE);
/// Load a texture from a file,
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(Image* 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 */
explicit Texture(const Vector2& size);
Texture() = default;
Texture(const Texture& rhs);
~Texture();
public:
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] Vector2 GetDimensions() const;
@@ -49,9 +52,6 @@ namespace JGL {
[[nodiscard]] TextureFlag GetFlags() const;
[[nodiscard]] TextureFormat GetFormat() const;
[[nodiscard]] std::vector<Color4> GetPixelData() const;
void SetTextureHandle(GLuint handle);
void Erase();
};
}

View File

@@ -1,72 +1,68 @@
#pragma once
#include <vector>
#include <glad/glad.h>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector2i.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/LinearAlgebra/Vector4.hpp>
#include <JGL/logger/logger.h>
#include <type_traits>
#include <vector>
#include <cstring>
#include <string>
namespace JGL {
class VRamList;
}
/// A wrapper for VBO, Storing texture coordinates or vertices or indices in vram.
/// A wrapped for "Vertex Buffer Object" In OpenGL, Store things in VRam.
class JGL::VRamList {
private:
GLuint list_handle = 0;
long size = 0;
long num_elements = 0;
bool element_array_buffer = false;
void load(const GLfloat* data, const long& size);
void load(const GLuint* data, const long& size);
void SetData(void* data, const long& length);
void UpdateData(void* data, const long& offset, const long& length);
void Erase();
public:
VRamList() = default;
VRamList(const GLuint* data, const long& size);
VRamList(const GLfloat* data, const long& size);
VRamList(Vector2* data, const long& size);
VRamList(Vector3* data, const long& size);
VRamList(Vector4* data, const long& size);
VRamList(const GLuint* data, const long& length);
VRamList(const GLfloat* data, const long& length);
VRamList(Vector2* data, const long& length);
VRamList(Vector3* data, const long& length);
VRamList(Vector4* data, const long& length);
~VRamList();
/** Copying around the VBO data to a new VBO like this is slow.
* Pass to function by const reference or pointer always. */
VRamList(const VRamList& rhs);
public:
[[nodiscard]] GLuint GetHandle() const;
/// Returns the number of GLfloat or GLuint in the list.
[[nodiscard]] long GetSize() const;
/// Returns the number of elements in the list.
[[nodiscard]] long GetLength() const;
/// Returns the size of the data in bytes.
[[nodiscard]] long GetDataSize() const;
[[nodiscard]] bool IsIntegerArray() const;
[[nodiscard]] size_t GetSize() const;
/** Get VBO data back from the GPU. This is *bad* because the CPU is going to wait
* for the transfer to finish. Has limited use other than testing. */
[[nodiscard]] std::vector<GLfloat> GetDataF() const;
[[nodiscard]] std::vector<GLuint> GetDataUI() const;
[[nodiscard]] bool IsFloatArray() const;
void Erase();
/** Replace the data of an existing VBO in it's entirety. Must be same type.
* "length" refers to the number of elements in data. Not the number of bytes. */
void SetData(const GLfloat* data, const long& length);
void SetData(const Vector2* data, const long& length);
void SetData(const Vector3* data, const long& length);
void SetData(const Vector4* data, const long& length);
/// Update the data of an existing VBO. Data would be the same type as the list already is.
/// "size" refers to the number of elements in data. Not the number of bytes.
void SetData(void* data, const long& size);
void SetData(const GLuint* data, const long& length);
void SetData(const Vector2i* data, const long& length);
/* Get VBO data back from the GPU. This is *very* slow because the CPU is going to wait
for the transfer to finish. I don't know why you'd want to do this outside of testing reasons.*/
template <typename T>
[[nodiscard]] std::vector<T> GetData() const {
GLenum buffer_type;
GLint current_buffer = 0;
if constexpr (std::is_same<T, GLfloat>::value)
buffer_type = GL_ARRAY_BUFFER,
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_buffer);
else if constexpr (std::is_same<T, GLuint>::value)
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_buffer);
else
jlog::Fatal("Typename T must be either GLfloat or GLuint.");
/** Update only a portion of the data in a VBO. Must be same type.
* "length" refers to the number of elements in data. Not the number of bytes.
* "offset" refers the number of Typename T into the buffer the data you want to change is.
* For ex, offset 0 and length of 1 overwrites the first value. Offset 1 the second etc */
void UpdateData(const GLfloat* data, const long& offset, const long& length);
void UpdateData(const Vector2* data, const long& offset, const long& length);
void UpdateData(const Vector3* data, const long& offset, const long& length);
void UpdateData(const Vector4* data, const long& offset, const long& length);
if ((element_array_buffer && buffer_type == GL_ARRAY_BUFFER) || (!element_array_buffer && buffer_type == GL_ELEMENT_ARRAY_BUFFER))
jlog::Fatal("Returning the contents of a VRamList using the incorrect Typename T?");
glBindBuffer(buffer_type, list_handle);
std::vector<T> data(size);
memcpy(data.data(), glMapBuffer(buffer_type, GL_READ_ONLY), size * sizeof(T));
glUnmapBuffer(buffer_type);
glBindBuffer(buffer_type, current_buffer);
return data;
}
void UpdateData(const GLuint* data, const long& offset, const long& length);
void UpdateData(const Vector2i* data, const long& offset, const long& length);
};

View File

@@ -1,4 +1,3 @@
#include <JGL/JGL.h>
#include <rewindow/types/window.h>
#include <Colors.hpp>
@@ -94,7 +93,9 @@ Gizmo c({350, 300});
Gizmo d({450, 250});
Texture* image;
Texture* image2;
RenderTarget* j2d_render_target;
RenderTarget* image2_render_target;
class JGLDemoWindow : public ReWindow::RWindow
{
@@ -102,10 +103,9 @@ public:
void initGL() {
camera = new Camera;
gladLoadGL();
if (!JGL::MeetsRequirements()) {
Logger::Fatal("The graphics driver does not meet the minimum requirements to run this program.");
exit(-1);
}
if (!JGL::MeetsRequirements())
Logger::Warning("The graphics driver does not meet the minimum requirements to run this program.");
JGL::InitTextEngine();
JGL::Update(getSize());
J3D::Init(getSize(), 90, 100);
@@ -117,7 +117,14 @@ public:
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
j2d_render_target = new RenderTarget({500, 500}, {255,0,0,0});
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_8X);
image2 = image;
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, FreeSans);
J2D::End();
}
Vector3 textAngle = {0,0,0};
@@ -155,16 +162,15 @@ public:
J3D::End();
J2D::Begin();
J2D::Begin(j2d_render_target, true);
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::DrawSprite(*image, {300, 300}, 0, {0,0}, {1, 1}, Colors::White, Direction::Vertical | Direction::Horizontal);
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});
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});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
@@ -194,11 +200,13 @@ public:
J2D::End();
//Draw the Render Target that we just drew all that stuff onto.
/*
auto image3_render_target = image2_render_target;
J2D::Begin();
J2D::DrawRenderTargetAsSprite(*j2d_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(*image3_render_target, {300, 500}, 0, {0.5, 0.5}, {1,1}, Colors::White);
J2D::End();
*/
}
void OnRefresh(float elapsed) override {

View File

@@ -37,8 +37,6 @@ namespace JGL {
bool MeetsRequirements() {
if (!GLAD_GL_VERSION_2_1)
return false;
if (!GLAD_GL_EXT_framebuffer_object)
return false;
if (!GLAD_GL_ARB_framebuffer_object)
return false;
return true;
@@ -53,6 +51,9 @@ namespace JGL {
glGetIntegerv(GL_VIEWPORT, viewport);
current_fbo = JGL::RenderTarget::GetActiveGLFramebufferHandle();
JGL::RenderTarget::SetActiveGLRenderTarget(*rt);
if (!(rt->GetJGLTexture()->GetFlags() & INVERT_Y))
Logger::Warning("You're rendering onto a texture that is upside-down. Your draw commands won't work how you'd expect.");
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
@@ -124,7 +125,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());
@@ -167,6 +168,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]);
@@ -296,24 +298,32 @@ 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.
Direction d{};
if (inversion == Direction::None)
if (inversion == Direction::None && !(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Vertical;
else if (inversion == Direction::Horizontal)
d = Direction::Horizontal | Direction::Vertical;
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical)
else if (inversion == Direction::Horizontal) {
d = Direction::Horizontal;
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Horizontal | Direction::Vertical;
}
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical) {
d = Direction::Horizontal;
if (!(rt.GetJGLTexture()->GetFlags() & INVERT_Y))
d = Direction::Horizontal | Direction::Vertical;
}
//Change the blending mode such that the alpha doesn't get multiplied again.
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
//J2D::DrawSprite(*rt.GetJGLTexture(), position, rad_rotation, origin, scale, color, d);
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);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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) {
@@ -323,7 +333,11 @@ namespace JGL {
const Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
std::array<Vector2, 4> textureCoordinates{};
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
// TODO: Kind of a mess, refactor to be more sensible later.
// Factors in scaling and origin correctly.
@@ -352,13 +366,12 @@ namespace JGL {
pos2.y + offset.y * scale.y
};
if (inversion == Direction::Vertical)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
else if (inversion == Direction::Horizontal)
textureCoordinates = {Vector2(1, 0), Vector2(1, 1), Vector2(0, 1), Vector2(0, 0)};
else if ((inversion& Direction::Horizontal) && (inversion& Direction::Vertical))
textureCoordinates = {Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1)};
std::swap(textureCoordinates[0], textureCoordinates[1]),
std::swap(textureCoordinates[3], textureCoordinates[2]);
if (inversion == Direction::Horizontal)
std::swap(textureCoordinates[0], textureCoordinates[3]),
std::swap(textureCoordinates[1], textureCoordinates[2]);
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
@@ -387,18 +400,32 @@ namespace JGL {
Logger::Error("Drawing J2D element before J2D begin.");
const Vector2 textureSize = texture.GetDimensions();
std::array<GLfloat, 8> textureCoordinates{};
// Calculate texture coordinates (relative to the whole texture)
std::array<GLfloat, 8> textureCoordinates = {
sub_texture_position.x / textureSize.x,
sub_texture_position.y / textureSize.y,
sub_texture_position.x / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
sub_texture_position.y / textureSize.y
};
if (!(texture.GetFlags() & INVERT_Y))
textureCoordinates = {
sub_texture_position.x / textureSize.x,
sub_texture_position.y / textureSize.y,
sub_texture_position.x / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(sub_texture_position.y + sub_texture_size.y) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
sub_texture_position.y / textureSize.y
};
else {
textureCoordinates = {
sub_texture_position.x / textureSize.x,
(textureSize.y - sub_texture_position.y) / textureSize.y,
sub_texture_position.x / textureSize.x,
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(textureSize.y - (sub_texture_position.y + sub_texture_size.y)) / textureSize.y,
(sub_texture_position.x + sub_texture_size.x) / textureSize.x,
(textureSize.y - sub_texture_position.y) / textureSize.y
};
}
if (inversion& Direction::Vertical)
std::swap(textureCoordinates[1], textureCoordinates[3]),
@@ -460,21 +487,35 @@ namespace JGL {
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
if (mirror_axis == Direction::Horizontal) {
size.x *= 2;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(2, 0), Vector2(2, 1)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(2, 1), Vector2(2, 0)};
}
if (mirror_axis == Direction::Horizontal)
size.x *= 2,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT),
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(2, 1), Vector2(2, 0)};
else if (mirror_axis == Direction::Vertical) {
size.y *= 2;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(1, 0), Vector2(1, 2)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(1, 2), Vector2(1, 0)};
}
else if (mirror_axis == Direction::Vertical)
size.y *= 2,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT),
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(1, 2), Vector2(1, 0)};
else if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical))
size *= 2,
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
else if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
size *= 2;
if (texture.GetFlags() & INVERT_Y)
textureCoordinates = {Vector2(0, 2), Vector2(0, 0), Vector2(2, 0), Vector2(2, 2)};
else
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
}
const Vector2 offset = origin * size;
Vector2 pos2 = position;
@@ -529,7 +570,7 @@ namespace JGL {
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step) {
x = radius * std::sin(angle) + center.x;
y = radius * std::cos(angle) + center.y;
if (i <= subdivisions)
if (i < subdivisions)
vertices[i] = {x, y};
else
vertices.emplace_back(x, y);
@@ -558,7 +599,7 @@ namespace JGL {
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step) {
x = radius * std::sin(angle) + center.x;
y = radius * std::cos(angle) + center.y;
if (i <= subdivisions)
if (i < subdivisions)
vertices[i] = {x, y};
else
vertices.emplace_back(x, y);
@@ -730,7 +771,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() {
@@ -759,7 +800,7 @@ namespace JGL {
void J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
if (!inJ3D)
Logger::Error("Attempt to Render J3D element before J3D begin.");
Logger::Error("Drawing J3D element before J3D begin.");
Vector3 vertices[] = {A, B};

View File

@@ -21,7 +21,7 @@ namespace JGL {
CachedFont* CacheFont(const Font& font, u32 size) {
CachedFont* cachedFont;
FT_Set_Pixel_Sizes(font.face, 0, size);
jlog::Debug("Caching font data...");
Logger::Debug("Caching font data...");
GLuint texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
@@ -95,6 +95,15 @@ namespace JGL {
// Offset by height to render at "correct" location.
y += size;
bool round_text_coords_for_crisp_rendering = true;
// TODO: This currently does not account for non-integer scale factors.
if (round_text_coords_for_crisp_rendering)
{
x = J3ML::Math::Floor(x);
y = J3ML::Math::Floor(y);
}
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
@@ -153,6 +162,19 @@ namespace JGL {
float y = pos.y;
float z = pos.z;
// TODO: this is broken because it causes the text to be shifted downwards.
/*
bool round_text_coords_for_crisp_rendering = true;
// TODO: This currently does not account for non-integer scale factors.
if (round_text_coords_for_crisp_rendering)
{
x = J3ML::Math::Floor(x);
y = J3ML::Math::Floor(y);
z = J3ML::Math::Floor(z);
}
*/
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
jlog::Fatal("Drawing a string with an uninitialized font?");

View File

@@ -1,8 +1,9 @@
#include <JGL/types/RenderTarget.h>
#include <jlog/Logger.hpp>
#include <JGL/types/Texture.h>
#include <JGL/logger/logger.h>
#include <stdexcept>
JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
const JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
return texture;
}
@@ -25,9 +26,8 @@ GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
}
void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_target) {
RenderTarget rt = render_target;
glBindFramebuffer(GL_FRAMEBUFFER, rt.GetGLFramebufferObjectHandle());
glViewport(0,0, rt.GetDimensions().x, rt.GetDimensions().y);
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);
}
Vector2 JGL::RenderTarget::GetDimensions() const {
@@ -36,21 +36,44 @@ Vector2 JGL::RenderTarget::GetDimensions() const {
void JGL::RenderTarget::Erase() {
if (GetActiveGLFramebufferHandle() == framebuffer_object)
jlog::Warning("Deleting the framebuffer that's currently in use?");
texture->Erase();
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 {
return clear_color;
}
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth) {
/// Idk why you'd ever want to clear it out if you're rendering onto a texture you passed in :shrug:.
JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear_color) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glViewport(0,0, size.x, size.y);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("A new framebuffer could not be allocated.");
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
this->size = texture->GetDimensions();
this->texture = texture;
texture_created_by_us = false;
}
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);
@@ -89,6 +112,10 @@ JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color,
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
this->size = size;
texture_created_by_us = true;
if (sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE)
SetMSAAEnabled(sample_rate);
}
std::vector<GLfloat> JGL::RenderTarget::GetData() const {
@@ -101,3 +128,217 @@ std::vector<GLfloat> JGL::RenderTarget::GetData() const {
return data;
}
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};
glGetIntegerv(GL_VIEWPORT, old_viewport);
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
/* If what was previously not part of the renderable area is big enough to
* just set the new size without reading data back */
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
size = new_size;
// Clear.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
glClear(GL_COLOR_BUFFER_BIT);
if (using_depth)
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
return;
}
//If we have to remake the texture.
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
// Erase it.
delete texture;
unsigned int biggest;
if (new_size.x >= new_size.y)
biggest = new_size.x;
else
biggest = new_size.y;
auto cc = GetClearColor();
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
glViewport(0,0, size.x, size.y);
texture = new Texture(Vector2((float) biggest, (float) biggest));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
size = new_size;
//Disable & Re-enable MSAA so the msaa buffer is remade with the correct dimensions.
if (MSAAEnabled()) {
MSAA_SAMPLE_RATE current_sample_rate = msaa_sample_rate;
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
SetMSAAEnabled(current_sample_rate);
}
}
JGL::RenderTarget::~RenderTarget() {
Erase();
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, &current_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()) {
// Save the GL state.
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &current_read_fbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_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);
}
// Fixes using render targets on a texture that has mipmaps.
if (GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_NEAREST
|| GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_BILINEAR ||
GetJGLTexture()->GetFilteringMode() == TextureFilteringMode::MIPMAP_TRILINEAR) {
GLint current_texture = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
glBindTexture(GL_TEXTURE_2D, GetJGLTexture()->GetGLTextureHandle());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, current_texture);
}
}
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination) {
if (source.size != destination->size)
Logger::Warning("Blitting a render target but they're not the same size?");
// Save the GL state.
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint current_draw_fbo = 0;
GLint current_read_fbo = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &current_read_fbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &current_draw_fbo);
// Draw the contents of one into the other.
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer_object);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
glBlitFramebuffer(0, 0, source.size.x, source.size.y, 0, 0, source.size.x, source.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);
}
JGL::RenderTarget::RenderTarget(const JGL::RenderTarget& rhs) {
auto* this_render_target = new RenderTarget(rhs.size, rhs.clear_color, rhs.using_depth, rhs.msaa_sample_rate);
RenderTarget::Blit(rhs, this_render_target);
this->clear_color = this_render_target->clear_color;
this->size = this_render_target->size;
this->using_depth = this_render_target->using_depth;
this->texture_created_by_us = true;
this->texture = this_render_target->texture;
this->framebuffer_object = this_render_target->framebuffer_object;
this->depth_buffer = this_render_target->depth_buffer;
this->msaa_sample_rate = this_render_target->msaa_sample_rate;
this->msaa_framebuffer_object = this_render_target->msaa_framebuffer_object;
this->msaa_depth_buffer = this_render_target->msaa_depth_buffer;
this->msaa_render_buffer = this_render_target->msaa_render_buffer;
operator delete(this_render_target);
}

View File

@@ -1,14 +1,14 @@
#include <JGL/types/Texture.h>
#include <iostream>
#include <JGL/types/RenderTarget.h>
using namespace ReTexture;
using namespace ReImage;
namespace JGL
{
Texture::Texture(const std::string& file, const ReTexture::TextureFlag& flags, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode)
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode, const TextureFlag& flags)
{
auto *t = new ReTexture::SoftwareTexture(file, flags);
auto* t = new ReImage::Image(file, flags);
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
@@ -16,21 +16,6 @@ namespace JGL
texture_flags = flags;
delete t;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
auto* t = new SoftwareTexture(file);
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode, wrapping_mode);
texture_flags = TextureFlag::NONE;
delete t;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const Vector2& size) {
@@ -52,73 +37,59 @@ namespace JGL
texture_size = size;
texture_filtering_mode = TextureFilteringMode::NEAREST;
texture_wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE;
texture_flags = TextureFlag::NONE;
// Because in vram it'll be right side up.
texture_flags = TextureFlag::INVERT_Y;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
void Texture::load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format,
void Texture::load(Image* software_texture, const Vector2& size, const TextureFormat& format,
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
glGenTextures(1, &texture_handle);
glBindTexture(GL_TEXTURE_2D, texture_handle);
if (format == TextureFormat::RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int) size.x, (int) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
software_texture->pixelData.data());
software_texture->pixel_data.data());
else if (format == TextureFormat::RGB)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (int) size.x, (int) size.y, 0, GL_RGB, GL_UNSIGNED_BYTE,
software_texture->pixelData.data());
software_texture->pixel_data.data());
if (wrapping_mode == TextureWrappingMode::CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
else if (wrapping_mode == TextureWrappingMode::REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else if (wrapping_mode == TextureWrappingMode::MIRRORED_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
else if (wrapping_mode == TextureWrappingMode::CLAMP_TO_BORDER)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
if (filtering_mode == TextureFilteringMode::NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
else if (filtering_mode == TextureFilteringMode::BILINEAR)
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);
else if (filtering_mode == TextureFilteringMode::MIPMAP_NEAREST ||
filtering_mode == TextureFilteringMode::MIPMAP_BILINEAR ||
filtering_mode == TextureFilteringMode::MIPMAP_TRILINEAR) {
//3 mipmap levels.
auto *m1 = new SoftwareTexture(software_texture->downscale(2));
auto *m2 = new SoftwareTexture(software_texture->downscale(4));
auto *m3 = new SoftwareTexture(software_texture->downscale(8));
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3);
if (format == TextureFormat::RGBA) {
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, m1->getWidth(), m1->getHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, m1->pixelData.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, m2->getWidth(), m2->getHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, m2->pixelData.data());
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA, m3->getWidth(), m3->getHeight(), 0, GL_RGBA,
GL_UNSIGNED_BYTE, m3->pixelData.data());
} else if (format == TextureFormat::RGB) {
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, m1->getWidth(), m1->getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE,
m1->pixelData.data());
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, m2->getWidth(), m2->getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE,
m2->pixelData.data());
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGB, m3->getWidth(), m3->getHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE,
m3->pixelData.data());
}
if (filtering_mode == TextureFilteringMode::MIPMAP_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST),
@@ -131,65 +102,91 @@ namespace JGL
else if (filtering_mode == TextureFilteringMode::MIPMAP_TRILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
delete m1;
delete m2;
delete m3;
}
texture_size = size;
texture_format = format;
texture_filtering_mode = filtering_mode;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
std::vector<Color4> JGL::Texture::GetPixelData() const {
std::vector<Color4> result((size_t) (texture_size.x * texture_size.y));
glBindTexture(GL_TEXTURE_2D, texture_handle);
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
if (texture_format == TextureFormat::RGBA) {
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
return result;
}
std::vector<Color4> result((size_t) (texture_size.x * texture_size.y));
glBindTexture(GL_TEXTURE_2D, texture_handle);
//if RGB
std::vector<Color3> color3((size_t) (texture_size.x * texture_size.y));
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, color3.data());
for (const auto &c: color3)
result.emplace_back(c);
if (texture_format == TextureFormat::RGBA) {
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, result.data());
glBindTexture(GL_TEXTURE_2D, current_texture);
return result;
}
void Texture::Erase() {
if (texture_handle != 0)
glDeleteTextures(1, &texture_handle);
}
//if RGB
std::vector<Color3> color3((size_t) (texture_size.x * texture_size.y));
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, color3.data());
for (const auto &c: color3)
result.emplace_back(c);
GLuint Texture::GetGLTextureHandle() const {
return texture_handle;
}
glBindTexture(GL_TEXTURE_2D, current_texture);
return result;
}
Vector2 Texture::GetDimensions() const {
return texture_size;
}
void Texture::Erase() {
if (texture_handle != 0)
glDeleteTextures(1, &texture_handle);
texture_handle = 0;
}
TextureFlag Texture::GetFlags() const {
return texture_flags;
}
GLuint Texture::GetGLTextureHandle() const {
return texture_handle;
}
TextureFormat Texture::GetFormat() const {
return texture_format;
}
Vector2 Texture::GetDimensions() const {
return texture_size;
}
TextureFlag Texture::GetFlags() const {
return texture_flags;
}
TextureFormat Texture::GetFormat() const {
return texture_format;
}
TextureFilteringMode Texture::GetFilteringMode() const {
return texture_filtering_mode;
}
void Texture::SetTextureHandle(GLuint handle) {
texture_handle = handle;
}
TextureWrappingMode Texture::GetWrappingMode() const {
return texture_wrapping_mode;
}
Texture::Texture(Image* software_texture, const Vector2& size, const TextureFormat& format,
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
load(software_texture, size, format, filtering_mode, wrapping_mode);
}
Texture::~Texture() {
Erase();
}
Texture::Texture(const Texture& rhs) {
auto* this_texture = new Texture(rhs.GetDimensions());
auto this_render_target = RenderTarget(this);
auto rhs_render_target = RenderTarget(&rhs);
RenderTarget::Blit(rhs_render_target, &this_render_target);
this->texture_handle = this_texture->texture_handle;
this->texture_size = this_texture->texture_size;
this->texture_flags = this_texture->texture_flags;
this->texture_format = this_texture->texture_format;
this->texture_filtering_mode = this_texture->texture_filtering_mode;
this->texture_wrapping_mode = this_texture->texture_wrapping_mode;
// Free the memory of "this_texture" without calling the destructor.
// In 99% of cases you wouldn't want this. But in this scenario we do.
operator delete(this_texture);
}
}

View File

@@ -1,52 +1,34 @@
#include <JGL/types/VRamList.h>
#include <jlog/Logger.hpp>
#include <JGL/logger/logger.h>
#include <cstring>
void JGL::VRamList::load(const GLfloat* data, const long& s) {
void JGL::VRamList::load(const GLfloat* data, const long& size) {
GLint current_array_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
glBufferData(GL_ARRAY_BUFFER, s, data, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
element_array_buffer = false;
size = s / sizeof(GLfloat);
num_elements = size / sizeof(GLfloat);
}
void JGL::VRamList::load(const GLuint* data, const long& s) {
void JGL::VRamList::load(const GLuint* data, const long& size) {
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
glGenBuffers(1, &list_handle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, s, data, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
element_array_buffer = true;
size = s / sizeof(GLuint);
}
JGL::VRamList::VRamList(const GLfloat* data, const long& size) {
load(data, (long) sizeof(GLfloat) * size);
}
JGL::VRamList::VRamList(const GLuint* data, const long& size) {
load(data, (long) sizeof(GLuint) * size);
}
JGL::VRamList::VRamList(Vector2* data, const long& size) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector2) * size);
}
JGL::VRamList::VRamList(Vector3* data, const long& size) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector3) * size);
}
JGL::VRamList::VRamList(Vector4* data, const long& size) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector4) * size);
num_elements = size / sizeof(GLuint);
}
void JGL::VRamList::Erase() {
if (list_handle == 0)
jlog::Warning("Erasing an uninitialized array buffer?");
if (list_handle == 0) {
JGL::Logger::Warning("Erasing an uninitialized VRamList?");
return;
}
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
@@ -54,47 +36,44 @@ void JGL::VRamList::Erase() {
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_array_buffer);
if (element_array_buffer && current_element_array_buffer == list_handle)
jlog::Warning("Erasing an element array buffer while it's in use?");
JGL::Logger::Warning("Erasing an element array buffer while it's in use?");
else if (!element_array_buffer && current_array_buffer == list_handle)
jlog::Warning("Erasing an array buffer while it's in use?");
JGL::Logger::Warning("Erasing an array buffer while it's in use?");
glDeleteBuffers(1, &list_handle);
list_handle = 0;
}
GLuint JGL::VRamList::GetHandle() const {
return list_handle;
}
bool JGL::VRamList::IsIntegerArray() const {
return element_array_buffer;
}
bool JGL::VRamList::IsFloatArray() const {
return !element_array_buffer;
}
long JGL::VRamList::GetSize() const {
return size;
long JGL::VRamList::GetLength() const {
return num_elements;
}
long JGL::VRamList::GetDataSize() const {
size_t JGL::VRamList::GetSize() const {
if (element_array_buffer)
return (long) sizeof(GLuint) * size;
return (long) sizeof(GLfloat) * size;
return sizeof(GLuint) * num_elements;
return sizeof(GLfloat) * num_elements;
}
void JGL::VRamList::SetData(void* data, const long& size) {
bool should_resize = (this->size != size);
void JGL::VRamList::SetData(void* data, const long& length) {
bool should_resize = (this->num_elements != length);
if (should_resize) {
glDeleteBuffers(1, &list_handle);
list_handle = 0;
if (!element_array_buffer)
load((GLfloat*) data, sizeof(GLfloat) * size);
load((GLfloat*) data, sizeof(GLfloat) * length);
else
load((GLuint*) data, sizeof(GLuint) * size);
load((GLuint*) data, sizeof(GLuint) * length);
return;
}
@@ -108,13 +87,184 @@ void JGL::VRamList::SetData(void* data, const long& size) {
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* buffer_data = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (buffer_data == nullptr)
jlog::Fatal("Mapping in a VBO that doesn't exist?");
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(buffer_data, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * size);
memcpy(vram, data, (element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat)) * length);
if (!glUnmapBuffer(buffer_type))
jlog::Fatal("We couldn't unmap the buffer?");
JGL::Logger::Fatal("We couldn't unmap the buffer?");
glBindBuffer(buffer_type, current_buffer);
}
void JGL::VRamList::UpdateData(void* data, const long& offset, const long& length) {
if (offset + length > num_elements) {
JGL::Logger::Warning("Using UpdateData to out-of-bounds write the VRamList? I'll resize it for you, But this is slow.");
unsigned long oob_delta = (offset + length) - num_elements;
if (element_array_buffer) {
auto list_data = GetDataUI();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLuint)), data, length * sizeof(GLuint));
SetData(list_data.data(), list_data.size());
}
else {
auto list_data = GetDataF();
list_data.resize(list_data.size() + oob_delta);
memcpy(list_data.data() + (offset * sizeof(GLfloat)), data, length * sizeof(GLfloat));
SetData(list_data.data(), list_data.size());
}
}
GLint current_buffer = 0;
GLenum buffer_type = GL_ARRAY_BUFFER;
GLenum buffer_binding = GL_ARRAY_BUFFER_BINDING;
if (element_array_buffer)
buffer_type = GL_ELEMENT_ARRAY_BUFFER,
buffer_binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
glGetIntegerv(buffer_binding, &current_buffer);
glBindBuffer(buffer_type, list_handle);
void* vram = glMapBuffer(buffer_type, GL_WRITE_ONLY);
if (!vram)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
size_t element_size = element_array_buffer ? sizeof(GLuint) : sizeof(GLfloat);
memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(vram) + (offset * element_size)), data, length * element_size);
if (!glUnmapBuffer(buffer_type))
JGL::Logger::Fatal("We couldn't unmap the buffer?");
glBindBuffer(buffer_type, current_buffer);
}
std::vector<GLfloat> JGL::VRamList::GetDataF() const {
if (element_array_buffer)
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
GLint current_buffer = 0;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
std::vector<GLfloat> data(num_elements);
void* vram = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLfloat));
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
return data;
}
std::vector<GLuint> JGL::VRamList::GetDataUI() const {
if (!element_array_buffer)
JGL::Logger::Warning("Getting data as GLuint but the buffer data is GLfloat?");
GLint current_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, list_handle);
std::vector<GLuint> data(num_elements);
void* vram = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
if (vram == nullptr)
JGL::Logger::Fatal("Mapping in a VBO that doesn't exist?");
memcpy(data.data(), vram, num_elements * sizeof(GLuint));
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_buffer);
return data;
}
JGL::VRamList::VRamList(const GLfloat* data, const long& length) {
load(data, (long) sizeof(GLfloat) * length);
}
JGL::VRamList::VRamList(const GLuint* data, const long& length) {
load(data, (long) sizeof(GLuint) * length);
}
JGL::VRamList::VRamList(Vector2* data, const long& length) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector2) * length);
}
JGL::VRamList::VRamList(Vector3* data, const long& length) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector3) * length);
}
JGL::VRamList::VRamList(Vector4* data, const long& length) {
load(reinterpret_cast<GLfloat*>(data), (long) sizeof(Vector4) * length);
}
void JGL::VRamList::SetData(const GLfloat* data, const long& length) {
SetData((void*) data, length);
}
void JGL::VRamList::SetData(const Vector2* data, const long& length) {
SetData((void*) data, length * 2);
}
void JGL::VRamList::SetData(const Vector3* data, const long& length) {
SetData((void*) data, length * 3);
}
void JGL::VRamList::SetData(const Vector4* data, const long& length) {
SetData((void*) data, length * 4);
}
void JGL::VRamList::SetData(const GLuint* data, const long& length) {
SetData((void*) data, length);
}
void JGL::VRamList::SetData(const Vector2i* data, const long& length) {
SetData((void*) data, length * 2);
}
void JGL::VRamList::UpdateData(const GLfloat* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length);
}
void JGL::VRamList::UpdateData(const Vector2* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 2);
}
void JGL::VRamList::UpdateData(const Vector3* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 3);
}
void JGL::VRamList::UpdateData(const Vector4* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 4);
}
void JGL::VRamList::UpdateData(const GLuint* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length);
}
void JGL::VRamList::UpdateData(const Vector2i* data, const long& offset, const long& length) {
UpdateData((void*) data, offset, length * 2);
}
JGL::VRamList::~VRamList() {
Erase();
}
JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
if (rhs.element_array_buffer) {
auto data_array = rhs.GetDataUI();
this->load(data_array.data(), data_array.size());
return;
}
auto data_array = rhs.GetDataF();
this->load(data_array.data(), data_array.size());
}