Compare commits
21 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
e8245c4442 | |||
bd918aa351 | |||
a0cc8524d9 | |||
1964aeae86 | |||
b84e2ee2c5 | |||
1597662e2e | |||
0823730e82 | |||
6cbd369d51 | |||
926ae06834 | |||
d5fd68eba8 | |||
08b2dfbecc | |||
e33a51b7d4 | |||
7f5ee5cf0c | |||
401e2c0883 | |||
e5bdc441d1 | |||
392375e56c | |||
b007c78cfe | |||
512dc3cb1a | |||
a22a83d2f8 | |||
76cd48c9b7 | |||
38bb1b22ce |
@@ -17,7 +17,7 @@ include(cmake/CPM.cmake)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME mcolor
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-4.zip
|
||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-5.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
@@ -27,7 +27,7 @@ CPMAddPackage(
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-26.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-31.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
@@ -61,8 +61,8 @@ endif()
|
||||
|
||||
file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||
file(GLOB_RECURSE ASSETS "assets/*")
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp" )
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp" )
|
||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp" "src/internals/*.h")
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
Binary file not shown.
164
assets/models/cone.obj
Normal file
164
assets/models/cone.obj
Normal file
@@ -0,0 +1,164 @@
|
||||
# Blender v3.6.4 OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cone
|
||||
v 0.000000 -1.000000 -1.000000
|
||||
v 0.195090 -1.000000 -0.980785
|
||||
v 0.382683 -1.000000 -0.923880
|
||||
v 0.555570 -1.000000 -0.831470
|
||||
v 0.707107 -1.000000 -0.707107
|
||||
v 0.831470 -1.000000 -0.555570
|
||||
v 0.923880 -1.000000 -0.382683
|
||||
v 0.980785 -1.000000 -0.195090
|
||||
v 1.000000 -1.000000 0.000000
|
||||
v 0.980785 -1.000000 0.195090
|
||||
v 0.923880 -1.000000 0.382683
|
||||
v 0.831470 -1.000000 0.555570
|
||||
v 0.707107 -1.000000 0.707107
|
||||
v 0.555570 -1.000000 0.831470
|
||||
v 0.382683 -1.000000 0.923880
|
||||
v 0.195090 -1.000000 0.980785
|
||||
v 0.000000 -1.000000 1.000000
|
||||
v -0.195090 -1.000000 0.980785
|
||||
v -0.382683 -1.000000 0.923880
|
||||
v -0.555570 -1.000000 0.831470
|
||||
v -0.707107 -1.000000 0.707107
|
||||
v -0.831470 -1.000000 0.555570
|
||||
v -0.923880 -1.000000 0.382683
|
||||
v -0.980785 -1.000000 0.195090
|
||||
v -1.000000 -1.000000 0.000000
|
||||
v -0.980785 -1.000000 -0.195090
|
||||
v -0.923880 -1.000000 -0.382683
|
||||
v -0.831470 -1.000000 -0.555570
|
||||
v -0.707107 -1.000000 -0.707107
|
||||
v -0.555570 -1.000000 -0.831470
|
||||
v -0.382683 -1.000000 -0.923880
|
||||
v -0.195090 -1.000000 -0.980785
|
||||
v 0.000000 1.000000 0.000000
|
||||
vt 0.250000 0.490000
|
||||
vt 0.250000 0.250000
|
||||
vt 0.296822 0.485388
|
||||
vt 0.341844 0.471731
|
||||
vt 0.383337 0.449553
|
||||
vt 0.419706 0.419706
|
||||
vt 0.449553 0.383337
|
||||
vt 0.471731 0.341844
|
||||
vt 0.485388 0.296822
|
||||
vt 0.490000 0.250000
|
||||
vt 0.485388 0.203178
|
||||
vt 0.471731 0.158156
|
||||
vt 0.449553 0.116663
|
||||
vt 0.419706 0.080294
|
||||
vt 0.383337 0.050447
|
||||
vt 0.341844 0.028269
|
||||
vt 0.296822 0.014612
|
||||
vt 0.250000 0.010000
|
||||
vt 0.203178 0.014612
|
||||
vt 0.158156 0.028269
|
||||
vt 0.116663 0.050447
|
||||
vt 0.080294 0.080294
|
||||
vt 0.050447 0.116663
|
||||
vt 0.028269 0.158156
|
||||
vt 0.014612 0.203178
|
||||
vt 0.010000 0.250000
|
||||
vt 0.014612 0.296822
|
||||
vt 0.028269 0.341844
|
||||
vt 0.050447 0.383337
|
||||
vt 0.080294 0.419706
|
||||
vt 0.116663 0.449553
|
||||
vt 0.158156 0.471731
|
||||
vt 0.796822 0.014612
|
||||
vt 0.514612 0.203178
|
||||
vt 0.703178 0.485388
|
||||
vt 0.203178 0.485388
|
||||
vt 0.750000 0.490000
|
||||
vt 0.796822 0.485388
|
||||
vt 0.841844 0.471731
|
||||
vt 0.883337 0.449553
|
||||
vt 0.919706 0.419706
|
||||
vt 0.949553 0.383337
|
||||
vt 0.971731 0.341844
|
||||
vt 0.985388 0.296822
|
||||
vt 0.990000 0.250000
|
||||
vt 0.985388 0.203178
|
||||
vt 0.971731 0.158156
|
||||
vt 0.949553 0.116663
|
||||
vt 0.919706 0.080294
|
||||
vt 0.883337 0.050447
|
||||
vt 0.841844 0.028269
|
||||
vt 0.750000 0.010000
|
||||
vt 0.703178 0.014612
|
||||
vt 0.658156 0.028269
|
||||
vt 0.616663 0.050447
|
||||
vt 0.580294 0.080294
|
||||
vt 0.550447 0.116663
|
||||
vt 0.528269 0.158156
|
||||
vt 0.510000 0.250000
|
||||
vt 0.514612 0.296822
|
||||
vt 0.528269 0.341844
|
||||
vt 0.550447 0.383337
|
||||
vt 0.580294 0.419706
|
||||
vt 0.616663 0.449553
|
||||
vt 0.658156 0.471731
|
||||
s off
|
||||
f 1/1 33/2 2/3
|
||||
f 2/3 33/2 3/4
|
||||
f 3/4 33/2 4/5
|
||||
f 4/5 33/2 5/6
|
||||
f 5/6 33/2 6/7
|
||||
f 6/7 33/2 7/8
|
||||
f 7/8 33/2 8/9
|
||||
f 8/9 33/2 9/10
|
||||
f 9/10 33/2 10/11
|
||||
f 10/11 33/2 11/12
|
||||
f 11/12 33/2 12/13
|
||||
f 12/13 33/2 13/14
|
||||
f 13/14 33/2 14/15
|
||||
f 14/15 33/2 15/16
|
||||
f 15/16 33/2 16/17
|
||||
f 16/17 33/2 17/18
|
||||
f 17/18 33/2 18/19
|
||||
f 18/19 33/2 19/20
|
||||
f 19/20 33/2 20/21
|
||||
f 20/21 33/2 21/22
|
||||
f 21/22 33/2 22/23
|
||||
f 22/23 33/2 23/24
|
||||
f 23/24 33/2 24/25
|
||||
f 24/25 33/2 25/26
|
||||
f 25/26 33/2 26/27
|
||||
f 26/27 33/2 27/28
|
||||
f 27/28 33/2 28/29
|
||||
f 28/29 33/2 29/30
|
||||
f 29/30 33/2 30/31
|
||||
f 30/31 33/2 31/32
|
||||
f 16/33 24/34 32/35
|
||||
f 31/32 33/2 32/36
|
||||
f 32/36 33/2 1/1
|
||||
f 32/35 1/37 2/38
|
||||
f 2/38 3/39 4/40
|
||||
f 4/40 5/41 6/42
|
||||
f 6/42 7/43 8/44
|
||||
f 8/44 9/45 10/46
|
||||
f 10/46 11/47 12/48
|
||||
f 12/48 13/49 14/50
|
||||
f 14/50 15/51 16/33
|
||||
f 16/33 17/52 18/53
|
||||
f 18/53 19/54 20/55
|
||||
f 20/55 21/56 22/57
|
||||
f 22/57 23/58 24/34
|
||||
f 24/34 25/59 26/60
|
||||
f 26/60 27/61 28/62
|
||||
f 28/62 29/63 30/64
|
||||
f 30/64 31/65 32/35
|
||||
f 32/35 2/38 8/44
|
||||
f 2/38 4/40 8/44
|
||||
f 4/40 6/42 8/44
|
||||
f 8/44 10/46 16/33
|
||||
f 10/46 12/48 16/33
|
||||
f 12/48 14/50 16/33
|
||||
f 16/33 18/53 24/34
|
||||
f 18/53 20/55 24/34
|
||||
f 20/55 22/57 24/34
|
||||
f 24/34 26/60 32/35
|
||||
f 26/60 28/62 32/35
|
||||
f 28/62 30/64 32/35
|
||||
f 32/35 8/44 16/33
|
46
assets/models/cube.amo
Normal file
46
assets/models/cube.amo
Normal file
@@ -0,0 +1,46 @@
|
||||
ao Cube 1
|
||||
v 8
|
||||
1.000000 1.000000 1.000000
|
||||
1.000000 1.000000 -1.000000
|
||||
1.000000 -1.000000 1.000000
|
||||
1.000000 -1.000000 -1.000000
|
||||
-1.000000 1.000000 1.000000
|
||||
-1.000000 1.000000 -1.000000
|
||||
-1.000000 -1.000000 1.000000
|
||||
-1.000000 -1.000000 -1.000000
|
||||
vt 14
|
||||
0.625000 0.500000
|
||||
0.875000 0.500000
|
||||
0.875000 0.750000
|
||||
0.625000 0.750000
|
||||
0.375000 0.750000
|
||||
0.625000 1.000000
|
||||
0.375000 1.000000
|
||||
0.375000 0.000000
|
||||
0.625000 0.000000
|
||||
0.625000 0.250000
|
||||
0.375000 0.250000
|
||||
0.125000 0.500000
|
||||
0.375000 0.500000
|
||||
0.125000 0.750000
|
||||
vn 6
|
||||
0.000000 0.000000 1.000000
|
||||
0.000000 -1.000000 0.000000
|
||||
-1.000000 0.000000 0.000000
|
||||
0.000000 0.000000 -1.000000
|
||||
1.000000 0.000000 0.000000
|
||||
0.000000 1.000000 0.000000
|
||||
f 12
|
||||
2 0 0 0 1 0 4 2 0
|
||||
7 3 1 3 4 1 2 3 1
|
||||
5 5 2 7 6 2 6 7 2
|
||||
7 8 3 5 9 3 1 10 3
|
||||
3 11 4 1 12 4 0 4 4
|
||||
1 13 5 5 12 5 4 0 5
|
||||
2 0 0 4 1 0 6 2 0
|
||||
7 3 1 2 4 1 6 3 1
|
||||
5 5 2 6 6 2 4 7 2
|
||||
7 8 3 1 9 3 3 10 3
|
||||
3 11 4 0 12 4 2 4 4
|
||||
1 13 5 4 12 5 0 0 5
|
||||
end
|
38
assets/models/cube.obj
Normal file
38
assets/models/cube.obj
Normal file
@@ -0,0 +1,38 @@
|
||||
# Blender v3.6.4 OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cube
|
||||
v 1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 1.000000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.875000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
s off
|
||||
f 5/1 3/2 1/3
|
||||
f 3/2 8/4 4/5
|
||||
f 7/6 6/7 8/8
|
||||
f 2/9 8/10 6/11
|
||||
f 1/3 4/5 2/9
|
||||
f 5/12 2/9 6/7
|
||||
f 5/1 7/13 3/2
|
||||
f 3/2 7/14 8/4
|
||||
f 7/6 5/12 6/7
|
||||
f 2/9 4/5 8/10
|
||||
f 1/3 3/2 4/5
|
||||
f 5/12 1/3 2/9
|
@@ -26,29 +26,44 @@
|
||||
#include <J3ML/Geometry/Sphere.hpp>
|
||||
#include <J3ML/Geometry/Capsule.hpp>
|
||||
#include <J3ML/Geometry/Triangle2D.hpp>
|
||||
#include <J3ML/J3ML.hpp>
|
||||
#include <JGL/types/Font.h>
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
|
||||
// Fonts that are included by default.
|
||||
namespace JGL::Fonts {
|
||||
void Init();
|
||||
// Built in fonts.
|
||||
inline Font Jupiteroid;
|
||||
}
|
||||
|
||||
// Simple shapes that are pre-computed and used in some draw functions.
|
||||
namespace JGL::ShapeCache {
|
||||
inline VRamList* cube_vertex_data = nullptr;
|
||||
inline VRamList* cube_index_data = nullptr;
|
||||
inline VRamList* cube_normal_data = nullptr;
|
||||
// Facing straight out.
|
||||
inline VRamList* j2d_default_normal_data = nullptr;
|
||||
void Init();
|
||||
}
|
||||
|
||||
/// OpenGL Wrapper for rendering 2D & 3D graphics in both a 2D and 3D context.
|
||||
namespace JGL {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
using namespace J3ML::Geometry;
|
||||
|
||||
|
||||
[[nodiscard]] bool Init(const Vector2& window_size, float fovY, float far_plane);
|
||||
|
||||
/// @param window_size
|
||||
void Update(const Vector2& window_size);
|
||||
|
||||
inline void PurgeFontCache() { JGL::fontCache.purgeCache(); }
|
||||
|
||||
|
||||
std::array<GLfloat, 16> OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far);
|
||||
|
||||
/// Returns true if the graphics driver meets the requirements (GL Version & Extensions).
|
||||
/// @returns true if the graphics driver meets the requirements (GL Version & Extensions).
|
||||
bool MeetsRequirements();
|
||||
/// Drawing functions for primitive 2D Shapes.
|
||||
}
|
||||
|
||||
/// Drawing functions for 2D objects.
|
||||
namespace JGL::J2D {
|
||||
/// 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.
|
||||
@@ -64,7 +79,10 @@ namespace JGL::J2D {
|
||||
|
||||
/// Provide a list of lights to be used in 2D space. Typically directly after J2D::Begin();
|
||||
/// 8 lights maximum for now. Some kind of light sorting will eventually be needed per j2d element.
|
||||
void LightArray(LightBase*, size_t light_count);
|
||||
void OptionalLights(const LightBase** lights, const size_t& light_count);
|
||||
|
||||
/// Specifies a light which is required for every object in the scene.
|
||||
void RequiredLight(const LightBase* light);
|
||||
|
||||
/// Plots a single pixel on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -88,6 +106,13 @@ namespace JGL::J2D {
|
||||
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);
|
||||
|
||||
/// Plots several line segments defined by a series of points to be connected together.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param points pointer to the first point in the list.
|
||||
/// @param point_count the number of points to draw.
|
||||
/// @param thickness The width at which to render the line.
|
||||
void DrawLines(const Color4& color, const Vector2* points, const size_t& point_count, float thickness = 1);
|
||||
|
||||
/// Plots a line segment using a series of points separated by a given distance.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
/// @param A The starting point of the line segment.
|
||||
@@ -336,7 +361,7 @@ namespace JGL::J2D {
|
||||
/// @param scale The value (in both axes) to scale the text by. Defaults to {1,1}.
|
||||
/// @param size The point-size at which to render the font out. Re-using the same point-size allows efficient glyph caching.
|
||||
/// @param font The font to use for rendering. @see Font.
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font);
|
||||
void DrawString(const Color4& color, const std::string& text, float x, float y, float scale, u32 size, const Font& font = Fonts::Jupiteroid);
|
||||
|
||||
|
||||
/// Draws an Arc (section of a circle) to the screen.
|
||||
@@ -357,7 +382,7 @@ namespace JGL::J2D {
|
||||
void FillEllipse(const Color4& color, const Vector2& position, float radius_x, float radius_y, int subdivisions = 8);
|
||||
}
|
||||
|
||||
/// Drawing functions for primitive 3D Shapes.
|
||||
/// Drawing functions for 3D objects.
|
||||
namespace JGL::J3D {
|
||||
/// A light for this 3D render that should never be culled out. up-to 8.
|
||||
/// The more you put here, The less we will solve for if you're also using LightArray.
|
||||
@@ -365,7 +390,7 @@ namespace JGL::J3D {
|
||||
void RequiredLight(const LightBase* light);
|
||||
|
||||
/// When each 3D object is drawn, We'll do our best to determine which lights would effect it the most and use those ones.
|
||||
void LightArray(const LightBase** lights, const size_t& light_count);
|
||||
void OptionalLights(const LightBase** lights, const size_t& light_count);
|
||||
|
||||
/// Helper function to conveniently change the Field-Of-View.
|
||||
void ChangeFOV(float fov);
|
||||
@@ -374,10 +399,9 @@ namespace JGL::J3D {
|
||||
void ChangeFarPlane(float far_plane);
|
||||
|
||||
/// Open a 3-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 3D context to render your content, then close when completed.
|
||||
/// This keeps our code from, say, clobbering the OpenGL rendering context driving 2D content in between our calls.
|
||||
void Begin();
|
||||
/// @param two_pass Whether or not we'll use two-pass rendering for occlusion.
|
||||
void Begin(bool two_pass = false);
|
||||
|
||||
/// Closes a 3-D rendering context with the underlying graphics system (In this case& by default OpenGL).
|
||||
/// @see Begin().
|
||||
@@ -652,8 +676,9 @@ namespace JGL::J3D {
|
||||
/// @param font The font object to use when drawing.
|
||||
/// @param angle The orientation in 3D space.
|
||||
/// @param draw_back_face
|
||||
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
|
||||
void DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font = Fonts::Jupiteroid, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
|
||||
|
||||
void DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position);
|
||||
/// Draws a string of text in 3D space that is always facing the exact direction of the camera projection.
|
||||
void DrawBillboardString();
|
||||
|
||||
|
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <JGL/types/VRamList.h>
|
||||
#include <array>
|
||||
|
||||
namespace JGL::ShapeCache {
|
||||
inline VRamList* cube_vertex_data = nullptr;
|
||||
inline VRamList* cube_index_data = nullptr;
|
||||
void Init();
|
||||
}
|
@@ -13,8 +13,6 @@ extern "C" typedef struct FT_LibraryRec_* FT_Library;
|
||||
|
||||
namespace JGL
|
||||
{
|
||||
|
||||
//bool Init();
|
||||
bool InitTextEngine();
|
||||
|
||||
/// A Font class implementation.
|
||||
@@ -23,7 +21,8 @@ namespace JGL
|
||||
public:
|
||||
/// Default constructor does not initialize any members
|
||||
Font() = default;
|
||||
Font(const std::filesystem::path& path);
|
||||
explicit Font(const std::filesystem::path& path);
|
||||
Font(const unsigned char* data, const size_t& size);
|
||||
/// Destructor handles freeing of the underlying asset handle.
|
||||
~Font();
|
||||
static Font LoadTTF(const std::filesystem::path& filepath);
|
||||
@@ -35,6 +34,6 @@ namespace JGL
|
||||
Vector2 MeasureString(const std::string& text, unsigned int ptSize);
|
||||
public:
|
||||
int index = 0;
|
||||
FT_Face face;
|
||||
FT_Face face = nullptr;
|
||||
};
|
||||
}
|
@@ -11,18 +11,22 @@ namespace JGL {
|
||||
class SpotLight;
|
||||
}
|
||||
|
||||
// TODO this can be consolidated.
|
||||
class JGL::LightBase {
|
||||
protected:
|
||||
/* The 4th number represents whether the light is a positional light.
|
||||
* In OpenGL, You can have positional lights, Like Point Lights or Spot Lights,
|
||||
* Or global lights, Like the sun. */
|
||||
Vector4 position = {0, 0, 0, 1};
|
||||
Color4 ambient = {0, 0, 0, 0};
|
||||
Color4 diffuse = {0, 0, 0, 0};
|
||||
Color4 specular = {0, 0, 0, 0};
|
||||
|
||||
float constant_attenuation;
|
||||
float linear_attenuation;
|
||||
float quadratic_attenuation;
|
||||
float constant_attenuation = 1;
|
||||
float linear_attenuation = 0;
|
||||
float quadratic_attenuation = 0;
|
||||
public:
|
||||
[[nodiscard]] Vector3 GetPosition() const;
|
||||
[[nodiscard]] Vector4 GetPosition() const;
|
||||
[[nodiscard]] Color4 GetAmbient() const;
|
||||
[[nodiscard]] Color4 GetDiffuse() const;
|
||||
[[nodiscard]] Color4 GetSpecular() const;
|
||||
@@ -41,12 +45,13 @@ public:
|
||||
/// Omni-directional lights.
|
||||
class JGL::PointLight : public LightBase {
|
||||
public:
|
||||
[[nodiscard]] float GetAttenuationAtPosition(const Vector3& pos) const override;
|
||||
[[nodiscard]] float GetAttenuationAtPosition(const Vector3& pos) const final;
|
||||
public:
|
||||
PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
|
||||
};
|
||||
|
||||
/// Lights which only effect things in a given cone.
|
||||
// TODO get attenuation at position for this.
|
||||
class JGL::SpotLight : public LightBase {
|
||||
protected:
|
||||
Matrix3x3 orientation;
|
||||
|
@@ -1,4 +1,19 @@
|
||||
/// A simple wrapper for OpenGL materials. Lets you set things such as the "shininess" of your elements.
|
||||
class Material {
|
||||
|
||||
#include <Color4.hpp>
|
||||
#include <glad/glad.h>
|
||||
namespace JGL {
|
||||
class Material;
|
||||
}
|
||||
class JGL::Material {
|
||||
public:
|
||||
Color4 ambient_ref;
|
||||
Color4 diffuse_ref;
|
||||
Color4 specular_ref;
|
||||
Color4 emission;
|
||||
float shininess;
|
||||
public:
|
||||
Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine);
|
||||
/// @param material Material to use.
|
||||
static void SetActiveMaterial(const Material& material);
|
||||
};
|
@@ -1,20 +1,21 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include <Color4.hpp>
|
||||
#include <Colors.hpp>
|
||||
#include <JGL/types/Enums.h>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class RenderTarget;
|
||||
class Texture; // Forward declare.
|
||||
class Texture;
|
||||
}
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2i;
|
||||
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};
|
||||
Vector2i size{0, 0};
|
||||
bool using_depth = false;
|
||||
bool texture_created_by_us = false;
|
||||
GLuint framebuffer_object = 0;
|
||||
@@ -26,47 +27,97 @@ private:
|
||||
GLuint msaa_render_buffer = 0;
|
||||
void Erase();
|
||||
public:
|
||||
/// @returns The Render Target currently in use by OpenGL.
|
||||
/// @note Zero is the screen.
|
||||
static GLuint GetActiveGLFramebufferHandle();
|
||||
|
||||
/// Changes the Render Target that OpenGL will draw on.
|
||||
/// @param render_target The new Render Target for OpenGL to draw on.
|
||||
static void SetActiveGLRenderTarget(const RenderTarget& render_target);
|
||||
|
||||
/** Change the size of the renderable area of the Render Target. **/
|
||||
/// @param new_size new size in px.
|
||||
void Resize(const Vector2& new_size);
|
||||
void SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
/// If you're using raw OpenGL commands to draw to this outside of J2D or J3D don't forget to do this.
|
||||
/// Blits the MSAA FBO onto the regular FBO if MSAA is enabled and or If you're rendering to a texture which uses mipmaps,
|
||||
/// It regenerates them so what you drew doesn't disappear at a distance. Otherwise it does nothing.
|
||||
void Blit() const;
|
||||
/// Changes the size of the renderable area of this Render Target.
|
||||
/// @param new_size new width & height in pixels.
|
||||
/// @note The data stored in this Render Target will be lost.
|
||||
void Resize(const Vector2i& new_size);
|
||||
|
||||
/// Blit a render target onto another. Will break if they're not the same size.
|
||||
static void Blit(const RenderTarget& source, RenderTarget* destination);
|
||||
/// Sets the MSAA mode for this Render Target.
|
||||
/// @returns false if the mode isn't available, true for success.
|
||||
[[nodiscard]] bool SetMSAAEnabled(MSAA_SAMPLE_RATE sample_rate);
|
||||
|
||||
/// Blit a single pixel onto a Render Target.
|
||||
/// If you're using MSAA and not using J2D || J3D Begin & End you must do this.
|
||||
void MSAABlit() const;
|
||||
|
||||
/// Copy one Render Target onto another. Will break if they're not the same size.
|
||||
// TODO support different sizes. If the destination is too small fix it for them but log a warning.
|
||||
static void Blit(const RenderTarget& source, RenderTarget* destination, const Vector2i& position = {0, 0});
|
||||
|
||||
/// Plots a single pixel onto a Render Target.
|
||||
/// @param color The color to render.
|
||||
/// @param position The position in the destination to draw the pixel.
|
||||
/// @param destination The destination RenderTarget.
|
||||
static void Blit(const Color4& color, const Vector2& position, RenderTarget* destination);
|
||||
[[nodiscard]] bool TextureCreatedByRenderTarget() const;
|
||||
static void Blit(const Color4& color, const Vector2i& position, RenderTarget* destination);
|
||||
|
||||
/// Blit an input texture onto this render target at the given position.
|
||||
/// @param source Source texture.
|
||||
/// @param destination Render Target to draw on.
|
||||
/// @param position Where in the destination to draw.
|
||||
static void Blit(const Texture* source, RenderTarget* destination, const Vector2i& position = {0, 0});
|
||||
|
||||
/// @returns Whether or not this Render Target created it's Texture.
|
||||
[[nodiscard]] bool OwnsTexture() const;
|
||||
public:
|
||||
[[nodiscard]] Vector2 GetDimensions() const;
|
||||
/// @returns the size of the renderable area.
|
||||
[[nodiscard]] Vector2i GetDimensions() const;
|
||||
|
||||
/// @returns The currently selected MSAA Sample Rate.
|
||||
[[nodiscard]] MSAA_SAMPLE_RATE GetMSAASampleRate() const;
|
||||
/// Returns whether or not MSAA is enabled, If it is and you're not using J2D || J3D Begin / End,
|
||||
/// You need to run "Blit()" after rendering to your FBO before you show it.
|
||||
/// @note Also, If the texture wasn't made by the RenderTarget you don't want this. It would destroy the texture.
|
||||
|
||||
/// @returns Whether or not this Render Target is using MSAA.
|
||||
[[nodiscard]] bool MSAAEnabled() const;
|
||||
|
||||
/// @returns The JGL texture this Render Target draws on.
|
||||
[[nodiscard]] const Texture* GetJGLTexture() const;
|
||||
|
||||
/// @returns The OpenGL handle for the texture this Render Target draws on.
|
||||
[[nodiscard]] GLuint GetGLTextureHandle() const;
|
||||
|
||||
/// @returns The OpenGL handle for this Render Target.
|
||||
[[nodiscard]] GLuint GetGLFramebufferObjectHandle() const;
|
||||
|
||||
/// @returns The handle to the OpenGL buffer containing depth information
|
||||
/// @note Only valid if this Render Target is being used for 3D.
|
||||
[[nodiscard]] GLuint GetGLDepthBufferHandle() const;
|
||||
|
||||
/// @returns The color that should be used to clear this Render Target.
|
||||
[[nodiscard]] Color4 GetClearColor() const;
|
||||
/// Get the data back from the FBO. This is *not* async friendly.
|
||||
[[nodiscard]] std::vector<GLfloat> GetData() const;
|
||||
|
||||
|
||||
/// @returns The color information for this Render Target.
|
||||
/// @note Both the CPU & GPU cannot do anything while this takes place. It's very slow.
|
||||
[[nodiscard]] std::vector<GLfloat> GetPixels() const;
|
||||
public:
|
||||
/// Copy constructor. Will always set "texture_created_by_us" to true and use our own texture to avoid memleaks.
|
||||
/// Create a Render Target from a Render Target that already exists.
|
||||
/** @note Render Targets that are copies of another will copy the Texture.
|
||||
* This is so that deleting the copy doesn't delete the Texture of the original.
|
||||
*/
|
||||
RenderTarget(const RenderTarget& rhs);
|
||||
/// Create a render target for a texture that already exists. For adding to an existing texture.
|
||||
explicit RenderTarget(const Texture* texture, const Color4& clear_color = Colors::Black);
|
||||
/// Create a Render Target with a brand new texture. Want to render JGL elements onto a texture and display it as a sprite?
|
||||
explicit RenderTarget(const Vector2& size, const Color4& clear_color = Colors::Black, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
|
||||
/// Create a Render Target for a texture that already exists.
|
||||
/// @param texture The Texture that using this Render Target would draw on.
|
||||
/// @param clear_color The color to be used if you want to clear the Render Target.
|
||||
/// @note For Render Targets created this way, The destructor will not delete the texture.
|
||||
explicit RenderTarget(const Texture* texture, const Color4& clear_color = Colors::Transparent);
|
||||
|
||||
/// Create a Render Target with a new texture.
|
||||
/// @param size The width & height the Render Target should have.
|
||||
/// @param clear_color The color to be used if you want to clear the Render Target.
|
||||
/// @param use_depth Whether or not this Render Target will have depth information.
|
||||
/// @param sample_rate The MSAA sample rate this Render Target will use.
|
||||
explicit RenderTarget(const Vector2i& size, const Color4& clear_color = Colors::Transparent, bool use_depth = false, MSAA_SAMPLE_RATE sample_rate = MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
|
||||
/// Deletes this Render Target.
|
||||
/** @note If this Render Target was made with a Texture that already existed
|
||||
* the Texture will not be deleted. */
|
||||
~RenderTarget();
|
||||
|
||||
};
|
@@ -8,19 +8,19 @@
|
||||
namespace JGL {
|
||||
using namespace ReImage;
|
||||
enum class TextureFilteringMode : u8 {
|
||||
NEAREST = 0, //Fastest for 2D, Sometimes causes graphical issues.
|
||||
BILINEAR = 1, //Fast and pretty, The best for 2D.
|
||||
NEAREST = 0, // Fastest for 2D, Sometimes causes graphical issues.
|
||||
BILINEAR = 1, // Fast and pretty, The best for 2D.
|
||||
|
||||
MIPMAP_NEAREST = 2, //Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
|
||||
MIPMAP_BILINEAR = 3, //Bilinear with mipmaps, Fast and pretty. Uses more vram.
|
||||
MIPMAP_TRILINEAR = 4 //The prettiest. Still decent speed. Uses more vram.
|
||||
MIPMAP_NEAREST = 2, // Nearest with mipmaps. The fastest for 3D, Sometimes causes graphical issues. Uses more vram.
|
||||
MIPMAP_BILINEAR = 3, // Bilinear with mipmaps, Fast and pretty. Uses more vram.
|
||||
MIPMAP_TRILINEAR = 4 // The prettiest. Still decent speed. Uses more vram.
|
||||
};
|
||||
|
||||
enum class TextureWrappingMode : u8 {
|
||||
REPEAT = 0,
|
||||
MIRRORED_REPEAT = 1,
|
||||
CLAMP_TO_EDGE = 2,
|
||||
CLAMP_TO_BORDER = 3 //Effectively the same as clamp_to_edge
|
||||
CLAMP_TO_BORDER = 3 // Effectively the same as clamp_to_edge
|
||||
};
|
||||
|
||||
/// Represents texture data loaded on the GPU. Contains a handle that can be passed to OpenGL draw calls.
|
||||
@@ -39,6 +39,8 @@ namespace JGL {
|
||||
/// Load a texture from a file,
|
||||
explicit Texture(const std::string& file, TextureFilteringMode filtering_mode = TextureFilteringMode::BILINEAR, TextureWrappingMode wrapping_mode = TextureWrappingMode::CLAMP_TO_EDGE, const TextureFlag& flags = TextureFlag::INVERT_Y);
|
||||
Texture(Image* software_texture, const Vector2& size, const TextureFormat& format, TextureFilteringMode filtering_mode, TextureWrappingMode wrapping_mode);
|
||||
// Texture atlas.
|
||||
Texture(const Texture* textures, const size_t& texture_count);
|
||||
/* Initialize a texture filled with trash data
|
||||
this is primarily for the RenderTarget */
|
||||
explicit Texture(const Vector2& size);
|
||||
|
@@ -34,7 +34,7 @@ public:
|
||||
/** Copying around the VBO data to a new VBO like this is slow.
|
||||
* Pass to function by const reference or pointer always. */
|
||||
VRamList(const VRamList& rhs);
|
||||
VRamList() = default;
|
||||
VRamList() : list_handle(0), num_elements(0), element_array_buffer(false), spin_lock(false) {}
|
||||
public:
|
||||
[[nodiscard]] GLuint GetHandle() const;
|
||||
/// Returns the number of elements in the list.
|
||||
|
@@ -29,10 +29,10 @@ protected:
|
||||
protected:
|
||||
std::vector<Animation> animations{};
|
||||
protected:
|
||||
VRamList vertices;
|
||||
VRamList indices;
|
||||
VRamList normals;
|
||||
VRamList texture_coordinates;
|
||||
VRamList* vertices;
|
||||
VRamList* indices;
|
||||
VRamList* normals;
|
||||
VRamList* texture_coordinates;
|
||||
protected:
|
||||
/** For models which are not animated, This is intended for a low quality version in
|
||||
* system memory for calculations to be done on the CPU. For models that are, the default pose of the model is here.
|
||||
@@ -43,10 +43,10 @@ protected:
|
||||
std::vector<Normal> local_normals{};
|
||||
public:
|
||||
/** Don't use these for anything other than drawing because the GPU is gonna spin during read-back */
|
||||
[[nodiscard]] VRamList GetVertices() const;
|
||||
[[nodiscard]] VRamList GetIndices() const;
|
||||
[[nodiscard]] VRamList GetNormals() const;
|
||||
[[nodiscard]] VRamList GetTextureCoordinates() const;
|
||||
[[nodiscard]] const VRamList* GetVertices() const;
|
||||
[[nodiscard]] const VRamList* GetIndices() const;
|
||||
[[nodiscard]] const VRamList* GetNormals() const;
|
||||
[[nodiscard]] const VRamList* GetTextureCoordinates() const;
|
||||
|
||||
/** These are for cpu side calculations */
|
||||
[[nodiscard]] std::vector<Vertex> GetLocalVertices() const;
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
[[nodiscard]] AABB GetMEAABB(const Matrix3x3& rotation_matrix, const Vector3& scale = Vector3::One, const Vector3& translate_part = Vector3::Zero) const;
|
||||
[[nodiscard]] AABB GetMEAABB(const Matrix4x4& instance_matrix, bool translate = false) const;
|
||||
public:
|
||||
VertexArray() = default;
|
||||
/// Vertices are required, Everything else is optional.
|
||||
VertexArray(const Vertex* vertex_positions, const long& vp_length, const unsigned int* vertex_indices = nullptr, const long& vi_length = 0,
|
||||
const Normal* vertex_normals = nullptr, const long& vn_length = 0, const TextureCoordinate* texture_coordinates = nullptr, const long& vt_length = 0);
|
||||
@@ -90,9 +91,13 @@ public:
|
||||
/// Vertices are required, Everything else is optional.
|
||||
explicit VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices = {},
|
||||
const std::vector<Normal>& vertex_normals = {}, const std::vector<TextureCoordinate>& texture_coordinates = {});
|
||||
|
||||
static VertexArray LoadWavefrontOBJ(const std::string& file_text);
|
||||
static VertexArray LoadAMO(const std::string& file_text);
|
||||
};
|
||||
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
static VertexArray Animate(int animation_id, float animation_time);
|
||||
static VertexArray Animate(const AnimationState& anim_state);
|
||||
|
||||
|
79
main.cpp
79
main.cpp
@@ -5,14 +5,16 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <rewindow/logger/logger.h>
|
||||
#include <JGL/types/VertexArray.h>
|
||||
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using namespace JGL::Fonts;
|
||||
using namespace JGL;
|
||||
|
||||
JGL::Font FreeSans;
|
||||
JGL::Font Jupiteroid;
|
||||
float fps = 0.0f;
|
||||
|
||||
/// A draggable 2D point that highlights when moused over and when clicked.
|
||||
class Gizmo
|
||||
{
|
||||
public:
|
||||
@@ -22,6 +24,15 @@ public:
|
||||
bool hovered = false;
|
||||
Vector2 position;
|
||||
float range = 6.f;
|
||||
float base_radius = 3.f;
|
||||
float hover_radius = 6.f;
|
||||
float drag_radius = 4.f;
|
||||
Color4 base_color = Colors::Reds::Salmon;
|
||||
Color4 hover_color = Colors::Reds::Firebrick;
|
||||
Color4 drag_color = Colors::White;
|
||||
float lerp_rate = 0.25f;
|
||||
float text_scale = 1.f;
|
||||
int text_size = 12;
|
||||
|
||||
void Grab() {
|
||||
if (hovered)
|
||||
@@ -33,27 +44,25 @@ public:
|
||||
|
||||
void Update(const Vector2& mouse) {
|
||||
if (dragging)
|
||||
position = position.Lerp(mouse, 0.25f);
|
||||
position = position.Lerp(mouse, lerp_rate);
|
||||
|
||||
hovered = mouse.Distance(position) < range;
|
||||
}
|
||||
|
||||
void Draw() {
|
||||
|
||||
|
||||
if (dragging)
|
||||
J2D::DrawPoint(Colors::White, position, 4.f);
|
||||
J2D::DrawPoint(drag_color, position, drag_radius);
|
||||
else if (hovered)
|
||||
J2D::DrawPoint(Colors::Reds::Crimson, position, 6.f);
|
||||
J2D::DrawPoint(hover_color, position, hover_radius);
|
||||
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);
|
||||
J2D::DrawPoint(base_color, position, base_radius);
|
||||
|
||||
J2D::DrawString(Colors::White, std::format("{:.1f},{:.1f}", position.x, position.y), position.x, position.y, text_scale, text_size);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/// A 3D Camera Controller.
|
||||
class Camera {
|
||||
public:
|
||||
Vector3 position = {0,0,0};
|
||||
@@ -97,6 +106,7 @@ Gizmo b({200, 250});
|
||||
Gizmo c({350, 300});
|
||||
Gizmo d({450, 250});
|
||||
|
||||
JGL::Font FreeSans;
|
||||
Texture* image;
|
||||
Texture* image_mask;
|
||||
RenderTarget* j2d_render_target;
|
||||
@@ -110,8 +120,8 @@ public:
|
||||
if (!JGL::Init(GetSize(), 75, 100))
|
||||
Logger::Fatal("Initialization failed.");
|
||||
|
||||
// Load a custom font.
|
||||
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||
Jupiteroid = JGL::Font("assets/fonts/Jupiteroid.ttf");
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
@@ -126,13 +136,15 @@ public:
|
||||
|
||||
EulerAngleXYZ textAngle = {0,0,0};
|
||||
float fov = 90;
|
||||
u8 pulse = 0;
|
||||
float sprite_radians = 0;
|
||||
bool fov_increasing = true;
|
||||
int blit_pos = 0;
|
||||
|
||||
void display() {
|
||||
pulse++;
|
||||
float dt = GetDeltaTime();
|
||||
|
||||
float dt = 1.f / fps;
|
||||
JGL::Update(GetSize());
|
||||
|
||||
if (fov_increasing)
|
||||
@@ -155,7 +167,7 @@ public:
|
||||
camera->render();
|
||||
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
|
||||
/* if rendering to screen space directly. */
|
||||
|
||||
auto test_light = PointLight({2,1,2}, {pulse,pulse,pulse, 255}, {pulse, pulse, pulse, 255}, {0,0,0}, 1, 0.1, 0.01);
|
||||
// If a 3D object has transparency. The things you'd like to see through it must be drawn before.
|
||||
J3D::Begin();
|
||||
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-1,-0.125,1});
|
||||
@@ -163,8 +175,9 @@ public:
|
||||
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
|
||||
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
|
||||
Sphere sphere = {{0,0, 0.5f}, 0.2125};
|
||||
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 16, 16, true);
|
||||
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.1f, 0.1f, 0.1f});
|
||||
J3D::BatchWireframeRevoSphere(Colors::Green, &sphere, 1, 1, 8, 8, true);
|
||||
J3D::RequiredLight(&test_light);
|
||||
J3D::FillAABB(Colors::Whites::AliceBlue, {0,0,0.5f}, {0.05f, 0.05f, 0.05f});
|
||||
J3D::WireframeAABB(Colors::Gray, {0,0,0.5f}, {0.11f, 0.06f, 0.11f});
|
||||
|
||||
AABB boxes[1] = {{Vector3(-0.2125, -0.2125,0.28750), Vector3(0.2125,0.2125,0.7125)}};
|
||||
@@ -232,6 +245,9 @@ public:
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override {
|
||||
|
||||
fps = GetRefreshRate();
|
||||
|
||||
if (IsKeyDown(Keys::RightArrow))
|
||||
camera->angle.y += 45.f * elapsed;
|
||||
if (IsKeyDown(Keys::LeftArrow))
|
||||
@@ -289,24 +305,37 @@ public:
|
||||
|
||||
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
|
||||
JGLDemoWindow() : ReWindow::RWindow() {}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height){}
|
||||
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::RWindow(title, width, height) {}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
||||
window->SetRenderer(RenderingAPI::OPENGL);
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->SetResizable(true);
|
||||
window->SetVsyncEnabled(false);
|
||||
window->SetVsyncEnabled(true);
|
||||
|
||||
while (window->IsAlive()) {
|
||||
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
|
||||
window->PollEvents();
|
||||
window->Refresh();
|
||||
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();
|
||||
}
|
||||
std::ifstream file("assets/models/cube.amo");
|
||||
if (!file.is_open())
|
||||
return -1;
|
||||
|
||||
/*
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string file_text = buffer.str();
|
||||
file.close();
|
||||
std::cout << file_text << std::endl;
|
||||
|
||||
auto result = VertexArray::LoadAMO(file_text);
|
||||
*/
|
||||
|
||||
//ReWindow::Logger::Error.EnableConsole(false);
|
||||
//ReWindow::Logger::Warning.EnableConsole(false);
|
||||
//ReWindow::Logger::Debug.EnableConsole(false);
|
||||
|
||||
while (window->IsAlive())
|
||||
window->ManagedRefresh();
|
||||
return 0;
|
||||
}
|
1704
src/JGL.cpp
1704
src/JGL.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
#include <JGL/ShapeCache.h>
|
||||
|
||||
void JGL::ShapeCache::Init() {
|
||||
if (!cube_vertex_data) {
|
||||
std::array<Vector3, 24> vertices {
|
||||
Vector3(-1, 1, -1), Vector3(1, 1, -1),
|
||||
Vector3(1, 1, -1), Vector3(1, 1, 1),
|
||||
Vector3(1, 1, 1), Vector3(-1, 1, 1),
|
||||
Vector3(-1, 1, 1), Vector3(-1, 1, -1),
|
||||
Vector3(-1, -1, -1), Vector3(1, -1, -1),
|
||||
Vector3(1, -1, -1), Vector3(1, -1, 1),
|
||||
Vector3(1, -1, 1), Vector3(-1, -1, 1),
|
||||
Vector3(-1, -1, 1), Vector3(-1, -1, -1),
|
||||
Vector3(-1, -1, -1), Vector3(-1, 1, -1),
|
||||
Vector3(1, -1, -1), Vector3(1, 1, -1),
|
||||
Vector3(1, -1, 1), Vector3(1, 1, 1),
|
||||
Vector3(-1, -1, 1), Vector3(-1, 1, 1)
|
||||
};
|
||||
cube_vertex_data = new VRamList(vertices.data(), vertices.size());
|
||||
}
|
||||
|
||||
if (!cube_index_data) {
|
||||
std::array<GLuint, 36> indices {
|
||||
0, 1, 3, 0, 3, 5,
|
||||
|
||||
8, 9, 11, 8, 11, 13,
|
||||
|
||||
5, 3, 11, 5, 11, 13,
|
||||
|
||||
0, 1, 9, 0, 9, 8,
|
||||
|
||||
0, 5, 13, 0, 13, 8,
|
||||
|
||||
1, 3, 11, 1, 11, 9
|
||||
};
|
||||
cube_index_data = new VRamList(indices.data(), indices.size());
|
||||
}
|
||||
}
|
9
src/internals/include/AMO.h
Normal file
9
src/internals/include/AMO.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace JGL {
|
||||
class VertexArray;
|
||||
/*
|
||||
VertexArray LoadAMO(const std::string& file_text);
|
||||
*/
|
||||
}
|
9
src/internals/include/WavefrontOBJ.h
Normal file
9
src/internals/include/WavefrontOBJ.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace JGL {
|
||||
class VertexArray;
|
||||
// Currently requires "Triangulate Mesh" ticked in Blender.
|
||||
// TODO use the number of slashes in the first "face-line" to detect quads.
|
||||
VertexArray LoadWavefrontOBJ(const std::string& file_text);
|
||||
}
|
59
src/internals/include/internals.h
Normal file
59
src/internals/include/internals.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/// Things used in J2D and J3D that should not be exposed to the user of the library.
|
||||
#pragma once
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "J3ML/LinearAlgebra/Vector2.hpp"
|
||||
#include "JGL/types/RenderTarget.h"
|
||||
#include "JGL/types/Light.h"
|
||||
#include "JGL/logger/logger.h"
|
||||
|
||||
namespace JGL {
|
||||
inline constexpr std::array<const LightBase*, 8> empty_light_array = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||
inline bool inJ2D = false;
|
||||
inline bool inJ3D = false;
|
||||
std::vector<Vector3> TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count);
|
||||
}
|
||||
|
||||
namespace JGL::OpenGLState {
|
||||
inline JGL::RenderTarget* render_target = nullptr;
|
||||
inline Vector2 window_size;
|
||||
|
||||
inline GLfloat oldColor[4] = {0, 0, 0, 1};
|
||||
inline GLfloat baseColor[4] = {1, 1, 1, 1};
|
||||
|
||||
inline GLuint current_fbo = 0;
|
||||
inline GLint viewport[4] = {0, 0, 0, 0};
|
||||
|
||||
inline bool wasTexture2DEnabled = false;
|
||||
inline bool wasTextureCoordArrayEnabled = false;
|
||||
inline bool wasNormalArrayEnabled = false;
|
||||
|
||||
inline bool wasDepthTestEnabled = false;
|
||||
inline bool wasVertexArraysEnabled = false;
|
||||
inline bool wasCullFaceEnabled = false;
|
||||
inline bool wasBlendEnabled = false;
|
||||
inline bool wasColorArrayEnabled = false;
|
||||
inline GLint activeTextureUnit = 0;
|
||||
}
|
||||
|
||||
namespace JGL::J2D {
|
||||
inline std::array<const LightBase*, 8> required_lights;
|
||||
inline std::vector<const LightBase*> light_array;
|
||||
}
|
||||
|
||||
namespace JGL::J3D {
|
||||
// List of lights required for each objects in the scene. up-to 8. For example, the sun. Or a flash-light.
|
||||
inline std::array<const LightBase*, 8> required_lights;
|
||||
// List of all lights in the scene.
|
||||
inline std::vector<const LightBase*> optional_lights;
|
||||
inline float far_plane = 0;
|
||||
inline float fov = 0;
|
||||
// Enables lighting and selects the correct lights to use.
|
||||
void SelectLights(const Vector3& position);
|
||||
// Resets the GL lights to default and disables them. Then, disables lighting.
|
||||
void ResetLights();
|
||||
[[nodiscard]] bool UsingLighting();
|
||||
|
||||
}
|
8671
src/internals/src/Fonts.cpp
Normal file
8671
src/internals/src/Fonts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
54
src/internals/src/ShapeCache.cpp
Normal file
54
src/internals/src/ShapeCache.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
void JGL::ShapeCache::Init() {
|
||||
std::array<Vector3, 8> vertices = {
|
||||
Vector3(1.0f, 1.0f, -1.0f),
|
||||
Vector3(1.0f, -1.0f, -1.0f),
|
||||
Vector3(1.0f, 1.0f, 1.0f),
|
||||
Vector3(1.0f, -1.0f, 1.0f),
|
||||
Vector3(-1.0f, 1.0f, -1.0f),
|
||||
Vector3(-1.0f, -1.0f, -1.0f),
|
||||
Vector3(-1.0f, 1.0f, 1.0f),
|
||||
Vector3(-1.0f, -1.0f, 1.0f)
|
||||
};
|
||||
std::array<unsigned int, 36> indices = {
|
||||
4, 2, 0,
|
||||
2, 7, 3,
|
||||
6, 5, 7,
|
||||
1, 7, 5,
|
||||
0, 3, 1,
|
||||
4, 1, 5,
|
||||
4, 6, 2,
|
||||
2, 6, 7,
|
||||
6, 4, 5,
|
||||
1, 3, 7,
|
||||
0, 2, 3,
|
||||
4, 0, 1
|
||||
};
|
||||
|
||||
std::array<Vector3, 8> vertex_normals = {
|
||||
Vector3( 0.816f, 0.408f, -0.408f),
|
||||
Vector3( 0.333f, -0.667f, -0.667f),
|
||||
Vector3( 0.333f, 0.667f, 0.667f),
|
||||
Vector3( 0.816f, -0.408f, 0.408f),
|
||||
Vector3(-0.333f, 0.667f, -0.667f),
|
||||
Vector3(-0.816f, -0.408f, -0.408f),
|
||||
Vector3(-0.816f, 0.408f, 0.408f),
|
||||
Vector3(-0.333f, -0.667f, 0.667f)
|
||||
};
|
||||
|
||||
if (!cube_vertex_data)
|
||||
cube_vertex_data = new VRamList(vertices.data(), vertices.size());
|
||||
|
||||
if (!cube_index_data)
|
||||
cube_index_data = new VRamList(indices.data(), indices.size());
|
||||
|
||||
if (!cube_normal_data) {
|
||||
cube_normal_data = new VRamList(vertex_normals.data(), vertex_normals.size());
|
||||
}
|
||||
|
||||
if (!j2d_default_normal_data) {
|
||||
std::array<GLfloat, 3> normal {0, 0, 1};
|
||||
j2d_default_normal_data = new VRamList(normal.data(), normal.size());
|
||||
}
|
||||
}
|
336
src/internals/src/WavefrontOBJ.cpp
Normal file
336
src/internals/src/WavefrontOBJ.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
#include "../include/WavefrontOBJ.h"
|
||||
#include "../include/AMO.h"
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
std::pair<float, unsigned long> ParseNumber(const std::string& file_text, const unsigned long& offset) {
|
||||
std::string number;
|
||||
unsigned long new_offset = offset;
|
||||
bool decimal_used = false;
|
||||
|
||||
if (offset >= file_text.size())
|
||||
return {0.0f, offset};
|
||||
|
||||
for (; new_offset < file_text.size(); new_offset++) {
|
||||
if (file_text[new_offset] == '-') {
|
||||
if (number.empty()) {
|
||||
number.push_back(file_text[new_offset]);
|
||||
continue;
|
||||
}
|
||||
Logger::Error("Error while parsing number, Index: " + std::to_string(new_offset) + " Extra negative sign.");
|
||||
return {0.0f, offset};
|
||||
}
|
||||
|
||||
else if (file_text[new_offset] == '.') {
|
||||
if (!decimal_used) {
|
||||
number.push_back(file_text[new_offset]);
|
||||
decimal_used = true;
|
||||
continue;
|
||||
}
|
||||
Logger::Error("Error parsing number at: " + std::to_string(new_offset) + " Extra decimal point.");
|
||||
return {0.0f, offset};
|
||||
}
|
||||
|
||||
else if (isdigit(file_text[new_offset]))
|
||||
number.push_back(file_text[new_offset]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return {std::stof(number), new_offset};
|
||||
}
|
||||
|
||||
std::pair<Vector2, unsigned long> ParseVector2(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
|
||||
// If the new offset is the same as the offset we passed in then we know it didn't work.
|
||||
if (x_result.second == offset || y_result.second == x_result.second)
|
||||
return {Vector2(0, 0), offset};
|
||||
|
||||
return {Vector2(x_result.first, y_result.first), y_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<Vector3, unsigned long> ParseVector3(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
auto z_result = ParseNumber(file_text, y_result.second + 1);
|
||||
|
||||
// If the new offset is the same as the offset we passed in then we know it didn't work.
|
||||
if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second)
|
||||
return {Vector3(0,0,0), offset};
|
||||
|
||||
return {Vector3(x_result.first, y_result.first, z_result.first), z_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<Vector4, unsigned long> ParseVector4(const std::string& file_text, const unsigned long& offset) {
|
||||
auto x_result = ParseNumber(file_text, offset);
|
||||
auto y_result = ParseNumber(file_text, x_result.second + 1);
|
||||
auto z_result = ParseNumber(file_text, y_result.second + 1);
|
||||
auto w_result = ParseNumber(file_text, z_result.second + 1);
|
||||
|
||||
if (x_result.second == offset || y_result.second == x_result.second || z_result.second == y_result.second || w_result.second == z_result.second)
|
||||
return {Vector4(0, 0, 0, 0), offset};
|
||||
|
||||
return {Vector4(x_result.first, y_result.first, z_result.first, w_result.first), w_result.second + 1};
|
||||
}
|
||||
|
||||
std::pair<std::array<Vector3, 3>, unsigned long> ParseWavefrontFaceData(const std::string& file_text, const unsigned long& offset) {
|
||||
unsigned long new_offset = offset;
|
||||
std::array<Vector3, 3> face_data;
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
Vector3 vertex = {-1, -1, -1};
|
||||
|
||||
// Vertex
|
||||
if (std::isdigit(file_text[new_offset])) {
|
||||
auto v_result = ParseNumber(file_text, new_offset);
|
||||
vertex.x = v_result.first;
|
||||
new_offset = v_result.second;
|
||||
}
|
||||
|
||||
// UV
|
||||
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
|
||||
new_offset++;
|
||||
|
||||
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
|
||||
auto vt_result = ParseNumber(file_text, new_offset);
|
||||
vertex.y = vt_result.first;
|
||||
new_offset = vt_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal
|
||||
if (new_offset < file_text.size() && file_text[new_offset] == '/') {
|
||||
new_offset++;
|
||||
|
||||
if (new_offset < file_text.size() && (std::isdigit(file_text[new_offset]))) {
|
||||
auto vn_result = ParseNumber(file_text, new_offset);
|
||||
vertex.z = vn_result.first;
|
||||
new_offset = vn_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
face_data[i] = vertex;
|
||||
new_offset++;
|
||||
}
|
||||
return {face_data, new_offset};
|
||||
}
|
||||
|
||||
VertexArray JGL::LoadWavefrontOBJ(const std::string &file_text) {
|
||||
std::vector<std::array<Vector3, 3>> faceline_data;
|
||||
|
||||
std::vector<TextureCoordinate> temp_uvs;
|
||||
std::vector<Normal> temp_normals;
|
||||
std::vector<Vertex> temp_vertices;
|
||||
|
||||
unsigned long offset = 0;
|
||||
while (offset < file_text.size()) {
|
||||
char c = file_text[offset];
|
||||
|
||||
// TODO the entire line a comment is on should be skipped.
|
||||
// Skip forward to the character after the next newline.
|
||||
if (c == '#' || c == '\n' || c == '\r') {
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Vertices
|
||||
if (c == 'v' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
|
||||
offset += 2;
|
||||
|
||||
auto vertex_result = ParseVector3(file_text, offset);
|
||||
if (vertex_result.second != offset) {
|
||||
temp_vertices.push_back(vertex_result.first);
|
||||
offset = vertex_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normals.
|
||||
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 'n' &&
|
||||
file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
|
||||
auto normal_result = ParseVector3(file_text, offset);
|
||||
if (normal_result.second != offset) {
|
||||
temp_normals.push_back(normal_result.first);
|
||||
offset = normal_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Texture Coordinates
|
||||
else if (c == 'v' && offset + 2 < file_text.size() && file_text[offset + 1] == 't' &&
|
||||
file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
|
||||
auto uv_result = ParseVector2(file_text, offset);
|
||||
if (uv_result.second != offset) {
|
||||
temp_uvs.push_back(uv_result.first);
|
||||
offset = uv_result.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Face lines.
|
||||
else if (c == 'f' && offset + 1 < file_text.size() && file_text[offset + 1] == ' ') {
|
||||
offset += 2;
|
||||
|
||||
auto faceline_result = ParseWavefrontFaceData(file_text, offset);
|
||||
if (faceline_result.second != offset) {
|
||||
faceline_data.push_back(faceline_result.first);
|
||||
offset = faceline_result.second;
|
||||
}
|
||||
} else
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Pick everything out of the face lines and set up how OpenGL expects.
|
||||
std::vector<Vertex> final_vertices;
|
||||
std::vector<TextureCoordinate> final_uvs;
|
||||
std::vector<Normal> final_normals;
|
||||
std::vector<unsigned int> final_indices;
|
||||
for (const auto &face: faceline_data) {
|
||||
for (const auto &vp: face) {
|
||||
Vertex vertex;
|
||||
TextureCoordinate uv;
|
||||
Normal normal;
|
||||
|
||||
if (vp.x != -1)
|
||||
vertex = temp_vertices[vp.x - 1];
|
||||
if (vp.y != -1)
|
||||
uv = temp_uvs[vp.y - 1];
|
||||
if (vp.z != -1)
|
||||
normal = temp_normals[vp.z - 1];
|
||||
|
||||
final_vertices.push_back(vertex);
|
||||
final_uvs.push_back(uv);
|
||||
final_normals.push_back(normal);
|
||||
final_indices.push_back((unsigned int) final_vertices.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return VertexArray(
|
||||
final_vertices.data(), final_vertices.size(),
|
||||
final_indices.data(), final_indices.size(),
|
||||
final_normals.data(), final_normals.size(),
|
||||
final_uvs.data(), final_uvs.size());
|
||||
}
|
||||
|
||||
/*
|
||||
VertexArray JGL::LoadAMO(const std::string& file_text) {
|
||||
std::vector<Vector3> temp_vertices;
|
||||
std::vector<Vector3> temp_normals;
|
||||
std::vector<Vector2> temp_uvs;
|
||||
std::vector<std::array<Vector3, 3>> faceline_data;
|
||||
std::string name;
|
||||
|
||||
unsigned long offset = 0;
|
||||
while (offset < file_text.size()) {
|
||||
char c = file_text[offset];
|
||||
|
||||
// If we've dropped on a newline character somehow then just skip passed it.
|
||||
if (c == '\n' || c == '\r') {
|
||||
offset++; continue;
|
||||
}
|
||||
|
||||
// File name.
|
||||
else if (offset + 2 < file_text.size() && c == 'a' && file_text[offset + 1] == 'o' && file_text[offset + 2] == ' ') {
|
||||
offset += 3;
|
||||
while (offset < file_text.size()) {
|
||||
if (file_text[offset] != '\n' && file_text[offset] != '\r')
|
||||
name.push_back(file_text[offset]), offset++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices
|
||||
else if (offset + 1 < file_text.size() && c == 'v' && file_text[offset + 1] == ' ') {
|
||||
offset += 2; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Vertex count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long vertex_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < vertex_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector3 = ParseVector3(file_text, offset);
|
||||
if (parsed_vector3.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Vertex at: " + std::to_string(offset));
|
||||
|
||||
temp_vertices.push_back(parsed_vector3.first);
|
||||
offset = parsed_vector3.second;
|
||||
}
|
||||
}
|
||||
|
||||
// UVs
|
||||
else if (offset + 2 < file_text.size() && c == 'v' && file_text[offset + 1] == 't' && file_text[offset + 2] == ' ') {
|
||||
offset += 3; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the UV count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long uv_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < uv_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector2 = ParseVector2(file_text, offset);
|
||||
if (parsed_vector2.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the UV at: " + std::to_string(offset));
|
||||
|
||||
temp_uvs.push_back(parsed_vector2.first);
|
||||
offset = parsed_vector2.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Normals
|
||||
else if (offset + 2 < file_text.size() && c == 'v' && file_text[offset + 1] == 'n' && file_text[offset + 2] == ' ') {
|
||||
offset += 3; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Normal count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long uv_count = parsed_number.first;
|
||||
offset = parsed_number.second;
|
||||
|
||||
for (unsigned long i = 0; i < uv_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
auto parsed_vector3 = ParseVector3(file_text, offset);
|
||||
if (parsed_vector3.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Normal at: " + std::to_string(offset));
|
||||
|
||||
temp_normals.push_back(parsed_vector3.first);
|
||||
offset = parsed_vector3.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Face Lines
|
||||
else if (offset + 1 < file_text.size() && c == 'f' && file_text[offset + 1] == ' ') {
|
||||
offset += 2; auto parsed_number = ParseNumber(file_text, offset);
|
||||
|
||||
if (parsed_number.second == offset)
|
||||
Logger::Fatal("We couldn't interpret the Face Line count at: " + std::to_string(offset));
|
||||
|
||||
unsigned long faceline_count = parsed_number.first;
|
||||
for (unsigned long i = 0; i < faceline_count; i++) {
|
||||
// Skip by newlines.
|
||||
while (file_text[offset] == '\n' || file_text[offset] == '\r')
|
||||
offset++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
119
src/internals/src/internals.cpp
Normal file
119
src/internals/src/internals.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "../include/internals.h"
|
||||
#include "J3ML/LinearAlgebra/Vector4.hpp"
|
||||
#include "JGL/types/Light.h"
|
||||
|
||||
// TODO handle the case that a required light is in the list of optional lights.
|
||||
void JGL::J3D::SelectLights(const Vector3& position) {
|
||||
std::array<const LightBase*, 8> result = required_lights;
|
||||
|
||||
unsigned int required_light_count = 0;
|
||||
for (const auto& i : result)
|
||||
if (i) required_light_count++;
|
||||
|
||||
// If there is optional lights.
|
||||
if (!optional_lights.empty()) {
|
||||
// The number of lights we need to solve for
|
||||
unsigned int remaining_lights = 8 - required_light_count;
|
||||
|
||||
std::vector<std::pair<float, const LightBase*>> light_influence;
|
||||
for (const auto* light: optional_lights)
|
||||
light_influence.emplace_back(light->GetAttenuationAtPosition(position), light);
|
||||
|
||||
// Sort by biggest influence.
|
||||
std::sort(light_influence.begin(), light_influence.end(),
|
||||
[](const auto &a, const auto &b) { return a.first > b.first; });
|
||||
|
||||
// Add in optional lights.
|
||||
for (unsigned int i = 0; i < remaining_lights && i < light_influence.size(); i++)
|
||||
result[required_light_count++] = light_influence[i].second;
|
||||
}
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
for (unsigned int i = 0; i < result.size(); i++) {
|
||||
// Terminate early if we have less than 8 lights.
|
||||
if (!result[i])
|
||||
break;
|
||||
|
||||
Vector4 ambient = { result[i]->GetAmbient().RN(), result[i]->GetAmbient().GN(), result[i]->GetAmbient().BN(), result[i]->GetAmbient().AN() };
|
||||
Vector4 diffuse = { result[i]->GetDiffuse().RN(), result[i]->GetDiffuse().GN(), result[i]->GetDiffuse().BN(), result[i]->GetDiffuse().AN() };
|
||||
Vector4 specular = { result[i]->GetSpecular().RN(), result[i]->GetSpecular().GN(), result[i]->GetSpecular().BN(), result[i]->GetSpecular().AN() };
|
||||
GLenum current_light = GL_LIGHT0 + i;
|
||||
|
||||
glEnable(GL_LIGHT0 + i);
|
||||
glLightfv(current_light, GL_POSITION, result[i]->GetPosition().ptr());
|
||||
|
||||
// How the light will affect different materials.
|
||||
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
|
||||
glLightfv(current_light, GL_DIFFUSE, diffuse.ptr());
|
||||
glLightfv(current_light, GL_SPECULAR, specular.ptr());
|
||||
|
||||
// How far the light goes.
|
||||
glLightf(current_light, GL_CONSTANT_ATTENUATION, result[i]->GetConstantAttenuation());
|
||||
glLightf(current_light, GL_LINEAR_ATTENUATION, result[i]->GetLinearAttenuation());
|
||||
glLightf(current_light, GL_QUADRATIC_ATTENUATION, result[i]->GetQuadraticAttenuation());
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::J3D::ResetLights() {
|
||||
Vector4 position = {0, 0, 1, 0};
|
||||
Vector4 ambient = {0, 0, 0, 1};
|
||||
Vector4 diffuse_light0 = {1,1,1,1};
|
||||
Vector4 diffuse = {0,0,0,1};
|
||||
Vector4 specular_light0 = {1,1,1,1};
|
||||
Vector4 specular = {0,0,0,1};
|
||||
Vector3 spot_direction = {0.0, 0.0, -1.0};
|
||||
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
GLenum current_light = GL_LIGHT0 + i;
|
||||
|
||||
glLightfv(current_light, GL_POSITION, position.ptr());
|
||||
glLightfv(current_light, GL_AMBIENT, ambient.ptr());
|
||||
glLightf(current_light, GL_CONSTANT_ATTENUATION, 1);
|
||||
glLightf(current_light, GL_LINEAR_ATTENUATION, 0);
|
||||
glLightf(current_light, GL_QUADRATIC_ATTENUATION, 0);
|
||||
glLightf(current_light, GL_SPOT_CUTOFF, 180.0);
|
||||
glLightfv(current_light, GL_SPOT_DIRECTION, spot_direction.ptr());
|
||||
glLightf(current_light, GL_SPOT_EXPONENT, 0.0);
|
||||
glLightfv(current_light, GL_DIFFUSE, (i == 0 ? diffuse_light0.ptr() : diffuse.ptr()));
|
||||
glLightfv(current_light, GL_SPECULAR, (i == 0 ? specular_light0.ptr() : specular.ptr()));
|
||||
glDisable(current_light);
|
||||
}
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
bool JGL::J3D::UsingLighting() {
|
||||
if (!optional_lights.empty())
|
||||
return true;
|
||||
|
||||
for (unsigned int i = 0; i < required_lights.size(); i++)
|
||||
if (required_lights[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Vector3> JGL::TriangleMeshVertexNormals(const Vector3* vertices, const size_t& vertex_count, const unsigned int* indices, const size_t& index_count) {
|
||||
std::vector<Vector3> normals(vertex_count, Vector3(0, 0, 0));
|
||||
|
||||
for (size_t i = 0; i < index_count; i += 3) {
|
||||
GLuint i1 = indices[i];
|
||||
GLuint i2 = indices[i + 1];
|
||||
GLuint i3 = indices[i + 2];
|
||||
|
||||
Vector3 v1 = vertices[i1];
|
||||
Vector3 v2 = vertices[i2];
|
||||
Vector3 v3 = vertices[i3];
|
||||
|
||||
Vector3 edge1 = v2 - v1;
|
||||
Vector3 edge2 = v3 - v1;
|
||||
|
||||
Vector3 faceNormal = Vector3::Cross(edge1, edge2);
|
||||
|
||||
normals[i1] += faceNormal;
|
||||
normals[i2] += faceNormal;
|
||||
normals[i3] += faceNormal;
|
||||
}
|
||||
for (auto& normal : normals)
|
||||
normal = normal.Normalized();
|
||||
|
||||
return normals;
|
||||
}
|
1128
src/renderer/J2D.cpp
Normal file
1128
src/renderer/J2D.cpp
Normal file
File diff suppressed because it is too large
Load Diff
608
src/renderer/J3D.cpp
Normal file
608
src/renderer/J3D.cpp
Normal file
@@ -0,0 +1,608 @@
|
||||
#include <JGL/JGL.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/OBB.hpp>
|
||||
#include <J3ML/Algorithm/Bezier.hpp>
|
||||
#include <JGL/types/Light.h>
|
||||
#include "../internals/include/internals.h"
|
||||
|
||||
|
||||
std::array<GLfloat, 16> JGL::OpenGLPerspectiveProjectionRH(float fovY, float aspect, float z_near, float z_far) {
|
||||
std::array<GLfloat, 16> result{};
|
||||
GLfloat f = 1.0f / std::tan(fovY * 0.5f * Math::Pi / 180.0f);
|
||||
result[0] = f / aspect;
|
||||
result[5] = f;
|
||||
result[10] = (z_far + z_near) / (z_near - z_far);
|
||||
result[11] = -1.0f;
|
||||
result[14] = (2.0f * z_far * z_near) / (z_near - z_far);
|
||||
return result;
|
||||
}
|
||||
|
||||
void JGL::J3D::ChangeFOV(float fov) {
|
||||
JGL::J3D::fov = fov;
|
||||
}
|
||||
|
||||
void JGL::J3D::ChangeFarPlane(float far_plane) {
|
||||
JGL::J3D::far_plane = far_plane;
|
||||
}
|
||||
|
||||
void JGL::J3D::RequiredLight(const JGL::LightBase* light) {
|
||||
bool success = false;
|
||||
for (auto& i : required_lights)
|
||||
if (i == nullptr) {
|
||||
i = light;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
Logger::Error("You cannot specify more than 8 required lights.");
|
||||
}
|
||||
|
||||
void JGL::J3D::OptionalLights(const JGL::LightBase** lights, const size_t& light_count) {
|
||||
for (size_t i = 0; i < light_count; i++)
|
||||
optional_lights.push_back(lights[i]);
|
||||
}
|
||||
|
||||
void JGL::J3D::Begin(bool two_pass) {
|
||||
auto aspect = (float) OpenGLState::window_size.x / (float) OpenGLState::window_size.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf(OpenGLPerspectiveProjectionRH(fov, aspect, 0.001, far_plane).data());
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
//Get what the draw color was before we did anything.
|
||||
glGetFloatv(GL_CURRENT_COLOR, OpenGLState::oldColor);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
|
||||
if (!glIsEnabled(GL_DEPTH_TEST))
|
||||
OpenGLState::wasDepthTestEnabled = false,
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
OpenGLState::wasDepthTestEnabled = true;
|
||||
|
||||
OpenGLState::wasVertexArraysEnabled = false;
|
||||
if (!glIsEnabled(GL_VERTEX_ARRAY))
|
||||
OpenGLState::wasVertexArraysEnabled = false,
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_NORMAL_ARRAY))
|
||||
OpenGLState::wasNormalArrayEnabled = true,
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
|
||||
OpenGLState::wasTextureCoordArrayEnabled = true,
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_TEXTURE_2D))
|
||||
OpenGLState::wasTexture2DEnabled = true,
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
OpenGLState::wasCullFaceEnabled = false;
|
||||
if (glIsEnabled(GL_CULL_FACE))
|
||||
OpenGLState::wasCullFaceEnabled = true,
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
if (!glIsEnabled(GL_BLEND))
|
||||
OpenGLState::wasBlendEnabled = false,
|
||||
glEnable(GL_BLEND),
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
OpenGLState::wasBlendEnabled = true;
|
||||
|
||||
// Reset the lights.
|
||||
required_lights = empty_light_array;
|
||||
optional_lights = {};
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
if (!inJ2D)
|
||||
inJ3D = true;
|
||||
else
|
||||
Logger::Error("Beginning J3D context inside of J2D context?");
|
||||
}
|
||||
|
||||
void JGL::J3D::End() {
|
||||
if (!OpenGLState::wasDepthTestEnabled)
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (!OpenGLState::wasVertexArraysEnabled)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
if (OpenGLState::wasTexture2DEnabled)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (!OpenGLState::wasBlendEnabled)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (OpenGLState::wasCullFaceEnabled)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
if (OpenGLState::wasNormalArrayEnabled)
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
if (OpenGLState::wasTextureCoordArrayEnabled)
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (glIsEnabled(GL_LIGHTING)) {
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_LIGHT0);
|
||||
glDisable(GL_LIGHT1);
|
||||
glDisable(GL_LIGHT2);
|
||||
glDisable(GL_LIGHT3);
|
||||
glDisable(GL_LIGHT4);
|
||||
glDisable(GL_LIGHT5);
|
||||
glDisable(GL_LIGHT6);
|
||||
glDisable(GL_LIGHT7);
|
||||
}
|
||||
|
||||
required_lights = empty_light_array;
|
||||
optional_lights = {};
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
inJ3D = false;
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawLine(const Color4& color, const Vector3& A, const Vector3& B, float thickness) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
Vector3 vertices[] = {A, B};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
BatchWireframeSphere(color,& sphere, 1, thickness, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int stacks) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
// Create one sphere with a radius of 1 about 0, 0.
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
|
||||
for (int j = 0; j <= stacks; j++) {
|
||||
float lng = 2 * J3ML::Math::Pi * (float) (j - 1) / stacks;
|
||||
float x = J3ML::Math::Cos(lng);
|
||||
float y = J3ML::Math::Sin(lng);
|
||||
|
||||
float pos_x = r * x * zr;
|
||||
float pos_y = r * y * zr;
|
||||
float pos_z = r * z;
|
||||
|
||||
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
|
||||
// Render each sphere in the batch at their given position and radius.
|
||||
for(size_t i = 0; i < sphere_count; i++) {
|
||||
glPushMatrix();
|
||||
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertices.size());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Vector3& position, float radius, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeRevoSphere(const Color4& color, const Sphere& sphere, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
BatchWireframeRevoSphere(color,& sphere, 1, thickness, sectors, revolutions, draw_stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeRevoSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, float thickness, unsigned int sectors, unsigned int revolutions, bool draw_stacks) {
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices;
|
||||
vertices.reserve((sectors + 1) * (revolutions + 1));
|
||||
|
||||
std::vector<Vector3> cross_section(sectors + 1);
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float)i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
cross_section[i] = Vector3(0, zr * r, z * r);
|
||||
}
|
||||
|
||||
// Revolve
|
||||
for (int j = 0; j <= revolutions; j++) {
|
||||
float lng = 2 * J3ML::Math::Pi * (float)j / revolutions;
|
||||
float cosLng = J3ML::Math::Cos(lng);
|
||||
float sinLng = J3ML::Math::Sin(lng);
|
||||
|
||||
for (const auto& point : cross_section) {
|
||||
float pos_x = point.y * cosLng;
|
||||
float pos_y = point.y * sinLng;
|
||||
float pos_z = point.z;
|
||||
|
||||
vertices.emplace_back(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
VRamList vertex_data(vertices.data(), vertices.size());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
// Render each sphere in the batch at their given position and radius.
|
||||
for(size_t i = 0; i < sphere_count; i++) {
|
||||
glPushMatrix();
|
||||
glTranslatef(spheres[i].Position.x, spheres[i].Position.y, spheres[i].Position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
if (draw_stacks)
|
||||
glRotatef(90, 0, 1, 0),
|
||||
glDrawArrays(GL_LINE_LOOP, 0, vertex_data.GetLength());
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosphere(const Color4& color, const Vector3& position, float radius, float thickness,
|
||||
unsigned int subdivisions) {
|
||||
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
// NOTE2SELF: Code i'm borrowing this from uses float-packed-arrays rather than discrete Vectors
|
||||
// working on translating that correctly...
|
||||
|
||||
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
|
||||
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
|
||||
|
||||
std::vector<Vector3> vertices; // array of 12 vertices (x,y,z)
|
||||
unsigned int index = 0; // indices
|
||||
float z, xy; // coords
|
||||
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
|
||||
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
|
||||
|
||||
// the first top vertex at (0,0,r)
|
||||
vertices[0] = position + Vector3{0,0,radius};
|
||||
|
||||
|
||||
|
||||
// compute 10 vertices at 1st and 2nd rows
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
|
||||
z = radius * Math::Sin(v_angle); // elevation
|
||||
xy = radius * Math::Cos(v_angle); // length on XY plane
|
||||
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
|
||||
|
||||
// next horizontal angles
|
||||
hAngle1 += h_angle;
|
||||
hAngle2 += h_angle;
|
||||
}
|
||||
|
||||
// the last bottom vertex at (0, 0, -r)
|
||||
vertices[11] = position + Vector3{0,0, -radius};
|
||||
|
||||
//glLineWidth(thickness);
|
||||
//glColor4ubv(color.ptr());
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
|
||||
//glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
//glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
|
||||
//glColor4fv(baseColor);
|
||||
|
||||
std::vector<Vector3> tmpVertices;
|
||||
std::vector<Vector3> tmpIndices;
|
||||
std::vector<Vector2> newVs((subdivisions+1) * (subdivisions+2) / 2 * 3);
|
||||
const Vector3 v1, v2, v3;
|
||||
Vector3 newV1, newV2, newV3;
|
||||
|
||||
int i, j, k;
|
||||
index = 0; // unsigned int
|
||||
float a; // lerp alpha
|
||||
unsigned int i1, i2; // indices
|
||||
|
||||
// copy prev arrays
|
||||
tmpVertices = vertices;
|
||||
//tmpIndices = indices;
|
||||
|
||||
// iterate each triangle of icosahedron
|
||||
for (i = 0; i < tmpIndices.size(); i++)
|
||||
{
|
||||
//v1 = tmpVertices[tmpIndices[i]];
|
||||
//v2 = tmpVertices[tmpIndices[i+1]];
|
||||
//v3 = tmpVertices[tmpIndices[i+2]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeIcosahedron(const Color4& color, const Vector3& position, float radius, float thickness) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
// TODO: Revise this once J3ML::Geometry::Icosahedron is implemented.
|
||||
const float h_angle = J3ML::Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = J3ML::Math::Atan(1.0f / 2.f); // elevation = 26.565;
|
||||
|
||||
std::array<Vector3, 12> vertices; // array of 12 vertices (x,y,z)
|
||||
int index = 0; // indices
|
||||
float z, xy; // coords
|
||||
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f; // start from -126 at 1st row
|
||||
float hAngle2 = -Math::Pi / 2.f; // start from -90 deg at 2nd row
|
||||
|
||||
// the first top vertex at (0,0,r)
|
||||
vertices[0] = position + Vector3{0,0,radius};
|
||||
|
||||
|
||||
|
||||
// compute 10 vertices at 1st and 2nd rows
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
|
||||
z = radius * Math::Sin(v_angle); // elevation
|
||||
xy = radius * Math::Cos(v_angle); // length on XY plane
|
||||
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z} ;
|
||||
vertices[index++] = position + Vector3{xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
|
||||
|
||||
// next horizontal angles
|
||||
hAngle1 += h_angle;
|
||||
hAngle2 += h_angle;
|
||||
}
|
||||
|
||||
// the last bottom vertex at (0, 0, -r)
|
||||
vertices[11] = position + Vector3{0,0, -radius};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
//glBindBuffer(GL_ARRAY_BUFFER, vertices.size());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertices.size());
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchWireframeAABB(const Color4& color, const AABB* boxes, const size_t& box_count, float thickness) {
|
||||
glColor4ubv(color.ptr());
|
||||
glLineWidth(thickness);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
|
||||
Vector3 center = boxes[i].Centroid();
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
glScalef(delta.x, delta.y, delta.z);
|
||||
glDrawArrays(GL_LINES, 0, ShapeCache::cube_vertex_data->GetLength());
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::baseColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeAABB(const Color4& color, const Vector3& pos, const Vector3& radii, float thickness) {
|
||||
AABB aabb = {Vector3(pos.x - radii.x, pos.y - radii.y, pos.z - radii.z), Vector3(pos.x + radii.x, pos.y + radii.y, pos.z + radii.z)};
|
||||
BatchWireframeAABB(color, &aabb, 1, thickness);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillAABB(const Color4& color, const AABB* boxes, const size_t& box_count) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_vertex_data->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ShapeCache::cube_index_data->GetHandle());
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
bool using_lights = false;
|
||||
if (UsingLighting()) {
|
||||
using_lights = true;
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, ShapeCache::cube_normal_data->GetHandle());
|
||||
glNormalPointer(GL_FLOAT, sizeof(float), nullptr);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
Vector3 delta = (boxes[i].maxPoint - boxes[i].minPoint) / 2;
|
||||
Vector3 center = boxes[i].Centroid();
|
||||
glPushMatrix();
|
||||
glTranslatef(center.x, center.y, center.z);
|
||||
glScalef(delta.x, delta.y, delta.z);
|
||||
if (using_lights)
|
||||
SelectLights(center);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
|
||||
if (using_lights)
|
||||
ResetLights();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
if (using_lights)
|
||||
glDisable(GL_NORMAL_ARRAY);
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
void JGL::J3D::FillAABB(const Color4& color, const Vector3& pos, const Vector3& radii) {
|
||||
AABB box = {pos - radii, pos + radii};
|
||||
BatchFillAABB(color, &box, 1);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillAABB(const Color4& color, const AABB& aabb) {
|
||||
BatchFillAABB(color, &aabb, 1);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillSphere(const Color4& color, const Sphere& sphere, unsigned int sectors, unsigned int stacks) {
|
||||
BatchFillSphere(color, &sphere, 1, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::BatchFillSphere(const Color4& color, const Sphere* spheres, const size_t& sphere_count, unsigned int sectors, unsigned int stacks) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
|
||||
float r = 1;
|
||||
std::vector<Vector3> vertices((sectors + 1) * (stacks + 1));
|
||||
std::vector<unsigned int> indices; indices.reserve(sectors * stacks * 6);
|
||||
|
||||
float two_pi = 2 * J3ML::Math::Pi;
|
||||
int index = 0;
|
||||
for (int i = 0; i <= sectors; i++) {
|
||||
float lat = J3ML::Math::Pi * (-0.5 + (float) i / sectors);
|
||||
float z = J3ML::Math::Sin(lat);
|
||||
float zr = J3ML::Math::Cos(lat);
|
||||
|
||||
for (int j = 0; j <= stacks; j++) {
|
||||
float lng = two_pi * (float) (j - 1) / stacks;
|
||||
float x = J3ML::Math::Cos(lng);
|
||||
float y = J3ML::Math::Sin(lng);
|
||||
|
||||
float pos_x = r * x * zr;
|
||||
float pos_y = r * y * zr;
|
||||
float pos_z = r * z;
|
||||
vertices[index++] = Vector3(pos_x, pos_y, pos_z);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sectors; i++) {
|
||||
for (int j = 0; j < stacks; j++) {
|
||||
int first_index = i * (stacks + 1) + j;
|
||||
int second_index = first_index + stacks + 1;
|
||||
|
||||
indices.push_back(first_index);
|
||||
indices.push_back(second_index);
|
||||
indices.push_back(first_index + 1);
|
||||
|
||||
indices.push_back(second_index);
|
||||
indices.push_back(second_index + 1);
|
||||
indices.push_back(first_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
VRamList vertex_data(vertices.data(), vertices.size());
|
||||
VRamList index_data(indices.data(), indices.size());
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_data.GetHandle());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_data.GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), nullptr);
|
||||
|
||||
for (size_t i = 0; i < sphere_count; i++) {
|
||||
const Vector3 position = spheres[i].Position;
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glScalef(spheres[i].Radius, spheres[i].Radius, spheres[i].Radius);
|
||||
glDrawElements(GL_TRIANGLES, index_data.GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
glPopMatrix();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::FillSphere(const Color4& color, const Vector3& position, float radius, unsigned int sectors, unsigned int stacks) {
|
||||
Sphere sphere = {position, radius};
|
||||
BatchFillSphere(color, &sphere, 1, sectors, stacks);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeAABB(const Color4& color, const AABB& aabb, float thickness) {
|
||||
BatchWireframeAABB(color, &aabb, 1, thickness);
|
||||
}
|
||||
|
||||
// TODO Make it work the same as AABB batching. I couldn't get rotation to do anything more than twitch in place :(.
|
||||
void JGL::J3D::BatchWireframeOBB(const Color4& color, const OBB* boxes, const size_t& box_count, float thickness) {
|
||||
std::array<Vector3, 8> corner_points;
|
||||
std::array<GLuint, 24> indices =
|
||||
{
|
||||
0, 1, 1, 2, 2, 3, 3, 0,
|
||||
4, 5, 5, 6, 6, 7, 7, 4,
|
||||
0, 4, 1, 5, 2, 6, 3, 7
|
||||
};
|
||||
|
||||
glLineWidth(thickness);
|
||||
glColor4ubv(color.ptr());
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(Vector3), corner_points.data());
|
||||
|
||||
for (size_t i = 0; i < box_count; i++) {
|
||||
boxes[i].GetCornerPoints(corner_points.data());
|
||||
glPushMatrix();
|
||||
glTranslatef(boxes[i].pos.x, boxes[i].pos.y, boxes[i].pos.z);
|
||||
glDrawElements(GL_LINES, indices.size(), GL_UNSIGNED_INT, indices.data());
|
||||
glPopMatrix();
|
||||
}
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
}
|
||||
|
||||
void JGL::J3D::WireframeOBB(const Color4& color, const OBB& obb, float thickness) {
|
||||
BatchWireframeOBB(color, &obb, 1, thickness);
|
||||
}
|
||||
|
||||
/*
|
||||
void JGL::J3D::WireframeOBB(const Color4& color, const Vector3& position, const Vector3& radii, const Matrix3x3& orientation, float thickness) {
|
||||
WireframeOBB(color, OBB(position, radii, orientation. * Vector3::UnitX, rotation * Vector3::UnitY, rotation * Vector3::UnitZ), thickness);
|
||||
}
|
||||
*/
|
||||
|
||||
void JGL::J3D::DrawCubicBezierCurve(const Color4& color, const Vector3& controlA, const Vector3& pointA,
|
||||
const Vector3& pointB, const Vector3& controlB, int subdivisions, float thickness) {
|
||||
Vector3 last = controlA;
|
||||
const Vector3& first = controlB;
|
||||
for (int i = 0; i < subdivisions; ++i)
|
||||
{
|
||||
float alpha = (float) i / (float) subdivisions;
|
||||
Vector3 step = J3ML::Algorithm::Bezier(alpha, controlA, pointA, pointB, controlB);
|
||||
DrawLine(color, last, step, thickness);
|
||||
last = step;
|
||||
}
|
||||
|
||||
// Have to manually draw the last segment of the curve.
|
||||
DrawLine(color, last, first, thickness);
|
||||
}
|
||||
|
||||
void JGL::J3D::DrawVertexArray(const Color4& color, const VertexArray& vertex_array, const Vector3& position) {
|
||||
if (!inJ3D)
|
||||
Logger::Error("Drawing J3D element before J3D begin.");
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertex_array.GetVertices()->GetHandle());
|
||||
glVertexPointer(3, GL_FLOAT, 0, nullptr);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
//glScalef(1,1,1);
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertex_array.GetVertices()->GetLength());
|
||||
glPopMatrix();
|
||||
|
||||
//glDrawElements(GL_LINES, vertex_array.GetIndices()->GetLength(), GL_UNSIGNED_INT, nullptr);
|
||||
//std::cout << vertex_array.GetVertices()->GetLength() << std::endl;
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
#include <JGL/JGL.h>
|
||||
#include "../internals/include/internals.h"
|
||||
|
||||
|
||||
#if __linux__
|
||||
@@ -157,7 +158,7 @@ namespace JGL {
|
||||
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);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
@@ -243,7 +244,7 @@ namespace JGL {
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glColor4f(1, 1, 1, 1);
|
||||
glColor4fv(OpenGLState::oldColor);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
@@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
#include <glad/glad.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include <JGL/JGL.h>
|
||||
|
||||
#if __linux__
|
||||
#include <freetype2/ft2build.h>
|
||||
@@ -58,25 +59,38 @@ namespace JGL {
|
||||
return Detail::InitTextEngine();
|
||||
}
|
||||
|
||||
Font::Font(const unsigned char* data, const size_t& size) {
|
||||
if (Detail::ft == nullptr)
|
||||
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||
|
||||
if (FT_New_Memory_Face(Detail::ft, data, size, 0, &face))
|
||||
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||
|
||||
unsigned int new_index = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= new_index)
|
||||
new_index = f.index + 1;
|
||||
index = new_index;
|
||||
|
||||
Detail::fonts.push_back(*this);
|
||||
std::cout << "Loaded font from memory at " << static_cast<const void*>(data) << " with index " << new_index << std::endl;
|
||||
}
|
||||
|
||||
Font::Font(const std::filesystem::path& path) {
|
||||
if (Detail::ft == nullptr)
|
||||
throw std::runtime_error("Error::FREETYPE: FT_Library was not initialized before attempting to load a font!");
|
||||
|
||||
Font font;
|
||||
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face)) {
|
||||
std::cout << "Error::FREETYPE: Failed to load font!" << std::endl;
|
||||
if (FT_New_Face(Detail::ft, path.string().c_str(), 0, &face))
|
||||
throw std::runtime_error("Error::FREETYPE: Failed to load font!");
|
||||
//return -1;
|
||||
}
|
||||
unsigned int newIndex = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= newIndex)
|
||||
newIndex = f.index + 1;
|
||||
|
||||
index = newIndex;
|
||||
Detail::fonts.push_back(font);
|
||||
std::cout << "Loaded font from " << path << " with index " << newIndex << std::endl;
|
||||
//return newIndex;
|
||||
unsigned int new_index = 0;
|
||||
for (const auto& f : Detail::fonts)
|
||||
if (f.index >= new_index)
|
||||
new_index = f.index + 1;
|
||||
|
||||
index = new_index;
|
||||
Detail::fonts.push_back(*this);
|
||||
std::cout << "Loaded font from " << path << " with index " << new_index << std::endl;
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
@@ -119,14 +133,18 @@ 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);
|
||||
jlog::Warning("Measuring a font size that is not cached, Defaulting to Jupiteroid.");
|
||||
FT_Set_Pixel_Sizes(Fonts::Jupiteroid.face, ptSize, ptSize);
|
||||
|
||||
for (const char& c : text) {
|
||||
// TODO: Fix segfault
|
||||
//FT_GlyphSlot slot = Fonts::Jupiteroid.face->glyph;
|
||||
//auto glyph_index = FT_Get_Char_Index(Fonts::Jupiteroid.face, c);
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
auto glyph_index = FT_Get_Char_Index(this->face, c);
|
||||
|
||||
auto error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
||||
//auto error = FT_Load_Glyph(Fonts::Jupiteroid.face, glyph_index, FT_LOAD_DEFAULT);
|
||||
auto error = FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
|
||||
|
||||
if (error)
|
||||
continue;
|
||||
@@ -146,9 +164,6 @@ namespace JGL {
|
||||
if (extents.y < ptSize)
|
||||
extents.y = ptSize;
|
||||
}
|
||||
|
||||
return extents;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -33,8 +33,8 @@ JGL::SpotLight::SpotLight(const Vector3& position, const Matrix3x3& ro_mat, floa
|
||||
this->quadratic_attenuation = quadratic_attenuation;
|
||||
}
|
||||
|
||||
Vector3 JGL::LightBase::GetPosition() const {
|
||||
return {position.x, position.y, position.z};
|
||||
Vector4 JGL::LightBase::GetPosition() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetAmbient() const {
|
||||
|
@@ -0,0 +1,31 @@
|
||||
#include <JGL/types/Material.h>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
|
||||
JGL::Material::Material(const Color4& ambient_reflection, const Color4& diffuse_reflection, const Color4& specular_reflection, const Color4& light_emission, float& shine) {
|
||||
ambient_ref = ambient_reflection;
|
||||
diffuse_ref = diffuse_reflection;
|
||||
specular_ref = specular_reflection;
|
||||
emission = light_emission;
|
||||
shininess = shine;
|
||||
}
|
||||
|
||||
void JGL::Material::SetActiveMaterial(const Material& material) {
|
||||
Vector4 ambient = { material.ambient_ref.RN(), material.ambient_ref.BN(), material.ambient_ref.GN(), material.ambient_ref.AN() };
|
||||
Vector4 diffuse = { material.diffuse_ref.RN(), material.diffuse_ref.BN(), material.diffuse_ref.GN(), material.diffuse_ref.AN() };
|
||||
Vector4 specular = { material.specular_ref.RN(), material.specular_ref.BN(), material.specular_ref.GN(), material.specular_ref.AN() };
|
||||
Vector4 emission = { material.emission.RN(), material.emission.BN(), material.emission.GN(), material.emission.AN() };
|
||||
|
||||
// Determine which faces we're going to apply this material to.
|
||||
GLenum face = GL_FRONT;
|
||||
if (glIsEnabled(GL_CULL_FACE)) {
|
||||
GLint current; glGetIntegerv(GL_CULL_FACE_MODE, ¤t);
|
||||
if (current == GL_FRONT)
|
||||
face = GL_BACK;
|
||||
}
|
||||
|
||||
glMaterialfv(face, GL_AMBIENT, ambient.ptr());
|
||||
glMaterialfv(face, GL_DIFFUSE, diffuse.ptr());
|
||||
glMaterialfv(face, GL_SPECULAR, specular.ptr());
|
||||
glMaterialfv(face, GL_EMISSION, emission.ptr());
|
||||
glMaterialf(face, GL_SHININESS, material.shininess);
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ void JGL::RenderTarget::SetActiveGLRenderTarget(const RenderTarget& render_targe
|
||||
glViewport(0,0, render_target.GetDimensions().x, render_target.GetDimensions().y);
|
||||
}
|
||||
|
||||
Vector2 JGL::RenderTarget::GetDimensions() const {
|
||||
Vector2i JGL::RenderTarget::GetDimensions() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -71,12 +71,12 @@ JGL::RenderTarget::RenderTarget(const JGL::Texture* texture, const Color4& clear
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
this->clear_color = clear_color;
|
||||
this->size = texture->GetDimensions();
|
||||
this->size = {(int) size.x, (int) size.y};
|
||||
this->texture = texture;
|
||||
texture_created_by_us = false;
|
||||
}
|
||||
|
||||
JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
|
||||
JGL::RenderTarget::RenderTarget(const Vector2i& size, const Color4& clear_color, bool use_depth, MSAA_SAMPLE_RATE sample_rate) {
|
||||
if (size.x < 1 || size.y < 1)
|
||||
Logger::Fatal("Creating a render target where the color attachment is empty?");
|
||||
|
||||
@@ -124,7 +124,7 @@ JGL::RenderTarget::RenderTarget(const Vector2& size, const Color4& clear_color,
|
||||
SetMSAAEnabled(sample_rate);
|
||||
}
|
||||
|
||||
std::vector<GLfloat> JGL::RenderTarget::GetData() const {
|
||||
std::vector<GLfloat> JGL::RenderTarget::GetPixels() const {
|
||||
std::vector<GLfloat> data(GetDimensions().x * GetDimensions().y * 4);
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
|
||||
@@ -132,12 +132,11 @@ std::vector<GLfloat> JGL::RenderTarget::GetData() const {
|
||||
glReadPixels(0, 0, GetDimensions().x, GetDimensions().y, GL_RGBA, GL_FLOAT, data.data());
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Resize(const Vector2& new_size) {
|
||||
void JGL::RenderTarget::Resize(const Vector2i& new_size) {
|
||||
if (!texture_created_by_us)
|
||||
Logger::Fatal("Resizing a texture that already existed?");
|
||||
Logger::Error("Resizing a Render Target that does not own it's texture?");
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLfloat old_clear_color[4];
|
||||
@@ -145,8 +144,8 @@ void JGL::RenderTarget::Resize(const Vector2& new_size) {
|
||||
glGetIntegerv(GL_VIEWPORT, old_viewport);
|
||||
glGetFloatv(GL_COLOR_CLEAR_VALUE, old_clear_color);
|
||||
|
||||
/* If what was previously not part of the renderable area is big enough to
|
||||
* just set the new size without reading data back */
|
||||
/* If what was previously not part of the renderable area is big enough
|
||||
* to just set the new size. */
|
||||
if (new_size.x <= texture->GetDimensions().x && new_size.y <= texture->GetDimensions().y) {
|
||||
size = new_size;
|
||||
|
||||
@@ -182,7 +181,7 @@ void JGL::RenderTarget::Resize(const Vector2& new_size) {
|
||||
glClearColor(cc.RedChannelNormalized(), cc.GreenChannelNormalized(), cc.BlueChannelNormalized(), cc.AlphaChannelNormalized());
|
||||
glViewport(0,0, size.x, size.y);
|
||||
|
||||
texture = new Texture(Vector2((float) biggest, (float) biggest));
|
||||
texture = new Texture(Vector2(biggest, biggest));
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->GetGLTextureHandle(), 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
@@ -204,7 +203,7 @@ JGL::RenderTarget::~RenderTarget() {
|
||||
delete texture;
|
||||
}
|
||||
|
||||
bool JGL::RenderTarget::TextureCreatedByRenderTarget() const {
|
||||
bool JGL::RenderTarget::OwnsTexture() const {
|
||||
return texture_created_by_us;
|
||||
}
|
||||
|
||||
@@ -216,19 +215,20 @@ bool JGL::RenderTarget::MSAAEnabled() const {
|
||||
return msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
bool JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
// If we'd be setting the same sample_rate we already have.
|
||||
if (sample_rate == msaa_sample_rate)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// If we'd be rendering onto a texture and not a plain render target we don't want this.
|
||||
if (!TextureCreatedByRenderTarget())
|
||||
return;
|
||||
if (!OwnsTexture())
|
||||
return false;
|
||||
|
||||
// Remove it if they request no msaa or if what they requested is different than what they already have.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE || msaa_sample_rate != MSAA_SAMPLE_RATE::MSAA_NONE) {
|
||||
if(using_depth)
|
||||
glDeleteRenderbuffers(1, &msaa_depth_buffer);
|
||||
|
||||
glDeleteRenderbuffers(1, &msaa_render_buffer);
|
||||
glDeleteFramebuffers(1, &msaa_framebuffer_object);
|
||||
|
||||
@@ -239,7 +239,7 @@ void JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
|
||||
// Only return here if they specifically requested no MSAA. else continue to change mode.
|
||||
if (sample_rate == MSAA_SAMPLE_RATE::MSAA_NONE)
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
@@ -271,11 +271,11 @@ void JGL::RenderTarget::SetMSAAEnabled(JGL::MSAA_SAMPLE_RATE sample_rate) {
|
||||
|
||||
if (failure)
|
||||
SetMSAAEnabled(MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
return failure;
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit() const {
|
||||
if (MSAAEnabled() && TextureCreatedByRenderTarget()) {
|
||||
|
||||
void JGL::RenderTarget::MSAABlit() const {
|
||||
if (MSAAEnabled() && OwnsTexture()) {
|
||||
// Save the GL state.
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
GLint current_draw_fbo = 0;
|
||||
@@ -308,10 +308,9 @@ void JGL::RenderTarget::Blit() const {
|
||||
}
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination) {
|
||||
//TODO allow blitting onto an FBO that is bigger but not smaller.
|
||||
if (source.size != destination->size)
|
||||
Logger::Warning("Blitting a render target but they're not the same size?");
|
||||
void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget* destination, const Vector2i& position) {
|
||||
if (source.GetDimensions().x > destination->GetDimensions().x || source.GetDimensions().y > destination->GetDimensions().y)
|
||||
Logger::Warning("Blitting a Render Target onto another Render Target but the destination Render Target is too small?");
|
||||
|
||||
// Save the GL state.
|
||||
GLuint current_fbo = GetActiveGLFramebufferHandle();
|
||||
@@ -323,7 +322,7 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
|
||||
// Draw the contents of one into the other.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, source.size.x, source.size.y, 0, 0, source.size.x, source.size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBlitFramebuffer(0, 0, source.size.x, source.size.y, position.x, position.y, position.x + source.size.x, position.y + source.size.y, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Put the GL state back.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, current_read_fbo);
|
||||
@@ -331,9 +330,15 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
void JGL::RenderTarget::Blit(const Texture* source, RenderTarget* destination, const Vector2i& position) {
|
||||
auto temp = new RenderTarget(source);
|
||||
Blit(*temp, destination);
|
||||
delete temp;
|
||||
}
|
||||
|
||||
// To avoid repeatedly allocating and deallocating.
|
||||
JGL::RenderTarget* pixel = nullptr;
|
||||
void JGL::RenderTarget::Blit(const Color4& color, const Vector2& position, JGL::RenderTarget* destination) {
|
||||
void JGL::RenderTarget::Blit(const Color4& color, const Vector2i& position, JGL::RenderTarget* destination) {
|
||||
if (position.x > destination->size.x || position.y > destination->size.y)
|
||||
Logger::Warning("Blitting outside of the renderable area of the destination.");
|
||||
|
||||
|
@@ -189,4 +189,24 @@ namespace JGL
|
||||
// In 99% of cases you wouldn't want this. But in this scenario we do.
|
||||
operator delete(this_texture);
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture* textures, const size_t& texture_count) {
|
||||
float length = 0;
|
||||
float biggest_y = 0;
|
||||
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
if (biggest_y < textures[i].texture_size.y)
|
||||
biggest_y = textures[i].texture_size.y;
|
||||
length += textures[i].texture_size.x;
|
||||
}
|
||||
|
||||
auto* result = new Texture(Vector2(length, biggest_y));
|
||||
auto render_target = RenderTarget(result);
|
||||
|
||||
int next_x = 0;
|
||||
for (int i = 0; i < texture_count; i++) {
|
||||
RenderTarget::Blit(&textures[i], &render_target, Vector2i(next_x, 0));
|
||||
next_x += textures[i].GetDimensions().x;
|
||||
}
|
||||
}
|
||||
}
|
@@ -170,6 +170,10 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
if (element_array_buffer)
|
||||
JGL::Logger::Warning("Getting data as GLfloat but the buffer data is GLuint?");
|
||||
|
||||
bool vertex_array_enabled = glIsEnabled(GL_VERTEX_ARRAY);
|
||||
if (!vertex_array_enabled)
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
GLint current_buffer = 0;
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, ¤t_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, list_handle);
|
||||
@@ -184,6 +188,8 @@ std::vector<GLfloat> JGL::VRamList::GetDataF() const {
|
||||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, current_buffer);
|
||||
|
||||
if (!vertex_array_enabled)
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -289,7 +295,6 @@ JGL::VRamList::VRamList(const JGL::VRamList& rhs) {
|
||||
if (rhs.element_array_buffer) {
|
||||
auto data_array = rhs.GetDataUI();
|
||||
this->load(data_array.data(), data_array.size());
|
||||
return;
|
||||
}
|
||||
|
||||
auto data_array = rhs.GetDataF();
|
||||
|
@@ -1,20 +1,23 @@
|
||||
#include <JGL/types/VertexArray.h>
|
||||
#include <JGL/logger/logger.h>
|
||||
#include "../internals/include/WavefrontOBJ.h"
|
||||
#include "../internals/include/AMO.h"
|
||||
|
||||
using namespace JGL;
|
||||
|
||||
VRamList VertexArray::GetVertices() const {
|
||||
const VRamList* VertexArray::GetVertices() const {
|
||||
return vertices;
|
||||
}
|
||||
|
||||
VRamList VertexArray::GetIndices() const {
|
||||
const VRamList* VertexArray::GetIndices() const {
|
||||
return indices;
|
||||
}
|
||||
|
||||
JGL::VRamList VertexArray::GetNormals() const {
|
||||
const VRamList* VertexArray::GetNormals() const {
|
||||
return normals;
|
||||
}
|
||||
|
||||
VRamList VertexArray::GetTextureCoordinates() const {
|
||||
const VRamList* VertexArray::GetTextureCoordinates() const {
|
||||
return texture_coordinates;
|
||||
}
|
||||
|
||||
@@ -144,48 +147,43 @@ VertexArray::VertexArray(const Vector3* vertex_positions, const long& vp_length,
|
||||
const Normal* vertex_normals, const long& vn_length, const TextureCoordinate* texture_coordinates, const long& vt_length) {
|
||||
|
||||
// TODO decimator. This is a total waste of memory as it sits.
|
||||
vertices = VRamList(vertex_positions, vp_length);
|
||||
this->vertices = new VRamList(vertex_positions, vp_length);
|
||||
|
||||
local_vertices.resize(vp_length);
|
||||
memcpy(local_vertices.data(), vertex_positions, sizeof(Vector3) * vp_length);
|
||||
|
||||
if (vertex_indices && vi_length) {
|
||||
indices = VRamList(vertex_indices, vi_length);
|
||||
indices = new VRamList(vertex_indices, vi_length);
|
||||
local_indices.resize(vi_length);
|
||||
memcpy(local_indices.data(), vertex_indices, sizeof(unsigned int) * vi_length);
|
||||
}
|
||||
|
||||
if (vertex_normals && vn_length) {
|
||||
normals = VRamList(vertex_normals, vn_length);
|
||||
normals = new VRamList(vertex_normals, vn_length);
|
||||
local_normals.resize(vn_length);
|
||||
memcpy(local_normals.data(), vertex_indices, sizeof(Normal) * vn_length);
|
||||
}
|
||||
|
||||
if (texture_coordinates && vt_length) {
|
||||
this->texture_coordinates = VRamList(texture_coordinates, vt_length);
|
||||
local_normals.resize(vt_length);
|
||||
this->texture_coordinates = new VRamList(texture_coordinates, vt_length);
|
||||
local_texture_coordinates.resize(vt_length);
|
||||
memcpy(local_texture_coordinates.data(), texture_coordinates, sizeof(TextureCoordinate) * vt_length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VertexArray::VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices,
|
||||
const std::vector<Normal>& vertex_normals, const std::vector<TextureCoordinate>& texture_coordinates) {
|
||||
vertices = VRamList(vertex_positions.data(), vertex_positions.size());
|
||||
local_vertices = vertex_positions;
|
||||
|
||||
if (!vertex_indices.empty()) {
|
||||
indices = VRamList(vertex_indices.data(), vertex_indices.size());
|
||||
local_indices = vertex_indices;
|
||||
}
|
||||
|
||||
if (!vertex_normals.empty()) {
|
||||
normals = VRamList(vertex_normals.data(), vertex_normals.size());
|
||||
local_normals = vertex_normals;
|
||||
}
|
||||
|
||||
if (!texture_coordinates.empty()){
|
||||
this->texture_coordinates = VRamList(texture_coordinates.data(), texture_coordinates.size());
|
||||
local_texture_coordinates = texture_coordinates;
|
||||
}
|
||||
VertexArray::VertexArray(const std::vector<Vertex>& vertex_positions, const std::vector<unsigned int>& vertex_indices, const std::vector<Normal>& vertex_normals, const std::vector<TextureCoordinate>& texture_coordinates) {
|
||||
*this = VertexArray(vertex_positions.data(), vertex_positions.size(), vertex_indices.data(), vertex_indices.size(), vertex_normals.data(), vertex_normals.size(), texture_coordinates.data(), texture_coordinates.size());
|
||||
}
|
||||
|
||||
bool VertexArray::Static() {
|
||||
return animations.empty();
|
||||
}
|
||||
|
||||
VertexArray VertexArray::LoadWavefrontOBJ(const std::string& file_text) {
|
||||
return JGL::LoadWavefrontOBJ(file_text);
|
||||
}
|
||||
|
||||
VertexArray VertexArray::LoadAMO(const std::string& file_text) {
|
||||
//return JGL::LoadAMO(file_text);
|
||||
}
|
||||
|
Reference in New Issue
Block a user