Blender V5.0
cycles/blender/util.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "RNA_access.hh"
8#include "RNA_blender_cpp.hh"
9
10#include "scene/mesh.h"
11#include "scene/scene.h"
12
13#include "util/algorithm.h"
14#include "util/array.h"
15#include "util/path.h"
16#include "util/set.h"
17#include "util/transform.h"
18#include "util/types.h"
19
20#include "DNA_mesh_types.h"
21#include "DNA_object_types.h"
22#include "DNA_view3d_types.h"
23
24#include "BKE_global.hh"
25#include "BKE_image.hh"
26#include "BKE_lib_id.hh"
27#include "BKE_mesh.h"
28#include "BKE_mesh_types.hh"
29#include "BKE_mesh_wrapper.hh"
30
32
33static inline BL::ID object_get_data(const BL::Object &b_ob, const bool use_adaptive_subdivision)
34{
35 ::Object *object = reinterpret_cast<::Object *>(b_ob.ptr.data);
36
37 if (!use_adaptive_subdivision && object->type == OB_MESH) {
38 ::Mesh *mesh = static_cast<::Mesh *>(object->data);
40 return BL::ID(RNA_id_pointer_create(&mesh->id));
41 }
42
43 return BL::ID(RNA_id_pointer_create(reinterpret_cast<ID *>(object->data)));
44}
45
47 /* Object directly provided by the depsgraph iterator. This object is only valid during one
48 * iteration and must not be accessed afterwards. Transforms and visibility should be checked on
49 * this object. */
50 BL::Object iter_object;
51
52 /* This object remains alive even after the object iterator is done. It corresponds to one
53 * original object. It is the object that owns the object data below. */
54 BL::Object real_object;
55
56 /* The object-data referenced by the iter object. This is still valid after the depsgraph
57 * iterator is done. It might have a different type compared to object_get_data(real_object). */
59
60 /* Object will use adaptive subdivision. */
62
63 /* True when the current geometry is the data of the referenced object. False when it is a
64 * geometry instance that does not have a 1-to-1 relationship with an object. */
66 {
67 return object_get_data(const_cast<BL::Object &>(real_object), use_adaptive_subdivision) ==
69 }
70};
71
72static inline BL::Mesh object_copy_mesh_data(const BObjectInfo &b_ob_info)
73{
74 ::Object *object = static_cast<::Object *>(b_ob_info.real_object.ptr.data);
76 nullptr, object, false, false, !b_ob_info.use_adaptive_subdivision);
77 return BL::Mesh(RNA_id_pointer_create(&mesh->id));
78}
79
80using BlenderAttributeType = BL::ShaderNodeAttribute::attribute_type_enum;
82
83void python_thread_state_save(void **python_thread_state);
84void python_thread_state_restore(void **python_thread_state);
85
86static bool mesh_use_corner_normals(const BObjectInfo &b_ob_info, BL::Mesh &mesh)
87{
88 return mesh && !b_ob_info.use_adaptive_subdivision &&
89 (static_cast<const ::Mesh *>(mesh.ptr.data)->normals_domain(true) ==
91}
92
93static inline BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
94{
95 BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
96 BL::Mesh(PointerRNA_NULL);
97
98 bool use_corner_normals = false;
99
100 if (b_ob_info.is_real_object_data()) {
101 if (mesh) {
102 if (mesh.is_editmode()) {
103 /* Flush edit-mesh to mesh, including all data layers. */
104 mesh = object_copy_mesh_data(b_ob_info);
105 use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh);
106 }
107 else if (mesh_use_corner_normals(b_ob_info, mesh)) {
108 /* Make a copy to split faces. */
109 mesh = object_copy_mesh_data(b_ob_info);
110 use_corner_normals = true;
111 }
112 }
113 else {
114 mesh = object_copy_mesh_data(b_ob_info);
115 use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh);
116 }
117 }
118 else {
119 /* TODO: what to do about non-mesh geometry instances? */
120 use_corner_normals = mesh_use_corner_normals(b_ob_info, mesh);
121 }
122
123 if (mesh) {
124 if (use_corner_normals) {
125 mesh.split_faces();
126 }
127
128 if (b_ob_info.use_adaptive_subdivision) {
129 mesh.calc_loop_triangles();
130 }
131 }
132
133 return mesh;
134}
135
136static inline void free_object_to_mesh(BObjectInfo &b_ob_info, BL::Mesh &mesh)
137{
138 if (!b_ob_info.is_real_object_data()) {
139 return;
140 }
141 /* Free mesh if we didn't just use the existing one. */
142 BL::Object object = b_ob_info.real_object;
143 if (object_get_data(object, b_ob_info.use_adaptive_subdivision).ptr.data != mesh.ptr.data) {
144 BKE_id_free(nullptr, static_cast<ID *>(mesh.ptr.data));
145 }
146}
147
148static inline void colorramp_to_array(BL::ColorRamp &ramp,
149 array<float3> &ramp_color,
150 array<float> &ramp_alpha,
151 const int size)
152{
153 const int full_size = size + 1;
154 ramp_color.resize(full_size);
155 ramp_alpha.resize(full_size);
156
157 for (int i = 0; i < full_size; i++) {
158 float color[4];
159
160 ramp.evaluate(float(i) / float(size), color);
161 ramp_color[i] = make_float3(color[0], color[1], color[2]);
162 ramp_alpha[i] = color[3];
163 }
164}
165
166static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x)
167{
168 *min_x = min(*min_x, curve.points[0].location()[0]);
169 *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
170}
171
172static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
173 const int num_curves,
174 float *min_x,
175 float *max_x)
176{
177 // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
178 *min_x = FLT_MAX;
179 *max_x = -FLT_MAX;
180 for (int i = 0; i < num_curves; ++i) {
181 BL::CurveMap map(cumap.curves[i]);
182 curvemap_minmax_curve(map, min_x, max_x);
183 }
184}
185
186static inline void curvemapping_to_array(BL::CurveMapping &cumap,
188 const int size)
189{
190 cumap.update();
191 BL::CurveMap curve = cumap.curves[0];
192 const int full_size = size + 1;
193 data.resize(full_size);
194 for (int i = 0; i < full_size; i++) {
195 const float t = float(i) / float(size);
196 data[i] = cumap.evaluate(curve, t);
197 }
198}
199
200static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
202 const int size)
203{
204 float min = 0.0f;
205 float max = 1.0f;
206
207 curvemapping_minmax(cumap, 1, &min, &max);
208
209 const float range = max - min;
210
211 cumap.update();
212
213 BL::CurveMap map = cumap.curves[0];
214
215 const int full_size = size + 1;
216 data.resize(full_size);
217
218 for (int i = 0; i < full_size; i++) {
219 const float t = min + float(i) / float(size) * range;
220 data[i] = cumap.evaluate(map, t);
221 }
222}
223
224static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
226 const int size,
227 bool rgb_curve)
228{
229 float min_x = 0.0f;
230 float max_x = 1.0f;
231
232 /* TODO(sergey): There is no easy way to automatically guess what is
233 * the range to be used here for the case when mapping is applied on
234 * top of another mapping (i.e. R curve applied on top of common
235 * one).
236 *
237 * Using largest possible range form all curves works correct for the
238 * cases like vector curves and should be good enough heuristic for
239 * the color curves as well.
240 *
241 * There might be some better estimations here tho.
242 */
243 const int num_curves = rgb_curve ? 4 : 3;
244 curvemapping_minmax(cumap, num_curves, &min_x, &max_x);
245
246 const float range_x = max_x - min_x;
247
248 cumap.update();
249
250 BL::CurveMap mapR = cumap.curves[0];
251 BL::CurveMap mapG = cumap.curves[1];
252 BL::CurveMap mapB = cumap.curves[2];
253
254 const int full_size = size + 1;
255 data.resize(full_size);
256
257 if (rgb_curve) {
258 BL::CurveMap mapI = cumap.curves[3];
259 for (int i = 0; i < full_size; i++) {
260 const float t = min_x + float(i) / float(size) * range_x;
261 data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
262 cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
263 cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
264 }
265 }
266 else {
267 for (int i = 0; i < full_size; i++) {
268 const float t = min_x + float(i) / float(size) * range_x;
269 data[i] = make_float3(
270 cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
271 }
272 }
273}
274
275static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
276{
277 return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
278}
279
280static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
281{
282 if (!self.is_real_object_data()) {
283 /* Comes from geometry nodes, can't use heuristic to guess if it's animated. */
284 return true;
285 }
286
287 /* Use heuristic to quickly check if object is potentially animated. */
288 return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
289 false;
290}
291
292static inline int render_resolution_x(BL::RenderSettings &b_render)
293{
294 return b_render.resolution_x() * b_render.resolution_percentage() / 100;
295}
296
297static inline int render_resolution_y(BL::RenderSettings &b_render)
298{
299 return b_render.resolution_y() * b_render.resolution_percentage() / 100;
300}
301
302static inline string image_user_file_path(BL::BlendData &data,
303 BL::ImageUser &iuser,
304 BL::Image &ima,
305 const int cfra)
306{
307 char filepath[1024];
308 iuser.tile(0);
310 static_cast<Image *>(ima.ptr.data), static_cast<ImageUser *>(iuser.ptr.data), cfra);
311 BKE_image_user_file_path_ex(static_cast<Main *>(data.ptr.data),
312 static_cast<ImageUser *>(iuser.ptr.data),
313 static_cast<Image *>(ima.ptr.data),
314 filepath,
315 false,
316 true);
317
318 return string(filepath);
319}
320
321static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, const int cfra)
322{
324 static_cast<Image *>(ima.ptr.data), static_cast<ImageUser *>(iuser.ptr.data), cfra);
325 return iuser.frame_current();
326}
327
328static inline bool image_is_builtin(BL::Image &ima, BL::RenderEngine &engine)
329{
330 const BL::Image::source_enum image_source = ima.source();
331 if (image_source == BL::Image::source_TILED) {
332 /* If any tile is marked as generated, then treat the entire Image as built-in. */
333 for (BL::UDIMTile &tile : ima.tiles) {
334 if (tile.is_generated_tile()) {
335 return true;
336 }
337 }
338 }
339
340 return ima.packed_file() || image_source == BL::Image::source_GENERATED ||
341 image_source == BL::Image::source_MOVIE ||
342 (engine.is_preview() && image_source != BL::Image::source_SEQUENCE);
343}
344
345static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
346{
347 b_rr.stamp_data_add_field(name.c_str(), value.c_str());
348}
349
350/* Utilities */
351
352static inline Transform get_transform(const BL::Array<float, 16> &array)
353{
354 /* Convert from Blender column major to Cycles row major, assume it's an affine transform that
355 * does not need the last row. */
356 return make_transform(array[0],
357 array[4],
358 array[8],
359 array[12],
360
361 array[1],
362 array[5],
363 array[9],
364 array[13],
365
366 array[2],
367 array[6],
368 array[10],
369 array[14]);
370}
371
372static inline float2 get_float2(const BL::Array<float, 2> &array)
373{
374 return make_float2(array[0], array[1]);
375}
376
377static inline float3 get_float3(const BL::Array<float, 2> &array)
378{
379 return make_float3(array[0], array[1], 0.0f);
380}
381
382static inline float3 get_float3(const BL::Array<float, 3> &array)
383{
384 return make_float3(array[0], array[1], array[2]);
385}
386
387static inline float3 get_float3(const BL::Array<float, 4> &array)
388{
389 return make_float3(array[0], array[1], array[2]);
390}
391
392static inline float4 get_float4(const BL::Array<float, 4> &array)
393{
394 return make_float4(array[0], array[1], array[2], array[3]);
395}
396
397static inline int3 get_int3(const BL::Array<int, 3> &array)
398{
399 return make_int3(array[0], array[1], array[2]);
400}
401
402static inline int4 get_int4(const BL::Array<int, 4> &array)
403{
404 return make_int4(array[0], array[1], array[2], array[3]);
405}
406
407static inline float3 get_float3(PointerRNA &ptr, const char *name)
408{
409 float3 f;
411 return f;
412}
413
414static inline void set_float3(PointerRNA &ptr, const char *name, const float3 value)
415{
416 RNA_float_set_array(&ptr, name, &value.x);
417}
418
419static inline float4 get_float4(PointerRNA &ptr, const char *name)
420{
421 float4 f;
423 return f;
424}
425
426static inline void set_float4(PointerRNA &ptr, const char *name, const float4 value)
427{
428 RNA_float_set_array(&ptr, name, &value.x);
429}
430
431static inline bool get_boolean(PointerRNA &ptr, const char *name)
432{
433 return RNA_boolean_get(&ptr, name) ? true : false;
434}
435
436static inline void set_boolean(PointerRNA &ptr, const char *name, bool value)
437{
438 RNA_boolean_set(&ptr, name, (int)value);
439}
440
441static inline float get_float(PointerRNA &ptr, const char *name)
442{
443 return RNA_float_get(&ptr, name);
444}
445
446static inline void set_float(PointerRNA &ptr, const char *name, const float value)
447{
448 RNA_float_set(&ptr, name, value);
449}
450
451static inline int get_int(PointerRNA &ptr, const char *name)
452{
453 return RNA_int_get(&ptr, name);
454}
455
456static inline void set_int(PointerRNA &ptr, const char *name, const int value)
457{
458 RNA_int_set(&ptr, name, value);
459}
460
461/* Get a RNA enum value with sanity check: if the RNA value is above num_values
462 * the function will return a fallback default value.
463 *
464 * NOTE: This function assumes that RNA enum values are a continuous sequence
465 * from 0 to num_values-1. Be careful to use it with enums where some values are
466 * deprecated!
467 */
468static inline int get_enum(PointerRNA &ptr,
469 const char *name,
470 int num_values = -1,
471 int default_value = -1)
472{
473 int value = RNA_enum_get(&ptr, name);
474 if (num_values != -1 && value >= num_values) {
475 assert(default_value != -1);
476 value = default_value;
477 }
478 return value;
479}
480
481static inline string get_enum_identifier(PointerRNA &ptr, const char *name)
482{
484 const char *identifier = "";
485 const int value = RNA_property_enum_get(&ptr, prop);
486
487 RNA_property_enum_identifier(nullptr, &ptr, prop, value, &identifier);
488
489 return string(identifier);
490}
491
492static inline void set_enum(PointerRNA &ptr, const char *name, const int value)
493{
494 RNA_enum_set(&ptr, name, value);
495}
496
497static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier)
498{
499 RNA_enum_set_identifier(nullptr, &ptr, name, identifier.c_str());
500}
501
502static inline string get_string(PointerRNA &ptr, const char *name)
503{
504 return RNA_string_get(&ptr, name);
505}
506
507static inline void set_string(PointerRNA &ptr, const char *name, const string &value)
508{
509 RNA_string_set(&ptr, name, value.c_str());
510}
511
512/* Relative Paths */
513
514static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
515{
516 if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
517 string dirname;
518
519 if (b_id.library()) {
520 BL::ID b_library_id(b_id.library());
521 dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath());
522 }
523 else {
524 dirname = b_data.filepath();
525 }
526
527 return path_join(path_dirname(dirname), path.substr(2));
528 }
529
530 return path;
531}
532
533static inline string get_text_datablock_content(const PointerRNA &ptr)
534{
535 if (ptr.data == nullptr) {
536 return "";
537 }
538
539 string content;
540 BL::Text::lines_iterator iter;
541 for (iter.begin(ptr); iter; ++iter) {
542 content += iter->body() + "\n";
543 }
544
545 return content;
546}
547
548/* Texture Space */
549
550static inline void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
551{
552 float texspace_location[3];
553 float texspace_size[3];
554 BKE_mesh_texspace_get(const_cast<::Mesh *>(&b_mesh), texspace_location, texspace_size);
555
556 loc = make_float3(texspace_location[0], texspace_location[1], texspace_location[2]);
557 size = make_float3(texspace_size[0], texspace_size[1], texspace_size[2]);
558
559 if (size.x != 0.0f) {
560 size.x = 0.5f / size.x;
561 }
562 if (size.y != 0.0f) {
563 size.y = 0.5f / size.y;
564 }
565 if (size.z != 0.0f) {
566 size.z = 0.5f / size.z;
567 }
568
569 loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
570}
571
572/* Object motion steps, returns 0 if no motion blur needed. */
573static inline uint object_motion_steps(BL::Object &b_parent,
574 BL::Object &b_ob,
575 const int max_steps = INT_MAX)
576{
577 /* Get motion enabled and steps from object itself. */
578 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
579 bool use_motion = get_boolean(cobject, "use_motion_blur");
580 if (!use_motion) {
581 return 0;
582 }
583
584 int steps = max(1, get_int(cobject, "motion_steps"));
585
586 /* Also check parent object, so motion blur and steps can be
587 * controlled by dupli-group duplicator for linked groups. */
588 if (b_parent.ptr.data != b_ob.ptr.data) {
589 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
590 use_motion &= get_boolean(parent_cobject, "use_motion_blur");
591
592 if (!use_motion) {
593 return 0;
594 }
595
596 steps = max(steps, get_int(parent_cobject, "motion_steps"));
597 }
598
599 /* Use uneven number of steps so we get one keyframe at the current frame,
600 * and use 2^(steps - 1) so objects with more/fewer steps still have samples
601 * at the same times, to avoid sampling at many different times. */
602 return min((2 << (steps - 1)) + 1, max_steps);
603}
604
605/* object uses deformation motion blur */
606static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
607{
608 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
609 bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
610 /* If motion blur is enabled for the object we also check
611 * whether it's enabled for the parent object as well.
612 *
613 * This way we can control motion blur from the dupli-group
614 * duplicator much easier. */
615 if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
616 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
617 use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
618 }
619 return use_deform_motion;
620}
621
622static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
623{
624 for (BL::Modifier &b_mod : b_ob.modifiers) {
625 if (b_mod.is_a(&RNA_FluidModifier)) {
626 BL::FluidModifier b_mmd(b_mod);
627
628 if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
629 b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS)
630 {
631 return b_mmd.domain_settings();
632 }
633 }
634 }
635
636 return BL::FluidDomainSettings(PointerRNA_NULL);
637}
638
639static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
640 bool *has_subdivision_modifier)
641{
642 for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
643 BL::Modifier b_mod = b_ob.modifiers[i];
644
645 if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
646 BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
647 return mesh_cache;
648 }
649
650 /* Skip possible particles system modifiers as they do not modify the geometry. */
651 if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
652 continue;
653 }
654
655 if (b_mod.type() == BL::Modifier::type_SUBSURF) {
656 if (has_subdivision_modifier) {
657 *has_subdivision_modifier = true;
658 }
659 continue;
660 }
661
662 break;
663 }
664
665 return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
666}
667
668static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview)
669{
670 if (!b_ob.modifiers.empty()) {
671 BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
672 const bool enabled = preview ? mod.show_viewport() : mod.show_render();
673
674 if (enabled && mod.type() == BL::Modifier::type_SUBSURF) {
675 BL::SubsurfModifier subsurf(mod);
676 if (subsurf.use_adaptive_subdivision()) {
677 return subsurf;
678 }
679 }
680 }
681
682 return PointerRNA_NULL;
683}
684
685static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
686 const bool preview,
687 const bool use_adaptive_subdivision)
688{
689 if (!use_adaptive_subdivision) {
691 }
692
693 BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
694
695 if (subsurf) {
696 if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
698 }
700 }
701
703}
704
705static inline void object_subdivision_to_mesh(BL::Object &b_ob,
706 Mesh &mesh,
707 const bool preview,
708 const bool use_adaptive_subdivision)
709{
710 if (!use_adaptive_subdivision) {
711 mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE);
712 return;
713 }
714
715 BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
716
717 if (!subsurf) {
718 mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE);
719 return;
720 }
721
722 if (subsurf.subdivision_type() != BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
723 mesh.set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
724 return;
725 }
726
727 mesh.set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
728
729 switch (subsurf.boundary_smooth()) {
730 case BL::SubsurfModifier::boundary_smooth_PRESERVE_CORNERS:
731 mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_AND_CORNER);
732 break;
733 case BL::SubsurfModifier::boundary_smooth_ALL:
734 mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_ONLY);
735 break;
736 }
737
738 switch (subsurf.uv_smooth()) {
739 case BL::SubsurfModifier::uv_smooth_NONE:
740 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_ALL);
741 break;
742 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS:
743 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_ONLY);
744 break;
745 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_AND_JUNCTIONS:
746 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS1);
747 break;
748 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
749 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS2);
750 break;
751 case BL::SubsurfModifier::uv_smooth_PRESERVE_BOUNDARIES:
752 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_BOUNDARIES);
753 break;
754 case BL::SubsurfModifier::uv_smooth_SMOOTH_ALL:
755 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_NONE);
756 break;
757 }
758}
759
760static inline uint object_ray_visibility(BL::Object &b_ob)
761{
762 uint flag = 0;
763
764 flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : PathRayFlag(0);
765 flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : PathRayFlag(0);
766 flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : PathRayFlag(0);
767 flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : PathRayFlag(0);
768 flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : PathRayFlag(0);
769 flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : PathRayFlag(0);
770
771 return flag;
772}
773
774/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
775 * things like velocity from cache modifier, fluid simulation).
776 *
777 * NOTE: This code is run prior to object motion blur initialization. so can not access properties
778 * set by `sync_object_motion_init()`. */
779static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
780{
781 const Scene::MotionType need_motion = scene->need_motion();
782 if (need_motion == Scene::MOTION_NONE) {
783 /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
784 * attributes. */
785 return false;
786 }
787
788 if (need_motion == Scene::MOTION_BLUR) {
789 /* A bit tricky and implicit case:
790 * - Motion blur is enabled in the scene, which implies specific number of time steps for
791 * objects.
792 * - If the object has motion blur disabled on it, it will have 0 time steps.
793 * - Motion attribute expects non-zero time steps.
794 *
795 * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
796 PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
797 const bool use_motion = get_boolean(cobject, "use_motion_blur");
798 if (!use_motion) {
799 return false;
800 }
801 }
802
803 /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
804 * level. */
805 return true;
806}
807
808static inline bool region_view3d_navigating_or_transforming(const BL::RegionView3D &b_rv3d)
809{
810 ::RegionView3D *rv3d = static_cast<::RegionView3D *>(b_rv3d.ptr.data);
811 return rv3d && ((rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) ||
812 (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)));
813}
814
815class EdgeMap {
816 public:
817 EdgeMap() = default;
818
819 void clear()
820 {
821 edges_.clear();
822 }
823
824 void insert(int v0, int v1)
825 {
826 get_sorted_verts(v0, v1);
827 edges_.insert(std::pair<int, int>(v0, v1));
828 }
829
830 bool exists(int v0, int v1)
831 {
832 get_sorted_verts(v0, v1);
833 return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
834 }
835
836 protected:
837 void get_sorted_verts(int &v0, int &v1)
838 {
839 if (v0 > v1) {
840 swap(v0, v1);
841 }
842 }
843
844 set<std::pair<int, int>> edges_;
845};
846
@ G_TRANSFORM_OBJ
@ G_TRANSFORM_EDIT
void BKE_image_user_frame_calc(Image *ima, ImageUser *iuser, int cfra)
void BKE_image_user_file_path_ex(const Main *bmain, const ImageUser *iuser, const Image *ima, char *filepath, const bool resolve_udim, const bool resolve_multiview)
void BKE_id_free(Main *bmain, void *idv)
void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
Mesh * BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers, bool preserve_origindex, bool ensure_subdivision)
Mesh * BKE_mesh_wrapper_ensure_subdivision(Mesh *mesh)
unsigned int uint
const char * dirname(char *path)
Object is a sort of wrapper for general info.
@ OB_MESH
@ RV3D_PAINTING
@ RV3D_NAVIGATING
BMesh const char void * data
return true
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
set< std::pair< int, int > > edges_
EdgeMap()=default
void insert(int v0, int v1)
bool exists(int v0, int v1)
void get_sorted_verts(int &v0, int &v1)
T * resize(const size_t newsize)
nullptr float
BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType
static void set_float3(PointerRNA &ptr, const char *name, const float3 value)
static void curvemapping_minmax(BL::CurveMapping &cumap, const int num_curves, float *min_x, float *max_x)
static void curvemapping_to_array(BL::CurveMapping &cumap, array< float > &data, const int size)
static bool mesh_use_corner_normals(const BObjectInfo &b_ob_info, BL::Mesh &mesh)
static uint object_ray_visibility(BL::Object &b_ob)
static float4 get_float4(const BL::Array< float, 4 > &array)
static BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
static bool image_is_builtin(BL::Image &ima, BL::RenderEngine &engine)
static uint object_motion_steps(BL::Object &b_parent, BL::Object &b_ob, const int max_steps=INT_MAX)
static int render_resolution_x(BL::RenderSettings &b_render)
static float get_float(PointerRNA &ptr, const char *name)
void python_thread_state_restore(void **python_thread_state)
Definition python.cpp:91
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static void set_boolean(PointerRNA &ptr, const char *name, bool value)
static bool get_boolean(PointerRNA &ptr, const char *name)
static bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
static int get_int(PointerRNA &ptr, const char *name)
static void free_object_to_mesh(BObjectInfo &b_ob_info, BL::Mesh &mesh)
static BL::Mesh object_copy_mesh_data(const BObjectInfo &b_ob_info)
static string get_enum_identifier(PointerRNA &ptr, const char *name)
static void set_float(PointerRNA &ptr, const char *name, const float value)
static string get_text_datablock_content(const PointerRNA &ptr)
static float3 get_float3(const BL::Array< float, 2 > &array)
static int render_resolution_y(BL::RenderSettings &b_render)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static int get_enum(PointerRNA &ptr, const char *name, int num_values=-1, int default_value=-1)
static void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name)
static Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, const bool preview, const bool use_adaptive_subdivision)
static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview)
static void object_subdivision_to_mesh(BL::Object &b_ob, Mesh &mesh, const bool preview, const bool use_adaptive_subdivision)
static void colorramp_to_array(BL::ColorRamp &ramp, array< float3 > &ramp_color, array< float > &ramp_alpha, const int size)
static bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
static int4 get_int4(const BL::Array< int, 4 > &array)
static string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
static void curvemapping_float_to_array(BL::CurveMapping &cumap, array< float > &data, const int size)
static int3 get_int3(const BL::Array< int, 3 > &array)
static float2 get_float2(const BL::Array< float, 2 > &array)
static void curvemapping_color_to_array(BL::CurveMapping &cumap, array< float3 > &data, const int size, bool rgb_curve)
static int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, const int cfra)
static void set_int(PointerRNA &ptr, const char *name, const int value)
static void set_float4(PointerRNA &ptr, const char *name, const float4 value)
static BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
void python_thread_state_save(void **python_thread_state)
Definition python.cpp:86
static CCL_NAMESPACE_BEGIN BL::ID object_get_data(const BL::Object &b_ob, const bool use_adaptive_subdivision)
static void curvemap_minmax_curve(BL::CurveMap &curve, float *min_x, float *max_x)
static string get_string(PointerRNA &ptr, const char *name)
static Transform get_transform(const BL::Array< float, 16 > &array)
static void set_enum(PointerRNA &ptr, const char *name, const int value)
static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob, bool *has_subdivision_modifier)
static bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
static bool region_view3d_navigating_or_transforming(const BL::RegionView3D &b_rv3d)
static void set_string(PointerRNA &ptr, const char *name, const string &value)
static string image_user_file_path(BL::BlendData &data, BL::ImageUser &iuser, BL::Image &ima, const int cfra)
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
ccl_device_forceinline int4 make_int4(const int x, const int y, const int z, const int w)
#define assert(assertion)
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
bool enabled
const ccl_global KernelWorkTile * tile
PathRayFlag
@ PATH_RAY_SHADOW
@ PATH_RAY_TRANSMIT
@ PATH_RAY_VOLUME_SCATTER
@ PATH_RAY_GLOSSY
@ PATH_RAY_DIFFUSE
@ PATH_RAY_CAMERA
#define G(x, y, z)
string path_dirname(const string &path)
Definition path.cpp:401
string path_join(const string &dir, const string &file)
Definition path.cpp:415
const char * name
#define make_float2
#define make_float4
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
const PointerRNA PointerRNA_NULL
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_enum_set_identifier(bContext *C, PointerRNA *ptr, const char *name, const char *id)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
#define swap(a, b)
Definition sort.cc:59
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
BL::Object real_object
BL::Object iter_object
bool is_real_object_data() const
Definition DNA_ID.h:414
@ SUBDIVISION_FVAR_LINEAR_NONE
Definition scene/mesh.h:130
@ SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS2
Definition scene/mesh.h:133
@ SUBDIVISION_FVAR_LINEAR_CORNERS_ONLY
Definition scene/mesh.h:131
@ SUBDIVISION_FVAR_LINEAR_ALL
Definition scene/mesh.h:135
@ SUBDIVISION_FVAR_LINEAR_BOUNDARIES
Definition scene/mesh.h:134
@ SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS1
Definition scene/mesh.h:132
SubdivisionType
Definition scene/mesh.h:117
@ SUBDIVISION_NONE
Definition scene/mesh.h:118
@ SUBDIVISION_LINEAR
Definition scene/mesh.h:119
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:120
@ SUBDIVISION_BOUNDARY_EDGE_ONLY
Definition scene/mesh.h:125
@ SUBDIVISION_BOUNDARY_EDGE_AND_CORNER
Definition scene/mesh.h:126
MotionType need_motion() const
Definition scene.cpp:410
MotionType
Definition scene.h:185
@ MOTION_NONE
Definition scene.h:185
@ MOTION_BLUR
Definition scene.h:185
float x
Definition sky_math.h:136
float x
Definition sky_math.h:225
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
ccl_device_inline Transform make_transform(const float a, const float b, const float c, const float d, const float e, const float f, const float g, const float h, const float i, const float j, const float k, const float l)
Definition transform.h:159
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145