47# include "potracelib.h"
74 bool *stop, *do_update;
91 bool use_current_frame;
97 TurnPolicy turnpolicy;
101 int foreground_material_index;
102 int background_material_index;
107 void ensure_output_object();
110void TraceJob::ensure_output_object()
115 if (this->ob_grease_pencil ==
nullptr) {
116 const ushort local_view_bits = (this->v3d && this->v3d->localvd) ? this->v3d->local_view_uid :
123 this->ob_active->loc,
124 this->ob_active->rot,
127 copy_v3_v3(this->ob_grease_pencil->scale, this->ob_active->scale);
128 this->was_ob_created =
true;
133 this->layer = grease_pencil.get_active_layer();
134 if (this->layer ==
nullptr) {
135 Layer &new_layer = grease_pencil.add_layer(
DATA_(
"Trace"));
136 grease_pencil.set_active_layer(&new_layer);
137 this->layer = &new_layer;
141static float4x4 pixel_to_object_transform(
const Object &image_object,
145 const float3 pixel_center_3d =
float3(pixel_center.x, pixel_center.y, 0);
149 const float3 image_aspect_3d = (ibuf.
x > ibuf.
y ?
float3(1,
float(ibuf.
y) /
float(ibuf.
x), 1) :
156 return to_normalized;
159static int ensure_foreground_material(Main *bmain,
Object *ob,
const StringRefNull
name)
171static int ensure_background_material(Main *bmain,
Object *ob,
const StringRefNull
name)
186static bke::CurvesGeometry grease_pencil_trace_image(TraceJob &trace_job,
const ImBuf &ibuf)
195 image_trace::TraceParams
params;
196 params.size_threshold = 0;
197 params.turn_policy = trace_job.turnpolicy;
202 const StringRef hole_attribute_id =
"is_hole";
205 const float4x4 transform = pixel_to_object_transform(*trace_job.ob_active, ibuf);
207 *trace, hole_attribute_id, transform);
213 "ensure_foreground_material must be called on the main thread");
215 "ensure_background_material must be called on the main thread");
216 const VArraySpan<bool> holes = *attributes.
lookup<
bool>(hole_attribute_id);
220 for (const int curve_i : range) {
221 const bool is_hole = holes[curve_i];
222 material_indices.span[curve_i] = (is_hole ? trace_job.background_material_index :
223 trace_job.foreground_material_index);
226 material_indices.
finish();
228 attributes.
remove(hole_attribute_id);
233 radii.
span.fill(trace_job.radius);
241 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
243 trace_job.stop = &worker_status->
stop;
244 trace_job.do_update = &worker_status->
do_update;
245 trace_job.progress = &worker_status->
progress;
246 trace_job.was_canceled =
false;
247 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0, 0);
252 if (trace_job.image->source ==
IMA_SRC_FILE || trace_job.mode == TraceMode::Single) {
253 ImageUser &iuser = *trace_job.ob_active->iuser;
254 trace_job.traced_curves.reinitialize(1);
256 iuser.
framenr = ((trace_job.frame_number == 0) || (trace_job.frame_number > iuser.
frames)) ?
258 trace_job.frame_number;
262 trace_job.traced_curves.first() = grease_pencil_trace_image(trace_job, *ibuf);
264 *(trace_job.progress) = 1.0f;
268 trace_job.mode = TraceMode::Single;
272 ImageUser &iuser = *trace_job.ob_active->iuser;
273 const int num_frames = iuser.
frames - init_frame + 1;
274 trace_job.traced_curves.reinitialize(num_frames);
277 trace_job.was_canceled =
true;
281 const int frame_number = init_frame +
i;
282 *(trace_job.progress) =
float(frame_number) /
float(iuser.
frames);
290 trace_job.traced_curves[
i] = grease_pencil_trace_image(trace_job, *ibuf);
296 trace_job.success = !trace_job.was_canceled;
298 worker_status->
stop =
false;
301static void trace_end_job(
void *customdata)
303 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
306 auto ensure_drawing_at_frame = [&](
const int frame_number) {
307 const std::optional<int> start_frame = trace_job.layer->start_frame_at(frame_number);
308 if (start_frame && *start_frame == frame_number) {
309 return grease_pencil.get_editable_drawing_at(*trace_job.layer, frame_number);
311 return grease_pencil.insert_frame(*trace_job.layer, frame_number);
316 switch (trace_job.mode) {
317 case TraceMode::Single: {
318 BLI_assert(trace_job.traced_curves.size() == 1);
325 case TraceMode::Sequence: {
326 const ImageUser &iuser = *trace_job.ob_active->iuser;
327 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0,
329 const int num_frames = iuser.
frames - init_frame + 1;
330 BLI_assert(trace_job.traced_curves.size() == num_frames);
332 const int frame_number = init_frame +
i;
343 if ((trace_job.was_canceled) && (trace_job.was_ob_created) && (trace_job.ob_grease_pencil)) {
344 BKE_id_delete(trace_job.bmain, &trace_job.ob_grease_pencil->id);
348 if (trace_job.success) {
359static void trace_free_job(
void *customdata)
361 TraceJob *tj =
static_cast<TraceJob *
>(customdata);
366static bool grease_pencil_trace_image_poll(
bContext *
C)
385 TraceJob *job = MEM_new<TraceJob>(
"TraceJob");
394 job->ob_active = job->base_active->object;
395 job->image =
static_cast<Image *
>(job->ob_active->data);
396 job->frame_target = scene->
r.
cfra;
401 job->ob_grease_pencil = (target == TargetObjectMode::Selected) ?
406 if (job->ob_grease_pencil !=
nullptr) {
409 job->ob_grease_pencil =
nullptr;
413 job->ob_grease_pencil =
nullptr;
417 job->was_ob_created =
false;
425 job->ensure_output_object();
431 job->foreground_material_index = ensure_foreground_material(
432 job->bmain, job->ob_grease_pencil,
"Stroke");
433 job->background_material_index = ensure_background_material(
434 job->bmain, job->ob_grease_pencil,
"Holdout");
436 if ((job->image->source ==
IMA_SRC_FILE) || (job->frame_number > 0)) {
438 trace_start_job(job, &worker_status);
474 {int(TurnPolicy::Foreground),
478 "Prefers to connect foreground components"},
479 {int(TurnPolicy::Background),
483 "Prefers to connect background components"},
484 {int(TurnPolicy::Left),
"LEFT", 0,
"Left",
"Always take a left turn"},
485 {int(TurnPolicy::Right),
"RIGHT", 0,
"Right",
"Always take a right turn"},
486 {int(TurnPolicy::Minority),
490 "Prefers to connect the color that occurs least frequently in the local "
491 "neighborhood of the current position"},
492 {int(TurnPolicy::Majority),
496 "Prefers to connect the color that occurs most frequently in the local "
497 "neighborhood of the current position"},
498 {int(TurnPolicy::Random),
"RANDOM", 0,
"Random",
"Choose pseudo-randomly"},
499 {0,
nullptr, 0,
nullptr,
nullptr},
503 {int(TraceMode::Single),
"SINGLE", 0,
"Single",
"Trace the current frame of the image"},
504 {int(TraceMode::Sequence),
"SEQUENCE", 0,
"Sequence",
"Trace full sequence"},
505 {0,
nullptr, 0,
nullptr,
nullptr},
509 {int(TargetObjectMode::New),
"NEW", 0,
"New Object",
""},
510 {int(TargetObjectMode::Selected),
"SELECTED", 0,
"Selected Object",
""},
511 {0,
nullptr, 0,
nullptr,
nullptr},
515 ot->name =
"Trace Image to Grease Pencil";
516 ot->idname =
"GREASE_PENCIL_OT_trace_image";
517 ot->description =
"Extract Grease Pencil strokes from image";
520 ot->invoke = grease_pencil_trace_image_invoke;
521 ot->exec = grease_pencil_trace_image_exec;
522 ot->poll = grease_pencil_trace_image_poll;
531 int(TargetObjectMode::New),
533 "Target Grease Pencil");
536 RNA_def_float(
ot->srna,
"radius", 0.01f, 0.001f, 1.0f,
"Radius",
"", 0.001, 1.0f);
544 "Determine the lightness threshold above which strokes are generated",
550 int(TurnPolicy::Minority),
552 "Determines how to resolve ambiguities during decomposition of bitmaps into paths");
556 int(TraceMode::Single),
558 "Determines if trace simple image or full sequence");
562 "Start At Current Frame",
563 "Trace Image starting in current image frame");
571 "Used to trace only one frame of the image sequence, set to zero to trace all",
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
Object * BKE_view_layer_non_active_selected_object(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
General operations, lookup, etc. for materials.
General operations, lookup, etc. for blender objects.
bool BKE_object_obdata_is_libdata(const Object *ob)
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_msg(a, msg)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ GP_MATERIAL_IS_STROKE_HOLDOUT
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_IS_FILL_HOLDOUT
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
@ WM_JOB_TYPE_TRACE_IMAGE
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
GAttributeReader lookup(const StringRef attribute_id) const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
bke::CurvesGeometry & strokes_for_write()
void tag_topology_changed()
void ED_operatortypes_grease_pencil_trace()
void free_bitmap(Bitmap *bm)
Bitmap * image_to_bitmap(const ImBuf &ibuf, ThresholdFn fn)
bke::CurvesGeometry trace_to_curves(const Trace &trace, StringRef hole_attribute_id, const float4x4 &transform)
void free_trace(Trace *trace)
Trace * trace_bitmap(const TraceParams ¶ms, Bitmap &bm)
Object * add_type(bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
void base_activate(bContext *C, Base *base)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
T average(const VecBase< T, Size > &a)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatBase< T, NumCol, NumRow > translate(const MatBase< T, NumCol, NumRow > &mat, const VectorT &translation)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
struct MaterialGPencilStyle * gp_style
MutableVArraySpan< T > span
struct ReportList * reports
void WM_main_add_notifier(uint type, void *reference)
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorStatus WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default, std::optional< std::string > message)