76 Image *ima_ =
nullptr;
77 ImBuf *ibuf_ =
nullptr;
78 void *lock_ =
nullptr;
85 return ibuf_ !=
nullptr;
98 size_ = {ibuf_->
x, ibuf_->
y};
121 return this->size_.x;
126 return this->size_.y;
131 return c.x >= 0 && c.x < this->size_.x && c.y >= 0 && c.y < this->size_.y;
136 const div_t d = div(index, this->size_.x);
137 return int2{d.rem, d.quot};
142 return c.x + c.y * this->size_.x;
157 return this->data_[index_from_coord(c)];
162 return this->data_[index_from_coord(c)];
168 return (color.
r &
flag) != 0;
173 color.
r =
value ? (color.
r |
flag) : (color.
r & (~flag));
181 const bool is_stroke = color.r > 0.0f;
182 const bool is_seed = color.g > 0.0f;
193 constexpr const ColorGeometry4b output_stroke_color = {255, 0, 0, 255};
194 constexpr const ColorGeometry4b output_seed_color = {127, 127, 0, 255};
195 constexpr const ColorGeometry4b output_border_color = {0, 0, 255, 255};
196 constexpr const ColorGeometry4b output_fill_color = {127, 255, 0, 255};
199 constexpr const ColorGeometry4b output_debug_color = {255, 127, 0, 255};
203 std::min(
int(a.
g) +
int(
b.g), 255),
204 std::min(
int(a.
b) +
int(
b.b), 255),
205 std::min(
int(a.
a) +
int(
b.a), 255));
211 output_color = add_colors(output_color, output_debug_color);
214 output_color = add_colors(output_color, output_fill_color);
217 output_color = add_colors(output_color, output_stroke_color);
220 output_color = add_colors(output_color, output_border_color);
223 output_color = add_colors(output_color, output_seed_color);
225 color = std::move(output_color);
237 row_start += buffer.
width();
242 row_start += buffer.
width();
262template<FillBorderMode border_mode>
266 const int width = buffer.
width();
267 const int height = buffer.
height();
273 active_pixels.
push(i);
277 enum FilterDirection {
282 bool border_contact =
false;
284 const int index = active_pixels.
pop();
290 border_contact =
true;
296 border_contact =
true;
316 std::min(width - 1 - coord.x, leak_filter_width));
319 std::min(height - 1 - coord.y, leak_filter_width));
320 bool is_boundary_horizontal =
false;
321 bool is_boundary_vertical =
false;
322 for (
const int filter_i : filter_y_neg) {
326 for (
const int filter_i : filter_y_pos) {
330 for (
const int filter_i : filter_x_neg) {
334 for (
const int filter_i : filter_x_pos) {
340 if (coord.x > 0 && !is_boundary_horizontal) {
343 if (coord.x < width - 1 && !is_boundary_horizontal) {
346 if (coord.y > 0 && !is_boundary_vertical) {
349 if (coord.y < height - 1 && !is_boundary_vertical) {
383 for ([[maybe_unused]]
const int iter :
IndexRange(iterations)) {
396 active_pixels.
push(i);
402 const int index = active_pixels.
pop();
413 for ([[maybe_unused]]
const int iter :
IndexRange(iterations)) {
426 active_pixels.
push(i);
432 const int index = active_pixels.
pop();
458 using BoundarySection = std::list<int>;
462 const int width = buffer.
width();
463 const int height = buffer.
height();
467 constexpr const uint8_t start_direction = 3;
468 auto find_start_coordinates = [&]() -> BoundaryStartMap {
469 BoundaryStartMap starts;
478 if (!filled_left && filled_right && !border_right) {
480 starts.add(index_right, {});
483 if (!include_holes) {
492 struct NeighborIterator {
498 auto find_next_neighbor = [&](NeighborIterator &iter) ->
bool {
503 const int neighbor_dir =
wrap_dir_3n(iter.direction + 5 + i);
514 iter.index = neighbor_index;
515 iter.direction = neighbor_dir;
522 BoundaryStartMap boundary_starts = find_start_coordinates();
525 for (
const int start_index : boundary_starts.keys()) {
527 if (!boundary_starts.contains(start_index)) {
530 BoundarySection §ion = boundary_starts.lookup(start_index);
531 section.push_back(start_index);
532 NeighborIterator iter = {start_index, start_direction};
533 while (find_next_neighbor(iter)) {
535 if (iter.index == start_index) {
540 if (boundary_starts.contains(iter.index)) {
541 BoundarySection &next_section = boundary_starts.lookup(iter.index);
542 if (next_section.empty()) {
544 boundary_starts.remove(iter.index);
548 section.splice(section.end(), next_section);
549 boundary_starts.remove(iter.index);
554 section.push_back(iter.index);
557 if (iter.index != start_index) {
558 boundary_starts.remove(start_index);
564 for (
const BoundarySection §ion : boundary_starts.values()) {
566 for (
const int index : section) {
572 return final_boundary;
583 const int material_index,
584 const float hardness)
598 "curve_type",
"material_index",
"cyclic",
"hardness",
"fill_opacity"};
626 cyclic.
span.fill(
true);
627 materials.
span.fill(material_index);
628 hardnesses.span.fill(hardness);
635 fill_opacities.finish();
638 const int pixel_index = boundary.
pixels[point_i];
640 const float2 region_coord =
643 positions[point_i] = position;
647 constexpr const float pressure = 1.0f;
661 if (use_vertex_color) {
667 skip_curve_attributes.
add(
"fill_color");
671 fill_colors.
span.fill(vertex_color);
675 skip_point_attributes.
add(
"vertex_color");
679 vertex_colors.
span.fill(vertex_color);
706 const int stroke_material_index,
707 const float stroke_hardness,
709 const bool output_as_colors)
711 constexpr const int leak_filter_width = 3;
716 if (output_as_colors) {
747 if (dilate_pixels > 0) {
748 dilate(buffer, dilate_pixels);
750 else if (dilate_pixels < 0) {
751 erode(buffer, -dilate_pixels);
756 const bool fill_holes =
invert;
766 stroke_material_index,
777 const bool is_boundary_layer,
785 auto is_visible_curve = [&](
const int curve_i) {
788 if (points.
size() < 2) {
794 materials[curve_i] + 1);
797 if (gp_style ==
nullptr || is_hidden_material) {
805 if (is_boundary_layer) {
811 if (!is_visible_curve(curve_i)) {
814 const bool is_boundary_stroke = fill_guides[curve_i];
815 return is_boundary_stroke;
828 const std::optional<float> alpha_threshold)
830 if (!alpha_threshold) {
836 for (const int curve_i : range) {
837 const Material *material = BKE_object_material_get(const_cast<Object *>(&object),
838 materials[curve_i] + 1);
839 const float material_alpha = material && material->gp_style ?
840 material->gp_style->stroke_rgba[3] :
842 const IndexRange points = curves.points_by_curve()[curve_i];
843 for (const int point_i : points) {
844 const float alpha = (material_alpha * opacities[point_i] > *alpha_threshold ? 1.0f : 0.0f);
845 colors[point_i] = ColorGeometry4f(tint_color.r, tint_color.g, tint_color.b, alpha);
864 const Object &object_eval,
871 std::optional<Bounds<float2>> boundary_bounds;
879 const Layer &layer = *grease_pencil.layers()[
info.layer_index];
882 bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
883 &object_eval,
object,
info.drawing);
884 const bool only_boundary_strokes = boundary_layers[
info.layer_index];
895 object,
info, only_boundary_strokes, curve_mask_memory);
900 if (points.
size() < 2) {
904 const int material_index = materials[curve_i];
911 if (only_boundary_strokes && !is_boundary_stroke[curve_i]) {
915 for (
const int point_i : points) {
924 boundary_bounds = bounds::merge(boundary_bounds, {point_bounds});
930 return boundary_bounds;
938 const bool uniform_zoom,
939 const float max_zoom_factor,
941 const float pixel_scale)
946 const int2 min_image_size =
int2(128, 128);
948 switch (fit_method) {
949 case FillToolFitMethod::None:
950 return std::make_tuple(
float2(1.0f),
float2(0.0f), min_image_size, float3x3::identity());
952 case FillToolFitMethod::FitToView: {
962 if (!boundary_bounds) {
963 return std::make_tuple(
float2(1.0f),
float2(0.0f), min_image_size, float3x3::identity());
984 fill_bounds.
center() - 0.5f * region_bounds.
size() * zoom.x,
985 fill_bounds.
center() + 0.5f * region_bounds.
size() * zoom.y};
989 region_bounds.
size());
994 return std::make_tuple(zoom, offset, image_size, image_to_region);
998 return std::make_tuple(
float2(1.0f),
float2(0.0f), min_image_size, float3x3::identity());
1007 const int2 &image_size,
1008 const std::optional<float> alpha_threshold,
1009 const float2 &fill_point,
1030 const float3 fill_point_layer = placement.
project(fill_point);
1035 BLI_SCOPED_DEFER([&]() { image_render::region_reset(region, region_view_data); });
1037 GPUOffScreen *offscreen_buffer = image_render::image_render_begin(image_size);
1038 if (offscreen_buffer ==
nullptr) {
1042 const bool use_xray =
false;
1046 const float4x4 layer_to_view = world_to_view * layer_to_world;
1050 image_render::compute_view_matrices(view_context,
scene, image_size, zoom, offset);
1051 ed::greasepencil::image_render::set_projection_matrix(rv3d);
1054 const float mouse_dot_size = 4.0f;
1055 image_render::draw_dot(layer_to_view, fill_point_layer, mouse_dot_size,
draw_seed_color);
1058 const Layer &layer = *grease_pencil.layers()[
info.layer_index];
1059 if (!layer.is_visible()) {
1063 const bool is_boundary_layer = boundary_layers[
info.layer_index];
1072 object,
info, is_boundary_layer, curve_mask_memory);
1075 info.drawing.strokes(),
1081 image_render::draw_grease_pencil_strokes(rv3d,
1097 const float line_width = 1.0f;
1099 image_render::draw_lines(world_to_view,
1108 ed::greasepencil::image_render::clear_projection_matrix();
1112 return image_render::image_render_end(*view_context.
bmain, offscreen_buffer);
1122 const std::optional<float> alpha_threshold,
1123 const float2 &fill_point,
1126 const int stroke_material_index,
1127 const bool keep_images)
1138 const bool uniform_zoom =
true;
1139 const float max_zoom_factor = 5.0f;
1143 const auto [zoom, offset, image_size, image_to_region] =
fit_strokes_to_view(view_context,
1176 const float stroke_hardness = 1.0f;
1184 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.
Material * BKE_object_material_get(Object *ob, short act)
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
#define BLI_SCOPED_DEFER(function_to_defer)
#define ENUM_OPERATORS(_type, _max)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
Object is a sort of wrapper for general info.
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)
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
constexpr IndexRange index_range() const
constexpr void copy_from(Span< T > values) 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)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
void update_curve_types()
MutableSpan< int8_t > curve_types_for_write()
MutableAttributeAccessor attributes_for_write()
IndexRange points_range() const
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
float4x4 to_world_space(const Object &object) const
bool use_project_to_surface() const
void cache_viewport_depths(Depsgraph *depsgraph, ARegion *region, View3D *view3d)
bool use_project_to_stroke() const
float4x4 to_world_space() const
float3 project_with_shift(float2 co) const
float3 project(float2 co, bool &clipped) 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
const Depsgraph * depsgraph
VecBase< float, 2 > float2
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const 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_is_fill_guide
constexpr const char * attr_material_index
static Bounds< float2 > get_region_bounds(const ARegion ®ion)
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 std::optional< Bounds< float2 > > 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 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 float3x3 &image_to_region, const int material_index, const float hardness)
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, const float pixel_scale)
static bke::CurvesGeometry process_image(Image &ima, const Scene &scene, const ViewContext &view_context, const Brush &brush, const ed::greasepencil::DrawingPlacement &placement, const float3x3 &image_to_region, const int stroke_material_index, const float stroke_hardness, const bool invert, const bool output_as_colors)
static Image * render_strokes(const ViewContext &view_context, const Brush &brush, const Scene &scene, const bke::greasepencil::Layer &layer, const VArray< bool > &boundary_layers, const Span< DrawingInfo > src_drawings, const int2 &image_size, const std::optional< float > alpha_threshold, const float2 &fill_point, const ExtensionData &extensions, const ed::greasepencil::DrawingPlacement &placement, const float2 &zoom, const float2 &offset)
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)
bool brush_using_vertex_color(const GpPaint *gp_paint, const Brush *brush)
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)
MatT from_loc_scale(const typename MatT::loc_type &location, const VecBase< typename MatT::base_type, ScaleDim > &scale)
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, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
struct BrushGpencilSettings * gpencil_settings
ImBufByteBuffer byte_buffer
struct MaterialGPencilStyle * gp_style
struct ToolSettings * toolsettings
VecBase< T, 2 > xy() const
MutableVArraySpan< T > span
struct blender::ed::greasepencil::ExtensionData::@269 lines
Vector< int > offset_indices