diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-10-24 15:19:19 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-10-26 16:37:04 +0300 |
commit | fd25e883e2807a151f673b87c152a59701a0df80 (patch) | |
tree | 9441933f32ba2672ca71c58842342a9c525e123e /intern/cycles/blender/util.h | |
parent | d7d40745fa09061a3117bd3669c5a46bbf611eae (diff) |
Cycles: remove prefix from source code file names
Remove prefix of filenames that is the same as the folder name. This used
to help when #includes were using individual files, but now they are always
relative to the cycles root directory and so the prefixes are redundant.
For patches and branches, git merge and rebase should be able to detect the
renames and move over code to the right file.
Diffstat (limited to 'intern/cycles/blender/util.h')
-rw-r--r-- | intern/cycles/blender/util.h | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h new file mode 100644 index 00000000000..33fd2c416c8 --- /dev/null +++ b/intern/cycles/blender/util.h @@ -0,0 +1,720 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLENDER_UTIL_H__ +#define __BLENDER_UTIL_H__ + +#include "scene/mesh.h" + +#include "util/algorithm.h" +#include "util/array.h" +#include "util/map.h" +#include "util/path.h" +#include "util/set.h" +#include "util/transform.h" +#include "util/types.h" +#include "util/vector.h" + +/* Hacks to hook into Blender API + * todo: clean this up ... */ + +extern "C" { +void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra); +void BKE_image_user_file_path(void *iuser, void *ima, char *path); +unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile); +float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile); +} + +CCL_NAMESPACE_BEGIN + +struct BObjectInfo { + /* Object directly provided by the depsgraph iterator. This object is only valid during one + * iteration and must not be accessed afterwards. Transforms and visibility should be checked on + * this object. */ + BL::Object iter_object; + + /* This object remains alive even after the object iterator is done. It corresponds to one + * original object. It is the object that owns the object data below. */ + BL::Object real_object; + + /* The object-data referenced by the iter object. This is still valid after the depsgraph + * iterator is done. It might have a different type compared to real_object.data(). */ + BL::ID object_data; + + /* True when the current geometry is the data of the referenced object. False when it is a + * geometry instance that does not have a 1-to-1 relationship with an object. */ + bool is_real_object_data() const + { + return const_cast<BL::Object &>(real_object).data() == object_data; + } +}; + +typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType; +BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name); + +void python_thread_state_save(void **python_thread_state); +void python_thread_state_restore(void **python_thread_state); + +static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/, + BObjectInfo &b_ob_info, + BL::Depsgraph & /*depsgraph*/, + bool /*calc_undeformed*/, + Mesh::SubdivisionType subdivision_type) +{ + /* TODO: make this work with copy-on-write, modifiers are already evaluated. */ +#if 0 + bool subsurf_mod_show_render = false; + bool subsurf_mod_show_viewport = false; + + if (subdivision_type != Mesh::SUBDIVISION_NONE) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1]; + + subsurf_mod_show_render = subsurf_mod.show_render(); + subsurf_mod_show_viewport = subsurf_mod.show_viewport(); + + subsurf_mod.show_render(false); + subsurf_mod.show_viewport(false); + } +#endif + + BL::Mesh mesh = (b_ob_info.object_data.is_a(&RNA_Mesh)) ? BL::Mesh(b_ob_info.object_data) : + BL::Mesh(PointerRNA_NULL); + + if (b_ob_info.is_real_object_data()) { + if (mesh) { + /* Make a copy to split faces if we use autosmooth, otherwise not needed. + * Also in edit mode do we need to make a copy, to ensure data layers like + * UV are not empty. */ + if (mesh.is_editmode() || + (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) { + BL::Depsgraph depsgraph(PointerRNA_NULL); + mesh = b_ob_info.real_object.to_mesh(false, depsgraph); + } + } + else { + BL::Depsgraph depsgraph(PointerRNA_NULL); + mesh = b_ob_info.real_object.to_mesh(false, depsgraph); + } + } + else { + /* TODO: what to do about non-mesh geometry instances? */ + } + +#if 0 + if (subdivision_type != Mesh::SUBDIVISION_NONE) { + BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1]; + + subsurf_mod.show_render(subsurf_mod_show_render); + subsurf_mod.show_viewport(subsurf_mod_show_viewport); + } +#endif + + if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) { + if (mesh.use_auto_smooth()) { + mesh.split_faces(false); + } + + mesh.calc_loop_triangles(); + } + + return mesh; +} + +static inline void free_object_to_mesh(BL::BlendData & /*data*/, + BObjectInfo &b_ob_info, + BL::Mesh &mesh) +{ + if (!b_ob_info.is_real_object_data()) { + return; + } + /* Free mesh if we didn't just use the existing one. */ + BL::Object object = b_ob_info.real_object; + if (object.data().ptr.data != mesh.ptr.data) { + object.to_mesh_clear(); + } +} + +static inline void colorramp_to_array(BL::ColorRamp &ramp, + array<float3> &ramp_color, + array<float> &ramp_alpha, + int size) +{ + ramp_color.resize(size); + ramp_alpha.resize(size); + + for (int i = 0; i < size; i++) { + float color[4]; + + ramp.evaluate((float)i / (float)(size - 1), color); + ramp_color[i] = make_float3(color[0], color[1], color[2]); + ramp_alpha[i] = color[3]; + } +} + +static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x) +{ + *min_x = min(*min_x, curve.points[0].location()[0]); + *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]); +} + +static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap, + int num_curves, + float *min_x, + float *max_x) +{ + // const int num_curves = cumap.curves.length(); /* Gives linking error so far. */ + *min_x = FLT_MAX; + *max_x = -FLT_MAX; + for (int i = 0; i < num_curves; ++i) { + BL::CurveMap map(cumap.curves[i]); + curvemap_minmax_curve(map, min_x, max_x); + } +} + +static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size) +{ + cumap.update(); + BL::CurveMap curve = cumap.curves[0]; + data.resize(size); + for (int i = 0; i < size; i++) { + float t = (float)i / (float)(size - 1); + data[i] = cumap.evaluate(curve, t); + } +} + +static inline void curvemapping_float_to_array(BL::CurveMapping &cumap, + array<float> &data, + int size) +{ + float min = 0.0f, max = 1.0f; + + curvemapping_minmax(cumap, 1, &min, &max); + + const float range = max - min; + + cumap.update(); + + BL::CurveMap map = cumap.curves[0]; + + data.resize(size); + + for (int i = 0; i < size; i++) { + float t = min + (float)i / (float)(size - 1) * range; + data[i] = cumap.evaluate(map, t); + } +} + +static inline void curvemapping_color_to_array(BL::CurveMapping &cumap, + array<float3> &data, + int size, + bool rgb_curve) +{ + float min_x = 0.0f, max_x = 1.0f; + + /* TODO(sergey): There is no easy way to automatically guess what is + * the range to be used here for the case when mapping is applied on + * top of another mapping (i.e. R curve applied on top of common + * one). + * + * Using largest possible range form all curves works correct for the + * cases like vector curves and should be good enough heuristic for + * the color curves as well. + * + * There might be some better estimations here tho. + */ + const int num_curves = rgb_curve ? 4 : 3; + curvemapping_minmax(cumap, num_curves, &min_x, &max_x); + + const float range_x = max_x - min_x; + + cumap.update(); + + BL::CurveMap mapR = cumap.curves[0]; + BL::CurveMap mapG = cumap.curves[1]; + BL::CurveMap mapB = cumap.curves[2]; + + data.resize(size); + + if (rgb_curve) { + BL::CurveMap mapI = cumap.curves[3]; + for (int i = 0; i < size; i++) { + const float t = min_x + (float)i / (float)(size - 1) * range_x; + data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)), + cumap.evaluate(mapG, cumap.evaluate(mapI, t)), + cumap.evaluate(mapB, cumap.evaluate(mapI, t))); + } + } + else { + for (int i = 0; i < size; i++) { + float t = min_x + (float)i / (float)(size - 1) * range_x; + data[i] = make_float3( + cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t)); + } + } +} + +static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview) +{ + return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false; +} + +static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview) +{ + if (!self.is_real_object_data()) { + return false; + } + return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : + false; +} + +static inline int render_resolution_x(BL::RenderSettings &b_render) +{ + return b_render.resolution_x() * b_render.resolution_percentage() / 100; +} + +static inline int render_resolution_y(BL::RenderSettings &b_render) +{ + return b_render.resolution_y() * b_render.resolution_percentage() / 100; +} + +static inline string image_user_file_path(BL::ImageUser &iuser, + BL::Image &ima, + int cfra, + bool load_tiled) +{ + char filepath[1024]; + iuser.tile(0); + BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra); + BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath); + + string filepath_str = string(filepath); + if (load_tiled && ima.source() == BL::Image::source_TILED) { + string udim; + if (ima.tiles.length() > 0) { + udim = to_string(ima.tiles[0].number()); + } + string_replace(filepath_str, udim, "<UDIM>"); + } + return filepath_str; +} + +static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra) +{ + BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra); + return iuser.frame_current(); +} + +static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile) +{ + return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile); +} + +static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile) +{ + return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile); +} + +static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value) +{ + b_rr.stamp_data_add_field(name.c_str(), value.c_str()); +} + +/* Utilities */ + +static inline Transform get_transform(const BL::Array<float, 16> &array) +{ + ProjectionTransform projection; + + /* We assume both types to be just 16 floats, and transpose because blender + * use column major matrix order while we use row major. */ + memcpy((void *)&projection, &array, sizeof(float) * 16); + projection = projection_transpose(projection); + + /* Drop last row, matrix is assumed to be affine transform. */ + return projection_to_transform(projection); +} + +static inline float2 get_float2(const BL::Array<float, 2> &array) +{ + return make_float2(array[0], array[1]); +} + +static inline float3 get_float3(const BL::Array<float, 2> &array) +{ + return make_float3(array[0], array[1], 0.0f); +} + +static inline float3 get_float3(const BL::Array<float, 3> &array) +{ + return make_float3(array[0], array[1], array[2]); +} + +static inline float3 get_float3(const BL::Array<float, 4> &array) +{ + return make_float3(array[0], array[1], array[2]); +} + +static inline float4 get_float4(const BL::Array<float, 4> &array) +{ + return make_float4(array[0], array[1], array[2], array[3]); +} + +static inline int3 get_int3(const BL::Array<int, 3> &array) +{ + return make_int3(array[0], array[1], array[2]); +} + +static inline int4 get_int4(const BL::Array<int, 4> &array) +{ + return make_int4(array[0], array[1], array[2], array[3]); +} + +static inline float3 get_float3(PointerRNA &ptr, const char *name) +{ + float3 f; + RNA_float_get_array(&ptr, name, &f.x); + return f; +} + +static inline void set_float3(PointerRNA &ptr, const char *name, float3 value) +{ + RNA_float_set_array(&ptr, name, &value.x); +} + +static inline float4 get_float4(PointerRNA &ptr, const char *name) +{ + float4 f; + RNA_float_get_array(&ptr, name, &f.x); + return f; +} + +static inline void set_float4(PointerRNA &ptr, const char *name, float4 value) +{ + RNA_float_set_array(&ptr, name, &value.x); +} + +static inline bool get_boolean(PointerRNA &ptr, const char *name) +{ + return RNA_boolean_get(&ptr, name) ? true : false; +} + +static inline void set_boolean(PointerRNA &ptr, const char *name, bool value) +{ + RNA_boolean_set(&ptr, name, (int)value); +} + +static inline float get_float(PointerRNA &ptr, const char *name) +{ + return RNA_float_get(&ptr, name); +} + +static inline void set_float(PointerRNA &ptr, const char *name, float value) +{ + RNA_float_set(&ptr, name, value); +} + +static inline int get_int(PointerRNA &ptr, const char *name) +{ + return RNA_int_get(&ptr, name); +} + +static inline void set_int(PointerRNA &ptr, const char *name, int value) +{ + RNA_int_set(&ptr, name, value); +} + +/* Get a RNA enum value with sanity check: if the RNA value is above num_values + * the function will return a fallback default value. + * + * NOTE: This function assumes that RNA enum values are a continuous sequence + * from 0 to num_values-1. Be careful to use it with enums where some values are + * deprecated! + */ +static inline int get_enum(PointerRNA &ptr, + const char *name, + int num_values = -1, + int default_value = -1) +{ + int value = RNA_enum_get(&ptr, name); + if (num_values != -1 && value >= num_values) { + assert(default_value != -1); + value = default_value; + } + return value; +} + +static inline string get_enum_identifier(PointerRNA &ptr, const char *name) +{ + PropertyRNA *prop = RNA_struct_find_property(&ptr, name); + const char *identifier = ""; + int value = RNA_property_enum_get(&ptr, prop); + + RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier); + + return string(identifier); +} + +static inline void set_enum(PointerRNA &ptr, const char *name, int value) +{ + RNA_enum_set(&ptr, name, value); +} + +static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier) +{ + RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str()); +} + +static inline string get_string(PointerRNA &ptr, const char *name) +{ + char cstrbuf[1024]; + char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), NULL); + string str(cstr); + if (cstr != cstrbuf) + MEM_freeN(cstr); + + return str; +} + +static inline void set_string(PointerRNA &ptr, const char *name, const string &value) +{ + RNA_string_set(&ptr, name, value.c_str()); +} + +/* Relative Paths */ + +static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path) +{ + if (path.size() >= 2 && path[0] == '/' && path[1] == '/') { + string dirname; + + if (b_id.library()) { + BL::ID b_library_id(b_id.library()); + dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath()); + } + else + dirname = b_data.filepath(); + + return path_join(path_dirname(dirname), path.substr(2)); + } + + return path; +} + +static inline string get_text_datablock_content(const PointerRNA &ptr) +{ + if (ptr.data == NULL) { + return ""; + } + + string content; + BL::Text::lines_iterator iter; + for (iter.begin(ptr); iter; ++iter) { + content += iter->body() + "\n"; + } + + return content; +} + +/* Texture Space */ + +static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size) +{ + loc = get_float3(b_mesh.texspace_location()); + size = get_float3(b_mesh.texspace_size()); + + if (size.x != 0.0f) + size.x = 0.5f / size.x; + if (size.y != 0.0f) + size.y = 0.5f / size.y; + if (size.z != 0.0f) + size.z = 0.5f / size.z; + + loc = loc * size - make_float3(0.5f, 0.5f, 0.5f); +} + +/* Object motion steps, returns 0 if no motion blur needed. */ +static inline uint object_motion_steps(BL::Object &b_parent, + BL::Object &b_ob, + const int max_steps = INT_MAX) +{ + /* Get motion enabled and steps from object itself. */ + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool use_motion = get_boolean(cobject, "use_motion_blur"); + if (!use_motion) { + return 0; + } + + int steps = max(1, get_int(cobject, "motion_steps")); + + /* Also check parent object, so motion blur and steps can be + * controlled by dupligroup duplicator for linked groups. */ + if (b_parent.ptr.data != b_ob.ptr.data) { + PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); + use_motion &= get_boolean(parent_cobject, "use_motion_blur"); + + if (!use_motion) { + return 0; + } + + steps = max(steps, get_int(parent_cobject, "motion_steps")); + } + + /* Use uneven number of steps so we get one keyframe at the current frame, + * and use 2^(steps - 1) so objects with more/fewer steps still have samples + * at the same times, to avoid sampling at many different times. */ + return min((2 << (steps - 1)) + 1, max_steps); +} + +/* object uses deformation motion blur */ +static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob) +{ + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + bool use_deform_motion = get_boolean(cobject, "use_deform_motion"); + /* If motion blur is enabled for the object we also check + * whether it's enabled for the parent object as well. + * + * This way we can control motion blur from the dupligroup + * duplicator much easier. + */ + if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) { + PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles"); + use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion"); + } + return use_deform_motion; +} + +static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob) +{ + for (BL::Modifier &b_mod : b_ob.modifiers) { + if (b_mod.is_a(&RNA_FluidModifier)) { + BL::FluidModifier b_mmd(b_mod); + + if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN && + b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) { + return b_mmd.domain_settings(); + } + } + } + + return BL::FluidDomainSettings(PointerRNA_NULL); +} + +static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob, + bool *has_subdivision_modifier) +{ + for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) { + BL::Modifier b_mod = b_ob.modifiers[i]; + + if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) { + BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod); + return mesh_cache; + } + + /* Skip possible particles system modifiers as they do not modify the geometry. */ + if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) { + continue; + } + + if (b_mod.type() == BL::Modifier::type_SUBSURF) { + if (has_subdivision_modifier) { + *has_subdivision_modifier = true; + } + continue; + } + + break; + } + + return BL::MeshSequenceCacheModifier(PointerRNA_NULL); +} + +static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, + bool preview, + bool experimental) +{ + PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); + + if (cobj.data && b_ob.modifiers.length() > 0 && experimental) { + BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1]; + bool enabled = preview ? mod.show_viewport() : mod.show_render(); + + if (enabled && mod.type() == BL::Modifier::type_SUBSURF && + RNA_boolean_get(&cobj, "use_adaptive_subdivision")) { + BL::SubsurfModifier subsurf(mod); + + if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) { + return Mesh::SUBDIVISION_CATMULL_CLARK; + } + else { + return Mesh::SUBDIVISION_LINEAR; + } + } + } + + return Mesh::SUBDIVISION_NONE; +} + +static inline uint object_ray_visibility(BL::Object &b_ob) +{ + uint flag = 0; + + flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : 0; + flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : 0; + flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : 0; + flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : 0; + flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : 0; + flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : 0; + + return flag; +} + +class EdgeMap { + public: + EdgeMap() + { + } + + void clear() + { + edges_.clear(); + } + + void insert(int v0, int v1) + { + get_sorted_verts(v0, v1); + edges_.insert(std::pair<int, int>(v0, v1)); + } + + bool exists(int v0, int v1) + { + get_sorted_verts(v0, v1); + return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end(); + } + + protected: + void get_sorted_verts(int &v0, int &v1) + { + if (v0 > v1) { + swap(v0, v1); + } + } + + set<std::pair<int, int>> edges_; +}; + +CCL_NAMESPACE_END + +#endif /* __BLENDER_UTIL_H__ */ |