Compare commits

...

22 Commits

Author SHA1 Message Date
b86377a092 Get VBO data back from the GPU.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m17s
2024-09-19 10:55:13 -04:00
5fc4914180 fix logger
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m45s
2024-09-17 23:19:55 -04:00
58e432b9c3 Make logging fit to standard
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m7s
2024-09-17 23:17:19 -04:00
41fa634da1 "VRam List" wrapped for VBO (useful later)
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 6m25s
2024-09-17 14:36:32 -04:00
9d6d256e80 fix for windoze
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m34s
2024-09-14 22:27:20 -04:00
0e22bc721a Positioning & Rotation bugfixes.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m51s
Make it such that a sprites "origin" doesn't effect the position. It is only the point at which transformations are done about.
2024-09-14 21:28:32 -04:00
881d031f3c Render Target for J2D
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m10s
2024-09-13 13:24:20 -04:00
9e3e0c949f Bugfix + Begin work on RenderTarget
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 2m0s
Fixed an issue that'd sometimes cause declaring a new texture to change to that texture.
2024-09-12 19:20:29 -04:00
1526a101c3 J3D::DrawString is now fast.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m33s
2024-09-11 20:36:46 -04:00
f6e8875eb9 ~ 5% speedup for font-rendering overall
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m55s
This is probably the last speedup for this.
2024-09-11 18:33:29 -04:00
9903fc19c9 Mirror Sprite and Cleanup
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m5s
2024-09-11 09:50:52 -04:00
e809b1b665 Rotate sprite & sub-sprite about origin
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 5m24s
2024-09-08 21:52:49 -04:00
d15b3f660d J3D draw string draw_back_face
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 7m30s
2024-09-05 11:50:12 -04:00
ff2a8ab787 Refactor & undo shader commits AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 6m18s
2024-09-05 11:20:57 -04:00
55160044b6 Fix cmake_minimum_required using rebitch
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m40s
2024-08-26 19:46:51 -04:00
04a4cbd54d Add Attributes to Shader.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m40s
2024-08-24 23:27:10 -04:00
f96a3851a1 Update engine components
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m32s
2024-08-24 10:58:37 -04:00
4996288163 More work on shader support.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m24s
2024-08-23 19:50:41 -04:00
f3c2fd5e93 Initial shader class & restructure
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m38s
2024-08-23 12:25:46 -04:00
6650af4fc4 Framerate test (Press 1)
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m42s
2024-08-22 19:27:31 -04:00
1d8823b046 Outline Polygon
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m8s
2024-08-22 11:55:56 -04:00
c0b65818c8 DrawPartialSprite
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 7m11s
2024-08-22 10:58:20 -04:00
22 changed files with 1146 additions and 773 deletions

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 3.18..3.27)
project(JGL
VERSION 1.0
LANGUAGES CXX
@@ -17,22 +17,22 @@ include(cmake/CPM.cmake)
CPMAddPackage(
NAME mcolor
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-3.zip
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-4.zip
)
CPMAddPackage(
NAME J3ML
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.0.zip
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.1.zip
)
CPMAddPackage(
NAME ReWindow
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-12.zip
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-15.zip
)
CPMAddPackage(
NAME GLAD
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_mt.zip
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo.zip
)
CPMAddPackage(
@@ -80,16 +80,16 @@ endif()
set_target_properties(JGL PROPERTIES LINKER_LANGUAGE CXX)
#Don't expose this one because it's only to be used in the demo program.
include_directories(${ReTexture_SOURCE_DIR}/include)
#Don't expose these ones.
include_directories(${ReWindow_SOURCE_DIR}/include)
target_include_directories(JGL PUBLIC
${PROJECT_SOURCE_DIR}/include
${OPENGL_INCLUDE_DIRS}
${ReTexture_SOURCE_DIR}/include
${mcolor_SOURCE_DIR}/include
${J3ML_SOURCE_DIR}/include
${Event_SOURCE_DIR}/include
${ReWindow_SOURCE_DIR}/include
${glad_SOURCE_DIR}/include
${jlog_SOURCE_DIR}/include
)
@@ -100,13 +100,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 ReWindowLibrary glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
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 ReWindowLibrary glad jlog Event ReTexture)
target_link_libraries(JGL PUBLIC ${OPENGL_LIBRARIES} mcolor J3ML glad jlog Event ReTexture)
endif()
target_link_libraries(JGL_Demo PUBLIC JGL)
target_link_libraries(JGL_Demo PUBLIC JGL ReWindowLibrary)

View File

@@ -0,0 +1,5 @@
#version 120
void main() {
gl_FragColor = vec4(1, 1, 1, 1);
}

View File

@@ -0,0 +1,7 @@
#version 120
attribute vec2 position;
void main() {
gl_Position = vec4(position.x, position.y, 1.0, 1.0);
}

View File

@@ -13,70 +13,42 @@
#pragma once
#include <string>
#include <iostream>
#include <Color3.hpp>
#include <Color4.hpp>
#include <Colors.hpp>
#include <JGL/Texture.h>
#include <JGL/enums.h>
#include <JGL/FontCache.h>
#include <JGL/Font.h>
#include <JGL/types/Texture.h>
#include <JGL/types/Enums.h>
#include <JGL/types/FontCache.h>
#include <JGL/types/Font.h>
#include <JGL/types/RenderTarget.h>
#include <J3ML/LinearAlgebra.hpp>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <J3ML/LinearAlgebra/Vector3.hpp>
#include <J3ML/Geometry/Sphere.hpp>
#include <J3ML/Geometry/Capsule.hpp>
#include <J3ML/Geometry/TriangleMesh.hpp>
#include <J3ML/Geometry/Triangle2D.hpp>
/// OpenGL Wrapper for rendering 2D graphics primitives in both a 2D and 3D context
/// OpenGL Wrapper for rendering 2D & 3D graphics in both a 2D and 3D context.
namespace JGL {
using namespace J3ML::LinearAlgebra;
using namespace J3ML::Geometry;
/// TODO: Implement HSV and other color representation conversions
struct HSV {
float hue;
float saturation;
float value;
};
/// TODO: Migrate to using J3ML's definition once finished (hint hint)
struct Triangle2D
{
Vector2 A;
Vector2 B;
Vector2 C;
};
void Update(const Vector2& window_size);
void PurgeFontCache();
// TODO: Implement
void SetActiveFont(const Font& font);
// TODO: Overrides specifically for Color3 are not **strictly** necessary, Color3 and Color4 should implicitly convert back and forth.
inline void PurgeFontCache() { fontCache.purgeCache(); }
std::vector<GLfloat> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
/// Drawing functions for primitive 2D Shapes.
/// Each function is overloaded with Color3 and Color4 for optional transparency.
namespace J2D {
/// Open a 2-D rendering context with the underlying graphics system (In this case & by default OpenGL).
/// Open a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @note This call may not strictly be necessary on some setups, but is provided to keep the API constant.
/// It is recommended to always open a JGL 2D context to render your content, then close when completed.
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 3D content in between our calls.
void Begin();
/// Closes a 2-D rendering context with the underlying graphics system (In this case & by default OpenGL).
void Begin(RenderTarget* render_target = nullptr, bool clear_buffers = false);
/// Closes a 2-D rendering context with the underlying graphics system (In this case& by default OpenGL).
/// @see Begin().
void End();
/// Plots a single pixel on the screen.
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
/// @param coordinates The pixel-point on-screen at which to plot the pixel.
void DrawPoint(const Color3& color, const Vector2& coordinates, float radius = 1.f);
void DrawPoint(const Color3& color, float x, float y, float radius = 1.f);
void DrawPoint(const Color4& color, const Vector2& coordinates, float radius = 1.f);
void DrawPoint(const Color4& color, float x, float y, float radius = 1.f);
@@ -85,117 +57,105 @@ namespace JGL {
/// @param A The starting point of the line segment.
/// @param B The end point of the line segment.
/// @param thickness The width at which to render the line.
void DrawLine(const Color3& color, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawLine(const Color3& color, float x, float y, float w, float h, float thickness = 1);
void DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawLine(const Color4& color, float x1, float y1, float x2, float y2, float thickness = 1);
///Draws a line with a gradient that transitions across it.
void DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color3& color1, const Color3& color2, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness = 1);
void DrawGradientLine(const Color3& color1, const Color3& color2, float x, float y, float w, float h, float thickness = 1);
void DrawGradientLine(const Color4& color_a, const Color4& color_b, const Vector2& A, const Vector2& B, float thickness = 1);
void DrawGradientLine(const Color4& color_a, const Color4& color_b, float x, float y, float w, float h, float thickness = 1);
/// Draws an outline of a rectangle on the screen.
void OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness = 1);
void OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness = 1);
/// Draws a sprite to the screen by passing a GLuint that represents a handle to a loaded texture.
/// Draws a filled rectangle on the screen.
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
/// Draws a filled rectangle where the color transitions across it.
void FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size);
/// 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),
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
/// @param origin The center point around which the image should have all transformations applied to it.
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
/// @param color A 32-bit RGBA value represented as four unsigned 8-bit integers.
/// @param inversion
/// @param inversion inverts the texture only.
/// @see class Texture
void DrawSprite(const Texture& texture,
const Vector2& position,
const Vector2& origin = Vector2(0,0),
const Vector2& scale = Vector2(1,1),
const Color4& color = Colors::White,
Inversion inversion = Inversion::None);
void DrawSprite(const Texture& texture, 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 Texture& texture,
float positionX, float positionY,
float rad_rotation = 0,
float originX = 0, float originY = 0,
float scaleX = 1, float scaleY = 1,
const Color4& color = Colors::White,
Inversion inversion = Inversion::None);
Direction inversion = Direction::None);
/// Draws a piece of a sprite to the screen, similar to DrawSprite.
/// @param texture
/// @param position
/// @param sub_texture_position The top left corner of the sub-texture to be drawn.
/// @param sub_texture_size The size of the sub-texture in px.
/// @param origin
/// @param scale
/// @param color
/// @param inversion
void DrawPartialSprite(const Texture& texture, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size, 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 DrawPartialSprite(const Texture& texture, float positionX, float positionY, float sub_texture_positionX, float sub_texture_positionY, unsigned int sub_texture_sizeX, unsigned int sub_texture_sizeY,
float rad_rotation = 0, float originX = 0, float originY = 0, float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
/// Draws a non axis-aligned fill rect to the screen.
/// The order of the vertices must be such that if you were to connect them you'd never go diagonally across the quad.
void FillQuad(const Color4& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4);
void FillQuad(const Color3& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4);
/// Draws a non axis-aligned outline rect to the screen.
/// The order of the vertices must be such that if you were to connect them you'd never go diagonally across the quad.
void OutlineQuad(const Color4& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float thickness = 1);
void OutlineQuad(const Color3& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float thickness = 1);
/// Draws a filled rectangle on the screen.
void FillRect(const Color4& color, const Vector2& pos, const Vector2& size);
void FillRect(const Color3& color, const Vector2& pos, const Vector2& size);
/// Draws a filled rectangle where the color transitions across it.
void FillGradientRect(const Color4& color1, const Color4& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
void FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size);
/// 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 FillRoundedRect(const Color3& color, const Vector2& pos, const Vector2& size, float radius = 5, unsigned int subdivisions = 8);
/// To save v-ram, Use if a sprite would be identical if mirrored horizontally, vertically, or both. For example, a circle.
/// Assumes the input texture is the top left quadrant. You can use "SoftwareTexture" to invert it correctly so that's the case.
/// @param texture
/// @param position
/// @param mirror_axis The axes to mirror across, Vertical and Horizontal or both only.
/// @param rad_rotation The rotation of the final result.
/// @param origin The point at which transformations are done about.
/// @param scale
/// @param color
void DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis = Direction::Horizontal | Direction::Vertical, float rad_rotation = 0, const Vector2& origin = Vector2(0,0), const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White);
/// Draws an outline of a circle on the screen.
void OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
void OutlineCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions = 16, float thickness = 1);
/// Draws a filled circle on the screen.
void FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
void FillCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions = 8);
/// Draws an outline of a triangle on the screen.
/// @param color
/// @param tri
/// @param thickness
void OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness = 1);
void OutlineTriangle(const Color3& color, const Triangle2D& tri, float thickness = 1);
void OutlineTriangle(const Color4& color,
const Vector2& triA, const Vector2& triB, const Vector2& triC,
float thickness = 1);
void OutlineTriangle(const Color3& color,
const Vector2& triA, const Vector2& triB, const Vector2& triC,
float thickness = 1);
// TODO: Take more Focalin
void OutlineTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC, float thickness = 1);
/// Draws a filled triangle on the screen.
void FillTriangle(const Color4& color, const Triangle2D& tri);
void FIllTriangle(const Color4& color, const Vector2& triA, const Vector2& triB, const Vector2& triC);
void FillTriangle(const Color3& color, const Triangle2D& tri);
/// Draws a triangle where each corner is defined by a given color, Smoothly transitioning between them.
void FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri);
void FillGradientTriangle(const Color3& a_color, const Color3& b_color, const Color3& c_color, const Triangle2D& tri);
// TODO: Implement an overload that simply takes 3 Vector3's
void DrawCubicBezierCurve(const Color4& color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
int subdivisions = 10, float thickness = 1);
/// Draws a series of points where the last point always connects to the first point.
void OutlinePolygon(const Color4& color, const std::vector<Vector2>& points, float thickness = 1);
/// Draws a text string on the screen with a given point-size and font.
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
void DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
// TODO: Implement the following:
void FillTexturedTriangle();
/// TODO Implement the following. These ones are going to be extremely annoying.
void FillPolygon(const Color4& color, const std::vector<Vector2>& points);
void FillTexturedPolygon();
void DrawPartialSprite();
void DrawCubicBezierCurve(const Color4& color,
const Vector2& controlA, const Vector2& pointA,
const Vector2& pointB, const Vector2& controlB,
int subdivisions = 10,
float thickness = 1);
void OutlinePolygon (const Color4& color, std::vector<Vector2> points);
void FillPolygon (const Color4& color, std::vector<Vector2> points, float thickness = 1);
void OutlineRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius = 5, float thickness = 1);
void FillTexturedTriangle();
}
/// Drawing functions for primitive 3D Shapes.
@@ -207,7 +167,6 @@ namespace JGL {
void End();
void SetMatrix(const std::vector<GLfloat>& matrix, const Vector2& window_size);
void DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness = 1);
void DrawLine(const Color3& color, const Vector3& A, const Vector3& B, float thickness = 1);
void FillSphere(const Color3& color, const Sphere& sphere);
void WireframeSphere(const Color3& color, const Sphere& sphere, float thickness = 1);
void FillOBB(const Color3& color, const OBB& obb);
@@ -216,7 +175,7 @@ namespace JGL {
void WireframeCapsule(const Color3& color, const Capsule& cap, float thickness = 1);
void FillTriangleMesh(const Color3& color, const TriangleMesh& mesh);
void WireframeTriangleMesh(const Color3& color, const TriangleMesh& mesh, float thickness = 1);
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, const Font& font);
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngle& angle = {0, 0, 0}, bool draw_back_face = false);
void DrawSprite();
void DrawMatrixGizmo (const Matrix3x3&, const Vector3&);
void DrawMatrixGizmo (const Matrix4x4&);

View File

@@ -1,33 +0,0 @@
#pragma once
namespace JGL {
enum class Inversion : u8 {
None = 0,
Vertical = 1,
Horizontal = 2,
};
inline Inversion operator|(Inversion a, Inversion b) {
return static_cast<Inversion>(static_cast<int>(a) | static_cast<int>(b));
}
inline bool operator&(Inversion a, Inversion b) {
return (u8)a & (u8)b;
}
}
namespace JGL {
enum class Gradient : u8 {
Vertical = 0,
Horizontal = 1,
DiagonalTopLeft = 2,
DiagonalBottomLeft = 4
};
inline Gradient operator|(Gradient a, Gradient b) {
return static_cast<Gradient>(static_cast<int>(a) | static_cast<int>(b));
}
inline bool operator&(Gradient a, Gradient b) {
return (u8)a & (u8)b;
}
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <jlog/Logger.hpp>
namespace JGL::Logger {
using namespace jlog;
extern GenericLogger Fatal;
extern GenericLogger Debug;
extern GenericLogger Error;
}

36
include/JGL/types/Enums.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
namespace JGL {
enum class Direction : u8 {
None = 0,
Vertical = 1,
Horizontal = 2,
Diagonal_NWSE = 3, // North West -> South East.
Diagonal_SWNE = 4 // South West -> North East.
};
inline Direction operator|(Direction a, Direction b) {
return static_cast<Direction>(static_cast<int>(a) | static_cast<int>(b));
}
inline bool operator&(Direction a, Direction b) {
return (u8)a & (u8)b;
}
static std::string to_string(JGL::Direction direction) {
switch (direction) {
case JGL::Direction::None:
return "None";
case JGL::Direction::Vertical:
return "Vertical";
case JGL::Direction::Horizontal:
return "Horizontal";
case JGL::Direction::Diagonal_NWSE:
return "Diagonal_NWSE";
case JGL::Direction::Diagonal_SWNE:
return "Diagonal_SWNE";
default:
return "Unknown";
}
}
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <array>
#include <map>
#include <vector>
#include <glad/glad.h>
#include <vector>
#include <array>
#include <unordered_map>
/// TODO: FontCache mechanism works amazing, but makes no fucking sense
@@ -27,13 +27,13 @@ public:
//CachedGlyph(GLuint texture_id, char c);
CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2o, float y2o, float w, float h, float advX, float advY);
char getCharacter();
const std::array<GLfloat, 12> getTexCoords() const;
[[nodiscard]] std::array<GLfloat, 12> getTexCoords() const;
};
/// Represents a Font object as it exists in the font-cache.
class JGL::CachedFont {
private:
std::map<char, CachedGlyph*> glyphs;
std::unordered_map<char, CachedGlyph*> glyphs;
GLuint texture = 0;
GLsizei texture_width = 0, texture_height = 0;
unsigned int font_size = 0;
@@ -43,16 +43,16 @@ public:
unsigned int getFontSize();
unsigned int getFontIndex();
CachedGlyph* getGlyph(char c);
std::map<char, CachedGlyph*> getGlyphs();
std::unordered_map<char, CachedGlyph*> getGlyphs();
const GLuint* getTexture();
GLsizei getTextureWidth() const;
GLsizei getTextureHeight() const;
[[nodiscard]] GLsizei getTextureWidth() const;
[[nodiscard]] GLsizei getTextureHeight() const;
CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture_height, unsigned int font_size, unsigned int font_index);
};
class JGL::FontCache {
private:
std::vector<CachedFont*> cachedFonts = {};
std::vector<CachedFont*> cachedFonts{};
public:
std::vector<CachedFont*> getFonts();
CachedFont* getFont(unsigned int font_size, unsigned int font_index);

View File

@@ -0,0 +1,37 @@
#pragma once
#include <glad/glad.h>
#include <JGL/types/Texture.h>
#include <Color4.hpp>
#include <Colors.hpp>
namespace JGL {
class RenderTarget;
}
class JGL::RenderTarget {
private:
Color4 clear_color{0,0,0,0};
/// "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;
GLuint framebuffer_object = 0;
GLuint depth_buffer = 0;
Texture* texture = nullptr;
public:
static GLuint GetActiveGLFramebufferHandle();
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
public:
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] Texture* GetJGLTexture() const;
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
[[nodiscard]] Color4 GetClearColor() 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);
/// 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();
};

View File

@@ -32,18 +32,23 @@ namespace JGL {
ReTexture::TextureFormat texture_format;
TextureFilteringMode texture_filtering_mode;
TextureWrappingMode texture_wrapping_mode;
virtual void load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
void load(SoftwareTexture* 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);
/* Initialize a texture filled with trash data
this is primarily for the RenderTarget */
explicit Texture(const Vector2& size);
Texture() = default;
public:
GLuint GetGLTextureHandle() const;
Vector2 GetDimensions() const;
TextureFilteringMode GetFilteringMode() const;
TextureFlag GetFlags() const;
TextureFormat GetFormat() const;
std::vector<Color4> GetPixelData() const;
[[nodiscard]] GLuint GetGLTextureHandle() const;
[[nodiscard]] Vector2 GetDimensions() const;
[[nodiscard]] TextureFilteringMode GetFilteringMode() const;
[[nodiscard]] TextureWrappingMode GetWrappingMode() const;
[[nodiscard]] TextureFlag GetFlags() const;
[[nodiscard]] TextureFormat GetFormat() const;
[[nodiscard]] std::vector<Color4> GetPixelData() const;
void SetTextureHandle(GLuint handle);
void Erase();

View File

@@ -0,0 +1,68 @@
#pragma once
#include <glad/glad.h>
#include <J3ML/LinearAlgebra/Vector2.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.
class JGL::VRamList {
private:
GLuint list_handle = 0;
long size = 0;
bool element_array_buffer = false;
void load(const GLfloat* data, const long& size);
void load(const GLuint* data, const long& size);
public:
VRamList() = default;
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& size);
public:
[[nodiscard]] GLuint GetHandle() const;
/// Returns the number of GLfloat or GLuint in the list.
[[nodiscard]] long GetSize() const;
/// Returns the size of the data in bytes.
[[nodiscard]] long GetDataSize() const;
[[nodiscard]] bool IsIntegerArray() const;
[[nodiscard]] bool IsFloatArray() const;
void Erase();
/// Get list data back from the GPU. This is *very* slow.
/// It's not recommended you use this in your normal rendering routines.
template <typename T>
[[nodiscard]] std::vector<T> GetListData() 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 {
Logger::Fatal("Typename T must be either GLfloat or GLuint.");
exit(-1);
}
glBindBuffer(buffer_type, list_handle);
std::vector<T> data(size);
memcpy(data.data(), (T*) glMapBuffer(buffer_type, GL_READ_ONLY), size * sizeof(T));
glUnmapBuffer(buffer_type);
glBindBuffer(buffer_type, current_buffer);
return data;
}
};

View File

@@ -2,10 +2,8 @@
#include <JGL/JGL.h>
#include <rewindow/types/window.h>
#include <Colors.hpp>
#include <chrono>
#include <J3ML/LinearAlgebra/Vector2.hpp>
#include <JGL/Font.h>
#include <jlog/jlog.hpp>
#include <ReTexture/Texture.h>
using J3ML::LinearAlgebra::Vector2;
using namespace JGL;
@@ -25,53 +23,31 @@ public:
void Grab() {
if (hovered)
{
dragging = true;
}
}
void Release() {
dragging = false;
}
void Update(const Vector2& mouse)
{
void Update(const Vector2& mouse) {
if (dragging)
{
position = position.Lerp(mouse, 0.25f);
}
if (mouse.Distance(position) < range)
{
hovered = true;
} else
{
hovered = false;
}
hovered = mouse.Distance(position) < range;
}
void Draw()
{
void Draw() {
if (dragging)
{
J2D::DrawPoint(Colors::White, position, 4.f);
} else if (hovered)
{
else if (hovered)
J2D::DrawPoint(Colors::Reds::Crimson, position, 6.f);
} else
{
else
J2D::DrawPoint(Colors::Reds::Salmon, position, 3.f);
}
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, 1.f, 10, FreeSans);
}
protected:
private:
};
Texture* image;
class Camera {
public:
Vector3 position = {0,0,0};
@@ -110,13 +86,14 @@ struct point {
GLfloat t;
};
Gizmo a({250, 150});
Gizmo b({200, 250});
Gizmo c({350, 300});
Gizmo d({450, 250});
Texture* image;
RenderTarget* j2d_render_target;
class JGLDemoWindow : public ReWindow::RWindow
{
public:
@@ -135,13 +112,19 @@ 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});
}
Vector3 textAngle = {0,0,0};
float fov = 90;
float sprite_radians = 0;
bool fov_increasing = true;
std::chrono::high_resolution_clock::time_point start;
float fps = 0.0f;
void display() {
start = std::chrono::high_resolution_clock::now();
JGL::Update(getSize());
if (fov_increasing)
fov += 0.25;
@@ -154,34 +137,36 @@ public:
fov_increasing = true;
J3D::ChangeFOV(fov);
sprite_radians += 0.05;
textAngle.y += 2.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera->render();
///All 3D elements of the scene and JGL elements *must* be rendered before the 2d stuff.
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
/* if rendering to screen space directly. */
J3D::Begin();
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f},textAngle, 1.f, 32, FreeSans);
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
J3D::End();
J2D::Begin();
J2D::FillQuad(Color4(Colors::Red), {500, 52}, {500, 152}, {600, 152}, {600, 52});
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
J2D::DrawSprite(*image, {200, 252}, {0.5, 0.5}, {2, 1});
J2D::DrawSprite(*image, {300, 300}, 0, {0,0}, {1, 1}, Colors::White, Direction::Vertical | Direction::Horizontal);
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::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
J2D::FillGradientRect(Colors::Red, Colors::Blue, Gradient::DiagonalBottomLeft, {100,52}, {100,100});
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);
//J2D::FillTriangle(Colors::Red, {{0, 275}, {0, 375}, {100, 375}});
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
@@ -191,7 +176,9 @@ public:
J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
J2D::OutlinePolygon(Colors::White, {{200, 400}, {220, 420}, {220, 430}, {230, 410}, {200, 400}});
//J2D::FillPolygon(Colors::White, {{200, 400}, {220, 420}, {220, 430}, {230, 410}, {200, 400}});
J2D::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
a.position,
b.position,
@@ -204,6 +191,17 @@ public:
c.Draw();
d.Draw();
J2D::End();
//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::End();
*/
std::chrono::high_resolution_clock::time_point stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> frame_time = stop - start;
fps = 1.0f / frame_time.count();
}
void OnRefresh(float elapsed) override {

View File

@@ -4,12 +4,16 @@
#include <JGL/JGL.h>
#include <glad/glad.h>
#include <Color3.hpp>
#include <jlog/jlog.hpp>
#include <J3ML/Algorithm/Bezier.hpp>
#include <JGL/logger/logger.h>
JGL::RenderTarget* render_target = nullptr;
GLfloat oldColor[4] = {0, 0, 0, 1};
GLfloat baseColor[4] = {1, 1, 1, 1};
GLuint current_fbo = 0;
GLint viewport[4] = {0, 0, 0, 0};
bool inJ2D = false;
bool inJ3D = false;
bool wasTexture2DEnabled = false;
@@ -27,69 +31,96 @@ namespace JGL {
void Update(const Vector2& window_size) {
wS = window_size;
glViewport(0, 0, wS.x, wS.y);
glViewport(0, 0, (int) wS.x, (int) wS.y);
}
void J2D::Begin() {
#pragma region J2D
void J2D::Begin(RenderTarget* rt, bool clear_buffers) {
GLfloat old_clear_color[4];
if (rt != nullptr) {
render_target = rt;
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
glGetIntegerv(GL_VIEWPORT, viewport);
current_fbo = JGL::RenderTarget::GetActiveGLFramebufferHandle();
JGL::RenderTarget::SetActiveGLRenderTarget(*rt);
}
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glViewport(0, 0, wS.x, wS.y);
glOrtho(0, wS.x, wS.y, 0, -1, 1);
if (rt == nullptr)
glViewport(0, 0, (int) wS.x, (int) wS.y),
glOrtho(0, wS.x, wS.y, 0, -1, 1);
else
glOrtho(0, rt->GetDimensions().x, rt->GetDimensions().y, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
//Get what the draw color was before we did anything.
glGetFloatv(GL_CURRENT_COLOR, oldColor);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
glGetIntegerv(GL_ACTIVE_TEXTURE,& activeTextureUnit);
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureUnit);
activeTextureUnit = activeTextureUnit - GL_TEXTURE0;
if (activeTextureUnit != 0)
glActiveTexture(GL_TEXTURE0);
wasDepthTestEnabled = false;
if (glIsEnabled(GL_DEPTH_TEST))
wasDepthTestEnabled = true,
glDisable(GL_DEPTH_TEST);
else
wasDepthTestEnabled = false;
wasVertexArraysEnabled = true;
if (!glIsEnabled(GL_VERTEX_ARRAY))
wasVertexArraysEnabled = false,
glEnableClientState(GL_VERTEX_ARRAY);
else
wasVertexArraysEnabled = true;
wasCullFaceEnabled = true;
if (!glIsEnabled(GL_CULL_FACE))
wasCullFaceEnabled = false,
glEnable(GL_CULL_FACE),
glCullFace(GL_BACK);
else
wasCullFaceEnabled = true;
wasBlendEnabled = true;
if (!glIsEnabled(GL_BLEND))
wasBlendEnabled = false,
glEnable(GL_BLEND),
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else
wasBlendEnabled = true;
wasTexture2DEnabled = true;
if (!glIsEnabled(GL_TEXTURE_2D))
wasTexture2DEnabled = false,
glEnable(GL_TEXTURE_2D);
else
wasTexture2DEnabled = true;
wasTextureCoordArrayEnabled = true;
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
wasTextureCoordArrayEnabled = false,
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
else
wasTextureCoordArrayEnabled = true;
wasColorArrayEnabled = false;
if (glIsEnabled(GL_COLOR_ARRAY))
wasColorArrayEnabled = true,
glDisableClientState(GL_COLOR_ARRAY);
else
wasColorArrayEnabled = false;
if (!inJ3D)
inJ2D = true;
else { ERROR("Attempt to Begin J2D inside of J3D context.") }
else { Logger::Error("Attempt to Begin J2D inside of J3D context."); }
if (rt != nullptr && clear_buffers) {
glClearColor(rt->GetClearColor().R(), rt->GetClearColor().G(), rt->GetClearColor().B(), rt->GetClearColor().A());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
}
}
void J2D::End() {
@@ -123,160 +154,130 @@ namespace JGL {
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
//Put the draw color back how it was before.
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
glColor4fv(oldColor);
if (render_target != nullptr) {
render_target = nullptr;
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
inJ2D = false;
}
void J2D::DrawSprite(const Texture& texture, const Vector2& pos, const Vector2& origin, const Vector2& scale, const Color4& color, Inversion inversion) {
void J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radius) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {coordinates};
const Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> 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.
// i.e. to render at 2x size, from the center, at coords XY, use {2, 2} scale, and {0.5, 0.5} offset.
const Vector2 offset = origin * size;
Vector2 pos2 = pos - offset*scale;
Vector2 scaled_size = scale * size;
Vector2 size2 = scaled_size;
const Vector2 vertices[] = {
pos2, // Top-left vertex
{pos2.x, pos2.y + size2.y}, // Bottom-left
{pos2.x + size2.x, pos2.y + size2.y}, // Bottom-right
{pos2.x + size2.x, pos2.y} // Top-right
};
if (inversion& Inversion::Vertical)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
if (inversion& Inversion::Horizontal)
textureCoordinates = {Vector2(1, 0), Vector2(1, 1), Vector2(0, 1), Vector2(0, 0)};
if ((inversion& Inversion::Horizontal) && (inversion& Inversion::Vertical))
textureCoordinates = {Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1)};
glPointSize(radius);
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
glDrawArrays(GL_QUADS, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glDrawArrays(GL_POINTS, 0, 1);
glColor4fv(baseColor);
}
void J2D::DrawSprite(const Texture& texture, float positionX, float positionY, float originX, float originY, float scaleX, float scaleY, const Color4& color, Inversion inversion)
{
DrawSprite(texture,
{positionX, positionX},
{originX, originY},
{scaleX, scaleY},
color,
inversion);
void J2D::DrawPoint(const Color4& color, float x, float y, float radius) {
DrawPoint(color, {x, y}, radius);
}
void J2D::FillQuad(const Color4& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4) {
void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
Vector2 vertices[] = {v1, v2, v3, v4};
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_QUADS, 0, 4);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J2D::FillQuad(const Color3& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4) {
J2D::FillQuad(Color4(color), v1, v2, v3, v4);
}
void J2D::OutlineQuad(const Color4& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Vector2 vertices[] = {v1, v2, v3, v4};
glLineWidth(thickness);
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
glColor4fv(baseColor);
}
void J2D::DrawLine(const Color4& color, float x, float y, float w, float h, float thickness) {
J2D::DrawLine(color, {x, y}, {w, h}, thickness);
}
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
if (!inJ2D)
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
GLfloat colors[8] = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized() };
glEnableClientState(GL_COLOR_ARRAY);
glLineWidth(thickness);
glColorPointer(4,GL_FLOAT,sizeof(Color4), colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
glDisableClientState(GL_COLOR_ARRAY);
glColor4fv(baseColor);
}
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness) {
J2D::DrawGradientLine(color1, color2, {x, y}, {w, h}, thickness);
}
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
if (!inJ2D)
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
}
void J2D::OutlineQuad(const Color3& color, const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float thickness) {
J2D::OutlineQuad(Color4(color), v1, v2, v3, v4);
}
void J2D::FillRect(const Color4& color, const Vector2& pos, const Vector2& size) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_QUADS, 0, 4);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
}
void J2D::FillRect(const Color3& color, const Vector2& pos, const Vector2& size) {
J2D::FillRect({color.r, color.g, color.b, 255}, pos, size);
}
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size) {
void J2D::FillGradientRect(const Color4& color1, const Color4& color2, const Direction& gradient, const Vector2& pos, const Vector2& size) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
std::vector<GLfloat> colors = {};
std::vector<GLfloat> colors{};
if (gradient == Gradient::Horizontal)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f, color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
if (gradient == Direction::Horizontal)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
else if (gradient == Gradient::Vertical)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f, color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f};
else if (gradient == Direction::Vertical)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(), color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized()};
else if (gradient == Gradient::DiagonalBottomLeft)
colors = {(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f, (color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f,
color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f,
(color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f, color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
else if (gradient == Direction::Diagonal_SWNE)
colors = {(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f,
color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(), (color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized()};
else if (gradient == Gradient::DiagonalTopLeft)
colors = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f,
(color1.b + color2.b) / 2.f / 255.f, (color1.a + color2.a) / 2.f / 255.f,color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f,
(color1.r + color2.r) / 2.f / 255.f, (color1.g + color2.g) / 2.f / 255.f, (color1.b + color2.b) / 2.f / 255.f,(color1.a + color2.a) / 2.f / 255.f};
else if (gradient == Direction::Diagonal_NWSE)
colors = {color1.RedChannelNormalized(), color1.GreenChannelNormalized(), color1.BlueChannelNormalized(), color1.AlphaChannelNormalized(),(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f,
(color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f, (color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f, color2.RedChannelNormalized(), color2.GreenChannelNormalized(), color2.BlueChannelNormalized(), color2.AlphaChannelNormalized(),
(color1.RedChannelNormalized() + color2.RedChannelNormalized()) / 2.f, (color1.GreenChannelNormalized() + color2.GreenChannelNormalized()) / 2.f, (color1.BlueChannelNormalized() + color2.BlueChannelNormalized()) / 2.f,(color1.AlphaChannelNormalized() + color2.AlphaChannelNormalized()) / 2.f};
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glColorPointer(4, GL_FLOAT, 0, colors.data());
glDrawArrays(GL_QUADS, 0, 4);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glColorPointer(4, GL_FLOAT, 0, colors.data());
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J2D::FillGradientRect(const Color3& color1, const Color3& color2, const Gradient& gradient, const Vector2& pos, const Vector2& size) {
J2D::FillGradientRect({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, gradient, pos, size);
glColor4fv(baseColor);
}
void J2D::FillRoundedRect(const Color4& color, const Vector2& pos, const Vector2& size, float radius, unsigned int subdivisions) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
J2D::FillRect(color, {pos.x + radius, pos.y}, {size.x - 2 * radius, size.y});
J2D::FillRect(color, {pos.x, pos.y + radius}, {size.x, size.y - 2 * radius});
@@ -287,117 +288,229 @@ namespace JGL {
J2D::FillCircle(color, {pos.x + size.x - radius, pos.y + size.y - radius}, radius, subdivisions);
}
void J2D::FillRoundedRect(const Color3& color, const J3ML::LinearAlgebra::Vector2& pos, const J3ML::LinearAlgebra::Vector2& size, float radius, unsigned int subdivisions) {
J2D::FillRoundedRect({color.r, color.g, color.b, 255}, pos, size, radius, subdivisions);
}
void
J2D::DrawRenderTargetAsSprite(const JGL::RenderTarget& rt, const Vector2& position, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
void J2D::OutlineRect(const Color4& color, const Vector2& pos, const Vector2& size, float thickness) {
//Correct for the render-target being upside-down.
Direction d{};
if (inversion == Direction::None)
d = Direction::Vertical;
else if (inversion == Direction::Horizontal)
d = Direction::Horizontal | Direction::Vertical;
else if (inversion& Direction::Horizontal && inversion& Direction::Vertical)
d = Direction::Horizontal;
//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);
J2D::DrawPartialSprite(*rt.GetJGLTexture(), position, {0, 0}, rt.GetDimensions(), rad_rotation, origin, scale, color, d);
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) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{pos.x, pos.y}, {pos.x, pos.y + size.y}, {pos.x + size.x, pos.y + size.y}, {pos.x + size.x, pos.y}};
glLineWidth(thickness);
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 4);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
const Vector2 size = texture.GetDimensions();
std::array<Vector2, 4> 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.
// i.e. to render at 2x size, from the center, at coords XY, use {2, 2} scale, and {0.5, 0.5} offset.
const Vector2 offset = origin * size;
Vector2 pos2 = pos;
Vector2 scaled_size = scale * size;
Vector2 size2 = scaled_size;
float cos_theta = std::cos(rad_rotation);
float sin_theta = std::sin(rad_rotation);
std::array<Vector2, 4> vertices =
{
pos2, // Top-left vertex
{pos2.x, pos2.y + size2.y}, // Bottom-left
{pos2.x + size2.x, pos2.y + size2.y}, // Bottom-right
{pos2.x + size2.x, pos2.y} // Top-right
};
//Rotate the vertices about the origin by float rad_rotation.
if (rad_rotation != 0)
for (auto& v: vertices)
v = {(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta +
pos2.x + offset.x * scale.x,
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta +
pos2.y + offset.y * scale.y
};
if (inversion& Direction::Vertical)
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
if (inversion& Direction::Horizontal)
textureCoordinates = {Vector2(1, 0), Vector2(1, 1), Vector2(0, 1), Vector2(0, 0)};
if ((inversion& Direction::Horizontal) && (inversion& Direction::Vertical))
textureCoordinates = {Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(0, 1)};
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
glDrawArrays(GL_QUADS, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(baseColor);
}
void J2D::OutlineRect(const Color3& color, const Vector2& pos, const Vector2& size, float thickness) {
J2D::OutlineRect({color.r, color.g, color.b, 255}, pos, size, thickness);
void J2D::DrawSprite(const Texture& texture, float positionX, float positionY, float rad_rotation, float originX,
float originY, float scaleX, float scaleY, const Color4& color, Direction inversion) {
DrawSprite(texture,
{positionX, positionY},
rad_rotation,
{originX, originY},
{scaleX, scaleY},
color, inversion);
}
void J2D::DrawLine(const Color4& color, const Vector2& A, const Vector2& B, float thickness) {
void J2D::DrawPartialSprite(const Texture& texture, const Vector2 &position, const Vector2& sub_texture_position,
const Vector2& sub_texture_size, float rad_rotation, const Vector2& origin,
const Vector2& scale, const Color4& color, Direction inversion) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
const Vector2 textureSize = texture.GetDimensions();
glLineWidth(thickness);
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
// 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 (inversion& Direction::Vertical)
std::swap(textureCoordinates[1], textureCoordinates[3]),
std::swap(textureCoordinates[5], textureCoordinates[7]);
if (inversion& Direction::Horizontal)
std::swap(textureCoordinates[0], textureCoordinates[6]),
std::swap(textureCoordinates[2], textureCoordinates[4]);
const Vector2 offset = origin * sub_texture_size;
Vector2 pos2 = position;
Vector2 scaled_size = scale * sub_texture_size;
Vector2 size2 = scaled_size;
float cos_theta = std::cos(rad_rotation);
float sin_theta = std::sin(rad_rotation);
std::array<Vector2, 4> vertices =
{
pos2, // Top-left
{pos2.x, pos2.y + size2.y}, // Bottom-left
{pos2.x + size2.x, pos2.y + size2.y},// Bottom-right
{pos2.x + size2.x, pos2.y} // Top-right
};
//Rotate the vertices about the origin by float rad_rotation.
if (rad_rotation != 0)
for (auto& v: vertices)
v = {(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta +
pos2.x + offset.x * scale.x,
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta +
pos2.y + offset.y * scale.y};
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordinates.data());
glDrawArrays(GL_QUADS, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(baseColor);
}
void J2D::DrawLine(const Color3& color, const Vector2& A, const Vector2& B, float thickness) {
J2D::DrawLine({color.r, color.g, color.b, 255}, A, B, thickness);
void
J2D::DrawPartialSprite(const JGL::Texture& texture, float positionX, float positionY, float sub_texture_positionX,
float sub_texture_positionY, unsigned int sub_texture_sizeX,
unsigned int sub_texture_sizeY, float originX, float originY, float rad_rotation,
float scaleX, float scaleY, const Color4& color, JGL::Direction inversion) {
J2D::DrawPartialSprite(texture, {positionX, positionY}, {sub_texture_positionX, sub_texture_positionY},
{(float) sub_texture_sizeX, (float) sub_texture_sizeY}, rad_rotation, {originX, originY},
{scaleX, scaleY}, color, inversion);
}
void J2D::DrawLine(const Color4& color, float x, float y, float w, float h, float thickness) {
J2D::DrawLine(color, {x, y}, {w, h}, thickness);
}
void J2D::DrawLine(const Color3& color, float x, float y, float w, float h, float thickness) {
J2D::DrawLine({color.r, color.g, color.b, 255}, x, y, w, h, thickness);
}
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
void J2D::DrawMirrorSprite(const Texture& texture, const Vector2& position, Direction mirror_axis, float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {A, B};
GLfloat colors[8] = {color1.r / 255.f, color1.g / 255.f, color1.b / 255.f, color1.a / 255.f,
color2.r / 255.f, color2.g / 255.f, color2.b / 255.f, color2.a / 255.f};
if (mirror_axis == Direction::None)
Logger::Warning("Drawing non-mirrored sprite with J2D::DrawMirrorSprite?");
glEnableClientState(GL_COLOR_ARRAY);
glLineWidth(thickness);
glColorPointer(4,GL_FLOAT,sizeof(GL_FLOAT) * 4, colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINES, 0, 2);
glDisableClientState(GL_COLOR_ARRAY);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
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)};
void J2D::DrawGradientLine(const Color3& color1, const Color3& color2, const Vector2& A, const Vector2& B, float thickness) {
J2D::DrawGradientLine({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, A, B, thickness);
}
void DrawGradientLine(const Color4& color1, const Color4& color2, float x, float y, float w, float h, float thickness) {
J2D::DrawGradientLine(color1, color2, {x, y}, {w, h}, thickness);
}
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)};
void DrawGradientLine(const Color3& color1, const Color3& color2, float x, float y, float w, float h, float thickness) {
J2D::DrawGradientLine({color1.r, color1.g, color1.b, 255}, {color2.r, color2.g, color2.b, 255}, {x, y}, {w, h}, thickness);
}
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)};
void J2D::DrawPoint(const Color4& color, const Vector2& coordinates, float radius) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.");
if ((mirror_axis& Direction::Horizontal) && (mirror_axis& Direction::Vertical))
textureCoordinates = {Vector2(0, 0), Vector2(0, 2), Vector2(2, 2), Vector2(2, 0)};
Vector2 vertices[] = {coordinates};
const Vector2 offset = origin * size;
Vector2 pos2 = position;
Vector2 size2 = scale * size;
float cos_theta = std::cos(rad_rotation);
float sin_theta = std::sin(rad_rotation);
glPointSize(radius);
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_POINTS, 0, 1);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
std::array<Vector2, 4> vertices =
{
pos2,
{pos2.x, pos2.y + size2.y},
{pos2.x + size2.x, pos2.y + size2.y},
{pos2.x + size2.x, pos2.y}
};
void J2D::DrawPoint(const Color3& color, const Vector2& coordinates, float radius) {
J2D::DrawPoint({color.r, color.g, color.b, 255}, coordinates);
}
if (rad_rotation != 0)
for (auto& v : vertices)
v = {
(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta + pos2.x + offset.x * scale.x,
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta + pos2.y + offset.y * scale.y
};
void J2D::DrawPoint(const Color4& color, float x, float y, float radius) {
DrawPoint(color, {x, y});
}
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
glDrawArrays(GL_QUADS, 0, 4);
void J2D::DrawPoint(const Color3& color, float x, float y, float radius) {
DrawPoint({color.r, color.g, color.b, 255}, {x, y});
//Reset the wrapping mode.
if (texture.GetWrappingMode() == 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);
else if (texture.GetWrappingMode() == TextureWrappingMode::REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else if (texture.GetWrappingMode() == 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);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4fv(baseColor);
}
void J2D::OutlineCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
float step = (2.f * Math::Pi) / (float) subdivisions;
std::vector<Vector2> vertices{};
@@ -410,110 +523,80 @@ namespace JGL {
}
glLineWidth(thickness);
glColor4f(color.RedChannelNormalized(),
color.GreenChannelNormalized(),
color.BlueChannelNormalized(),
color.AlphaChannelNormalized());
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J2D::OutlineCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions, float thickness) {
J2D::OutlineCircle({color.r, color.g, color.b, 255}, center, radius, subdivisions, thickness);
glDrawArrays(GL_LINE_LOOP, 0, (int) vertices.size());
glColor4fv(baseColor);
}
void J2D::FillCircle(const Color4& color, const Vector2& center, float radius, unsigned int subdivisions) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
GLfloat angle, x, y;
float step = (2.f * Math::Pi) / (float) subdivisions;
std::vector<Vector2> vertices{};
for (angle = 0.0f; angle < (2.f * Math::Pi); angle += step)
x = radius * sin(angle) + center.x,
y = radius * cos(angle) + center.y,
vertices.push_back({x, y});
x = radius * std::sin(angle) + center.x,
y = radius * std::cos(angle) + center.y,
vertices.emplace_back(x, y);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J2D::FillCircle(const Color3& color, const Vector2& center, float radius, unsigned int subdivisions) {
J2D::FillCircle({color.r, color.g, color.b, 255}, center, radius, subdivisions);
glDrawArrays(GL_TRIANGLE_FAN, 0, (int) vertices.size());
glColor4fv(baseColor);
}
void J2D::OutlineTriangle(const Color4& color, const Triangle2D& tri, float thickness) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
glLineWidth(thickness);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_LINE_LOOP, 0, 3);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J2D::OutlineTriangle(const Color3& color, const Triangle2D& tri, float thickness) {
J2D::OutlineTriangle({color.r, color.g, color.b, 255}, tri, thickness);
glColor4fv(baseColor);
}
void J2D::FillTriangle(const Color4& color, const Triangle2D& tri) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
}
void J2D::FillGradientTriangle(const Color4& a_color, const Color4& b_color, const Color4& c_color, const Triangle2D& tri) {
if (!inJ2D)
ERROR("Attempt to Render J2D element before J2D begin.")
Logger::Error("Drawing J2D element before J2D begin.");
Vector2 vertices[] = {{tri.A.x, tri.A.y}, {tri.B.x, tri.B.y}, {tri.C.x, tri.C.y}};
GLfloat colors[] = {a_color.r / 255.f, a_color.g / 255.f, a_color.b / 255.f, a_color.a / 255.f,b_color.r / 255.f,
b_color.g / 255.f, b_color.b / 255.f, b_color.a / 255.f,c_color.r / 255.f, c_color.g / 255.f, c_color.b / 255.f,
c_color.a / 255.f };
GLfloat colors[] = {a_color.RedChannelNormalized(), a_color.GreenChannelNormalized(), a_color.BlueChannelNormalized(), a_color.AlphaChannelNormalized(),
b_color.RedChannelNormalized(),b_color.GreenChannelNormalized(), b_color.BlueChannelNormalized(), b_color.AlphaChannelNormalized(),
c_color.RedChannelNormalized(), c_color.GreenChannelNormalized(), c_color.BlueChannelNormalized(),c_color.AlphaChannelNormalized()};
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(Color4), colors);
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableClientState(GL_COLOR_ARRAY);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
}
void J2D::FillGradientTriangle(const Color3& a_color, const Color3& b_color, const Color3& c_color, const Triangle2D& tri) {
J2D::FillGradientTriangle(Color4(a_color), Color4(b_color), Color4(c_color), tri);
}
void J2D::FillTriangle(const Color3& color, const Triangle2D& tri) {
J2D::FillTriangle({color.r, color.g, color.b, 255}, tri);
}
void J2D::DrawCubicBezierCurve(const Color4 &color, const J3ML::LinearAlgebra::Vector2 &controlA,
const J3ML::LinearAlgebra::Vector2 &pointA,
const J3ML::LinearAlgebra::Vector2 &pointB,
const J3ML::LinearAlgebra::Vector2 &controlB, int subdivisions, float thickness) {
void J2D::DrawCubicBezierCurve(const Color4 &color, const Vector2& controlA, const Vector2& pointA, const Vector2& pointB, const Vector2& controlB,
int subdivisions, float thickness) {
Vector2 last = controlA;
Vector2 first = controlB;
const Vector2& first = controlB;
for (int i = 0; i < subdivisions; ++i)
{
float alpha = (float)i / (float)subdivisions;
float alpha = (float) i / (float) subdivisions;
Vector2 step = J3ML::Algorithm::Bezier(alpha, controlA, pointA, pointB, controlB);
DrawLine(color, last, step, thickness);
last = step;
@@ -521,24 +604,33 @@ namespace JGL {
// Have to manually draw the last segment of the curve.
DrawLine(color, last, first, thickness);
// Display control points
DrawPoint(Colors::Red, controlA, 2.f);
DrawPoint(Colors::Red, controlB, 2.f);
DrawPoint(Colors::Reds::Salmon, pointA, 2.f);
DrawPoint(Colors::Reds::Salmon, pointB, 2.f);
}
//The 3D projection.
std::vector<GLfloat> perspective(float fov, float aspect, float nearPlane, float farPlane) {
std::vector<float> result(16);
float f = 1.0f / tan(fov * 0.5f * Math::Pi / 180.0f);
void J2D::OutlinePolygon(const Color4 &color, const std::vector<Vector2>& points, float thickness) {
if (!inJ2D)
Logger::Error("Drawing J2D element before J2D begin.");
if (points.front() != points.back())
throw std::runtime_error("J2D::OutlinePolygon: The first point and the last point must connect.");
glLineWidth(thickness);
glColor4ubv(color.ptr());
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), points.data());
glDrawArrays(GL_LINE_LOOP, 0, (int) points.size());
glColor4fv(baseColor);
}
#pragma endregion
#pragma region J3D
std::vector<GLfloat> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far) {
std::vector<GLfloat> result(16);
GLfloat f = 1.0f / std::tan(fovY * 0.5f * Math::Pi / 180.0f);
result[0] = f / aspect;
result[5] = f;
result[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
result[10] = (z_far + z_near) / (z_near - z_far);
result[11] = -1.0f;
result[14] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
result[14] = (2.0f * z_far * z_near) / (z_near - z_far);
return result;
}
@@ -568,12 +660,12 @@ namespace JGL {
auto aspect = (float) wS.x / (float) wS.y;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMultMatrixf(perspective(j3d_fov, aspect, 0.001, j3d_far_plane).data());
glMultMatrixf(OpenGLPerspectiveProjectionRH(j3d_fov, aspect, 0.001, j3d_far_plane).data());
glMatrixMode(GL_MODELVIEW);
//Get what the draw color was before we did anything.
glGetFloatv(GL_CURRENT_COLOR, oldColor);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
glColor4fv(baseColor);
wasDepthTestEnabled = false;
if (glIsEnabled(GL_DEPTH_TEST))
@@ -585,28 +677,34 @@ namespace JGL {
wasVertexArraysEnabled = false,
glEnableClientState(GL_VERTEX_ARRAY);
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
wasTextureCoordArrayEnabled = false,
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
else
wasTextureCoordArrayEnabled = true;
wasTexture2DEnabled = true;
if (!glIsEnabled(GL_TEXTURE_2D))
wasTexture2DEnabled = false,
glEnable(GL_TEXTURE_2D);
// TODO: implement bool drawBackface as DrawString parameter.
wasCullFaceEnabled = false;
if (glIsEnabled(GL_CULL_FACE))
wasCullFaceEnabled = true,
glDisable(GL_CULL_FACE);
wasBlendEnabled = true;
if (!glIsEnabled(GL_BLEND))
wasBlendEnabled = false,
glEnable(GL_BLEND),
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
else
wasBlendEnabled = true;
if (!inJ2D)
inJ3D = true;
else { ERROR("Attempt to Begin J3D inside of J2D context.")}
else
Logger::Error("Can't begin J3D context inside J2D context.");
}
void J3D::End() {
@@ -625,26 +723,25 @@ namespace JGL {
if (wasCullFaceEnabled)
glEnable(GL_CULL_FACE);
//Put the draw color back how it was before.
glColor4f(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
if (!wasTextureCoordArrayEnabled)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//Put the draw color back how it was before.
glColor4fv(oldColor);
inJ3D = false;
}
void J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
if (!inJ3D)
ERROR("Attempt to Render J3D element before J3D begin.")
Logger::Error("Attempt to Render J3D element before J3D begin.");
Vector3 vertices[] = {A, B};
glLineWidth(thickness);
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
glColor4ubv(color.ptr());
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
glDrawArrays(GL_LINES, 0, 2);
glColor4f(baseColor[0], baseColor[1], baseColor[2], baseColor[3]);
}
void J3D::DrawLine(const Color3& color, const Vector3& A, const Vector3& B, float thickness) {
J3D::DrawLine({color.r, color.g, color.b, 255}, A, B, thickness);
glColor4fv(baseColor);
}
#pragma endregion
}

View File

@@ -1,251 +0,0 @@
#include <JGL/JGL.h>
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#include <JGL/Font.h>
#include <JGL/FontCache.h>
#include <jlog/jlog.hpp>
namespace JGL {
void PurgeFontCache() {
fontCache.purgeCache();
}
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
glUseProgram(0); // Fixed-function pipeline.
// Offset by height to render at "correct" location.
y += size;
CachedFont* cachedFont = fontCache.getFont(size, font.index);
//Set up the regular font.
//for (const auto &f : Font::GetLoadedFonts())
// if (f.index == font.index)
// font = f;
if (font.face == nullptr)
return;
FT_Set_Pixel_Sizes(font.face, 0, size);
//If the font doesn't exist in the cache yet.
if (!cachedFont) {
DEBUG("Caching font data...");
GLuint texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
GLsizei width = 0;
GLsizei max_height = 0;
FT_ULong charcode;
FT_UInt gindex;
//We have to loop over the available glyphs twice as we need the
//final width and height of the texture_handle before we can construct it
//and subsequently upload the glyph data.
charcode = FT_Get_First_Char(font.face, &gindex);
//Strings are char-based so we only handle charcodes within the extended ASCII range.
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
width += g->bitmap.width;
max_height = std::max(max_height, (GLsizei)g->bitmap.rows);
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
fontCache.newFont(texture_id, width, max_height, size, font.index);
cachedFont = fontCache.getFont(size, font.index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, max_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
GLsizei xoffset = 0;
charcode = FT_Get_First_Char(font.face, &gindex);
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
GLfloat u0 = (GLfloat)xoffset / cachedFont->getTextureWidth();
GLfloat u1 = u0 + (GLfloat)g->bitmap.width / cachedFont->getTextureWidth();
GLfloat v0 = 0.0f;
GLfloat v1 = (GLfloat)g->bitmap.rows / cachedFont->getTextureHeight();
std::array<GLfloat, 12> texcoords = {
u0, v0,
u0, v1,
u1, v1,
u0, v0,
u1, v1,
u1, v0
};
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
xoffset += g->bitmap.width;
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
}
glColor4f(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
//Texture parameters are restored when the texture_handle is bound
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
std::vector<std::array<GLfloat, 12>> vertices(text.size());
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
for (int i = 0; i < text.length(); i++) {
float x2, y2, w, h;
CachedGlyph *glyph = cachedFont->getGlyph(text.c_str()[i]);
if (glyph == nullptr) continue;
x2 = x + glyph->x2offset * scale;
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
w = glyph->w * scale;
h = glyph->h * scale;
x += glyph->advanceX * scale;
y += glyph->advanceY * scale;
std::array<GLfloat, 12> glyph_vertices = {
x2, y2,
x2, y2 + h,
x2 + w, y2 + h,
x2, y2,
x2 + w, y2 + h,
x2 + w, y2
};
auto glyph_texcoords = glyph->getTexCoords();
vertices[i] = glyph_vertices;
texcoords[i] = glyph_texcoords;
}
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat) * 2, vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat) * 2, texcoords.data());
glDrawArrays(GL_TRIANGLES, 0, vertices.size() * 6);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(1, 1, 1, 1);
}
void J2D::DrawString(const Color3& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
J2D::DrawString(Color4::FromColor3(color, 255), text, x, y, scale, size, font);
}
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, const Vector3& angle, float scale, u32 size, const Font& font) {
//TODO figure out what the scale should actually be mathematically.
scale = scale * 0.002f;
scale = -scale;
float x = pos.x;
float y = pos.y;
float z = pos.z;
std::vector<GLuint> textures(text.length());
glUseProgram(0); // Fixed-function pipeline.
glColor4ubv(color.ptr());
//Font font;
//for (auto& f : Font::GetLoadedFonts())
//if (f.index == font.index)
//font = f;
if (font.face == NULL) {
std::cout << "null font" << std::endl;
return;
}
FT_Set_Pixel_Sizes(font.face, 0, size);
glPushMatrix();
glTranslatef(x, y, z);
glRotatef(angle.x, 1.0f, 0.0f, 0.0f);
glRotatef(angle.y, 0.0f, 1.0f, 0.0f);
glRotatef(angle.z, 0.0f, 0.0f, 1.0f);
x = 0;
y = 0;
z = 0;
for (int i = 0; i < text.length(); i++)
{
if (FT_Load_Char(font.face, text.c_str()[i], FT_LOAD_RENDER))
continue;
FT_GlyphSlot g = font.face->glyph;
glGenTextures(1, &textures.at(i));
glBindTexture(GL_TEXTURE_2D, textures[i]);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, g->bitmap.width, g->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
float x2 = x + g->bitmap_left * scale;
float y2 = y - g->bitmap_top * scale; // Adjust y-coordinate
float z2 = z;
float w = g->bitmap.width * scale;
float h = g->bitmap.rows * scale;
glBegin(GL_TRIANGLES);
glTexCoord2f(0, 0);
glVertex3f(x2, y2, z2);
glTexCoord2f(0, 1);
glVertex3f(x2, y2 + h, z2);
glTexCoord2f(1, 1);
glVertex3f(x2 + w, y2 + h, z2);
glTexCoord2f(0, 0);
glVertex3f(x2, y2, z2);
glTexCoord2f(1, 1);
glVertex3f(x2 + w, y2 + h, z2);
glTexCoord2f(1, 0);
glVertex3f(x2 + w, y2, z2);
glEnd();
x += (g->advance.x >> 6) * scale;
y += (g->advance.y >> 6) * scale;
}
for (unsigned int& texture : textures)
glDeleteTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture_handle
glColor4f(1, 1, 1, 1);
glPopMatrix();
}
}

216
src/TextRendering.cpp Normal file
View File

@@ -0,0 +1,216 @@
#include <JGL/JGL.h>
#if __linux__
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#if _WIN32
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#endif
#include <JGL/types/Font.h>
#include <JGL/types/FontCache.h>
#include "JGL/logger/logger.h"
namespace JGL {
CachedFont* CacheFont(const Font& font, u32 size) {
CachedFont* cachedFont;
FT_Set_Pixel_Sizes(font.face, 0, size);
jlog::Debug("Caching font data...");
GLuint texture_id;
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
GLsizei width = 0;
GLsizei max_height = 0;
FT_ULong charcode;
FT_UInt gindex;
//We have to loop over the available glyphs twice as we need the
//final width and height of the texture_handle before we can construct it
//and subsequently upload the glyph data.
charcode = FT_Get_First_Char(font.face, &gindex);
//Strings are char-based so we only handle charcodes within the extended ASCII range.
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
width += g->bitmap.width;
max_height = std::max(max_height, (GLsizei) g->bitmap.rows);
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
fontCache.newFont(texture_id, width, max_height, size, font.index);
cachedFont = fontCache.getFont(size, font.index);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, max_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
GLsizei xoffset = 0;
charcode = FT_Get_First_Char(font.face, &gindex);
while (gindex != 0 && charcode < 255) {
if (FT_Load_Char(font.face, charcode, FT_LOAD_RENDER))
std::cout << "Error::FREETYPE: Failed to load charcode: " << charcode << std::endl;
FT_GlyphSlot g = font.face->glyph;
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
GLfloat u0 = (GLfloat)xoffset / cachedFont->getTextureWidth();
GLfloat u1 = u0 + (GLfloat)g->bitmap.width / cachedFont->getTextureWidth();
GLfloat v0 = 0.0f;
GLfloat v1 = (GLfloat)g->bitmap.rows / cachedFont->getTextureHeight();
std::array<GLfloat, 12> texcoords
{
u0, v0,
u0, v1,
u1, v1,
u0, v0,
u1, v1,
u1, v0
};
cachedFont->appendGlyph(new CachedGlyph((char)charcode, texcoords, g->bitmap_left, g->bitmap_top, g->bitmap.width, g->bitmap.rows, (g->advance.x >> 6), (g->advance.y >> 6)));
xoffset += g->bitmap.width;
charcode = FT_Get_Next_Char(font.face, charcode, &gindex);
}
return cachedFont;
}
void J2D::DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font) {
// Offset by height to render at "correct" location.
y += size;
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
jlog::Fatal("Drawing a string with an uninitialized font?");
//If the font doesn't exist in the cache yet.
if (!cachedFont)
cachedFont = CacheFont(font, size);
glColor4ubv(color.ptr());
//Texture parameters are restored when the texture_handle is bound
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
std::vector<std::array<GLfloat, 12>> vertices(text.size());
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
for (int i = 0; i < text.length(); i++) {
float x2, y2, w, h;
CachedGlyph* glyph = cachedFont->getGlyph(text.c_str()[i]);
if (glyph == nullptr)
continue;
x2 = x + glyph->x2offset * scale;
y2 = y - glyph->y2offset * scale; // Adjust y-coordinate
w = glyph->w * scale;
h = glyph->h * scale;
x += glyph->advanceX * scale;
y += glyph->advanceY * scale;
std::array<GLfloat, 12> glyph_vertices
{
x2, y2,
x2, y2 + h,
x2 + w, y2 + h,
x2, y2,
x2 + w, y2 + h,
x2 + w, y2
};
auto glyph_texcoords = glyph->getTexCoords();
vertices[i] = glyph_vertices;
texcoords[i] = glyph_texcoords;
}
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(1, 1, 1, 1);
}
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngle& angle, bool draw_back_face) {
// TODO: Determine the proper scale factor mathematically
scale = scale * 0.002f;
scale = -scale;
float x = pos.x;
float y = pos.y;
float z = pos.z;
CachedFont* cachedFont = fontCache.getFont(size, font.index);
if (font.face == nullptr)
jlog::Fatal("Drawing a string with an uninitialized font?");
if (!cachedFont)
cachedFont = CacheFont(font, size);
glColor4ubv(color.ptr());
glBindTexture(GL_TEXTURE_2D, *cachedFont->getTexture());
std::vector<std::array<GLfloat, 18>> vertices(text.size());
std::vector<std::array<GLfloat, 12>> texcoords(text.size());
glPushMatrix();
glTranslatef(x, y, z);
glRotatef(angle.pitch, 1.0f, 0.0f, 0.0f);
glRotatef(angle.yaw, 0.0f, 1.0f, 0.0f);
glRotatef(angle.roll, 0.0f, 0.0f, 1.0f);
x = y = z = 0;
for (int i = 0; i < text.length(); i++) {
CachedGlyph* glyph = cachedFont->getGlyph(text[i]);
float x2 = x + glyph->x2offset * scale;
float y2 = y - glyph->y2offset * scale;
float w = glyph->w * scale;
float h = glyph->h * scale;
std::array<GLfloat, 18> glyph_vertices
{
x2, y2, z,
x2, y2 + h, z,
x2 + w, y2 + h, z,
x2, y2, z,
x2 + w, y2 + h, z,
x2 + w, y2, z
};
vertices[i] = glyph_vertices;
texcoords[i] = glyph->getTexCoords();
x += glyph->advanceX * scale;
y += glyph->advanceY * scale;
}
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), texcoords.data());
if (!draw_back_face)
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glDrawArrays(GL_TRIANGLES, 0, (int) vertices.size() * 6);
if (!draw_back_face)
glDisable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, 0);
glColor4f(1, 1, 1, 1);
glPopMatrix();
}
}

9
src/logger/logger.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include <JGL/logger/logger.h>
namespace JGL::Logger {
using namespace jlog;
GenericLogger Fatal {"JGL::fatal", GlobalLogFile, Colors::Reds::Crimson, Colors::Gray, Colors::Gray, Colors::Reds::Crimson, Colors::White};
GenericLogger Debug {"JGL::debug", GlobalLogFile, Colors::Purples::Purple, Colors::Gray, Colors::Gray, Colors::Purples::Purple, Colors::White};
GenericLogger Error {"JGL::error", GlobalLogFile, Colors::Red, Colors::Gray, Colors::Gray, Colors::Red, Colors::White};
}

View File

@@ -3,6 +3,7 @@
#include <string>
#include <iostream>
#include <glad/glad.h>
#include <jlog/Logger.hpp>
#if __linux__
#include <freetype2/ft2build.h>
@@ -16,8 +17,8 @@
#include FT_OUTLINE_H
#endif
#include <JGL/Font.h>
#include <JGL/FontCache.h>
#include <JGL/types/Font.h>
#include <JGL/types/FontCache.h>
namespace JGL::Detail
{
@@ -122,6 +123,7 @@ namespace JGL
return extents;
}
jlog::Warning("Measuring a font size that is not cached, This is *super* slow.");
FT_Set_Pixel_Sizes(this->face, ptSize, ptSize);
for (const char& c : text) {

View File

@@ -1,4 +1,4 @@
#include <JGL/FontCache.h>
#include <JGL/types/FontCache.h>
using namespace JGL;
@@ -6,7 +6,7 @@ char CachedGlyph::getCharacter() {
return character;
}
const std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
std::array<GLfloat, 12> CachedGlyph::getTexCoords() const {
return texcoords;
}
@@ -21,9 +21,6 @@ CachedGlyph::CachedGlyph(char c, std::array<GLfloat, 12> texcoords, float x2offs
this->texcoords = texcoords;
}
//TODO
//Because most things shown would be english characters. We can cut down on the iteration time significantly
//by putting each english character at the beginning of the list in order of how often they usually occur in text.
void JGL::CachedFont::appendGlyph(JGL::CachedGlyph* glyph) {
glyphs.emplace(glyph->getCharacter(), glyph);
}
@@ -36,7 +33,6 @@ unsigned int JGL::CachedFont::getFontIndex() {
return font_index;
}
//TODO make this code go faster.
CachedGlyph* JGL::CachedFont::getGlyph(char c) {
auto it = glyphs.find(c);
if (it != glyphs.end())
@@ -52,7 +48,7 @@ CachedFont::CachedFont(GLuint texture_id, GLsizei texture_width, GLsizei texture
this->font_index = font_index;
}
std::map<char, CachedGlyph*> CachedFont::getGlyphs() {
std::unordered_map<char, CachedGlyph*> CachedFont::getGlyphs() {
return glyphs;
}

View File

@@ -0,0 +1,93 @@
#include <JGL/types/RenderTarget.h>
#include <jlog/Logger.hpp>
#include <stdexcept>
JGL::Texture* JGL::RenderTarget::GetJGLTexture() const {
return texture;
}
GLuint JGL::RenderTarget::GetGLTextureHandle() const {
return texture->GetGLTextureHandle();
}
GLuint JGL::RenderTarget::GetGLFramebufferObjectHandle() const {
return framebuffer_object;
}
GLuint JGL::RenderTarget::GetGLDepthBufferHandle() const {
return depth_buffer;
}
GLuint JGL::RenderTarget::GetActiveGLFramebufferHandle() {
GLuint fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &fbo);
return fbo;
}
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);
}
Vector2 JGL::RenderTarget::GetDimensions() const {
return size;
}
void JGL::RenderTarget::Erase() {
if (GetActiveGLFramebufferHandle() == framebuffer_object)
jlog::Warning("Deleting the framebuffer that's currently in use?");
texture->Erase();
if (using_depth)
glDeleteRenderbuffers(1, &depth_buffer);
glDeleteFramebuffers(1, &framebuffer_object);
}
Color4 JGL::RenderTarget::GetClearColor() const {
return clear_color;
}
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth) {
GLuint current_fbo = GetActiveGLFramebufferHandle();
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
unsigned int biggest;
if (size.x >= size.y)
biggest = size.x;
else biggest = size.y;
texture = new Texture(Vector2(biggest, biggest));
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 (use_depth) {
GLuint depthBuffer;
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, biggest, biggest);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
using_depth = true;
}
GLfloat old_clear_color[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
glClearColor(clear_color.RedChannelNormalized(), clear_color.GreenChannelNormalized(), clear_color.BlueChannelNormalized(), clear_color.AlphaChannelNormalized());
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(old_clear_color[0], old_clear_color[1], old_clear_color[2], old_clear_color[3]);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Error " + std::to_string(status) + "while generating framebuffer");
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
this->clear_color = clear_color;
this->size = size;
}

View File

@@ -1,33 +1,63 @@
#include <JGL/Texture.h>
#include <JGL/types/Texture.h>
#include <iostream>
using namespace ReTexture;
namespace JGL
{
Texture::Texture(const std::string &file, const ReTexture::TextureFlag &flags, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode)
Texture::Texture(const std::string& file, const ReTexture::TextureFlag& flags, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode)
{
auto *t = new ReTexture::SoftwareTexture(file, flags);
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode,
wrapping_mode);
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode, wrapping_mode);
texture_flags = flags;
delete t;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
Texture::Texture(const std::string &file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
auto *t = new SoftwareTexture(file);
Texture::Texture(const std::string& file, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
load(t, {(float) t->getWidth(), (float) t->getHeight()}, t->getTextureFormat(), filtering_mode,
wrapping_mode);
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);
}
void Texture::load(SoftwareTexture *software_texture, const Vector2 &size, const TextureFormat &format,
Texture::Texture(const Vector2& size) {
GLuint previous_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*) &previous_texture);
glGenTextures(1, &texture_handle);
glBindTexture(GL_TEXTURE_2D, texture_handle);
//NEAREST
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//Clamp
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int) size.x, (int) size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
texture_format = TextureFormat::RGBA;
texture_size = size;
texture_filtering_mode = TextureFilteringMode::NEAREST;
texture_wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE;
texture_flags = TextureFlag::NONE;
glBindTexture(GL_TEXTURE_2D, previous_texture);
}
void Texture::load(SoftwareTexture* software_texture, const Vector2& size, const TextureFormat& format,
TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode) {
glGenTextures(1, &texture_handle);
glBindTexture(GL_TEXTURE_2D, texture_handle);
@@ -92,22 +122,20 @@ namespace JGL
if (filtering_mode == TextureFilteringMode::MIPMAP_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_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::MIPMAP_BILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST),
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_TRILINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR),
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
delete m1;
delete m2;
delete m3;
}
glBindTexture(GL_TEXTURE_2D, 0);
texture_size = size;
texture_format = format;
texture_filtering_mode = filtering_mode;
@@ -160,4 +188,8 @@ namespace JGL
void Texture::SetTextureHandle(GLuint handle) {
texture_handle = handle;
}
TextureWrappingMode Texture::GetWrappingMode() const {
return texture_wrapping_mode;
}
}

85
src/types/VRamList.cpp Normal file
View File

@@ -0,0 +1,85 @@
#include <JGL/types/VRamList.h>
#include <jlog/Logger.hpp>
#include <cstring>
void JGL::VRamList::load(const GLfloat* data, const long& s) {
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, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, current_array_buffer);
size = s;
}
void JGL::VRamList::load(const GLuint* data, const long& s) {
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, size, data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, current_element_array_buffer);
element_array_buffer = true;
size = s;
}
JGL::VRamList::VRamList(const GLfloat* data, const long& size) {
long data_size = (long) sizeof(GLfloat) * size;
load(data, data_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);
}
void JGL::VRamList::Erase() {
if (list_handle == 0)
jlog::Warning("Erasing an uninitialized array buffer?");
GLint current_element_array_buffer = 0;
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &current_element_array_buffer);
GLint current_array_buffer = 0;
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?");
else if (!element_array_buffer && current_array_buffer == list_handle)
jlog::Warning("Erasing an array buffer while it's in use?");
glDeleteBuffers(1, &list_handle);
}
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::GetDataSize() const {
if (element_array_buffer)
return (long) sizeof(GLuint) * size;
return (long) sizeof(GLfloat) * size;
}