#pragma once /* * 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 #ifndef IMAGE_GP_6_IMAGE_OPERATIONS_H #define IMAGE_GP_6_IMAGE_OPERATIONS_H inline blt::gp::operation_t add(make_double(std::plus()), "add"); inline blt::gp::operation_t sub(make_double(std::minus()), "sub"); inline blt::gp::operation_t mul(make_double(std::multiplies()), "mul"); inline blt::gp::operation_t pro_div([](const full_image_t& a, const full_image_t& b) { full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) img.rgb_data[i] = b.rgb_data[i] == 0 ? 0 : (a.rgb_data[i] / b.rgb_data[i]); return img; }, "div"); inline blt::gp::operation_t op_sin(make_single([](float a) { return (std::sin(a) + 1.0f) / 2.0f; }), "sin"); inline blt::gp::operation_t op_cos(make_single([](float a) { return (std::cos(a) + 1.0f) / 2.0f; }), "cos"); inline blt::gp::operation_t op_atan(make_single((float (*)(float)) &std::atan), "atan"); inline blt::gp::operation_t op_exp(make_single((float (*)(float)) &std::exp), "exp"); inline blt::gp::operation_t op_abs(make_single((float (*)(float)) &std::abs), "abs"); inline blt::gp::operation_t op_log(make_single((float (*)(float)) &std::log), "log"); inline blt::gp::operation_t op_v_mod([](const full_image_t& a, const full_image_t& b) { full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) img.rgb_data[i] = b.rgb_data[i] <= 0 ? 0 : static_cast(blt::mem::type_cast(a.rgb_data[i]) % blt::mem::type_cast(b.rgb_data[i])); return img; }, "v_mod"); inline blt::gp::operation_t bitwise_and([](const full_image_t& a, const full_image_t& b) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) img.rgb_data[i] = static_cast(type_cast(a.rgb_data[i]) & type_cast(b.rgb_data[i])); return img; }, "and"); inline blt::gp::operation_t bitwise_or([](const full_image_t& a, const full_image_t& b) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) img.rgb_data[i] = static_cast(type_cast(a.rgb_data[i]) | type_cast(b.rgb_data[i])); return img; }, "or"); inline blt::gp::operation_t bitwise_invert([](const full_image_t& a) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) img.rgb_data[i] = static_cast(~type_cast(a.rgb_data[i])); return img; }, "invert"); inline blt::gp::operation_t bitwise_xor([](const full_image_t& a, const full_image_t& b) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { auto in_a = type_cast(a.rgb_data[i]); auto in_b = type_cast(b.rgb_data[i]); img.rgb_data[i] = static_cast(in_a ^ in_b); } return img; }, "xor"); inline blt::gp::operation_t dissolve([](const full_image_t& a, const full_image_t& b) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { auto diff = (a.rgb_data[i] - b.rgb_data[i]) / 2.0f; img.rgb_data[i] = a.rgb_data[i] + diff; } return img; }, "dissolve"); inline blt::gp::operation_t band_pass([](const full_image_t& a, float min, float max) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { if (a.rgb_data[i] >= min && a.rgb_data[i] <= max) { img.rgb_data[i] = a.rgb_data[i]; } else if (a.rgb_data[i] < min) { auto dist_min = min == 0 ? 0.0f : (a.rgb_data[i] / min); img.rgb_data[i] = a.rgb_data[i] * dist_min; } else if (a.rgb_data[i] > max) { auto dist_max = max == 0 ? 0.0f : ((a.rgb_data[i] - max) / max); img.rgb_data[i] = a.rgb_data[i] * dist_max; } else { img.rgb_data[i] = 0; } } return img; }, "band_pass"); inline blt::gp::operation_t hsv_to_rgb([](const full_image_t& a) { using blt::mem::type_cast; full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto h = static_cast(a.rgb_data[i * CHANNELS + 0]) % 360; auto s = a.rgb_data[i * CHANNELS + 1]; auto v = a.rgb_data[i * CHANNELS + 2]; auto c = v * s; auto x = c * static_cast(1 - std::abs(((h / 60) % 2) - 1)); auto m = v - c; blt::vec3 rgb; if (h >= 0 && h < 60) rgb = {c, x, 0.0f}; else if (h >= 60 && h < 120) rgb = {x, c, 0.0f}; else if (h >= 120 && h < 180) rgb = {0.0f, c, x}; else if (h >= 180 && h < 240) rgb = {0.0f, x, c}; else if (h >= 240 && h < 300) rgb = {x, 0.0f, c}; else if (h >= 300 && h < 360) rgb = {c, 0.0f, x}; img.rgb_data[i * CHANNELS] = rgb.x() + m; img.rgb_data[i * CHANNELS + 1] = rgb.y() + m; img.rgb_data[i * CHANNELS + 2] = rgb.z() + m; } return img; }, "hsv"); inline blt::gp::operation_t lit([]() { full_image_t img{}; auto r = program.get_random().get_float(0.0f, 1.0f); auto g = program.get_random().get_float(0.0f, 1.0f); auto b = program.get_random().get_float(0.0f, 1.0f); for (blt::size_t i = 0; i < DATA_SIZE; i++) { img.rgb_data[i * CHANNELS] = r; img.rgb_data[i * CHANNELS + 1] = g; img.rgb_data[i * CHANNELS + 2] = b; } return img; }, "lit"); inline blt::gp::operation_t random_val([]() { full_image_t img{}; for (auto& i : img.rgb_data) i = program.get_random().get_float(0.0f, 1.0f); return img; }, "color_noise"); inline blt::gp::operation_t perlin([](const full_image_t& x, const full_image_t& y, const full_image_t& z, const full_image_t& scale) { full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { auto s = scale.rgb_data[i]; img.rgb_data[i] = perlin_noise(x.rgb_data[i] / s, y.rgb_data[i] / s, z.rgb_data[i] / s); } return img; }, "perlin"); inline blt::gp::operation_t perlin_terminal([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { auto ctx = get_ctx(i); img.rgb_data[i] = perlin_noise(ctx.x / IMAGE_SIZE, ctx.y / IMAGE_SIZE, static_cast(i % CHANNELS) / CHANNELS); } return img; }, "perlin_term"); inline blt::gp::operation_t perlin_warped([](const full_image_t& u, const full_image_t& v) { full_image_t img{}; for (blt::size_t i = 0; i < DATA_CHANNELS_SIZE; i++) { auto ctx = get_ctx(i); img.rgb_data[i] = perlin_noise(ctx.x / IMAGE_SIZE + u.rgb_data[i], ctx.y / IMAGE_SIZE + v.rgb_data[i], static_cast(i % CHANNELS) / CHANNELS); } return img; }, "perlin_warped"); inline blt::gp::operation_t op_img_size([]() { full_image_t img{}; for (float& i : img.rgb_data) { i = IMAGE_SIZE; } return img; }, "img_size"); inline blt::gp::operation_t op_x_r([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).x; img.rgb_data[i * CHANNELS] = ctx; img.rgb_data[i * CHANNELS + 1] = 0; img.rgb_data[i * CHANNELS + 2] = 0; } return img; }, "x_r"); inline blt::gp::operation_t op_x_g([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).x; img.rgb_data[i * CHANNELS] = 0; img.rgb_data[i * CHANNELS + 1] = ctx; img.rgb_data[i * CHANNELS + 2] = 0; } return img; }, "x_g"); inline blt::gp::operation_t op_x_b([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).x; img.rgb_data[i * CHANNELS] = 0; img.rgb_data[i * CHANNELS + 1] = 0; img.rgb_data[i * CHANNELS + 2] = ctx; } return img; }, "x_b"); inline blt::gp::operation_t op_x_rgb([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).x; img.rgb_data[i * CHANNELS] = ctx; img.rgb_data[i * CHANNELS + 1] = ctx; img.rgb_data[i * CHANNELS + 2] = ctx; } return img; }, "x_rgb"); inline blt::gp::operation_t op_y_r([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).y; img.rgb_data[i * CHANNELS] = ctx; img.rgb_data[i * CHANNELS + 1] = 0; img.rgb_data[i * CHANNELS + 2] = 0; } return img; }, "y_r"); inline blt::gp::operation_t op_y_g([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).y; img.rgb_data[i * CHANNELS] = 0; img.rgb_data[i * CHANNELS + 1] = ctx; img.rgb_data[i * CHANNELS + 2] = 0; } return img; }, "y_g"); inline blt::gp::operation_t op_y_b([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).y; img.rgb_data[i * CHANNELS] = 0; img.rgb_data[i * CHANNELS + 1] = 0; img.rgb_data[i * CHANNELS + 2] = ctx; } return img; }, "y_b"); inline blt::gp::operation_t op_y_rgb([]() { full_image_t img{}; for (blt::size_t i = 0; i < DATA_SIZE; i++) { auto ctx = get_ctx(i).y; img.rgb_data[i * CHANNELS] = ctx; img.rgb_data[i * CHANNELS + 1] = ctx; img.rgb_data[i * CHANNELS + 2] = ctx; } return img; }, "y_rgb"); template void create_image_operations(blt::gp::operator_builder& builder) { builder.add_operator(perlin); builder.add_operator(perlin_terminal); builder.add_operator(perlin_warped); builder.add_operator(add); builder.add_operator(sub); builder.add_operator(mul); builder.add_operator(pro_div); builder.add_operator(op_sin); builder.add_operator(op_cos); builder.add_operator(op_atan); builder.add_operator(op_exp); builder.add_operator(op_log); builder.add_operator(op_abs); builder.add_operator(op_v_mod); builder.add_operator(bitwise_and); builder.add_operator(bitwise_or); builder.add_operator(bitwise_invert); builder.add_operator(bitwise_xor); builder.add_operator(dissolve); builder.add_operator(band_pass); builder.add_operator(hsv_to_rgb); bool state = false; builder.add_operator(lit, true); builder.add_operator(random_val); builder.add_operator(op_x_r, state); builder.add_operator(op_x_g, state); builder.add_operator(op_x_b, state); builder.add_operator(op_x_rgb, state); builder.add_operator(op_y_r, state); builder.add_operator(op_y_g, state); builder.add_operator(op_y_b, state); builder.add_operator(op_y_rgb, state); } #endif //IMAGE_GP_6_IMAGE_OPERATIONS_H