Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package frei0r-plugins for openSUSE:Factory 
checked in at 2026-08-26 19:52:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/frei0r-plugins (Old)
 and      /work/SRC/openSUSE:Factory/.frei0r-plugins.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "frei0r-plugins"

Wed Aug 26 19:52:34 2026 rev:27 rq:1373629 version:3.5.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/frei0r-plugins/frei0r-plugins.changes    
2026-08-24 15:44:07.226783652 +0200
+++ /work/SRC/openSUSE:Factory/.frei0r-plugins.new.1258/frei0r-plugins.changes  
2026-08-26 19:53:04.587370714 +0200
@@ -1,0 +2,6 @@
+Tue Aug 25 12:40:07 UTC 2026 - Bjørn Lie <[email protected]>
+
+- Update to version 3.5.0:
+  + feat: add squigglevision filter.
+
+-------------------------------------------------------------------

Old:
----
  frei0r-plugins-3.4.3.tar.gz

New:
----
  frei0r-plugins-3.5.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ frei0r-plugins.spec ++++++
--- /var/tmp/diff_new_pack.DEK1bV/_old  2026-08-26 19:53:05.585405962 +0200
+++ /var/tmp/diff_new_pack.DEK1bV/_new  2026-08-26 19:53:05.587406033 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           frei0r-plugins
-Version:        3.4.3
+Version:        3.5.0
 Release:        0
 Summary:        Collection of video sources and filters plugins
 # Upstream says 2.0+ but quite few of their plugins are GPL-3.0+

++++++ frei0r-plugins-3.4.3.tar.gz -> frei0r-plugins-3.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/frei0r-3.4.3/src/filter/CMakeLists.txt 
new/frei0r-3.5.0/src/filter/CMakeLists.txt
--- old/frei0r-3.4.3/src/filter/CMakeLists.txt  2026-08-21 12:33:41.000000000 
+0200
+++ new/frei0r-3.5.0/src/filter/CMakeLists.txt  2026-08-24 19:21:41.000000000 
+0200
@@ -96,6 +96,7 @@
 add_subdirectory (sopsat)
 add_subdirectory (spillsupress)
 add_subdirectory (squareblur)
+add_subdirectory (squigglevision)
 add_subdirectory (tehroxx0r)
 add_subdirectory (three_point_balance)
 add_subdirectory (threelay0r)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/frei0r-3.4.3/src/filter/squigglevision/CMakeLists.txt 
new/frei0r-3.5.0/src/filter/squigglevision/CMakeLists.txt
--- old/frei0r-3.4.3/src/filter/squigglevision/CMakeLists.txt   1970-01-01 
01:00:00.000000000 +0100
+++ new/frei0r-3.5.0/src/filter/squigglevision/CMakeLists.txt   2026-08-24 
19:21:41.000000000 +0200
@@ -0,0 +1,28 @@
+include(CheckCXXSourceCompiles)
+
+set(SOURCES squigglevision.cpp)
+set(TARGET squigglevision)
+
+if(MSVC)
+  set(SOURCES ${SOURCES} ${FREI0R_DEF})
+endif()
+
+add_library(${TARGET} MODULE ${SOURCES})
+set_target_properties(${TARGET} PROPERTIES PREFIX "")
+
+# multithreading based on the kaleid0sc0pe filter: std::async over row bands,
+# with a serial fallback where std::future is unavailable.
+if(NOT WIN32)
+  set(THREADS_PREFER_PTHREAD_FLAG ON)
+  find_package(Threads REQUIRED)
+  target_link_libraries(${TARGET} PRIVATE Threads::Threads)
+endif()
+
+check_cxx_source_compiles("
+  #include <future>
+  int main() { std::future<void> f; return 0; }" HAS_WORKING_FUTURE)
+if(NOT HAS_WORKING_FUTURE)
+  target_compile_definitions(${TARGET} PRIVATE NO_FUTURE)
+endif()
+
+install(TARGETS ${TARGET} LIBRARY DESTINATION ${LIBDIR})
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/frei0r-3.4.3/src/filter/squigglevision/squigglevision.cpp 
new/frei0r-3.5.0/src/filter/squigglevision/squigglevision.cpp
--- old/frei0r-3.4.3/src/filter/squigglevision/squigglevision.cpp       
1970-01-01 01:00:00.000000000 +0100
+++ new/frei0r-3.5.0/src/filter/squigglevision/squigglevision.cpp       
2026-08-24 19:21:41.000000000 +0200
@@ -0,0 +1,296 @@
+/* squigglevision.cpp
+ * Copyright (C) 2026 Gabriel Lobo (https://olobo.xyz)
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "frei0r.hpp"
+#include "frei0r/math.h"
+
+#include <cmath>
+#include <cstdint>
+#include <vector>
+
+#ifndef NO_FUTURE
+#include <future>
+#include <thread>
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_E
+#define M_E 2.71828182845904523536
+#endif
+
+namespace
+{
+
+    float hash2(int x, int y)
+    {
+        unsigned int h = (unsigned int)(x * 374761393 + y * 668265263);
+        h = (h ^ (h >> 13)) * 1274126177u;
+        h ^= h >> 16;
+        return (h & 0xffffffu) / (float)0x1000000;
+    }
+
+    float value_noise(float x, float y)
+    {
+        int xi = (int)std::floor(x);
+        int yi = (int)std::floor(y);
+        float fx = x - xi;
+        float fy = y - yi;
+
+        float a = hash2(xi, yi);
+        float b = hash2(xi + 1, yi);
+        float c = hash2(xi, yi + 1);
+        float d = hash2(xi + 1, yi + 1);
+
+        float ab = a + (b - a) * fx;
+        float cd = c + (d - c) * fx;
+        return ab + (cd - ab) * fy;
+    }
+
+    void sample_bilinear(const unsigned char *s, int w, int h,
+                         float fx, float fy, unsigned char *o)
+    {
+        if (fx < 0)
+            fx = 0;
+        if (fy < 0)
+            fy = 0;
+        if (fx > w - 1)
+            fx = w - 1;
+        if (fy > h - 1)
+            fy = h - 1;
+
+        int x0 = (int)fx;
+        int y0 = (int)fy;
+        int x1 = x0 + 1 < w ? x0 + 1 : x0;
+        int y1 = y0 + 1 < h ? y0 + 1 : y0;
+        float dx = fx - x0;
+        float dy = fy - y0;
+
+        const unsigned char *corners[4] = {
+            s + ((size_t)y0 * w + x0) * 4,
+            s + ((size_t)y0 * w + x1) * 4,
+            s + ((size_t)y1 * w + x0) * 4,
+            s + ((size_t)y1 * w + x1) * 4};
+        float weights[4] = {
+            (1 - dx) * (1 - dy),
+            dx * (1 - dy),
+            (1 - dx) * dy,
+            dx * dy};
+
+        float inv255 = 1.0f / 255.0f;
+        float pr = 0, pg = 0, pb = 0, pa = 0;
+
+        for (int k = 0; k < 4; k++)
+        {
+            const unsigned char *p = corners[k];
+            float a = p[3] * inv255;
+            float wk = weights[k];
+            pr += p[0] * a * wk;
+            pg += p[1] * a * wk;
+            pb += p[2] * a * wk;
+            pa += p[3] * wk;
+        }
+
+        o[3] = (unsigned char)(pa + 0.5f);
+
+        if (pa > 0.0f)
+        {
+            float inv = 255.0f / pa;
+            o[0] = CLAMP0255((int32_t)(pr * inv + 0.5f));
+            o[1] = CLAMP0255((int32_t)(pg * inv + 0.5f));
+            o[2] = CLAMP0255((int32_t)(pb * inv + 0.5f));
+        }
+        else
+        {
+            o[0] = 0;
+            o[1] = 0;
+            o[2] = 0;
+        }
+    }
+
+} // namespace
+
+class squigglevision : public frei0r::filter
+{
+public:
+    squigglevision(unsigned int width, unsigned int height)
+    {
+        (void)width;
+        (void)height;
+
+        register_param(m_strength, "Strength",
+                       "Displacement amount, normalized 0..1 mapped to 0..100 
percent (8 percent is a moderate default).");
+        register_param(m_fps, "FPS",
+                       "Squiggle updates per second, normalized 0..1 mapped to 
0..30 fps (0 = frozen; 6 fps is a moderate default).");
+        register_param(m_scale, "Scale",
+                       "Noise cell size, normalized 0..1 mapped to 4..128 px 
(about 23 px is a moderate default).");
+
+        m_strength = 0.08;
+        m_fps = 0.2;
+        m_scale = 0.15;
+    }
+
+    void update(double time, uint32_t *out, const uint32_t *in)
+    {
+        const int w = (int)width;
+        const int h = (int)height;
+
+        const double disp = m_strength * 5.0 * 0.005;
+        const double fps = m_fps * 30.0;
+        const double cell = 4.0 + m_scale * 124.0;
+
+        m_inv_cell = (float)(1.0 / cell);
+        m_dispx = (float)(disp * w);
+        m_dispy = (float)(disp * h);
+
+        const double frame = std::floor(time * fps);
+        build_grid(w, h, (float)(frame * M_PI), (float)(frame * M_E));
+
+        dispatch((const unsigned char *)in, (unsigned char *)out, w, h);
+    }
+
+private:
+    void build_grid(int w, int h, float offx, float offy)
+    {
+        m_gw = (int)(w * m_inv_cell) + 2;
+        m_gh = (int)(h * m_inv_cell) + 2;
+        m_gx.resize((size_t)m_gw * m_gh);
+        m_gy.resize((size_t)m_gw * m_gh);
+
+        for (int j = 0; j < m_gh; j++)
+        {
+            for (int i = 0; i < m_gw; i++)
+            {
+                float angle = value_noise(i + offx, j + offy) * 4.0f * 
(float)M_PI;
+                m_gx[(size_t)j * m_gw + i] = std::cos(angle) * m_dispx;
+                m_gy[(size_t)j * m_gw + i] = std::sin(angle) * m_dispy;
+            }
+        }
+    }
+
+    void render_rows(int y0, int y1, const unsigned char *src, unsigned char 
*dst,
+                     int w, int h) const
+    {
+        const float *gx = m_gx.data();
+        const float *gy = m_gy.data();
+        const int gw = m_gw;
+        const float inv_cell = m_inv_cell;
+
+        for (int y = y0; y < y1; y++)
+        {
+            const float v = y * inv_cell;
+            const int j = (int)v;
+            const float fv = v - j;
+
+            for (int x = 0; x < w; x++)
+            {
+                const float u = x * inv_cell;
+                const int i = (int)u;
+                const float fu = u - i;
+                const size_t g = (size_t)j * gw + i;
+
+                float xa = gx[g] + (gx[g + 1] - gx[g]) * fu;
+                float xb = gx[g + gw] + (gx[g + gw + 1] - gx[g + gw]) * fu;
+                float ddx = xa + (xb - xa) * fv;
+
+                float ya = gy[g] + (gy[g + 1] - gy[g]) * fu;
+                float yb = gy[g + gw] + (gy[g + gw + 1] - gy[g + gw]) * fu;
+                float ddy = ya + (yb - ya) * fv;
+
+                unsigned char px[4];
+                sample_bilinear(src, w, h, x + ddx, y + ddy, px);
+
+                const size_t idx = ((size_t)y * w + x) * 4;
+                const unsigned char *orig = src + idx;
+                unsigned char *d = dst + idx;
+
+                if (px[3] >= orig[3])
+                {
+                    d[0] = px[0];
+                    d[1] = px[1];
+                    d[2] = px[2];
+                    d[3] = px[3];
+                }
+                else
+                {
+                    d[0] = orig[0];
+                    d[1] = orig[1];
+                    d[2] = orig[2];
+                    d[3] = orig[3];
+                }
+            }
+        }
+    }
+
+    void dispatch(const unsigned char *src, unsigned char *dst, int w, int h)
+    {
+#ifndef NO_FUTURE
+        unsigned int nthreads = std::thread::hardware_concurrency();
+        const int min_band = 64;
+
+        if (nthreads > 1 && h >= 2 * min_band)
+        {
+            if (nthreads > (unsigned int)(h / min_band))
+            {
+                nthreads = (unsigned int)(h / min_band);
+            }
+
+            std::vector<std::future<void>> futures;
+            futures.reserve(nthreads);
+
+            const int band = h / nthreads;
+            int y0 = 0;
+            for (unsigned int t = 0; t < nthreads; t++)
+            {
+                int y1 = (t == nthreads - 1) ? h : y0 + band;
+                futures.push_back(std::async(std::launch::async,
+                                             &squigglevision::render_rows, 
this, y0, y1, src, dst, w, h));
+                y0 = y1;
+            }
+            for (size_t k = 0; k < futures.size(); k++)
+            {
+                futures[k].wait();
+            }
+            return;
+        }
+#endif
+        render_rows(0, h, src, dst, w, h);
+    }
+
+    double m_strength;
+    double m_fps;
+    double m_scale;
+
+    std::vector<float> m_gx;
+    std::vector<float> m_gy;
+    int m_gw = 0;
+    int m_gh = 0;
+    float m_inv_cell = 0;
+    float m_dispx = 0;
+    float m_dispy = 0;
+};
+
+frei0r::construct<squigglevision> plugin(
+    "squigglevision",
+    "Hand-drawn wobble via time-quantized noise displacement",
+    "Gabriel Lobo (https://olobo.xyz)",
+    1, 0,
+    F0R_COLOR_MODEL_RGBA8888);

Reply via email to