73 Image *ima_ =
nullptr;
74 ImBuf *ibuf_ =
nullptr;
75 void *lock_ =
nullptr;
82 return ibuf_ !=
nullptr;
95 size_ = {ibuf_->
x, ibuf_->
y};
118 return this->size_.x;
123 return this->size_.y;
128 return c.x >= 0 && c.x < this->size_.x && c.y >= 0 && c.y < this->size_.y;
133 const div_t d = div(index, this->size_.x);
134 return int2{d.rem, d.quot};
139 return c.x + c.y * this->size_.x;
154 return this->data_[index_from_coord(c)];
159 return this->data_[index_from_coord(c)];
165 return (color.r &
flag) != 0;
170 color.r = value ? (color.r |
flag) : (color.r & (~flag));
178 const bool is_stroke = color.r > 0.0f;
179 const bool is_seed = color.g > 0.0f;
190 constexpr const ColorGeometry4b output_stroke_color = {255, 0, 0, 255};
191 constexpr const ColorGeometry4b output_seed_color = {127, 127, 0, 255};
192 constexpr const ColorGeometry4b output_border_color = {0, 0, 255, 255};
193 constexpr const ColorGeometry4b output_fill_color = {127, 255, 0, 255};
196 constexpr const ColorGeometry4b output_debug_color = {255, 127, 0, 255};
200 std::min(
int(a.g) +
int(
b.g), 255),
201 std::min(
int(a.b) +
int(
b.b), 255),
202 std::min(
int(a.a) +
int(
b.a), 255));
208 output_color = add_colors(output_color, output_debug_color);
211 output_color = add_colors(output_color, output_fill_color);
214 output_color = add_colors(output_color, output_stroke_color);
217 output_color = add_colors(output_color, output_border_color);
220 output_color = add_colors(output_color, output_seed_color);
222 color = std::move(output_color);
234 row_start += buffer.
width();
239 row_start += buffer.
width();
259template<FillBorderMode border_mode>
263 const int width = buffer.
width();
264 const int height = buffer.
height();
268 for (
const int i : pixels.index_range()) {
270 active_pixels.
push(i);
274 enum FilterDirection {
279 bool border_contact =
false;
281 const int index = active_pixels.
pop();
287 border_contact =
true;
293 border_contact =
true;
313 std::min(width - 1 - coord.x, leak_filter_width));
316 std::min(height - 1 - coord.y, leak_filter_width));
317 bool is_boundary_horizontal =
false;
318 bool is_boundary_vertical =
false;
319 for (
const int filter_i : filter_y_neg) {
323 for (
const int filter_i : filter_y_pos) {
327 for (
const int filter_i : filter_x_neg) {
331 for (
const int filter_i : filter_x_pos) {
337 if (coord.x > 0 && !is_boundary_horizontal) {
340 if (coord.x < width - 1 && !is_boundary_horizontal) {
343 if (coord.y > 0 && !is_boundary_vertical) {
346 if (coord.y < height - 1 && !is_boundary_vertical) {
380 for ([[maybe_unused]]
const int iter :
IndexRange(iterations)) {
381 for (
const int i : pixels.index_range()) {
393 active_pixels.
push(i);
399 const int index = active_pixels.
pop();
410 for ([[maybe_unused]]
const int iter :
IndexRange(iterations)) {
411 for (
const int i : pixels.index_range()) {
423 active_pixels.
push(i);
429 const int index = active_pixels.
pop();
455 using BoundarySection = std::list<int>;
459 const int width = buffer.
width();
460 const int height = buffer.
height();
464 constexpr const uint8_t start_direction = 3;
465 auto find_start_coordinates = [&]() -> BoundaryStartMap {
466 BoundaryStartMap starts;
475 if (!filled_left && filled_right && !border_right) {
477 starts.add(index_right, {});
480 if (!include_holes) {
489 struct NeighborIterator {
495 auto find_next_neighbor = [&](NeighborIterator &iter) ->
bool {
500 const int neighbor_dir =
wrap_dir_3n(iter.direction + 5 + i);
511 iter.index = neighbor_index;
512 iter.direction = neighbor_dir;
519 BoundaryStartMap boundary_starts = find_start_coordinates();
522 for (
const int start_index : boundary_starts.keys()) {
524 if (!boundary_starts.contains(start_index)) {
527 BoundarySection §ion = boundary_starts.lookup(start_index);
528 section.push_back(start_index);
529 NeighborIterator iter = {start_index, start_direction};
530 while (find_next_neighbor(iter)) {
532 if (iter.index == start_index) {
537 if (boundary_starts.contains(iter.index)) {
538 BoundarySection &next_section = boundary_starts.lookup(iter.index);
539 if (next_section.empty()) {
541 boundary_starts.remove(iter.index);
545 section.splice(section.end(), next_section);
546 boundary_starts.remove(iter.index);
551 section.push_back(iter.index);
554 if (iter.index != start_index) {
555 boundary_starts.remove(start_index);
561 for (
const BoundarySection §ion : boundary_starts.values()) {
563 for (
const int index : section) {
569 return final_boundary;
579 const int material_index,
580 const float hardness)
583 if (boundary.offset_indices.is_empty() || boundary.pixels.is_empty()) {
589 curves.offsets_for_write().copy_from(boundary.offset_indices);
594 "curve_type",
"material_index",
"cyclic",
"hardness",
"fill_opacity"};
598 curves.update_curve_types();
621 cyclic.
span.fill(
true);
622 materials.span.fill(material_index);
623 hardnesses.span.fill(hardness);
630 fill_opacities.finish();
632 for (
const int point_i : curves.points_range()) {
633 const int pixel_index = boundary.pixels[point_i];
636 positions[point_i] = position;
640 constexpr const float pressure = 1.0f;
658 skip_curve_attributes.
add(
"fill_color");
662 fill_colors.
span.fill(vertex_color);
666 skip_point_attributes.
add(
"vertex_color");
668 attributes.lookup_or_add_for_write_span<
ColorGeometry4f>(
"vertex_color",
670 vertex_colors.
span.fill(vertex_color);
682 curves.curves_range());
686 curves.points_range());
696 const int stroke_material_index,
697 const float stroke_hardness,
699 const bool output_as_colors)
701 constexpr const int leak_filter_width = 3;
706 if (output_as_colors) {
737 if (dilate_pixels > 0) {
738 dilate(buffer, dilate_pixels);
740 else if (dilate_pixels < 0) {
741 erode(buffer, -dilate_pixels);
746 const bool fill_holes =
invert;
755 stroke_material_index,
766 const bool is_boundary_layer,
774 auto is_visible_curve = [&](
const int curve_i) {
777 if (points.size() < 2) {
783 materials[curve_i] + 1);
787 if (gp_style ==
nullptr || is_hidden_material || !is_stroke_material) {
795 if (is_boundary_layer) {
796 const VArray<bool> boundary_strokes = *attributes.lookup_or_default<
bool>(
801 if (!is_visible_curve(curve_i)) {
804 const bool is_boundary_stroke = boundary_strokes[curve_i];
805 return is_boundary_stroke;
818 const std::optional<float> alpha_threshold)
820 if (!alpha_threshold) {
826 for (const int curve_i : range) {
827 const Material *material = BKE_object_material_get(const_cast<Object *>(&object),
828 materials[curve_i] + 1);
829 const float material_alpha = material && material->gp_style ?
830 material->gp_style->stroke_rgba[3] :
832 const IndexRange points = curves.points_by_curve()[curve_i];
833 for (const int point_i : points) {
834 const float alpha = (material_alpha * opacities[point_i] > *alpha_threshold ? 1.0f : 0.0f);
835 colors[point_i] = ColorGeometry4f(tint_color.r, tint_color.g, tint_color.b, alpha);
846 BLI_rctf_init(®ion_bounds, 0, region.winx, 0, region.winy);
847 return region_bounds;
856 const Object &object_eval,
872 const Layer &layer = *grease_pencil.layers()[info.layer_index];
873 const float4x4 layer_to_world = layer.to_world_space(
object);
875 bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
876 &object_eval,
object, info.layer_index, info.frame_number);
877 const bool only_boundary_strokes = boundary_layers[info.layer_index];
882 bke::AttrDomain::Curve);
883 const VArray<bool> is_boundary_stroke = *attributes.lookup_or_default<
bool>(
884 "is_boundary", bke::AttrDomain::Curve,
false);
888 object, info, only_boundary_strokes, curve_mask_memory);
893 if (points.size() < 2) {
897 const int material_index = materials[curve_i];
904 if (only_boundary_strokes && !is_boundary_stroke[curve_i]) {
908 for (
const int point_i : points) {
910 deformation.positions[point_i]);
932 const bool uniform_zoom,
933 const float max_zoom_factor,
939 switch (fit_method) {
940 case FillToolFitMethod::None:
943 case FillToolFitMethod::FitToView: {
958 const float2 fill_bounds_min =
math::min(bounds_min, fill_point) - margin;
959 const float2 fill_bounds_max =
math::max(bounds_max, fill_point) + margin;
960 const float2 fill_bounds_center = 0.5f * (fill_bounds_min + fill_bounds_max);
961 const float2 fill_bounds_extent = fill_bounds_max - fill_bounds_min;
965 const float2 region_center = 0.5f * (region_min + region_max);
966 const float2 region_extent = region_max - region_min;
975 const float2 offset_center = fill_bounds_center - region_center;
976 const float2 offset_min = fill_point + 0.5f * fill_bounds_extent - region_center;
977 const float2 offset_max = fill_point - 0.5f * fill_bounds_extent - region_center;
979 fill_point.x < bounds_min.x ?
981 (fill_point.x > bounds_max.x ? offset_max.x : offset_center.x),
982 fill_point.y < bounds_min.y ?
984 (fill_point.y > bounds_max.y ? offset_max.y : offset_center.y));
987 return std::make_pair(zoom, offset);
1001 const std::optional<float> alpha_threshold,
1002 const float2 &fill_point,
1005 const int stroke_material_index,
1006 const bool keep_images)
1021 const bool uniform_zoom =
true;
1022 const float max_zoom_factor = 5.0f;
1033 const float radius_scale = 0.5f;
1035 constexpr const int min_image_size = 128;
1038 const int2 region_size =
int2(region.winx, region.winy);
1039 const int2 image_size =
math::max(region_size * pixel_scale,
int2(min_image_size));
1043 offset *
float2(region_size),
1045 float2(region_size) * 0.5f) *
1051 BLI_SCOPED_DEFER([&]() { image_render::region_reset(region, region_view_data); });
1053 GPUOffScreen *offscreen_buffer = image_render::image_render_begin(image_size);
1054 if (offscreen_buffer ==
nullptr) {
1058 const bool use_xray =
false;
1060 const float4x4 layer_to_world = layer.to_world_space(
object);
1062 const float4x4 layer_to_view = world_to_view * layer_to_world;
1067 image_render::compute_view_matrices(view_context, scene, image_size, zoom, offset);
1068 ed::greasepencil::image_render::set_projection_matrix(rv3d);
1071 const float mouse_dot_size = 4.0f;
1072 const float3 fill_point_layer = placement.
project(fill_point_image);
1073 image_render::draw_dot(layer_to_view, fill_point_layer, mouse_dot_size,
draw_seed_color);
1076 const Layer &layer = *grease_pencil.layers()[info.layer_index];
1077 if (!layer.is_visible()) {
1080 const float4x4 layer_to_world = layer.to_world_space(
object);
1081 const bool is_boundary_layer = boundary_layers[info.layer_index];
1086 bke::AttrDomain::Curve);
1090 object, info, is_boundary_layer, curve_mask_memory);
1093 info.drawing.strokes(),
1099 image_render::draw_grease_pencil_strokes(rv3d,
1115 const float line_width = 1.0f;
1117 image_render::draw_lines(world_to_view,
1126 ed::greasepencil::image_render::clear_projection_matrix();
1130 Image *ima = image_render::image_render_end(*view_context.
bmain, offscreen_buffer);
1136 const float stroke_hardness = 1.0f;
1143 stroke_material_index,
Camera data-block and utility functions.
Low-level operations for curves.
Low-level operations for grease pencil.
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_id_free(Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
#define BLI_SCOPED_DEFER(function_to_defer)
void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b)
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size)
void BLI_rctf_init_minmax(struct rctf *rect)
#define ENUM_OPERATORS(_type, _max)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ GP_MATERIAL_STROKE_SHOW
Object is a sort of wrapper for general info.
@ GPPAINT_FLAG_USE_VERTEXCOLOR
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
eV3DProjStatus ED_view3d_project_float_global(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void GPU_blend(eGPUBlend blend)
void GPU_depth_mask(bool depth)
Contains defines and structs used throughout the imbuf module.
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr IndexRange drop_front(int64_t n) const
void push(const T &value)
static VArray ForContainer(ContainerT container)
static VArray ForSingle(T value, const int64_t size)
void append(const T &value)
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
AttributeAccessor attributes() const
const bke::CurvesGeometry & strokes() const
float3 project(float2 co) const
float4x4 to_world_space() const
MutableSpan< ColorGeometry4b > pixels()
Span< ColorGeometry4b > pixels() const
ColorGeometry4b & pixel_from_coord(const int2 &c)
int2 coord_from_index(const int index) const
int index_from_coord(const int2 &c) const
bool is_valid_coord(const int2 &c) const
const ColorGeometry4b & pixel_from_coord(const int2 &c) const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
void foreach_index(Fn &&fn) const
local_group_size(16, 16) .push_constant(Type b
const Depsgraph * depsgraph
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes, AttrDomain domain, const AttributeFilter &attribute_filter, IndexRange range)
static FillBoundary build_fill_boundary(const ImageBufferAccessor &buffer, bool include_holes)
static IndexMask get_visible_boundary_strokes(const Object &object, const DrawingInfo &info, const bool is_boundary_layer, IndexMaskMemory &memory)
static const int2 offset_by_direction[num_directions]
constexpr const char * attr_material_index
static void dilate(ImageBufferAccessor &buffer, int iterations=1)
float opacity_from_input_sample(const float pressure, const Brush *brush, const BrushGpencilSettings *settings)
FillResult flood_fill(ImageBufferAccessor &buffer, const int leak_filter_width=0)
static void erode(ImageBufferAccessor &buffer, int iterations=1)
const ColorGeometry4f draw_boundary_color
static int wrap_dir_3n(const int dir)
bke::CurvesGeometry fill_strokes(const ViewContext &view_context, const Brush &brush, const Scene &scene, const bke::greasepencil::Layer &layer, const VArray< bool > &boundary_layers, Span< DrawingInfo > src_drawings, bool invert, const std::optional< float > alpha_threshold, const float2 &fill_point, const ExtensionData &extensions, FillToolFitMethod fit_method, int stroke_material_index, bool keep_images)
constexpr const int num_directions
float radius_from_input_sample(const RegionView3D *rv3d, const ARegion *region, const Brush *brush, const float pressure, const float3 location, const float4x4 to_world, const BrushGpencilSettings *settings)
static VArray< ColorGeometry4f > get_stroke_colors(const Object &object, const bke::CurvesGeometry &curves, const VArray< float > &opacities, const VArray< int > materials, const ColorGeometry4f &tint_color, const std::optional< float > alpha_threshold)
static void mark_borders(ImageBufferAccessor &buffer)
static rctf get_region_bounds(const ARegion ®ion)
static void convert_colors_to_flags(ImageBufferAccessor &buffer)
static bke::CurvesGeometry boundary_to_curves(const Scene &scene, const ViewContext &view_context, const Brush &brush, const FillBoundary &boundary, const ImageBufferAccessor &buffer, const ed::greasepencil::DrawingPlacement &placement, const int material_index, const float hardness)
constexpr const char * attr_is_boundary
static rctf get_boundary_bounds(const ARegion ®ion, const RegionView3D &rv3d, const Object &object, const Object &object_eval, const VArray< bool > &boundary_layers, const Span< DrawingInfo > src_drawings)
static auto fit_strokes_to_view(const ViewContext &view_context, const VArray< bool > &boundary_layers, const Span< DrawingInfo > src_drawings, const FillToolFitMethod fit_method, const float2 fill_point, const bool uniform_zoom, const float max_zoom_factor, const float2 margin)
static void convert_flags_to_colors(ImageBufferAccessor &buffer)
static void set_flag(ColorGeometry4b &color, const ColorFlag flag, bool value)
const ColorGeometry4f draw_seed_color
static bool get_flag(const ColorGeometry4b &color, const ColorFlag flag)
static void invert_fill(ImageBufferAccessor &buffer)
static bke::CurvesGeometry process_image(Image &ima, const Scene &scene, const ViewContext &view_context, const Brush &brush, const ed::greasepencil::DrawingPlacement &placement, const int stroke_material_index, const float stroke_hardness, const bool invert, const bool output_as_colors)
T clamp(const T &a, const T &min, const T &max)
T safe_divide(const T &a, const T &b)
T reduce_max(const VecBase< T, Size > &a)
T min(const T &a, const T &b)
T max(const T &a, const T &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
struct BrushGpencilSettings * gpencil_settings
ImBufByteBuffer byte_buffer
struct MaterialGPencilStyle * gp_style
MutableVArraySpan< T > span
const bke::greasepencil::Drawing & drawing
struct blender::ed::greasepencil::ExtensionData::@345 lines
Vector< int > offset_indices