70 bool *stop, *do_update;
87 bool use_current_frame;
93 TurnPolicy turnpolicy;
101 void ensure_output_object();
104void TraceJob::ensure_output_object()
109 if (this->ob_grease_pencil ==
nullptr) {
110 const ushort local_view_bits = (this->v3d && this->v3d->localvd) ? this->v3d->local_view_uid :
117 this->ob_active->loc,
118 this->ob_active->rot,
121 copy_v3_v3(this->ob_grease_pencil->scale, this->ob_active->scale);
122 this->was_ob_created =
true;
127 this->layer = grease_pencil.get_active_layer();
128 if (this->layer ==
nullptr) {
129 Layer &new_layer = grease_pencil.add_layer(
DATA_(
"Trace"));
130 grease_pencil.set_active_layer(&new_layer);
131 this->layer = &new_layer;
135static float4x4 pixel_to_object_transform(
const Object &image_object,
139 const float3 pixel_center_3d =
float3(pixel_center.x, pixel_center.y, 0);
143 const float3 image_aspect_3d = (ibuf.
x > ibuf.
y ?
float3(1,
float(ibuf.
y) /
float(ibuf.
x), 1) :
150 return to_normalized;
187 image_trace::TraceParams
params;
188 params.size_threshold = 0;
189 params.turn_policy = trace_job.turnpolicy;
194 const StringRef hole_attribute_id =
"is_hole";
197 const float4x4 transform = pixel_to_object_transform(*trace_job.ob_active, ibuf);
199 *trace, hole_attribute_id, transform);
204 const int material_fg = ensure_foreground_material(
205 trace_job.bmain, trace_job.ob_grease_pencil,
"Stroke");
206 const int material_bg = ensure_background_material(
207 trace_job.bmain, trace_job.ob_grease_pencil,
"Holdout");
212 for (const int curve_i : range) {
213 const bool is_hole = holes[curve_i];
214 material_indices.span[curve_i] = (is_hole ? material_bg : material_fg);
217 material_indices.
finish();
219 attributes.remove(hole_attribute_id);
224 radii.
span.fill(trace_job.radius);
232 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
234 trace_job.stop = &worker_status->
stop;
235 trace_job.do_update = &worker_status->
do_update;
236 trace_job.progress = &worker_status->
progress;
237 trace_job.was_canceled =
false;
238 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0, 0);
243 if (trace_job.image->source ==
IMA_SRC_FILE || trace_job.mode == TraceMode::Single) {
244 ImageUser &iuser = *trace_job.ob_active->iuser;
245 trace_job.traced_curves.reinitialize(1);
247 iuser.
framenr = ((trace_job.frame_number == 0) || (trace_job.frame_number > iuser.
frames)) ?
249 trace_job.frame_number;
253 trace_job.traced_curves.first() = grease_pencil_trace_image(trace_job, *ibuf);
255 *(trace_job.progress) = 1.0f;
260 ImageUser &iuser = *trace_job.ob_active->iuser;
261 const int num_frames = iuser.
frames - init_frame + 1;
262 trace_job.traced_curves.reinitialize(num_frames);
265 trace_job.was_canceled =
true;
269 const int frame_number = init_frame + i;
270 *(trace_job.progress) =
float(frame_number) /
float(iuser.
frames);
278 trace_job.traced_curves[i] = grease_pencil_trace_image(trace_job, *ibuf);
284 trace_job.success = !trace_job.was_canceled;
286 worker_status->
stop =
false;
289static void trace_end_job(
void *customdata)
291 TraceJob &trace_job = *
static_cast<TraceJob *
>(customdata);
296 switch (trace_job.mode) {
297 case TraceMode::Single: {
298 BLI_assert(trace_job.traced_curves.size() == 1);
300 trace_job.frame_target);
301 if (drawing ==
nullptr) {
302 drawing = grease_pencil.insert_frame(*trace_job.layer, trace_job.frame_target);
309 case TraceMode::Sequence: {
310 const ImageUser &iuser = *trace_job.ob_active->iuser;
311 const int init_frame = std::max((trace_job.use_current_frame) ? trace_job.frame_target : 0,
313 const int num_frames = iuser.
frames - init_frame + 1;
314 BLI_assert(trace_job.traced_curves.size() == num_frames);
316 const int frame_number = init_frame + i;
319 if (drawing ==
nullptr) {
320 drawing = grease_pencil.insert_frame(*trace_job.layer, frame_number);
331 if ((trace_job.was_canceled) && (trace_job.was_ob_created) && (trace_job.ob_grease_pencil)) {
332 BKE_id_delete(trace_job.bmain, &trace_job.ob_grease_pencil->id);
336 if (trace_job.success) {
347static void trace_free_job(
void *customdata)
349 TraceJob *tj =
static_cast<TraceJob *
>(customdata);
354static bool grease_pencil_trace_image_poll(
bContext *C)
373 TraceJob *job = MEM_new<TraceJob>(
"TraceJob");
382 job->ob_active = job->base_active->object;
383 job->image =
static_cast<Image *
>(job->ob_active->data);
384 job->frame_target = scene->r.cfra;
389 job->ob_grease_pencil = (target == TargetObjectMode::Selected) ?
394 if (job->ob_grease_pencil !=
nullptr) {
397 job->ob_grease_pencil =
nullptr;
401 job->ob_grease_pencil =
nullptr;
405 job->was_ob_created =
false;
413 job->ensure_output_object();
418 if ((job->image->source ==
IMA_SRC_FILE) || (job->frame_number > 0)) {
420 trace_start_job(job, &worker_status);
454 {
int(TurnPolicy::Foreground),
458 "Prefers to connect foreground components"},
459 {
int(TurnPolicy::Background),
463 "Prefers to connect background components"},
464 {
int(TurnPolicy::Left),
"LEFT", 0,
"Left",
"Always take a left turn"},
465 {
int(TurnPolicy::Right),
"RIGHT", 0,
"Right",
"Always take a right turn"},
466 {
int(TurnPolicy::Minority),
470 "Prefers to connect the color that occurs least frequently in the local "
471 "neighborhood of the current position"},
472 {
int(TurnPolicy::Majority),
476 "Prefers to connect the color that occurs most frequently in the local "
477 "neighborhood of the current position"},
478 {
int(TurnPolicy::Random),
"RANDOM", 0,
"Random",
"Choose pseudo-randomly"},
479 {0,
nullptr, 0,
nullptr,
nullptr},
483 {
int(TraceMode::Single),
"SINGLE", 0,
"Single",
"Trace the current frame of the image"},
484 {
int(TraceMode::Sequence),
"SEQUENCE", 0,
"Sequence",
"Trace full sequence"},
485 {0,
nullptr, 0,
nullptr,
nullptr},
489 {
int(TargetObjectMode::New),
"NEW", 0,
"New Object",
""},
490 {
int(TargetObjectMode::Selected),
"SELECTED", 0,
"Selected Object",
""},
491 {0,
nullptr, 0,
nullptr,
nullptr},
495 ot->
name =
"Trace Image to Grease Pencil";
496 ot->
idname =
"GREASE_PENCIL_OT_trace_image";
497 ot->
description =
"Extract Grease Pencil strokes from image";
500 ot->
invoke = grease_pencil_trace_image_invoke;
501 ot->
exec = grease_pencil_trace_image_exec;
502 ot->
poll = grease_pencil_trace_image_poll;
511 int(TargetObjectMode::New),
513 "Target grease pencil");
524 "Determine the lightness threshold above which strokes are generated",
530 int(TurnPolicy::Minority),
532 "Determines how to resolve ambiguities during decomposition of bitmaps into paths");
536 int(TraceMode::Single),
538 "Determines if trace simple image or full sequence");
542 "Start At Current Frame",
543 "Trace Image starting in current image frame");
551 "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)
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.
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
@ WM_JOB_TYPE_TRACE_IMAGE
ATTR_WARN_UNUSED_RESULT BMesh * bm
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
bke::CurvesGeometry & strokes_for_write()
void tag_topology_changed()
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
draw_view in_light_buf[] float
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
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))
VecBase< float, 2 > float2
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
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
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 *))
int 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)