Blender V4.5
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;
81BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
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;
410 RNA_float_get_array(&ptr, name, &f.x);
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;
422 RNA_float_get_array(&ptr, name, &f.x);
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 char cstrbuf[1024];
505 char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), nullptr);
506 string str(cstr);
507 if (cstr != cstrbuf) {
508 MEM_freeN(cstr);
509 }
510
511 return str;
512}
513
514static inline void set_string(PointerRNA &ptr, const char *name, const string &value)
515{
516 RNA_string_set(&ptr, name, value.c_str());
517}
518
519/* Relative Paths */
520
521static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
522{
523 if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
524 string dirname;
525
526 if (b_id.library()) {
527 BL::ID b_library_id(b_id.library());
528 dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath());
529 }
530 else {
531 dirname = b_data.filepath();
532 }
533
534 return path_join(path_dirname(dirname), path.substr(2));
535 }
536
537 return path;
538}
539
540static inline string get_text_datablock_content(const PointerRNA &ptr)
541{
542 if (ptr.data == nullptr) {
543 return "";
544 }
545
546 string content;
547 BL::Text::lines_iterator iter;
548 for (iter.begin(ptr); iter; ++iter) {
549 content += iter->body() + "\n";
550 }
551
552 return content;
553}
554
555/* Texture Space */
556
557static inline void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
558{
559 float texspace_location[3];
560 float texspace_size[3];
561 BKE_mesh_texspace_get(const_cast<::Mesh *>(&b_mesh), texspace_location, texspace_size);
562
563 loc = make_float3(texspace_location[0], texspace_location[1], texspace_location[2]);
564 size = make_float3(texspace_size[0], texspace_size[1], texspace_size[2]);
565
566 if (size.x != 0.0f) {
567 size.x = 0.5f / size.x;
568 }
569 if (size.y != 0.0f) {
570 size.y = 0.5f / size.y;
571 }
572 if (size.z != 0.0f) {
573 size.z = 0.5f / size.z;
574 }
575
576 loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
577}
578
579/* Object motion steps, returns 0 if no motion blur needed. */
580static inline uint object_motion_steps(BL::Object &b_parent,
581 BL::Object &b_ob,
582 const int max_steps = INT_MAX)
583{
584 /* Get motion enabled and steps from object itself. */
585 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
586 bool use_motion = get_boolean(cobject, "use_motion_blur");
587 if (!use_motion) {
588 return 0;
589 }
590
591 int steps = max(1, get_int(cobject, "motion_steps"));
592
593 /* Also check parent object, so motion blur and steps can be
594 * controlled by dupli-group duplicator for linked groups. */
595 if (b_parent.ptr.data != b_ob.ptr.data) {
596 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
597 use_motion &= get_boolean(parent_cobject, "use_motion_blur");
598
599 if (!use_motion) {
600 return 0;
601 }
602
603 steps = max(steps, get_int(parent_cobject, "motion_steps"));
604 }
605
606 /* Use uneven number of steps so we get one keyframe at the current frame,
607 * and use 2^(steps - 1) so objects with more/fewer steps still have samples
608 * at the same times, to avoid sampling at many different times. */
609 return min((2 << (steps - 1)) + 1, max_steps);
610}
611
612/* object uses deformation motion blur */
613static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
614{
615 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
616 bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
617 /* If motion blur is enabled for the object we also check
618 * whether it's enabled for the parent object as well.
619 *
620 * This way we can control motion blur from the dupli-group
621 * duplicator much easier. */
622 if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
623 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
624 use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
625 }
626 return use_deform_motion;
627}
628
629static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
630{
631 for (BL::Modifier &b_mod : b_ob.modifiers) {
632 if (b_mod.is_a(&RNA_FluidModifier)) {
633 BL::FluidModifier b_mmd(b_mod);
634
635 if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
636 b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS)
637 {
638 return b_mmd.domain_settings();
639 }
640 }
641 }
642
643 return BL::FluidDomainSettings(PointerRNA_NULL);
644}
645
646static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
647 bool *has_subdivision_modifier)
648{
649 for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
650 BL::Modifier b_mod = b_ob.modifiers[i];
651
652 if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
653 BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
654 return mesh_cache;
655 }
656
657 /* Skip possible particles system modifiers as they do not modify the geometry. */
658 if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
659 continue;
660 }
661
662 if (b_mod.type() == BL::Modifier::type_SUBSURF) {
663 if (has_subdivision_modifier) {
664 *has_subdivision_modifier = true;
665 }
666 continue;
667 }
668
669 break;
670 }
671
672 return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
673}
674
675static BL::SubsurfModifier object_subdivision_modifier(BL::Object &b_ob, const bool preview)
676{
677 PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
678
679 if (cobj.data && !b_ob.modifiers.empty()) {
680 BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
681 const bool enabled = preview ? mod.show_viewport() : mod.show_render();
682
683 if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
684 RNA_boolean_get(&cobj, "use_adaptive_subdivision"))
685 {
686 BL::SubsurfModifier subsurf(mod);
687 return subsurf;
688 }
689 }
690
691 return PointerRNA_NULL;
692}
693
694static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
695 const bool preview,
696 const bool use_adaptive_subdivision)
697{
698 if (!use_adaptive_subdivision) {
700 }
701
702 BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
703
704 if (subsurf) {
705 if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
707 }
709 }
710
712}
713
714static inline void object_subdivision_to_mesh(BL::Object &b_ob,
715 Mesh &mesh,
716 const bool preview,
717 const bool use_adaptive_subdivision)
718{
719 if (!use_adaptive_subdivision) {
720 mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE);
721 return;
722 }
723
724 BL::SubsurfModifier subsurf = object_subdivision_modifier(b_ob, preview);
725
726 if (!subsurf) {
727 mesh.set_subdivision_type(Mesh::SUBDIVISION_NONE);
728 return;
729 }
730
731 if (subsurf.subdivision_type() != BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
732 mesh.set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
733 return;
734 }
735
736 mesh.set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
737
738 switch (subsurf.boundary_smooth()) {
739 case BL::SubsurfModifier::boundary_smooth_PRESERVE_CORNERS:
740 mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_AND_CORNER);
741 break;
742 case BL::SubsurfModifier::boundary_smooth_ALL:
743 mesh.set_subdivision_boundary_interpolation(Mesh::SUBDIVISION_BOUNDARY_EDGE_ONLY);
744 break;
745 }
746
747 switch (subsurf.uv_smooth()) {
748 case BL::SubsurfModifier::uv_smooth_NONE:
749 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_ALL);
750 break;
751 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS:
752 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_ONLY);
753 break;
754 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_AND_JUNCTIONS:
755 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS1);
756 break;
757 case BL::SubsurfModifier::uv_smooth_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
758 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_CORNERS_PLUS2);
759 break;
760 case BL::SubsurfModifier::uv_smooth_PRESERVE_BOUNDARIES:
761 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_BOUNDARIES);
762 break;
763 case BL::SubsurfModifier::uv_smooth_SMOOTH_ALL:
764 mesh.set_subdivision_fvar_interpolation(Mesh::SUBDIVISION_FVAR_LINEAR_NONE);
765 break;
766 }
767}
768
769static inline uint object_ray_visibility(BL::Object &b_ob)
770{
771 uint flag = 0;
772
773 flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : PathRayFlag(0);
774 flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : PathRayFlag(0);
775 flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : PathRayFlag(0);
776 flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : PathRayFlag(0);
777 flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : PathRayFlag(0);
778 flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : PathRayFlag(0);
779
780 return flag;
781}
782
783/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
784 * things like velocity from cache modifier, fluid simulation).
785 *
786 * NOTE: This code is run prior to object motion blur initialization. so can not access properties
787 * set by `sync_object_motion_init()`. */
788static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
789{
790 const Scene::MotionType need_motion = scene->need_motion();
791 if (need_motion == Scene::MOTION_NONE) {
792 /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
793 * attributes. */
794 return false;
795 }
796
797 if (need_motion == Scene::MOTION_BLUR) {
798 /* A bit tricky and implicit case:
799 * - Motion blur is enabled in the scene, which implies specific number of time steps for
800 * objects.
801 * - If the object has motion blur disabled on it, it will have 0 time steps.
802 * - Motion attribute expects non-zero time steps.
803 *
804 * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
805 PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
806 const bool use_motion = get_boolean(cobject, "use_motion_blur");
807 if (!use_motion) {
808 return false;
809 }
810 }
811
812 /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
813 * level. */
814 return true;
815}
816
817static inline bool region_view3d_navigating_or_transforming(const BL::RegionView3D &b_rv3d)
818{
819 ::RegionView3D *rv3d = static_cast<::RegionView3D *>(b_rv3d.ptr.data);
820 return rv3d && ((rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) ||
821 (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)));
822}
823
824class EdgeMap {
825 public:
826 EdgeMap() = default;
827
828 void clear()
829 {
830 edges_.clear();
831 }
832
833 void insert(int v0, int v1)
834 {
835 get_sorted_verts(v0, v1);
836 edges_.insert(std::pair<int, int>(v0, v1));
837 }
838
839 bool exists(int v0, int v1)
840 {
841 get_sorted_verts(v0, v1);
842 return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
843 }
844
845 protected:
846 void get_sorted_verts(int &v0, int &v1)
847 {
848 if (v0 > v1) {
849 swap(v0, v1);
850 }
851 }
852
853 set<std::pair<int, int>> edges_;
854};
855
@ 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)
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 float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline float2 make_float2(const float x, const float y)
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 str(s)
VecBase< float, 4 > float4
#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
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#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
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)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
float RNA_float_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)
static const int steps
#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:404
@ 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
void * data
Definition RNA_types.hh:53
MotionType need_motion() const
Definition scene.cpp:399
MotionType
Definition scene.h:184
@ MOTION_NONE
Definition scene.h:184
@ MOTION_BLUR
Definition scene.h:184
float x
Definition sky_float3.h:27
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:126
PointerRNA * ptr
Definition wm_files.cc:4227
uint8_t flag
Definition wm_window.cc:139