mirror of
https://github.com/dyne/frei0r.git
synced 2025-12-05 14:19:59 +01:00
Compare commits
41 Commits
v2.4.0
...
a718fa601c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a718fa601c | ||
|
|
f081aa64d4 | ||
|
|
542c4bc0a9 | ||
|
|
ce386ca806 | ||
|
|
7a044cba04 | ||
|
|
27af2abfb4 | ||
|
|
3a720e4270 | ||
|
|
b0a990ed18 | ||
|
|
33aaa39ac7 | ||
|
|
69d0711057 | ||
|
|
40a50bec63 | ||
|
|
697fc9b2a5 | ||
|
|
91526e95fb | ||
|
|
e2ab161052 | ||
|
|
b061db50aa | ||
|
|
53e635ab3b | ||
|
|
a2b274ccce | ||
|
|
0dbbac5258 | ||
|
|
2183bc1cf6 | ||
|
|
65fa7ea8ea | ||
|
|
d6a0ea5268 | ||
|
|
69d23fc0a2 | ||
|
|
def52c449f | ||
|
|
772d2e5edb | ||
|
|
f11132bb4b | ||
|
|
455aa7d1f5 | ||
|
|
4a4503b1e8 | ||
|
|
8482bc9680 | ||
|
|
cf5cb9654d | ||
|
|
91f4cb3bbc | ||
|
|
fb4e92925f | ||
|
|
62dd46650c | ||
|
|
de67485abb | ||
|
|
5d8e8f8498 | ||
|
|
683e40f147 | ||
|
|
a12d01602b | ||
|
|
42ee3fee46 | ||
|
|
dcd39d95a7 | ||
|
|
ac46ae351d | ||
|
|
cd109d4452 | ||
|
|
542b9a9ddb |
49
AUTHORS.md
49
AUTHORS.md
@@ -6,4 +6,51 @@ Frei0r is a Dyne.org project maintained by Denis "Jaromil" Roio and Dan Dennedy.
|
||||
|
||||
## Developers who contributed, in alphabetic order:
|
||||
|
||||
Akito Iwakura, Albert Frisch, Ajrat Makhmutov, Brendan Hack, Brian Matherly, Burkhard Plaum, Carlo E. Prelz, Christoph Willing, Erik Beck, Esmane, Filippo Giunchedi, Gabriel Finch (Salsaman), Georg Seidel, Henner Zeller, Hedde Bosman, IOhannes M. Zmölnig, Janne Liljeblad, Jean-Baptiste Mardelle, Jean-François Fortin Tam , Jean-Sebastien Senecal, Jerome Blanchi (d.j.a.y), Joshua M. Doe, Luca Bigliardi, Maksim Golovkin (Максим Головкин), Marko Cebokli, Martin Bayer, Mathieu Guindon, Matthias Schnoell, Nicolas Carion, Niels Elburg, Phillip Promesberger, Raphael Graf, Richard Spindler, Richard Ling (Chungzuwalla), Robert Schweikert, Ross Lagerwall, Samuel Mimram, Simon A. Eugster, Sofian Audry, Stefano Sabatini, Steinar H. Gunderson, Thomas Coldrick, Thomas Perl, Till Theato, Vincent Pinon.
|
||||
Akito Iwakura
|
||||
Albert Frisch
|
||||
Ajrat Makhmutov
|
||||
Brendan Hack
|
||||
Brian Matherly
|
||||
Burkhard Plaum
|
||||
Carlo E. Prelz
|
||||
Christoph Willing
|
||||
Cynthia
|
||||
Erik Beck
|
||||
Esmane
|
||||
Filippo Giunchedi
|
||||
Gabriel Finch (Salsaman)
|
||||
Georg Seidel
|
||||
Henner Zeller
|
||||
Hedde Bosman
|
||||
IOhannes m. zmölnig
|
||||
Janne Liljeblad
|
||||
Jean-Baptiste Mardelle
|
||||
Jean-François Fortin Tam
|
||||
Jean-Sebastien Senecal
|
||||
Jerome Blanchi (d.j.a.y)
|
||||
Johann Jeg
|
||||
Joshua M. Doe
|
||||
Luca Bigliardi
|
||||
Maksim Golovkin (Максим Головкин)
|
||||
Marko Cebokli
|
||||
Martin Bayer
|
||||
Mathieu Guindon
|
||||
Matthias Schnöll
|
||||
Nicolas Carion
|
||||
Niels Elburg
|
||||
Phillip Promesberger
|
||||
Raphael Graf
|
||||
Richard Spindler
|
||||
Richard Ling (Chungzuwalla)
|
||||
Robert Schweikert
|
||||
Ross Lagerwall
|
||||
Samuel Mimram
|
||||
Simon A. Eugster
|
||||
Sofian Audry
|
||||
Stefano Sabatini
|
||||
Steinar H. Gunderson
|
||||
Thomas Coldrick
|
||||
Thomas Perl
|
||||
Till Theato
|
||||
Vadim Druzhin
|
||||
Vincent Pinon
|
||||
|
||||
11
BUILD.md
11
BUILD.md
@@ -10,6 +10,10 @@ The presence of optional libraries on the system will trigger compilation of ext
|
||||
|
||||
+ [Cairo](http://cairographics.org) required for cairo- filters and mixers
|
||||
|
||||
## Optional build flags
|
||||
|
||||
+ `-DWITHOUT_FACERECOGNITION=ON` - Disable face recognition plugins (facedetect and facebl0r) to avoid protobuf conflicts with applications like MLT
|
||||
|
||||
It is recommended to use a separate `build` sub-folder.
|
||||
|
||||
```
|
||||
@@ -18,6 +22,13 @@ cd build && cmake ../
|
||||
make
|
||||
```
|
||||
|
||||
To disable face recognition plugins (recommended when using with MLT):
|
||||
```
|
||||
mkdir -p build
|
||||
cd build && cmake -DWITHOUT_FACERECOGNITION=ON ../
|
||||
make
|
||||
```
|
||||
|
||||
Also ninja and nmake are supported through cmake:
|
||||
```
|
||||
cmake -G 'Ninja' ../
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
cmake_minimum_required (VERSION 3.12...3.31)
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
project (frei0r)
|
||||
set (VERSION 1.8)
|
||||
set (VERSION 2.5.1)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
option (WITHOUT_OPENCV "Disable plugins dependent upon OpenCV" OFF)
|
||||
option (WITHOUT_FACERECOGNITION "Disable facedetect plugin to avoid protobuf conflicts" OFF)
|
||||
|
||||
if (NOT WITHOUT_OPENCV)
|
||||
find_package (OpenCV)
|
||||
endif ()
|
||||
|
||||
@@ -53,6 +53,10 @@ Stable frei0r releases are built automatically and made available on
|
||||
|
||||
Frei0r sourcecode is released under the terms of the GNU General Public License and, eventually other compatible Free Software licenses.
|
||||
|
||||
## Packaging
|
||||
|
||||
[](https://repology.org/project/frei0r/versions)
|
||||
|
||||
## Build dependencies
|
||||
|
||||
Frei0r can be built on GNU/Linux, M$/Windows and Apple/OSX platforms, possibly in even more environments like embedded devices.
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
* @subsection sec_icon_location Icon location
|
||||
*
|
||||
* The exact location where the application should look for the
|
||||
* plugin is platform dependant.
|
||||
* plugin is platform dependent.
|
||||
*
|
||||
* For Windows platforms, the icon should be at the same place as
|
||||
* the plugin containing the effect.
|
||||
@@ -190,7 +190,7 @@
|
||||
* - \ref f0r_update2
|
||||
*
|
||||
* If a thread is in one of these methods its allowed for another thread to
|
||||
* enter one of theses methods for a different effect instance. But for one
|
||||
* enter one of these methods for a different effect instance. But for one
|
||||
* effect instance only one thread is allowed to execute any of these methods.
|
||||
*/
|
||||
|
||||
@@ -260,7 +260,7 @@ void f0r_deinit(void);
|
||||
* List of supported color models.
|
||||
*
|
||||
* Note: the color models are endian independent, because the
|
||||
* color components are defined by their positon in memory, not
|
||||
* color components are defined by their position in memory, not
|
||||
* by their significance in an uint32_t value.
|
||||
*
|
||||
* For effects that work on the color components,
|
||||
@@ -309,7 +309,7 @@ void f0r_deinit(void);
|
||||
|
||||
/**
|
||||
* In PACKED32, each pixel is represented by 4 consecutive
|
||||
* bytes, but it is not defined how the color componets are
|
||||
* bytes, but it is not defined how the color components are
|
||||
* stored. The true color format could be RGBA8888,
|
||||
* BGRA8888, a packed 32 bit YUV format, or any other
|
||||
* color format that stores pixels in 32 bit.
|
||||
|
||||
@@ -341,7 +341,7 @@ void f0r_update2(f0r_instance_t instance, double time,
|
||||
inframe3);
|
||||
}
|
||||
|
||||
// compability for frei0r 1.0
|
||||
// compatibility for frei0r 1.0
|
||||
void f0r_update(f0r_instance_t instance,
|
||||
double time, const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
|
||||
@@ -62,6 +62,14 @@
|
||||
*/
|
||||
void frei0r_cairo_set_operator(cairo_t *cr, char *op)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!cr || !op) {
|
||||
if (cr) {
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(strcmp(op, NORMAL) == 0)
|
||||
{
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
@@ -196,7 +204,7 @@ void freior_cairo_set_color_stop_rgba_LITTLE_ENDIAN(cairo_pattern_t *pat, double
|
||||
/**
|
||||
* frei0r_cairo_get_pixel_position
|
||||
* @norm_pos: position in range 0 - 1, either x or y
|
||||
* @dim: dimension, either witdh or height
|
||||
* @dim: dimension, either width or height
|
||||
*
|
||||
* Converts double range [0 -> 1] to pixel range [-2*dim -> 3*dim]. Input 0.4 gives position 0.
|
||||
*
|
||||
@@ -231,6 +239,11 @@ double frei0r_cairo_get_scale (double norm_scale)
|
||||
*/
|
||||
void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!rgba || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = rgba[3];
|
||||
@@ -255,6 +268,11 @@ void frei0r_cairo_premultiply_rgba (unsigned char *rgba, int pixels, int alpha)
|
||||
*/
|
||||
void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!rgba || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = rgba[3];
|
||||
@@ -281,6 +299,11 @@ void frei0r_cairo_unpremultiply_rgba (unsigned char *rgba, int pixels)
|
||||
void frei0r_cairo_premultiply_rgba2 (unsigned char *in, unsigned char *out,
|
||||
int pixels, int alpha)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!in || !out || pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = pixels + 1;
|
||||
while ( --i ) {
|
||||
register unsigned char a = in[3];
|
||||
|
||||
@@ -207,7 +207,7 @@ for (i=0;i<=255;i++)
|
||||
//convert from paked uchar RGBA to packed float RGBA
|
||||
//w,h are width and height of the image
|
||||
//tab = table used for RGB conversion
|
||||
//atab = table used for alpha converion (usually linear)
|
||||
//atab = table used for alpha conversion (usually linear)
|
||||
static inline void RGBA8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab, float *atab)
|
||||
{
|
||||
int i;
|
||||
@@ -224,7 +224,7 @@ for (i=0;i<w*h;i++)
|
||||
|
||||
//--------------------------------------------------------
|
||||
//convert from paked uchar RGBA to packed float RGBA,
|
||||
//covert RGB only, SKIP ALPHA
|
||||
//convert RGB only, SKIP ALPHA
|
||||
//w,h are width and height of the image
|
||||
//tab = table used for RGB conversion
|
||||
static inline void RGB8_2_float(const uint32_t *in, float_rgba *out, int w, int h, float *tab)
|
||||
@@ -259,7 +259,7 @@ for (i=0;i<w*h;i++)
|
||||
//----------------------------------------------------------
|
||||
//convert from packed float RGBA to packed uchar RGBA
|
||||
//tab = table used for RGB conversion
|
||||
//atab = table used for alpha converion (usually linear)
|
||||
//atab = table used for alpha conversion (usually linear)
|
||||
static inline void float_2_RGBA8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab, uint8_t *atab)
|
||||
{
|
||||
int i;
|
||||
@@ -276,7 +276,7 @@ for (i=0;i<w*h;i++)
|
||||
|
||||
//----------------------------------------------------------
|
||||
//convert from packed float RGBA to packed uchar RGBA
|
||||
//covert RGB only, SKIP ALPHA
|
||||
//convert RGB only, SKIP ALPHA
|
||||
//tab = table used for RGB conversion
|
||||
static inline void float_2_RGB8(const float_rgba *in, uint32_t *out, int w, int h, uint8_t *tab)
|
||||
{
|
||||
|
||||
@@ -13,11 +13,13 @@ if (${Cairo_FOUND})
|
||||
add_subdirectory (cairoimagegrid)
|
||||
add_subdirectory (cairogradient)
|
||||
add_subdirectory (mirr0r)
|
||||
add_subdirectory (shakeoscillate)
|
||||
endif (${Cairo_FOUND})
|
||||
|
||||
add_subdirectory (3dflippo)
|
||||
add_subdirectory (aech0r)
|
||||
add_subdirectory (alpha0ps)
|
||||
add_subdirectory (autothresh0ld)
|
||||
add_subdirectory (balanc0r)
|
||||
add_subdirectory (baltan)
|
||||
add_subdirectory (bluescreen0r)
|
||||
@@ -54,6 +56,7 @@ add_subdirectory (gateweave)
|
||||
add_subdirectory (glow)
|
||||
add_subdirectory (glitch0r)
|
||||
#add_subdirectory (host_param_test)
|
||||
add_subdirectory (heatmap0r)
|
||||
add_subdirectory (hueshift0r)
|
||||
add_subdirectory (invert0r)
|
||||
add_subdirectory (kaleid0sc0pe)
|
||||
|
||||
@@ -32,19 +32,19 @@
|
||||
|
||||
////// TODO / IDEAS / ... //////
|
||||
// IDEA - directionnal echo ? (X/Y like parameter )
|
||||
// TODO RGB gradiant by fading influence need more love (See '//Fade by color layers')!
|
||||
// FIXME SSE2 version doesnt support RGB fading influence !
|
||||
// TODO RGB gradient by fading influence need more love (See '//Fade by color layers')!
|
||||
// FIXME SSE2 version doesn't support RGB fading influence !
|
||||
|
||||
// FIXME (Veejay specifics?) on activate/desactivate/activate/..., some buffers must be cleared!
|
||||
// FIXME (Veejay specifics?) on activate/deactivate/activate/..., some buffers must be cleared!
|
||||
|
||||
// EXPORE ME -
|
||||
// EXPLORE ME -
|
||||
//~ if((skip_count++)>m_skip) {
|
||||
//~ - skip_count = 0;
|
||||
//~ - m_factor += (factor * 64);
|
||||
//~ [...]
|
||||
//~ }
|
||||
|
||||
// EXPLORE ME a very high m_factor value give some interresting color result ( m_factor += (factor * 64) * m_skip;)
|
||||
// EXPLORE ME a very high m_factor value give some interesting color result ( m_factor += (factor * 64) * m_skip;)
|
||||
|
||||
|
||||
/* Intrinsic declarations */
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
m_skip_count = 0;
|
||||
|
||||
register_param(factor, "Fade Factor", "Disappearance rate of the echo"); // 0 No fade, 1 No Trace
|
||||
register_param(bright, "Direction", "Darker or Brighter echo"); // Add or Substract data
|
||||
register_param(bright, "Direction", "Darker or Brighter echo"); // Add or Subtract data
|
||||
register_param(flag_r, "Keep RED", "Influence on Red channel"); // 0 Fade canal, 1 Keep canal data
|
||||
register_param(flag_g, "Keep GREEN", "Influence on Green channel"); // 0 Fade canal, 1 Keep canal data
|
||||
register_param(flag_b, "Keep BLUE", "Influence on Blue channel"); // 0 Fade canal, 1 Keep canal data
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
//~ register_param(factor_r, "Fade R", "influence"); // 0 No fade, 1 No Trace
|
||||
//~ register_param(factor_g, "Fade G", "influence"); // 0 No fade, 1 No Trace
|
||||
//~ register_param(factor_b, "Fade B", "influence"); // 0 No fade, 1 No Trace
|
||||
//~ register_param(flag_rgb, "Plans comparaison", "RGB");
|
||||
//~ register_param(flag_rgb, "Plans comparison", "RGB");
|
||||
|
||||
}
|
||||
~aech0r() {
|
||||
|
||||
@@ -58,7 +58,7 @@ typedef struct
|
||||
float sga;
|
||||
int inv;
|
||||
|
||||
//auxilliary variables for fibe2o
|
||||
//auxiliary variables for fibe2o
|
||||
float f,q,a0,a1,a2,b0,b1,b2,rd1,rd2,rs1,rs2,rc1,rc2;
|
||||
|
||||
} inst;
|
||||
|
||||
11
src/filter/autothresh0ld/CMakeLists.txt
Normal file
11
src/filter/autothresh0ld/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
set (SOURCES autothresh0ld.c)
|
||||
set (TARGET autothresh0ld)
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
|
||||
# No «lib» prefix (name.so instead of libname.so)
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
192
src/filter/autothresh0ld/autothresh0ld.c
Normal file
192
src/filter/autothresh0ld/autothresh0ld.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* (c) Copyright 2025 Cynthia <cynthia2048@proton.me>
|
||||
*
|
||||
* This is based on Otsu's algorithm to segment an image into foreground
|
||||
* or background based on the shape of the histogram. Instead of doing a
|
||||
* hard threshold, we use the threshold obtained from Otsu's algorithm
|
||||
* as the base for a sigmoidal transfer with a high slope; this produces
|
||||
* a more eye-soothing threshold effect as seen in ImageMagick.
|
||||
*
|
||||
* This has the added benefit that, whereas the sigmoidal filter's base
|
||||
* requires manual tuning, here it is determined algorithmically and thus
|
||||
* can adapt on a frame-to-frame basis.
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
#include "variance.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int width, height;
|
||||
float slope;
|
||||
|
||||
uint8_t lut[256][256];
|
||||
uint8_t *lumaframe;
|
||||
} s0ft0tsu_t;
|
||||
|
||||
static void gen_sigmoid_lut (uint8_t lut[256][256], float slope)
|
||||
{
|
||||
float k = expf(slope) / 255.0;
|
||||
|
||||
for (int j = 0; j < 256; ++j)
|
||||
for (int i = 0; i < 256; ++i)
|
||||
lut[j][i] = CLAMP (255.0 / (1.0 + expf(-k * (i - j))), 0, 255);
|
||||
}
|
||||
|
||||
int f0r_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f0r_deinit() {}
|
||||
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
s0ft0tsu_t* s = calloc(1, sizeof(s0ft0tsu_t));
|
||||
|
||||
s->width = width;
|
||||
s->height = height;
|
||||
s->slope = 4.0;
|
||||
s->lumaframe = malloc(s->width * s->height);
|
||||
|
||||
gen_sigmoid_lut(s->lut, s->slope);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* info)
|
||||
{
|
||||
info->name = "autothreshold";
|
||||
info->author = "Cynthia";
|
||||
info->explanation = "Automatically threshold moving pictures";
|
||||
info->major_version = 0;
|
||||
info->minor_version = 1;
|
||||
info->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
info->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
info->num_params = 1;
|
||||
}
|
||||
|
||||
void f0r_get_param_info(f0r_param_info_t *info, int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
info->name = "Slope";
|
||||
info->explanation = "Slope of sigmoidal transfer";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_get_param_value(f0r_instance_t inst, f0r_param_t param, int index)
|
||||
{
|
||||
s0ft0tsu_t* s = inst;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
*(double*)param = s->slope / 7.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t inst, f0r_param_t param, int index)
|
||||
{
|
||||
s0ft0tsu_t* s = inst;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
s->slope = *(double*)param * 7.0;
|
||||
|
||||
gen_sigmoid_lut(s->lut, s->slope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t inst, double time,
|
||||
const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
s0ft0tsu_t *s = inst;
|
||||
|
||||
uint8_t *src = (uint8_t*)inframe;
|
||||
uint8_t *dst = s->lumaframe;
|
||||
uint8_t r, g, b, luma;
|
||||
size_t len = s->width * s->height;
|
||||
|
||||
// Normalised histogram (L = 256)
|
||||
float hist[256] = {0};
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
r = *src++;
|
||||
g = *src++;
|
||||
b = *src++;
|
||||
src++; // Ignore alpha
|
||||
|
||||
luma = CLAMP(0.299 * r + 0.587 * g + 0.114 * b, 0, 255);
|
||||
*dst++ = luma;
|
||||
|
||||
++hist[luma]; // Add to histogram
|
||||
}
|
||||
|
||||
// Normalise histogram; becomes a probability distribution
|
||||
for (int i = 0; i < 256; ++i)
|
||||
hist[i] /= len;
|
||||
|
||||
uint8_t thresh = 0.0;
|
||||
float max_var = 0.0; // Maximum inter-class variance.
|
||||
|
||||
for (int i = 1; i < 256; ++i)
|
||||
{
|
||||
float var = find_variance(hist, i);
|
||||
if (var > max_var)
|
||||
{
|
||||
thresh = i;
|
||||
max_var = var;
|
||||
}
|
||||
}
|
||||
|
||||
src = (uint8_t*)s->lumaframe; // Replenish
|
||||
dst = (uint8_t*)outframe;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
// Select the appropriate transfer
|
||||
uint8_t* lut = s->lut[thresh];
|
||||
|
||||
luma = lut[*src++];
|
||||
|
||||
*dst++ = luma;
|
||||
*dst++ = luma;
|
||||
*dst++ = luma;
|
||||
*dst++ = 0xFF; // TODO Copy alpha
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_destruct(f0r_instance_t s)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
84
src/filter/autothresh0ld/variance.h
Normal file
84
src/filter/autothresh0ld/variance.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
static float find_variance(float *hist, int thresh)
|
||||
{
|
||||
float w_0 = 0.0, mu_0 = 0.0, w_1 = 0.0, mu_1 = 0.0;
|
||||
|
||||
for (int i = 0; i < thresh; ++i)
|
||||
{
|
||||
w_0 += hist[i];
|
||||
mu_0 += i * hist[i];
|
||||
}
|
||||
for (int i = thresh; i < 256; ++i)
|
||||
{
|
||||
w_1 += hist[i];
|
||||
mu_1 += i * hist[i];
|
||||
}
|
||||
|
||||
float mu_diff = (mu_0/w_0 - mu_1/w_1);
|
||||
return w_0*w_1*mu_diff*mu_diff;
|
||||
}
|
||||
|
||||
#ifdef __SSE2__
|
||||
static float _sse1_hadd_ps(__m128 v)
|
||||
{
|
||||
// Based on a StackOverflow answer.
|
||||
__m128 shuf = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
__m128 sums = _mm_add_ps(v, shuf);
|
||||
shuf = _mm_movehl_ps(shuf, sums);
|
||||
sums = _mm_add_ss(sums, shuf);
|
||||
return _mm_cvtss_f32(sums);
|
||||
}
|
||||
|
||||
static float find_variance_sse2(float *hist, int thresh)
|
||||
{
|
||||
__m128 vw_0 = _mm_setzero_ps(), vmu_0 = _mm_setzero_ps(),
|
||||
vw_1 = _mm_setzero_ps(), vmu_1 = _mm_setzero_ps();
|
||||
__m128 vcnt = _mm_set_ps(0, 1, 2, 3);
|
||||
|
||||
int thresh_low = (thresh / 4 + 0) * 4,
|
||||
thresh_up = (thresh / 4 + 1) * 4;
|
||||
|
||||
for (int i = 0; i < thresh_low; i+=4)
|
||||
{
|
||||
__m128 vhist = _mm_castsi128_ps(_mm_loadu_si128((void*)&hist[i]));
|
||||
|
||||
vw_0 = _mm_add_ps(vhist, vw_0);
|
||||
vmu_0 = _mm_add_ps(_mm_mul_ps(vcnt, vhist), vw_0);
|
||||
vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
|
||||
}
|
||||
|
||||
// This is skipped, and handled as an edge case by non-SSE code.
|
||||
vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
|
||||
|
||||
for (int i = thresh_up; i < 256; i+=4)
|
||||
{
|
||||
__m128 vhist = _mm_castsi128_ps(_mm_loadu_si128((void*)&hist[i]));
|
||||
|
||||
vw_1 = _mm_add_ps(vhist, vw_1);
|
||||
vmu_1 = _mm_add_ps(_mm_mul_ps(vcnt, vhist), vw_1);
|
||||
vcnt = _mm_add_ps(vcnt, _mm_set1_ps(4));
|
||||
}
|
||||
|
||||
float w_0 = _sse1_hadd_ps(vw_0), mu_0 = _sse1_hadd_ps(vmu_0),
|
||||
w_1 = _sse1_hadd_ps(vw_1), mu_1 = _sse1_hadd_ps(vmu_1);
|
||||
|
||||
// This edge case is here, because thresh may not be a multiple of 4.
|
||||
for (int i = thresh_low; i < thresh; ++i)
|
||||
{
|
||||
w_0 += hist[i];
|
||||
mu_0 += i * hist[i];
|
||||
}
|
||||
|
||||
for (int i = thresh; i < thresh_up; ++i)
|
||||
{
|
||||
w_1 += hist[i];
|
||||
mu_1 += i * hist[i];
|
||||
}
|
||||
|
||||
float mu_diff = (mu_0/w_0 - mu_1/w_1);
|
||||
return w_0*w_1*mu_diff*mu_diff;
|
||||
}
|
||||
#endif
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
*outpixel= (*pixel & 0x00FFFFFF); // copy all except alpha
|
||||
|
||||
uint32_t d = distance(*pixel); // get distance
|
||||
unsigned char a = 255; // default alpha
|
||||
unsigned char a = (*pixel >> 24); // default alpha
|
||||
if (d < distInt) {
|
||||
a = 0;
|
||||
if (d > distInt2) {
|
||||
@@ -100,5 +100,8 @@ public:
|
||||
};
|
||||
|
||||
|
||||
frei0r::construct<bluescreen0r> plugin("bluescreen0r", "Color to alpha (blit SRCALPHA)", "Hedde Bosman",0,4,F0R_COLOR_MODEL_RGBA8888);
|
||||
|
||||
frei0r::construct<bluescreen0r> plugin("bluescreen0r",
|
||||
"Color to alpha (blit SRCALPHA)",
|
||||
"Hedde Bosman",
|
||||
0, 5,
|
||||
F0R_COLOR_MODEL_RGBA8888);
|
||||
|
||||
@@ -80,12 +80,13 @@ float AitNev3(int t, float xt[], float yt[], float x)
|
||||
{
|
||||
float p[10];
|
||||
int i,j,m;
|
||||
float zero = 0.0f; // MSVC doesn't allow division through a zero literal, but allows it through non-const variable set to zero
|
||||
|
||||
if ((x<xt[0])||(x>xt[t-1]))
|
||||
{
|
||||
// printf("\n\n x=%f je izven mej tabele!",x);
|
||||
return 1.0/zero;
|
||||
// Return a reasonable value instead of dividing by zero
|
||||
if (x<xt[0]) return yt[0];
|
||||
else return yt[t-1];
|
||||
}
|
||||
|
||||
//poisce, katere tocke bo uporabil
|
||||
@@ -98,7 +99,13 @@ float AitNev3(int t, float xt[], float yt[], float x)
|
||||
for (j=1;j<4;j++)
|
||||
for (i=(4-1);i>=j;i--)
|
||||
{
|
||||
p[i]=p[i]+(x-xt[i+m])/(xt[i+m]-xt[i-j+m])*(p[i]-p[i-1]);
|
||||
// Check for division by zero
|
||||
float denominator = xt[i+m]-xt[i-j+m];
|
||||
if (denominator == 0.0f) {
|
||||
// If denominator is zero, skip this iteration to avoid undefined behavior
|
||||
continue;
|
||||
}
|
||||
p[i]=p[i]+(x-xt[i+m])/denominator*(p[i]-p[i-1]);
|
||||
}
|
||||
return p[4-1];
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ The algorithms are very simple, but the code is a bit bloated,
|
||||
because I did some optimizations for speed.
|
||||
The algorithms are so simple, that using SSE didn't bring
|
||||
much speedup - the limiting factor is memory bandwidth, not
|
||||
arithmetics. Therefore I decided not to include the SSE versions.
|
||||
arithmetic. Therefore I decided not to include the SSE versions.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,13 +35,13 @@ Copyright (C) 2011 Marko Cebokli http://lea.hamradio.si/~s57uuu
|
||||
CONTENTS OF FIBE.H FILE:
|
||||
--------------------------------
|
||||
|
||||
calcab_lp1() auxilliary function to calculate lowpass
|
||||
calcab_lp1() auxiliary function to calculate lowpass
|
||||
tap coefficients for FIBE-2
|
||||
|
||||
young_vliet() auxilliary function to calculate tap coefs
|
||||
young_vliet() auxiliary function to calculate tap coefs
|
||||
for Gauss approximation with FIBE-3
|
||||
|
||||
rep() auxilliary function to calculate wraparound
|
||||
rep() auxiliary function to calculate wraparound
|
||||
values for FIBE-2
|
||||
|
||||
fibe1o_8() one tap quadrilateral IIR filter
|
||||
|
||||
@@ -107,7 +107,7 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
{
|
||||
int val;
|
||||
case 0:
|
||||
/* constrast */
|
||||
/* contrast */
|
||||
val = (int) ((*((double*)param) - 0.5) * 512.0); /* remap to [-256, 256] */
|
||||
if (val != inst->brightness)
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@ The supplied Kdenlive effect description XML file should change this range to
|
||||
left corner x=1000, y=1000, the upper right corner x=2000, y=1000 and so on. It
|
||||
should also set the defaults so that the undistorted input picture is displayed.
|
||||
If you have no image, check that the corners specify a nonzero area at least
|
||||
partly overlaping the output window.
|
||||
partly overlapping the output window.
|
||||
|
||||
2. Stretch, x and y
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************
|
||||
* The remapping functions use a map aray, which contains a pair
|
||||
* The remapping functions use a map array, which contains a pair
|
||||
* of floating values fo each pixel of the output image. These
|
||||
* represent the location in the input image, from where the value
|
||||
* of the given output pixel should be interpolated.
|
||||
|
||||
@@ -46,7 +46,7 @@ typedef struct {
|
||||
uint32_t size;
|
||||
} ScreenGeometry;
|
||||
|
||||
#define PIXELAT(x1,y1,s) ((s)+(x1)+ yprecal[y1])// (y1)*(geo->w)))
|
||||
#define PIXELAT(x1,y1,s,inst) ((s)+(x1)+ inst->yprecal[y1])// (y1)*(geo->w)))
|
||||
#define GMERROR(cc1,cc2) ((((RED(cc1)-RED(cc2))*(RED(cc1)-RED(cc2))) + \
|
||||
((GREEN(cc1)-GREEN(cc2)) *(GREEN(cc1)-GREEN(cc2))) + \
|
||||
((BLUE(cc1)-BLUE(cc2))*(BLUE(cc1)-BLUE(cc2)))))
|
||||
@@ -155,26 +155,26 @@ long Cartoon::GetMaxContrast(int32_t *src,int x,int y) {
|
||||
long error,max=0;
|
||||
|
||||
/* Assumes PrePixelModify has been run */
|
||||
c1 = *PIXELAT(x-m_diffspace,y,src);
|
||||
c2 = *PIXELAT(x+m_diffspace,y,src);
|
||||
c1 = *PIXELAT(x-m_diffspace,y,src,this);
|
||||
c2 = *PIXELAT(x+m_diffspace,y,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x-m_diffspace,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x+m_diffspace,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src);
|
||||
c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src);
|
||||
|
||||
c1 = *PIXELAT(x+m_diffspace,y-m_diffspace,src,this);
|
||||
c2 = *PIXELAT(x-m_diffspace,y+m_diffspace,src,this);
|
||||
error = GMERROR(c1,c2);
|
||||
if (error>max) max = error;
|
||||
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,16 +125,17 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
float b1 = inst->color.b * 255.0;
|
||||
float r2, g2, b2;
|
||||
int l;
|
||||
/* Scale factor to normalize distance to 0-255 range:
|
||||
0.705724361914764 ≈ 255.0 / sqrt(3 * 255^2) = 255.0 / (255.0 * sqrt(3)) */
|
||||
const float SCALE_FACTOR = 0.705724361914764;
|
||||
while (len--) {
|
||||
r2 = *src++;
|
||||
g2 = *src++;
|
||||
b2 = *src++;
|
||||
l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * 0.705724361914764 );
|
||||
/* Hint 0.35320727852735 == 255.0 / sqrt( (255)**2 + (255)**2 + (255)*2 )*/
|
||||
if ( r1 < 0 || r1 > 255 || g1 < 0 || g1 > 255 || b1 < 0 || b1 > 255 || r2 < 0 || r2 > 255 || g2 < 0 || g2 > 255 || b2 < 0 || b2 > 255 ) {
|
||||
printf ("%f %f %f\n", r2, g2, b2 );
|
||||
}
|
||||
l = (int)rint( sqrtf( powf( r1 - r2, 2 ) + powf( g1 - g2, 2 ) + powf( b1 - b2, 2 ) ) * SCALE_FACTOR );
|
||||
|
||||
// Clamp result to valid range
|
||||
l = CLAMP(l, 0, 255);
|
||||
|
||||
*dst++ = (unsigned char) (l);
|
||||
*dst++ = (unsigned char) (l);
|
||||
|
||||
@@ -119,7 +119,7 @@ void color_halftone(f0r_instance_t instance, double time,
|
||||
// We check all four neighbours, but in practice only one can ever overlap any given point.
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
// Find neigbouring grid point
|
||||
// Find neighbouring grid point
|
||||
ttx = tx + mx[i]*gridSize;
|
||||
tty = ty + my[i]*gridSize;
|
||||
// Transform back into image space
|
||||
|
||||
@@ -100,7 +100,7 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
{
|
||||
int val;
|
||||
case 0:
|
||||
/* constrast */
|
||||
/* contrast */
|
||||
val = (int) ((*((double*)param) - 0.5) * 512.0); /* remap to [-256, 256] */
|
||||
if (val != inst->contrast)
|
||||
{
|
||||
|
||||
@@ -388,7 +388,7 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
|
||||
double* gaussSLESolve(size_t size, double* A) {
|
||||
int extSize = size + 1;
|
||||
//direct way: tranform matrix A to triangular form
|
||||
//direct way: transform matrix A to triangular form
|
||||
for(int row = 0; row < size; row++) {
|
||||
int col = row;
|
||||
int lastRowToSwap = size - 1;
|
||||
@@ -546,7 +546,7 @@ position pointOnBezier(double t, position points[4])
|
||||
/*
|
||||
* Calculating a point on the bezier curve using the coefficients from Bernstein basis polynomial of degree 3.
|
||||
* Using the De Casteljau algorithm would be slightly faster when calculating a lot of values
|
||||
* but the difference is far from noticable here since we update the spline only when the parameter changes
|
||||
* but the difference is far from noticeable here since we update the spline only when the parameter changes
|
||||
*/
|
||||
double c1 = (1-t) * (1-t) * (1-t);
|
||||
double c2 = 3 * t * (1-t) * (1-t);
|
||||
@@ -557,6 +557,10 @@ position pointOnBezier(double t, position points[4])
|
||||
return pos;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# define strtok_r strtok_s
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Splits given string into sub-strings at given delimiter.
|
||||
* \param string input string
|
||||
@@ -569,11 +573,11 @@ int tokenise(char *string, const char *delimiter, char ***tokens)
|
||||
int count = 0;
|
||||
char *input = strdup(string);
|
||||
char *result = NULL;
|
||||
result = strtok(input, delimiter);
|
||||
result = strtok_r(string, delimiter, &input);
|
||||
while (result != NULL) {
|
||||
*tokens = realloc(*tokens, (count + 1) * sizeof(char *));
|
||||
(*tokens)[count++] = strdup(result);
|
||||
result = strtok(NULL, delimiter);
|
||||
result = strtok_r(NULL, delimiter, &input);
|
||||
}
|
||||
free(input);
|
||||
return count;
|
||||
@@ -776,7 +780,7 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
curves_instance_t* inst = (curves_instance_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
|
||||
// test initalization c/b spline
|
||||
// test initialization c/b spline
|
||||
double *splinemap = strlen(inst->bspline)>0 ? inst->bsplineMap : inst->csplineMap;
|
||||
if(!splinemap) {
|
||||
memcpy(outframe,inframe,inst->width * inst->height * 4);
|
||||
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
for (unsigned int pixel = 0; pixel < width*4; pixel++) {
|
||||
// Use linear interpolation on the colours
|
||||
|
||||
// Use pointer arithmetics. Colour values are stored
|
||||
// Use pointer arithmetic. Colour values are stored
|
||||
// as AABBGGRR in the uint32_t values.
|
||||
// Convert each colour separately.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Defish0r is a Frei0r plugin that can convert fisheye video to
|
||||
rectilinear, and vice versa. It is based on the angular mapping
|
||||
functions actually used in fisheye lens design, to get the best
|
||||
possible results. It can also be used to correct the slight distortion
|
||||
of some wideangle convertors, or to bend the image beyond recognition
|
||||
of some wideangle converters, or to bend the image beyond recognition
|
||||
for special effects and light shows.
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ Description of the available parameters:
|
||||
unreasonable values the image might indeed disappear, when there are
|
||||
math overflows or imaginary results... (types 1 and 2 are more prone
|
||||
to image vanishing). Anyway, when working in the "special effect"
|
||||
range, it is alway worth to try manual scaling.
|
||||
range, it is always worth to try manual scaling.
|
||||
|
||||
"DeFish"
|
||||
If checked, the transform direction is from fisheye to rectiliear,
|
||||
@@ -163,7 +163,7 @@ Type = 1000
|
||||
Scaling = 1000 (manual)
|
||||
Manual Scale = 191
|
||||
|
||||
For an effect, reminiscent of some scenes from the "2001 Spcae Odyssey" try
|
||||
For an effect, reminiscent of some scenes from the "2001 Space Odyssey" try
|
||||
this:
|
||||
Amount = 876
|
||||
Defish = ON
|
||||
|
||||
@@ -213,8 +213,8 @@ void fishmap(int wi, int hi, int wo, int ho, int n, float f, float scal, float p
|
||||
//pari,paro = pixel aspect ratio (input / output)
|
||||
//dx, dy offset on input (for non-cosited chroma subsampling)
|
||||
//lbox = letterbox
|
||||
//stretch = dymanic stretch, convert between 4:3 and 16:9
|
||||
//yScale = -0.5.. 0.5 change aspect ratio on y acess only
|
||||
//stretch = dynamic stretch, convert between 4:3 and 16:9
|
||||
//yScale = -0.5.. 0.5 change aspect ratio on y access only
|
||||
void defishmap(int wi, int hi, int wo, int ho, int n, float f, float scal, float pari, float paro, float dx, float dy, float *map
|
||||
, int lbox, float stretchFactor, float yScale)
|
||||
{
|
||||
@@ -312,7 +312,7 @@ void defishmap(int wi, int hi, int wo, int ho, int n, float f, float scal, float
|
||||
//aspt: 0..4 aspect type square, PAL, NTSC, HDV, manual
|
||||
//par: pixel aspect ratio
|
||||
//lbox: 1=letterbox
|
||||
//stretch 0..1 stretch video to fix superview distorsion
|
||||
//stretch 0..1 stretch video to fix superview distortion
|
||||
typedef struct
|
||||
{
|
||||
int w;
|
||||
@@ -513,7 +513,7 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
p->mpar=1.0;
|
||||
p->lbox=0; //letterbox
|
||||
p->stretch = 0.0f; //dynamic stretch
|
||||
p->yScale = 1.0f; //seperate Y stretch
|
||||
p->yScale = 1.0f; //separate Y stretch
|
||||
|
||||
p->map=(float*)calloc(1, sizeof(float)*(p->w*p->h*2+2));
|
||||
p->interpol=set_intp(*p);
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
*/
|
||||
|
||||
/*******************************************************************
|
||||
* The remapping functions use a map aray, which contains a pair
|
||||
* of floating values fo each pixel of the output image. These
|
||||
* The remapping functions use a map array, which contains a pair
|
||||
* of floating values of each pixel of the output image. These
|
||||
* represent the location in the input image, from where the value
|
||||
* of the given output pixel should be interpolated.
|
||||
* They are given in pixels of the input image.
|
||||
|
||||
@@ -254,16 +254,21 @@ void interpolateGrid(grid_point_t* grid, unsigned int w, unsigned int h,
|
||||
step_line_u = (int32_t) ((u_right-u_left) >> GRID_SIZE_LOG);
|
||||
step_line_v = (int32_t) ((v_right-v_left) >> GRID_SIZE_LOG);
|
||||
|
||||
for(block_x=0; block_x < GRID_SIZE; ++block_x)
|
||||
{
|
||||
for(block_x=0; block_x < GRID_SIZE; ++block_x)
|
||||
{
|
||||
int uu = u_line_index >> 16;
|
||||
int vv = v_line_index >> 16;
|
||||
|
||||
u_line_index += step_line_u;
|
||||
v_line_index += step_line_v;
|
||||
|
||||
*pos++ = src[uu + vv * w];
|
||||
}
|
||||
|
||||
u_line_index += step_line_u;
|
||||
v_line_index += step_line_v;
|
||||
|
||||
// Bounds checking to prevent buffer overrun
|
||||
if (uu >= 0 && uu < (int)w && vv >= 0 && vv < (int)h) {
|
||||
*pos++ = src[uu + vv * w];
|
||||
} else {
|
||||
*pos++ = 0; // Black pixel for out-of-bounds access
|
||||
}
|
||||
}
|
||||
|
||||
start_col_uu += step_start_col_u;
|
||||
end_col_uu += step_end_col_u;
|
||||
|
||||
@@ -15,7 +15,7 @@ initial release of plugin
|
||||
## Description of the parameters:
|
||||
|
||||
"Scale Center":<br/>
|
||||
Sets the horizontal center where the scaling orgins from. range: [0,1]
|
||||
Sets the horizontal center where the scaling origins from. range: [0,1]
|
||||
|
||||
|
||||
"Linear Scale Area":<br/>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
set (SOURCES facebl0r.cpp)
|
||||
set (TARGET facebl0r)
|
||||
# facebl0r filter - requires OpenCV (and protobuf)
|
||||
# This filter can cause conflicts with applications that also use protobuf
|
||||
# such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
|
||||
set (SOURCES facebl0r.cpp)
|
||||
set (TARGET facebl0r)
|
||||
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
endif()
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
set (SOURCES facedetect.cpp)
|
||||
set (TARGET facedetect)
|
||||
# facedetect filter - requires OpenCV (and protobuf)
|
||||
# This filter can cause conflicts with applications that also use protobuf
|
||||
# such as MLT, so it can be disabled with -DWITHOUT_FACERECOGNITION=ON
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
if (OpenCV_FOUND AND NOT WITHOUT_FACERECOGNITION)
|
||||
set (SOURCES facedetect.cpp)
|
||||
set (TARGET facedetect)
|
||||
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
include_directories(${OpenCV_INCLUDE_DIRS})
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${TARGET} ${OpenCV_LIBS})
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
endif()
|
||||
|
||||
@@ -45,7 +45,7 @@ struct glitch0r_state // helps to save time when allocating in a loop
|
||||
short int howToDistort1;
|
||||
short int howToDistort2;
|
||||
short int passThisLine;
|
||||
} g0r_state;
|
||||
};
|
||||
|
||||
typedef struct glitch0r_instance
|
||||
{
|
||||
@@ -58,6 +58,8 @@ typedef struct glitch0r_instance
|
||||
short int colorGlitchIntensity;
|
||||
short int doColorDistortion;
|
||||
short int glitchChance;
|
||||
|
||||
struct glitch0r_state state; // Instance-specific state
|
||||
} glitch0r_instance_t;
|
||||
|
||||
|
||||
@@ -68,17 +70,17 @@ inline static unsigned int rnd (unsigned int min, unsigned int max)
|
||||
|
||||
inline static void glitch0r_state_reset(glitch0r_instance_t *inst)
|
||||
{
|
||||
g0r_state.currentPos = 0;
|
||||
g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
g0r_state.blkShift = rnd(1, inst->maxBlockShift);
|
||||
g0r_state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
|
||||
inst->state.currentPos = 0;
|
||||
inst->state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
inst->state.blkShift = rnd(1, inst->maxBlockShift);
|
||||
inst->state.passThisLine = (inst->glitchChance < rnd(1, 101)) ? 1 : 0;
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
{
|
||||
g0r_state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
|
||||
g0r_state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
|
||||
g0r_state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
|
||||
g0r_state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
|
||||
inst->state.distortionSeed1 = rnd(0x00000000, 0xfffffffe);
|
||||
inst->state.distortionSeed2 = rnd(0x00000000, 0xfffffffe);
|
||||
inst->state.howToDistort1 = rnd (0, inst->colorGlitchIntensity);
|
||||
inst->state.howToDistort2 = rnd (0, inst->colorGlitchIntensity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,49 +306,49 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
|
||||
uint32_t* dst = outframe;
|
||||
const uint32_t* src = inframe;
|
||||
uint32_t *pixel;
|
||||
uint32_t *pixel;
|
||||
|
||||
g0r_state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
inst->state.currentBlock = rnd(1, inst->maxBlockSize);
|
||||
|
||||
for (y = 0; y < inst->height; y++)
|
||||
{
|
||||
|
||||
if (g0r_state.currentPos > g0r_state.currentBlock)
|
||||
if (inst->state.currentPos > inst->state.currentBlock)
|
||||
{
|
||||
glitch0r_state_reset(inst);
|
||||
}
|
||||
else
|
||||
g0r_state.currentPos++;
|
||||
inst->state.currentPos++;
|
||||
|
||||
g0r_state.currentY = y*inst->width;
|
||||
pixel = dst + g0r_state.currentY;
|
||||
inst->state.currentY = y*inst->width;
|
||||
pixel = dst + inst->state.currentY;
|
||||
|
||||
if (g0r_state.passThisLine)
|
||||
if (inst->state.passThisLine)
|
||||
{
|
||||
memcpy((uint32_t *)(dst + g0r_state.currentY),
|
||||
(uint32_t *)(src + g0r_state.currentY),
|
||||
memcpy((uint32_t *)(dst + inst->state.currentY),
|
||||
(uint32_t *)(src + inst->state.currentY),
|
||||
(inst->width) * sizeof(uint32_t));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = g0r_state.blkShift; x < (inst->width); x++)
|
||||
for (x = inst->state.blkShift; x < (inst->width); x++)
|
||||
{
|
||||
*(pixel) = *(src + g0r_state.currentY + x);
|
||||
*(pixel) = *(src + inst->state.currentY + x);
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
glitch0r_pixel_dist0rt(pixel,
|
||||
g0r_state.distortionSeed1, g0r_state.howToDistort1);
|
||||
inst->state.distortionSeed1, inst->state.howToDistort1);
|
||||
|
||||
pixel++;
|
||||
}
|
||||
|
||||
for (x = 0; x < g0r_state.blkShift; x++)
|
||||
for (x = 0; x < inst->state.blkShift; x++)
|
||||
{
|
||||
*(pixel) = *(src + g0r_state.currentY + x);
|
||||
*(pixel) = *(src + inst->state.currentY + x);
|
||||
|
||||
if (inst->doColorDistortion)
|
||||
glitch0r_pixel_dist0rt(pixel,
|
||||
g0r_state.distortionSeed2, g0r_state.howToDistort2);
|
||||
inst->state.distortionSeed2, inst->state.howToDistort2);
|
||||
|
||||
pixel++;
|
||||
}
|
||||
|
||||
11
src/filter/heatmap0r/CMakeLists.txt
Normal file
11
src/filter/heatmap0r/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
set (SOURCES heatmap0r.c)
|
||||
set (TARGET heatmap0r)
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
201
src/filter/heatmap0r/heatmap0r.c
Normal file
201
src/filter/heatmap0r/heatmap0r.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* heatmap0r.c -- feel the heat, frei0r style.
|
||||
*
|
||||
* Copyright (C) 2025 Cynthia (cynthia2048@proton.me)
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int width, height;
|
||||
uint8_t rlut[256], glut[256], blut[256];
|
||||
|
||||
f0r_param_color_t black, grey, white;
|
||||
double gp; //< Grey point
|
||||
} heatmap0r_t;
|
||||
|
||||
static void gen_heatmap0r_luts(heatmap0r_t *inst)
|
||||
{
|
||||
double luma;
|
||||
double L0, L1, L2;
|
||||
double gp = inst->gp;
|
||||
double l0 = 1.0 / gp,
|
||||
l1 = 1.0 / (gp * (gp - 1.0)),
|
||||
l2 = 1.0 / (1.0 - gp);
|
||||
|
||||
f0r_param_color_t black = inst->black,
|
||||
grey = inst->grey,
|
||||
white = inst->white;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
luma = 1.0 / 255.0 * (double)i;
|
||||
|
||||
L0 = (luma - gp) * (luma - 1.0) * l0;
|
||||
L1 = luma * (luma - 1.0) * l1;
|
||||
L2 = luma * (luma - gp) * l2;
|
||||
|
||||
inst->rlut[i] = CLAMP(255.0 * (L0 * black.r + L1 * grey.r + L2 * white.r), 0, 255);
|
||||
inst->glut[i] = CLAMP(255.0 * (L0 * black.g + L1 * grey.g + L2 * white.g), 0, 255);
|
||||
inst->blut[i] = CLAMP(255.0 * (L0 * black.b + L1 * grey.b + L2 * white.b), 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
int f0r_init()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void f0r_deinit() {}
|
||||
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
heatmap0r_t* inst = calloc(1, sizeof(*inst));
|
||||
|
||||
inst->width = width; inst->height = height;
|
||||
inst->gp = 0.5;
|
||||
inst->white = (f0r_param_color_t) {/* Yellow */ 1.0, 1.0, 0.0};
|
||||
inst->grey = (f0r_param_color_t) {/* Deeppink */ 1.0, 0.0, 0.5};
|
||||
inst->black = (f0r_param_color_t) {/* Darkviolet */ 0.27, 0.0, 0.5};
|
||||
|
||||
gen_heatmap0r_luts (inst);
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
void f0r_destruct(f0r_instance_t instance)
|
||||
{
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* info)
|
||||
{
|
||||
info->name = "heatmap0r";
|
||||
info->author = "Cynthia";
|
||||
info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
info->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
info->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
info->major_version = 0;
|
||||
info->minor_version = 1;
|
||||
info->num_params = 4;
|
||||
info->explanation = "Performs a continuous trichromatic tinting";
|
||||
}
|
||||
|
||||
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
{
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
info->name = "Map black to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with zero luminance";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "Map grey to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with mid luminance";
|
||||
break;
|
||||
case 2:
|
||||
info->name = "Map white to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with full luminance";
|
||||
break;
|
||||
case 3:
|
||||
info->name = "Grey point";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Point in the luminance axis grey color is located";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
assert(instance);
|
||||
heatmap0r_t* inst = (heatmap0r_t*)instance;
|
||||
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
inst->black = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 1:
|
||||
inst->grey = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 2:
|
||||
inst->white = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 3:
|
||||
inst->gp = *((double *)param);
|
||||
break;
|
||||
}
|
||||
|
||||
gen_heatmap0r_luts (inst);
|
||||
}
|
||||
|
||||
void f0r_get_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
assert(instance);
|
||||
heatmap0r_t* inst = (heatmap0r_t*)instance;
|
||||
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
*((f0r_param_color_t*)param) = inst->black;
|
||||
break;
|
||||
case 1:
|
||||
*((f0r_param_color_t*)param) = inst->grey;
|
||||
break;
|
||||
case 2:
|
||||
*((f0r_param_color_t*)param) = inst->white;
|
||||
break;
|
||||
case 3:
|
||||
*((double *)param) = inst->gp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
assert(instance);
|
||||
heatmap0r_t* inst = (heatmap0r_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
|
||||
const unsigned char* src = (void*)inframe;
|
||||
unsigned char* dst = (void*)outframe;
|
||||
|
||||
unsigned char luma, r, g, b;
|
||||
while (len--)
|
||||
{
|
||||
r = *src++;
|
||||
g = *src++;
|
||||
b = *src++;
|
||||
|
||||
luma = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
|
||||
*dst++ = inst->rlut[luma];
|
||||
*dst++ = inst->glut[luma];
|
||||
*dst++ = inst->blut[luma];
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
{
|
||||
int val;
|
||||
case 0:
|
||||
/* constrast */
|
||||
/* contrast */
|
||||
val = (int) (*((double*)param) * 360.0); /* remap to [0, 360] */
|
||||
if (val != inst->hueshift)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* matrix -
|
||||
* Use 4x4 matricies to process color images.
|
||||
* Use 4x4 matrices to process color images.
|
||||
*
|
||||
* To compile:
|
||||
cc matrix.c -o matrix -lgutil -limage -lgl -lm
|
||||
@@ -73,7 +73,7 @@ applymatrix(unsigned long *lptr,float mat[4][4],int n)
|
||||
|
||||
/*
|
||||
* matrixmult -
|
||||
* multiply two matricies
|
||||
* multiply two matrices
|
||||
*/
|
||||
void
|
||||
matrixmult(float a[4][4],float b[4][4],float c[4][4])
|
||||
@@ -132,7 +132,7 @@ xformpnt(float matrix[4][4],float x,float y,float z,float *tx,float *ty,float *t
|
||||
|
||||
/*
|
||||
* cscalemat -
|
||||
* make a color scale marix
|
||||
* make a color scale matrix
|
||||
*/
|
||||
void
|
||||
cscalemat(float mat[4][4],float rscale,float gscale,float bscale)
|
||||
@@ -164,7 +164,7 @@ cscalemat(float mat[4][4],float rscale,float gscale,float bscale)
|
||||
|
||||
/*
|
||||
* lummat -
|
||||
* make a luminance marix
|
||||
* make a luminance matrix
|
||||
*/
|
||||
void
|
||||
lummat(float mat[4][4])
|
||||
@@ -199,7 +199,7 @@ lummat(float mat[4][4])
|
||||
|
||||
/*
|
||||
* saturatemat -
|
||||
* make a saturation marix
|
||||
* make a saturation matrix
|
||||
*/
|
||||
void
|
||||
saturatemat(float mat[4][4],float sat)
|
||||
|
||||
@@ -28,7 +28,7 @@ Allows for specification of number of segments (mirrors), auto selection of opti
|
||||
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]`.
|
||||
6. `segmentation_direction` `(float=1)` - When `source_segment` is `false` the source segment 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.
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace std
|
||||
{
|
||||
|
||||
// default delete for IKaleid0sc0pe
|
||||
// this isn't going to work across an actaul shared object boundary but
|
||||
// this isn't going to work across an actual shared object boundary but
|
||||
// not particular worried about that at the moment
|
||||
template<>
|
||||
class default_delete<libkaleid0sc0pe::IKaleid0sc0pe>
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
/**
|
||||
* Sets the number of threads to use when processing.
|
||||
* Default to 0.
|
||||
* @param threading the nubmer of threads to use. \c 0, calculate automatically,
|
||||
* @param threading the number of threads to use. \c 0, calculate automatically,
|
||||
* otherwise the explicit thread count.
|
||||
* @return
|
||||
* - 0: Success
|
||||
|
||||
@@ -143,7 +143,7 @@ private:
|
||||
/// <tt>source_x,source_y</tt>
|
||||
/// @param x x coordinate to start rotate from
|
||||
/// @param y y coordinate to rotate
|
||||
/// @param source_x receives the x coordiante results
|
||||
/// @param source_x receives the x coordinate results
|
||||
/// @param source_y receives the y coordinate results
|
||||
inline void rotate(int x, int y, __m128 *source_x, __m128 *source_y);
|
||||
#else
|
||||
@@ -164,8 +164,8 @@ private:
|
||||
Reflect_info calculate_reflect_info(std::uint32_t x, std::uint32_t y);
|
||||
|
||||
/// Converts coordinates to screen space
|
||||
/// @param x recieves x coordinate
|
||||
/// @param y recieves y coordinate
|
||||
/// @param x receives x coordinate
|
||||
/// @param y receives y coordinate
|
||||
/// @param sx source x coordinate
|
||||
/// @param sy source y coordinate
|
||||
void to_screen(float *x, float *y, std::uint32_t sx, std::uint32_t sy);
|
||||
|
||||
@@ -301,7 +301,7 @@ _PS_CONST(coscof_p2, 4.166664568298827E-002);
|
||||
_PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI
|
||||
|
||||
|
||||
/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so
|
||||
/* evaluation of 4 sines at once, using only SSE1+MMX intrinsics so
|
||||
it runs also on old athlons XPs and the pentium III of your grand
|
||||
mother.
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ CASCADING
|
||||
This plugin can be cascaded, but it is not possible to get the same
|
||||
color based mask in the second instance, because the colors will be
|
||||
changed by the first instance. To enable two operations with the
|
||||
same mask, each plugin instance can do two opertions.
|
||||
same mask, each plugin instance can do two operations.
|
||||
With transparency and edge masks, cascading is a bit easier.
|
||||
If the hue gate and saturation threshold are not used, transparency
|
||||
and edge masks can be exactly the same in cascaded plugins.
|
||||
@@ -122,10 +122,10 @@ Enable a second operation to be performed with the same mask.
|
||||
|
||||
Show mask:
|
||||
This will show the selected mask as a greyscale image, to help with
|
||||
fine tuning of the masks. Shoud be OFF for the final render.
|
||||
fine tuning of the masks. Should be OFF for the final render.
|
||||
|
||||
Mask to Alpha:
|
||||
Copies the active mask to the alpha channel.
|
||||
For all normal spill cleaning operations, this should be OFF.
|
||||
By seting it ON, the keyspillm0pup itself can be used as a keyer,
|
||||
By setting it ON, the keyspillm0pup itself can be used as a keyer,
|
||||
or to generate some special effects.
|
||||
|
||||
@@ -852,7 +852,7 @@ public:
|
||||
fb = m_rgbLightMask[pixel].b;
|
||||
|
||||
if (lowerOverexposure > 0) {
|
||||
// Comparisation of plots with octave:
|
||||
// Comparison of plots with octave:
|
||||
// clf;hold on;plot([0 1],[0 1],'k');plot(range,ones(length(range),1),'k');plot(range,sqrt(range));plot(range,log(1+range),'k');plot(range,log(1+range),'g');plot(range,(log(1+range)/3).^.5,'r');axis equal
|
||||
fr = pow( log(1+fr)/lowerOverexposure, .5 );
|
||||
fg = pow( log(1+fg)/lowerOverexposure, .5 );
|
||||
|
||||
@@ -38,7 +38,7 @@ Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu
|
||||
double PI=3.14159265358979;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void draw_rectangle(float_rgba *s, int w, int h, float x, float y, float wr, float hr, float_rgba c)
|
||||
static inline void draw_rectangle(float_rgba *s, int w, int h, float x, float y, float wr, float hr, float_rgba c)
|
||||
{
|
||||
int i,j;
|
||||
int zx,kx,zy,ky;
|
||||
@@ -139,7 +139,7 @@ draw_rectangle(s, w, h, x1, y1+1, v, 1, black);
|
||||
//justified
|
||||
//p=0 one decimal place p=1 three decimal places
|
||||
//m=1 always show sign
|
||||
void forstr(float a, int p, int m, char *s)
|
||||
inline static void forstr(float a, int p, int m, char *s)
|
||||
{
|
||||
float b;
|
||||
char *p3=" %5.3f";
|
||||
@@ -192,20 +192,20 @@ if (mm==1)
|
||||
forstr(s.rms,1-u,0,rs);
|
||||
forstr(s.min,1-u,m,ns);
|
||||
forstr(s.max,1-u,m,xs);
|
||||
sprintf(fs,"%s%s%s %s%s", lab, as, rs, ns, xs);
|
||||
snprintf(fs,255,"%s%s%s %s%s", lab, as, rs, ns, xs);
|
||||
sprintf(str,fs,s.avg,s.rms,s.min,s.max);
|
||||
}
|
||||
else
|
||||
{
|
||||
forstr(s.avg,1-u,m,as);
|
||||
forstr(s.rms,1-u,0,rs);
|
||||
sprintf(fs,"%s%s%s", lab, as, rs);
|
||||
snprintf(fs,255,"%s%s%s", lab, as, rs);
|
||||
sprintf(str,fs,s.avg,s.rms);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
//probe size markers in the magnifier diaplay
|
||||
//probe size markers in the magnifier display
|
||||
void sxmarkers(float_rgba *s, int w, int h, int x0, int y0, int np, int sx, int sy, int vp)
|
||||
{
|
||||
int np2,x,y,i,j;
|
||||
@@ -251,7 +251,7 @@ if (sx>np)
|
||||
s[w*y+x]=white;
|
||||
x=x0+(np+2)*vp-i-1;
|
||||
s[w*y+x]=white;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sy>np)
|
||||
{
|
||||
@@ -263,7 +263,7 @@ if (sy>np)
|
||||
s[w*y+x]=white;
|
||||
y=y0+(np+2)*vp-i-1;
|
||||
s[w*y+x]=white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -301,7 +301,7 @@ y0=h/20;
|
||||
if (bw==1) //big window
|
||||
{
|
||||
vx=240;
|
||||
vy = (m<=2) ? 320 : 300;
|
||||
vy = (m<=2) ? 320 : 300;
|
||||
x0 = (*poz==0) ? h/20 : w-h/20-vx;
|
||||
np=25; //size of magnifier
|
||||
xn = (m<=2) ? x0+8 : x0+70;
|
||||
@@ -745,4 +745,3 @@ crosshair(in->sl, in->w, in->h, in->x, in->y, 2*in->sx+1, 2*in->sy+1, 15);
|
||||
|
||||
floatrgba2color(in->sl, outframe, in->w , in->h);
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ while (c[i]!=0)
|
||||
//justified
|
||||
//p=0 one decimal place p=1 three decimal places
|
||||
//m=1 always show sign
|
||||
void forstr(float a, int p, int m, char *s)
|
||||
inline static void forstr(float a, int p, int m, char *s)
|
||||
{
|
||||
float b;
|
||||
char *p3=" %5.3f";
|
||||
@@ -320,7 +320,7 @@ if ((dit&0x00000001)!=0) //marker 1 value
|
||||
if (m1>0)
|
||||
{
|
||||
forstr(data[0],1-u,0,frs);
|
||||
sprintf(fs,"%%s Mk1=%s", frs);
|
||||
snprintf(fs,255,"%%s Mk1=%s", frs);
|
||||
sprintf(str,fs,str,data[0]);
|
||||
}
|
||||
else
|
||||
@@ -331,7 +331,7 @@ if ((dit&0x00000004)!=0) //marker 2 value
|
||||
if (m2>0)
|
||||
{
|
||||
forstr(data[1],1-u,0,frs);
|
||||
sprintf(fs,"%%s Mk2=%s", frs);
|
||||
snprintf(fs,255,"%%s Mk2=%s", frs);
|
||||
sprintf(str,fs,str,data[1]);
|
||||
}
|
||||
else
|
||||
@@ -342,7 +342,7 @@ if ((dit&0x00000010)!=0) //difference marker2-marker1
|
||||
if ((m2>0)&&(m1>0))
|
||||
{
|
||||
forstr(data[2],1-u,0,frs);
|
||||
sprintf(fs,"%%s D=%s", frs);
|
||||
snprintf(fs,255,"%%s D=%s", frs);
|
||||
sprintf(str,fs,str,data[2]);
|
||||
}
|
||||
else
|
||||
@@ -351,25 +351,25 @@ if ((dit&0x00000010)!=0) //difference marker2-marker1
|
||||
if ((dit&0x00000020)!=0) //average of profile
|
||||
{
|
||||
forstr(data[3],1-u,0,frs);
|
||||
sprintf(fs,"%%s Avg=%s", frs);
|
||||
snprintf(fs,255,"%%s Avg=%s", frs);
|
||||
sprintf(str,fs,str,data[3]);
|
||||
}
|
||||
if ((dit&0x00000040)!=0) //RMS of profile
|
||||
{
|
||||
forstr(data[4],1-u,0,frs);
|
||||
sprintf(fs,"%%s RMS=%s", frs);
|
||||
snprintf(fs,255,"%%s RMS=%s", frs);
|
||||
sprintf(str,fs,str,data[4]);
|
||||
}
|
||||
if ((dit&0x00000080)!=0) //MIN of profile
|
||||
{
|
||||
forstr(data[5],1-u,0,frs);
|
||||
sprintf(fs,"%%s Min=%s", frs);
|
||||
snprintf(fs,255,"%%s Min=%s", frs);
|
||||
sprintf(str,fs,str,data[5]);
|
||||
}
|
||||
if ((dit&0x00000100)!=0) //MAX of profile
|
||||
{
|
||||
forstr(data[6],1-u,0,frs);
|
||||
sprintf(fs,"%%s Max=%s", frs);
|
||||
snprintf(fs,255,"%%s Max=%s", frs);
|
||||
sprintf(str,fs,str,data[6]);
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ if (y<h/2-20) *poz=1; //bottom
|
||||
if (y>h/2+20) *poz=0; //top
|
||||
x0=h/20;
|
||||
vx=w*15/16;
|
||||
vy = h*6/16;
|
||||
vy = h*6/16;
|
||||
y0 = (*poz==0) ? h/20 : h-h/20-vy;
|
||||
|
||||
//end points of profile
|
||||
@@ -1035,4 +1035,3 @@ prof(in->sl, in->w, in->h, &in->poz, in->x, in->y, in->tilt, in->len, 1, in->mer
|
||||
|
||||
floatrgba2color(in->sl, outframe, in->w , in->h);
|
||||
}
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ static void ctmf_helper(
|
||||
* odd dimensions. Images of arbitrary size may be processed.
|
||||
*
|
||||
* To process multi-channel images, you must call this function multiple times,
|
||||
* changing the source and destination adresses and steps such that each channel
|
||||
* changing the source and destination addresses and steps such that each channel
|
||||
* is processed as an independent single-channel image.
|
||||
*
|
||||
* Processing images of arbitrary bit depth is not supported.
|
||||
|
||||
@@ -68,8 +68,8 @@ Arp ML3D: multilevel spatio-temporal, see [1]
|
||||
ML3DEX: multilevel spatio-temporal, see [1]
|
||||
|
||||
|
||||
[1] Anil Christopher Kokaram: Motion Picure Restoration
|
||||
phd disertation
|
||||
[1] Anil Christopher Kokaram: Motion Picture Restoration
|
||||
phd dissertation
|
||||
|
||||
****************************************** */
|
||||
|
||||
|
||||
@@ -114,5 +114,5 @@ REFERENCES
|
||||
http://nomis80.org/ctmf.pdf
|
||||
http://nomis80.org/ctmf.html
|
||||
|
||||
[3] Anil Christopher Kokaram: Motion Picure Restoration
|
||||
phd disertation
|
||||
[3] Anil Christopher Kokaram: Motion Picture Restoration
|
||||
phd dissertation
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* 2002/2/9
|
||||
* Original code copied same frame twice, and did not use memcpy().
|
||||
* I modifed those point.
|
||||
* I modified those point.
|
||||
* -Kentarou Fukuchi
|
||||
*
|
||||
* 2009/8/26
|
||||
|
||||
@@ -60,6 +60,23 @@ crt_sincos14(int *s, int *c, int n)
|
||||
}
|
||||
}
|
||||
|
||||
extern int
|
||||
crt_bpp4fmt(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case CRT_PIX_FORMAT_RGB:
|
||||
case CRT_PIX_FORMAT_BGR:
|
||||
return 3;
|
||||
case CRT_PIX_FORMAT_ARGB:
|
||||
case CRT_PIX_FORMAT_RGBA:
|
||||
case CRT_PIX_FORMAT_ABGR:
|
||||
case CRT_PIX_FORMAT_BGRA:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/********************************* FILTERS ***********************************/
|
||||
/*****************************************************************************/
|
||||
@@ -222,10 +239,11 @@ eqf(struct EQF *f, int s)
|
||||
/*****************************************************************************/
|
||||
|
||||
extern void
|
||||
crt_resize(struct CRT *v, int w, int h, unsigned char *out)
|
||||
crt_resize(struct CRT *v, int w, int h, int f, unsigned char *out)
|
||||
{
|
||||
v->outw = w;
|
||||
v->outh = h;
|
||||
v->out_format = f;
|
||||
v->out = out;
|
||||
}
|
||||
|
||||
@@ -239,22 +257,14 @@ crt_reset(struct CRT *v)
|
||||
v->black_point = 0;
|
||||
v->white_point = 100;
|
||||
v->hsync = 0;
|
||||
v->vsync = 0;
|
||||
|
||||
v->scanlines = 0; /* leave gaps between lines if necessary */
|
||||
v->blend = 0; /* blend new field onto previous image */
|
||||
|
||||
// these options were previously #defined in crt_core.h
|
||||
v->crt_do_vsync = 1;
|
||||
v->crt_do_hsync = 1;
|
||||
v->do_vhs_noise = 0;
|
||||
v->vsync = 0;
|
||||
}
|
||||
|
||||
extern void
|
||||
crt_init(struct CRT *v, int w, int h, unsigned char *out)
|
||||
crt_init(struct CRT *v, int w, int h, int f, unsigned char *out)
|
||||
{
|
||||
memset(v, 0, sizeof(struct CRT));
|
||||
crt_resize(v, w, h, out);
|
||||
crt_resize(v, w, h, f, out);
|
||||
crt_reset(v);
|
||||
v->rn = 194;
|
||||
|
||||
@@ -293,58 +303,61 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
int huesn, huecs;
|
||||
int xnudge = -3, ynudge = 3;
|
||||
int bright = v->brightness - (BLACK_LEVEL + v->black_point);
|
||||
int pitch;
|
||||
int bpp, pitch;
|
||||
#if CRT_DO_BLOOM
|
||||
int prev_e; /* filtered beam energy per scan line */
|
||||
int max_e; /* approx maximum energy in a scan line */
|
||||
#endif
|
||||
|
||||
pitch = v->outw * BPP;
|
||||
bpp = crt_bpp4fmt(v->out_format);
|
||||
if (bpp == 0) {
|
||||
return;
|
||||
}
|
||||
pitch = v->outw * bpp;
|
||||
|
||||
crt_sincos14(&huesn, &huecs, ((v->hue % 360) + 33) * 8192 / 180);
|
||||
huesn >>= 11; /* make 4-bit */
|
||||
huecs >>= 11;
|
||||
|
||||
rn = v->rn;
|
||||
if(!v->crt_do_vsync)
|
||||
{
|
||||
/* determine field before we add noise,
|
||||
* otherwise it's not reliably recoverable
|
||||
*/
|
||||
for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
|
||||
line = POSMOD(v->vsync + i, CRT_VRES);
|
||||
sig = v->analog + line * CRT_HRES;
|
||||
s = 0;
|
||||
for (j = 0; j < CRT_HRES; j++) {
|
||||
s += sig[j];
|
||||
if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
|
||||
goto found_field;
|
||||
}
|
||||
#if !CRT_DO_VSYNC
|
||||
/* determine field before we add noise,
|
||||
* otherwise it's not reliably recoverable
|
||||
*/
|
||||
for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
|
||||
line = POSMOD(v->vsync + i, CRT_VRES);
|
||||
sig = v->analog + line * CRT_HRES;
|
||||
s = 0;
|
||||
for (j = 0; j < CRT_HRES; j++) {
|
||||
s += sig[j];
|
||||
if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
|
||||
goto found_field;
|
||||
}
|
||||
}
|
||||
found_field:
|
||||
/* if vsync signal was in second half of line, odd field */
|
||||
field = (j > (CRT_HRES / 2));
|
||||
v->vsync = -3;
|
||||
}
|
||||
if(v->do_vhs_noise)
|
||||
{
|
||||
line = ((rand() % 8) - 4) + 14;
|
||||
}
|
||||
found_field:
|
||||
/* if vsync signal was in second half of line, odd field */
|
||||
field = (j > (CRT_HRES / 2));
|
||||
v->vsync = -3;
|
||||
#endif
|
||||
#if ((CRT_SYSTEM == CRT_SYSTEM_NTSCVHS) && CRT_VHS_NOISE)
|
||||
line = ((rand() % 8) - 4) + 14;
|
||||
#endif
|
||||
for (i = 0; i < CRT_INPUT_SIZE; i++) {
|
||||
int nn = noise;
|
||||
if(v->do_vhs_noise)
|
||||
{
|
||||
rn = rand();
|
||||
if (i > (CRT_INPUT_SIZE - CRT_HRES * (16 + ((rand() % 20) - 10))) &&
|
||||
i < (CRT_INPUT_SIZE - CRT_HRES * (5 + ((rand() % 8) - 4)))) {
|
||||
int ln, sn, cs;
|
||||
#if ((CRT_SYSTEM == CRT_SYSTEM_NTSCVHS) && CRT_VHS_NOISE)
|
||||
rn = rand();
|
||||
if (i > (CRT_INPUT_SIZE - CRT_HRES * (16 + ((rand() % 20) - 10))) &&
|
||||
i < (CRT_INPUT_SIZE - CRT_HRES * (5 + ((rand() % 8) - 4)))) {
|
||||
int ln, sn, cs;
|
||||
|
||||
ln = (i * line) / CRT_HRES;
|
||||
crt_sincos14(&sn, &cs, ln * 8192 / 180);
|
||||
nn = cs >> 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rn = (214019 * rn + 140327895);
|
||||
ln = (i * line) / CRT_HRES;
|
||||
crt_sincos14(&sn, &cs, ln * 8192 / 180);
|
||||
nn = cs >> 8;
|
||||
}
|
||||
#else
|
||||
rn = (214019 * rn + 140327895);
|
||||
#endif
|
||||
/* signal + noise */
|
||||
s = v->analog[i] + (((((rn >> 16) & 0xff) - 0x7f) * nn) >> 8);
|
||||
if (s > 127) { s = 127; }
|
||||
@@ -353,37 +366,40 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
}
|
||||
v->rn = rn;
|
||||
|
||||
if(v->crt_do_vsync)
|
||||
{
|
||||
/* Look for vertical sync.
|
||||
*
|
||||
* This is done by integrating the signal and
|
||||
* seeing if it exceeds a threshold. The threshold of
|
||||
* the vertical sync pulse is much higher because the
|
||||
* vsync pulse is a lot longer than the hsync pulse.
|
||||
* The signal needs to be integrated to lessen
|
||||
* the noise in the signal.
|
||||
*/
|
||||
for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
|
||||
line = POSMOD(v->vsync + i, CRT_VRES);
|
||||
sig = v->inp + line * CRT_HRES;
|
||||
s = 0;
|
||||
for (j = 0; j < CRT_HRES; j++) {
|
||||
s += sig[j];
|
||||
/* increase the multiplier to make the vsync
|
||||
* more stable when there is a lot of noise
|
||||
*/
|
||||
if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
|
||||
goto vsync_found;
|
||||
}
|
||||
#if CRT_DO_VSYNC
|
||||
/* Look for vertical sync.
|
||||
*
|
||||
* This is done by integrating the signal and
|
||||
* seeing if it exceeds a threshold. The threshold of
|
||||
* the vertical sync pulse is much higher because the
|
||||
* vsync pulse is a lot longer than the hsync pulse.
|
||||
* The signal needs to be integrated to lessen
|
||||
* the noise in the signal.
|
||||
*/
|
||||
for (i = -CRT_VSYNC_WINDOW; i < CRT_VSYNC_WINDOW; i++) {
|
||||
line = POSMOD(v->vsync + i, CRT_VRES);
|
||||
sig = v->inp + line * CRT_HRES;
|
||||
s = 0;
|
||||
for (j = 0; j < CRT_HRES; j++) {
|
||||
s += sig[j];
|
||||
/* increase the multiplier to make the vsync
|
||||
* more stable when there is a lot of noise
|
||||
*/
|
||||
if (s <= (CRT_VSYNC_THRESH * SYNC_LEVEL)) {
|
||||
goto vsync_found;
|
||||
}
|
||||
}
|
||||
vsync_found:
|
||||
v->vsync = line; /* vsync found (or gave up) at this line */
|
||||
/* if vsync signal was in second half of line, odd field */
|
||||
field = (j > (CRT_HRES / 2));
|
||||
}
|
||||
}
|
||||
vsync_found:
|
||||
v->vsync = line; /* vsync found (or gave up) at this line */
|
||||
/* if vsync signal was in second half of line, odd field */
|
||||
field = (j > (CRT_HRES / 2));
|
||||
#endif
|
||||
|
||||
#if CRT_DO_BLOOM
|
||||
max_e = (128 + (noise / 2)) * AV_LEN;
|
||||
prev_e = (16384 / 8);
|
||||
#endif
|
||||
/* ratio of output height to active video lines in the signal */
|
||||
ratio = (v->outh << 16) / CRT_LINES;
|
||||
ratio = (ratio + 32768) >> 16;
|
||||
@@ -405,6 +421,9 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
int xpos, ypos;
|
||||
int beg, end;
|
||||
int phasealign;
|
||||
#if CRT_DO_BLOOM
|
||||
int line_w;
|
||||
#endif
|
||||
|
||||
beg = (line - CRT_TOP + 0) * (v->outh + v->v_fac) / CRT_LINES + field;
|
||||
end = (line - CRT_TOP + 1) * (v->outh + v->v_fac) / CRT_LINES + field;
|
||||
@@ -424,14 +443,11 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(v->crt_do_hsync)
|
||||
{
|
||||
v->hsync = POSMOD(i + v->hsync, CRT_HRES);
|
||||
}
|
||||
else
|
||||
{
|
||||
v->hsync = 0;
|
||||
}
|
||||
#if CRT_DO_HSYNC
|
||||
v->hsync = POSMOD(i + v->hsync, CRT_HRES);
|
||||
#else
|
||||
v->hsync = 0;
|
||||
#endif
|
||||
|
||||
xpos = POSMOD(AV_BEG + v->hsync + xnudge, CRT_HRES);
|
||||
ypos = POSMOD(line + v->vsync + ynudge, CRT_VRES);
|
||||
@@ -493,13 +509,28 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
}
|
||||
#endif
|
||||
sig = v->inp + pos;
|
||||
#if CRT_DO_BLOOM
|
||||
s = 0;
|
||||
for (i = 0; i < AV_LEN; i++) {
|
||||
s += sig[i]; /* sum up the scan line */
|
||||
}
|
||||
/* bloom emulation */
|
||||
prev_e = (prev_e * 123 / 128) + ((((max_e >> 1) - s) << 10) / max_e);
|
||||
line_w = (AV_LEN * 112 / 128) + (prev_e >> 9);
|
||||
|
||||
dx = (line_w << 12) / v->outw;
|
||||
scanL = ((AV_LEN / 2) - (line_w >> 1) + 8) << 12;
|
||||
scanR = (AV_LEN - 1) << 12;
|
||||
|
||||
L = (scanL >> 12);
|
||||
R = (scanR >> 12);
|
||||
#else
|
||||
dx = ((AV_LEN - 1) << 12) / v->outw;
|
||||
scanL = 0;
|
||||
scanR = (AV_LEN - 1) << 12;
|
||||
L = 0;
|
||||
R = AV_LEN;
|
||||
|
||||
R = AV_LEN;
|
||||
#endif
|
||||
reset_eq(&eqY);
|
||||
reset_eq(&eqI);
|
||||
reset_eq(&eqQ);
|
||||
@@ -552,8 +583,26 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
|
||||
if (v->blend) {
|
||||
aa = (r << 16 | g << 8 | b);
|
||||
bb = cL[0] << 16 | cL[1] << 8 | cL[2];
|
||||
|
||||
switch (v->out_format) {
|
||||
case CRT_PIX_FORMAT_RGB:
|
||||
case CRT_PIX_FORMAT_RGBA:
|
||||
bb = cL[0] << 16 | cL[1] << 8 | cL[2];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_BGR:
|
||||
case CRT_PIX_FORMAT_BGRA:
|
||||
bb = cL[2] << 16 | cL[1] << 8 | cL[0];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_ARGB:
|
||||
bb = cL[1] << 16 | cL[2] << 8 | cL[3];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_ABGR:
|
||||
bb = cL[3] << 16 | cL[2] << 8 | cL[1];
|
||||
break;
|
||||
default:
|
||||
bb = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* blend with previous color there */
|
||||
bb = (((aa & 0xfefeff) >> 1) + ((bb & 0xfefeff) >> 1));
|
||||
@@ -561,12 +610,52 @@ crt_demodulate(struct CRT *v, int noise)
|
||||
bb = (r << 16 | g << 8 | b);
|
||||
}
|
||||
|
||||
cL[0] = bb >> 16 & 0xff;
|
||||
cL[1] = bb >> 8 & 0xff;
|
||||
cL[2] = bb >> 0 & 0xff;
|
||||
cL[3] = 0xff;
|
||||
switch (v->out_format) {
|
||||
case CRT_PIX_FORMAT_RGB:
|
||||
cL[0] = bb >> 16 & 0xff;
|
||||
cL[1] = bb >> 8 & 0xff;
|
||||
cL[2] = bb >> 0 & 0xff;
|
||||
break;
|
||||
|
||||
cL += BPP;
|
||||
case CRT_PIX_FORMAT_RGBA:
|
||||
cL[0] = bb >> 16 & 0xff;
|
||||
cL[1] = bb >> 8 & 0xff;
|
||||
cL[2] = bb >> 0 & 0xff;
|
||||
cL[3] = 0xff;
|
||||
break;
|
||||
|
||||
case CRT_PIX_FORMAT_BGR:
|
||||
cL[0] = bb >> 0 & 0xff;
|
||||
cL[1] = bb >> 8 & 0xff;
|
||||
cL[2] = bb >> 16 & 0xff;
|
||||
break;
|
||||
|
||||
case CRT_PIX_FORMAT_BGRA:
|
||||
cL[0] = bb >> 0 & 0xff;
|
||||
cL[1] = bb >> 8 & 0xff;
|
||||
cL[2] = bb >> 16 & 0xff;
|
||||
cL[3] = 0xff;
|
||||
break;
|
||||
|
||||
case CRT_PIX_FORMAT_ARGB:
|
||||
cL[0] = 0xff;
|
||||
cL[1] = bb >> 16 & 0xff;
|
||||
cL[2] = bb >> 8 & 0xff;
|
||||
cL[3] = bb >> 0 & 0xff;
|
||||
break;
|
||||
|
||||
case CRT_PIX_FORMAT_ABGR:
|
||||
cL[0] = 0xff;
|
||||
cL[1] = bb >> 0 & 0xff;
|
||||
cL[2] = bb >> 8 & 0xff;
|
||||
cL[3] = bb >> 16 & 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cL += bpp;
|
||||
}
|
||||
|
||||
/* duplicate extra lines */
|
||||
|
||||
@@ -18,36 +18,72 @@ extern "C" {
|
||||
/* crt_core.h
|
||||
*
|
||||
* The demodulator. This is also where you can define which system to emulate.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* library version */
|
||||
#define CRT_MAJOR 2
|
||||
#define CRT_MINOR 3
|
||||
#define CRT_PATCH 2
|
||||
|
||||
#include "crt_ntsc.h"
|
||||
|
||||
// frei0r always uses 4 bits per pixel so it is pointless for there to be any other possibilities
|
||||
#define BPP 4
|
||||
|
||||
#define CRT_SYSTEM_NTSC 0 /* standard NTSC */
|
||||
#define CRT_SYSTEM_NES 1 /* decode 6 or 9-bit NES pixels */
|
||||
#define CRT_SYSTEM_PV1K 2 /* Casio PV-1000 */
|
||||
#define CRT_SYSTEM_SNES 3 /* SNES - uses RGB */
|
||||
#define CRT_SYSTEM_TEMP 4 /* template implementation */
|
||||
#define CRT_SYSTEM_NTSCVHS 5 /* standard NTSC VHS */
|
||||
#define CRT_SYSTEM_NESRGB 6 /* encode RGB image with NES artifacts */
|
||||
|
||||
/* the system to be compiled */
|
||||
#ifndef CRT_SYSTEM
|
||||
#define CRT_SYSTEM CRT_SYSTEM_NTSC
|
||||
#endif
|
||||
|
||||
#if (CRT_SYSTEM == CRT_SYSTEM_NES)
|
||||
#include "crt_nes.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_SNES)
|
||||
#include "crt_snes.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_NTSC)
|
||||
#include "crt_ntsc.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_PV1K)
|
||||
#include "crt_pv1k.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_TEMP)
|
||||
#include "crt_template.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_NTSCVHS)
|
||||
#include "crt_ntscvhs.h"
|
||||
#elif (CRT_SYSTEM == CRT_SYSTEM_NESRGB)
|
||||
#include "crt_nesrgb.h"
|
||||
#else
|
||||
#error No system defined
|
||||
#endif
|
||||
|
||||
/* NOTE: this library does not use the alpha channel at all */
|
||||
#define CRT_PIX_FORMAT_RGB 0 /* 3 bytes per pixel [R,G,B,R,G,B,R,G,B...] */
|
||||
#define CRT_PIX_FORMAT_BGR 1 /* 3 bytes per pixel [B,G,R,B,G,R,B,G,R...] */
|
||||
#define CRT_PIX_FORMAT_ARGB 2 /* 4 bytes per pixel [A,R,G,B,A,R,G,B...] */
|
||||
#define CRT_PIX_FORMAT_RGBA 3 /* 4 bytes per pixel [R,G,B,A,R,G,B,A...] */
|
||||
#define CRT_PIX_FORMAT_ABGR 4 /* 4 bytes per pixel [A,B,G,R,A,B,G,R...] */
|
||||
#define CRT_PIX_FORMAT_BGRA 5 /* 4 bytes per pixel [B,G,R,A,B,G,R,A...] */
|
||||
|
||||
/* do bloom emulation (side effect: makes screen have black borders) */
|
||||
#define CRT_DO_BLOOM 0 /* does not work for NES */
|
||||
#define CRT_DO_VSYNC 1 /* look for VSYNC */
|
||||
#define CRT_DO_HSYNC 1 /* look for HSYNC */
|
||||
|
||||
struct CRT {
|
||||
signed char analog[CRT_INPUT_SIZE];
|
||||
signed char inp[CRT_INPUT_SIZE]; /* CRT input, can be noisy */
|
||||
|
||||
int outw, outh; /* output width/height */
|
||||
int out_format; /* output pixel format (one of the CRT_PIX_FORMATs) */
|
||||
unsigned char *out; /* output image */
|
||||
|
||||
int hue, brightness, contrast, saturation; /* common monitor settings */
|
||||
int black_point, white_point; /* user-adjustable */
|
||||
int scanlines; /* leave gaps between lines if necessary */
|
||||
int blend; /* blend new field onto previous image */
|
||||
unsigned v_fac; /* factor to stretch img vertically onto the output img */
|
||||
|
||||
// these options were previously #defined in crt_core.h
|
||||
int crt_do_vsync;
|
||||
int crt_do_hsync;
|
||||
int do_vhs_noise; /* 0 = no additional vhs noise, 1 = with additional vhs noise */
|
||||
unsigned v_fac; /* factor to stretch img vertically onto the output img */
|
||||
|
||||
/* internal data */
|
||||
int ccf[CRT_CC_VPER][CRT_CC_SAMPLES]; /* faster color carrier convergence */
|
||||
@@ -61,7 +97,7 @@ struct CRT {
|
||||
* f - format of the output image
|
||||
* out - pointer to output image data
|
||||
*/
|
||||
extern void crt_init(struct CRT *v, int w, int h, unsigned char *out);
|
||||
extern void crt_init(struct CRT *v, int w, int h, int f, unsigned char *out);
|
||||
|
||||
/* Updates the output image parameters
|
||||
* w - width of the output image
|
||||
@@ -69,7 +105,7 @@ extern void crt_init(struct CRT *v, int w, int h, unsigned char *out);
|
||||
* f - format of the output image
|
||||
* out - pointer to output image data
|
||||
*/
|
||||
extern void crt_resize(struct CRT *v, int w, int h, unsigned char *out);
|
||||
extern void crt_resize(struct CRT *v, int w, int h, int f, unsigned char *out);
|
||||
|
||||
/* Resets the CRT settings back to their defaults */
|
||||
extern void crt_reset(struct CRT *v);
|
||||
@@ -78,12 +114,20 @@ extern void crt_reset(struct CRT *v);
|
||||
* s - struct containing settings to apply to this field
|
||||
*/
|
||||
extern void crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s);
|
||||
|
||||
|
||||
/* Demodulates the NTSC signal generated by crt_modulate()
|
||||
* noise - the amount of noise added to the signal (0 - inf)
|
||||
*/
|
||||
extern void crt_demodulate(struct CRT *v, int noise);
|
||||
|
||||
/* Get the bytes per pixel for a certain CRT_PIX_FORMAT_
|
||||
*
|
||||
* format - the format to get the bytes per pixel for
|
||||
*
|
||||
* returns 0 if the specified format does not exist
|
||||
*/
|
||||
extern int crt_bpp4fmt(int format);
|
||||
|
||||
/*****************************************************************************/
|
||||
/*************************** FIXED POINT SIN/COS *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* NTSC/CRT - integer-only NTSC video signal encoding / decoding emulation
|
||||
*
|
||||
*
|
||||
* by EMMIR 2018-2023
|
||||
*
|
||||
*
|
||||
* YouTube: https://www.youtube.com/@EMMIR_KC/videos
|
||||
* Discord: https://discord.com/invite/hdYctSmyQJ
|
||||
*/
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "crt_core.h"
|
||||
|
||||
#if (CRT_SYSTEM == CRT_SYSTEM_NTSCVHS)
|
||||
#if (CRT_SYSTEM == CRT_SYSTEM_NTSC)
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -35,7 +35,7 @@ static int e11[] = {
|
||||
15133, /* e^2 */
|
||||
41135, /* e^3 */
|
||||
111817 /* e^4 */
|
||||
};
|
||||
};
|
||||
|
||||
/* fixed point e^x */
|
||||
static int
|
||||
@@ -61,7 +61,7 @@ expx(int n)
|
||||
if (idx > 0) {
|
||||
res = EXP_MUL(res, e11[idx]);
|
||||
}
|
||||
|
||||
|
||||
n &= EXP_MASK;
|
||||
nxt = EXP_ONE;
|
||||
acc = 0;
|
||||
@@ -99,7 +99,7 @@ static void
|
||||
init_iir(struct IIRLP *f, int freq, int limit)
|
||||
{
|
||||
int rate; /* cycles/pixel rate */
|
||||
|
||||
|
||||
memset(f, 0, sizeof(struct IIRLP));
|
||||
rate = (freq << 9) / limit;
|
||||
f->c = EXP_ONE - expx(-((EXP_PI << 9) / rate));
|
||||
@@ -137,41 +137,29 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
int ccburst[CRT_CC_SAMPLES]; /* color phase for burst */
|
||||
int sn, cs, n, ph;
|
||||
int inv_phase = 0;
|
||||
int aberration = 0;
|
||||
int bpp;
|
||||
|
||||
if (!s->iirs_initialized) {
|
||||
int y_freq = Y_FREQ_OFF;
|
||||
int i_freq = I_FREQ_OFF;
|
||||
int q_freq = Q_FREQ_OFF;
|
||||
|
||||
switch(s->vhs_mode)
|
||||
{
|
||||
case VHS_OFF:
|
||||
break;
|
||||
case VHS_SP:
|
||||
y_freq = Y_FREQ_SP;
|
||||
i_freq = I_FREQ_SP;
|
||||
q_freq = Q_FREQ_SP;
|
||||
break;
|
||||
case VHS_LP:
|
||||
y_freq = Y_FREQ_LP;
|
||||
i_freq = I_FREQ_LP;
|
||||
q_freq = Q_FREQ_LP;
|
||||
break;
|
||||
case VHS_EP:
|
||||
y_freq = Y_FREQ_EP;
|
||||
i_freq = I_FREQ_EP;
|
||||
q_freq = Q_FREQ_EP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
init_iir(&iirY, L_FREQ, y_freq);
|
||||
init_iir(&iirI, L_FREQ, i_freq);
|
||||
init_iir(&iirQ, L_FREQ, q_freq);
|
||||
init_iir(&iirY, L_FREQ, Y_FREQ);
|
||||
init_iir(&iirI, L_FREQ, I_FREQ);
|
||||
init_iir(&iirQ, L_FREQ, Q_FREQ);
|
||||
s->iirs_initialized = 1;
|
||||
}
|
||||
#if CRT_DO_BLOOM
|
||||
if (s->raw) {
|
||||
destw = s->w;
|
||||
desth = s->h;
|
||||
if (destw > ((AV_LEN * 55500) >> 16)) {
|
||||
destw = ((AV_LEN * 55500) >> 16);
|
||||
}
|
||||
if (desth > ((CRT_LINES * 63500) >> 16)) {
|
||||
desth = ((CRT_LINES * 63500) >> 16);
|
||||
}
|
||||
} else {
|
||||
destw = (AV_LEN * 55500) >> 16;
|
||||
desth = (CRT_LINES * 63500) >> 16;
|
||||
}
|
||||
#else
|
||||
if (s->raw) {
|
||||
destw = s->w;
|
||||
desth = s->h;
|
||||
@@ -182,7 +170,7 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
desth = ((CRT_LINES * 64500) >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (s->as_color) {
|
||||
for (x = 0; x < CRT_CC_SAMPLES; x++) {
|
||||
n = s->hue + x * (360 / CRT_CC_SAMPLES);
|
||||
@@ -198,10 +186,14 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
memset(ccmodI, 0, sizeof(ccmodI));
|
||||
memset(ccmodQ, 0, sizeof(ccmodQ));
|
||||
}
|
||||
|
||||
|
||||
bpp = crt_bpp4fmt(s->format);
|
||||
if (bpp == 0) {
|
||||
return; /* just to be safe */
|
||||
}
|
||||
xo = AV_BEG + s->xoffset + (AV_LEN - destw) / 2;
|
||||
yo = CRT_TOP + s->yoffset + (CRT_LINES - desth) / 2;
|
||||
|
||||
|
||||
s->field &= 1;
|
||||
s->frame &= 1;
|
||||
inv_phase = (s->field == s->frame);
|
||||
@@ -209,13 +201,11 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
|
||||
/* align signal */
|
||||
xo = (xo & ~3);
|
||||
if (s->do_aberration) {
|
||||
aberration = ((rand() % 12) - 8) + 14;
|
||||
}
|
||||
|
||||
for (n = 0; n < CRT_VRES; n++) {
|
||||
int t; /* time */
|
||||
signed char *line = &v->analog[n * CRT_HRES];
|
||||
|
||||
|
||||
t = LINE_BEG;
|
||||
|
||||
if (n <= 3 || (n >= 7 && n <= 9)) {
|
||||
@@ -238,13 +228,11 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
while (t < (offs[3] * CRT_HRES / 100)) line[t++] = BLANK_LEVEL;
|
||||
} else {
|
||||
int cb;
|
||||
if (n < (CRT_VRES - aberration)) {
|
||||
/* video line */
|
||||
while (t < SYNC_BEG) line[t++] = BLANK_LEVEL; /* FP */
|
||||
while (t < BW_BEG) line[t++] = SYNC_LEVEL; /* SYNC */
|
||||
}
|
||||
while (t < AV_BEG) line[t++] = BLANK_LEVEL; /* BW + CB + BP */
|
||||
|
||||
/* video line */
|
||||
while (t < SYNC_BEG) line[t++] = BLANK_LEVEL; /* FP */
|
||||
while (t < BW_BEG) line[t++] = SYNC_LEVEL; /* SYNC */
|
||||
while (t < AV_BEG) line[t++] = BLANK_LEVEL; /* BW + CB + BP */
|
||||
if (n < CRT_TOP) {
|
||||
while (t < CRT_HRES) line[t++] = BLANK_LEVEL;
|
||||
}
|
||||
@@ -261,50 +249,67 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
iccf[t % CRT_CC_SAMPLES] = line[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(s->vhs_mode != VHS_OFF)
|
||||
{
|
||||
/* reset hsync every frame so only the bottom part is warped */
|
||||
v->hsync = 0;
|
||||
}
|
||||
|
||||
for (y = 0; y < desth; y++) {
|
||||
int field_offset;
|
||||
int sy;
|
||||
|
||||
|
||||
field_offset = (s->field * s->h + desth) / desth / 2;
|
||||
sy = (y * s->h) / desth;
|
||||
|
||||
|
||||
sy += field_offset;
|
||||
|
||||
if (sy >= s->h) sy = s->h;
|
||||
|
||||
|
||||
sy *= s->w;
|
||||
|
||||
|
||||
reset_iir(&iirY);
|
||||
reset_iir(&iirI);
|
||||
reset_iir(&iirQ);
|
||||
|
||||
|
||||
for (x = 0; x < destw; x++) {
|
||||
int fy, fi, fq;
|
||||
int rA, gA, bA;
|
||||
const unsigned char *pix;
|
||||
int ire; /* composite signal */
|
||||
int xoff;
|
||||
|
||||
pix = s->data + ((((x * s->w) / destw) + sy) * BPP);
|
||||
rA = pix[0];
|
||||
gA = pix[1];
|
||||
bA = pix[2];
|
||||
|
||||
|
||||
pix = s->data + ((((x * s->w) / destw) + sy) * bpp);
|
||||
switch (s->format) {
|
||||
case CRT_PIX_FORMAT_RGB:
|
||||
case CRT_PIX_FORMAT_RGBA:
|
||||
rA = pix[0];
|
||||
gA = pix[1];
|
||||
bA = pix[2];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_BGR:
|
||||
case CRT_PIX_FORMAT_BGRA:
|
||||
rA = pix[2];
|
||||
gA = pix[1];
|
||||
bA = pix[0];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_ARGB:
|
||||
rA = pix[1];
|
||||
gA = pix[2];
|
||||
bA = pix[3];
|
||||
break;
|
||||
case CRT_PIX_FORMAT_ABGR:
|
||||
rA = pix[3];
|
||||
gA = pix[2];
|
||||
bA = pix[1];
|
||||
break;
|
||||
default:
|
||||
rA = gA = bA = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* RGB to YIQ */
|
||||
fy = (19595 * rA + 38470 * gA + 7471 * bA) >> 14;
|
||||
fi = (39059 * rA - 18022 * gA - 21103 * bA) >> 14;
|
||||
fq = (13894 * rA - 34275 * gA + 20382 * bA) >> 14;
|
||||
ire = BLACK_LEVEL + v->black_point;
|
||||
|
||||
|
||||
xoff = (x + xo) % CRT_CC_SAMPLES;
|
||||
/* bandlimit Y,I,Q */
|
||||
fy = iirf(&iirY, fy);
|
||||
@@ -319,14 +324,7 @@ crt_modulate(struct CRT *v, struct NTSC_SETTINGS *s)
|
||||
}
|
||||
for (n = 0; n < CRT_CC_VPER; n++) {
|
||||
for (x = 0; x < CRT_CC_SAMPLES; x++) {
|
||||
if(s->vhs_mode != VHS_OFF)
|
||||
{
|
||||
v->ccf[n][x] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
v->ccf[n][x] = iccf[x] << 7;
|
||||
}
|
||||
v->ccf[n][x] = iccf[x] << 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,18 +8,17 @@
|
||||
* Discord: https://discord.com/invite/hdYctSmyQJ
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
#ifndef _CRT_NTSC_VHS_H_
|
||||
#define _CRT_NTSC_VHS_H_
|
||||
#ifndef _CRT_NTSC_H_
|
||||
#define _CRT_NTSC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* crt_ntscvhs.h
|
||||
*
|
||||
* An interface to convert a digital image to an analog NTSC signal with VHS
|
||||
* quality and some optional signal aberration at the bottom.
|
||||
/* crt_ntsc.h
|
||||
*
|
||||
* An interface to convert a digital image to an analog NTSC signal.
|
||||
*
|
||||
*/
|
||||
/* 0 = vertical chroma (228 chroma clocks per line) */
|
||||
/* 1 = checkered chroma (227.5 chroma clocks per line) */
|
||||
@@ -42,7 +41,7 @@ extern "C" {
|
||||
#define CRT_TOP 21 /* first line with active video */
|
||||
#define CRT_BOT 261 /* final line with active video */
|
||||
#define CRT_LINES (CRT_BOT - CRT_TOP) /* number of active video lines */
|
||||
|
||||
|
||||
#define CRT_CC_SAMPLES 4 /* samples per chroma period (samples per 360 deg) */
|
||||
#define CRT_CC_VPER 1 /* vertical period in which the artifacts repeat */
|
||||
|
||||
@@ -62,14 +61,14 @@ extern "C" {
|
||||
* |---------------------------------------------------------------------------|
|
||||
* HBLANK (~10900 ns) ACTIVE VIDEO (~52600 ns)
|
||||
* |-------------------||------------------------------------------------------|
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* WITHIN HBLANK PERIOD:
|
||||
*
|
||||
*
|
||||
* FP (~1500 ns) SYNC (~4700 ns) BW (~600 ns) CB (~2500 ns) BP (~1600 ns)
|
||||
* |--------------||---------------||------------||-------------||-------------|
|
||||
* BLANK SYNC BLANK BLANK BLANK
|
||||
*
|
||||
*
|
||||
*/
|
||||
#define LINE_BEG 0
|
||||
#define FP_ns 1500 /* front porch */
|
||||
@@ -95,33 +94,12 @@ extern "C" {
|
||||
|
||||
/* somewhere between 7 and 12 cycles */
|
||||
#define CB_CYCLES 10
|
||||
|
||||
#define VHS_OFF 0
|
||||
#define VHS_SP 1
|
||||
#define VHS_LP 2
|
||||
#define VHS_EP 3
|
||||
|
||||
#define VHS_MODE VHS_OFF
|
||||
|
||||
/* frequencies for bandlimiting */
|
||||
#define L_FREQ 1431818 /* full line */
|
||||
|
||||
#define Y_FREQ_OFF 420000 /* Luma (Y) 4.2 MHz of the 14.31818 MHz */
|
||||
#define I_FREQ_OFF 150000 /* Chroma (I) 1.5 MHz of the 14.31818 MHz */
|
||||
#define Q_FREQ_OFF 55000 /* Chroma (Q) 0.55 MHz of the 14.31818 MHz */
|
||||
|
||||
#define Y_FREQ_SP 300000 /* Luma (Y) 3.0 MHz of the 14.31818 MHz */
|
||||
#define I_FREQ_SP 62700 /* Chroma (I) 627 kHz of the 14.31818 MHz */
|
||||
#define Q_FREQ_SP 62700 /* Chroma (Q) 627 kHz of the 14.31818 MHz */
|
||||
|
||||
#define Y_FREQ_LP 240000 /* Luma (Y) 2.4 MHz of the 14.31818 MHz */
|
||||
#define I_FREQ_LP 40000 /* Chroma (I) 400 kHz of the 14.31818 MHz */
|
||||
#define Q_FREQ_LP 40000 /* Chroma (Q) 400 kHz of the 14.31818 MHz */
|
||||
|
||||
#define Y_FREQ_EP 200000 /* Luma (Y) 2.0 MHz of the 14.31818 MHz */
|
||||
#define I_FREQ_EP 37000 /* Chroma (I) 370 kHz of the 14.31818 MHz */
|
||||
#define Q_FREQ_EP 37000 /* Chroma (Q) 370 kHz of the 14.31818 MHz */
|
||||
|
||||
/* frequencies for bandlimiting */
|
||||
#define L_FREQ 1431818 /* full line */
|
||||
#define Y_FREQ 420000 /* Luma (Y) 4.2 MHz of the 14.31818 MHz */
|
||||
#define I_FREQ 150000 /* Chroma (I) 1.5 MHz of the 14.31818 MHz */
|
||||
#define Q_FREQ 55000 /* Chroma (Q) 0.55 MHz of the 14.31818 MHz */
|
||||
|
||||
/* IRE units (100 = 1.0V, -40 = 0.0V) */
|
||||
#define WHITE_LEVEL 100
|
||||
@@ -132,6 +110,7 @@ extern "C" {
|
||||
|
||||
struct NTSC_SETTINGS {
|
||||
const unsigned char *data; /* image data */
|
||||
int format; /* pix format (one of the CRT_PIX_FORMATs in crt_core.h) */
|
||||
int w, h; /* width and height of image */
|
||||
int raw; /* 0 = scale image to fit monitor, 1 = don't scale */
|
||||
int as_color; /* 0 = monochrome, 1 = full color */
|
||||
@@ -140,14 +119,6 @@ struct NTSC_SETTINGS {
|
||||
int hue; /* 0-359 */
|
||||
int xoffset; /* x offset in sample space. 0 is minimum value */
|
||||
int yoffset; /* y offset in # of lines. 0 is minimum value */
|
||||
int do_aberration; /* 0 = no aberration, 1 = with aberration */
|
||||
|
||||
// these are changed by the vhs mode
|
||||
int vhs_mode;
|
||||
int y_freq;
|
||||
int i_freq;
|
||||
int q_freq;
|
||||
|
||||
/* make sure your NTSC_SETTINGS struct is zeroed out before you do anything */
|
||||
int iirs_initialized; /* internal state */
|
||||
};
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
#include "crt_core.h"
|
||||
|
||||
// the actual NTSC emulation code is modified from here: https://github.com/LMP88959/NTSC-CRT
|
||||
// the actual NTSC emulation code is from here: https://github.com/LMP88959/NTSC-CRT
|
||||
|
||||
|
||||
typedef struct ntsc_instance
|
||||
{
|
||||
@@ -15,16 +17,15 @@ typedef struct ntsc_instance
|
||||
|
||||
// parameters
|
||||
struct CRT crt;
|
||||
struct NTSC_SETTINGS ntsc_settings;
|
||||
struct NTSC_SETTINGS ntsc;
|
||||
|
||||
int noise;
|
||||
double vhs_speed;
|
||||
|
||||
int field;
|
||||
int progressive;
|
||||
|
||||
} ntsc_instance_t;
|
||||
|
||||
|
||||
// these functions are for frei0r
|
||||
// mostly copy/paste/slightly modified from the other frei0r effects
|
||||
int f0r_init()
|
||||
@@ -44,8 +45,8 @@ void f0r_get_plugin_info(f0r_plugin_info_t* info)
|
||||
info->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
info->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
info->major_version = 0;
|
||||
info->minor_version = 1;
|
||||
info->num_params = 8;
|
||||
info->minor_version = 2;
|
||||
info->num_params = 3;
|
||||
}
|
||||
|
||||
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
@@ -57,51 +58,22 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
info->explanation = "Amount of noise introduced into the NTSC signal.";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
break;
|
||||
|
||||
|
||||
case 1:
|
||||
info->name = "VHS Speed";
|
||||
info->explanation = "Simulates VHS. 0 = off, 1 = SP, 2 = LP, 3 = EP";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
info->name = "VHS Noise";
|
||||
info->explanation = "Toggles VHS noise at the bottom of the screen";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
info->name = "Aberration";
|
||||
info->explanation = "Toggles VHS aberration at the bottom of the screen. Not visible if V-sync is on.";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
info->name = "Force V-sync";
|
||||
info->explanation = "Forces V-sync even when the signal is really noisy.";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
info->name = "Force H-sync";
|
||||
info->explanation = "Forces V-sync even when the signal is really noisy.";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
info->name = "Progressive Scan";
|
||||
info->explanation = "Toggles progressive scan (Interlaced if off).";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
info->name = "Blend";
|
||||
info->explanation = "Blends frames.";
|
||||
case 2:
|
||||
info->name = "Scanlines";
|
||||
info->explanation = "Draw borders between scanlines.";
|
||||
info->type = F0R_PARAM_BOOL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
ntsc_instance_t* inst = (ntsc_instance_t*)calloc(1, sizeof(*inst));
|
||||
@@ -109,36 +81,28 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
|
||||
inst->vhs_speed = 0.0;
|
||||
inst->field = 0;
|
||||
inst->progressive = 1;
|
||||
|
||||
crt_init(&(inst->crt), width, height, NULL);
|
||||
|
||||
// init NTSC_SETTINGS
|
||||
inst->ntsc_settings.data = NULL;
|
||||
inst->ntsc_settings.w = width;
|
||||
inst->ntsc_settings.h = height;
|
||||
inst->ntsc_settings.raw = 0;
|
||||
inst->ntsc_settings.as_color = 1;
|
||||
inst->ntsc_settings.field = 0;
|
||||
inst->ntsc_settings.frame = 0;
|
||||
inst->ntsc_settings.hue = 0;
|
||||
inst->ntsc_settings.xoffset = 0;
|
||||
inst->ntsc_settings.yoffset = 0;
|
||||
inst->ntsc_settings.do_aberration = 0;
|
||||
|
||||
// these are changed by the vhs mode
|
||||
inst->ntsc_settings.vhs_mode = 0;
|
||||
inst->ntsc_settings.y_freq = 0;
|
||||
inst->ntsc_settings.i_freq = 0;
|
||||
inst->ntsc_settings.q_freq = 0;
|
||||
|
||||
/* make sure your NTSC_SETTINGS struct is zeroed out before you do anything */
|
||||
inst->ntsc_settings.iirs_initialized = 0;
|
||||
|
||||
inst->ntsc.format = CRT_PIX_FORMAT_RGBA;
|
||||
inst->ntsc.w = width;
|
||||
inst->ntsc.h = height;
|
||||
inst->ntsc.raw = 0;
|
||||
inst->ntsc.field = 0;
|
||||
inst->ntsc.frame = 0;
|
||||
inst->ntsc.as_color = 1;
|
||||
inst->ntsc.hue = 0;
|
||||
inst->ntsc.xoffset = 0;
|
||||
inst->ntsc.yoffset = 0;
|
||||
inst->ntsc.iirs_initialized = 0;
|
||||
|
||||
inst->noise = 0;
|
||||
inst->progressive = 0;
|
||||
inst->field = 0;
|
||||
|
||||
crt_init(&(inst->crt), width, height, CRT_PIX_FORMAT_RGBA, NULL);
|
||||
inst->crt.blend = 0;
|
||||
inst->crt.scanlines = 0;
|
||||
|
||||
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -155,29 +119,13 @@ void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
inst->noise = *((double*)param) * 100;
|
||||
inst->noise = *((double*)param) * 200;
|
||||
break;
|
||||
case 1:
|
||||
inst->ntsc_settings.vhs_mode = (int)CLAMP(*((double*)param) * 4, 0, 4);
|
||||
inst->ntsc_settings.iirs_initialized = 0;
|
||||
break;
|
||||
case 2:
|
||||
inst->crt.do_vhs_noise = (*((double*)param) >= 0.5);
|
||||
break;
|
||||
case 3:
|
||||
inst->ntsc_settings.do_aberration = (*((double*)param) >= 0.5);
|
||||
break;
|
||||
case 4:
|
||||
inst->crt.crt_do_vsync = !(*((double*)param) >= 0.5);
|
||||
break;
|
||||
case 5:
|
||||
inst->crt.crt_do_hsync = !(*((double*)param) >= 0.5);
|
||||
break;
|
||||
case 6:
|
||||
inst->progressive = (*((double*)param) >= 0.5);
|
||||
break;
|
||||
case 7:
|
||||
inst->crt.blend = (*((double*)param) >= 0.5);
|
||||
case 2:
|
||||
inst->crt.scanlines = (*((double*)param) >= 0.5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -188,50 +136,52 @@ void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
*((double*)param) = (inst->noise / 100);
|
||||
*((double*)param) = (inst->noise / 200);
|
||||
break;
|
||||
case 1:
|
||||
*((double*)param) = (inst->ntsc_settings.vhs_mode / 4);
|
||||
break;
|
||||
case 2:
|
||||
*((double*)param) = (inst->crt.do_vhs_noise ? 1.0 : 0.0);
|
||||
break;
|
||||
case 3:
|
||||
*((double*)param) = (inst->ntsc_settings.do_aberration ? 1.0 : 0.0);
|
||||
break;
|
||||
case 4:
|
||||
*((double*)param) = !(inst->crt.crt_do_vsync ? 1.0 : 0.0);
|
||||
break;
|
||||
case 5:
|
||||
*((double*)param) = !(inst->crt.crt_do_hsync ? 1.0 : 0.0);
|
||||
break;
|
||||
case 6:
|
||||
*((double*)param) = (inst->progressive ? 1.0 : 0.0);
|
||||
break;
|
||||
case 7:
|
||||
*((double*)param) = (inst->crt.blend ? 1.0 : 0.0);
|
||||
case 2:
|
||||
*((double*)param) = (inst->crt.scanlines ? 1.0 : 0.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
{
|
||||
ntsc_instance_t* inst = (ntsc_instance_t*)instance;
|
||||
|
||||
|
||||
// clear the output frame
|
||||
memset(outframe, 0, inst->width * inst->height * sizeof(uint32_t));
|
||||
inst->crt.blend = 0;
|
||||
|
||||
// set everything up for the simulation
|
||||
inst->crt.out = (char*)outframe;
|
||||
inst->ntsc_settings.data = (const char*)inframe;
|
||||
inst->ntsc.data = (const char*)inframe;
|
||||
|
||||
inst->ntsc_settings.field = inst->field & 1;
|
||||
if (inst->ntsc_settings.field == 0) {
|
||||
_render_field:
|
||||
inst->ntsc.field = inst->field & 1;
|
||||
|
||||
if (inst->ntsc.field == 0) {
|
||||
/* a frame is two fields */
|
||||
inst->ntsc_settings.frame ^= 1;
|
||||
inst->ntsc.frame ^= 1;
|
||||
}
|
||||
|
||||
crt_modulate(&(inst->crt), &(inst->ntsc_settings));
|
||||
// encode and decode ntsc signal
|
||||
crt_modulate(&(inst->crt), &(inst->ntsc));
|
||||
crt_demodulate(&(inst->crt), inst->noise);
|
||||
if(!inst->progressive)
|
||||
|
||||
inst->field ^= 1;
|
||||
// if we are in progressive mode, we render both fields onto the frame.
|
||||
// in interlaced mode, we will hit the opposite field on the next frame.
|
||||
if(inst->field && inst->progressive)
|
||||
{
|
||||
inst->field ^= 1;
|
||||
// if we are not leaving scanlines blank, we will want to blend the frames in progressive mode
|
||||
if(!inst->crt.scanlines)
|
||||
{
|
||||
inst->crt.blend = 1;
|
||||
}
|
||||
goto _render_field;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void f0r_get_param_info (f0r_param_info_t *info, int param_index)
|
||||
case 0:
|
||||
info->name = "shift_intensity";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Agressiveness of row/column-shifting";
|
||||
info->explanation = "Aggressiveness of row/column-shifting";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
@@ -122,6 +122,9 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
levelsInput = CLAMP(levelsInput, 0.0, 48.0) + 2.0;
|
||||
int numLevels = (int)levelsInput;
|
||||
|
||||
// Prevent division by zero
|
||||
if (numLevels < 2) numLevels = 2;
|
||||
|
||||
// create levels table
|
||||
unsigned char levels[256];
|
||||
int i;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* It contains code from plug-ins/common/noise-rgb.c, see that for copyrights.
|
||||
*
|
||||
* rgbnoise.c
|
||||
* Copyright 2012 Janne Liljeblad
|
||||
* Copyright 2012 Janne Liljeblad
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
@@ -29,17 +29,17 @@
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
static int MY_MAX_RAND = 32767;// I assume RAND_MAX to be at least this big.
|
||||
static double gaussian_lookup[32767];
|
||||
static int TABLE_INITED = 0;
|
||||
static int next_gaussian_index = 0;
|
||||
static int last_in_range = 32766;
|
||||
#define MY_MAX_RAND 32767 // assume RAND_MAX to be at least this big.
|
||||
|
||||
typedef struct rgbnoise_instance
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double noise;
|
||||
double gaussian_lookup[MY_MAX_RAND];
|
||||
int table_inited;
|
||||
int next_gaussian_index;
|
||||
int last_in_range;
|
||||
} rgbnoise_instance_t;
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ void f0r_get_plugin_info(f0r_plugin_info_t* rgbnoiseInfo)
|
||||
rgbnoiseInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
rgbnoiseInfo->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
rgbnoiseInfo->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
rgbnoiseInfo->major_version = 0;
|
||||
rgbnoiseInfo->minor_version = 9;
|
||||
rgbnoiseInfo->num_params = 1;
|
||||
rgbnoiseInfo->major_version = 0;
|
||||
rgbnoiseInfo->minor_version = 9;
|
||||
rgbnoiseInfo->num_params = 1;
|
||||
rgbnoiseInfo->explanation = "Adds RGB noise to image.";
|
||||
}
|
||||
|
||||
@@ -74,9 +74,12 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
inst->noise = 0.2;
|
||||
inst->table_inited = 0;
|
||||
inst->next_gaussian_index = 0;
|
||||
inst->last_in_range = MY_MAX_RAND;
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -85,7 +88,7 @@ void f0r_destruct(f0r_instance_t instance)
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
@@ -99,9 +102,9 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
|
||||
void f0r_get_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
{
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
switch (param_index)
|
||||
switch (param_index)
|
||||
{
|
||||
case 0:
|
||||
*((double*)param) = inst->noise;
|
||||
@@ -133,7 +136,7 @@ static inline double gauss()
|
||||
return x;
|
||||
}
|
||||
|
||||
static void create_new_lookup_range()
|
||||
static void create_new_lookup_range(rgbnoise_instance_t* inst)
|
||||
{
|
||||
int first, last, tmp;
|
||||
first = rand() % (MY_MAX_RAND - 1);
|
||||
@@ -144,42 +147,33 @@ static void create_new_lookup_range()
|
||||
last = first;
|
||||
first = tmp;
|
||||
}
|
||||
next_gaussian_index = first;
|
||||
last_in_range = last;
|
||||
inst->next_gaussian_index = first;
|
||||
inst->last_in_range = last;
|
||||
}
|
||||
|
||||
static inline double next_gauss()
|
||||
static inline double next_gauss(rgbnoise_instance_t* inst)
|
||||
{
|
||||
next_gaussian_index++;
|
||||
if (next_gaussian_index >= last_in_range)
|
||||
inst->next_gaussian_index++;
|
||||
if (inst->next_gaussian_index >= inst->last_in_range)
|
||||
{
|
||||
create_new_lookup_range();
|
||||
create_new_lookup_range(inst);
|
||||
}
|
||||
return gaussian_lookup[next_gaussian_index];
|
||||
return inst->gaussian_lookup[inst->next_gaussian_index];
|
||||
}
|
||||
|
||||
static inline int addNoise(int sample, double noise)
|
||||
static inline int addNoise(rgbnoise_instance_t* inst, int sample, double noise)
|
||||
{
|
||||
int byteNoise = 0;
|
||||
int noiseSample = 0;
|
||||
|
||||
byteNoise = (int) (noise * next_gauss());
|
||||
byteNoise = (int) (noise * next_gauss(inst));
|
||||
noiseSample = sample + byteNoise;
|
||||
noiseSample = CLAMP(noiseSample, 0, 255);
|
||||
return noiseSample;
|
||||
}
|
||||
}
|
||||
|
||||
int f0r_init()
|
||||
{
|
||||
if (TABLE_INITED == 0)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MY_MAX_RAND; i++)
|
||||
{
|
||||
gaussian_lookup[i] = gauss() * 127.0;
|
||||
}
|
||||
TABLE_INITED = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -189,6 +183,19 @@ void rgb_noise(f0r_instance_t instance, double time,
|
||||
rgbnoise_instance_t* inst = (rgbnoise_instance_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
|
||||
// Initialize the gaussian lookup table if not already done
|
||||
if (inst->table_inited == 0)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MY_MAX_RAND; i++)
|
||||
{
|
||||
inst->gaussian_lookup[i] = gauss() * 127.0;
|
||||
}
|
||||
inst->table_inited = 1;
|
||||
inst->next_gaussian_index = 0;
|
||||
inst->last_in_range = MY_MAX_RAND;
|
||||
}
|
||||
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
const unsigned char* src = (unsigned char*)inframe;
|
||||
|
||||
@@ -197,11 +204,11 @@ void rgb_noise(f0r_instance_t instance, double time,
|
||||
while (len--)
|
||||
{
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
sample = *src++;
|
||||
*dst++ = addNoise(sample, noise);
|
||||
*dst++ = addNoise(inst, sample, noise);
|
||||
*dst++ = *src++;
|
||||
}
|
||||
}
|
||||
@@ -213,4 +220,3 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
assert(instance);
|
||||
rgb_noise(instance, time, inframe, outframe);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* rgbsplit0r.c
|
||||
* Copyright (C) 2016 IDENT Software ~ http://identsoft.org
|
||||
* Inspired by the witch house and web culture
|
||||
*
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -111,7 +111,6 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
inst->width = width; inst->height = height;
|
||||
inst->shiftY = 0;
|
||||
inst->shiftX = 0;
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -120,7 +119,7 @@ void f0r_destruct(f0r_instance_t instance)
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
assert(instance);
|
||||
@@ -135,7 +134,10 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
double shiftY = *((double*)param) - 0.5;
|
||||
|
||||
// Convert to range from 0 to one eighth of height
|
||||
shiftY = ((inst->height / 8) * shiftY);
|
||||
if (inst->height > 0)
|
||||
shiftY = ((inst->height / 8) * shiftY);
|
||||
else
|
||||
shiftY = 0;
|
||||
|
||||
inst->shiftY = (unsigned int)shiftY;
|
||||
break;
|
||||
@@ -145,9 +147,12 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
{
|
||||
// scale to [-1/16..1/16]
|
||||
double shiftX = *((double*)param) - 0.5;
|
||||
|
||||
|
||||
// Convert to range from 0 to one eighth of width
|
||||
shiftX = ((inst->width / 8) * shiftX);
|
||||
if (inst->width > 0)
|
||||
shiftX = ((inst->width / 8) * shiftX);
|
||||
else
|
||||
shiftX = 0;
|
||||
|
||||
inst->shiftX = (unsigned int)shiftX;
|
||||
break;
|
||||
@@ -167,14 +172,20 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
case 0 : // vertical shift
|
||||
{
|
||||
// convert plugin's param to frei0r range
|
||||
*((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
|
||||
if (inst->height > 0)
|
||||
*((double*)param) = (inst->shiftY) / (inst->height / 8) + 0.5;
|
||||
else
|
||||
*((double*)param) = 0.5;
|
||||
break;
|
||||
}
|
||||
|
||||
case 1 : // horizontal shift
|
||||
{
|
||||
// convert plugin's param to frei0r range
|
||||
*((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
|
||||
if (inst->width > 0)
|
||||
*((double*)param) = (inst->shiftX) / (inst->width / 8) + 0.5;
|
||||
else
|
||||
*((double*)param) = 0.5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -195,8 +206,8 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
uint32_t pxR = 0, pxG = 0, pxB = 0;
|
||||
|
||||
// First make a blue layer shifted back
|
||||
if (((x - inst->shiftX) < inst->width) &&
|
||||
((y - inst->shiftY) < inst->height))
|
||||
if (((int)x >= (int)inst->shiftX) &&
|
||||
((int)y >= (int)inst->shiftY))
|
||||
{
|
||||
rgbsplit0r_extract_color((uint32_t *)(src +
|
||||
(x - inst->shiftX) +
|
||||
@@ -221,4 +232,3 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
*(dst + x + (y*inst->width)) = (pxG | pxB | pxR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ color subspace.
|
||||
Invert selection:
|
||||
When ON, the selected color will be transparent, as normally used
|
||||
with keying. When OFF (default) the selected color will be opaque,
|
||||
for exmaple for alpha controlled adjustment of that color only.
|
||||
for example for alpha controlled adjustment of that color only.
|
||||
|
||||
Delta XXXX:
|
||||
These three parameters determine the size of the color subspace
|
||||
|
||||
15
src/filter/shakeoscillate/CMakeLists.txt
Executable file
15
src/filter/shakeoscillate/CMakeLists.txt
Executable file
@@ -0,0 +1,15 @@
|
||||
set (SOURCES shakeoscillate.cpp)
|
||||
set (TARGET shakeoscillate)
|
||||
|
||||
include_directories(${Cairo_INCLUDE_DIR})
|
||||
set(LIBS ${LIBS} ${Cairo_LIBRARY})
|
||||
|
||||
if (MSVC)
|
||||
set (SOURCES ${SOURCES} ${FREI0R_DEF})
|
||||
endif (MSVC)
|
||||
|
||||
add_library (${TARGET} MODULE ${SOURCES})
|
||||
|
||||
set_target_properties (${TARGET} PROPERTIES PREFIX "")
|
||||
target_link_libraries(shakeoscillate ${LIBS})
|
||||
install (TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
|
||||
195
src/filter/shakeoscillate/shakeoscillate.cpp
Executable file
195
src/filter/shakeoscillate/shakeoscillate.cpp
Executable file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Johann JEG (johannjeg1057@gmail.com)
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "frei0r.hpp"
|
||||
#include <cairo.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
class ShakeOscillate : public frei0r::filter {
|
||||
|
||||
private:
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double movement_amount_x;
|
||||
double movement_speed_x;
|
||||
double movement_amount_y;
|
||||
double movement_speed_y;
|
||||
double rotation_amount;
|
||||
double rotation_speed;
|
||||
double scale;
|
||||
double phase;
|
||||
bool mirrored;
|
||||
|
||||
const float MOVEMENT_AMOUNT_MULTIPLIER = 0.3f;
|
||||
const float ROTATION_AMOUNT_MULTIPLIER = 0.2f;
|
||||
const float SPEED_MULTIPLIER = 10.0f;
|
||||
|
||||
public:
|
||||
|
||||
ShakeOscillate(unsigned int width, unsigned int height) {
|
||||
register_param(this->movement_amount_x, "movement_amount_x", "Amount of the X movement.");
|
||||
register_param(this->movement_speed_x, "movement_speed_x", "X Movement Speed.");
|
||||
register_param(this->movement_amount_y, "movement_amount_y", "Amount of the Y movement.");
|
||||
register_param(this->movement_speed_y, "movement_speed_y", "Y Movement Speed.");
|
||||
register_param(this->rotation_amount, "rotation_amount", "Rotation amount.");
|
||||
register_param(this->rotation_speed, "rotation_speed", "Rotation Speed.");
|
||||
register_param(this->scale, "scale", "Scale level.");
|
||||
register_param(this->phase, "phase", "The phase of the sin and cos functions of this effect.");
|
||||
register_param(this->mirrored, "mirrored", "On/Off Image Mirror Extend");
|
||||
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->movement_amount_x = 0.5; // Movement amount off is 0.5
|
||||
this->movement_speed_x = 0.2;
|
||||
this->movement_amount_y = 0.5; // Movement amount off is 0.5
|
||||
this->movement_speed_y = 0.1;
|
||||
this->rotation_amount = 0.5; // Rotation amount off is 0.5
|
||||
this->rotation_speed = 0.2;
|
||||
this->scale = 0.5; // Original image size is 0.5
|
||||
this->phase = 0.0;
|
||||
this->mirrored = true;
|
||||
}
|
||||
|
||||
~ShakeOscillate() {
|
||||
|
||||
}
|
||||
|
||||
void clearScreen(cairo_t* cr, int width, int height) {
|
||||
cairo_save (cr);
|
||||
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
void oscillate(cairo_matrix_t* matrix, double time) {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
|
||||
// Operations for the translation amount do not depend on the screen size
|
||||
float movement_range_x = MOVEMENT_AMOUNT_MULTIPLIER * this->height;
|
||||
float movement_range_y = MOVEMENT_AMOUNT_MULTIPLIER * this->width;
|
||||
|
||||
// Translate X
|
||||
if(this->movement_amount_x != 0.5){
|
||||
float movement_x = (this->movement_amount_x - 0.5f) * 2.0f;
|
||||
float movement_speed_value_x = this->movement_speed_x * SPEED_MULTIPLIER * time;
|
||||
x = movement_x * movement_range_x * std::sin(movement_speed_value_x + this->phase);
|
||||
}
|
||||
|
||||
// Translate Y
|
||||
if(this->movement_amount_y != 0.5){
|
||||
float movement_y = (this->movement_amount_y - 0.5f) * 2.0f;
|
||||
float movement_speed_value_y = this->movement_speed_y * SPEED_MULTIPLIER * time;
|
||||
y = movement_y * movement_range_y * std::cos(movement_speed_value_y + this->phase);
|
||||
}
|
||||
|
||||
// Translate by adding the half screen coordinates to scale and rotate from center
|
||||
float center_x = this->width / 2.0f;
|
||||
float center_y = this->height / 2.0f;
|
||||
cairo_matrix_translate(matrix, center_x + x, center_y + y);
|
||||
|
||||
// Scale
|
||||
if(this->scale != 0.5){
|
||||
float scale_factor = 1.5f - this->scale;
|
||||
cairo_matrix_scale(matrix, scale_factor, scale_factor);
|
||||
}
|
||||
|
||||
// Rotation
|
||||
if(this->rotation_amount != 0.5){
|
||||
float rotation_speed_value = (this->rotation_speed * SPEED_MULTIPLIER * time) + this->phase;
|
||||
float rotation = ((this->rotation_amount - 0.5f) * ROTATION_AMOUNT_MULTIPLIER) * std::sin(rotation_speed_value) * M_PI;
|
||||
cairo_matrix_rotate(matrix, rotation);
|
||||
}
|
||||
|
||||
// Restore translate coordinates
|
||||
cairo_matrix_translate(matrix, -center_x, -center_y);
|
||||
}
|
||||
|
||||
virtual void update(double time, uint32_t* out, const uint32_t* in) {
|
||||
int w = this->width;
|
||||
int h = this->height;
|
||||
|
||||
// Calculate the stride for the image surface based on width and format
|
||||
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w);
|
||||
|
||||
// Create a Cairo surface for the destination image
|
||||
cairo_surface_t* dest_image = cairo_image_surface_create_for_data((unsigned char*)out,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
|
||||
// Create a Cairo drawing context for the destination surface
|
||||
cairo_t *cr = cairo_create(dest_image);
|
||||
|
||||
// Clear the screen
|
||||
clearScreen(cr, w, h);
|
||||
|
||||
// Create a Cairo surface for the source image
|
||||
cairo_surface_t *image = cairo_image_surface_create_for_data((unsigned char*)in,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
|
||||
// Create a pattern from the source image surface
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
|
||||
|
||||
if(this->mirrored){
|
||||
// Set the pattern extend mode to reflect (mirror) when the pattern is out of bounds
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
|
||||
} else {
|
||||
// Set the pattern extend mode to none (mirroring does not apply)
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
|
||||
}
|
||||
|
||||
// Initialize the transformation matrix
|
||||
cairo_matrix_t matrix;
|
||||
cairo_matrix_init_identity(&matrix);
|
||||
|
||||
// Call the function that applies the movement
|
||||
oscillate(&matrix, time);
|
||||
|
||||
// Set the transformation matrix for the pattern
|
||||
cairo_pattern_set_matrix(pattern, &matrix);
|
||||
// Set the source pattern to be used for drawing
|
||||
cairo_set_source(cr, pattern);
|
||||
|
||||
// Draw a rectangle covering the entire image area
|
||||
cairo_rectangle(cr, 0, 0, w, h);
|
||||
// Fill the rectangle with the source pattern
|
||||
cairo_fill(cr);
|
||||
|
||||
// Clean up resources
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_surface_destroy (image);
|
||||
cairo_surface_destroy (dest_image);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
};
|
||||
|
||||
frei0r::construct<ShakeOscillate> plugin(
|
||||
"ShakeOscillate",
|
||||
"Animate the input image with adjustable parameters such as amount, speed, rotation, scale and option to mirror the image if it goes outside the screen bounds.",
|
||||
"Johann JEG",
|
||||
1, 0,
|
||||
F0R_COLOR_MODEL_RGBA8888);
|
||||
@@ -1,8 +1,10 @@
|
||||
/*
|
||||
* This file is contains sigmoidal transfer function from file plug-ins/common/softglow.c in gimp.
|
||||
* This file used to contain sigmoidal transfer function from file plug-ins/common/softglow.c in gimp.
|
||||
* However, it is now modified to match ImageMagick; i.e. whereas only the steepness of the sigmoidal
|
||||
* curves was tunable earlier, now the midpoint of the curve is adjustable as well -- both to a degree.
|
||||
*
|
||||
* sigmoidaltransfer.c
|
||||
* Copyright 2012 Janne Liljeblad
|
||||
* Copyright 2012 Janne Liljeblad, 2025 Cynthia
|
||||
*
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
@@ -28,35 +30,25 @@
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
|
||||
#define SIGMOIDAL_BASE 2
|
||||
#define SIGMOIDAL_RANGE 20
|
||||
|
||||
typedef struct sigmoidal_instance
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double brightness;
|
||||
double base;
|
||||
double sharpness;
|
||||
|
||||
/* Precomputed values of the (scaled and shifted) sigmoid function
|
||||
is stored in this lookup table. */
|
||||
uint8_t lut[256];
|
||||
} sigmoidal_instance_t;
|
||||
|
||||
static inline int gimp_rgb_to_l_int (int red,
|
||||
int green,
|
||||
int blue)
|
||||
void gen_sigmoid_lut (uint8_t *const lut, const float base, const float sharpness)
|
||||
{
|
||||
int min, max;
|
||||
float k = expf(sharpness * 5.0) / 255.0;
|
||||
float b = (base - 0.5) * 63.0;
|
||||
|
||||
if (red > green)
|
||||
{
|
||||
max = MAX (red, blue);
|
||||
min = MIN (green, blue);
|
||||
}
|
||||
else
|
||||
{
|
||||
max = MAX (green, blue);
|
||||
min = MIN (red, blue);
|
||||
}
|
||||
|
||||
return ROUND ((max + min) / 2.0);
|
||||
for (int i = 0; i < 256; ++i)
|
||||
lut[i] = CLAMP (255.0 / (1.0 + expf(-k * (i - b - 127.0))), 0, 255.0);
|
||||
}
|
||||
|
||||
void sigmoidal_transfer(f0r_instance_t instance, double time,
|
||||
@@ -66,9 +58,6 @@ void sigmoidal_transfer(f0r_instance_t instance, double time,
|
||||
sigmoidal_instance_t* inst = (sigmoidal_instance_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
|
||||
double brightness = inst->brightness;
|
||||
double sharpness = inst->sharpness;
|
||||
|
||||
const unsigned char* src = (unsigned char*)inframe;
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
|
||||
@@ -81,13 +70,9 @@ void sigmoidal_transfer(f0r_instance_t instance, double time,
|
||||
b = *src++;
|
||||
|
||||
//desaturate
|
||||
luma = (unsigned char) gimp_rgb_to_l_int (r, g, b);
|
||||
|
||||
luma = (unsigned char)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
//compute sigmoidal transfer
|
||||
val = luma / 255.0;
|
||||
val = 255.0 / (1 + exp (-(SIGMOIDAL_BASE + (sharpness * SIGMOIDAL_RANGE)) * (val - 0.5)));
|
||||
val = val * brightness;
|
||||
luma = (unsigned char) CLAMP (val, 0, 255);
|
||||
luma = inst->lut[luma];
|
||||
|
||||
*dst++ = luma;
|
||||
*dst++ = luma;
|
||||
@@ -108,12 +93,12 @@ void f0r_deinit()
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* sigmoidalInfo)
|
||||
{
|
||||
sigmoidalInfo->name = "sigmoidaltransfer";
|
||||
sigmoidalInfo->author = "Janne Liljeblad";
|
||||
sigmoidalInfo->author = "Janne Liljeblad & Cynthia";
|
||||
sigmoidalInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
sigmoidalInfo->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
sigmoidalInfo->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
sigmoidalInfo->major_version = 0;
|
||||
sigmoidalInfo->minor_version = 9;
|
||||
sigmoidalInfo->major_version = 1;
|
||||
sigmoidalInfo->minor_version = 0;
|
||||
sigmoidalInfo->num_params = 2;
|
||||
sigmoidalInfo->explanation = "Desaturates image and creates a particular look that could be called Stamp, Newspaper or Photocopy";
|
||||
}
|
||||
@@ -122,15 +107,15 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
{
|
||||
switch ( param_index ) {
|
||||
case 0:
|
||||
info->name = "brightness";
|
||||
info->name = "base";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Brightnesss of image";
|
||||
info->explanation = "Brightness of image. Midpoint of sigmoidal curve";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "sharpness";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Sharpness of transfer";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "sharpness";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Sharpness of transfer";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +124,10 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
sigmoidal_instance_t* inst = (sigmoidal_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
inst->brightness = 0.75;
|
||||
inst->sharpness = 0.85;
|
||||
inst->base = 0.5;
|
||||
inst->sharpness = 3.0 / 5.0;
|
||||
|
||||
gen_sigmoid_lut (inst->lut, inst->base, inst->sharpness);
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
@@ -156,12 +143,14 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
switch (param_index)
|
||||
{
|
||||
case 0:
|
||||
inst->brightness = *((double*)param);
|
||||
inst->base = *((double*)param);
|
||||
break;
|
||||
case 1:
|
||||
inst->sharpness = *((double*)param);
|
||||
break;
|
||||
}
|
||||
|
||||
gen_sigmoid_lut (inst->lut, inst->base, inst->sharpness);
|
||||
}
|
||||
|
||||
void f0r_get_param_value(f0r_instance_t instance,
|
||||
@@ -171,7 +160,7 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
switch (param_index)
|
||||
{
|
||||
case 0:
|
||||
*((double*)param) = inst->brightness;
|
||||
*((double*)param) = inst->base;
|
||||
break;
|
||||
case 1:
|
||||
*((double*)param) = inst->sharpness;
|
||||
|
||||
@@ -26,12 +26,16 @@ class sobel : public frei0r::filter
|
||||
public:
|
||||
sobel(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
}
|
||||
|
||||
virtual void update(double time,
|
||||
uint32_t* out,
|
||||
const uint32_t* in)
|
||||
{
|
||||
if (width == 0 || height == 0) return;
|
||||
|
||||
std::copy(in, in + width*height, out);
|
||||
for (unsigned int y=1; y<height-1; ++y)
|
||||
{
|
||||
@@ -46,9 +50,9 @@ public:
|
||||
unsigned char *p7 = (unsigned char *)&in[(y+1)*width+(x-1)];
|
||||
unsigned char *p8 = (unsigned char *)&in[(y+1)*width+x];
|
||||
unsigned char *p9 = (unsigned char *)&in[(y+1)*width+(x+1)];
|
||||
|
||||
|
||||
unsigned char *g = (unsigned char *)&out[y*width+x];
|
||||
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
g[i] = CLAMP0255(
|
||||
abs(p1[i] + p2[i]*2 + p3[i] - p7[i] - p8[i]*2 - p9[i]) +
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
uint32_t* out,
|
||||
const uint32_t* in)
|
||||
{
|
||||
// Rebuild the lookup table in case the prarameters have changed.
|
||||
// Rebuild the lookup table in case the parameters have changed.
|
||||
updateLUT();
|
||||
|
||||
unsigned char *pixel = (unsigned char *) in;
|
||||
|
||||
@@ -91,9 +91,9 @@ typedef struct spillsupress_instance
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
double supress_type; /* type of spill supression applied to image
|
||||
<= 0.5, green supress
|
||||
> 0.5, blue supress */
|
||||
double supress_type; /* type of spill suppression applied to image
|
||||
<= 0.5, green suppress
|
||||
> 0.5, blue suppress */
|
||||
} spillsupress_instance_t;
|
||||
|
||||
int f0r_init()
|
||||
@@ -134,7 +134,7 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
spillsupress_instance_t* inst = (spillsupress_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
inst->supress_type = 0.0; // default supress type is green supress
|
||||
inst->supress_type = 0.0; // default suppress type is green suppress
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
|
||||
double* gaussSLESolve(size_t size, double* A) {
|
||||
int extSize = size + 1;
|
||||
//direct way: tranform matrix A to triangular form
|
||||
//direct way: transform matrix A to triangular form
|
||||
for(int row = 0; row < size; row++) {
|
||||
int col = row;
|
||||
int lastRowToSwap = size - 1;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* tint0r.c
|
||||
* Copyright (C) 2009 Maksim Golovkin (m4ks1k@gmail.com)
|
||||
* Copyright (C) 2009 Maksim Golovkin (m4ks1k@gmail.com),
|
||||
* 2025 Cynthia (cynthia2048@proton.me)
|
||||
* This file is a Frei0r plugin.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -17,11 +18,35 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "frei0r.h"
|
||||
#include "frei0r/math.h"
|
||||
/* Check for SSE4.1 support */
|
||||
#if defined(__SSE4_1__)
|
||||
#include <smmintrin.h>
|
||||
#define USE_SSE4_1 1
|
||||
#else
|
||||
#define USE_SSE4_1 0
|
||||
#endif
|
||||
|
||||
/* Check for other SIMD instruction sets */
|
||||
#if defined(__AVX__) && defined(__AVX2__)
|
||||
#include <immintrin.h>
|
||||
#define USE_AVX2 1
|
||||
#else
|
||||
#define USE_AVX2 0
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
|
||||
#include <arm_neon.h>
|
||||
#define USE_NEON 1
|
||||
#else
|
||||
#define USE_NEON 0
|
||||
#endif
|
||||
|
||||
#include <frei0r.h>
|
||||
#include <frei0r/math.h>
|
||||
|
||||
typedef struct tint0r_instance
|
||||
{
|
||||
@@ -40,38 +65,38 @@ int f0r_init()
|
||||
void f0r_deinit()
|
||||
{ /* no initialization required */ }
|
||||
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* tint0r_instance_t)
|
||||
void f0r_get_plugin_info(f0r_plugin_info_t* info)
|
||||
{
|
||||
tint0r_instance_t->name = "Tint0r";
|
||||
tint0r_instance_t->author = "Maksim Golovkin";
|
||||
tint0r_instance_t->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
tint0r_instance_t->color_model = F0R_COLOR_MODEL_RGBA8888;
|
||||
tint0r_instance_t->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
tint0r_instance_t->major_version = 0;
|
||||
tint0r_instance_t->minor_version = 1;
|
||||
tint0r_instance_t->num_params = 3;
|
||||
tint0r_instance_t->explanation = "Tint a source image with specified color";
|
||||
info->name = "Tint0r";
|
||||
info->author = "Maksim Golovkin & Cynthia";
|
||||
info->plugin_type = F0R_PLUGIN_TYPE_FILTER;
|
||||
info->color_model = F0R_COLOR_MODEL_BGRA8888;
|
||||
info->frei0r_version = FREI0R_MAJOR_VERSION;
|
||||
info->major_version = 0;
|
||||
info->minor_version = 1;
|
||||
info->num_params = 3;
|
||||
info->explanation = "Tint a source image with specified colors";
|
||||
}
|
||||
|
||||
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
{
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
info->name = "Map black to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with null luminance";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "Map white to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with full luminance";
|
||||
break;
|
||||
case 2:
|
||||
info->name = "Tint amount";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Amount of color";
|
||||
break;
|
||||
case 0:
|
||||
info->name = "Map black to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with null luminance";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "Map white to";
|
||||
info->type = F0R_PARAM_COLOR;
|
||||
info->explanation = "The color to map source color with full luminance";
|
||||
break;
|
||||
case 2:
|
||||
info->name = "Tint amount";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Amount of color";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +104,10 @@ f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
tint0r_instance_t* inst = (tint0r_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width; inst->height = height;
|
||||
inst->amount = .25;
|
||||
inst->whiteColor.r = .5;
|
||||
inst->amount = 0.25;
|
||||
inst->whiteColor.r = 0.5;
|
||||
inst->whiteColor.g = 1.0;
|
||||
inst->whiteColor.b = .5;
|
||||
inst->whiteColor.b = 0.5;
|
||||
inst->blackColor.r = 0.0;
|
||||
inst->blackColor.g = 0.0;
|
||||
inst->blackColor.b = 0.0;
|
||||
@@ -94,7 +119,7 @@ void f0r_destruct(f0r_instance_t instance)
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
void f0r_set_param_value(f0r_instance_t instance,
|
||||
f0r_param_t param, int param_index)
|
||||
{
|
||||
assert(instance);
|
||||
@@ -102,18 +127,18 @@ void f0r_set_param_value(f0r_instance_t instance,
|
||||
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
/* black color */
|
||||
inst->blackColor = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 1:
|
||||
/* white color */
|
||||
inst->whiteColor = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 2:
|
||||
/* amount */
|
||||
inst->amount = *((double *)param);
|
||||
break;
|
||||
case 0:
|
||||
/* black color */
|
||||
inst->blackColor = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 1:
|
||||
/* white color */
|
||||
inst->whiteColor = *((f0r_param_color_t *)param);
|
||||
break;
|
||||
case 2:
|
||||
/* amount */
|
||||
inst->amount = *((double *)param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,53 +147,146 @@ void f0r_get_param_value(f0r_instance_t instance,
|
||||
{
|
||||
assert(instance);
|
||||
tint0r_instance_t* inst = (tint0r_instance_t*)instance;
|
||||
|
||||
|
||||
switch(param_index)
|
||||
{
|
||||
case 0:
|
||||
*((f0r_param_color_t*)param) = inst->blackColor;
|
||||
break;
|
||||
case 1:
|
||||
*((f0r_param_color_t*)param) = inst->whiteColor;
|
||||
break;
|
||||
case 2:
|
||||
*((double *)param) = inst->amount;
|
||||
break;
|
||||
case 0:
|
||||
*((f0r_param_color_t*)param) = inst->blackColor;
|
||||
break;
|
||||
case 1:
|
||||
*((f0r_param_color_t*)param) = inst->whiteColor;
|
||||
break;
|
||||
case 2:
|
||||
*((double *)param) = inst->amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char map_color(double amount, double comp_amount, float color, float luma, float minColor, float maxColor) {
|
||||
static inline unsigned char map_color(double amount, double comp_amount, float color, float luma, float minColor, float maxColor)
|
||||
{
|
||||
double val = (comp_amount * color) + amount * (luma * (maxColor - minColor) + minColor);
|
||||
return (unsigned char)(255*CLAMP(val, 0, 1));
|
||||
}
|
||||
|
||||
#if USE_SSE4_1
|
||||
static void tint_sse41(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
const __m128 weights = _mm_set_ps(0.0, 0.114, 0.587, 0.299),
|
||||
sse_amount = _mm_set1_ps(amount),
|
||||
/* Pass the alpha channel */
|
||||
comp_amount = _mm_set_ps(1.0,
|
||||
1.0 - amount,
|
||||
1.0 - amount,
|
||||
1.0 - amount);
|
||||
|
||||
/* Zero the alpha component to exclude it from calculations. */
|
||||
const __m128 cmin = _mm_set_ps(0.0, blackColor.b, blackColor.g, blackColor.r),
|
||||
cdelta = _mm_sub_ps(_mm_set_ps(0.0, whiteColor.b, whiteColor.g, whiteColor.r), cmin),
|
||||
tmp0 = _mm_mul_ps(cdelta, sse_amount),
|
||||
tmp1 = _mm_mul_ps(_mm_mul_ps(sse_amount, _mm_set1_ps(255.0)), cmin);
|
||||
|
||||
__m128 p, p0, p1, p2, p3, luma;
|
||||
|
||||
// Process pixels in groups of 4
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
/* Load four pixels at once. */
|
||||
p = _mm_loadu_si128((__m128i*)(inframe + i * 4));
|
||||
|
||||
/* Extract four pixels into separate XMM registers and convert them to float. */
|
||||
p0 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(p));
|
||||
p1 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 4)));
|
||||
p2 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 8)));
|
||||
p3 = _mm_cvtepi32_ps(_mm_cvtepu8_epi32(_mm_srli_si128(p, 12)));
|
||||
|
||||
#define tint(v) \
|
||||
luma = _mm_dp_ps((v), weights, 0x7F); \
|
||||
v = _mm_add_ps(_mm_mul_ps(comp_amount, (v)), \
|
||||
_mm_add_ps(_mm_mul_ps(luma, tmp0), tmp1)); \
|
||||
v = _mm_cvtps_epi32(v)
|
||||
|
||||
tint(p0); tint(p1); tint(p2); tint(p3);
|
||||
|
||||
/* Gather the processed pixels */
|
||||
p = _mm_packus_epi16(_mm_packus_epi32(p0, p1),
|
||||
_mm_packus_epi32(p2, p3));
|
||||
|
||||
_mm_storeu_si128((__m128i*)(outframe + i * 4), p);
|
||||
}
|
||||
}
|
||||
#elif USE_AVX2
|
||||
static void tint_avx2(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
// AVX2 implementation would go here
|
||||
// For now, fall back to scalar implementation
|
||||
// This is a placeholder for a future AVX2 implementation
|
||||
}
|
||||
#elif USE_NEON
|
||||
static void tint_neon(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
// NEON implementation would go here
|
||||
// For now, fall back to scalar implementation
|
||||
// This is a placeholder for a future NEON implementation
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tint_scalar(const uint32_t* inframe, uint32_t* outframe, size_t len,
|
||||
double amount, f0r_param_color_t blackColor, f0r_param_color_t whiteColor)
|
||||
{
|
||||
double comp_amount = 1.0 - amount;
|
||||
|
||||
const unsigned char* src = (const unsigned char*)inframe;
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
|
||||
float b, g, r;
|
||||
float luma;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
b = src[0] / 255.0f;
|
||||
g = src[1] / 255.0f;
|
||||
r = src[2] / 255.0f;
|
||||
|
||||
luma = (b * 0.114f + g * 0.587f + r * 0.299f);
|
||||
|
||||
dst[0] = map_color(amount, comp_amount, b, luma, blackColor.b, whiteColor.b);
|
||||
dst[1] = map_color(amount, comp_amount, g, luma, blackColor.g, whiteColor.g);
|
||||
dst[2] = map_color(amount, comp_amount, r, luma, blackColor.r, whiteColor.r);
|
||||
dst[3] = src[3]; // Copy alpha
|
||||
|
||||
src += 4;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
const uint32_t* inframe, uint32_t* outframe)
|
||||
{
|
||||
assert(instance);
|
||||
tint0r_instance_t* inst = (tint0r_instance_t*)instance;
|
||||
unsigned int len = inst->width * inst->height;
|
||||
double amount = inst->amount;
|
||||
double comp_amount = 1.0 - inst->amount;
|
||||
|
||||
unsigned char* dst = (unsigned char*)outframe;
|
||||
const unsigned char* src = (unsigned char*)inframe;
|
||||
float b, g, r;
|
||||
float luma;
|
||||
size_t len = inst->width * inst->height;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
r = *src++ / 255.;
|
||||
g = *src++ / 255.;
|
||||
b = *src++ / 255.;
|
||||
|
||||
luma = (b * .114 + g * .587 + r * .299);
|
||||
|
||||
*dst++ = map_color(amount, comp_amount, r, luma, inst->blackColor.r, inst->whiteColor.r);
|
||||
*dst++ = map_color(amount, comp_amount, g, luma, inst->blackColor.g, inst->whiteColor.g);
|
||||
*dst++ = map_color(amount, comp_amount, b, luma, inst->blackColor.b, inst->whiteColor.b);
|
||||
#if USE_SSE4_1
|
||||
// Process in chunks of 4 pixels for SSE
|
||||
size_t sse_len = len / 4;
|
||||
size_t remainder = len % 4;
|
||||
|
||||
*dst++ = *src++; // copy alpha
|
||||
if (sse_len > 0) {
|
||||
tint_sse41(inframe, outframe, sse_len, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
}
|
||||
|
||||
// Handle remaining pixels with scalar implementation
|
||||
if (remainder > 0) {
|
||||
const uint32_t* remaining_in = inframe + (sse_len * 4);
|
||||
uint32_t* remaining_out = outframe + (sse_len * 4);
|
||||
tint_scalar(remaining_in, remaining_out, remainder, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
}
|
||||
#else
|
||||
// Use scalar implementation for all pixels
|
||||
tint_scalar(inframe, outframe, len, inst->amount, inst->blackColor, inst->whiteColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
const uint32_t* in)
|
||||
{
|
||||
// Just copy input to output.
|
||||
// This is useful if ony few changes are made to the output.
|
||||
// This is useful if only few changes are made to the output.
|
||||
// If the whole image is processed, this makes no sense!
|
||||
std::copy(in, in + width*height, out);
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
|
||||
// This parameter allows one to do simple benchmarking: Rendering a
|
||||
// video with uint8_t pointers and with uint32_t pointers.
|
||||
// (Don't forget to substract the rendering time without this effect applied to avoid counting
|
||||
// (Don't forget to subtract the rendering time without this effect applied to avoid counting
|
||||
// encoding and decoding as well!)
|
||||
if (m_pointerMethod == 0) {
|
||||
uint8_t *in_pointer = (uint8_t *) in;
|
||||
|
||||
@@ -142,7 +142,7 @@ private:
|
||||
for (int y = 0; y < m_height; y++) {
|
||||
for (int x = 0; x < m_width; x++) {
|
||||
|
||||
// Euclidian distance to the center, normalized to [0,1]
|
||||
// Euclidean distance to the center, normalized to [0,1]
|
||||
r = std::sqrt(std::pow(scaleX*(x-cx), 2) + std::pow(scaleY*(y-cy), 2))/rmax;
|
||||
|
||||
// Subtract the clear center
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Water filter
|
||||
*
|
||||
* (c) Copyright 2000-2007 Denis Rojo <jaromil@dyne.org>
|
||||
*
|
||||
* (c) Copyright 2000-2025 Denis Roio <jaromil@dyne.org>
|
||||
*
|
||||
* from an original idea of water algorithm by Federico 'Pix' Feroldi
|
||||
*
|
||||
* this code contains optimizations by Jason Hood and Scott Scriven
|
||||
@@ -10,7 +10,7 @@
|
||||
* ported to C++ and frei0r plugin API in 2007
|
||||
*
|
||||
* This source code is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Public License as published
|
||||
* modify it under the terms of the GNU Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
@@ -23,8 +23,6 @@
|
||||
* this source code; if not, write to:
|
||||
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* "$Id: water.c 193 2004-06-01 11:00:25Z jaromil $"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -81,8 +79,9 @@ public:
|
||||
surfer = 0;
|
||||
distort = 0;
|
||||
smooth = 0;
|
||||
position.x = 0;
|
||||
position.y = 0;
|
||||
position.x = 0.0;
|
||||
position.y = 0.0;
|
||||
//randomize_swirl = false;
|
||||
register_param(physics, "physics", "water density: from 0.0 to 1.0");
|
||||
register_param(swirl, "swirl", "swirling whirpool in the center");
|
||||
register_param(rain, "rain", "rain drops all over");
|
||||
@@ -120,11 +119,11 @@ public:
|
||||
|
||||
water_surfacesize = geo->size;
|
||||
calc_optimization = (height)*(width);
|
||||
|
||||
|
||||
xang = fastrand()%2048;
|
||||
yang = fastrand()%2048;
|
||||
swirlangle = fastrand()%2048;
|
||||
|
||||
|
||||
/* buffer allocation tango */
|
||||
if ( width*height > 0 ) {
|
||||
Height[0] = (uint32_t*)calloc(width*(height+1), sizeof(uint32_t));
|
||||
@@ -135,6 +134,9 @@ public:
|
||||
BkGdImage = (uint32_t*) malloc(geo->size);
|
||||
BkGdImagePost = (uint32_t*)malloc(geo->size);
|
||||
}
|
||||
|
||||
// Initialize surface to NULL
|
||||
surface = NULL;
|
||||
}
|
||||
|
||||
~Water() {
|
||||
@@ -152,7 +154,7 @@ public:
|
||||
memcpy(BkGdImage, in, width*height*sizeof(uint32_t));
|
||||
water_update(out);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
ScreenGeometry *geo;
|
||||
|
||||
@@ -162,11 +164,11 @@ private:
|
||||
uint32_t *BkGdImagePre;
|
||||
uint32_t *BkGdImage;
|
||||
uint32_t *BkGdImagePost;
|
||||
|
||||
|
||||
// uint32_t *buffer;
|
||||
|
||||
|
||||
void *surface;
|
||||
|
||||
|
||||
/* water effect variables */
|
||||
int Hpage;
|
||||
int xang, yang;
|
||||
@@ -174,39 +176,39 @@ private:
|
||||
int x, y, ox, oy;
|
||||
int done;
|
||||
int mode;
|
||||
|
||||
|
||||
/* precalculated to optimize a bit */
|
||||
int water_surfacesize;
|
||||
int calc_optimization;
|
||||
|
||||
|
||||
/* density: water density (step 1)
|
||||
pheight: splash height (step 40)
|
||||
radius: waterdrop radius (step 1) */
|
||||
int density, pheight, radius;
|
||||
int offset;
|
||||
|
||||
int offset;
|
||||
|
||||
int raincount;
|
||||
int blend;
|
||||
|
||||
void water_clear();
|
||||
void water_distort();
|
||||
void water_setphysics(double physics);
|
||||
void water_update(uint32_t* out);
|
||||
void water_update(uint32_t *out);
|
||||
void water_drop(int x, int y);
|
||||
void water_bigsplash(int x, int y);
|
||||
void water_surfer();
|
||||
void water_swirl();
|
||||
void water_3swirls();
|
||||
|
||||
void DrawWater(int page,uint32_t* out);
|
||||
|
||||
void DrawWater(int page, uint32_t* out);
|
||||
void CalcWater(int npage, int density);
|
||||
void CalcWaterBigFilter(int npage, int density);
|
||||
|
||||
|
||||
void SmoothWater(int npage);
|
||||
|
||||
|
||||
void HeightBlob(int x, int y, int radius, int height, int page);
|
||||
void HeightBox (int x, int y, int radius, int height, int page);
|
||||
|
||||
|
||||
void WarpBlob(int x, int y, int radius, int height, int page);
|
||||
void SineBlob(int x, int y, int radius, int height, int page);
|
||||
|
||||
@@ -215,7 +217,7 @@ private:
|
||||
int FSin(int angle) { return FSinTab[angle&FSINMAX]; }
|
||||
int FCos(int angle) { return FCosTab[angle&FSINMAX]; }
|
||||
void FCreateSines() {
|
||||
int i; double angle;
|
||||
int i; double angle;
|
||||
for(i=0; i<2048; i++) {
|
||||
angle = (float)i * (PI/1024.0);
|
||||
FSinTab[i] = (int)(sin(angle) * (float)0x10000);
|
||||
@@ -227,7 +229,7 @@ private:
|
||||
uint32_t randval;
|
||||
uint32_t fastrand() { return (randval=randval*1103515245+12345); };
|
||||
void fastsrand(uint32_t seed) { randval = seed; };
|
||||
|
||||
|
||||
/* integer optimized square root by jaromil */
|
||||
int isqrt(unsigned int x) {
|
||||
unsigned int m, y, b; m = 0x40000000;
|
||||
@@ -235,7 +237,7 @@ private:
|
||||
if(x>=b) { x=x-b; y=y|m; }
|
||||
m=m>>2; } return y;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
void Water::water_clear() {
|
||||
@@ -306,6 +308,7 @@ void Water::water_bigsplash(int x, int y) {
|
||||
}
|
||||
|
||||
void Water::water_surfer() {
|
||||
int x, y;
|
||||
x = (geo->w>>1)
|
||||
+ ((
|
||||
(
|
||||
@@ -322,7 +325,7 @@ void Water::water_surfer() {
|
||||
) >> 16);
|
||||
xang += 13;
|
||||
yang += 12;
|
||||
|
||||
|
||||
if(mode & 0x4000)
|
||||
{
|
||||
offset = (oy+y)/2*geo->w + ((ox+x)>>1); // QUAAA
|
||||
@@ -331,7 +334,7 @@ void Water::water_surfer() {
|
||||
Height[Hpage][offset - 1] =
|
||||
Height[Hpage][offset + geo->w] =
|
||||
Height[Hpage][offset - geo->w] = pheight >> 1;
|
||||
|
||||
|
||||
offset = y*geo->w + x;
|
||||
Height[Hpage][offset] = pheight<<1;
|
||||
Height[Hpage][offset + 1] =
|
||||
@@ -344,23 +347,24 @@ void Water::water_surfer() {
|
||||
SineBlob(((ox+x)>>1), ((oy+y)>>1), 3, -1200, Hpage);
|
||||
SineBlob(x, y, 4, -2000, Hpage);
|
||||
}
|
||||
|
||||
|
||||
ox = x;
|
||||
oy = y;
|
||||
oy = y;
|
||||
}
|
||||
|
||||
void Water::water_swirl() {
|
||||
int x, y;
|
||||
x = (geo->w>>1)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (25)
|
||||
) >> 16);
|
||||
|
||||
|
||||
y = (geo->h>>1)
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (25)
|
||||
) >> 16);
|
||||
x += position.x;
|
||||
y += position.y;
|
||||
x += (int)(position.x * geo->w);
|
||||
y += (int)(position.y * geo->h);
|
||||
|
||||
swirlangle += 50;
|
||||
if(mode & 0x4000)
|
||||
@@ -371,6 +375,7 @@ void Water::water_swirl() {
|
||||
|
||||
void Water::water_3swirls() {
|
||||
#define ANGLE 15
|
||||
int x, y;
|
||||
x = (95)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -382,7 +387,7 @@ void Water::water_3swirls() {
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
|
||||
x = (95)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -391,10 +396,10 @@ void Water::water_3swirls() {
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (ANGLE)
|
||||
) >> 16);
|
||||
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
|
||||
x = (345)
|
||||
+ ((
|
||||
(FCos(swirlangle)) * (ANGLE)
|
||||
@@ -403,7 +408,7 @@ void Water::water_3swirls() {
|
||||
+ ((
|
||||
(FSin(swirlangle)) * (ANGLE)
|
||||
) >> 16);
|
||||
|
||||
|
||||
if(mode & 0x4000) HeightBlob(x,y, radius>>2, pheight, Hpage);
|
||||
else WarpBlob(x, y, radius, pheight, Hpage);
|
||||
|
||||
@@ -413,27 +418,27 @@ void Water::water_3swirls() {
|
||||
/* internal physics routines */
|
||||
void Water::DrawWater(int page,uint32_t* out) {
|
||||
int dx, dy;
|
||||
int x, y;
|
||||
uint32_t offset=geo->w + 1;
|
||||
uint32_t newoffset;
|
||||
int offset=geo->w + 1;
|
||||
int newoffset;
|
||||
int maxoffset = geo->w * geo->h;
|
||||
int *ptr = (int*)&Height[page][0];
|
||||
int maxoffset=geo->size/sizeof(uint32_t);
|
||||
|
||||
for (y = calc_optimization; offset < y; offset+=2) {
|
||||
for (x = offset+geo->w-2; offset < x; offset++) {
|
||||
|
||||
for (int y = calc_optimization; offset < y; offset += 2) {
|
||||
for (int x = offset+geo->w-2; offset < x; offset++) {
|
||||
dx = ptr[offset] - ptr[offset+1];
|
||||
dy = ptr[offset] - ptr[offset+geo->w];
|
||||
newoffset = offset + geo->w*(dy>>3) + (dx>>3);
|
||||
if(newoffset<maxoffset)
|
||||
if (newoffset < maxoffset) {
|
||||
out[offset] = BkGdImage[newoffset];
|
||||
}
|
||||
|
||||
offset++;
|
||||
|
||||
dx = ptr[offset] - ptr[offset+1];
|
||||
dy = ptr[offset] - ptr[offset+geo->w];
|
||||
newoffset = offset + geo->w*(dy>>3) + (dx>>3);
|
||||
if(newoffset<maxoffset)
|
||||
if (newoffset < maxoffset) {
|
||||
out[offset] = BkGdImage[newoffset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,10 +448,9 @@ void Water::CalcWater(int npage, int density) {
|
||||
int count = geo->w + 1;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for (y = calc_optimization; count < y; count += 2) {
|
||||
for (x = count+geo->w-2; count < x; count++) {
|
||||
for (int y = calc_optimization; count < y; count += 2) {
|
||||
for (int x = count+geo->w-2; count < x; count++) {
|
||||
/* eight pixels */
|
||||
newh = ((oldptr[count + geo->w]
|
||||
+ oldptr[count - geo->w]
|
||||
@@ -468,10 +472,9 @@ void Water::SmoothWater(int npage) {
|
||||
int count = geo->w + 1;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for(y=1; y<geo->h-1; y++) {
|
||||
for(x=1; x<geo->w-1; x++) {
|
||||
for(int y=1; y<geo->h-1; y++) {
|
||||
for(int x=1; x<geo->w-1; x++) {
|
||||
/* eight pixel */
|
||||
newh = ((oldptr[count + geo->w]
|
||||
+ oldptr[count - geo->w]
|
||||
@@ -483,8 +486,8 @@ void Water::SmoothWater(int npage) {
|
||||
+ oldptr[count + geo->w + 1]
|
||||
) >> 3 )
|
||||
+ newptr[count];
|
||||
|
||||
|
||||
|
||||
|
||||
newptr[count] = newh>>1;
|
||||
count++;
|
||||
}
|
||||
@@ -497,10 +500,9 @@ void Water::CalcWaterBigFilter(int npage, int density) {
|
||||
int count = (geo->w<<1) + 2;
|
||||
int *newptr = (int*) &Height[npage][0];
|
||||
int *oldptr = (int*) &Height[npage^1][0];
|
||||
int x, y;
|
||||
|
||||
for(y=2; y<geo->h-2; y++) {
|
||||
for(x=2; x<geo->w-2; x++) {
|
||||
|
||||
for(int y=2; y<geo->h-2; y++) {
|
||||
for(int x=2; x<geo->w-2; x++) {
|
||||
/* 25 pixels */
|
||||
newh = (
|
||||
(
|
||||
@@ -559,8 +561,13 @@ void Water::HeightBlob(int x, int y, int radius, int height, int page) {
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
cyq = cy*cy;
|
||||
for(cx = left; cx < right; cx++) {
|
||||
if(cx*cx + cyq < rquad)
|
||||
Height[page][geo->w*(cy+y) + (cx+x)] += height;
|
||||
if(cx*cx + cyq < rquad) {
|
||||
int index = geo->w*(cy+y) + (cx+x);
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,17 +579,21 @@ void Water::HeightBox (int x, int y, int radius, int height, int page) {
|
||||
|
||||
if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
|
||||
if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
|
||||
|
||||
|
||||
left=-radius; right = radius;
|
||||
top=-radius; bottom = radius;
|
||||
|
||||
|
||||
CLIP_EDGES
|
||||
|
||||
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
for(cx = left; cx < right; cx++) {
|
||||
Height[page][geo->w*(cy+y) + (cx+x)] = height;
|
||||
int index = geo->w*(cy+y) + (cx+x);
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Water::WarpBlob(int x, int y, int radius, int height, int page) {
|
||||
@@ -590,22 +601,25 @@ void Water::WarpBlob(int x, int y, int radius, int height, int page) {
|
||||
int left,top,right,bottom;
|
||||
int square;
|
||||
int radsquare = radius * radius;
|
||||
|
||||
|
||||
radsquare = (radius*radius);
|
||||
|
||||
|
||||
height = height>>5;
|
||||
|
||||
|
||||
left=-radius; right = radius;
|
||||
top=-radius; bottom = radius;
|
||||
|
||||
CLIP_EDGES
|
||||
|
||||
|
||||
for(cy = top; cy < bottom; cy++) {
|
||||
for(cx = left; cx < right; cx++) {
|
||||
square = cy*cy + cx*cx;
|
||||
if(square < radsquare) {
|
||||
Height[page][geo->w*(cy+y) + cx+x]
|
||||
+= (int)((radius-isqrt(square))*(float)(height));
|
||||
int index = geo->w*(cy+y) + cx+x;
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += (int)((radius-isqrt(square))*(float)(height));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -617,7 +631,7 @@ void Water::SineBlob(int x, int y, int radius, int height, int page) {
|
||||
int square, dist;
|
||||
int radsquare = radius * radius;
|
||||
float length = (1024.0/(float)radius)*(1024.0/(float)radius);
|
||||
|
||||
|
||||
if(x<0) x = 1+radius+ fastrand()%(geo->w-2*radius-1);
|
||||
if(y<0) y = 1+radius+ fastrand()%(geo->h-2*radius-1);
|
||||
|
||||
@@ -632,8 +646,11 @@ void Water::SineBlob(int x, int y, int radius, int height, int page) {
|
||||
square = cy*cy + cx*cx;
|
||||
if(square < radsquare) {
|
||||
dist = (int)(isqrt(square*length));
|
||||
Height[page][geo->w*(cy+y) + cx+x]
|
||||
+= (int)((FCos(dist)+0xffff)*(height)) >> 19;
|
||||
int index = geo->w*(cy+y) + cx+x;
|
||||
// Bounds check
|
||||
if (index >= 0 && index < geo->w * geo->h) {
|
||||
Height[page][index] += (int)((FCos(dist)+0xffff)*(height)) >> 19;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ void Partik0l::blossom(uint32_t* out) {
|
||||
double zx, zy;
|
||||
|
||||
/* here place a formula that draws on the screen
|
||||
the surface being drawed at this point is always blank */
|
||||
the surface being drawn at this point is always blank */
|
||||
for( a=0.0 ; a<pi2; a+=0.005 ) {
|
||||
zx = blossom_m*a;
|
||||
zy = blossom_n*a;
|
||||
|
||||
@@ -163,11 +163,11 @@ Selects between three possible cross sections, 12(3), 23(1), 31(2)
|
||||
NOTE: the numbers tell which two axes are represented in the 2D plane,
|
||||
(the first two numbers), and which axis is controlled by the "third
|
||||
axis value" slider (the third number in parentheses). For example,
|
||||
23(1) in RGB menas that G will change along the horizontal axis, B
|
||||
23(1) in RGB means that G will change along the horizontal axis, B
|
||||
along vertical, and R will be set by the "third axis value" slider.
|
||||
|
||||
Third axis value:
|
||||
sets the value along the "third" axis, which cannot be accomodated
|
||||
sets the value along the "third" axis, which cannot be accommodated
|
||||
on a 2D display.
|
||||
|
||||
Fullscreen:
|
||||
@@ -380,7 +380,7 @@ All patterns, except 8 and 9 which are square waves, are drawn as
|
||||
smooth phase sinewaves.
|
||||
|
||||
NOTE: These patterns are very sensitive to scaling and interpolation,
|
||||
any warts there will be revealed in a very drastical manner! Monitor
|
||||
any warts there will be revealed in a drastic manner! Monitor
|
||||
windows in video software are often done in a "fast" way, so it may
|
||||
be necessary to do a final rendering, to see a fair result.
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ for (i=h/2+100; i<h; i=i+100)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//draws a transparent mesurement grid
|
||||
//draws a transparent measurement grid
|
||||
//*a = alpha channel
|
||||
void grid(unsigned char *sl, int w, int h, unsigned char *a)
|
||||
{
|
||||
|
||||
@@ -658,7 +658,7 @@ void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
case 4: //contrast bands
|
||||
trakovi(inst->sl, inst->w, inst->h);
|
||||
break;
|
||||
case 5: //gama ckecking chart
|
||||
case 5: //gama checking chart
|
||||
gamatest(inst->sl, inst->w, inst->h);
|
||||
break;
|
||||
case 6: //for testing orthicon simulator
|
||||
|
||||
@@ -513,7 +513,7 @@ else
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//fills frame with constand 2D spatial frequency
|
||||
//fills frame with constant 2D spatial frequency
|
||||
//ar = pixel aspect ratio (not used currently)
|
||||
void diags(float *sl, int w, int h, float a, float ar, float fh, float fv)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,9 @@ class blend : public frei0r::mixer2
|
||||
public:
|
||||
blend(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->size = width * height;
|
||||
blend_factor = 0.5;
|
||||
register_param(blend_factor,"blend","blend factor");
|
||||
}
|
||||
@@ -45,6 +48,11 @@ public:
|
||||
const uint32_t* in1,
|
||||
const uint32_t* in2)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!out || !in1 || !in2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
|
||||
const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t*>(out);
|
||||
@@ -52,12 +60,17 @@ public:
|
||||
const uint8_t one_minus_bf = (255 - bf);
|
||||
uint32_t w = size;
|
||||
uint32_t b;
|
||||
|
||||
|
||||
// Validate size
|
||||
if (w == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (w--)
|
||||
{
|
||||
for (b = 0; b < NBYTES; b++)
|
||||
dst[b] = (src1[b] * one_minus_bf + src2[b] * bf) / 255;
|
||||
|
||||
|
||||
src1 += NBYTES;
|
||||
src2 += NBYTES;
|
||||
dst += NBYTES;
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
uint32_t b;
|
||||
|
||||
/* FIXME: Is the burn effect supposed to be dependant on the sign of this
|
||||
/* FIXME: Is the burn effect supposed to be dependent on the sign of this
|
||||
* temporary variable? */
|
||||
int tmp;
|
||||
|
||||
|
||||
@@ -75,27 +75,27 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
case 0:
|
||||
info->name = "x";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "X position of second input, value interperted as range -2*width - 3*width";
|
||||
info->explanation = "X position of second input, value interpreted as range -2*width - 3*width";
|
||||
break;
|
||||
case 1:
|
||||
info->name = "y";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Y position of second input, value interperted as range -2*height - 3*height";
|
||||
info->explanation = "Y position of second input, value interpreted as range -2*height - 3*height";
|
||||
break;
|
||||
case 2:
|
||||
info->name = "x scale";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "X scale of second input, value interperted as range 0 - 5";
|
||||
info->explanation = "X scale of second input, value interpreted as range 0 - 5";
|
||||
break;
|
||||
case 3:
|
||||
info->name = "y scale";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Y scale of second input, value interperted as range 0 - 5";
|
||||
info->explanation = "Y scale of second input, value interpreted as range 0 - 5";
|
||||
break;
|
||||
case 4:
|
||||
info->name = "rotation";
|
||||
info->type = F0R_PARAM_DOUBLE;
|
||||
info->explanation = "Rotation of second input, value interperted as range 0 - 360";
|
||||
info->explanation = "Rotation of second input, value interpreted as range 0 - 360";
|
||||
break;
|
||||
case 5:
|
||||
info->name = "opacity";
|
||||
|
||||
@@ -77,23 +77,42 @@ void f0r_get_param_info(f0r_param_info_t* info, int param_index)
|
||||
|
||||
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Validate inputs
|
||||
if (width == 0 || height == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*)calloc(1, sizeof(*inst));
|
||||
inst->width = width;
|
||||
if (!inst) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inst->width = width;
|
||||
inst->height = height;
|
||||
|
||||
inst->opacity = 1.0;
|
||||
|
||||
const char* blend_val = NORMAL;
|
||||
inst->blend_mode = (char*) malloc (strlen(blend_val) + 1 );
|
||||
strcpy (inst->blend_mode, blend_val);
|
||||
const char* blend_val = NORMAL;
|
||||
inst->blend_mode = (char*) malloc (strlen(blend_val) + 1);
|
||||
if (!inst->blend_mode) {
|
||||
free(inst);
|
||||
return NULL;
|
||||
}
|
||||
strcpy (inst->blend_mode, blend_val);
|
||||
|
||||
return (f0r_instance_t)inst;
|
||||
}
|
||||
|
||||
void f0r_destruct(f0r_instance_t instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*)instance;
|
||||
free(inst->blend_mode);
|
||||
if (inst->blend_mode) {
|
||||
free(inst->blend_mode);
|
||||
}
|
||||
free(instance);
|
||||
}
|
||||
|
||||
@@ -104,12 +123,22 @@ void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
char* sval;
|
||||
switch(param_index) {
|
||||
case 0:
|
||||
inst->opacity = *((double*)param);
|
||||
// Validate double parameter
|
||||
if (param) {
|
||||
inst->opacity = *((double*)param);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
sval = (*(char**)param);
|
||||
inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
|
||||
strcpy (inst->blend_mode, sval);
|
||||
// Validate string parameter
|
||||
if (param) {
|
||||
sval = (*(char**)param);
|
||||
if (sval) {
|
||||
inst->blend_mode = (char*)realloc (inst->blend_mode, strlen(sval) + 1);
|
||||
if (inst->blend_mode) {
|
||||
strcpy (inst->blend_mode, sval);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -121,10 +150,16 @@ void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_i
|
||||
|
||||
switch(param_index) {
|
||||
case 0:
|
||||
*((double*)param) = inst->opacity;
|
||||
if (param) {
|
||||
*((double*)param) = inst->opacity;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
*((f0r_param_string *)param) = inst->blend_mode;
|
||||
if (param && inst->blend_mode) {
|
||||
*((f0r_param_string *)param) = inst->blend_mode;
|
||||
} else if (param) {
|
||||
*((f0r_param_string *)param) = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -135,27 +170,53 @@ void draw_composite(cairo_blend_instance_t* inst, unsigned char* out, unsigned c
|
||||
int h = inst->height;
|
||||
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
|
||||
|
||||
// Validate inputs
|
||||
if (!inst || !out || !src || w <= 0 || h <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_surface_t* out_image = cairo_image_surface_create_for_data (out,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
// Check if surface creation succeeded
|
||||
if (!out_image) {
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_t* cr = cairo_create (out_image);
|
||||
// Check if context creation succeeded
|
||||
if (!cr) {
|
||||
cairo_surface_destroy (out_image);
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_surface_t* src_image = cairo_image_surface_create_for_data ((unsigned char*)src,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
w,
|
||||
h,
|
||||
stride);
|
||||
// Check if surface creation succeeded
|
||||
if (!src_image) {
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (out_image);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate blend mode string
|
||||
if (inst->blend_mode) {
|
||||
// Set source, blend mode and draw with current opacity
|
||||
frei0r_cairo_set_operator(cr, inst->blend_mode);
|
||||
}
|
||||
|
||||
// Set source, blen mode and draw with current opacity
|
||||
frei0r_cairo_set_operator(cr, inst->blend_mode);
|
||||
cairo_set_source_surface (cr, src_image, 0, 0);
|
||||
cairo_paint_with_alpha (cr, inst->opacity);
|
||||
|
||||
cairo_surface_destroy (out_image);
|
||||
// Clean up in proper order
|
||||
cairo_surface_destroy (src_image);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (out_image);
|
||||
}
|
||||
|
||||
void f0r_update(f0r_instance_t instance, double time,
|
||||
@@ -167,6 +228,11 @@ void f0r_update(f0r_instance_t instance, double time,
|
||||
void f0r_update2(f0r_instance_t instance, double time, const uint32_t* inframe1,
|
||||
const uint32_t* inframe2, const uint32_t* inframe3, uint32_t* outframe)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!instance || !inframe1 || !inframe2 || !outframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(instance);
|
||||
cairo_blend_instance_t* inst = (cairo_blend_instance_t*) instance;
|
||||
|
||||
@@ -175,6 +241,11 @@ void f0r_update2(f0r_instance_t instance, double time, const uint32_t* inframe1,
|
||||
unsigned char* out = (unsigned char*)outframe;
|
||||
int pixels = inst->width * inst->height;
|
||||
|
||||
// Validate dimensions
|
||||
if (pixels <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
frei0r_cairo_premultiply_rgba2 (dst, out, pixels, -1);
|
||||
frei0r_cairo_premultiply_rgba (src, pixels, -1);
|
||||
draw_composite (inst, out, src, time);
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
r1 = r2;
|
||||
g1 = g2;
|
||||
|
||||
/* set the dstination */
|
||||
/* set the destination */
|
||||
hsl_to_rgb_int(&r1, &g1, &b1);
|
||||
|
||||
dst[0] = r1;
|
||||
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
};
|
||||
|
||||
frei0r::construct<euclid_eraser> plugin("euclid_eraser",
|
||||
"Erasing backgrounds with euclidian distance",
|
||||
"Erasing backgrounds with euclidean distance",
|
||||
"Erik H. Beck",
|
||||
0,1,
|
||||
F0R_COLOR_MODEL_RGBA8888);
|
||||
|
||||
@@ -21,16 +21,16 @@ This mixer takes the (first) reference input, such as a static
|
||||
background, and removes it from every frame in the video stream of the
|
||||
second input.
|
||||
|
||||
The alpha channel on the output is based on the euclidian distance of
|
||||
The alpha channel on the output is based on the euclidean distance of
|
||||
the two input coordinates in 3-d RGB space. If the calculated distance
|
||||
betwen the two inputs for a given pixel is less than a provided
|
||||
between the two inputs for a given pixel is less than a provided
|
||||
(variable) threshold amount, that indicates the pixel in the
|
||||
background (reference) image is the same or similar enough to the
|
||||
operational (second) input that is part of the background to be
|
||||
removed, and the transparency is set to fully transparent via the
|
||||
alpha channel (set to 0).
|
||||
|
||||
If the calcuated distance exceeds the threshold, then that pixel is
|
||||
If the calculated distance exceeds the threshold, then that pixel is
|
||||
part of the foreground image to be retained, and the transparency
|
||||
of it is set to be fully opaque (alpha channel for that pixel set
|
||||
to 255).
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
if (g2)
|
||||
r1 = r2;
|
||||
|
||||
/* set the dstination */
|
||||
/* set the destination */
|
||||
hsv_to_rgb_int (&r1, &g1, &b1);
|
||||
|
||||
dst[0] = r1;
|
||||
|
||||
@@ -29,6 +29,9 @@ class overlay : public frei0r::mixer2
|
||||
public:
|
||||
overlay(unsigned int width, unsigned int height)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->size = width * height;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,22 +47,32 @@ public:
|
||||
const uint32_t* in1,
|
||||
const uint32_t* in2)
|
||||
{
|
||||
// Validate inputs
|
||||
if (!out || !in1 || !in2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1);
|
||||
const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2);
|
||||
uint8_t *dst = reinterpret_cast<uint8_t*>(out);
|
||||
uint32_t sizeCounter = size;
|
||||
|
||||
|
||||
// Validate size
|
||||
if (sizeCounter == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t b, tmp, tmpM;
|
||||
|
||||
|
||||
while (sizeCounter--)
|
||||
{
|
||||
for (b = 0; b < ALPHA; b++)
|
||||
{
|
||||
dst[b] = INT_MULT(src1[b], src1[b] + INT_MULT(2 * src2[b], 255 - src1[b], tmpM), tmp);
|
||||
}
|
||||
|
||||
|
||||
dst[ALPHA] = MIN(src1[ALPHA], src2[ALPHA]);
|
||||
|
||||
|
||||
src1 += NBYTES;
|
||||
src2 += NBYTES;
|
||||
dst += NBYTES;
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
g1 = g2;
|
||||
|
||||
/* set the dstination */
|
||||
/* set the destination */
|
||||
hsv_to_rgb_int(&r1, &g1, &b1);
|
||||
|
||||
dst[0] = r1;
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
b1 = b2;
|
||||
|
||||
/* set the dstination */
|
||||
/* set the destination */
|
||||
hsv_to_rgb_int(&r1, &g1, &b1);
|
||||
|
||||
dst[0] = r1;
|
||||
|
||||
Reference in New Issue
Block a user