Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
brush.c File Reference
#include "iop/drawlayer/brush.h"
#include "iop/drawlayer/cache.h"
#include "iop/drawlayer/paint.h"
#include "iop/drawlayer/brush_profile.h"
#include "system/macros.h"
#include "system/simd.h"
#include "iop/noise_generator.h"
#include <math.h>
#include <string.h>
+ Include dependency graph for iop/drawlayer/brush.c:

Go to the source code of this file.

Data Structures

struct  dt_drawlayer_sprinkle_preview_t
 
struct  dt_drawlayer_brush_runtime_view_t
 
struct  dt_drawlayer_brush_pixel_eval_t
 

Typedefs

typedef struct dt_drawlayer_sprinkle_preview_t dt_drawlayer_sprinkle_preview_t
 
typedef struct dt_drawlayer_brush_runtime_view_t dt_drawlayer_brush_runtime_view_t
 
typedef struct dt_drawlayer_brush_pixel_eval_t dt_drawlayer_brush_pixel_eval_t
 

Functions

static float _clamp01 (const float v)
 Clamp scalar to [0,1].
 
static float _lerpf (const float a, const float b, const float t)
 Linear interpolation helper.
 
static float _cell_hash01_from_seed (const uint64_t cell_seed, const uint64_t salt)
 Stable scalar hash in [0,1] from precomputed cell seed.
 
static float _cellular_grain_2d (const uint64_t seed, const float x, const float y)
 Grain-like round cellular field. Peaks at grain centers, falls off radially.
 
static void _sprinkle_octave_weights (const float coarseness, float *w0, float *w1, float *w2)
 Resolve octave weights from coarseness control.
 
static float _sprinkle_noise_at_pixel_precomputed (const float px, const float py, const float scale, const float strength, const float w0, const float w1, const float w2, const uint64_t seed0, const uint64_t seed1, const uint64_t seed2)
 Evaluate sprinkle modulation from precomputed dab constants.
 
static void _prepare_sprinkle_preview (const dt_drawlayer_brush_dab_t *dab, const float center_x, const float center_y, const float radius, dt_drawlayer_sprinkle_preview_t *preview)
 
static float _sample_sprinkle_preview (const dt_drawlayer_sprinkle_preview_t *preview, const float px, const float py)
 
static gboolean _brush_runtime_view_from_bounds (const dt_drawlayer_damaged_rect_t *bounds, const dt_drawlayer_brush_dab_t *dab, const int origin_x, const int origin_y, const float scale, dt_drawlayer_brush_runtime_view_t *view)
 Build immutable per-dab raster view from stroke runtime state.
 
static gboolean _brush_runtime_view_from_state (const dt_drawlayer_paint_stroke_t *stroke, const dt_drawlayer_brush_dab_t *dab, const int origin_x, const int origin_y, const float scale, dt_drawlayer_brush_runtime_view_t *view)
 
static float _sample_alpha_noise_raw (const dt_drawlayer_brush_dab_t *dab, const dt_drawlayer_brush_runtime_view_t *view, const int pixel_x, const int pixel_y)
 Resolve multiplicative alpha noise at one pixel.
 
static float _estimate_alpha_noise_gain (const dt_drawlayer_brush_dab_t *dab, const dt_drawlayer_brush_runtime_view_t *view)
 Estimate per-dab texture gain so noise preserves average opacity across samples.
 
static float _stroke_flow_alpha (const dt_drawlayer_brush_dab_t *dab, const float opacity, const float flow, const float sample_opacity_scale, const float profile, const float brush_alpha, const float old_alpha, const float stroke_old_alpha, const gboolean have_stroke_alpha)
 Compute per-pixel source alpha from opacity/flow model.
 
static gboolean _prepare_analytic_pixel_context (const dt_drawlayer_brush_runtime_view_t *view, const float sample_opacity_scale, float *stroke_mask, const int stroke_mask_width, const int stroke_mask_height, const int x, const int y, const float old_alpha, dt_drawlayer_brush_pixel_eval_t *pixel_eval)
 Compute full analytic per-pixel brush context.
 
static gboolean _prepare_blur_context (dt_aligned_pixel_simd_t *blur_px, const float *buffer, const int width, const int height, const int source_origin_x, const int source_origin_y, const int patch_origin_x, const int patch_origin_y, const dt_drawlayer_brush_runtime_view_t *view)
 Build blur gather color for current dab footprint.
 
static float _smudge_hash_signed (const int x, const int y, const int lane)
 Stable signed pseudo-random helper in [-1,1].
 
static __attribute__ ((always_inline))
 Bilinear RGBA sample from float buffer.
 
static float _smudge_deposit_alpha (const float src_alpha, const float carried_alpha, const float opacity)
 Resolve effective smudge deposit alpha for one pixel.
 
static dt_aligned_pixel_simd_t _apply_smudge_stroke_mode (const float *source_buffer, const int source_width, const int source_height, const int source_origin_x, const int source_origin_y, dt_drawlayer_paint_stroke_t *runtime_private, const dt_drawlayer_brush_runtime_view_t *view, const float scale, const int patch_origin_x, const int patch_origin_y, const int x, const int y, const float src_alpha, const dt_aligned_pixel_simd_t old_px)
 Apply smudge mode for one pixel and update carried sample.
 
gboolean dt_drawlayer_brush_rasterize (const dt_drawlayer_cache_patch_t *sample_patch, dt_drawlayer_cache_patch_t *patch, const float scale, const dt_drawlayer_brush_dab_t *dab, const float sample_opacity_scale, dt_drawlayer_cache_patch_t *stroke_mask, dt_drawlayer_paint_stroke_t *runtime_private)
 Public dab rasterization entry point.
 
static float _brush_alpha_at (const dt_drawlayer_brush_runtime_view_t *const view, const int x, const int y)
 Per-pixel brush alpha, the part of the pixel context that owes nothing to the destination.
 
static float _brush_alpha_at_noise (const dt_drawlayer_brush_runtime_view_t *const view, const int x, const int y, const float raw_noise)
 As _brush_alpha_at, with the shared sprinkle field already sampled.
 
gboolean dt_drawlayer_brush_batch_is_uniform (const dt_drawlayer_brush_dab_t *dabs, const guint count, dt_drawlayer_brush_batch_t *out)
 Decide whether a run of dabs can take the batch path, and describe it if so.
 
gboolean dt_drawlayer_brush_rasterize_batch (const dt_drawlayer_brush_batch_t *batch, dt_drawlayer_cache_patch_t *patch, const float scale, dt_drawlayer_cache_patch_t *stroke_mask, float *const transmittance, float *const noise_scratch, dt_drawlayer_damaged_rect_t *batch_damage)
 Rasterize a whole batch in two passes: accumulate transmittance, then composite once.
 
gboolean dt_drawlayer_brush_rasterize_dab_argb8 (const dt_drawlayer_brush_dab_t *dab, uint8_t *argb, const int width, const int height, const int stride, const float center_x, const float center_y, const float opacity_multiplier)
 Render one dab to 8-bit ARGB surface for GUI cursor preview.
 
gboolean dt_drawlayer_brush_rasterize_dab_rgbaf (const dt_drawlayer_brush_dab_t *dab, float *rgba, const int width, const int height, const float center_x, const float center_y, const float opacity_multiplier, const float background_rgb[3])
 Rasterize a single dab preview in linear float RGBA over an opaque background.
 

Typedef Documentation

◆ dt_drawlayer_brush_pixel_eval_t

◆ dt_drawlayer_brush_runtime_view_t

◆ dt_drawlayer_sprinkle_preview_t

Function Documentation

◆ __attribute__()

static __attribute__ ( (always_inline)  )
inlinestatic

Bilinear RGBA sample from float buffer.

Multi-tap smudge source sample with directional jitter.

Note
Coordinates are clamped to valid image bounds.
Parameters
motion_dxMotion X used to orient anisotropic taps.
motion_dyMotion Y used to orient anisotropic taps.

Definition at line 505 of file iop/drawlayer/brush.c.

References dt_simd_set1(), fx, height, IS_NULL_PTR, MIN, width, and x.

◆ _apply_smudge_stroke_mode()

static dt_aligned_pixel_simd_t _apply_smudge_stroke_mode ( const float *  source_buffer,
const int  source_width,
const int  source_height,
const int  source_origin_x,
const int  source_origin_y,
dt_drawlayer_paint_stroke_t *  runtime_private,
const dt_drawlayer_brush_runtime_view_t *  view,
const float  scale,
const int  patch_origin_x,
const int  patch_origin_y,
const int  x,
const int  y,
const float  src_alpha,
const dt_aligned_pixel_simd_t  old_px 
)
static

◆ _brush_alpha_at()

static float _brush_alpha_at ( const dt_drawlayer_brush_runtime_view_t *const  view,
const int  x,
const int  y 
)
inlinestatic

Per-pixel brush alpha, the part of the pixel context that owes nothing to the destination.

Definition at line 851 of file iop/drawlayer/brush.c.

References _clamp01(), _sample_alpha_noise_raw(), dt_drawlayer_brush_profile_eval_fast(), view, and x.

Referenced by dt_drawlayer_brush_rasterize_batch().

◆ _brush_alpha_at_noise()

static float _brush_alpha_at_noise ( const dt_drawlayer_brush_runtime_view_t *const  view,
const int  x,
const int  y,
const float  raw_noise 
)
inlinestatic

As _brush_alpha_at, with the shared sprinkle field already sampled.

Definition at line 867 of file iop/drawlayer/brush.c.

References _clamp01(), dt_drawlayer_brush_profile_eval_fast(), view, and x.

Referenced by dt_drawlayer_brush_rasterize_batch().

◆ _brush_runtime_view_from_bounds()

◆ _brush_runtime_view_from_state()

static gboolean _brush_runtime_view_from_state ( const dt_drawlayer_paint_stroke_t *  stroke,
const dt_drawlayer_brush_dab_t *  dab,
const int  origin_x,
const int  origin_y,
const float  scale,
dt_drawlayer_brush_runtime_view_t *  view 
)
static

◆ _cell_hash01_from_seed()

static float _cell_hash01_from_seed ( const uint64_t  cell_seed,
const uint64_t  salt 
)
inlinestatic

Stable scalar hash in [0,1] from precomputed cell seed.

Definition at line 51 of file iop/drawlayer/brush.c.

References splitmix32().

Referenced by _cellular_grain_2d().

◆ _cellular_grain_2d()

static float _cellular_grain_2d ( const uint64_t  seed,
const float  x,
const float  y 
)
inlinestatic

Grain-like round cellular field. Peaks at grain centers, falls off radially.

Definition at line 57 of file iop/drawlayer/brush.c.

References _cell_hash01_from_seed(), _clamp01(), and x.

Referenced by _sprinkle_noise_at_pixel_precomputed().

◆ _clamp01()

◆ _estimate_alpha_noise_gain()

static float _estimate_alpha_noise_gain ( const dt_drawlayer_brush_dab_t *  dab,
const dt_drawlayer_brush_runtime_view_t *  view 
)
inlinestatic

Estimate per-dab texture gain so noise preserves average opacity across samples.

Definition at line 331 of file iop/drawlayer/brush.c.

References _sample_alpha_noise_raw(), IS_NULL_PTR, and view.

Referenced by dt_drawlayer_brush_rasterize(), and dt_drawlayer_brush_rasterize_batch().

◆ _lerpf()

static float _lerpf ( const float  a,
const float  b,
const float  t 
)
inlinestatic

Linear interpolation helper.

Definition at line 45 of file iop/drawlayer/brush.c.

References t.

Referenced by _sprinkle_octave_weights(), and _stroke_flow_alpha().

◆ _prepare_analytic_pixel_context()

static gboolean _prepare_analytic_pixel_context ( const dt_drawlayer_brush_runtime_view_t *  view,
const float  sample_opacity_scale,
float *  stroke_mask,
const int  stroke_mask_width,
const int  stroke_mask_height,
const int  x,
const int  y,
const float  old_alpha,
dt_drawlayer_brush_pixel_eval_t *  pixel_eval 
)
static

◆ _prepare_blur_context()

static gboolean _prepare_blur_context ( dt_aligned_pixel_simd_t *  blur_px,
const float *  buffer,
const int  width,
const int  height,
const int  source_origin_x,
const int  source_origin_y,
const int  patch_origin_x,
const int  patch_origin_y,
const dt_drawlayer_brush_runtime_view_t *  view 
)
static

Build blur gather color for current dab footprint.

Returns
TRUE when footprint contributed at least one weighted sample.

Definition at line 457 of file iop/drawlayer/brush.c.

References dt_drawlayer_brush_profile_eval_fast(), dt_simd_set1(), FALSE, height, IS_NULL_PTR, TRUE, view, width, and x.

Referenced by dt_drawlayer_brush_rasterize().

◆ _prepare_sprinkle_preview()

◆ _sample_alpha_noise_raw()

static float _sample_alpha_noise_raw ( const dt_drawlayer_brush_dab_t *  dab,
const dt_drawlayer_brush_runtime_view_t *  view,
const int  pixel_x,
const int  pixel_y 
)
inlinestatic

Resolve multiplicative alpha noise at one pixel.

Returns
Texture factor.

Definition at line 308 of file iop/drawlayer/brush.c.

References _sprinkle_noise_at_pixel_precomputed(), IS_NULL_PTR, and view.

Referenced by _brush_alpha_at(), _estimate_alpha_noise_gain(), _prepare_analytic_pixel_context(), and dt_drawlayer_brush_rasterize_batch().

◆ _sample_sprinkle_preview()

static float _sample_sprinkle_preview ( const dt_drawlayer_sprinkle_preview_t *  preview,
const float  px,
const float  py 
)
inlinestatic

◆ _smudge_deposit_alpha()

static float _smudge_deposit_alpha ( const float  src_alpha,
const float  carried_alpha,
const float  opacity 
)
inlinestatic

Resolve effective smudge deposit alpha for one pixel.

Definition at line 594 of file iop/drawlayer/brush.c.

References _clamp01().

Referenced by _apply_smudge_stroke_mode().

◆ _smudge_hash_signed()

static float _smudge_hash_signed ( const int  x,
const int  y,
const int  lane 
)
inlinestatic

Stable signed pseudo-random helper in [-1,1].

Definition at line 492 of file iop/drawlayer/brush.c.

References x.

◆ _sprinkle_noise_at_pixel_precomputed()

static float _sprinkle_noise_at_pixel_precomputed ( const float  px,
const float  py,
const float  scale,
const float  strength,
const float  w0,
const float  w1,
const float  w2,
const uint64_t  seed0,
const uint64_t  seed1,
const uint64_t  seed2 
)
inlinestatic

Evaluate sprinkle modulation from precomputed dab constants.

Definition at line 111 of file iop/drawlayer/brush.c.

References _cellular_grain_2d(), strength(), w1, w2, and x.

Referenced by _prepare_sprinkle_preview(), _sample_alpha_noise_raw(), and _sample_sprinkle_preview().

◆ _sprinkle_octave_weights()

static void _sprinkle_octave_weights ( const float  coarseness,
float *  w0,
float *  w1,
float *  w2 
)
inlinestatic

Resolve octave weights from coarseness control.

Definition at line 91 of file iop/drawlayer/brush.c.

References _clamp01(), _lerpf(), IS_NULL_PTR, t, w1, and w2.

Referenced by _brush_runtime_view_from_bounds(), and _prepare_sprinkle_preview().

◆ _stroke_flow_alpha()

static float _stroke_flow_alpha ( const dt_drawlayer_brush_dab_t *  dab,
const float  opacity,
const float  flow,
const float  sample_opacity_scale,
const float  profile,
const float  brush_alpha,
const float  old_alpha,
const float  stroke_old_alpha,
const gboolean  have_stroke_alpha 
)
inlinestatic

Compute per-pixel source alpha from opacity/flow model.

Assumptions:

  • flow uses internal brush convention (see caller conversion),
  • sample_opacity_scale already reflects spacing normalization.

Definition at line 365 of file iop/drawlayer/brush.c.

References _clamp01(), _lerpf(), DT_DRAWLAYER_BRUSH_MODE_BLUR, DT_DRAWLAYER_BRUSH_MODE_ERASE, DT_DRAWLAYER_BRUSH_MODE_SMUDGE, dt_drawlayer_brush_dab_t::mode, and void().

Referenced by _prepare_analytic_pixel_context().

◆ dt_drawlayer_brush_batch_is_uniform()

gboolean dt_drawlayer_brush_batch_is_uniform ( const dt_drawlayer_brush_dab_t *  dabs,
guint  count,
dt_drawlayer_brush_batch_t *  out 
)

Decide whether a run of dabs can take the batch path, and describe it if so.

Requires one mode across the run (PAINT or ERASE), one opacity, one colour, and UI Flow at 100% (internal flow 0). Those are the conditions under which the per-pixel stroke alpha collapses to a product of per-dab transmittance factors clamped once – see the derivation above dt_drawlayer_brush_rasterize_batch in brush.c. SMUDGE and BLUR never qualify: they read the destination per dab.

Returns
TRUE and fills out when the run qualifies, FALSE otherwise.

Definition at line 879 of file iop/drawlayer/brush.c.

References _clamp01(), dt_drawlayer_brush_dab_t::color, d, DT_DRAWLAYER_BRUSH_MODE_ERASE, DT_DRAWLAYER_BRUSH_MODE_PAINT, FALSE, dt_drawlayer_brush_dab_t::flow, i, IS_NULL_PTR, dt_drawlayer_brush_dab_t::mode, dt_drawlayer_brush_dab_t::opacity, out, dt_drawlayer_brush_dab_t::sprinkle_coarseness, dt_drawlayer_brush_dab_t::sprinkle_size, dt_drawlayer_brush_dab_t::sprinkles, dt_drawlayer_brush_dab_t::stroke_batch, and TRUE.

Referenced by _rasterize_pending_dab_batch(), _report_speedup(), _run_batch(), and test_gate_refuses_non_uniform().

◆ dt_drawlayer_brush_rasterize()

gboolean dt_drawlayer_brush_rasterize ( const dt_drawlayer_cache_patch_t *  sample_patch,
dt_drawlayer_cache_patch_t *  patch,
const float  scale,
const dt_drawlayer_brush_dab_t *  dab,
const float  sample_opacity_scale,
dt_drawlayer_cache_patch_t *  stroke_mask,
dt_drawlayer_paint_stroke_t *  runtime_private 
)

◆ dt_drawlayer_brush_rasterize_batch()

gboolean dt_drawlayer_brush_rasterize_batch ( const dt_drawlayer_brush_batch_t *  batch,
dt_drawlayer_cache_patch_t *  patch,
float  scale,
dt_drawlayer_cache_patch_t *  stroke_mask,
float *  transmittance,
float *  noise_scratch,
dt_drawlayer_damaged_rect_t *  batch_damage 
)

Rasterize a whole batch in two passes: accumulate transmittance, then composite once.

Parameters
batchUniform run from dt_drawlayer_brush_batch_is_uniform.
patchDestination premultiplied RGBA float patch (the heartbeat scratch).
scaleLayer-to-buffer scale factor, must be >0.
stroke_maskStroke-local alpha, same dimensions as patch. Read as the batch's starting alpha and overwritten with the batch's result.
transmittanceCaller-owned scratch plane of at least patch->width * patch->height floats. Contents on entry are irrelevant; the batch box is initialised.
noise_scratchOptional second plane of the same size. When the batch carries texture, the sprinkle field – a function of LAYER position alone, hence identical for every overlapping dab – is evaluated into it once instead of once per dab per pixel. NULL falls back to evaluating it per dab.
batch_damageOptional; the batch's footprint is unioned into it.
Returns
TRUE when at least one dab contributed.

Both passes are parallel over disjoint rows, so the result does not depend on the thread schedule – unlike the per-dab loop it replaces, whose tile locks excluded but did not order.

Definition at line 917 of file iop/drawlayer/brush.c.

References _brush_alpha_at(), _brush_alpha_at_noise(), _brush_runtime_view_from_bounds(), _clamp01(), _estimate_alpha_noise_gain(), _sample_alpha_noise_raw(), bbox, dt_drawlayer_brush_batch_t::cap, dt_drawlayer_brush_batch_t::color, dt_drawlayer_brush_batch_t::count, dt_drawlayer_brush_batch_t::dabs, DT_DRAWLAYER_BRUSH_MODE_ERASE, dt_drawlayer_paint_runtime_note_dab_damage(), dt_simd_set1(), dt_store_simd(), FALSE, dt_drawlayer_brush_dab_t::flow, height, dt_drawlayer_cache_patch_t::height, i, IS_NULL_PTR, MAX, MIN, dt_drawlayer_brush_batch_t::mode, dt_drawlayer_damaged_rect_t::nw, dt_drawlayer_brush_dab_t::opacity, dt_drawlayer_cache_patch_t::pixels, dt_drawlayer_brush_dab_t::radius, row, dt_drawlayer_damaged_rect_t::se, dt_drawlayer_brush_batch_t::sprinkles, t, TRUE, dt_drawlayer_damaged_rect_t::valid, view, views(), width, dt_drawlayer_cache_patch_t::width, x, dt_drawlayer_brush_dab_t::x, dt_drawlayer_cache_patch_t::x, dt_drawlayer_brush_dab_t::y, and dt_drawlayer_cache_patch_t::y.

Referenced by _rasterize_pending_dab_batch(), _report_speedup(), and _run_batch().

◆ dt_drawlayer_brush_rasterize_dab_argb8()

gboolean dt_drawlayer_brush_rasterize_dab_argb8 ( const dt_drawlayer_brush_dab_t *  dab,
uint8_t *  argb,
const int  width,
const int  height,
const int  stride,
const float  center_x,
const float  center_y,
const float  opacity_multiplier 
)

Render one dab to 8-bit ARGB surface for GUI cursor preview.

Rasterize a single dab preview into ARGB8 for GUI overlays.

Returns
TRUE on success.

Definition at line 1081 of file iop/drawlayer/brush.c.

References _clamp01(), _prepare_sprinkle_preview(), _sample_sprinkle_preview(), dt_drawlayer_brush_profile_eval(), FALSE, height, IS_NULL_PTR, dt_drawlayer_brush_dab_t::opacity, preview, dt_drawlayer_brush_dab_t::radius, TRUE, width, and x.

Referenced by _ensure_cursor_stamp_surface().

◆ dt_drawlayer_brush_rasterize_dab_rgbaf()

gboolean dt_drawlayer_brush_rasterize_dab_rgbaf ( const dt_drawlayer_brush_dab_t *  dab,
float *  rgba,
int  width,
int  height,
float  center_x,
float  center_y,
float  opacity_multiplier,
const float  background_rgb[3] 
)

Rasterize a single dab preview in linear float RGBA over an opaque background.

Parameters
dabInput dab descriptor.
rgbaDestination float RGBA buffer (width*height*4), filled in linear display RGB.
widthSurface width.
heightSurface height.
center_xDab center X in surface coordinates.
center_yDab center Y in surface coordinates.
opacity_multiplierAdditional UI-time opacity scalar in [0,1].
background_rgbOpaque linear RGB background color, or NULL for white.
Returns
TRUE on success, FALSE on invalid inputs.

Definition at line 1134 of file iop/drawlayer/brush.c.

References _clamp01(), _prepare_sprinkle_preview(), _sample_sprinkle_preview(), dt_drawlayer_brush_profile_eval(), FALSE, height, i, IS_NULL_PTR, dt_drawlayer_brush_dab_t::opacity, preview, dt_drawlayer_brush_dab_t::radius, TRUE, width, and x.

Referenced by _render_brush_profile_cell().