644 lines
22 KiB
C++
644 lines
22 KiB
C++
/// Fractal Inspector Application
|
|
|
|
#include <iostream>
|
|
#include <JGL/logger/logger.h>
|
|
#include <ReWindow/types/Window.h>
|
|
#include <JUI/Widgets/Scene.hpp>
|
|
#include <JUI/Widgets/Slider.hpp>
|
|
#include <JUI/Widgets/Window.hpp>
|
|
#include "JUI/Widgets/CommandLine.hpp"
|
|
#include "JGL/types/Shader.h"
|
|
#include <ReWindow/Logger.h>
|
|
#include <Color4.hpp>
|
|
|
|
#include "JUI/Widgets/UtilityBar.hpp"
|
|
#include <JUI/Widgets/ColorPicker.hpp>
|
|
|
|
#include "JUI/Widgets/Image.hpp"
|
|
#include "JUI/Widgets/ImageRect.hpp"
|
|
|
|
std::vector<std::string> string_expand(const std::string& input, char delimiter = ' ');
|
|
|
|
|
|
#pragma region OpenGL Introspection
|
|
|
|
inline std::string GetGLVendor() { return {(const char*)glGetString(GL_VENDOR)}; }
|
|
inline std::string GetGLRenderer() { return {(const char*)glGetString(GL_RENDERER)}; }
|
|
inline std::string GetGLVersion() { return {(const char*)glGetString(GL_VERSION)}; }
|
|
inline std::string GetGLSLVersion() { return {(const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)}; }
|
|
inline std::string GetGLExtensions() { return {(const char*)glGetString(GL_EXTENSIONS)}; }
|
|
inline std::vector<std::string> GetGLExtensionList() { return string_expand({(const char*)glGetString(GL_EXTENSIONS)}); }
|
|
|
|
#pragma endregion
|
|
|
|
std::vector<std::string> string_expand(const std::string& input, char delimiter)
|
|
{
|
|
std::vector<std::string> result;
|
|
std::stringstream ss (input);
|
|
std::string item;
|
|
|
|
while (getline(ss, item, delimiter)) {
|
|
result.push_back(item);
|
|
}
|
|
return result;
|
|
|
|
}
|
|
|
|
using namespace JUI::UDimLiterals;
|
|
|
|
enum class Fractal {
|
|
MandelbrotSet, JuliaSet
|
|
};
|
|
|
|
class FractalInspectorApp : public ReWindow::OpenGLWindow {
|
|
public:
|
|
JUI::Scene *scene;
|
|
JUI::UtilityBar* toolbar;
|
|
JUI::CommandLine *console;
|
|
JUI::Window* info_dialog;
|
|
JUI::TextRect* fps_label;
|
|
|
|
JUI::Window* mandelbrotset_dialog;
|
|
JUI::Window* juliaset_dialog;
|
|
JUI::Window* colorpicker_window;
|
|
|
|
JGL::Shader mandelbrot_shader;
|
|
JGL::Shader julia_shader;
|
|
JGL::RenderTarget *canvas;
|
|
float u_time;
|
|
float u_scale = 2.f;
|
|
Vector2 u_translation {0.4f, 0.f};
|
|
Color4 u_rgb_1 = Colors::Greens::Chartreuse;
|
|
Color4 u_rgb_2 = Colors::Reds::LightCoral;
|
|
Color4 u_rgb_3 = Colors::Yellow;
|
|
Color4 u_rgb_4 = Colors::Green;
|
|
Vector2 u_julia_set {0,0};
|
|
Vector2 u_julia_value {0,0};
|
|
|
|
Fractal current_fractal = Fractal::MandelbrotSet;
|
|
|
|
FractalInspectorApp();
|
|
|
|
/// Returns a full-path file name for a GLSL vertex shader, from a given prefix name.
|
|
static std::filesystem::path VertexShaderFilepathFromPrefixName(const std::string &name)
|
|
{
|
|
return "../shaders/" + name + ".vert.glsl";
|
|
}
|
|
|
|
/// Returns a full-path file name for a GLSL fragment shader, from a given prefix name.
|
|
static std::filesystem::path FragmentShaderFilepathFromPrefixName(const std::string &name)
|
|
{
|
|
return "../shaders/" + name + ".frag.glsl";
|
|
}
|
|
|
|
void LoadShaders() {
|
|
|
|
// TODO: Come up with a decent way to bake the shader program sources into the executable, when compiling a release build!
|
|
|
|
mandelbrot_shader = Shader(VertexShaderFilepathFromPrefixName("test"), FragmentShaderFilepathFromPrefixName("mandelbrot"));
|
|
julia_shader = Shader(VertexShaderFilepathFromPrefixName("test" ), FragmentShaderFilepathFromPrefixName("julia"));
|
|
}
|
|
|
|
void ReloadShader() {
|
|
LoadShaders();
|
|
}
|
|
|
|
using CmdArgs = std::vector<std::string>;
|
|
void PositionCmd(const CmdArgs& args) {
|
|
if (args.empty()) { // Output position + scale
|
|
console->Log(std::format("Pos: {}, {}, Zoom: {}", u_translation.x, u_translation.y, u_scale));
|
|
return;
|
|
}
|
|
|
|
if (args.size() >= 2) { // Set Position
|
|
u_translation.x = std::stof(args[0]);
|
|
u_translation.y = std::stof(args[1]);
|
|
if (args.size() >= 3) { // Also set scale
|
|
u_scale = std::stof(args[2]);
|
|
}
|
|
}
|
|
console->Log(std::format("{}", args.size()));
|
|
}
|
|
|
|
void ParseCmdLineMessage(const std::string& message) {
|
|
auto tokens = string_expand(message);
|
|
|
|
if (tokens.size() == 0) {
|
|
console->Log("No command input!", Colors::Red);
|
|
return;
|
|
}
|
|
|
|
std::string cmd = tokens[0];
|
|
|
|
// Remove 0th element from tokens before passing to command delegates.
|
|
tokens.erase(tokens.begin());
|
|
|
|
if (cmd == "r" || cmd == "reload") {
|
|
ReloadShader();
|
|
} else if (cmd == "pos") {
|
|
return PositionCmd(tokens);
|
|
} else {
|
|
console->Log(std::format("No such command: {}", cmd), Colors::Red);
|
|
}
|
|
}
|
|
|
|
|
|
void LoadJulia() {
|
|
juliaset_dialog->Open();
|
|
}
|
|
|
|
void UnloadJulia() {
|
|
juliaset_dialog->Close();
|
|
}
|
|
|
|
JUI::Window* CreateAppInfoDialogWindow(JUI::Widget* parent) {
|
|
// TODO: Implement JUI structure that makes blocks of text easy to impelement.
|
|
auto window = new JUI::Window(parent);
|
|
window->SetTitle("About FractalInspector");
|
|
window->Size({300_px, 375_px});
|
|
window->MinSize({300, 375});
|
|
|
|
auto* layout = new JUI::VerticalListLayout(window->Content());
|
|
layout->Padding(0_px);
|
|
|
|
// TODO: Code like this ends up being a common construct in JUI programs: Make a TextList widget.
|
|
auto line_item = [&] (const std::string& text, int size = 20, const Color4& color = Colors::White) {
|
|
auto* content = new JUI::TextRect(layout);
|
|
content->Size({100_percent, JUI::UDim(size+5, 0)});
|
|
content->SetContent(text);
|
|
content->SetTextSize(size);
|
|
content->SetTextColor(color);
|
|
content->BGColor(Colors::Transparent);
|
|
content->AlignCenterHorizontally();
|
|
content->BorderWidth(0);
|
|
};
|
|
|
|
|
|
line_item("FractalInspector", 30);
|
|
line_item("Version 1.0", 14);
|
|
|
|
auto* box = new JUI::Rect(layout);
|
|
box->Size({100_percent, 200_px});
|
|
box->BGColor(Colors::Transparent);
|
|
box->BorderWidth(0);
|
|
auto* img = new JUI::ImageRect(box);
|
|
img->Content(new JGL::Texture("../icon.png"));
|
|
img->Size({200_px, 200_px});
|
|
img->BGColor(Colors::Transparent);
|
|
img->AnchorPoint({.5f, .5f});
|
|
img->Position({50_percent, 50_percent});
|
|
img->BorderWidth(0);
|
|
img->BGColor(Colors::Transparent);
|
|
|
|
line_item("Developed & Maintained by Josh O'Leary.", 16);
|
|
line_item("William R. Maxine H. Ash B.", 12);
|
|
line_item("(c) 2024 - 2025 Redacted Software", 16);
|
|
|
|
auto* btn_box = new JUI::Rect(layout);
|
|
btn_box->Size({100_percent, 40_px});
|
|
btn_box->BGColor(Colors::Transparent);
|
|
btn_box->BorderWidth(0);
|
|
|
|
auto* btn_layout = new JUI::HorizontalListLayout(btn_box);
|
|
btn_layout->Padding(8_px);
|
|
|
|
auto btn_item = [&] (const std::string& text) -> JUI::TextButton* {
|
|
JUI::TextButton* btn = new JUI::TextButton(btn_layout);
|
|
btn->SetContent(text);
|
|
btn->Size({32_percent, 100_percent});
|
|
btn->SetTextColor(Colors::Black);
|
|
btn->Center();
|
|
return btn;
|
|
};
|
|
|
|
auto* btn_a = btn_item("License");
|
|
auto* btn_b = btn_item("Wiki");
|
|
auto* btn_c = btn_item("Source");
|
|
|
|
|
|
return window;
|
|
}
|
|
|
|
void CreateMenu() {
|
|
using namespace JUI::UDimLiterals;
|
|
|
|
toolbar = new JUI::UtilityBar(scene);
|
|
auto* fractals_list = toolbar->AddSubmenu("Fractals");
|
|
|
|
fractals_list->AddButton("Mandelbrot set", [this]{
|
|
UnloadJulia();
|
|
current_fractal = Fractal::MandelbrotSet;
|
|
});
|
|
fractals_list->AddButton("Julia set", [this]{
|
|
LoadJulia();
|
|
current_fractal = Fractal::JuliaSet;
|
|
});
|
|
|
|
|
|
|
|
auto* view = toolbar->AddSubmenu("View"); {
|
|
view->AddButton("Color Picker Dialog", [this] {
|
|
colorpicker_window->Toggle();
|
|
});
|
|
|
|
view->AddButton("Console", [this] {
|
|
console->Toggle();
|
|
});
|
|
|
|
view->AddButton("README", [this] {
|
|
info_dialog->Toggle();
|
|
});
|
|
|
|
view->AddSeparator();
|
|
view->AddButton("Reset Viewport");
|
|
view->AddButton("Reset Colors");
|
|
view->AddButton("Zoom In");
|
|
view->AddButton("Zoom Out");
|
|
}
|
|
auto* btn_toggle_console = toolbar->AddButton("Console");
|
|
|
|
btn_toggle_console->OnClickEvent += [this] (auto a, auto b) mutable {
|
|
console->Toggle();
|
|
};
|
|
|
|
auto* btn_toggle_info_dialog = toolbar->AddButton("Info");
|
|
|
|
auto* misc = toolbar->AddSubmenu("Miscellaneous");
|
|
{
|
|
misc->AddButton("Take Screenshot");
|
|
misc->AddButton("Take Collage");
|
|
}
|
|
|
|
|
|
info_dialog = CreateAppInfoDialogWindow(scene);
|
|
|
|
btn_toggle_info_dialog->OnClickEvent += [this] (auto a, auto b) mutable {
|
|
info_dialog->Toggle();
|
|
};
|
|
|
|
fps_label = new JUI::TextRect(toolbar);
|
|
fps_label->Position({100_percent - 200_px, 0_px});
|
|
fps_label->Size({200_px, 100_percent});
|
|
fps_label->SetTextColor(Colors::Black);
|
|
fps_label->SetContent("60 FPS");
|
|
|
|
|
|
|
|
|
|
// TODO: Utilize for things later.
|
|
colorpicker_window = new JUI::Window(scene);
|
|
colorpicker_window->SetTitle("Color-Pickers");
|
|
colorpicker_window->MinSize({600, 150});
|
|
colorpicker_window->Size({600_px, 150_px});
|
|
colorpicker_window->Position({50_px, 50_px});
|
|
|
|
auto* col_layout = new JUI::HorizontalListLayout(colorpicker_window->Content());
|
|
//wind->Close();
|
|
|
|
JUI::ColorPicker* pp = new JUI::ColorPicker(col_layout);
|
|
pp->Size({25_percent, 100_percent});
|
|
pp->OnColorValueChanged += [this] (const Color4& color) mutable {
|
|
u_rgb_1 = color;
|
|
};
|
|
|
|
/*auto* wind2 = new JUI::Window(scene);
|
|
wind2->SetTitle("Color-Picker B");
|
|
wind2->MinSize({200, 150});
|
|
wind2->Size({200_px, 150_px});
|
|
wind2->Position({50_px, 250_px});*/
|
|
|
|
JUI::ColorPicker* pp2 = new JUI::ColorPicker(col_layout);
|
|
pp2->Size({25_percent, 100_percent});
|
|
pp2->OnColorValueChanged += [this] (const Color4& color) mutable {
|
|
u_rgb_2 = color;
|
|
};
|
|
|
|
JUI::ColorPicker* pp3 = new JUI::ColorPicker(col_layout);
|
|
pp3->Size({25_percent, 100_percent});
|
|
pp3->OnColorValueChanged += [this] (const Color4& color) mutable {
|
|
u_rgb_3 = color;
|
|
};
|
|
|
|
JUI::ColorPicker* pp4 = new JUI::ColorPicker(col_layout);
|
|
pp4->Size({25_percent, 100_percent});
|
|
pp4->OnColorValueChanged += [this] (const Color4& color) mutable {
|
|
u_rgb_3 = color;
|
|
};
|
|
|
|
|
|
console = new JUI::CommandLine(scene);
|
|
console->MinSize(Vector2(200, 200));
|
|
console->MaxSize(Vector2(GetWidth()-10, GetHeight()-10));
|
|
console->Size({100_percent, 200_px});
|
|
console->Position({0_percent, JUI::UDim(-200, 1)});
|
|
console->OnInput += [this] (const std::string& message) {
|
|
ParseCmdLineMessage(message);
|
|
};
|
|
|
|
|
|
mandelbrotset_dialog = new JUI::Window(scene);
|
|
mandelbrotset_dialog->Position({20_px, 300_px});
|
|
mandelbrotset_dialog->Close();
|
|
|
|
auto* mandelbrotset_layout = new JUI::VerticalListLayout(mandelbrotset_dialog->ViewportInstance());
|
|
mandelbrotset_layout->LayoutOrder(JUI::LayoutOrder::V::TOP);
|
|
|
|
int idx = 999;
|
|
|
|
auto mb_line_item = [&] (const std::string& text, int size = 20, const Color4& color = Colors::White) {
|
|
|
|
auto* content = new JUI::TextRect(mandelbrotset_layout);
|
|
content->Size({100_percent, 25_px});
|
|
content->SetContent(text);
|
|
content->SetTextSize(size);
|
|
content->SetTextColor(color);
|
|
content->BGColor(Colors::Transparent);
|
|
content->AlignCenterHorizontally();
|
|
content->LayoutOrder(idx--);
|
|
};
|
|
|
|
mb_line_item("The Mandelbrot Set");
|
|
mb_line_item("Imagine a simple rule: ");
|
|
mb_line_item("Take a number, square it, and add back the original number.");
|
|
|
|
// TODO: Collapsible section: Evaluation of mandelbrot set with z = 0.
|
|
mb_line_item("If we start with zero, and keep repeating this rule, we always get zero. Boring, right?");
|
|
|
|
// TODO: Collapsible section: Evaluation of mandelbrot set with z = 1.
|
|
mb_line_item("But what if we start with a different number. Let's say 1.");
|
|
mb_line_item("1 squared is 1, plus 1 is 2.");
|
|
mb_line_item("2 squared is 4, plus 1 is 5.");
|
|
mb_line_item("5 squared is 25, plus 1 is 26.");
|
|
mb_line_item("The numbers keep getting bigger and bigger -- they 'escape' to infinity.");
|
|
|
|
// TODO: Collapsible section: Evaluation of mandelbrot set with z = -1.
|
|
mb_line_item("Now, let's try a number like -1.");
|
|
mb_line_item("-1 squared is 1, plus -1 is 0.");
|
|
mb_line_item("0 squared is 0, plus -1 is -1");
|
|
mb_line_item("-1 squared is 1, plus -1 is 0");
|
|
mb_line_item("The numbers get stuck in a loop between -1 and 0 -- they don't escape");
|
|
|
|
mb_line_item("The Mandelbrot set is a collection of all the starting numbers that don't escape to infinity when you repeat this simple rule.");
|
|
mb_line_item("These numbers, when plotted on a complex number plane, create this incredibly intricate and beautiful fractal shape.");
|
|
mb_line_item("Color-code the 'escape velocity' of the input numbers that do escape, and you get a result like the one you see.");
|
|
|
|
|
|
juliaset_dialog = new JUI::Window(scene);
|
|
juliaset_dialog->SetTitle("Julia Set Inputs");
|
|
juliaset_dialog->Position({20_px, 300_px});
|
|
juliaset_dialog->Size({900_px, 70_px});
|
|
|
|
auto* julia_x_slider = new JUI::Slider(juliaset_dialog->Content());
|
|
|
|
julia_x_slider->Size({900_px, 25_px});
|
|
julia_x_slider->Interval(1e-5f); julia_x_slider->Minimum(0); julia_x_slider->Maximum(1);
|
|
julia_x_slider->ValueChanged += [this] (double value) {
|
|
value = value * 2;
|
|
value = value - 1;
|
|
u_julia_set.x = value;
|
|
};
|
|
|
|
auto* julia_y_slider = new JUI::Slider(juliaset_dialog->Content());
|
|
julia_y_slider->Size({900_px, 25_px});
|
|
julia_y_slider->Position({0_px, 30_px});
|
|
julia_y_slider->Interval(1e-5f); julia_y_slider->Minimum(0); julia_y_slider->Maximum(1);
|
|
julia_y_slider->ValueChanged += [this] (double value) {
|
|
value = value * 2;
|
|
value = value - 1;
|
|
u_julia_set.y = value;
|
|
};
|
|
}
|
|
|
|
bool Open() override
|
|
{
|
|
if (!OpenGLWindow::Open())
|
|
return false;
|
|
|
|
auto size = GetSize();
|
|
auto vec_size = Vector2i(size.x, size.y);
|
|
if (!JGL::Init(vec_size, 0.f, 1.f))
|
|
return false;
|
|
JGL::Update(vec_size);
|
|
|
|
|
|
|
|
glClearColor(0.f, 0.f, 0.f, 0.f);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
glDepthMask(GL_TRUE);
|
|
// TODO: Delete when we update to the next release of JGL
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // NOTE: This MUST be called for text rendering to work properly!!!
|
|
|
|
scene = new JUI::Scene();
|
|
CreateMenu();
|
|
|
|
canvas = new RenderTarget(vec_size);
|
|
LoadShaders();
|
|
|
|
console->Log(std::format("OpenGL Renderer: {}", GetGLRenderer()));
|
|
console->Log(std::format("OpenGL Vendor: {}", GetGLVendor()));
|
|
console->Log(std::format("OpenGL Version: {}", GetGLVersion()));
|
|
console->Log(std::format("GLSL Version: {}", GetGLSLVersion()));
|
|
/*auto ext_list = GetGLExtensionList();
|
|
|
|
// TODO: output 3 at a time.
|
|
console->Log("GL-Extensions: ");
|
|
std::string formatted_output = "";//"GL-Extensions: {}";
|
|
|
|
|
|
int iter = 0;
|
|
for (auto& str : ext_list) {
|
|
formatted_output += str + ", ";
|
|
iter++;
|
|
if (iter > 5) {
|
|
iter = 0;
|
|
console->Log(formatted_output);
|
|
formatted_output = "";
|
|
}
|
|
}*/
|
|
|
|
return true;
|
|
}
|
|
void PropagateWindowSize() {
|
|
auto size = GetSize();
|
|
Vector2i vSize = Vector2i(size.x, size.y);
|
|
JGL::Update(vSize);
|
|
scene->SetViewportSize(Vector2(vSize));
|
|
console->MaxSize(Vector2(GetWidth()-10, GetHeight()-10));
|
|
|
|
// TODO: Causes the shader canvas to not appear...?
|
|
//canvas->Resize(vSize);
|
|
}
|
|
void Update(float elapsed) {
|
|
scene->Update(elapsed);
|
|
|
|
if (IsKeyDown(Keys::F6)) {
|
|
u_scale = 2.f;
|
|
u_translation = {.4, 0};
|
|
}
|
|
|
|
// TODO: Vary the rate appropriately.
|
|
float rate = elapsed * 0.125f;
|
|
|
|
if (IsKeyDown(Keys::LeftShift))
|
|
rate *= 0.125f;
|
|
|
|
if (IsKeyDown(Keys::LeftControl))
|
|
rate *= 0.125f;
|
|
|
|
if (IsKeyDown(Keys::Minus))
|
|
u_scale += rate;
|
|
if (IsKeyDown(Keys::Equals))
|
|
u_scale -= rate;
|
|
|
|
if (IsKeyDown(Keys::DownArrow))
|
|
u_translation.y += rate;
|
|
if (IsKeyDown(Keys::UpArrow))
|
|
u_translation.y -= rate;
|
|
|
|
if (IsKeyDown(Keys::LeftArrow))
|
|
u_translation.x += rate;
|
|
if (IsKeyDown(Keys::RightArrow))
|
|
u_translation.x -= rate;
|
|
|
|
|
|
u_time += elapsed;
|
|
|
|
u_julia_value = Vector2::Lerp(u_julia_value, u_julia_set, 0.001f);
|
|
|
|
UpdateShaderUniforms(elapsed);
|
|
|
|
int fps = 1.f / elapsed;
|
|
|
|
std::string fps_text = std::format("FPS: {}", fps);
|
|
|
|
fps_label->SetContent(fps_text);
|
|
}
|
|
|
|
void UpdateShaderUniforms(float elapsed) {
|
|
Vector2 u_res = Vector2(GetSize().x, GetSize().y);
|
|
|
|
// TODO: Why do we need to multiply X by 1.5 here?
|
|
Vector2 u_mouse = Vector2(GetMouseCoordinates().x*1.5f, GetSize().y-GetMouseCoordinates().y);
|
|
|
|
JGL::Shader shader;
|
|
if (current_fractal == Fractal::JuliaSet) {
|
|
shader = julia_shader;
|
|
shader.SetVector2("u_julia_set", u_julia_value);
|
|
}
|
|
|
|
if (current_fractal == Fractal::MandelbrotSet) {
|
|
shader = mandelbrot_shader;
|
|
}
|
|
|
|
shader.SetVector2("u_resolution", u_res);
|
|
shader.SetFloat("u_time", u_time);
|
|
shader.SetVector2("u_mouse", u_mouse);
|
|
shader.SetVector3("u_rgb_1", Vector3(u_rgb_1.RN(), u_rgb_1.GN(), u_rgb_1.BN()));
|
|
shader.SetVector3("u_rgb_2", Vector3(u_rgb_2.RN(), u_rgb_2.GN(), u_rgb_2.BN()));
|
|
shader.SetVector3("u_rgb_3", Vector3(u_rgb_3.RN(), u_rgb_3.GN(), u_rgb_3.BN()));
|
|
shader.SetVector3("u_rgb_4", Vector3(u_rgb_4.RN(), u_rgb_4.GN(), u_rgb_4.BN()));
|
|
shader.SetFloat("u_scale", u_scale);
|
|
shader.SetVector2("u_translation", u_translation);
|
|
}
|
|
|
|
void Draw() {
|
|
|
|
Shader::UseDefault();
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
// TODO: Have to be particular about the order-of-operations in regards to shaders.
|
|
// Protip: Use RenderTarget to draw a quad with the shader in question. *After rendering the rest of the scene.*
|
|
|
|
J2D::Begin();
|
|
J2D::DrawRenderTarget(canvas, {0, 0});
|
|
J2D::End();
|
|
|
|
scene->Draw();
|
|
|
|
JGL::J2D::Begin(canvas, true);
|
|
if (current_fractal == Fractal::JuliaSet) {
|
|
julia_shader.Use();
|
|
}
|
|
|
|
if (current_fractal == Fractal::MandelbrotSet) {
|
|
mandelbrot_shader.Use();
|
|
}
|
|
JGL::J2D::FillRect(Colors::Black, {0, 0}, Vector2(GetSize().x, GetSize().y));
|
|
JGL::J2D::End();
|
|
|
|
}
|
|
void OnRefresh(float elapsed) override {
|
|
PropagateWindowSize();
|
|
Update(elapsed);
|
|
Draw();
|
|
this->SwapBuffers();
|
|
}
|
|
|
|
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &e) override {
|
|
if (e.Button == MouseButtons::Left)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Left, true);
|
|
if (e.Button == MouseButtons::Middle)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Middle, true);
|
|
if (e.Button == MouseButtons::Right)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Right, true);
|
|
}
|
|
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &e) override {
|
|
if (e.Button == MouseButtons::Left)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Left, false);
|
|
if (e.Button == MouseButtons::Middle)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Middle, false);
|
|
if (e.Button == MouseButtons::Right)
|
|
scene->ObserveMouseInput(JUI::MouseButton::Right, false);
|
|
}
|
|
void OnMouseMove(const ReWindow::MouseMoveEvent &e) override {
|
|
Vector2 nmp = Vector2(e.Position.x, e.Position.y);
|
|
scene->ObserveMouseMovement(nmp);
|
|
}
|
|
void OnKeyDown(const ReWindow::KeyDownEvent &e) override {
|
|
if (scene->ObserveKeyInput(e.key, true))
|
|
return;
|
|
|
|
if (e.key == Keys::R)
|
|
ReloadShader();
|
|
}
|
|
void OnKeyUp(const ReWindow::KeyUpEvent &e) override {
|
|
scene->ObserveKeyInput(e.key, false);
|
|
}
|
|
protected:
|
|
private:
|
|
};
|
|
|
|
FractalInspectorApp::FractalInspectorApp(): ReWindow::OpenGLWindow("ReShader", 1800, 1000, 2, 1) {
|
|
Shader::OnCompilationErrorMessage += [this](std::string type, std::string infoLog) {
|
|
auto log_lines = string_expand(infoLog, '\n');
|
|
console->Log(type, Colors::Red);
|
|
std::cerr << type << std::endl;
|
|
for (auto line: log_lines) {
|
|
console->Log(line, Colors::Red);
|
|
std::cerr << line << std::endl;
|
|
}
|
|
};
|
|
|
|
u_time = 0;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
ReWindow::Logger::Debug.EnableConsole(false);
|
|
|
|
auto* program = new FractalInspectorApp();
|
|
|
|
program->Open();
|
|
program->SetFullscreen(false);
|
|
program->SetVsyncEnabled(false);
|
|
program->SetResizable(true);
|
|
|
|
while (program->IsAlive())
|
|
program->ManagedRefresh();
|
|
|
|
return 0;
|
|
}
|