Compare commits
6 Commits
Prerelease
...
main
Author | SHA1 | Date | |
---|---|---|---|
f0b097b782 | |||
e5fb5400c5 | |||
f316a3241d | |||
f64734c632 | |||
a9ca448a10 | |||
1ccfaeb85f |
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.18..3.30)
|
cmake_minimum_required(VERSION 3.18..3.29)
|
||||||
|
|
||||||
project(FractalInspector
|
project(FractalInspector
|
||||||
VERSION 1.0
|
VERSION 1.1
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
|
|
||||||
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
|
||||||
@@ -15,7 +15,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
|||||||
include(cmake/CPM.cmake)
|
include(cmake/CPM.cmake)
|
||||||
|
|
||||||
CPMAddPackage(NAME mcolor
|
CPMAddPackage(NAME mcolor
|
||||||
URL https://git.redacted.cc/maxine/mcolor/archive/Prerelease-7.3.zip)
|
URL https://git.redacted.cc/maxine/mcolor/archive/Release-1.zip)
|
||||||
|
|
||||||
CPMAddPackage(NAME jlog
|
CPMAddPackage(NAME jlog
|
||||||
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-18.zip)
|
URL https://git.redacted.cc/josh/jlog/archive/Prerelease-18.zip)
|
||||||
@@ -35,14 +35,20 @@ CPMAddPackage(NAME JGL
|
|||||||
CPMAddPackage(NAME JUI
|
CPMAddPackage(NAME JUI
|
||||||
URL https://git.redacted.cc/josh/ReJUI/archive/Prerelease-6.zip)
|
URL https://git.redacted.cc/josh/ReJUI/archive/Prerelease-6.zip)
|
||||||
|
|
||||||
#file(COPY "assets" DESTINATION "${PROJECT_BINARY_DIR}")
|
file(COPY "shaders" DESTINATION "${PROJECT_BINARY_DIR}")
|
||||||
#file(GLOB_RECURSE ASSETS "assets/")
|
#file(GLOB_RECURSE ASSETS "assets/")
|
||||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
||||||
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp")
|
file(GLOB_RECURSE SOURCES "src/*.c" "src/*.cpp")
|
||||||
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
add_executable(FractalInspector main.cpp ${SOURCES})
|
if (WIN32)
|
||||||
|
add_executable(FractalInspector main.cpp ${SOURCES} app.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
add_executable(FractalInspector main.cpp ${SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_include_directories(FractalInspector PUBLIC ${Event_SOURCE_DIR}/include)
|
target_include_directories(FractalInspector PUBLIC ${Event_SOURCE_DIR}/include)
|
||||||
target_include_directories(FractalInspector PUBLIC ${J3ML_SOURCE_DIR}/include)
|
target_include_directories(FractalInspector PUBLIC ${J3ML_SOURCE_DIR}/include)
|
||||||
|
4
app.rc
Normal file
4
app.rc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
MAINICON ICON "icon.ico"
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "icon.ico"
|
||||||
|
MANIFEST ICON "icon.ico"
|
||||||
|
AAA ICON "icon.ico"
|
@@ -51,6 +51,8 @@ inline void Lerped<float>::Update(float elapsed) { current = Math::Lerp(current,
|
|||||||
template <>
|
template <>
|
||||||
inline void Lerped<Vector2>::Update(float elapsed) { current = Vector2::Lerp(current, goal, elapsed*rate); }
|
inline void Lerped<Vector2>::Update(float elapsed) { current = Vector2::Lerp(current, goal, elapsed*rate); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// This class represents the FractalApp program state.
|
/// This class represents the FractalApp program state.
|
||||||
class FractalInspectorApp : public ReWindow::OpenGLWindow {
|
class FractalInspectorApp : public ReWindow::OpenGLWindow {
|
||||||
protected:
|
protected:
|
||||||
@@ -67,6 +69,12 @@ protected:
|
|||||||
JGL::Shader mandelbrot_shader;
|
JGL::Shader mandelbrot_shader;
|
||||||
JGL::Shader julia_shader;
|
JGL::Shader julia_shader;
|
||||||
JGL::RenderTarget *canvas;
|
JGL::RenderTarget *canvas;
|
||||||
|
|
||||||
|
JUI::Slider* julia_x_slider;
|
||||||
|
JUI::Slider* julia_y_slider;
|
||||||
|
JUI::Text* julia_x_label;
|
||||||
|
JUI::Text* julia_y_label;
|
||||||
|
|
||||||
float u_time;
|
float u_time;
|
||||||
float u_scale = 2.f;
|
float u_scale = 2.f;
|
||||||
float u_scale_goal = 2.f;
|
float u_scale_goal = 2.f;
|
||||||
@@ -122,6 +130,23 @@ public:
|
|||||||
/// Passes the current window size to subordinate objects, such as the JUI scene.
|
/// Passes the current window size to subordinate objects, such as the JUI scene.
|
||||||
void PropagateWindowSize();
|
void PropagateWindowSize();
|
||||||
|
|
||||||
|
Vector2 FractalSpaceToScreenSpace(const Vector2& pos) {
|
||||||
|
Vector2 R(GetWidth(), GetHeight());
|
||||||
|
Vector2 translation(u_translation.x, -u_translation.y);
|
||||||
|
|
||||||
|
return ((pos + u_translation) * R.y + R + Vector2(1.f, 1.f)) / u_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 ScreenSpaceToFractalSpace(const Vector2& pos) {
|
||||||
|
Vector2 tpos = -pos;
|
||||||
|
Vector2 R(GetWidth(), GetHeight());
|
||||||
|
Vector2 scaled = pos * u_scale;
|
||||||
|
Vector2 translation(u_translation.x, -u_translation.y);
|
||||||
|
|
||||||
|
Vector2 uv = ((scaled - R - Vector2(1.f, 1.f)) / R.y) - u_translation;
|
||||||
|
return uv;
|
||||||
|
}
|
||||||
|
|
||||||
void ZoomIn(float rate);
|
void ZoomIn(float rate);
|
||||||
|
|
||||||
void ZoomInTowards(const Vector2 &dir, float rate);
|
void ZoomInTowards(const Vector2 &dir, float rate);
|
||||||
@@ -179,7 +204,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TakeScreenshot();
|
void TakeScreenshot();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
3
main.cpp
3
main.cpp
@@ -8,9 +8,10 @@
|
|||||||
// TODO: Parse command-line args.
|
// TODO: Parse command-line args.
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
mcolor::windowsSaneify();
|
||||||
ReWindow::Logger::Debug.EnableConsole(false);
|
ReWindow::Logger::Debug.EnableConsole(false);
|
||||||
|
|
||||||
int default_app_width = 1660;
|
int default_app_width = 1440;
|
||||||
int default_app_height = 900;
|
int default_app_height = 900;
|
||||||
|
|
||||||
// TODO: Create AppConfig struct and pass to constructor.
|
// TODO: Create AppConfig struct and pass to constructor.
|
||||||
|
@@ -24,7 +24,7 @@ uniform vec3 u_rgb_3;
|
|||||||
uniform vec3 u_rgb_4;
|
uniform vec3 u_rgb_4;
|
||||||
|
|
||||||
#define N 256. // Number of iterations?
|
#define N 256. // Number of iterations?
|
||||||
#define B 4. // What does B mean?
|
#define B 8. // What does B mean?
|
||||||
|
|
||||||
// The mandelbrot set is a set of complex numbers c for which the function:
|
// The mandelbrot set is a set of complex numbers c for which the function:
|
||||||
// f(z) = z*z + c
|
// f(z) = z*z + c
|
||||||
@@ -38,8 +38,8 @@ float iterate_mandelbrot(vec2 p) {
|
|||||||
for (i=0.; i < N; i++ ) {
|
for (i=0.; i < N; i++ ) {
|
||||||
// This line performs the core Mandelbrot iteration: z = z^2 + c.
|
// This line performs the core Mandelbrot iteration: z = z^2 + c.
|
||||||
// It is done using a matrix multiplication to perform the complex number squaring.
|
// It is done using a matrix multiplication to perform the complex number squaring.
|
||||||
// If z = x + iy, then z&2 = (i+iy)(x+iy) = x^2 - y ^ 2 + 2ixy.
|
// If z = x + iy, then z&2 = (x+iy)(x+iy) = x^2 - y ^ 2 + 2ixy.
|
||||||
// The matrix [x, -y; y, x] multiplied by [x, y] gives [x*x - y&y, y*x + x*y] = [Re(z^2) Im(z^2)].
|
// The matrix [x, -y; y, x] multiplied by [x, y] gives [x*x - y*y, y*x + x*y] = [Re(z^2) Im(z^2)].
|
||||||
// Then we add the constant complex number c (represented by the input vec2).
|
// Then we add the constant complex number c (represented by the input vec2).
|
||||||
z = mat2(z, -z.y, z.x) * z + c;
|
z = mat2(z, -z.y, z.x) * z + c;
|
||||||
|
|
||||||
|
@@ -20,11 +20,11 @@ FractalInspectorApp::FractalInspectorApp(int width, int height):
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path FractalInspectorApp::VertexShaderFilepathFromPrefixName(const std::string &name) {
|
std::filesystem::path FractalInspectorApp::VertexShaderFilepathFromPrefixName(const std::string &name) {
|
||||||
return "../shaders/" + name + ".vert.glsl";
|
return "shaders/" + name + ".vert.glsl";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path FractalInspectorApp::FragmentShaderFilepathFromPrefixName(const std::string &name) {
|
std::filesystem::path FractalInspectorApp::FragmentShaderFilepathFromPrefixName(const std::string &name) {
|
||||||
return "../shaders/" + name + ".frag.glsl";
|
return "shaders/" + name + ".frag.glsl";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FractalInspectorApp::LoadShaders() {
|
void FractalInspectorApp::LoadShaders() {
|
||||||
@@ -105,6 +105,16 @@ void FractalInspectorApp::UnloadJulia() {
|
|||||||
juliaset_dialog->Close();
|
juliaset_dialog->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tested and works on both platform, but is a security **NIGHTMARE**.
|
||||||
|
void OpenURL(const std::string &url) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
system(std::format("start {}", url).c_str());
|
||||||
|
#endif
|
||||||
|
#ifdef linux
|
||||||
|
system(std::format("xdg-open {}", url).c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
JUI::Window * FractalInspectorApp::CreateAppInfoDialogWindow(JUI::Widget *parent) {
|
JUI::Window * FractalInspectorApp::CreateAppInfoDialogWindow(JUI::Widget *parent) {
|
||||||
// TODO: Implement JUI structure that makes blocks of text easy to impelement.
|
// TODO: Implement JUI structure that makes blocks of text easy to impelement.
|
||||||
auto window = new JUI::Window(parent);
|
auto window = new JUI::Window(parent);
|
||||||
@@ -112,6 +122,8 @@ JUI::Window * FractalInspectorApp::CreateAppInfoDialogWindow(JUI::Widget *parent
|
|||||||
window->Size({300_px, 375_px});
|
window->Size({300_px, 375_px});
|
||||||
window->MinSize({300, 375});
|
window->MinSize({300, 375});
|
||||||
|
|
||||||
|
window->Position({100_percent - 325_px, 100_percent - 400_px});
|
||||||
|
|
||||||
auto* layout = new JUI::VerticalListLayout(window->Content());
|
auto* layout = new JUI::VerticalListLayout(window->Content());
|
||||||
layout->Padding(0_px);
|
layout->Padding(0_px);
|
||||||
|
|
||||||
@@ -156,18 +168,23 @@ JUI::Window * FractalInspectorApp::CreateAppInfoDialogWindow(JUI::Widget *parent
|
|||||||
auto* btn_layout = new JUI::HorizontalListLayout(btn_box);
|
auto* btn_layout = new JUI::HorizontalListLayout(btn_box);
|
||||||
btn_layout->Padding(8_px);
|
btn_layout->Padding(8_px);
|
||||||
|
|
||||||
auto btn_item = [&] (const std::string& text) -> JUI::TextButton* {
|
auto btn_item = [&] (const std::string& text, const std::function<void()>& callback = {}) -> JUI::TextButton* {
|
||||||
JUI::TextButton* btn = new JUI::TextButton(btn_layout);
|
JUI::TextButton* btn = new JUI::TextButton(btn_layout);
|
||||||
btn->SetContent(text);
|
btn->SetContent(text);
|
||||||
btn->Size({32_percent, 100_percent});
|
btn->Size({32_percent, 100_percent});
|
||||||
btn->SetTextColor(Colors::Black);
|
btn->SetTextColor(Colors::Black);
|
||||||
btn->Center();
|
btn->Center();
|
||||||
|
btn->OnClickEvent += [callback] (auto a, auto b) {
|
||||||
|
callback();
|
||||||
|
};
|
||||||
return btn;
|
return btn;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* btn_a = btn_item("License");
|
auto* btn_a = btn_item("License");
|
||||||
auto* btn_b = btn_item("Wiki");
|
auto* btn_b = btn_item("Wiki");
|
||||||
auto* btn_c = btn_item("Source");
|
auto* btn_c = btn_item("Source", []() {
|
||||||
|
OpenURL("https://git.redacted.cc/josh/FractalInspector");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
@@ -239,8 +256,8 @@ void FractalInspectorApp::CreateMenu() {
|
|||||||
// TODO: Utilize for things later.
|
// TODO: Utilize for things later.
|
||||||
colorpicker_window = new JUI::Window(scene);
|
colorpicker_window = new JUI::Window(scene);
|
||||||
colorpicker_window->SetTitle("Color-Pickers");
|
colorpicker_window->SetTitle("Color-Pickers");
|
||||||
colorpicker_window->MinSize({600, 150});
|
colorpicker_window->MinSize({300, 150});
|
||||||
colorpicker_window->Size({600_px, 150_px});
|
colorpicker_window->Size({400_px, 150_px});
|
||||||
colorpicker_window->Position({50_px, 50_px});
|
colorpicker_window->Position({50_px, 50_px});
|
||||||
|
|
||||||
auto* col_layout = new JUI::HorizontalListLayout(colorpicker_window->Content());
|
auto* col_layout = new JUI::HorizontalListLayout(colorpicker_window->Content());
|
||||||
@@ -285,6 +302,7 @@ void FractalInspectorApp::CreateMenu() {
|
|||||||
console->OnInput += [this] (const std::string& message) {
|
console->OnInput += [this] (const std::string& message) {
|
||||||
ParseCmdLineMessage(message);
|
ParseCmdLineMessage(message);
|
||||||
};
|
};
|
||||||
|
console->Close();
|
||||||
|
|
||||||
|
|
||||||
mandelbrotset_dialog = new JUI::Window(scene);
|
mandelbrotset_dialog = new JUI::Window(scene);
|
||||||
@@ -340,21 +358,36 @@ void FractalInspectorApp::CreateMenu() {
|
|||||||
juliaset_dialog->Size({900_px, 70_px});
|
juliaset_dialog->Size({900_px, 70_px});
|
||||||
juliaset_dialog->Close(); // Defaults to close.
|
juliaset_dialog->Close(); // Defaults to close.
|
||||||
|
|
||||||
auto* julia_x_slider = new JUI::Slider(juliaset_dialog->Content());
|
julia_x_slider = new JUI::Slider(juliaset_dialog->Content());
|
||||||
|
julia_x_label = new JUI::Text(julia_x_slider);
|
||||||
|
|
||||||
|
julia_x_label->AlignCenterHorizontally();
|
||||||
|
julia_x_label->AlignTop();
|
||||||
|
julia_x_label->SetTextColor(Colors::Black);
|
||||||
|
julia_x_label->SetContent("X: 0");
|
||||||
|
|
||||||
julia_x_slider->Size({900_px, 25_px});
|
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->Interval(1e-5f); julia_x_slider->Minimum(0); julia_x_slider->Maximum(1);
|
||||||
julia_x_slider->ValueChanged += [this] (double value) {
|
julia_x_slider->ValueChanged += [this] (double value) {
|
||||||
|
julia_x_label->SetContent(std::format("X: {}", Math::FloorInt(value*360)));
|
||||||
value = value * 2;
|
value = value * 2;
|
||||||
value = value - 1;
|
value = value - 1;
|
||||||
u_julia_set.x = value;
|
u_julia_set.x = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* julia_y_slider = new JUI::Slider(juliaset_dialog->Content());
|
julia_y_slider = new JUI::Slider(juliaset_dialog->Content());
|
||||||
|
julia_y_label = new JUI::Text(julia_y_slider);
|
||||||
|
|
||||||
|
julia_y_label->AlignCenterHorizontally();
|
||||||
|
julia_y_label->AlignTop();
|
||||||
|
julia_y_label->SetTextColor(Colors::Black);
|
||||||
|
julia_y_label->SetContent("Y: 0");
|
||||||
|
|
||||||
julia_y_slider->Size({900_px, 25_px});
|
julia_y_slider->Size({900_px, 25_px});
|
||||||
julia_y_slider->Position({0_px, 30_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->Interval(1e-5f); julia_y_slider->Minimum(0); julia_y_slider->Maximum(1);
|
||||||
julia_y_slider->ValueChanged += [this] (double value) {
|
julia_y_slider->ValueChanged += [this] (double value) {
|
||||||
|
julia_y_label->SetContent(std::format("Y: {}", Math::FloorInt(value*360)));
|
||||||
value = value * 2;
|
value = value * 2;
|
||||||
value = value - 1;
|
value = value - 1;
|
||||||
u_julia_set.y = value;
|
u_julia_set.y = value;
|
||||||
@@ -523,6 +556,9 @@ void FractalInspectorApp::Update(float elapsed) {
|
|||||||
Math::Round(u_translation.x, 4), Math::Round(u_translation.y, 4), readable_scale, fps);
|
Math::Round(u_translation.x, 4), Math::Round(u_translation.y, 4), readable_scale, fps);
|
||||||
|
|
||||||
fps_label->SetContent(fps_text);
|
fps_label->SetContent(fps_text);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float FractalInspectorApp::ReadableScale() {
|
float FractalInspectorApp::ReadableScale() {
|
||||||
@@ -556,6 +592,16 @@ void FractalInspectorApp::UpdateShaderUniforms(float elapsed) {
|
|||||||
shader.SetVector2("u_translation", u_translation);
|
shader.SetVector2("u_translation", u_translation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 solve(Vector2 a, Vector2 b) {
|
||||||
|
float real = (a.x*a.x) + (-1 * a.y*a.y);
|
||||||
|
float imag = (a.x*a.y)*2;
|
||||||
|
|
||||||
|
real += b.x;
|
||||||
|
imag += b.y;
|
||||||
|
|
||||||
|
return {real, imag};
|
||||||
|
}
|
||||||
|
|
||||||
void FractalInspectorApp::Draw() {
|
void FractalInspectorApp::Draw() {
|
||||||
|
|
||||||
Shader::UseDefault();
|
Shader::UseDefault();
|
||||||
@@ -570,6 +616,47 @@ void FractalInspectorApp::Draw() {
|
|||||||
J2D::DrawRenderTarget(canvas, {0, 0});
|
J2D::DrawRenderTarget(canvas, {0, 0});
|
||||||
J2D::End();
|
J2D::End();
|
||||||
|
|
||||||
|
// This is annoying, leaving note here to comment it out when I work on this - maxine
|
||||||
|
J2D::Begin();
|
||||||
|
|
||||||
|
const float N = 512.f;
|
||||||
|
const float B = 2.f;
|
||||||
|
|
||||||
|
auto mpos_ipair = GetMouseCoordinates();
|
||||||
|
Vector2 mpos (mpos_ipair.x, mpos_ipair.y);
|
||||||
|
Vector2 R(GetWidth(), GetHeight());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Vector2 trans = Vector2(0, R.y) - u_translation;
|
||||||
|
|
||||||
|
Vector2 z = Vector2(0, 0);
|
||||||
|
|
||||||
|
Vector2 c = ScreenSpaceToFractalSpace(mpos);
|
||||||
|
Vector2 last_z = c;
|
||||||
|
|
||||||
|
J2D::FillCircle(Colors::Red, FractalSpaceToScreenSpace(ScreenSpaceToFractalSpace(mpos)), 6);
|
||||||
|
|
||||||
|
|
||||||
|
for (float i = 0.f; i < N; i++) {
|
||||||
|
float x = z.x;
|
||||||
|
float y = z.y;
|
||||||
|
Vector2 z_nplus1 = Vector2(x*x - y*y, y*x + x*y) + c;
|
||||||
|
|
||||||
|
|
||||||
|
J2D::DrawLine(Colors::White, FractalSpaceToScreenSpace(z), FractalSpaceToScreenSpace(last_z), 0.25);
|
||||||
|
|
||||||
|
last_z = z;
|
||||||
|
z = z_nplus1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (Vector2::Dot(z, z) > B*B) break;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
J2D::End();
|
||||||
|
|
||||||
scene->Draw();
|
scene->Draw();
|
||||||
|
|
||||||
JGL::J2D::Begin(canvas, true);
|
JGL::J2D::Begin(canvas, true);
|
||||||
|
Reference in New Issue
Block a user