Blender V5.0
vse_effect_glow.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_vector.hh"
10#include "BLI_task.hh"
11
12#include "DNA_scene_types.h"
13#include "DNA_sequence_types.h"
14
16#include "IMB_imbuf.hh"
17
18#include "SEQ_render.hh"
19
20#include "effects.hh"
21
22namespace blender::seq {
23
24static void glow_blur_bitmap(
25 const float4 *src, float4 *map, int width, int height, float blur, int quality)
26{
27 using namespace blender;
28
29 /* If we're not really blurring, bail out */
30 if (blur <= 0) {
31 return;
32 }
33
34 /* If result would be no blurring, early out. */
35 const int halfWidth = ((quality + 1) * blur);
36 if (halfWidth == 0) {
37 return;
38 }
39
40 Array<float4> temp(width * height);
41
42 /* Initialize the gaussian filter.
43 * TODO: use code from #RE_filter_value. */
44 Array<float> filter(halfWidth * 2);
45 const float k = -1.0f / (2.0f * float(M_PI) * blur * blur);
46 float weight = 0;
47 for (int ix = 0; ix < halfWidth; ix++) {
48 weight = exp(k * (ix * ix));
49 filter[halfWidth - ix] = weight;
50 filter[halfWidth + ix] = weight;
51 }
52 filter[0] = weight;
53 /* Normalize the array */
54 float fval = 0;
55 for (int ix = 0; ix < halfWidth * 2; ix++) {
56 fval += filter[ix];
57 }
58 for (int ix = 0; ix < halfWidth * 2; ix++) {
59 filter[ix] /= fval;
60 }
61
62 /* Blur the rows: read map, write temp */
63 threading::parallel_for(IndexRange(height), 32, [&](const IndexRange y_range) {
64 for (const int y : y_range) {
65 for (int x = 0; x < width; x++) {
66 float4 curColor = float4(0.0f);
67 int xmin = math::max(x - halfWidth, 0);
68 int xmax = math::min(x + halfWidth, width);
69 for (int nx = xmin, index = (xmin - x) + halfWidth; nx < xmax; nx++, index++) {
70 curColor += map[nx + y * width] * filter[index];
71 }
72 temp[x + y * width] = curColor;
73 }
74 }
75 });
76
77 /* Blur the columns: read temp, write map */
78 threading::parallel_for(IndexRange(width), 32, [&](const IndexRange x_range) {
79 const float4 one = float4(1.0f);
80 for (const int x : x_range) {
81 for (int y = 0; y < height; y++) {
82 float4 curColor = float4(0.0f);
83 int ymin = math::max(y - halfWidth, 0);
84 int ymax = math::min(y + halfWidth, height);
85 for (int ny = ymin, index = (ymin - y) + halfWidth; ny < ymax; ny++, index++) {
86 curColor += temp[x + ny * width] * filter[index];
87 }
88 if (src != nullptr) {
89 curColor = math::min(one, src[x + y * width] + curColor);
90 }
91 map[x + y * width] = curColor;
92 }
93 }
94 });
95}
96
98 float4 *out,
99 int width,
100 int height,
101 float threshold,
102 float boost,
103 float clamp)
104{
105 using namespace blender;
106 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
107 const float4 clampv = float4(clamp);
108 for (const int y : y_range) {
109 int index = y * width;
110 for (int x = 0; x < width; x++, index++) {
111
112 /* Isolate the intensity */
113 float intensity = (in[index].x + in[index].y + in[index].z - threshold);
114 float4 val;
115 if (intensity > 0) {
116 val = math::min(clampv, in[index] * (boost * intensity));
117 }
118 else {
119 val = float4(0.0f);
120 }
121 out[index] = val;
122 }
123 }
124 });
125}
126
127static void init_glow_effect(Strip *strip)
128{
129 if (strip->effectdata) {
130 MEM_freeN(strip->effectdata);
131 }
132
133 GlowVars *glow = MEM_callocN<GlowVars>("glowvars");
134 strip->effectdata = glow;
135
136 glow->fMini = 0.25;
137 glow->fClamp = 1.0;
138 glow->fBoost = 0.5;
139 glow->dDist = 3.0;
140 glow->dQuality = 3;
141 glow->bNoComp = 0;
142}
143
144static int num_inputs_glow()
145{
146 return 1;
147}
148
149static void free_glow_effect(Strip *strip, const bool /*do_id_user*/)
150{
152}
153
154static void copy_glow_effect(Strip *dst, const Strip *src, const int /*flag*/)
155{
157}
158
159static void do_glow_effect_byte(Strip *strip,
160 int render_size,
161 float fac,
162 int x,
163 int y,
164 uchar *rect1,
165 uchar * /*rect2*/,
166 uchar *out)
167{
168 using namespace blender;
169 GlowVars *glow = (GlowVars *)strip->effectdata;
170
171 Array<float4> inbuf(x * y);
172 Array<float4> outbuf(x * y);
173
174 using namespace blender;
175 IMB_colormanagement_transform_byte_to_float(*inbuf.data(), rect1, x, y, 4, "sRGB", "sRGB");
176
178 inbuf.data(), outbuf.data(), x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
179 glow_blur_bitmap(glow->bNoComp ? nullptr : inbuf.data(),
180 outbuf.data(),
181 x,
182 y,
183 glow->dDist * (render_size / 100.0f),
184 glow->dQuality);
185
186 threading::parallel_for(IndexRange(y), 64, [&](const IndexRange y_range) {
187 size_t offset = y_range.first() * x;
188 IMB_buffer_byte_from_float(out + offset * 4,
189 *(outbuf.data() + offset),
190 4,
191 0.0f,
194 true,
195 x,
196 y_range.size(),
197 x,
198 x);
199 });
200}
201
202static void do_glow_effect_float(Strip *strip,
203 int render_size,
204 float fac,
205 int x,
206 int y,
207 float *rect1,
208 float * /*rect2*/,
209 float *out)
210{
211 using namespace blender;
212 float4 *outbuf = reinterpret_cast<float4 *>(out);
213 float4 *inbuf = reinterpret_cast<float4 *>(rect1);
214 GlowVars *glow = (GlowVars *)strip->effectdata;
215
217 inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
218 glow_blur_bitmap(glow->bNoComp ? nullptr : inbuf,
219 outbuf,
220 x,
221 y,
222 glow->dDist * (render_size / 100.0f),
223 glow->dQuality);
224}
225
226static ImBuf *do_glow_effect(const RenderData *context,
227 SeqRenderState * /*state*/,
228 Strip *strip,
229 float /*timeline_frame*/,
230 float fac,
231 ImBuf *ibuf1,
232 ImBuf *ibuf2)
233{
234 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
235
236 int render_size = 100 * context->rectx / context->scene->r.xsch;
237
238 if (out->float_buffer.data) {
240 render_size,
241 fac,
242 context->rectx,
243 context->recty,
244 ibuf1->float_buffer.data,
245 nullptr,
246 out->float_buffer.data);
247 }
248 else {
250 render_size,
251 fac,
252 context->rectx,
253 context->recty,
254 ibuf1->byte_buffer.data,
255 nullptr,
256 out->byte_buffer.data);
257 }
258
259 return out;
260}
261
270
271} // namespace blender::seq
#define M_PI
unsigned char uchar
void IMB_colormanagement_transform_byte_to_float(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from, int start_y=0)
Definition conversion.cc:71
#define IB_PROFILE_SRGB
#define MEM_SAFE_FREE(v)
const T * data() const
Definition BLI_array.hh:312
constexpr int64_t first() const
constexpr int64_t size() const
nullptr float
#define in
#define out
#define filter
#define exp
constexpr T clamp(T, U, U) RET
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
T min(const T &a, const T &b)
T max(const T &a, const T &b)
static void init_glow_effect(Strip *strip)
static void copy_glow_effect(Strip *dst, const Strip *src, const int)
ImBuf * prepare_effect_imbufs(const RenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, bool uninitialized_pixels)
Definition effects.cc:28
static ImBuf * do_glow_effect(const RenderData *context, SeqRenderState *, Strip *strip, float, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
static void glow_blur_bitmap(const float4 *src, float4 *map, int width, int height, float blur, int quality)
static void free_glow_effect(Strip *strip, const bool)
static void do_glow_effect_byte(Strip *strip, int render_size, float fac, int x, int y, uchar *rect1, uchar *, uchar *out)
static void do_glow_effect_float(Strip *strip, int render_size, float fac, int x, int y, float *rect1, float *, float *out)
static void blur_isolate_highlights(const float4 *in, float4 *out, int width, int height, float threshold, float boost, float clamp)
static int num_inputs_glow()
void glow_effect_get_handle(EffectHandle &rval)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< float, 4 > float4
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
void * effectdata
void(* copy)(Strip *dst, const Strip *src, int flag)
ImBuf *(* execute)(const RenderData *context, SeqRenderState *state, Strip *strip, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
void(* free)(Strip *strip, bool do_id_user)
void(* init)(Strip *strip)