Blender V4.3
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#ifndef __BLENDER_UTIL_H__
6#define __BLENDER_UTIL_H__
7
8#include "scene/mesh.h"
9#include "scene/scene.h"
10
11#include "util/algorithm.h"
12#include "util/array.h"
13#include "util/map.h"
14#include "util/path.h"
15#include "util/set.h"
16#include "util/transform.h"
17#include "util/types.h"
18#include "util/vector.h"
19
20#include "BKE_image.hh"
21#include "BKE_mesh.hh"
22
24
26 /* Object directly provided by the depsgraph iterator. This object is only valid during one
27 * iteration and must not be accessed afterwards. Transforms and visibility should be checked on
28 * this object. */
29 BL::Object iter_object;
30
31 /* This object remains alive even after the object iterator is done. It corresponds to one
32 * original object. It is the object that owns the object data below. */
33 BL::Object real_object;
34
35 /* The object-data referenced by the iter object. This is still valid after the depsgraph
36 * iterator is done. It might have a different type compared to real_object.data(). */
38
39 /* True when the current geometry is the data of the referenced object. False when it is a
40 * geometry instance that does not have a 1-to-1 relationship with an object. */
42 {
43 return const_cast<BL::Object &>(real_object).data() == object_data;
44 }
45};
46
47typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
48BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
49
50void python_thread_state_save(void **python_thread_state);
51void python_thread_state_restore(void **python_thread_state);
52
53static bool mesh_use_corner_normals(BL::Mesh &mesh, Mesh::SubdivisionType subdivision_type)
54{
55 return mesh && (subdivision_type == Mesh::SUBDIVISION_NONE) &&
56 (static_cast<const ::Mesh *>(mesh.ptr.data)->normals_domain(true) ==
58}
59
60static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
61 BObjectInfo &b_ob_info,
62 BL::Depsgraph & /*depsgraph*/,
63 bool /*calc_undeformed*/,
64 Mesh::SubdivisionType subdivision_type)
65{
66 /* TODO: make this work with copy-on-evaluation, modifiers are already evaluated. */
67#if 0
68 bool subsurf_mod_show_render = false;
69 bool subsurf_mod_show_viewport = false;
70
71 if (subdivision_type != Mesh::SUBDIVISION_NONE) {
72 BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
73
74 subsurf_mod_show_render = subsurf_mod.show_render();
75 subsurf_mod_show_viewport = subsurf_mod.show_viewport();
76
77 subsurf_mod.show_render(false);
78 subsurf_mod.show_viewport(false);
79 }
80#endif
81
82 BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) :
83 BL::Mesh(PointerRNA_NULL);
84
85 bool use_corner_normals = false;
86
87 if (b_ob_info.is_real_object_data()) {
88 if (mesh) {
89 if (mesh.is_editmode()) {
90 /* Flush edit-mesh to mesh, including all data layers. */
91 BL::Depsgraph depsgraph(PointerRNA_NULL);
92 mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
93 use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
94 }
95 else if (mesh_use_corner_normals(mesh, subdivision_type)) {
96 /* Make a copy to split faces. */
97 BL::Depsgraph depsgraph(PointerRNA_NULL);
98 mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
99 use_corner_normals = true;
100 }
101 }
102 else {
103 BL::Depsgraph depsgraph(PointerRNA_NULL);
104 mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
105 use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
106 }
107 }
108 else {
109 /* TODO: what to do about non-mesh geometry instances? */
110 use_corner_normals = mesh_use_corner_normals(mesh, subdivision_type);
111 }
112
113#if 0
114 if (subdivision_type != Mesh::SUBDIVISION_NONE) {
115 BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
116
117 subsurf_mod.show_render(subsurf_mod_show_render);
118 subsurf_mod.show_viewport(subsurf_mod_show_viewport);
119 }
120#endif
121
122 if (mesh) {
123 if (use_corner_normals) {
124 mesh.split_faces();
125 }
126
127 if (subdivision_type == Mesh::SUBDIVISION_NONE) {
128 mesh.calc_loop_triangles();
129 }
130 }
131
132 return mesh;
133}
134
135static inline void free_object_to_mesh(BL::BlendData & /*data*/,
136 BObjectInfo &b_ob_info,
137 BL::Mesh &mesh)
138{
139 if (!b_ob_info.is_real_object_data()) {
140 return;
141 }
142 /* Free mesh if we didn't just use the existing one. */
143 BL::Object object = b_ob_info.real_object;
144 if (object.data().ptr.data != mesh.ptr.data) {
145 object.to_mesh_clear();
146 }
147}
148
149static inline void colorramp_to_array(BL::ColorRamp &ramp,
150 array<float3> &ramp_color,
151 array<float> &ramp_alpha,
152 int size)
153{
154 const int full_size = size + 1;
155 ramp_color.resize(full_size);
156 ramp_alpha.resize(full_size);
157
158 for (int i = 0; i < full_size; i++) {
159 float color[4];
160
161 ramp.evaluate(float(i) / float(size), color);
162 ramp_color[i] = make_float3(color[0], color[1], color[2]);
163 ramp_alpha[i] = color[3];
164 }
165}
166
167static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x)
168{
169 *min_x = min(*min_x, curve.points[0].location()[0]);
170 *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
171}
172
173static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
174 int num_curves,
175 float *min_x,
176 float *max_x)
177{
178 // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
179 *min_x = FLT_MAX;
180 *max_x = -FLT_MAX;
181 for (int i = 0; i < num_curves; ++i) {
182 BL::CurveMap map(cumap.curves[i]);
183 curvemap_minmax_curve(map, min_x, max_x);
184 }
185}
186
187static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size)
188{
189 cumap.update();
190 BL::CurveMap curve = cumap.curves[0];
191 const int full_size = size + 1;
192 data.resize(full_size);
193 for (int i = 0; i < full_size; i++) {
194 float t = float(i) / float(size);
195 data[i] = cumap.evaluate(curve, t);
196 }
197}
198
199static inline void curvemapping_float_to_array(BL::CurveMapping &cumap,
200 array<float> &data,
201 int size)
202{
203 float min = 0.0f, max = 1.0f;
204
205 curvemapping_minmax(cumap, 1, &min, &max);
206
207 const float range = max - min;
208
209 cumap.update();
210
211 BL::CurveMap map = cumap.curves[0];
212
213 const int full_size = size + 1;
214 data.resize(full_size);
215
216 for (int i = 0; i < full_size; i++) {
217 float t = min + float(i) / float(size) * range;
218 data[i] = cumap.evaluate(map, t);
219 }
220}
221
222static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
223 array<float3> &data,
224 int size,
225 bool rgb_curve)
226{
227 float min_x = 0.0f, max_x = 1.0f;
228
229 /* TODO(sergey): There is no easy way to automatically guess what is
230 * the range to be used here for the case when mapping is applied on
231 * top of another mapping (i.e. R curve applied on top of common
232 * one).
233 *
234 * Using largest possible range form all curves works correct for the
235 * cases like vector curves and should be good enough heuristic for
236 * the color curves as well.
237 *
238 * There might be some better estimations here tho.
239 */
240 const int num_curves = rgb_curve ? 4 : 3;
241 curvemapping_minmax(cumap, num_curves, &min_x, &max_x);
242
243 const float range_x = max_x - min_x;
244
245 cumap.update();
246
247 BL::CurveMap mapR = cumap.curves[0];
248 BL::CurveMap mapG = cumap.curves[1];
249 BL::CurveMap mapB = cumap.curves[2];
250
251 const int full_size = size + 1;
252 data.resize(full_size);
253
254 if (rgb_curve) {
255 BL::CurveMap mapI = cumap.curves[3];
256 for (int i = 0; i < full_size; i++) {
257 const float t = min_x + float(i) / float(size) * range_x;
258 data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
259 cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
260 cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
261 }
262 }
263 else {
264 for (int i = 0; i < full_size; i++) {
265 float t = min_x + float(i) / float(size) * range_x;
266 data[i] = make_float3(
267 cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
268 }
269 }
270}
271
272static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
273{
274 return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
275}
276
277static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
278{
279 if (!self.is_real_object_data()) {
280 /* Comes from geometry nodes, can't use heuristic to guess if it's animated. */
281 return true;
282 }
283
284 /* Use heuristic to quickly check if object is potentially animated. */
285 return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
286 false;
287}
288
289static inline int render_resolution_x(BL::RenderSettings &b_render)
290{
291 return b_render.resolution_x() * b_render.resolution_percentage() / 100;
292}
293
294static inline int render_resolution_y(BL::RenderSettings &b_render)
295{
296 return b_render.resolution_y() * b_render.resolution_percentage() / 100;
297}
298
299static inline string image_user_file_path(BL::BlendData &data,
300 BL::ImageUser &iuser,
301 BL::Image &ima,
302 int cfra)
303{
304 char filepath[1024];
305 iuser.tile(0);
307 static_cast<Image *>(ima.ptr.data), static_cast<ImageUser *>(iuser.ptr.data), cfra);
308 BKE_image_user_file_path_ex(static_cast<Main *>(data.ptr.data),
309 static_cast<ImageUser *>(iuser.ptr.data),
310 static_cast<Image *>(ima.ptr.data),
311 filepath,
312 false,
313 true);
314
315 return string(filepath);
316}
317
318static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
319{
321 static_cast<Image *>(ima.ptr.data), static_cast<ImageUser *>(iuser.ptr.data), cfra);
322 return iuser.frame_current();
323}
324
325static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
326{
327 return BKE_image_get_pixels_for_frame(static_cast<Image *>(image.ptr.data), frame, tile);
328}
329
330static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
331{
332 return BKE_image_get_float_pixels_for_frame(static_cast<Image *>(image.ptr.data), frame, tile);
333}
334
335static inline bool image_is_builtin(BL::Image &ima, BL::RenderEngine &engine)
336{
337 const BL::Image::source_enum image_source = ima.source();
338 if (image_source == BL::Image::source_TILED) {
339 /* If any tile is marked as generated, then treat the entire Image as built-in. */
340 for (BL::UDIMTile &tile : ima.tiles) {
341 if (tile.is_generated_tile()) {
342 return true;
343 }
344 }
345 }
346
347 return ima.packed_file() || image_source == BL::Image::source_GENERATED ||
348 image_source == BL::Image::source_MOVIE ||
349 (engine.is_preview() && image_source != BL::Image::source_SEQUENCE);
350}
351
352static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
353{
354 b_rr.stamp_data_add_field(name.c_str(), value.c_str());
355}
356
357/* Utilities */
358
359static inline Transform get_transform(const BL::Array<float, 16> &array)
360{
361 ProjectionTransform projection;
362
363 /* We assume both types to be just 16 floats, and transpose because blender
364 * use column major matrix order while we use row major. */
365 memcpy((void *)&projection, &array, sizeof(float) * 16);
366 projection = projection_transpose(projection);
367
368 /* Drop last row, matrix is assumed to be affine transform. */
369 return projection_to_transform(projection);
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, 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, 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, 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, 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 int value = RNA_property_enum_get(&ptr, prop);
486
487 RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
488
489 return string(identifier);
490}
491
492static inline void set_enum(PointerRNA &ptr, const char *name, 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(NULL, &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), NULL);
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 == NULL) {
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], texspace_size[3];
560 BKE_mesh_texspace_get(const_cast<::Mesh *>(&b_mesh), texspace_location, texspace_size);
561
562 loc = make_float3(texspace_location[0], texspace_location[1], texspace_location[2]);
563 size = make_float3(texspace_size[0], texspace_size[1], texspace_size[2]);
564
565 if (size.x != 0.0f) {
566 size.x = 0.5f / size.x;
567 }
568 if (size.y != 0.0f) {
569 size.y = 0.5f / size.y;
570 }
571 if (size.z != 0.0f) {
572 size.z = 0.5f / size.z;
573 }
574
575 loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
576}
577
578/* Object motion steps, returns 0 if no motion blur needed. */
579static inline uint object_motion_steps(BL::Object &b_parent,
580 BL::Object &b_ob,
581 const int max_steps = INT_MAX)
582{
583 /* Get motion enabled and steps from object itself. */
584 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
585 bool use_motion = get_boolean(cobject, "use_motion_blur");
586 if (!use_motion) {
587 return 0;
588 }
589
590 int steps = max(1, get_int(cobject, "motion_steps"));
591
592 /* Also check parent object, so motion blur and steps can be
593 * controlled by dupli-group duplicator for linked groups. */
594 if (b_parent.ptr.data != b_ob.ptr.data) {
595 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
596 use_motion &= get_boolean(parent_cobject, "use_motion_blur");
597
598 if (!use_motion) {
599 return 0;
600 }
601
602 steps = max(steps, get_int(parent_cobject, "motion_steps"));
603 }
604
605 /* Use uneven number of steps so we get one keyframe at the current frame,
606 * and use 2^(steps - 1) so objects with more/fewer steps still have samples
607 * at the same times, to avoid sampling at many different times. */
608 return min((2 << (steps - 1)) + 1, max_steps);
609}
610
611/* object uses deformation motion blur */
612static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
613{
614 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
615 bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
616 /* If motion blur is enabled for the object we also check
617 * whether it's enabled for the parent object as well.
618 *
619 * This way we can control motion blur from the dupli-group
620 * duplicator much easier. */
621 if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
622 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
623 use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
624 }
625 return use_deform_motion;
626}
627
628static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
629{
630 for (BL::Modifier &b_mod : b_ob.modifiers) {
631 if (b_mod.is_a(&RNA_FluidModifier)) {
632 BL::FluidModifier b_mmd(b_mod);
633
634 if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
635 b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS)
636 {
637 return b_mmd.domain_settings();
638 }
639 }
640 }
641
642 return BL::FluidDomainSettings(PointerRNA_NULL);
643}
644
645static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
646 bool *has_subdivision_modifier)
647{
648 for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
649 BL::Modifier b_mod = b_ob.modifiers[i];
650
651 if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
652 BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
653 return mesh_cache;
654 }
655
656 /* Skip possible particles system modifiers as they do not modify the geometry. */
657 if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
658 continue;
659 }
660
661 if (b_mod.type() == BL::Modifier::type_SUBSURF) {
662 if (has_subdivision_modifier) {
663 *has_subdivision_modifier = true;
664 }
665 continue;
666 }
667
668 break;
669 }
670
671 return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
672}
673
674static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
675 bool preview,
676 bool experimental)
677{
678 PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
679
680 if (cobj.data && !b_ob.modifiers.empty() && experimental) {
681 BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
682 bool enabled = preview ? mod.show_viewport() : mod.show_render();
683
684 if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
685 RNA_boolean_get(&cobj, "use_adaptive_subdivision"))
686 {
687 BL::SubsurfModifier subsurf(mod);
688
689 if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
691 }
692 else {
694 }
695 }
696 }
697
699}
700
701static inline uint object_ray_visibility(BL::Object &b_ob)
702{
703 uint flag = 0;
704
705 flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : 0;
706 flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : 0;
707 flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : 0;
708 flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : 0;
709 flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : 0;
710 flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : 0;
711
712 return flag;
713}
714
715/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
716 * things like velocity from cache modifier, fluid simulation).
717 *
718 * NOTE: This code is run prior to object motion blur initialization. so can not access properties
719 * set by `sync_object_motion_init()`. */
720static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
721{
722 const Scene::MotionType need_motion = scene->need_motion();
723 if (need_motion == Scene::MOTION_NONE) {
724 /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
725 * attributes. */
726 return false;
727 }
728
729 if (need_motion == Scene::MOTION_BLUR) {
730 /* A bit tricky and implicit case:
731 * - Motion blur is enabled in the scene, which implies specific number of time steps for
732 * objects.
733 * - If the object has motion blur disabled on it, it will have 0 time steps.
734 * - Motion attribute expects non-zero time steps.
735 *
736 * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
737 PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
738 const bool use_motion = get_boolean(cobject, "use_motion_blur");
739 if (!use_motion) {
740 return false;
741 }
742 }
743
744 /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
745 * level. */
746 return true;
747}
748
749class EdgeMap {
750 public:
752
753 void clear()
754 {
755 edges_.clear();
756 }
757
758 void insert(int v0, int v1)
759 {
760 get_sorted_verts(v0, v1);
761 edges_.insert(std::pair<int, int>(v0, v1));
762 }
763
764 bool exists(int v0, int v1)
765 {
766 get_sorted_verts(v0, v1);
767 return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
768 }
769
770 protected:
771 void get_sorted_verts(int &v0, int &v1)
772 {
773 if (v0 > v1) {
774 swap(v0, v1);
775 }
776 }
777
778 set<std::pair<int, int>> edges_;
779};
780
782
783#endif /* __BLENDER_UTIL_H__ */
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)
unsigned char * BKE_image_get_pixels_for_frame(Image *image, int frame, int tile)
float * BKE_image_get_float_pixels_for_frame(Image *image, int frame, int tile)
void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
unsigned int uint
const char * dirname(char *path)
constexpr PointerRNA PointerRNA_NULL
Definition RNA_types.hh:45
PyObject * self
set< std::pair< int, int > > edges_
void insert(int v0, int v1)
bool exists(int v0, int v1)
void get_sorted_verts(int &v0, int &v1)
T * resize(size_t newsize)
static string image_user_file_path(BL::BlendData &data, BL::ImageUser &iuser, BL::Image &ima, int cfra)
static float * image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
static uint object_ray_visibility(BL::Object &b_ob)
static float4 get_float4(const BL::Array< float, 4 > &array)
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 bool mesh_use_corner_normals(BL::Mesh &mesh, Mesh::SubdivisionType subdivision_type)
static float get_float(PointerRNA &ptr, const char *name)
static void curvemapping_float_to_array(BL::CurveMapping &cumap, array< float > &data, int size)
void python_thread_state_restore(void **python_thread_state)
Definition python.cpp:96
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 void set_float3(PointerRNA &ptr, const char *name, float3 value)
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(BL::BlendData &, BObjectInfo &b_ob_info, BL::Mesh &mesh)
static string get_enum_identifier(PointerRNA &ptr, const char *name)
static BL::Mesh object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Depsgraph &, bool, Mesh::SubdivisionType subdivision_type)
static string get_text_datablock_content(const PointerRNA &ptr)
static void colorramp_to_array(BL::ColorRamp &ramp, array< float3 > &ramp_color, array< float > &ramp_alpha, int size)
static void curvemapping_to_array(BL::CurveMapping &cumap, array< float > &data, int size)
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 set_enum(PointerRNA &ptr, const char *name, int value)
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 void set_float4(PointerRNA &ptr, const char *name, float4 value)
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 void curvemapping_color_to_array(BL::CurveMapping &cumap, array< float3 > &data, int size, bool rgb_curve)
static string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
static int3 get_int3(const BL::Array< int, 3 > &array)
static unsigned char * image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
static float2 get_float2(const BL::Array< float, 2 > &array)
static Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, bool preview, bool experimental)
static void set_int(PointerRNA &ptr, const char *name, int 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:91
static void curvemap_minmax_curve(BL::CurveMap &curve, float *min_x, float *max_x)
static string get_string(PointerRNA &ptr, const char *name)
static void set_float(PointerRNA &ptr, const char *name, float value)
static Transform get_transform(const BL::Array< float, 16 > &array)
static void curvemapping_minmax(BL::CurveMapping &cumap, int num_curves, float *min_x, float *max_x)
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 void set_string(PointerRNA &ptr, const char *name, const string &value)
BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType
static int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
ccl_device_inline Transform projection_to_transform(const ProjectionTransform &a)
ccl_device_inline ProjectionTransform projection_transpose(const ProjectionTransform &a)
const Depsgraph * depsgraph
#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)
#define NULL
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)
draw_view in_light_buf[] float
#define str(s)
IndexRange range
ccl_global const KernelWorkTile * tile
@ 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:105
string path_dirname(const string &path)
Definition path.cpp:403
string path_join(const string &dir, const string &file)
Definition path.cpp:417
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)
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)
static const int steps
#define swap(a, b)
Definition sort.c:55
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
BL::Object real_object
BL::Object iter_object
bool is_real_object_data() const
SubdivisionType
Definition scene/mesh.h:120
@ SUBDIVISION_NONE
Definition scene/mesh.h:121
@ SUBDIVISION_LINEAR
Definition scene/mesh.h:122
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:123
void * data
Definition RNA_types.hh:42
MotionType
Definition scene.h:177
@ MOTION_NONE
Definition scene.h:177
@ MOTION_BLUR
Definition scene.h:177
float x
Definition sky_float3.h:27
float max
ccl_device_inline int mod(int x, int m)
Definition util/math.h:520
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138