Skip to content

Commit

Permalink
Add kaleid0sc0pe filter
Browse files Browse the repository at this point in the history
Original implementation from https://github.com/gbendy/kaleidoscope

Includes minor modifications to build correctly in the frei0r source
tree.
  • Loading branch information
gbendy committed Jul 18, 2023
1 parent c3f987c commit ca2361a
Show file tree
Hide file tree
Showing 12 changed files with 2,749 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/filter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ add_subdirectory (glitch0r)
#add_subdirectory (host_param_test)
add_subdirectory (hueshift0r)
add_subdirectory (invert0r)
add_subdirectory (kaleid0sc0pe)
add_subdirectory (keyspillm0pup)
add_subdirectory (lenscorrection)
add_subdirectory (letterb0xed)
Expand Down
62 changes: 62 additions & 0 deletions src/filter/kaleid0sc0pe/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
include(CheckIncludeFileCXX)
include(CheckCSourceCompiles)

cmake_policy(SET CMP0056 NEW)
cmake_policy(SET CMP0066 NEW)
cmake_policy(SET CMP0067 NEW)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

set (SOURCES api.cpp ikaleid0sc0pe.h kaleid0sc0pe.cpp kaleid0sc0pe.h sse_mathfun_extension.h sse_mathfun.h)
set (TARGET kaleid0sc0pe)

if (MSVC)
set (SOURCES ${SOURCES} ${FREI0R_DEF})
endif (MSVC)

add_library (${TARGET} MODULE ${SOURCES})
set_target_properties (${TARGET} PROPERTIES PREFIX "")

if (NOT WIN32)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(${TARGET} PRIVATE Threads::Threads)
endif()

if(NO_SSE2)
message(STATUS "SSE2 is disabled")
add_definitions(-DNO_SSE2)
else()
check_include_file_cxx(immintrin.h HAS_INTEL_INTRINSICS)
if (HAS_INTEL_INTRINSICS)
add_definitions(-DHAS_INTEL_INTRINSICS)
if (NOT WIN32)
target_compile_options(${TARGET} PRIVATE -msse2)
set(CMAKE_REQUIRED_FLAGS "-msse2")
endif()
check_c_source_compiles("
#include <emmintrin.h>
#include <immintrin.h>
int main(){ __m128 a = _mm_set1_ps(0.0f); a = _mm_sin_ps(a); return 0;}" HAS_SIN_INTRINSIC)
check_c_source_compiles("
#include <emmintrin.h>
#include <immintrin.h>
int main(){ __m128 a = _mm_set1_ps(0.0f); a = _mm_cos_ps(a); return 0;}" HAS_COS_INTRINSIC)
check_c_source_compiles("
#include <emmintrin.h>
#include <immintrin.h>
int main(){ __m128 a = _mm_set1_ps(0.0f); __m128 b = _mm_set1_ps(0.0f); a = _mm_atan2_ps(a,b); return 0;}" HAS_ATAN2_INTRINSIC)
if (HAS_SIN_INTRINSIC)
add_definitions(-DHAS_SIN_INTRINSIC)
endif()
if (HAS_COS_INTRINSIC)
add_definitions(-DHAS_COS_INTRINSIC)
endif()
if (HAS_ATAN2_INTRINSIC)
add_definitions(-DHAS_ATAN2_INTRINSIC)
endif()
endif()
endif()

install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
41 changes: 41 additions & 0 deletions src/filter/kaleid0sc0pe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Kaleidoscope

A [frei0r](https://frei0r.dyne.org "frei0r") plugin to produce a kaleidoscope effect.

Written by Brendan Hack. Original source repository at [https://github.com/gbendy/kaleidoscope](https://github.com/gbendy/kaleidoscope "https://github.com/gbendy/kaleidoscope").

| ["Colorful Stones"](https://www.flickr.com/photos/82955120@N05/7995277667 "Colorful Stones") by ["Bold Frontiers"](https://www.flickr.com/photos/82955120@N05 "Bold Frontiers") | kaleid0sc0ped |
| - | - |
| [![Colorful Stones](colorful_stones-400.jpg)](colorful_stones.jpg) | [![Kaleidoscoped Colorful Stones](colorful_stones-tr16-400.jpg)](colorful_stones-tr16.jpg) |
|Licensed under [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/?ref=ccsearch&atype=html "CC BY 2.0") | Segmentation 16, source segment centred to top right|

| [Created Many and Strange (Official Music Video)](https://www.youtube.com/watch?v=2r9ggSie1wI) (YouTube) by [Spaceman Paul](https://github.com/SpacemanPaul "Spaceman Paul") |
| --- |
| [![Created Many and Strange (Official Music Video) by @SpacemanPaul](https://img.youtube.com/vi/2r9ggSie1wI/0.jpg)](https://www.youtube.com/watch?v=2r9ggSie1wI) |
| Animated Music Video created in [KdenLive](https://kdenlive.org) by [Spaceman Paul](https://www.youtube.com/channel/UCBVFfRZw4Vbk3j6mNCukztg) |

Allows for specification of number of segments (mirrors), auto selection of optimal source reflection segment, placement of origin and much more!

# Parameters

1. `origin_x` `(float=0.5)` - Origin of the kaleid0sc0pe in x. Range `[0, 1]`.
2. `origin_y` `(float=0.5)` - Origin of the kaleid0sc0pe in y. Range `[0, 1]`.
3. `segmentation` `(float=16/128)` - The kaleid0sc0pe effect is broken into `segmentation * 128` segments. Segmentations of 1, 2 or multiples of 4 work best. Range `[0, 1]`.
4. `specify_source` `(bool=false)` - If `true` then the source segment for the mirror is specified by `source_segment`. Otherwise the furthest corner from the origin is used as the source segment and the segment's orientation is defined by `segmentation_direction`. When multiple corners are the same distance the tie is broken according to the `preferred_corner` and `corner_search` parameters.
5. `source_segment` `(float=0)` - Normalized angle that specifies the centre of the source segment if `specify_source` is `true`. `0` is in `+x` and rotates counter clockwise. Range `[0, 1]`.
6. `segmentation_direction` `(float=1)` - When `source_segment` is `false` the source segement is either centred on the corner (< `1/3`), extends counter clockwise from the corner (< `2/3`) or clockwise from the corner (>= `2/3` the default). Range `[0, 1]`.
7. `reflect_edges` `(bool=true)` - If `true` then reflections that end up outside the frame reflect back into it, otherwise the colour specified in `bg_color` is used.
8. `edge_threshold` `(float=0)` - if `reflect_edges` is `false` then reflections outside the frame but within `edge_threshold * 4` pixels of the frame clamp to the edge value rather than use the background color. Range `[0, 1]`.
9. `preferred_corner` `(float=0)` - The preferred corner when breaking ties when searching for the furthest corner. Searching starts in this corner and proceeds in the direction given in `corner_search`. The first and furthest corner found wins. Supported values are `0`: top right (default), `0.25`: top left, `0.5`: bottom left, `0.75`: bottom right.
10. `corner_search` `(bool=true)` - If `true` search clockwise for furthest corner, otherwise counter clockwise.
11. `bg_color` `(color=1,0,1)` - Color used when reflections end up outside the frame and `reflect_edges` is `false`.
12. `bg_alpha` `(float=1)` - Alpha value to use when reflections end up outside the frame and `reflect_edges` is `false`. Range `[0, 1]`.
13. `multithreaded` `(bool=true)` - If `true` then processing is multithreaded.
14. `n_threads` `(float=0)` - If `multithreaded` is `true` then the number of threads to use. `0` autocalculates otherwise `n_threads * 32` threads are used. Range `[0, 1]`.

# Contributors

This filter exists thanks to all the people who contribute.

- [Brendan Hack](https://github.com/gbendy "Brendan Hack")
- [Spaceman Paul](https://github.com/SpacemanPaul "Spaceman Paul")
178 changes: 178 additions & 0 deletions src/filter/kaleid0sc0pe/api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* api.cpp
* Copyright (C) 2020-2023 Brendan Hack ([email protected])
* This file is part of a Frei0r plugin that applies a kaleidoscope
* effect.
* Version 1.1 july 2023
*
* Implements the Frei0r interface
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This source code 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. Please refer
* to the GNU Public License for more details.
*
* You should have received a copy of the GNU Public License along
* with this source code; if not, write to: Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "frei0r.hpp"
#include "ikaleid0sc0pe.h"

class kaleid0sc0pe : public frei0r::filter
{
public:
kaleid0sc0pe(unsigned int width, unsigned int height):
m_kaleid0sc0pe(libkaleid0sc0pe::IKaleid0sc0pe::factory(width,height,1,4)),
m_origin_x(0.5),
m_origin_y(0.5),
m_segmentation(16/128.0),
m_direction(1.0),
m_corner(0),
m_corner_direction(true),
m_reflect_edges(true),
m_edge_threshold(0),
m_bg_alpha(1),
m_specify_source(false),
m_source_segment(0),
m_multithreaded(true),
m_threads(0)
{
m_bg_colour.r = 1.0;
m_bg_colour.g = 0.0;
m_bg_colour.b = 1.0;

register_param(m_origin_x,
"origin_x",
"origin of the kaleid0sc0pe in x. default 0.5");
register_param(m_origin_y,
"origin_y",
"origin of the kaleid0sc0pe in y. default 0.5");
register_param(m_segmentation,
"segmentation",
"kaleid0sc0pe segmentation / 128, segmentations of 1, 2 or multiples of 4 work best. default 16/128");
register_param(m_specify_source,
"specify_source",
"if true then source angle is read from source_segment, otherwise auto-calculated");
register_param(m_source_segment,
"source_segment",
"centre of source segment if specify_source is true. 0 is in +x and rotates counter clockwise");
register_param(m_direction,
"segmentation_direction",
"segmentation direction, < 1/3 is none, < 2/3 is counter clockwise, otherwise clockwise");
register_param(m_reflect_edges,
"reflect_edges",
"if true then reflections that end up outside the source reflect back into it, otherwise the specified background colour is used.");
register_param(m_edge_threshold,
"edge_threshold",
"edge threshold / 4, reflections outside the image but within this distance clamp to the edge. default 0");
register_param(m_corner,
"preferred_corner",
"preferred corner, 0 is top right, 0.25 top left, 0.5 bottom left, 0.75 bottom right");
register_param(m_corner_direction,
"corner_search",
"if true search clockwise for furthest corner, otherwise counter clockwise");
register_param(m_bg_colour,
"bg_color",
"colour to use if reflection lies outside of source image and not reflecting back in. default 1,0,1");
register_param(m_bg_alpha,
"bg_alpha",
"alpha to use if reflection lies outside of source image and not reflecting back in. default 1");
register_param(m_multithreaded,
"multithreaded",
"set to true to enable multithreaded calculation. default true");
register_param(m_threads,
"n_threads",
"the number of threads to use, if 0 then autocalculate otherwise value * 32. default 0");


m_kaleid0sc0pe->set_background_colour(m_background);
}

virtual void update(double time,
uint32_t* out,
const uint32_t* in) {

update_params();
m_kaleid0sc0pe->process(in, out);
}

private:
void update_params()
{
m_kaleid0sc0pe->set_origin(static_cast<float>(m_origin_x), static_cast<float>(m_origin_y));
m_kaleid0sc0pe->set_segmentation(static_cast<std::uint32_t>(m_segmentation * 128));
if (m_direction < 1/3.0) {
m_kaleid0sc0pe->set_segment_direction(libkaleid0sc0pe::IKaleid0sc0pe::Direction::NONE);
} else if (m_direction < 2/3.0) {
m_kaleid0sc0pe->set_segment_direction(libkaleid0sc0pe::IKaleid0sc0pe::Direction::ANTICLOCKWISE);
} else {
m_kaleid0sc0pe->set_segment_direction(libkaleid0sc0pe::IKaleid0sc0pe::Direction::CLOCKWISE);
}
if (m_corner < 0.25) {
m_kaleid0sc0pe->set_preferred_corner(libkaleid0sc0pe::IKaleid0sc0pe::Corner::TR);
} else if (m_corner < 0.5) {
m_kaleid0sc0pe->set_preferred_corner(libkaleid0sc0pe::IKaleid0sc0pe::Corner::TL);
} else if (m_corner < 0.75) {
m_kaleid0sc0pe->set_preferred_corner(libkaleid0sc0pe::IKaleid0sc0pe::Corner::BL);
} else {
m_kaleid0sc0pe->set_preferred_corner(libkaleid0sc0pe::IKaleid0sc0pe::Corner::BR);
}
if (m_corner_direction) {
m_kaleid0sc0pe->set_preferred_corner_search_direction(libkaleid0sc0pe::IKaleid0sc0pe::Direction::CLOCKWISE);
} else {
m_kaleid0sc0pe->set_preferred_corner_search_direction(libkaleid0sc0pe::IKaleid0sc0pe::Direction::ANTICLOCKWISE);
}
m_kaleid0sc0pe->set_reflect_edges(m_reflect_edges);
m_kaleid0sc0pe->set_edge_threshold(static_cast<std::uint32_t>(m_edge_threshold * 4));

if (m_specify_source) {
m_kaleid0sc0pe->set_source_segment(static_cast<float>(m_source_segment) * 3.141592654f * 2);
} else {
m_kaleid0sc0pe->set_source_segment(-1);
}
if (m_multithreaded) {
m_kaleid0sc0pe->set_threading(static_cast<std::uint32_t>(m_threads * 32));
} else {
m_kaleid0sc0pe->set_threading(1);
}
m_background[0] = static_cast<std::uint8_t>(m_bg_colour.r * 255);
m_background[1] = static_cast<std::uint8_t>(m_bg_colour.g * 255);
m_background[2] = static_cast<std::uint8_t>(m_bg_colour.b * 255);
m_background[3] = static_cast<std::uint8_t>(m_bg_alpha * 255);
}

double m_origin_x;
double m_origin_y;

double m_segmentation;
double m_direction;

double m_corner;
bool m_corner_direction;

bool m_reflect_edges;

double m_edge_threshold;

f0r_param_color m_bg_colour;
double m_bg_alpha;

bool m_specify_source;
double m_source_segment;

bool m_multithreaded;
double m_threads;

std::uint8_t m_background[4];

std::unique_ptr<libkaleid0sc0pe::IKaleid0sc0pe> m_kaleid0sc0pe;
};

frei0r::construct<kaleid0sc0pe> plugin("Kaleid0sc0pe", "Applies a kaleid0sc0pe effect", "Brendan Hack", 1, 1, F0R_COLOR_MODEL_RGBA8888);
Binary file added src/filter/kaleid0sc0pe/colorful_stones-400.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ca2361a

Please sign in to comment.