All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 5m11s
337 lines
12 KiB
C++
337 lines
12 KiB
C++
#include <JGL/JGL.h>
|
|
#include <ReWindow/types/Window.h>
|
|
#include <Colors.hpp>
|
|
#include <chrono>
|
|
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
|
#include <JGL/logger/logger.h>
|
|
#include <J3ML/Geometry/AABB.hpp>
|
|
#include <ReWindow/Logger.h>
|
|
#include <JGL/types/VertexArray.h>
|
|
#include <JGL/types/Shader.h>
|
|
|
|
using J3ML::LinearAlgebra::Vector2;
|
|
using namespace JGL::Fonts;
|
|
using namespace JGL;
|
|
using JGL::Font;
|
|
|
|
float fps = 0.0f;
|
|
|
|
/// A draggable 2D point that highlights when moused over and when clicked.
|
|
class Gizmo
|
|
{
|
|
public:
|
|
Gizmo() {}
|
|
Gizmo(const Vector2& pos) : position(pos) {}
|
|
bool dragging = false;
|
|
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)
|
|
dragging = true;
|
|
}
|
|
void Release() {
|
|
dragging = false;
|
|
}
|
|
|
|
void Update(const Vector2& mouse) {
|
|
if (dragging)
|
|
position = position.Lerp(mouse, lerp_rate);
|
|
|
|
hovered = mouse.Distance(position) < range;
|
|
}
|
|
|
|
void Draw() {
|
|
if (dragging)
|
|
J2D::DrawPoint(drag_color, position, drag_radius);
|
|
else if (hovered)
|
|
J2D::DrawPoint(hover_color, position, hover_radius);
|
|
else
|
|
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};
|
|
Vector3 angle = {0,0,0};
|
|
|
|
std::vector<GLfloat> lookAt(const Vector3& eye, const Vector3& center, const Vector3& up) {
|
|
Vector3 f = Vector3::Normalized((center - eye));
|
|
Vector3 upN = Vector3::Normalized(up);
|
|
Vector3 s = Vector3::Normalized(f.Cross(upN));
|
|
Vector3 u = Vector3::Normalized(s.Cross(f));
|
|
|
|
std::vector<GLfloat> result = {
|
|
s.x, u.x, -f.x, 0.0f,
|
|
s.y, u.y, -f.y, 0.0f,
|
|
s.z, u.z, -f.z, 0.0f,
|
|
-s.Dot(eye), -u.Dot(eye), f.Dot(eye), 1.0f
|
|
};
|
|
return result;
|
|
}
|
|
|
|
void render() {
|
|
glRotatef(angle.x,1.0f, 0.0f, 0.0f);
|
|
glRotatef(angle.y,0.0f, 1.0f, 0.0f);
|
|
glRotatef(angle.z,0.0f, 0.0f, 1.0f);
|
|
glMultMatrixf(lookAt({position.x, position.y, position.z}, {position.x, position.y, 100.f + position.z}, {0,1,0}).data());
|
|
}
|
|
};
|
|
|
|
Camera* camera;
|
|
using J3ML::LinearAlgebra::Matrix4x4;
|
|
|
|
struct point {
|
|
GLfloat x;
|
|
GLfloat y;
|
|
GLfloat s;
|
|
GLfloat t;
|
|
};
|
|
|
|
Gizmo a({250, 150});
|
|
Gizmo b({200, 250});
|
|
Gizmo c({350, 300});
|
|
Gizmo d({450, 250});
|
|
|
|
JGL::Font FreeSans;
|
|
Texture* image;
|
|
Texture* image_mask;
|
|
RenderTarget* j2d_render_target;
|
|
Shader* shader;
|
|
|
|
class JGLDemoWindow : public ReWindow::OpenGLWindow
|
|
{
|
|
public:
|
|
void initGL() {
|
|
camera = new Camera;
|
|
|
|
if (!JGL::Init({ GetSize().x, GetSize().y}, 75, 100))
|
|
Logger::Fatal("Initialization failed.");
|
|
|
|
// Load a custom font.
|
|
FreeSans = JGL::Font("assets/fonts/FreeSans.ttf");
|
|
|
|
glClearColor(0.f, 0.f, 0.f, 0.f);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
glDepthMask(GL_TRUE);
|
|
image = new Texture("assets/sprites/Re3D.png", FilteringMode::MIPMAP_NEAREST, JGL::SampleRate::X16);
|
|
image_mask = new Texture("assets/sprites/alpha_mask_2.png");
|
|
j2d_render_target = new RenderTarget({540, 500}, {0,0,0,0}, false,
|
|
SampleRate::NONE, FilteringMode::MIPMAP_NEAREST);
|
|
|
|
//Texture::MultiplyByAlphaMask(*image, *image_mask);
|
|
|
|
shader = new Shader(std::filesystem::path("assets/shader_programs/test_vertex.glsl"), std::filesystem::path("assets/shader_programs/test_fragment.glsl"));
|
|
}
|
|
|
|
EulerAngleXYZ textAngle = {0,0,0};
|
|
float fov = 90;
|
|
float pulse = 0;
|
|
float sprite_radians = 0;
|
|
bool fov_increasing = true;
|
|
|
|
void display() {
|
|
|
|
pulse += 20 * delta_time;
|
|
float dt = GetDeltaTime();
|
|
|
|
JGL::Update({ GetSize().x, GetSize().y });
|
|
|
|
if (fov_increasing)
|
|
fov += 0.025;
|
|
else
|
|
fov -= 0.050;
|
|
|
|
if (fov >= 120)
|
|
fov_increasing = false;
|
|
else if (fov <= 75)
|
|
fov_increasing = true;
|
|
//J3D::ChangeFOV(fov);
|
|
|
|
sprite_radians += 0.005;
|
|
textAngle.yaw += 1;
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
camera->render();
|
|
// All 3D elements of the scene and JGL elements *must* be rendered before the 2D stuff
|
|
/* if rendering to screen space directly. */
|
|
auto test_light = PointLight({2,1,2}, {(u8) pulse,(u8) pulse,(u8) pulse, 255}, {(u8) pulse, (u8) pulse, (u8) 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});
|
|
J3D::DrawLine(Colors::Red, {-0.33,-0.125,1}, {-0.33,0.25,1});
|
|
J3D::DrawString(Colors::Red, "JGL Sample Text", {-0.33, -0.1, 1.0f}, 1.f, 32, FreeSans, textAngle, true);
|
|
//J3D::WireframeSphere(Colors::Green, {0,0,0.5f}, 0.25f, 1, 128, 128);
|
|
Sphere sphere = {{1,0, 0.5f}, 0.2125};
|
|
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::Yellow, {0.5, 0, 0.5}, {0.125, 0.125, 0.125}, 1);
|
|
J3D::End();
|
|
|
|
J2D::Begin(j2d_render_target, shader, true);
|
|
J2D::FillRect(Colors::Blue, {0,52}, {100,100});
|
|
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, Vector2(225, 300), Vector2(image->GetDimensions()) * 0.25, Vector2(image->GetDimensions()) * 0.75, sprite_radians, {0.5, 0.5}, {1,1}, Colors::White);
|
|
J2D::FillRect(Colors::Pinks::HotPink, {68, 120}, {32, 32});
|
|
J2D::FillGradientRect(Colors::Red, Colors::Blue, Direction::Diagonal_SWNE, {100,52}, {100,100});
|
|
J2D::FillRoundedRect(Colors::Red, {200, 52}, {100, 100}, 8, 8);
|
|
J2D::FillRoundedRect(Colors::Purples::BlueViolet, {300, 52}, {100, 100}, 8, 4);
|
|
J2D::FillCircle(Colors::White, {52, 204}, 50, 24);
|
|
J2D::OutlineCircle(Colors::White, {153, 204}, 50, 24);
|
|
|
|
J2D::FillChamferRect(Colors::Reds::LightSalmon, {150, 400}, {64, 64}, 5);
|
|
J2D::OutlineRoundedRect(Colors::Reds::LightCoral, {250, 350}, {128, 128}, 10, 2);
|
|
std::vector<Vector2> points = {{1,1}, {4,4}, {8,8}, {16,16}, {32,32}};
|
|
J2D::FillGradientTriangle(Color4(Colors::Red), Color4(Colors::Green), Color4(Colors::Blue), {{0, 275}, {0, 375}, {100, 375}});
|
|
J2D::OutlineTriangle(Colors::Blue, {{100, 275}, {0, 275}, {100, 375}});
|
|
J2D::DrawGradientLine(Colors::Red, Colors::Blue, {105, 375}, {200, 275}, 2);
|
|
auto result = Jupiteroid.MeasureString("Jupiteroid Font", 16);
|
|
|
|
J2D::DrawString(Colors::Green, "Jupteroid Font", 0.f, 0, 1.f, 16, Jupiteroid);
|
|
J2D::DrawString(Colors::White, "Position: " + std::to_string(camera->position.x) + " " + std::to_string(camera->position.y) + " " + std::to_string(camera->position.z), 0, 16, 1,16, Jupiteroid);
|
|
J2D::DrawString(Colors::White, "ViewAngle: " + std::to_string(camera->angle.x) + " " + std::to_string(camera->angle.y) + " " + std::to_string(camera->angle.z), 0, 33, 1,16, Jupiteroid);
|
|
J2D::DrawString(Colors::White, "Framerate: " + std::to_string((int) fps), 0, 48, 1, 16, Jupiteroid);
|
|
std::array<Vector2, 5> polygon = {Vector2(200, 400), {220, 420}, {220, 430}, {230, 410}, {200, 400}};
|
|
J2D::OutlinePolygon(Colors::White, polygon.data(), polygon.size());
|
|
J2D::DrawCubicBezierCurve(Colors::Blues::CornflowerBlue,
|
|
a.position,
|
|
b.position,
|
|
c.position,
|
|
d.position
|
|
, 20, 1.5f);
|
|
|
|
a.Draw();
|
|
b.Draw();
|
|
c.Draw();
|
|
d.Draw();
|
|
|
|
J2D::End();
|
|
|
|
|
|
J2D::Begin(nullptr, shader, true);
|
|
J2D::DrawRenderTarget(j2d_render_target, {0, 0});
|
|
J2D::DrawSprite(image, image_mask, {0, 0}, 0.25, {0.5, 0.5}, {1,1});
|
|
J2D::End();
|
|
|
|
}
|
|
|
|
void OnRefresh(float elapsed) override {
|
|
fps = GetRefreshRate();
|
|
|
|
if (IsKeyDown(Keys::RightArrow))
|
|
camera->angle.y += 45.f * elapsed;
|
|
if (IsKeyDown(Keys::LeftArrow))
|
|
camera->angle.y -= 45.f * elapsed;
|
|
if (IsKeyDown(Keys::UpArrow))
|
|
camera->angle.x -= 45.f * elapsed;
|
|
if (IsKeyDown(Keys::DownArrow))
|
|
camera->angle.x += 45.f * elapsed;
|
|
if (IsKeyDown(Keys::Space))
|
|
camera->position.y += 1.f * elapsed;
|
|
if (IsKeyDown(Keys::LeftShift))
|
|
camera->position.y -= 1.f * elapsed;
|
|
|
|
//This is wrong of course. Just for testing purposes.
|
|
if (IsKeyDown(Keys::W))
|
|
camera->position.z += 1.f * elapsed;
|
|
if (IsKeyDown(Keys::S))
|
|
camera->position.z -= 1.f * elapsed;
|
|
if (IsKeyDown(Keys::A))
|
|
camera->position.x += 1.f * elapsed;
|
|
if (IsKeyDown(Keys::D))
|
|
camera->position.x -= 1.f * elapsed;
|
|
|
|
|
|
auto mouse = GetMouseCoordinates();
|
|
a.Update({(float) mouse.x, (float) mouse.y});
|
|
b.Update({(float) mouse.x, (float) mouse.y});
|
|
c.Update({(float) mouse.x, (float) mouse.y});
|
|
d.Update({(float) mouse.x, (float) mouse.y});
|
|
display();
|
|
int glError = glGetError();
|
|
if (glError != GL_NO_ERROR)
|
|
std::cout << glError << std::endl;
|
|
SwapBuffers();
|
|
}
|
|
|
|
|
|
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent & ev) override
|
|
{
|
|
RWindow::OnMouseButtonDown(ev);
|
|
a.Grab();
|
|
b.Grab();
|
|
c.Grab();
|
|
d.Grab();
|
|
}
|
|
|
|
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent & ev) override
|
|
{
|
|
RWindow::OnMouseButtonUp(ev);
|
|
a.Release();
|
|
b.Release();
|
|
c.Release();
|
|
d.Release();
|
|
}
|
|
|
|
bool OnResizeRequest(const ReWindow::WindowResizeRequestEvent& e) override {return true;}
|
|
JGLDemoWindow(const std::string& title, int width, int height) : ReWindow::OpenGLWindow(title, width, height, 2, 1) {}
|
|
};
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
auto* window = new JGLDemoWindow("JGL Demo Window", 1280, 720);
|
|
if (!window->Open())
|
|
exit(-1);
|
|
window->initGL();
|
|
window->SetResizable(true);
|
|
window->SetVsyncEnabled(false);
|
|
|
|
std::ifstream file("assets/models/cube.amo");
|
|
if (!file.is_open())
|
|
return -1;
|
|
|
|
Shader::OnCompilationErrorMessage += [] (std::string type, std::string info) {
|
|
std::cout << type << ", " << info << std::endl;
|
|
};
|
|
|
|
/*
|
|
std::stringstream buffer;
|
|
buffer << file.rdbuf();
|
|
std::string file_text = buffer.str();
|
|
file.close();
|
|
std::cout << file_text << std::endl;
|
|
|
|
auto result = VertexArray::LoadAMO(file_text);
|
|
*/
|
|
|
|
//ReWindow::Logger::Error.EnableConsole(false);
|
|
//ReWindow::Logger::Warning.EnableConsole(false);
|
|
//ReWindow::Logger::Debug.EnableConsole(false);
|
|
|
|
while (window->IsAlive())
|
|
window->ManagedRefresh();
|
|
return 0;
|
|
} |