/* * * Copyright (C) 2024 Brett Terpstra * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #define FUNCTION_COORD() \ int xi = static_cast(x); \ int yi = static_cast(y); #define GET_IMAGE(name, pos) auto name = argv[pos]->get(xi, yi); #define SINGLE_FUNCTION(op) \ FUNCTION_COORD() \ GET_IMAGE(i1, 0) \ img.set(blt::vec3{op(i1.x()), op(i1.y()), op(i1.z())}, xi, yi); #define DOUBLE_FUNCTION(op) \ FUNCTION_COORD() \ GET_IMAGE(i1, 0) \ GET_IMAGE(i2, 1) \ img.set(blt::vec3{op(i1.x(), i2.x()), op(i1.y(), i2.y()), op(i1.z(), i2.z())}, xi, yi); #define BITWISE_FUNCTION(op) \ FUNCTION_COORD() \ GET_IMAGE(i1, 0) \ GET_IMAGE(i2, 1) \ auto bitsRI1 = blt::mem::type_cast(i1.x()); \ auto bitsGI1 = blt::mem::type_cast(i1.y()); \ auto bitsBI1 = blt::mem::type_cast(i1.z()); \ \ auto bitsRI2 = blt::mem::type_cast(i2.x()); \ auto bitsGI2 = blt::mem::type_cast(i2.y()); \ auto bitsBI2 = blt::mem::type_cast(i2.z()); \ \ auto r = blt::mem::type_cast(bitsRI1 op bitsRI2); \ auto g = blt::mem::type_cast(bitsGI1 op bitsGI2); \ auto b = blt::mem::type_cast(bitsBI1 op bitsBI2); \ \ img.set(blt::vec3{r, g, b}, xi, yi); inline float protect_div(float x, float y, float d = 0) { if (y == 0) return d; return x / y; } void f_x(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { img = x; } void f_y(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { img = y; } void f_random(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { static std::random_device dev; static std::mt19937_64 engine(dev()); static std::uniform_real_distribution dist(0, 1); img = dist(engine); } void f_noise(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { float z = 0.5; float scaleX = width; float scaleY = height; if (argc >= 1) scaleX *= argv[0]->get().x(); if (argc > 1) scaleY *= argv[1]->get().x(); auto val = stb_perlin_noise3(protect_div(x, scaleX, z), protect_div(y, scaleY, z), z, 0, 0, 0); img.set({val, val, val}, static_cast(x), static_cast(y)); } void f_cnoise(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { float z = 0.5; float scaleRX = width; float scaleGX = width; float scaleBX = width; float scaleRY = height; float scaleGY = height; float scaleBY = height; if (argc >= 1) scaleRX *= argv[0]->get().x(); if (argc > 1) scaleRY *= argv[1]->get().x(); if (argc >= 3) scaleRX *= argv[2]->get().x(); if (argc > 3) scaleRY *= argv[3]->get().x(); if (argc >= 5) scaleRX *= argv[4]->get().x(); if (argc > 5) scaleRY *= argv[5]->get().x(); auto valR = stb_perlin_noise3(protect_div(x, scaleRX, z), protect_div(y, scaleRY, z), z, 0, 0, 0); auto valG = stb_perlin_noise3(protect_div(x, scaleGX, z), protect_div(y, scaleGY, z), z, 0, 0, 0); auto valB = stb_perlin_noise3(protect_div(x, scaleBX, z), protect_div(y, scaleBY, z), z, 0, 0, 0); img.set({valR, valG, valB}, static_cast(x), static_cast(y)); } void f_scalar(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { img = extra_data[0]; } void f_color(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { img = blt::vec3{extra_data[0], extra_data[1], extra_data[2]}; } void f_log(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { SINGLE_FUNCTION(std::log); } void f_sqrt(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { SINGLE_FUNCTION(std::sqrt); } void f_sin(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD_SIN(x) ((std::sin(x) + 1) * 0.5f) SINGLE_FUNCTION(F_MOD_SIN); #undef F_MOD_SIN } void f_cos(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD_COS(x) ((std::cos(x) + 1) * 0.5f) SINGLE_FUNCTION(F_MOD_COS); #undef F_MOD_COS } void f_atan(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD_ATAN(x) ((std::atan(x) + 1) * 0.5f) SINGLE_FUNCTION(F_MOD_ATAN); #undef F_MOD_ATAN } void f_add(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD(x, y) (x + y) DOUBLE_FUNCTION(F_MOD); #undef F_MOD } void f_sub(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD(x, y) (x - y) DOUBLE_FUNCTION(F_MOD); #undef F_MOD } void f_mul(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD(x, y) (x * y) DOUBLE_FUNCTION(F_MOD); #undef F_MOD } void f_div(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { #define F_MOD(x, y) protect_div(x, y) DOUBLE_FUNCTION(F_MOD); #undef F_MOD } void f_or(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { BITWISE_FUNCTION(|); } void f_and(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { BITWISE_FUNCTION(&); } void f_xor(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { BITWISE_FUNCTION(^); } void f_if(image& img, float x, float y, blt::size_t argc, const image** argv, const data_t& extra_data) { FUNCTION_COORD(); GET_IMAGE(i1, 0); GET_IMAGE(i2, 1); GET_IMAGE(i3, 2); constexpr float SCALE = 0.1; if (i1.x() > SCALE || i1.x() < -SCALE) img.set(i2, xi, yi); else img.set(i3, xi, yi); } double on_data(const double* data, blt::size_t len) { const static float NEGATION = 0; willbruh results(data, len); switch (results->error) { case 0: if (!std::isnan(results->estimate)) return results->estimate; return 0; case 1: BLT_INFO("Somehow we have sent more than 5000 values!"); return 0; default: return 0; case -2: // should never consider this a valid solution / punish for having large sections of no difference return NEGATION; } } float eval_DNF_SW(const image& img) { std::vector order(width * height); for (const auto& v : img.getData()) order.push_back(v.magnitude()); std::sort(order.begin(), order.end()); blt::size_t len = 5000; blt::size_t current_pos = 0; double total = 0; while (true) { if (order.size() - current_pos < len) { len = order.size() - current_pos; if (len <= 0) break; } total += on_data(order.data() + current_pos, len); current_pos += len; } return static_cast(total); } float eval_DNF_KS(const image& img) { return 0; }