Compare commits

...

16 Commits

Author SHA1 Message Date
1597662e2e Just pushing what I have.
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 47s
2024-12-22 00:38:16 -05:00
0823730e82 Better Wavefront OBJ loader.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m35s
2024-12-20 10:12:11 -05:00
6cbd369d51 Fixed one side of the cube looking weird
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m9s
How I understand it, When lighting a cube specifically. It will always look weird because it's just not enough information 🤷
2024-12-18 11:11:26 -05:00
926ae06834 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m59s
2024-12-17 21:40:06 -05:00
d5fd68eba8 Light test 1 2024-12-17 21:39:58 -05:00
08b2dfbecc Update internals.h
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m20s
msvc
2024-12-17 13:58:07 -05:00
e33a51b7d4 Materials.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m18s
2024-12-16 22:25:36 -05:00
7f5ee5cf0c Pushing what I have.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m57s
2024-12-16 16:33:16 -05:00
401e2c0883 Minor edits.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m37s
2024-12-09 18:46:24 -05:00
e5bdc441d1 Merge branch 'master' of https://git.redacted.cc/Josh/JGL
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m45s
2024-12-09 14:21:44 -05:00
392375e56c small refactor 2024-12-09 14:21:34 -05:00
b007c78cfe Roll back to code from prelease-41. Fix segfault later
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m0s
2024-12-09 13:15:46 -05:00
512dc3cb1a Separate J2D and J3D.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m10s
2024-12-08 10:30:03 -05:00
a22a83d2f8 Fix out-of-date ReWindow API usage.
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 2m0s
2024-12-06 12:05:29 -05:00
76cd48c9b7 Update Font.cpp
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 6m31s
Fixed several cases where the font index would be incorrect.
2024-12-06 11:34:38 -05:00
38bb1b22ce Include Jupiteroid as a default font
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m41s
2024-12-04 16:22:14 -05:00
31 changed files with 11377 additions and 1912 deletions

View File

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

38
assets/models/cube.obj Normal file
View 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

View File

@@ -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
@@ -336,7 +354,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 +375,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 +383,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 +392,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 +669,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();

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,90 @@ 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.
/// 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);
/// 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);
/// Blit a single pixel onto a Render Target.
/// 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);
/// @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();
};

View File

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

View File

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

View File

@@ -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,12 @@ 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);
};
using namespace JGL;
static VertexArray Animate(int animation_id, float animation_time);
static VertexArray Animate(const AnimationState& anim_state);

View File

@@ -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,38 @@ 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.obj");
if (!file.is_open())
return -1;
std::stringstream buffer;
buffer << file.rdbuf();
std::string file_text = buffer.str();
file.close();
//std::cout << "File contents:\n" << file_text << std::endl;
auto result = VertexArray::LoadWavefrontOBJ(file_text);
ReWindow::Logger::Error.EnableConsole(false);
ReWindow::Logger::Warning.EnableConsole(false);
ReWindow::Logger::Debug.EnableConsole(false);
while (window->IsAlive())
window->ManagedRefresh();
return 0;
//for (const auto& v3 : result)
//std::cout << v3.x << " " << v3.y << " " << v3.z << std::endl;
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace JGL {
class VertexArray;
VertexArray LoadWavefrontOBJ(const std::string& file_text);
}

View 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

File diff suppressed because it is too large Load Diff

View 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());
}
}

View File

@@ -0,0 +1,203 @@
#include "../include/WavefrontOBJ.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<std::array<Vector3, 3>, unsigned long> ParseFaceData(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 = ParseFaceData(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());
}

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

1118
src/renderer/J2D.cpp Normal file

File diff suppressed because it is too large Load Diff

608
src/renderer/J3D.cpp Normal file
View 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);
}

View File

@@ -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();

View File

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

View File

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

View File

@@ -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, &current);
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);
}

View File

@@ -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;
@@ -309,7 +309,6 @@ 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?");
@@ -333,7 +332,7 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
// 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.");

View File

@@ -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, &current_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();

View File

@@ -1,20 +1,22 @@
#include <JGL/types/VertexArray.h>
#include <JGL/logger/logger.h>
#include "../internals/include/WavefrontOBJ.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 +146,39 @@ 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);
}