Compare commits
7 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
122644a013 | |||
|
641f2de8d0 | ||
6618aa5e6b | |||
3970aa2718 | |||
fb5ca55fda | |||
bcca6285af | |||
f8395726cd |
@@ -22,17 +22,17 @@ CPMAddPackage(
|
||||
|
||||
CPMAddPackage(
|
||||
NAME J3ML
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/Release-3.4.zip
|
||||
URL https://git.redacted.cc/josh/j3ml/archive/3.4.3.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME ReWindow
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-21.zip
|
||||
URL https://git.redacted.cc/Redacted/ReWindow/archive/Prerelease-26.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME GLAD
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fboV2.zip
|
||||
URL https://git.redacted.cc/Redacted/glad/archive/v2.1ext_fbo_depthtexture_shadow.zip
|
||||
)
|
||||
|
||||
CPMAddPackage(
|
||||
|
@@ -53,7 +53,7 @@ JGL::J2D::End();
|
||||
```
|
||||
## Requirements
|
||||
|
||||
An OpenGL 2.1 or newer accelerator that supports the `GL_ARB_framebuffer_object` extension or
|
||||
An OpenGL 2.1 or newer accelerator with at-least two texture mappers that supports the `GL_ARB_framebuffer_object` extension or
|
||||
an implementation that can provide those features through alternative means (common on ArmSoC and Risc-V).
|
||||
|
||||
## Compatability
|
||||
|
BIN
assets/sprites/alpha_mask.png
Normal file
BIN
assets/sprites/alpha_mask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 942 B |
BIN
assets/sprites/alpha_mask_2.png
Normal file
BIN
assets/sprites/alpha_mask_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
@@ -64,8 +64,7 @@ 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(Light*, size_t size);
|
||||
void LightArray(std::vector<Light> lights);
|
||||
void LightArray(LightBase*, size_t light_count);
|
||||
|
||||
/// Plots a single pixel on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -79,7 +78,7 @@ namespace JGL::J2D {
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param points A set of x,y points to render.
|
||||
/// @param radius The size of the point to plot. By default, a single pixel.
|
||||
void DrawPoints(const Color4& color, const Vector2* points, int num_points, float radius = 1.f);
|
||||
void DrawPoints(const Color4& color, const Vector2* points, int point_count, float radius = 1.f);
|
||||
|
||||
/// Plots a line (segment) on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see classes Color3, Color4.
|
||||
@@ -89,6 +88,27 @@ 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 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.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param spacing The distance between each point (px)
|
||||
/// @param thickness The width at which to render the line.
|
||||
/// @note With diagonal lines, the distance between points can differ by one px.
|
||||
void DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 1.f, float thickness = 1.f);
|
||||
void DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 1.f, float thickness = 1.f);
|
||||
|
||||
/// 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.
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param spacing The distance between each point (px)
|
||||
/// @param dash_length The length of each dash making up the line.
|
||||
/// @param thickness The width at which to render the line.
|
||||
/// @note With diagonal lines, the distance between dashes can differ by one px.
|
||||
void DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
|
||||
void DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing = 4.f, float dash_length = 6.f, float thickness = 1.f);
|
||||
|
||||
/// Draws a line with a color gradient that transitions across it.
|
||||
/// @param color_a A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param color_b A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -96,7 +116,7 @@ namespace JGL::J2D {
|
||||
/// @param B The end point of the line segment.
|
||||
/// @param thickness The width at which to render the line.
|
||||
void DrawGradientLine(const Color4& color_a, const Color4& color_b, const Vector2& A, const Vector2& B, float thickness = 1);
|
||||
void DrawGradientLine(const Color4& color_a, const Color4& color_b, float x, float y, float w, float h, float thickness = 1);
|
||||
void DrawGradientLine(const Color4& color_a, const Color4& color_b, float x1, float y1, float x2, float y2, float thickness = 1);
|
||||
|
||||
/// Draws an outline of a rectangle on the screen.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -203,6 +223,26 @@ namespace JGL::J2D {
|
||||
float originX = 0, float originY = 0,float scaleX = 1, float scaleY = 1,
|
||||
const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
|
||||
/// Draws a sprite to the screen by passing a G̶L̶u̶i̶n̶t̶ JGL Texture that represents a handle to a loaded texture.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param alpha_mask A texture which determines how much of the sprite you can see. Grayscale image exported as "8bpc RGBA".
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
/// @param origin The center point around which the image should have all transformations applied to it.
|
||||
/// @param scale The scale transformation for the image. X and Y axis are independently-scalable.
|
||||
/// @param rad_rotation A float representing the rotation of the sprite where 0 is no rotation and 1 is the maximum rotation (would look the same as 0).
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
/// @param inversion @see Direction
|
||||
/// @see class Texture
|
||||
void DrawSprite(const Texture& texture, const Texture& alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation = 0, const Vector2& origin = Vector2(0,0),
|
||||
const Vector2& scale = Vector2(1,1), const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
|
||||
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
void DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation = 0, float originX = 0, float originY = 0,
|
||||
float scaleX = 1, float scaleY = 1, const Color4& color = Colors::White, Direction inversion = Direction::None);
|
||||
|
||||
/// Draws a piece of a sprite to the screen, similar to DrawSprite.
|
||||
/// @param texture A texture instance to be displayed.
|
||||
/// @param position The point at which to draw the sprite (from the top-left down).
|
||||
@@ -319,6 +359,13 @@ namespace JGL::J2D {
|
||||
|
||||
/// Drawing functions for primitive 3D Shapes.
|
||||
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.
|
||||
/// @note More than 8 lights will cause an error to be printed.
|
||||
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);
|
||||
|
||||
/// Helper function to conveniently change the Field-Of-View.
|
||||
void ChangeFOV(float fov);
|
||||
@@ -573,7 +620,7 @@ namespace JGL::J3D {
|
||||
/// @param position The center-position of the oriented bounding box.
|
||||
/// @param radii The radii along x,y,z axes to size the bounding box.
|
||||
/// @param orientation The rotation in 3D space of the OBB.
|
||||
void FillOBB(const Color4& color, const Vector3& position, const Vector3& radii, const EulerAngle& orientation);
|
||||
void FillOBB(const Color4& color, const Vector3& position, const Vector3& radii, const EulerAngleXYZ& orientation);
|
||||
|
||||
/// Draws a solid oriented bounding box in 3D space.
|
||||
/// @param color A 3-or-4 channel color value. @see class Color3, class Color4
|
||||
@@ -605,7 +652,7 @@ 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 EulerAngle& 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, const EulerAngleXYZ& angle = {0, 0, 0}, bool draw_back_face = false);
|
||||
|
||||
/// Draws a string of text in 3D space that is always facing the exact direction of the camera projection.
|
||||
void DrawBillboardString();
|
||||
|
@@ -1,30 +1,65 @@
|
||||
#pragma once
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/DirectionVector.hpp>
|
||||
#include <J3ML/Geometry/Frustum.hpp>
|
||||
#include <Color4.hpp>
|
||||
|
||||
namespace JGL {
|
||||
class Light;
|
||||
class OmnidirectionalLight2D;
|
||||
class PointLight2D;
|
||||
class LightBase;
|
||||
class PointLight;
|
||||
class SpotLight;
|
||||
}
|
||||
|
||||
class JGL::Light {
|
||||
private:
|
||||
/// W in position seems to determine whether or not the light is omni-directional. 1 = omni 0 = point.
|
||||
/// Position is un-normalized screen space. For ex 500, 500, 1 for a light coming from where you're sitting.
|
||||
class JGL::LightBase {
|
||||
protected:
|
||||
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;
|
||||
public:
|
||||
Light(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular);
|
||||
Vector3 GetNormalizedSceenSpaceCoordinates() const;
|
||||
[[nodiscard]] Vector3 GetPosition() const;
|
||||
[[nodiscard]] Color4 GetAmbient() const;
|
||||
[[nodiscard]] Color4 GetDiffuse() const;
|
||||
[[nodiscard]] Color4 GetSpecular() const;
|
||||
|
||||
[[nodiscard]] float GetConstantAttenuation() const;
|
||||
[[nodiscard]] float GetLinearAttenuation() const;
|
||||
[[nodiscard]] float GetQuadraticAttenuation() const;
|
||||
public:
|
||||
/// Runs a calculation to determine the lights influence on a given point in 3D space.
|
||||
/// @note 0 would be no impact, 1 would be the light is at the same position.
|
||||
[[nodiscard]] virtual float GetAttenuationAtPosition(const Vector3& pos) const { return 0; }
|
||||
public:
|
||||
virtual ~LightBase() = default;
|
||||
};
|
||||
|
||||
class JGL::OmnidirectionalLight2D {
|
||||
private:
|
||||
/// Omni-directional lights.
|
||||
class JGL::PointLight : public LightBase {
|
||||
public:
|
||||
OmnidirectionalLight2D(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular);
|
||||
|
||||
[[nodiscard]] float GetAttenuationAtPosition(const Vector3& pos) const override;
|
||||
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.
|
||||
class JGL::SpotLight : public LightBase {
|
||||
protected:
|
||||
Matrix3x3 orientation;
|
||||
float exponent;
|
||||
float cut;
|
||||
public:
|
||||
/// Create a spotlight in 3D space.
|
||||
/// @param position The position of the light in 3D space.
|
||||
/// @param ro_mat Orientation of the light in 3D space.
|
||||
/// @param cone_size_degrees The size of the cone.
|
||||
/// @param exponent How focused the beam should be, Higher is more focused, Lower is less.
|
||||
/// @param ambient How much this light should effect the ambient light of the scene.
|
||||
/// @param diffuse
|
||||
/// @param specular How much this light should effect specular highlights of objects being influenced by it.
|
||||
SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation = 1, float linear_attenuation = 0, float quadratic_attenuation = 0);
|
||||
};
|
18
include/JGL/types/ShadowMap.h
Normal file
18
include/JGL/types/ShadowMap.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <JGL/types/RenderTarget.h>
|
||||
#include <JGL/types/Light.h>
|
||||
|
||||
namespace JGL {
|
||||
class ShadowMap;
|
||||
}
|
||||
|
||||
/// You render your scene with all the static objects from the perspective of each static light to a ShadowMap.
|
||||
/// Then, for shadow casters which move. Or lights that move. You only redraw that object from the perspective of each light.
|
||||
/// Some of the approaches I saw for this were disgusting - Redacted.
|
||||
|
||||
class JGL::ShadowMap {
|
||||
private:
|
||||
RenderTarget shadow_map;
|
||||
private:
|
||||
void Create(const LightBase* Light);
|
||||
};
|
69
main.cpp
69
main.cpp
@@ -98,9 +98,8 @@ Gizmo c({350, 300});
|
||||
Gizmo d({450, 250});
|
||||
|
||||
Texture* image;
|
||||
Texture* image2;
|
||||
Texture* image_mask;
|
||||
RenderTarget* j2d_render_target;
|
||||
RenderTarget* image2_render_target;
|
||||
|
||||
class JGLDemoWindow : public ReWindow::RWindow
|
||||
{
|
||||
@@ -108,7 +107,7 @@ public:
|
||||
void initGL() {
|
||||
camera = new Camera;
|
||||
|
||||
if (!JGL::Init(getSize(), 75, 100))
|
||||
if (!JGL::Init(GetSize(), 75, 100))
|
||||
Logger::Fatal("Initialization failed.");
|
||||
|
||||
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
||||
@@ -119,17 +118,13 @@ public:
|
||||
glDepthFunc(GL_LESS);
|
||||
glDepthMask(GL_TRUE);
|
||||
image = new Texture("assets/sprites/Re3D.png", TextureFilteringMode::BILINEAR);
|
||||
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
|
||||
j2d_render_target = new RenderTarget({540, 540}, {0,0,0,0}, false, MSAA_SAMPLE_RATE::MSAA_NONE);
|
||||
image2 = image;
|
||||
image2_render_target = new RenderTarget(image2);
|
||||
|
||||
J2D::Begin(image2_render_target);
|
||||
J2D::DrawString(Colors::Red, "TEST", 0, 16, 1, 16, FreeSans);
|
||||
J2D::FillRect(Colors::Blue, {0,0}, {4,4});
|
||||
J2D::End();
|
||||
//Texture::MultiplyByAlphaMask(*image, *image_mask);
|
||||
}
|
||||
|
||||
Vector3 textAngle = {0,0,0};
|
||||
EulerAngleXYZ textAngle = {0,0,0};
|
||||
float fov = 90;
|
||||
float sprite_radians = 0;
|
||||
bool fov_increasing = true;
|
||||
@@ -138,7 +133,7 @@ public:
|
||||
void display() {
|
||||
|
||||
float dt = 1.f / fps;
|
||||
JGL::Update(getSize());
|
||||
JGL::Update(GetSize());
|
||||
|
||||
if (fov_increasing)
|
||||
fov += 0.025;
|
||||
@@ -152,7 +147,7 @@ public:
|
||||
//J3D::ChangeFOV(fov);
|
||||
|
||||
sprite_radians += 0.005;
|
||||
textAngle.y += (1);
|
||||
textAngle.yaw += 1;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
@@ -184,7 +179,7 @@ public:
|
||||
|
||||
J2D::Begin(j2d_render_target, true);
|
||||
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
||||
J2D::DrawSprite(image2, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawSprite(image, {300, 400}, sprite_radians * 0.10f, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawMirrorSprite(image, {400, 300}, Direction::Horizontal | Direction::Vertical, sprite_radians, {0.5,0.5}, {1, 1}, Colors::White);
|
||||
J2D::DrawPartialSprite(image, {225, 300}, image->GetDimensions() * 0.25, image->GetDimensions() * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
|
||||
@@ -228,36 +223,38 @@ public:
|
||||
|
||||
J2D::Begin();
|
||||
J2D::DrawPartialRenderTarget(j2d_render_target, {0, 0}, {0,0}, {512, 512});
|
||||
//J2D::DrawSprite(j2d_render_target, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawSprite(image2_render_target, {300, 500}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
|
||||
//J2D::DrawSprite(, {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
|
||||
//J2D::DrawSprite( {0, 0}, 0, {0.5, 0.5}, {1,1}, Colors::White);
|
||||
J2D::End();
|
||||
|
||||
}
|
||||
|
||||
void OnRefresh(float elapsed) override {
|
||||
if (isKeyDown(Keys::RightArrow))
|
||||
if (IsKeyDown(Keys::RightArrow))
|
||||
camera->angle.y += 45.f * elapsed;
|
||||
if (isKeyDown(Keys::LeftArrow))
|
||||
if (IsKeyDown(Keys::LeftArrow))
|
||||
camera->angle.y -= 45.f * elapsed;
|
||||
if (isKeyDown(Keys::UpArrow))
|
||||
if (IsKeyDown(Keys::UpArrow))
|
||||
camera->angle.x -= 45.f * elapsed;
|
||||
if (isKeyDown(Keys::DownArrow))
|
||||
if (IsKeyDown(Keys::DownArrow))
|
||||
camera->angle.x += 45.f * elapsed;
|
||||
if (isKeyDown(Keys::Space))
|
||||
if (IsKeyDown(Keys::Space))
|
||||
camera->position.y += 1.f * elapsed;
|
||||
if (isKeyDown(Keys::LeftShift))
|
||||
if (IsKeyDown(Keys::LeftShift))
|
||||
camera->position.y -= 1.f * elapsed;
|
||||
|
||||
/* This is wrong of course. Just for testing purposes.
|
||||
if (isKeyDown(Keys::W))
|
||||
//This is wrong of course. Just for testing purposes.
|
||||
if (IsKeyDown(Keys::W))
|
||||
camera->position.z += 1.f * elapsed;
|
||||
if (isKeyDown(Keys::S))
|
||||
if (IsKeyDown(Keys::S))
|
||||
camera->position.z -= 1.f * elapsed;
|
||||
if (isKeyDown(Keys::A))
|
||||
if (IsKeyDown(Keys::A))
|
||||
camera->position.x += 1.f * elapsed;
|
||||
if (isKeyDown(Keys::D))
|
||||
if (IsKeyDown(Keys::D))
|
||||
camera->position.x -= 1.f * elapsed;
|
||||
*/
|
||||
|
||||
|
||||
auto mouse = GetMouseCoordinates();
|
||||
a.Update(mouse);
|
||||
@@ -268,11 +265,11 @@ public:
|
||||
int glError = glGetError();
|
||||
if (glError != GL_NO_ERROR)
|
||||
std::cout << glError << std::endl;
|
||||
glSwapBuffers();
|
||||
GLSwapBuffers();
|
||||
}
|
||||
|
||||
|
||||
void OnMouseButtonDown(const ReWindow::WindowEvents::MouseButtonDownEvent & ev) override
|
||||
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent & ev) override
|
||||
{
|
||||
RWindow::OnMouseButtonDown(ev);
|
||||
a.Grab();
|
||||
@@ -281,7 +278,7 @@ public:
|
||||
d.Grab();
|
||||
}
|
||||
|
||||
void OnMouseButtonUp(const ReWindow::WindowEvents::MouseButtonUpEvent & ev) override
|
||||
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent & ev) override
|
||||
{
|
||||
RWindow::OnMouseButtonUp(ev);
|
||||
a.Release();
|
||||
@@ -297,16 +294,16 @@ public:
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
||||
window->setRenderer(RenderingAPI::OPENGL);
|
||||
window->SetRenderer(RenderingAPI::OPENGL);
|
||||
window->Open();
|
||||
window->initGL();
|
||||
window->setResizable(true);
|
||||
window->setVsyncEnabled(false);
|
||||
window->SetResizable(true);
|
||||
window->SetVsyncEnabled(false);
|
||||
|
||||
while (window->isAlive()) {
|
||||
while (window->IsAlive()) {
|
||||
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
|
||||
window->pollEvents();
|
||||
window->refresh();
|
||||
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();
|
||||
|
226
src/JGL.cpp
226
src/JGL.cpp
@@ -32,6 +32,9 @@ bool wasBlendEnabled = false;
|
||||
bool wasColorArrayEnabled = false;
|
||||
GLint activeTextureUnit = 0;
|
||||
|
||||
std::array<const JGL::LightBase*, 8> J3D_Empty_Light_Array{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||
std::array<const JGL::LightBase*, 8> J3D_Required_Lights{};
|
||||
std::vector<const JGL::LightBase*> J3D_Light_Array{};
|
||||
float j3d_far_plane = 0;
|
||||
float j3d_fov = 0;
|
||||
Vector2 wS;
|
||||
@@ -64,6 +67,10 @@ namespace JGL {
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_framebuffer_object)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_depth_texture)
|
||||
return false;
|
||||
if (!GLAD_GL_ARB_shadow)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -101,8 +108,10 @@ namespace JGL {
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTextureUnit);
|
||||
activeTextureUnit = activeTextureUnit - GL_TEXTURE0;
|
||||
|
||||
if (activeTextureUnit != 0)
|
||||
if (activeTextureUnit != 0) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
if (glIsEnabled(GL_DEPTH_TEST))
|
||||
wasDepthTestEnabled = true,
|
||||
@@ -173,6 +182,10 @@ namespace JGL {
|
||||
if (!wasBlendEnabled)
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
//Select whatever texture mapper was selected before.
|
||||
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
||||
glClientActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
||||
|
||||
if (wasTexture2DEnabled)
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
@@ -182,9 +195,6 @@ namespace JGL {
|
||||
if (wasColorArrayEnabled)
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
//Select whatever texture_handle unit was selected before.
|
||||
glActiveTexture(GL_TEXTURE0 + activeTextureUnit);
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(oldColor);
|
||||
|
||||
@@ -228,6 +238,55 @@ namespace JGL {
|
||||
J2D::DrawLine(color, {x, y}, {w, h}, thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawDottedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float thickness) {
|
||||
float distance = Vector2::Distance(A, B);
|
||||
Vector2 direction = (B - A).Normalized();
|
||||
|
||||
unsigned int point_count = distance / spacing;
|
||||
std::vector<Vector2> points(point_count);
|
||||
|
||||
if (spacing > distance)
|
||||
Logger::Error("Drawing a dotted line that would have no dots?");
|
||||
|
||||
for (unsigned int i = 0; i < point_count; ++i)
|
||||
points[i] = A + direction * (i * spacing);
|
||||
|
||||
return J2D::DrawPoints(color, points.data(), points.size(), thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawDottedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float thickness) {
|
||||
return J2D::DrawDottedLine(color, {x1, y1}, {x2, y2}, spacing, thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawDashedLine(const Color4& color, const Vector2& A, const Vector2& B, float spacing, float dash_length, float thickness) {
|
||||
float distance = Vector2::Distance(A, B);
|
||||
Vector2 direction = (B - A).Normalized();
|
||||
float length_of_dash_and_gap = dash_length + spacing;
|
||||
unsigned int dash_count = distance / length_of_dash_and_gap;
|
||||
|
||||
if (spacing > distance)
|
||||
Logger::Error("Drawing a dashed line that would have no dashes?");
|
||||
|
||||
Vector2 A_current, B_current;
|
||||
for (unsigned int i = 0; i < dash_count; i++) {
|
||||
A_current = A + direction * (i * length_of_dash_and_gap);
|
||||
B_current = A_current + (direction * dash_length);
|
||||
J2D::DrawLine(color, A_current, B_current, thickness);
|
||||
}
|
||||
|
||||
// For the little piece at the end.
|
||||
float distance_left = distance - (dash_count * length_of_dash_and_gap);
|
||||
if (distance_left > 0) {
|
||||
A_current = A + direction * (dash_count * length_of_dash_and_gap);
|
||||
B_current = A_current + direction * std::min(dash_length, distance_left);
|
||||
J2D::DrawLine(color, A_current, B_current, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void J2D::DrawDashedLine(const Color4& color, float x1, float y1, float x2, float y2, float spacing, float dash_length, float thickness) {
|
||||
return J2D::DrawDashedLine(color, {x1, y1}, {x2, y2}, spacing, dash_length, thickness);
|
||||
}
|
||||
|
||||
void J2D::DrawGradientLine(const Color4& color1, const Color4& color2, const Vector2& A, const Vector2& B, float thickness) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
@@ -393,7 +452,113 @@ namespace JGL {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
void J2D::DrawPartialRenderTarget(const JGL::RenderTarget & rt, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size,
|
||||
void J2D::DrawSprite(const Texture& texture, const Texture &alpha_mask, const Vector2& position, float rad_rotation,
|
||||
const Vector2& origin, const Vector2& scale,const Color4& color, JGL::Direction inversion) {
|
||||
if (!inJ2D)
|
||||
Logger::Error("Drawing J2D element before J2D begin.");
|
||||
|
||||
if (texture.GetDimensions() != alpha_mask.GetDimensions())
|
||||
Logger::Warning("The alpha mask and the texture are not the same size.");
|
||||
|
||||
const Vector2 size = texture.GetDimensions();
|
||||
|
||||
std::array<Vector2, 4> textureCoordinates{};
|
||||
if (texture.GetFlags() & INVERT_Y)
|
||||
textureCoordinates = {Vector2(0, 1), Vector2(0, 0), Vector2(1, 0), Vector2(1, 1)};
|
||||
else
|
||||
textureCoordinates = {Vector2(0, 0), Vector2(0, 1), Vector2(1, 1), Vector2(1, 0)};
|
||||
|
||||
// TODO: Kind of a mess, refactor to be more sensible later.
|
||||
// Factors in scaling and origin correctly.
|
||||
// i.e. to render at 2x size, from the center, at coords XY, use {2, 2} scale, and {0.5, 0.5} offset.
|
||||
const Vector2 offset = origin * size;
|
||||
Vector2 pos2 = position;
|
||||
Vector2 scaled_size = scale * size;
|
||||
Vector2 size2 = scaled_size;
|
||||
float cos_theta = std::cos(rad_rotation);
|
||||
float sin_theta = std::sin(rad_rotation);
|
||||
|
||||
std::array<Vector2, 4> vertices =
|
||||
{
|
||||
pos2, // Top-left vertex
|
||||
{pos2.x, pos2.y + size2.y}, // Bottom-left
|
||||
{pos2.x + size2.x, pos2.y + size2.y}, // Bottom-right
|
||||
{pos2.x + size2.x, pos2.y} // Top-right
|
||||
};
|
||||
|
||||
//Rotate the vertices about the origin by float rad_rotation.
|
||||
if (rad_rotation != 0)
|
||||
for (auto& v: vertices)
|
||||
v = {(v.x - pos2.x - offset.x * scale.x) * cos_theta - (v.y - pos2.y - offset.y * scale.y) * sin_theta +
|
||||
pos2.x + offset.x * scale.x,
|
||||
(v.x - pos2.x - offset.x * scale.x) * sin_theta + (v.y - pos2.y - offset.y * scale.y) * cos_theta +
|
||||
pos2.y + offset.y * scale.y
|
||||
};
|
||||
|
||||
if (inversion == Direction::Vertical)
|
||||
std::swap(textureCoordinates[0], textureCoordinates[1]),
|
||||
std::swap(textureCoordinates[3], textureCoordinates[2]);
|
||||
if (inversion == Direction::Horizontal)
|
||||
std::swap(textureCoordinates[0], textureCoordinates[3]),
|
||||
std::swap(textureCoordinates[1], textureCoordinates[2]);
|
||||
|
||||
|
||||
glColor4ubv(color.ptr());
|
||||
|
||||
// Texture 0.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.GetGLTextureHandle());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
|
||||
|
||||
// Texture 1.
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glClientActiveTexture(GL_TEXTURE1);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, alpha_mask.GetGLTextureHandle());
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Vector2), vertices.data());
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Vector2), textureCoordinates.data());
|
||||
|
||||
// Draw.
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
|
||||
// Reset Texture 1.
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
// Reset Texture 0.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glColor4fv(baseColor);
|
||||
}
|
||||
|
||||
void J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, const Vector2& position, float rad_rotation,
|
||||
const Vector2& origin, const Vector2& scale,const Color4& color, Direction inversion) {
|
||||
DrawSprite(*texture, *alpha_mask, position, rad_rotation, origin, scale, color, inversion);
|
||||
}
|
||||
|
||||
void J2D::DrawSprite(const Texture& texture, const Texture& alpha_mask, float positionX, float positionY, float rad_rotation,
|
||||
float originX, float originY,float scaleX, float scaleY,const Color4& color, Direction inversion) {
|
||||
DrawSprite(texture, alpha_mask, {positionX, positionY}, rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
|
||||
}
|
||||
|
||||
void J2D::DrawSprite(const Texture* texture, const Texture* alpha_mask, float positionX, float positionY, float rad_rotation,
|
||||
float originX, float originY,float scaleX, float scaleY,const Color4& color, Direction inversion) {
|
||||
DrawSprite(*texture, *alpha_mask, {positionX, positionY}, rad_rotation, {originX, originY}, {scaleX, scaleY}, color, inversion);
|
||||
}
|
||||
|
||||
void J2D::DrawPartialRenderTarget(const JGL::RenderTarget& rt, const Vector2& position, const Vector2& sub_texture_position, const Vector2& sub_texture_size,
|
||||
float rad_rotation, const Vector2& origin, const Vector2& scale, const Color4& color, JGL::Direction inversion) {
|
||||
|
||||
//Correct for the render-target being upside-down.
|
||||
@@ -999,7 +1164,18 @@ namespace JGL {
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// TODO We're going to need two-pass rendering for occlusion queries and for determining what lights to use for what object.
|
||||
// We'll do a pre-render pass where we render a *very* simple scene where each object is replaced by an AABB.
|
||||
// Then, For each object we get a result on whether it was actually visible or not.
|
||||
// For lights, We can get the closest point on the AABB to each light and see how much it would influence that point.
|
||||
// Finally, we decide what lights to have enabled for the objects which were not occluded based on influence and distance from the camera.
|
||||
// For objects that are *extremely* big, Like base level geometry, I'll have to use its collision map for this to look right. - Redacted.
|
||||
|
||||
#pragma region J3D
|
||||
|
||||
#pragma region internal_drawables
|
||||
#pragma endregion
|
||||
|
||||
std::array<GLfloat, 16> 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);
|
||||
@@ -1011,6 +1187,14 @@ namespace JGL {
|
||||
return result;
|
||||
}
|
||||
|
||||
float EffectOfLightOnPointIn3DSpace(const PointLight* light, const Vector3& position) {
|
||||
Vector3 light_pos = light->GetPosition();
|
||||
Vector3 vector_to_position = position - light_pos;
|
||||
float distance = vector_to_position.Length();
|
||||
|
||||
return 1.0f / (light->GetConstantAttenuation() + light->GetLinearAttenuation() * distance + light->GetQuadraticAttenuation() * distance * distance);
|
||||
}
|
||||
|
||||
void J3D::ChangeFOV(float fov) {
|
||||
j3d_fov = fov;
|
||||
}
|
||||
@@ -1019,6 +1203,17 @@ namespace JGL {
|
||||
j3d_far_plane = far_plane;
|
||||
}
|
||||
|
||||
void J3D::RequiredLight(const JGL::LightBase* light) {
|
||||
for (auto* i : J3D_Required_Lights)
|
||||
if (i == nullptr)
|
||||
i = light;
|
||||
}
|
||||
|
||||
void J3D::LightArray(const JGL::LightBase** lights, const size_t& light_count) {
|
||||
for (size_t i = 0; i < light_count; i++)
|
||||
J3D_Light_Array.push_back(lights[i]);
|
||||
}
|
||||
|
||||
void J3D::Begin() {
|
||||
|
||||
auto aspect = (float) wS.x / (float) wS.y;
|
||||
@@ -1062,6 +1257,12 @@ namespace JGL {
|
||||
else
|
||||
wasBlendEnabled = true;
|
||||
|
||||
// Reset the lights.
|
||||
J3D_Required_Lights = J3D_Empty_Light_Array;
|
||||
J3D_Light_Array = {};
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
||||
if (!inJ2D)
|
||||
inJ3D = true;
|
||||
else
|
||||
@@ -1087,6 +1288,21 @@ namespace JGL {
|
||||
if (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);
|
||||
}
|
||||
|
||||
J3D_Required_Lights = J3D_Empty_Light_Array;
|
||||
J3D_Light_Array = {};
|
||||
|
||||
//Put the draw color back how it was before.
|
||||
glColor4fv(oldColor);
|
||||
inJ3D = false;
|
||||
|
@@ -162,7 +162,7 @@ namespace JGL {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngle& angle, bool draw_back_face) {
|
||||
void J3D::DrawString(const Color4& color, const std::string& text, const Vector3& pos, float scale, u32 size, const Font& font, const EulerAngleXYZ& angle, bool draw_back_face) {
|
||||
// TODO: Determine the proper scale factor mathematically
|
||||
// This number was arrived at holistically.
|
||||
scale = scale * 0.002f;
|
||||
|
@@ -1,19 +1,64 @@
|
||||
#include <JGL/types/Light.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
JGL::Light::Light(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular) {
|
||||
JGL::PointLight::PointLight(const Vector3& position, const Color4& ambient, const Color4& diffuse, const Color4& specular, float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
|
||||
this->position = Vector4(position, 1.0f);
|
||||
this->ambient = ambient;
|
||||
this->diffuse = diffuse;
|
||||
this->specular = specular;
|
||||
this->constant_attenuation = constant_attenuation;
|
||||
this->linear_attenuation = linear_attenuation;
|
||||
this->quadratic_attenuation = quadratic_attenuation;
|
||||
}
|
||||
|
||||
Vector3 JGL::Light::GetNormalizedSceenSpaceCoordinates() const {
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
float JGL::PointLight::GetAttenuationAtPosition(const Vector3& pos) const {
|
||||
Vector3 light_pos = {position.x, position.y, position.z};
|
||||
Vector3 vector_to_position = pos - light_pos;
|
||||
float distance = vector_to_position.Length();
|
||||
|
||||
float normalized_x = 2.0f * (position.x - viewport[0]) / viewport[2] - 1.0f;
|
||||
float normalized_y = 2.0f * (position.y - viewport[1]) / viewport[3] - 1.0f;
|
||||
|
||||
return {normalized_x, normalized_y, position.z};
|
||||
return 1.0f / (GetConstantAttenuation() + GetLinearAttenuation() * distance + GetQuadraticAttenuation() * distance * distance);
|
||||
}
|
||||
|
||||
JGL::SpotLight::SpotLight(const Vector3& position, const Matrix3x3& ro_mat, float cone_size_degrees, float exponent, const Color4& ambient, const Color4& diffuse, const Color4& specular,
|
||||
float constant_attenuation, float linear_attenuation, float quadratic_attenuation) {
|
||||
this->position = Vector4(position, 1);
|
||||
//TODO RotationMatrix to "Normalized direction vector."
|
||||
orientation = ro_mat;
|
||||
this->cut = cone_size_degrees;
|
||||
this->exponent = exponent;
|
||||
this->ambient = ambient;
|
||||
this->diffuse = diffuse;
|
||||
this->specular = specular;
|
||||
this->constant_attenuation = constant_attenuation;
|
||||
this->linear_attenuation = linear_attenuation;
|
||||
this->quadratic_attenuation = quadratic_attenuation;
|
||||
}
|
||||
|
||||
Vector3 JGL::LightBase::GetPosition() const {
|
||||
return {position.x, position.y, position.z};
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetAmbient() const {
|
||||
return ambient;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetDiffuse() const {
|
||||
return diffuse;
|
||||
}
|
||||
|
||||
Color4 JGL::LightBase::GetSpecular() const {
|
||||
return specular;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetConstantAttenuation() const {
|
||||
return constant_attenuation;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetLinearAttenuation() const {
|
||||
return linear_attenuation;
|
||||
}
|
||||
|
||||
float JGL::LightBase::GetQuadraticAttenuation() const {
|
||||
return quadratic_attenuation;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -331,12 +331,14 @@ void JGL::RenderTarget::Blit(const JGL::RenderTarget& source, JGL::RenderTarget*
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
// To avoid repeatedly allocating and deallocating.
|
||||
JGL::RenderTarget* pixel = nullptr;
|
||||
void JGL::RenderTarget::Blit(const Color4& color, const Vector2& 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.");
|
||||
|
||||
Texture texture(Vector2(1,1));
|
||||
RenderTarget source(&texture,color);
|
||||
if (pixel == nullptr)
|
||||
pixel = new RenderTarget({1,1});
|
||||
|
||||
GLint current_draw_fbo = 0;
|
||||
GLint current_read_fbo = 0;
|
||||
@@ -348,13 +350,14 @@ void JGL::RenderTarget::Blit(const Color4& color, const Vector2& position, JGL::
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, ¤t_read_fbo);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_draw_fbo);
|
||||
|
||||
SetActiveGLRenderTarget(source);
|
||||
SetActiveGLRenderTarget(*pixel);
|
||||
glClearColor(color.RedChannelNormalized(), color.GreenChannelNormalized(), color.BlueChannelNormalized(), color.AlphaChannelNormalized());
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Invert so it's relative to the top left corner.
|
||||
int target_y = destination->size.y - position.y - 1;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer_object);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, pixel->framebuffer_object);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination->framebuffer_object);
|
||||
glBlitFramebuffer(0, 0, 1, 1, position.x, target_y, position.x + 1, target_y + 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
|
Reference in New Issue
Block a user