aboutsummaryrefslogtreecommitdiff
path: root/extension/src/Utilities.cpp
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-08-17 20:25:25 +0200
committer GitHub <noreply@github.com>2023-08-17 20:25:25 +0200
commitaa9961b27a4859f088b037dd8037accb4e3119be (patch)
treee93af9cabfbefc6ea089a153399e04d74e4b605a /extension/src/Utilities.cpp
parentff0d38b5d53fa95609f2587a2be5205f0c0d3118 (diff)
parent9a086523513994b0183d5f7d479b2f82412177f6 (diff)
Merge pull request #146 from Nemrav/piechart2
Add Piecharts (gd 4.1)
Diffstat (limited to 'extension/src/Utilities.cpp')
-rw-r--r--extension/src/Utilities.cpp90
1 files changed, 90 insertions, 0 deletions
diff --git a/extension/src/Utilities.cpp b/extension/src/Utilities.cpp
index a912490..f09eae0 100644
--- a/extension/src/Utilities.cpp
+++ b/extension/src/Utilities.cpp
@@ -1,5 +1,7 @@
#include "Utilities.hpp"
+#include <numbers>
+
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
@@ -14,3 +16,91 @@ Ref<Image> OpenVic::load_godot_image(String const& path) {
return Image::load_from_file(path);
}
}
+
+// Get the polar coordinates of a pixel relative to the center
+static Vector2 getPolar(Vector2 UVin, Vector2 center) {
+ Vector2 relcoord = (UVin-center);
+ float dist = relcoord.length();
+ float theta = std::numbers::pi / 2 + atan2(relcoord.y, relcoord.x);
+ if (theta < 0.0f) theta += std::numbers::pi * 2;
+ return { dist, theta };
+}
+
+// From thebookofshaders, returns a gradient falloff
+static inline float parabola(float base, float x, float k){
+ return powf(base * x * (1.0 - x), k);
+}
+
+static inline float parabola_shadow(float base, float x){
+ return base * x * x;
+}
+
+static Color pie_chart_fragment(Vector2 UV, float radius, Array const& stopAngles, Array const& colours,
+ Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
+ Color trim_colour, float trim_size, float gradient_falloff, float gradient_base,
+ bool donut, bool donut_inner_trim, float donut_inner_radius) {
+
+ Vector2 coords = getPolar(UV, { 0.5, 0.5 });
+ float dist = coords.x;
+ float theta = coords.y;
+
+ Vector2 shadow_polar = getPolar(UV, shadow_displacement);
+ float shadow_peak = radius + (radius - donut_inner_radius) / 2.0;
+ float shadow_gradient = shadow_thickness + parabola_shadow(shadow_tightness * -10.0, shadow_polar.x + shadow_peak - shadow_radius);
+
+ // Inner hole of the donut => make it transparent
+ if (donut && dist <= donut_inner_radius) {
+ return { 0.1, 0.1, 0.1, shadow_gradient };
+ }
+ // Inner trim
+ else if (donut && donut_inner_trim && dist <= donut_inner_radius + trim_size) {
+ return { trim_colour, 1.0 };
+ }
+ // Interior
+ else if (dist <= radius-trim_size) {
+ Color col { 1.0f, 0.0f, 0.0f };
+ for (int i = 0; i < stopAngles.size(); i++){
+ if (theta <= float(stopAngles[i])) {
+ col = colours[i];
+ break;
+ }
+ }
+ float gradient = parabola(gradient_base, dist, gradient_falloff);
+ return { col * (1.0 - gradient), 1.0 };
+ }
+ // Outer trim
+ else if (dist <= radius) {
+ return { trim_colour, 1.0 };
+ }
+ // Outside the circle
+ else{
+ return { 0.1, 0.1, 0.1, shadow_gradient };
+ }
+}
+
+void OpenVic::draw_pie_chart(Ref<Image> image,
+ Array const& stopAngles, Array const& colours, float radius,
+ Vector2 shadow_displacement, float shadow_tightness, float shadow_radius, float shadow_thickness,
+ Color trim_colour, float trim_size, float gradient_falloff, float gradient_base,
+ bool donut, bool donut_inner_trim, float donut_inner_radius) {
+
+ ERR_FAIL_NULL_EDMSG(image, "Cannot draw pie chart to null image.");
+ const int32_t width = image->get_width();
+ const int32_t height = image->get_height();
+ ERR_FAIL_COND_EDMSG(width <= 0 || height <= 0, "Cannot draw pie chart to empty image.");
+ if (width != height) {
+ UtilityFunctions::push_warning("Drawing pie chart to non-square image: ", width, "x", height);
+ }
+ const int32_t size = std::min(width, height);
+ for (int32_t y = 0; y < size; ++y) {
+ for (int32_t x = 0; x < size; ++x) {
+ image->set_pixel(x, y, pie_chart_fragment(
+ { static_cast<float>(x) / static_cast<float>(size),
+ static_cast<float>(y) / static_cast<float>(size) },
+ radius, stopAngles, colours,
+ shadow_displacement, shadow_tightness, shadow_radius, shadow_thickness,
+ trim_colour, trim_size, gradient_falloff, gradient_base,
+ donut, donut_inner_trim, donut_inner_radius));
+ }
+ }
+}