Cleanup: split Cycles export into smaller files
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 2 Feb 2020 12:09:18 +0000 (13:09 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Fri, 7 Feb 2020 11:18:15 +0000 (12:18 +0100)
14 files changed:
intern/cycles/blender/CMakeLists.txt
intern/cycles/blender/blender_curves.cpp
intern/cycles/blender/blender_geometry.cpp [new file with mode: 0644]
intern/cycles/blender/blender_id_map.h [new file with mode: 0644]
intern/cycles/blender/blender_image.cpp [new file with mode: 0644]
intern/cycles/blender/blender_light.cpp [new file with mode: 0644]
intern/cycles/blender/blender_mesh.cpp
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_object_cull.cpp
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/blender/blender_util.h
intern/cycles/blender/blender_volume.cpp [new file with mode: 0644]

index 0888eeb78bbc07ac772faebd82f51f4616736e5f..d9a2ebf85711e21804011acc27875c700a826e82 100644 (file)
@@ -18,6 +18,9 @@ set(INC_SYS
 set(SRC
   blender_camera.cpp
   blender_device.cpp
+  blender_image.cpp
+  blender_geometry.cpp
+  blender_light.cpp
   blender_mesh.cpp
   blender_object.cpp
   blender_object_cull.cpp
@@ -30,9 +33,11 @@ set(SRC
   blender_sync.cpp
   blender_texture.cpp
   blender_viewport.cpp
+  blender_volume.cpp
 
   CCL_api.h
   blender_device.h
+  blender_id_map.h
   blender_object_cull.h
   blender_sync.h
   blender_session.h
index 755214f422c0cbd05839e0bd6373da71f6d8c03e..64efaab70e0de42772ae55895b92e83c23e31917 100644 (file)
@@ -1160,6 +1160,63 @@ void BlenderSync::sync_particle_hair(
   }
 
   mesh->compute_bounds();
+  mesh->geometry_flags |= Mesh::GEOMETRY_CURVES;
+}
+
+void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
+{
+  /* compares curve_keys rather than strands in order to handle quick hair
+   * adjustments in dynamic BVH - other methods could probably do this better*/
+  array<float3> oldcurve_keys;
+  array<float> oldcurve_radius;
+  oldcurve_keys.steal_data(mesh->curve_keys);
+  oldcurve_radius.steal_data(mesh->curve_radius);
+
+  if (view_layer.use_hair) {
+    /* Particle hair. */
+    bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
+    BL::Mesh b_mesh = object_to_mesh(
+        b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
+
+    if (b_mesh) {
+      sync_particle_hair(mesh, b_mesh, b_ob, false);
+      free_object_to_mesh(b_data, b_ob, b_mesh);
+    }
+  }
+
+  /* tag update */
+  bool rebuild = (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius);
+  mesh->tag_update(scene, rebuild);
+}
+
+void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
+                                   BL::Object b_ob,
+                                   Mesh *mesh,
+                                   int motion_step)
+{
+  /* Skip if no curves were exported. */
+  size_t numkeys = mesh->curve_keys.size();
+  if (numkeys == 0) {
+    return;
+  }
+
+  /* Export deformed coordinates. */
+  if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
+    /* Particle hair. */
+    BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
+    if (b_mesh) {
+      sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step);
+      free_object_to_mesh(b_data, b_ob, b_mesh);
+      return;
+    }
+  }
+
+  /* No deformation on this frame, copy coordinates if other frames did have it. */
+  Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+  if (attr_mP) {
+    float3 *keys = &mesh->curve_keys[0];
+    memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys);
+  }
 }
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp
new file mode 100644 (file)
index 0000000..151b741
--- /dev/null
@@ -0,0 +1,146 @@
+
+/*
+ * 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.
+ */
+
+#include "render/mesh.h"
+#include "render/object.h"
+
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+Mesh *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
+                                 BL::Object &b_ob,
+                                 BL::Object &b_ob_instance,
+                                 bool object_updated,
+                                 bool use_particle_hair)
+{
+  /* Test if we can instance or if the object is modified. */
+  BL::ID b_ob_data = b_ob.data();
+  BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
+  MeshKey key(b_key_id.ptr.data, use_particle_hair);
+  BL::Material material_override = view_layer.material_override;
+  Shader *default_shader = scene->default_surface;
+
+  /* Find shader indices. */
+  vector<Shader *> used_shaders;
+
+  BL::Object::material_slots_iterator slot;
+  for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
+    if (material_override) {
+      find_shader(material_override, used_shaders, default_shader);
+    }
+    else {
+      BL::ID b_material(slot->material());
+      find_shader(b_material, used_shaders, default_shader);
+    }
+  }
+
+  if (used_shaders.size() == 0) {
+    if (material_override)
+      find_shader(material_override, used_shaders, default_shader);
+    else
+      used_shaders.push_back(default_shader);
+  }
+
+  /* Test if we need to sync. */
+  Mesh *mesh;
+
+  if (!mesh_map.sync(&mesh, b_key_id, key)) {
+    /* If transform was applied to mesh, need full update. */
+    if (object_updated && mesh->transform_applied)
+      ;
+    /* Test if shaders changed, these can be object level so mesh
+     * does not get tagged for recalc. */
+    else if (mesh->used_shaders != used_shaders)
+      ;
+    else {
+      /* Even if not tagged for recalc, we may need to sync anyway
+       * because the shader needs different mesh attributes. */
+      bool attribute_recalc = false;
+
+      foreach (Shader *shader, mesh->used_shaders)
+        if (shader->need_update_mesh)
+          attribute_recalc = true;
+
+      if (!attribute_recalc)
+        return mesh;
+    }
+  }
+
+  /* Ensure we only sync instanced meshes once. */
+  if (mesh_synced.find(mesh) != mesh_synced.end())
+    return mesh;
+
+  progress.set_sync_status("Synchronizing object", b_ob.name());
+
+  mesh_synced.insert(mesh);
+
+  mesh->clear();
+  mesh->used_shaders = used_shaders;
+  mesh->name = ustring(b_ob_data.name().c_str());
+
+  if (use_particle_hair) {
+    sync_hair(b_depsgraph, b_ob, mesh);
+  }
+  else if (object_fluid_gas_domain_find(b_ob)) {
+    sync_volume(b_ob, mesh);
+  }
+  else {
+    sync_mesh(b_depsgraph, b_ob, mesh);
+  }
+
+  return mesh;
+}
+
+void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
+                                       BL::Object &b_ob,
+                                       Object *object,
+                                       float motion_time,
+                                       bool use_particle_hair)
+{
+  /* Ensure we only sync instanced meshes once. */
+  Mesh *mesh = object->mesh;
+
+  if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
+    return;
+
+  mesh_motion_synced.insert(mesh);
+
+  /* Ensure we only motion sync meshes that also had mesh synced, to avoid
+   * unnecessary work and to ensure that its attributes were clear. */
+  if (mesh_synced.find(mesh) == mesh_synced.end())
+    return;
+
+  /* Find time matching motion step required by mesh. */
+  int motion_step = mesh->motion_step(motion_time);
+  if (motion_step < 0) {
+    return;
+  }
+
+  if (use_particle_hair) {
+    sync_hair_motion(b_depsgraph, b_ob, mesh, motion_step);
+  }
+  else if (object_fluid_gas_domain_find(b_ob)) {
+    /* No volume motion blur support yet. */
+  }
+  else {
+    sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
+  }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_id_map.h b/intern/cycles/blender/blender_id_map.h
new file mode 100644 (file)
index 0000000..52031cd
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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_ID_MAP_H__
+#define __BLENDER_ID_MAP_H__
+
+#include <string.h>
+
+#include "util/util_map.h"
+#include "util/util_set.h"
+#include "util/util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* ID Map
+ *
+ * Utility class to map between Blender datablocks and Cycles data structures,
+ * and keep track of recalc tags from the dependency graph. */
+
+template<typename K, typename T> class id_map {
+ public:
+  id_map(vector<T *> *scene_data_)
+  {
+    scene_data = scene_data_;
+  }
+
+  T *find(const BL::ID &id)
+  {
+    return find(id.ptr.owner_id);
+  }
+
+  T *find(const K &key)
+  {
+    if (b_map.find(key) != b_map.end()) {
+      T *data = b_map[key];
+      return data;
+    }
+
+    return NULL;
+  }
+
+  void set_recalc(const BL::ID &id)
+  {
+    b_recalc.insert(id.ptr.data);
+  }
+
+  void set_recalc(void *id_ptr)
+  {
+    b_recalc.insert(id_ptr);
+  }
+
+  bool has_recalc()
+  {
+    return !(b_recalc.empty());
+  }
+
+  void pre_sync()
+  {
+    used_set.clear();
+  }
+
+  bool sync(T **r_data, const BL::ID &id)
+  {
+    return sync(r_data, id, id, id.ptr.owner_id);
+  }
+
+  bool sync(T **r_data, const BL::ID &id, const K &key)
+  {
+    return sync(r_data, id, id, key);
+  }
+
+  bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key)
+  {
+    T *data = find(key);
+    bool recalc;
+
+    if (!data) {
+      /* add data if it didn't exist yet */
+      data = new T();
+      scene_data->push_back(data);
+      b_map[key] = data;
+      recalc = true;
+    }
+    else {
+      recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
+      if (parent.ptr.data && parent.ptr.data != id.ptr.data) {
+        recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
+      }
+    }
+
+    used(data);
+
+    *r_data = data;
+    return recalc;
+  }
+
+  bool is_used(const K &key)
+  {
+    T *data = find(key);
+    return (data) ? used_set.find(data) != used_set.end() : false;
+  }
+
+  void used(T *data)
+  {
+    /* tag data as still in use */
+    used_set.insert(data);
+  }
+
+  void set_default(T *data)
+  {
+    b_map[NULL] = data;
+  }
+
+  bool post_sync(bool do_delete = true)
+  {
+    /* remove unused data */
+    vector<T *> new_scene_data;
+    typename vector<T *>::iterator it;
+    bool deleted = false;
+
+    for (it = scene_data->begin(); it != scene_data->end(); it++) {
+      T *data = *it;
+
+      if (do_delete && used_set.find(data) == used_set.end()) {
+        delete data;
+        deleted = true;
+      }
+      else
+        new_scene_data.push_back(data);
+    }
+
+    *scene_data = new_scene_data;
+
+    /* update mapping */
+    map<K, T *> new_map;
+    typedef pair<const K, T *> TMapPair;
+    typename map<K, T *>::iterator jt;
+
+    for (jt = b_map.begin(); jt != b_map.end(); jt++) {
+      TMapPair &pair = *jt;
+
+      if (used_set.find(pair.second) != used_set.end())
+        new_map[pair.first] = pair.second;
+    }
+
+    used_set.clear();
+    b_recalc.clear();
+    b_map = new_map;
+
+    return deleted;
+  }
+
+  const map<K, T *> &key_to_scene_data()
+  {
+    return b_map;
+  }
+
+ protected:
+  vector<T *> *scene_data;
+  map<K, T *> b_map;
+  set<T *> used_set;
+  set<void *> b_recalc;
+};
+
+/* Object Key
+ *
+ * To uniquely identify instances, we use the parent, object and persistent instance ID.
+ * We also export separate object for a mesh and its particle hair. */
+
+enum { OBJECT_PERSISTENT_ID_SIZE = 16 };
+
+struct ObjectKey {
+  void *parent;
+  int id[OBJECT_PERSISTENT_ID_SIZE];
+  void *ob;
+  bool use_particle_hair;
+
+  ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
+      : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
+  {
+    if (id_)
+      memcpy(id, id_, sizeof(id));
+    else
+      memset(id, 0, sizeof(id));
+  }
+
+  bool operator<(const ObjectKey &k) const
+  {
+    if (ob < k.ob) {
+      return true;
+    }
+    else if (ob == k.ob) {
+      if (parent < k.parent) {
+        return true;
+      }
+      else if (parent == k.parent) {
+        if (use_particle_hair < k.use_particle_hair) {
+          return true;
+        }
+        else if (use_particle_hair == k.use_particle_hair) {
+          return memcmp(id, k.id, sizeof(id)) < 0;
+        }
+      }
+    }
+
+    return false;
+  }
+};
+
+/* Mesh Key
+ *
+ * We export separate geomtry for a mesh and its particle hair, so key needs to
+ * distinguish between them. */
+
+struct MeshKey {
+  void *id;
+  bool use_particle_hair;
+
+  MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair)
+  {
+  }
+
+  bool operator<(const MeshKey &k) const
+  {
+    if (id < k.id) {
+      return true;
+    }
+    else if (id == k.id) {
+      if (use_particle_hair < k.use_particle_hair) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+};
+
+/* Particle System Key */
+
+struct ParticleSystemKey {
+  void *ob;
+  int id[OBJECT_PERSISTENT_ID_SIZE];
+
+  ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
+  {
+    if (id_)
+      memcpy(id, id_, sizeof(id));
+    else
+      memset(id, 0, sizeof(id));
+  }
+
+  bool operator<(const ParticleSystemKey &k) const
+  {
+    /* first id is particle index, we don't compare that */
+    if (ob < k.ob)
+      return true;
+    else if (ob == k.ob)
+      return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0;
+
+    return false;
+  }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_ID_MAP_H__ */
diff --git a/intern/cycles/blender/blender_image.cpp b/intern/cycles/blender/blender_image.cpp
new file mode 100644 (file)
index 0000000..0fe42b2
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * 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.
+ */
+
+#include "render/image.h"
+
+#include "blender/blender_sync.h"
+#include "blender/blender_session.h"
+#include "blender/blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* builtin image file name is actually an image datablock name with
+ * absolute sequence frame number concatenated via '@' character
+ *
+ * this function splits frame from builtin name
+ */
+int BlenderSession::builtin_image_frame(const string &builtin_name)
+{
+  int last = builtin_name.find_last_of('@');
+  return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
+}
+
+void BlenderSession::builtin_image_info(const string &builtin_name,
+                                        void *builtin_data,
+                                        ImageMetaData &metadata)
+{
+  /* empty image */
+  metadata.width = 1;
+  metadata.height = 1;
+
+  if (!builtin_data)
+    return;
+
+  /* recover ID pointer */
+  PointerRNA ptr;
+  RNA_id_pointer_create((ID *)builtin_data, &ptr);
+  BL::ID b_id(ptr);
+
+  if (b_id.is_a(&RNA_Image)) {
+    /* image data */
+    BL::Image b_image(b_id);
+
+    metadata.builtin_free_cache = !b_image.has_data();
+    metadata.is_float = b_image.is_float();
+    metadata.width = b_image.size()[0];
+    metadata.height = b_image.size()[1];
+    metadata.depth = 1;
+    metadata.channels = b_image.channels();
+
+    if (metadata.is_float) {
+      /* Float images are already converted on the Blender side,
+       * no need to do anything in Cycles. */
+      metadata.colorspace = u_colorspace_raw;
+    }
+  }
+  else if (b_id.is_a(&RNA_Object)) {
+    /* smoke volume data */
+    BL::Object b_ob(b_id);
+    BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+
+    metadata.is_float = true;
+    metadata.depth = 1;
+    metadata.channels = 1;
+
+    if (!b_domain)
+      return;
+
+    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
+        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) ||
+        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) ||
+        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE))
+      metadata.channels = 1;
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
+      metadata.channels = 4;
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY))
+      metadata.channels = 3;
+    else
+      return;
+
+    int3 resolution = get_int3(b_domain.domain_resolution());
+    int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+    /* Velocity and heat data is always low-resolution. */
+    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
+        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+      amplify = 1;
+    }
+
+    metadata.width = resolution.x * amplify;
+    metadata.height = resolution.y * amplify;
+    metadata.depth = resolution.z * amplify;
+  }
+  else {
+    /* TODO(sergey): Check we're indeed in shader node tree. */
+    PointerRNA ptr;
+    RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+    BL::Node b_node(ptr);
+    if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+      BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+      metadata.channels = 4;
+      metadata.width = b_point_density_node.resolution();
+      metadata.height = metadata.width;
+      metadata.depth = metadata.width;
+      metadata.is_float = true;
+    }
+  }
+}
+
+bool BlenderSession::builtin_image_pixels(const string &builtin_name,
+                                          void *builtin_data,
+                                          int tile,
+                                          unsigned char *pixels,
+                                          const size_t pixels_size,
+                                          const bool associate_alpha,
+                                          const bool free_cache)
+{
+  if (!builtin_data) {
+    return false;
+  }
+
+  const int frame = builtin_image_frame(builtin_name);
+
+  PointerRNA ptr;
+  RNA_id_pointer_create((ID *)builtin_data, &ptr);
+  BL::Image b_image(ptr);
+
+  const int width = b_image.size()[0];
+  const int height = b_image.size()[1];
+  const int channels = b_image.channels();
+
+  unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
+  const size_t num_pixels = ((size_t)width) * height;
+
+  if (image_pixels && num_pixels * channels == pixels_size) {
+    memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+  }
+  else {
+    if (channels == 1) {
+      memset(pixels, 0, pixels_size * sizeof(unsigned char));
+    }
+    else {
+      const size_t num_pixels_safe = pixels_size / channels;
+      unsigned char *cp = pixels;
+      for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
+        cp[0] = 255;
+        cp[1] = 0;
+        cp[2] = 255;
+        if (channels == 4) {
+          cp[3] = 255;
+        }
+      }
+    }
+  }
+
+  if (image_pixels) {
+    MEM_freeN(image_pixels);
+  }
+
+  /* Free image buffers to save memory during render. */
+  if (free_cache) {
+    b_image.buffers_free();
+  }
+
+  if (associate_alpha) {
+    /* Premultiply, byte images are always straight for Blender. */
+    unsigned char *cp = pixels;
+    for (size_t i = 0; i < num_pixels; i++, cp += channels) {
+      cp[0] = (cp[0] * cp[3]) >> 8;
+      cp[1] = (cp[1] * cp[3]) >> 8;
+      cp[2] = (cp[2] * cp[3]) >> 8;
+    }
+  }
+  return true;
+}
+
+bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
+                                                void *builtin_data,
+                                                int tile,
+                                                float *pixels,
+                                                const size_t pixels_size,
+                                                const bool,
+                                                const bool free_cache)
+{
+  if (!builtin_data) {
+    return false;
+  }
+
+  PointerRNA ptr;
+  RNA_id_pointer_create((ID *)builtin_data, &ptr);
+  BL::ID b_id(ptr);
+
+  if (b_id.is_a(&RNA_Image)) {
+    /* image data */
+    BL::Image b_image(b_id);
+    int frame = builtin_image_frame(builtin_name);
+
+    const int width = b_image.size()[0];
+    const int height = b_image.size()[1];
+    const int channels = b_image.channels();
+
+    float *image_pixels;
+    image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
+    const size_t num_pixels = ((size_t)width) * height;
+
+    if (image_pixels && num_pixels * channels == pixels_size) {
+      memcpy(pixels, image_pixels, pixels_size * sizeof(float));
+    }
+    else {
+      if (channels == 1) {
+        memset(pixels, 0, num_pixels * sizeof(float));
+      }
+      else {
+        const size_t num_pixels_safe = pixels_size / channels;
+        float *fp = pixels;
+        for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
+          fp[0] = 1.0f;
+          fp[1] = 0.0f;
+          fp[2] = 1.0f;
+          if (channels == 4) {
+            fp[3] = 1.0f;
+          }
+        }
+      }
+    }
+
+    if (image_pixels) {
+      MEM_freeN(image_pixels);
+    }
+
+    /* Free image buffers to save memory during render. */
+    if (free_cache) {
+      b_image.buffers_free();
+    }
+
+    return true;
+  }
+  else if (b_id.is_a(&RNA_Object)) {
+    /* smoke volume data */
+    BL::Object b_ob(b_id);
+    BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+
+    if (!b_domain) {
+      return false;
+    }
+#if WITH_FLUID
+    int3 resolution = get_int3(b_domain.domain_resolution());
+    int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
+
+    /* Velocity and heat data is always low-resolution. */
+    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
+        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+      amplify = 1;
+    }
+
+    const int width = resolution.x * amplify;
+    const int height = resolution.y * amplify;
+    const int depth = resolution.z * amplify;
+    const size_t num_pixels = ((size_t)width) * height * depth;
+
+    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
+      FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels) {
+        FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
+      /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
+       * as 1500..3000 K with the first part faded to zero density */
+      FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels) {
+        FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
+      /* the RGB is "premultiplied" by density for better interpolation results */
+      FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels * 4) {
+        FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
+      FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels * 3) {
+        FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+      FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels) {
+        FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
+      FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
+      if (length == num_pixels) {
+        FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
+        return true;
+      }
+    }
+    else {
+      fprintf(
+          stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str());
+      pixels[0] = 0.0f;
+      return false;
+    }
+#endif
+    fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
+  }
+  else {
+    /* We originally were passing view_layer here but in reality we need a
+     * a depsgraph to pass to the RE_point_density_minmax() function.
+     */
+    /* TODO(sergey): Check we're indeed in shader node tree. */
+    PointerRNA ptr;
+    RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
+    BL::Node b_node(ptr);
+    if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+      BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+      int length;
+      b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels);
+    }
+  }
+
+  return false;
+}
+
+void BlenderSession::builtin_images_load()
+{
+  /* Force builtin images to be loaded along with Blender data sync. This
+   * is needed because we may be reading from depsgraph evaluated data which
+   * can be freed by Blender before Cycles reads it.
+   *
+   * TODO: the assumption that no further access to builtin image data will
+   * happen is really weak, and likely to break in the future. We should find
+   * a better solution to hand over the data directly to the image manager
+   * instead of through callbacks whose timing is difficult to control. */
+  ImageManager *manager = session->scene->image_manager;
+  Device *device = session->device;
+  manager->device_load_builtin(device, session->scene, session->progress);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp
new file mode 100644 (file)
index 0000000..a8e28a0
--- /dev/null
@@ -0,0 +1,213 @@
+
+
+/*
+ * 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.
+ */
+
+#include "render/light.h"
+
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
+
+#include "util/util_hash.h"
+
+CCL_NAMESPACE_BEGIN
+
+void BlenderSync::sync_light(BL::Object &b_parent,
+                             int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+                             BL::Object &b_ob,
+                             BL::Object &b_ob_instance,
+                             int random_id,
+                             Transform &tfm,
+                             bool *use_portal)
+{
+  /* test if we need to sync */
+  Light *light;
+  ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
+  BL::Light b_light(b_ob.data());
+
+  /* Update if either object or light data changed. */
+  if (!light_map.sync(&light, b_ob, b_parent, key)) {
+    Shader *shader;
+    if (!shader_map.sync(&shader, b_light)) {
+      if (light->is_portal)
+        *use_portal = true;
+      return;
+    }
+  }
+
+  /* type */
+  switch (b_light.type()) {
+    case BL::Light::type_POINT: {
+      BL::PointLight b_point_light(b_light);
+      light->size = b_point_light.shadow_soft_size();
+      light->type = LIGHT_POINT;
+      break;
+    }
+    case BL::Light::type_SPOT: {
+      BL::SpotLight b_spot_light(b_light);
+      light->size = b_spot_light.shadow_soft_size();
+      light->type = LIGHT_SPOT;
+      light->spot_angle = b_spot_light.spot_size();
+      light->spot_smooth = b_spot_light.spot_blend();
+      break;
+    }
+    /* Hemi were removed from 2.8 */
+    // case BL::Light::type_HEMI: {
+    //  light->type = LIGHT_DISTANT;
+    //  light->size = 0.0f;
+    //  break;
+    // }
+    case BL::Light::type_SUN: {
+      BL::SunLight b_sun_light(b_light);
+      light->angle = b_sun_light.angle();
+      light->type = LIGHT_DISTANT;
+      break;
+    }
+    case BL::Light::type_AREA: {
+      BL::AreaLight b_area_light(b_light);
+      light->size = 1.0f;
+      light->axisu = transform_get_column(&tfm, 0);
+      light->axisv = transform_get_column(&tfm, 1);
+      light->sizeu = b_area_light.size();
+      switch (b_area_light.shape()) {
+        case BL::AreaLight::shape_SQUARE:
+          light->sizev = light->sizeu;
+          light->round = false;
+          break;
+        case BL::AreaLight::shape_RECTANGLE:
+          light->sizev = b_area_light.size_y();
+          light->round = false;
+          break;
+        case BL::AreaLight::shape_DISK:
+          light->sizev = light->sizeu;
+          light->round = true;
+          break;
+        case BL::AreaLight::shape_ELLIPSE:
+          light->sizev = b_area_light.size_y();
+          light->round = true;
+          break;
+      }
+      light->type = LIGHT_AREA;
+      break;
+    }
+  }
+
+  /* strength */
+  light->strength = get_float3(b_light.color());
+  light->strength *= BL::PointLight(b_light).energy();
+
+  /* location and (inverted!) direction */
+  light->co = transform_get_column(&tfm, 3);
+  light->dir = -transform_get_column(&tfm, 2);
+  light->tfm = tfm;
+
+  /* shader */
+  vector<Shader *> used_shaders;
+  find_shader(b_light, used_shaders, scene->default_light);
+  light->shader = used_shaders[0];
+
+  /* shadow */
+  PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+  PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
+  light->cast_shadow = get_boolean(clight, "cast_shadow");
+  light->use_mis = get_boolean(clight, "use_multiple_importance_sampling");
+
+  int samples = get_int(clight, "samples");
+  if (get_boolean(cscene, "use_square_samples"))
+    light->samples = samples * samples;
+  else
+    light->samples = samples;
+
+  light->max_bounces = get_int(clight, "max_bounces");
+
+  if (b_ob != b_ob_instance) {
+    light->random_id = random_id;
+  }
+  else {
+    light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0);
+  }
+
+  if (light->type == LIGHT_AREA)
+    light->is_portal = get_boolean(clight, "is_portal");
+  else
+    light->is_portal = false;
+
+  if (light->is_portal)
+    *use_portal = true;
+
+  /* visibility */
+  uint visibility = object_ray_visibility(b_ob);
+  light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
+  light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
+  light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
+  light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
+
+  /* tag */
+  light->tag_update(scene);
+}
+
+void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
+{
+  BL::World b_world = b_scene.world();
+
+  if (b_world) {
+    PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+    PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
+
+    enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
+    int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
+    bool sample_as_light = (sampling_method != SAMPLING_NONE);
+
+    if (sample_as_light || use_portal) {
+      /* test if we need to sync */
+      Light *light;
+      ObjectKey key(b_world, 0, b_world, false);
+
+      if (light_map.sync(&light, b_world, b_world, key) || world_recalc ||
+          b_world.ptr.data != world_map) {
+        light->type = LIGHT_BACKGROUND;
+        if (sampling_method == SAMPLING_MANUAL) {
+          light->map_resolution = get_int(cworld, "sample_map_resolution");
+        }
+        else {
+          light->map_resolution = 0;
+        }
+        light->shader = scene->default_background;
+        light->use_mis = sample_as_light;
+        light->max_bounces = get_int(cworld, "max_bounces");
+
+        /* force enable light again when world is resynced */
+        light->is_enabled = true;
+
+        int samples = get_int(cworld, "samples");
+        if (get_boolean(cscene, "use_square_samples"))
+          light->samples = samples * samples;
+        else
+          light->samples = samples;
+
+        light->tag_update(scene);
+        light_map.set_recalc(b_world);
+      }
+    }
+  }
+
+  world_map = b_world.ptr.data;
+  world_recalc = false;
+  viewport_parameters = BlenderViewportParameters(b_v3d);
+}
+
+CCL_NAMESPACE_END
+
index d3dac3c615142dd9eac64516c1f5892f232d5d01..00faafe29eeacacfa6b269d22b26972c7b667780 100644 (file)
@@ -278,54 +278,6 @@ static void mikk_compute_tangents(
   genTangSpaceDefault(&context);
 }
 
-/* Create Volume Attribute */
-
-static void create_mesh_volume_attribute(
-    BL::Object &b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
-{
-  BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
-
-  if (!b_domain)
-    return;
-
-  mesh->volume_isovalue = b_domain.clipping();
-
-  Attribute *attr = mesh->attributes.add(std);
-  VoxelAttribute *volume_data = attr->data_voxel();
-  ImageMetaData metadata;
-  bool animated = false;
-
-  volume_data->manager = image_manager;
-  volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
-                                               b_ob.ptr.data,
-                                               animated,
-                                               frame,
-                                               INTERPOLATION_LINEAR,
-                                               EXTENSION_CLIP,
-                                               IMAGE_ALPHA_AUTO,
-                                               u_colorspace_raw,
-                                               metadata);
-}
-
-static void create_mesh_volume_attributes(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame)
-{
-  /* for smoke volume rendering */
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
-    create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame);
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
-    create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame);
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
-    create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame);
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT))
-    create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame);
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE))
-    create_mesh_volume_attribute(
-        b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame);
-  if (mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY))
-    create_mesh_volume_attribute(
-        b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame);
-}
-
 /* Create vertex color attributes. */
 static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
 {
@@ -767,6 +719,7 @@ static void create_mesh(Scene *scene,
   /* allocate memory */
   mesh->reserve_mesh(numverts, numtris);
   mesh->reserve_subd_faces(numfaces, numngons, numcorners);
+  mesh->geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
 
   /* create vertex coordinates and normals */
   BL::Mesh::vertices_iterator v;
@@ -859,9 +812,9 @@ static void create_mesh(Scene *scene,
     attr_create_uv_map(scene, mesh, b_mesh);
   }
 
-  /* for volume objects, create a matrix to transform from object space to
+  /* For volume objects, create a matrix to transform from object space to
    * mesh texture space. this does not work with deformations but that can
-   * probably only be done well with a volume grid mapping of coordinates */
+   * probably only be done well with a volume grid mapping of coordinates. */
   if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
     Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
     Transform *tfm = attr->data_transform();
@@ -930,7 +883,7 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
   if (scene->need_motion() == Scene::MOTION_NONE)
     return;
 
-  BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+  BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
 
   if (!b_fluid_domain)
     return;
@@ -963,82 +916,8 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
   }
 }
 
-Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
-                             BL::Object &b_ob,
-                             BL::Object &b_ob_instance,
-                             bool object_updated,
-                             bool use_particle_hair)
+void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
 {
-  /* test if we can instance or if the object is modified */
-  BL::ID b_ob_data = b_ob.data();
-  BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
-  MeshKey key(b_key_id.ptr.data, use_particle_hair);
-  BL::Material material_override = view_layer.material_override;
-
-  /* find shader indices */
-  vector<Shader *> used_shaders;
-
-  BL::Object::material_slots_iterator slot;
-  for (b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
-    if (material_override) {
-      find_shader(material_override, used_shaders, scene->default_surface);
-    }
-    else {
-      BL::ID b_material(slot->material());
-      find_shader(b_material, used_shaders, scene->default_surface);
-    }
-  }
-
-  if (used_shaders.size() == 0) {
-    if (material_override)
-      find_shader(material_override, used_shaders, scene->default_surface);
-    else
-      used_shaders.push_back(scene->default_surface);
-  }
-
-  /* test if we need to sync */
-  int requested_geometry_flags = Mesh::GEOMETRY_NONE;
-  if (view_layer.use_surfaces) {
-    requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
-  }
-  if (view_layer.use_hair) {
-    requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
-  }
-  Mesh *mesh;
-
-  if (!mesh_map.sync(&mesh, b_key_id, key)) {
-    /* if transform was applied to mesh, need full update */
-    if (object_updated && mesh->transform_applied)
-      ;
-    /* test if shaders changed, these can be object level so mesh
-     * does not get tagged for recalc */
-    else if (mesh->used_shaders != used_shaders)
-      ;
-    else if (requested_geometry_flags != mesh->geometry_flags)
-      ;
-    else {
-      /* even if not tagged for recalc, we may need to sync anyway
-       * because the shader needs different mesh attributes */
-      bool attribute_recalc = false;
-
-      foreach (Shader *shader, mesh->used_shaders)
-        if (shader->need_update_mesh)
-          attribute_recalc = true;
-
-      if (!attribute_recalc)
-        return mesh;
-    }
-  }
-
-  /* ensure we only sync instanced meshes once */
-  if (mesh_synced.find(mesh) != mesh_synced.end())
-    return mesh;
-
-  progress.set_sync_status("Synchronizing object", b_ob.name());
-
-  mesh_synced.insert(mesh);
-
-  /* create derived mesh */
   array<int> oldtriangles;
   array<Mesh::SubdFace> oldsubd_faces;
   array<int> oldsubd_face_corners;
@@ -1046,152 +925,64 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph &b_depsgraph,
   oldsubd_faces.steal_data(mesh->subd_faces);
   oldsubd_face_corners.steal_data(mesh->subd_face_corners);
 
-  /* compares curve_keys rather than strands in order to handle quick hair
-   * adjustments in dynamic BVH - other methods could probably do this better*/
-  array<float3> oldcurve_keys;
-  array<float> oldcurve_radius;
-  oldcurve_keys.steal_data(mesh->curve_keys);
-  oldcurve_radius.steal_data(mesh->curve_radius);
-
-  /* ensure bvh rebuild (instead of refit) if has_voxel_attributes() changed */
-  bool oldhas_voxel_attributes = mesh->has_voxel_attributes();
+  mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
 
-  mesh->clear();
-  mesh->used_shaders = used_shaders;
-  mesh->name = ustring(b_ob_data.name().c_str());
-
-  if (requested_geometry_flags != Mesh::GEOMETRY_NONE) {
+  if (view_layer.use_surfaces) {
     /* Adaptive subdivision setup. Not for baking since that requires
      * exact mapping to the Blender mesh. */
-    if (scene->bake_manager->get_baking()) {
-      mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
-    }
-    else {
+    if (!scene->bake_manager->get_baking()) {
       mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
     }
 
     /* For some reason, meshes do not need this... */
     bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
-
     BL::Mesh b_mesh = object_to_mesh(
         b_data, b_ob, b_depsgraph, need_undeformed, mesh->subdivision_type);
 
     if (b_mesh) {
       /* Sync mesh itself. */
-      if (view_layer.use_surfaces && !use_particle_hair) {
-        if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
-          create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders, dicing_rate, max_subdivisions);
-        else
-          create_mesh(scene, mesh, b_mesh, used_shaders, false);
-
-        create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
-      }
-
-      /* Sync hair curves. */
-      if (view_layer.use_hair && use_particle_hair &&
-          mesh->subdivision_type == Mesh::SUBDIVISION_NONE) {
-        sync_particle_hair(mesh, b_mesh, b_ob, false);
-      }
+      if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
+        create_subd_mesh(
+            scene, mesh, b_ob, b_mesh, mesh->used_shaders, dicing_rate, max_subdivisions);
+      else
+        create_mesh(scene, mesh, b_mesh, mesh->used_shaders, false);
 
       free_object_to_mesh(b_data, b_ob, b_mesh);
     }
   }
-  mesh->geometry_flags = requested_geometry_flags;
 
   /* mesh fluid motion mantaflow */
-  if (!use_particle_hair) {
-    sync_mesh_fluid_motion(b_ob, scene, mesh);
-  }
+  sync_mesh_fluid_motion(b_ob, scene, mesh);
 
   /* tag update */
   bool rebuild = (oldtriangles != mesh->triangles) || (oldsubd_faces != mesh->subd_faces) ||
-                 (oldsubd_face_corners != mesh->subd_face_corners) ||
-                 (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius) ||
-                 (oldhas_voxel_attributes != mesh->has_voxel_attributes());
+                 (oldsubd_face_corners != mesh->subd_face_corners);
 
   mesh->tag_update(scene, rebuild);
-
-  return mesh;
 }
 
-void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
-                                   BL::Object &b_ob,
-                                   Object *object,
-                                   float motion_time)
+void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
+                                   BL::Object b_ob,
+                                   Mesh *mesh,
+                                   int motion_step)
 {
-  /* ensure we only sync instanced meshes once */
-  Mesh *mesh = object->mesh;
-
-  if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
-    return;
-
-  mesh_motion_synced.insert(mesh);
-
-  /* ensure we only motion sync meshes that also had mesh synced, to avoid
-   * unnecessary work and to ensure that its attributes were clear */
-  if (mesh_synced.find(mesh) == mesh_synced.end())
-    return;
-
-  /* Find time matching motion step required by mesh. */
-  int motion_step = mesh->motion_step(motion_time);
-  if (motion_step < 0) {
+  /* Skip if no vertices were exported. */
+  size_t numverts = mesh->verts.size();
+  if (numverts == 0) {
     return;
   }
 
-  /* skip empty meshes */
-  const size_t numverts = mesh->verts.size();
-  const size_t numkeys = mesh->curve_keys.size();
-
-  if (!numverts && !numkeys)
-    return;
-
-  /* skip objects without deforming modifiers. this is not totally reliable,
-   * would need a more extensive check to see which objects are animated */
+  /* Skip objects without deforming modifiers. this is not totally reliable,
+   * would need a more extensive check to see which objects are animated. */
   BL::Mesh b_mesh(PointerRNA_NULL);
-
-  /* manta motion is exported immediate with mesh, skip here */
-  BL::FluidDomainSettings b_fluid_domain = object_fluid_domain_find(b_ob);
-  if (b_fluid_domain)
-    return;
-
   if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
     /* get derived mesh */
     b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
   }
 
-  if (!b_mesh) {
-    /* if we have no motion blur on this frame, but on other frames, copy */
-    if (numverts) {
-      /* triangles */
-      Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
-      if (attr_mP) {
-        Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
-        Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
-        float3 *P = &mesh->verts[0];
-        float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
-
-        memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts);
-        if (attr_mN)
-          memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts);
-      }
-    }
-
-    if (numkeys) {
-      /* curves */
-      Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
-
-      if (attr_mP) {
-        float3 *keys = &mesh->curve_keys[0];
-        memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys);
-      }
-    }
-
-    return;
-  }
-
   /* TODO(sergey): Perform preliminary check for number of vertices. */
-  if (numverts) {
+  if (b_mesh) {
+    /* Export deformed coordinates. */
     /* Find attributes. */
     Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
     Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
@@ -1256,14 +1047,24 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph &b_depsgraph,
         }
       }
     }
+
+    free_object_to_mesh(b_data, b_ob, b_mesh);
+    return;
   }
 
-  /* hair motion */
-  if (numkeys)
-    sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step);
+  /* No deformation on this frame, copy coordinates if other frames did have it. */
+  Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
 
-  /* free derived mesh */
-  free_object_to_mesh(b_data, b_ob, b_mesh);
+  if (attr_mP) {
+    Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
+    Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+    float3 *P = &mesh->verts[0];
+    float3 *N = (attr_N) ? attr_N->data_float3() : NULL;
+
+    memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts);
+    if (attr_mN)
+      memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts);
+  }
 }
 
 CCL_NAMESPACE_END
index c397a95fa71f852dc296713a71a0c24638b0d9f2..13dfd0867ba365d78c48967fdc67a4cd2a5eebec 100644 (file)
@@ -88,207 +88,6 @@ bool BlenderSync::object_is_light(BL::Object &b_ob)
   return (b_ob_data && b_ob_data.is_a(&RNA_Light));
 }
 
-static uint object_ray_visibility(BL::Object &b_ob)
-{
-  PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
-  uint flag = 0;
-
-  flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
-  flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
-  flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
-  flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
-  flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0;
-  flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
-
-  return flag;
-}
-
-/* Light */
-
-void BlenderSync::sync_light(BL::Object &b_parent,
-                             int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
-                             BL::Object &b_ob,
-                             BL::Object &b_ob_instance,
-                             int random_id,
-                             Transform &tfm,
-                             bool *use_portal)
-{
-  /* test if we need to sync */
-  Light *light;
-  ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
-  BL::Light b_light(b_ob.data());
-
-  /* Update if either object or light data changed. */
-  if (!light_map.sync(&light, b_ob, b_parent, key)) {
-    Shader *shader;
-    if (!shader_map.sync(&shader, b_light)) {
-      if (light->is_portal)
-        *use_portal = true;
-      return;
-    }
-  }
-
-  /* type */
-  switch (b_light.type()) {
-    case BL::Light::type_POINT: {
-      BL::PointLight b_point_light(b_light);
-      light->size = b_point_light.shadow_soft_size();
-      light->type = LIGHT_POINT;
-      break;
-    }
-    case BL::Light::type_SPOT: {
-      BL::SpotLight b_spot_light(b_light);
-      light->size = b_spot_light.shadow_soft_size();
-      light->type = LIGHT_SPOT;
-      light->spot_angle = b_spot_light.spot_size();
-      light->spot_smooth = b_spot_light.spot_blend();
-      break;
-    }
-    /* Hemi were removed from 2.8 */
-    // case BL::Light::type_HEMI: {
-    //  light->type = LIGHT_DISTANT;
-    //  light->size = 0.0f;
-    //  break;
-    // }
-    case BL::Light::type_SUN: {
-      BL::SunLight b_sun_light(b_light);
-      light->angle = b_sun_light.angle();
-      light->type = LIGHT_DISTANT;
-      break;
-    }
-    case BL::Light::type_AREA: {
-      BL::AreaLight b_area_light(b_light);
-      light->size = 1.0f;
-      light->axisu = transform_get_column(&tfm, 0);
-      light->axisv = transform_get_column(&tfm, 1);
-      light->sizeu = b_area_light.size();
-      switch (b_area_light.shape()) {
-        case BL::AreaLight::shape_SQUARE:
-          light->sizev = light->sizeu;
-          light->round = false;
-          break;
-        case BL::AreaLight::shape_RECTANGLE:
-          light->sizev = b_area_light.size_y();
-          light->round = false;
-          break;
-        case BL::AreaLight::shape_DISK:
-          light->sizev = light->sizeu;
-          light->round = true;
-          break;
-        case BL::AreaLight::shape_ELLIPSE:
-          light->sizev = b_area_light.size_y();
-          light->round = true;
-          break;
-      }
-      light->type = LIGHT_AREA;
-      break;
-    }
-  }
-
-  /* strength */
-  light->strength = get_float3(b_light.color());
-  light->strength *= BL::PointLight(b_light).energy();
-
-  /* location and (inverted!) direction */
-  light->co = transform_get_column(&tfm, 3);
-  light->dir = -transform_get_column(&tfm, 2);
-  light->tfm = tfm;
-
-  /* shader */
-  vector<Shader *> used_shaders;
-  find_shader(b_light, used_shaders, scene->default_light);
-  light->shader = used_shaders[0];
-
-  /* shadow */
-  PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-  PointerRNA clight = RNA_pointer_get(&b_light.ptr, "cycles");
-  light->cast_shadow = get_boolean(clight, "cast_shadow");
-  light->use_mis = get_boolean(clight, "use_multiple_importance_sampling");
-
-  int samples = get_int(clight, "samples");
-  if (get_boolean(cscene, "use_square_samples"))
-    light->samples = samples * samples;
-  else
-    light->samples = samples;
-
-  light->max_bounces = get_int(clight, "max_bounces");
-
-  if (b_ob != b_ob_instance) {
-    light->random_id = random_id;
-  }
-  else {
-    light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0);
-  }
-
-  if (light->type == LIGHT_AREA)
-    light->is_portal = get_boolean(clight, "is_portal");
-  else
-    light->is_portal = false;
-
-  if (light->is_portal)
-    *use_portal = true;
-
-  /* visibility */
-  uint visibility = object_ray_visibility(b_ob);
-  light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
-  light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
-  light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
-  light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
-
-  /* tag */
-  light->tag_update(scene);
-}
-
-void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal)
-{
-  BL::World b_world = b_scene.world();
-
-  if (b_world) {
-    PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
-    PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
-
-    enum SamplingMethod { SAMPLING_NONE = 0, SAMPLING_AUTOMATIC, SAMPLING_MANUAL, SAMPLING_NUM };
-    int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
-    bool sample_as_light = (sampling_method != SAMPLING_NONE);
-
-    if (sample_as_light || use_portal) {
-      /* test if we need to sync */
-      Light *light;
-      ObjectKey key(b_world, 0, b_world, false);
-
-      if (light_map.sync(&light, b_world, b_world, key) || world_recalc ||
-          b_world.ptr.data != world_map) {
-        light->type = LIGHT_BACKGROUND;
-        if (sampling_method == SAMPLING_MANUAL) {
-          light->map_resolution = get_int(cworld, "sample_map_resolution");
-        }
-        else {
-          light->map_resolution = 0;
-        }
-        light->shader = scene->default_background;
-        light->use_mis = sample_as_light;
-        light->max_bounces = get_int(cworld, "max_bounces");
-
-        /* force enable light again when world is resynced */
-        light->is_enabled = true;
-
-        int samples = get_int(cworld, "samples");
-        if (get_boolean(cscene, "use_square_samples"))
-          light->samples = samples * samples;
-        else
-          light->samples = samples;
-
-        light->tag_update(scene);
-        light_map.set_recalc(b_world);
-      }
-    }
-  }
-
-  world_map = b_world.ptr.data;
-  world_recalc = false;
-  viewport_parameters = BlenderViewportParameters(b_v3d);
-}
-
 /* Object */
 
 Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
@@ -393,7 +192,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
 
       /* mesh deformation */
       if (object->mesh)
-        sync_mesh_motion(b_depsgraph, b_ob, object, motion_time);
+        sync_geometry_motion(b_depsgraph, b_ob, object, motion_time, use_particle_hair);
     }
 
     return object;
@@ -406,7 +205,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
     object_updated = true;
 
   /* mesh sync */
-  object->mesh = sync_mesh(b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair);
+  object->mesh = sync_geometry(
+      b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair);
 
   /* special case not tracked by object update flags */
 
index 74f8fb1dc532c89aca71da6960b2726fc97364af..bebecb364eb7cc2c0712e1f73308143dfee0b64c 100644 (file)
@@ -19,6 +19,7 @@
 #include "render/camera.h"
 
 #include "blender/blender_object_cull.h"
+#include "blender/blender_util.h"
 
 CCL_NAMESPACE_BEGIN
 
index 335d4daf09c006eeacec8eae982f30ae93ec59ff..816b4552fff7234523ef6f3fc37969fbd8c83efd 100644 (file)
@@ -21,6 +21,7 @@
 #include "blender/blender_device.h"
 #include "blender/blender_sync.h"
 #include "blender/blender_session.h"
+#include "blender/blender_util.h"
 
 #include "render/denoising.h"
 #include "render/merge.h"
index e2dea24fdd19badbc5eae9486846acebc744020c..663f3d72110d0aab3b9d502d1df7ab436e218557 100644 (file)
@@ -1112,341 +1112,6 @@ void BlenderSession::test_cancel()
       session->progress.set_cancel("Cancelled");
 }
 
-/* builtin image file name is actually an image datablock name with
- * absolute sequence frame number concatenated via '@' character
- *
- * this function splits frame from builtin name
- */
-int BlenderSession::builtin_image_frame(const string &builtin_name)
-{
-  int last = builtin_name.find_last_of('@');
-  return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
-}
-
-void BlenderSession::builtin_image_info(const string &builtin_name,
-                                        void *builtin_data,
-                                        ImageMetaData &metadata)
-{
-  /* empty image */
-  metadata.width = 1;
-  metadata.height = 1;
-
-  if (!builtin_data)
-    return;
-
-  /* recover ID pointer */
-  PointerRNA ptr;
-  RNA_id_pointer_create((ID *)builtin_data, &ptr);
-  BL::ID b_id(ptr);
-
-  if (b_id.is_a(&RNA_Image)) {
-    /* image data */
-    BL::Image b_image(b_id);
-
-    metadata.builtin_free_cache = !b_image.has_data();
-    metadata.is_float = b_image.is_float();
-    metadata.width = b_image.size()[0];
-    metadata.height = b_image.size()[1];
-    metadata.depth = 1;
-    metadata.channels = b_image.channels();
-
-    if (metadata.is_float) {
-      /* Float images are already converted on the Blender side,
-       * no need to do anything in Cycles. */
-      metadata.colorspace = u_colorspace_raw;
-    }
-  }
-  else if (b_id.is_a(&RNA_Object)) {
-    /* smoke volume data */
-    BL::Object b_ob(b_id);
-    BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
-
-    metadata.is_float = true;
-    metadata.depth = 1;
-    metadata.channels = 1;
-
-    if (!b_domain)
-      return;
-
-    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
-        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) ||
-        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT) ||
-        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE))
-      metadata.channels = 1;
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
-      metadata.channels = 4;
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY))
-      metadata.channels = 3;
-    else
-      return;
-
-    int3 resolution = get_int3(b_domain.domain_resolution());
-    int amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
-    /* Velocity and heat data is always low-resolution. */
-    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
-        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
-      amplify = 1;
-    }
-
-    metadata.width = resolution.x * amplify;
-    metadata.height = resolution.y * amplify;
-    metadata.depth = resolution.z * amplify;
-  }
-  else {
-    /* TODO(sergey): Check we're indeed in shader node tree. */
-    PointerRNA ptr;
-    RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
-    BL::Node b_node(ptr);
-    if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
-      BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
-      metadata.channels = 4;
-      metadata.width = b_point_density_node.resolution();
-      metadata.height = metadata.width;
-      metadata.depth = metadata.width;
-      metadata.is_float = true;
-    }
-  }
-}
-
-bool BlenderSession::builtin_image_pixels(const string &builtin_name,
-                                          void *builtin_data,
-                                          int tile,
-                                          unsigned char *pixels,
-                                          const size_t pixels_size,
-                                          const bool associate_alpha,
-                                          const bool free_cache)
-{
-  if (!builtin_data) {
-    return false;
-  }
-
-  const int frame = builtin_image_frame(builtin_name);
-
-  PointerRNA ptr;
-  RNA_id_pointer_create((ID *)builtin_data, &ptr);
-  BL::Image b_image(ptr);
-
-  const int width = b_image.size()[0];
-  const int height = b_image.size()[1];
-  const int channels = b_image.channels();
-
-  unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
-  const size_t num_pixels = ((size_t)width) * height;
-
-  if (image_pixels && num_pixels * channels == pixels_size) {
-    memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
-  }
-  else {
-    if (channels == 1) {
-      memset(pixels, 0, pixels_size * sizeof(unsigned char));
-    }
-    else {
-      const size_t num_pixels_safe = pixels_size / channels;
-      unsigned char *cp = pixels;
-      for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
-        cp[0] = 255;
-        cp[1] = 0;
-        cp[2] = 255;
-        if (channels == 4) {
-          cp[3] = 255;
-        }
-      }
-    }
-  }
-
-  if (image_pixels) {
-    MEM_freeN(image_pixels);
-  }
-
-  /* Free image buffers to save memory during render. */
-  if (free_cache) {
-    b_image.buffers_free();
-  }
-
-  if (associate_alpha) {
-    /* Premultiply, byte images are always straight for Blender. */
-    unsigned char *cp = pixels;
-    for (size_t i = 0; i < num_pixels; i++, cp += channels) {
-      cp[0] = (cp[0] * cp[3]) >> 8;
-      cp[1] = (cp[1] * cp[3]) >> 8;
-      cp[2] = (cp[2] * cp[3]) >> 8;
-    }
-  }
-  return true;
-}
-
-bool BlenderSession::builtin_image_float_pixels(const string &builtin_name,
-                                                void *builtin_data,
-                                                int tile,
-                                                float *pixels,
-                                                const size_t pixels_size,
-                                                const bool,
-                                                const bool free_cache)
-{
-  if (!builtin_data) {
-    return false;
-  }
-
-  PointerRNA ptr;
-  RNA_id_pointer_create((ID *)builtin_data, &ptr);
-  BL::ID b_id(ptr);
-
-  if (b_id.is_a(&RNA_Image)) {
-    /* image data */
-    BL::Image b_image(b_id);
-    int frame = builtin_image_frame(builtin_name);
-
-    const int width = b_image.size()[0];
-    const int height = b_image.size()[1];
-    const int channels = b_image.channels();
-
-    float *image_pixels;
-    image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
-    const size_t num_pixels = ((size_t)width) * height;
-
-    if (image_pixels && num_pixels * channels == pixels_size) {
-      memcpy(pixels, image_pixels, pixels_size * sizeof(float));
-    }
-    else {
-      if (channels == 1) {
-        memset(pixels, 0, num_pixels * sizeof(float));
-      }
-      else {
-        const size_t num_pixels_safe = pixels_size / channels;
-        float *fp = pixels;
-        for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
-          fp[0] = 1.0f;
-          fp[1] = 0.0f;
-          fp[2] = 1.0f;
-          if (channels == 4) {
-            fp[3] = 1.0f;
-          }
-        }
-      }
-    }
-
-    if (image_pixels) {
-      MEM_freeN(image_pixels);
-    }
-
-    /* Free image buffers to save memory during render. */
-    if (free_cache) {
-      b_image.buffers_free();
-    }
-
-    return true;
-  }
-  else if (b_id.is_a(&RNA_Object)) {
-    /* smoke volume data */
-    BL::Object b_ob(b_id);
-    BL::FluidDomainSettings b_domain = object_fluid_domain_find(b_ob);
-
-    if (!b_domain) {
-      return false;
-    }
-#if WITH_FLUID
-    int3 resolution = get_int3(b_domain.domain_resolution());
-    int length, amplify = (b_domain.use_noise()) ? b_domain.noise_scale() : 1;
-
-    /* Velocity and heat data is always low-resolution. */
-    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
-        builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
-      amplify = 1;
-    }
-
-    const int width = resolution.x * amplify;
-    const int height = resolution.y * amplify;
-    const int depth = resolution.z * amplify;
-    const size_t num_pixels = ((size_t)width) * height * depth;
-
-    if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
-      FluidDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels) {
-        FluidDomainSettings_density_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
-      /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
-       * as 1500..3000 K with the first part faded to zero density */
-      FluidDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels) {
-        FluidDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
-      /* the RGB is "premultiplied" by density for better interpolation results */
-      FluidDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels * 4) {
-        FluidDomainSettings_color_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
-      FluidDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels * 3) {
-        FluidDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
-      FluidDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels) {
-        FluidDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else if (builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
-      FluidDomainSettings_temperature_grid_get_length(&b_domain.ptr, &length);
-      if (length == num_pixels) {
-        FluidDomainSettings_temperature_grid_get(&b_domain.ptr, pixels);
-        return true;
-      }
-    }
-    else {
-      fprintf(
-          stderr, "Cycles error: unknown volume attribute %s, skipping\n", builtin_name.c_str());
-      pixels[0] = 0.0f;
-      return false;
-    }
-#endif
-    fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
-  }
-  else {
-    /* We originally were passing view_layer here but in reality we need a
-     * a depsgraph to pass to the RE_point_density_minmax() function.
-     */
-    /* TODO(sergey): Check we're indeed in shader node tree. */
-    PointerRNA ptr;
-    RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
-    BL::Node b_node(ptr);
-    if (b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
-      BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
-      int length;
-      b_point_density_node.calc_point_density(b_depsgraph, &length, &pixels);
-    }
-  }
-
-  return false;
-}
-
-void BlenderSession::builtin_images_load()
-{
-  /* Force builtin images to be loaded along with Blender data sync. This
-   * is needed because we may be reading from depsgraph evaluated data which
-   * can be freed by Blender before Cycles reads it.
-   *
-   * TODO: the assumption that no further access to builtin image data will
-   * happen is really weak, and likely to break in the future. We should find
-   * a better solution to hand over the data directly to the image manager
-   * instead of through callbacks whose timing is difficult to control. */
-  ImageManager *manager = session->scene->image_manager;
-  Device *device = session->device;
-  manager->device_load_builtin(device, session->scene, session->progress);
-}
-
 void BlenderSession::update_resumable_tile_manager(int num_samples)
 {
   const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
index 07dccdc5a73bc566f804fabb718eb2031c7c8e39..295d9d2e30755041c0f3328f31355728e05394f2 100644 (file)
@@ -22,7 +22,7 @@
 #include "RNA_access.h"
 #include "RNA_blender_cpp.h"
 
-#include "blender/blender_util.h"
+#include "blender/blender_id_map.h"
 #include "blender/blender_viewport.h"
 
 #include "render/scene.h"
@@ -118,19 +118,13 @@ class BlenderSync {
                    void **python_thread_state);
   void sync_film(BL::SpaceView3D &b_v3d);
   void sync_view();
+
+  /* Shader */
   void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
   void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);
-  void sync_curve_settings();
-
   void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree);
-  Mesh *sync_mesh(BL::Depsgraph &b_depsgrpah,
-                  BL::Object &b_ob,
-                  BL::Object &b_ob_instance,
-                  bool object_updated,
-                  bool use_particle_hair);
-  bool object_has_particle_hair(BL::Object b_ob);
-  void sync_particle_hair(
-      Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
+
+  /* Object */
   Object *sync_object(BL::Depsgraph &b_depsgraph,
                       BL::ViewLayer &b_view_layer,
                       BL::DepsgraphObjectInstance &b_instance,
@@ -139,6 +133,39 @@ class BlenderSync {
                       bool show_lights,
                       BlenderObjectCulling &culling,
                       bool *use_portal);
+
+  /* Volume */
+  void sync_volume(BL::Object &b_ob, Mesh *mesh);
+
+  /* Mesh */
+  void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh);
+  void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step);
+
+  /* Hair */
+  void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh);
+  void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step);
+  void sync_particle_hair(
+      Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
+  void sync_curve_settings();
+  bool object_has_particle_hair(BL::Object b_ob);
+
+  /* Camera */
+  void sync_camera_motion(
+      BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
+
+  /* Geometry */
+  Mesh *sync_geometry(BL::Depsgraph &b_depsgrpah,
+                      BL::Object &b_ob,
+                      BL::Object &b_ob_instance,
+                      bool object_updated,
+                      bool use_particle_hair);
+  void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
+                            BL::Object &b_ob,
+                            Object *object,
+                            float motion_time,
+                            bool use_particle_hair);
+
+  /* Light */
   void sync_light(BL::Object &b_parent,
                   int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
                   BL::Object &b_ob,
@@ -147,14 +174,8 @@ class BlenderSync {
                   Transform &tfm,
                   bool *use_portal);
   void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal);
-  void sync_mesh_motion(BL::Depsgraph &b_depsgraph,
-                        BL::Object &b_ob,
-                        Object *object,
-                        float motion_time);
-  void sync_camera_motion(
-      BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time);
 
-  /* particles */
+  /* Particles */
   bool sync_dupli_particle(BL::Object &b_ob,
                            BL::DepsgraphObjectInstance &b_instance,
                            Object *object);
index 6d6dd75db6b7cfb6daffee7eea83ba38e62e2717..cb7d1c62f6049a700793efc0f570355d5d705b11 100644 (file)
@@ -531,7 +531,7 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
   return use_deform_motion;
 }
 
-static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob)
+static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
 {
   BL::Object::modifiers_iterator b_mod;
 
@@ -539,8 +539,28 @@ static inline BL::FluidDomainSettings object_fluid_domain_find(BL::Object &b_ob)
     if (b_mod->is_a(&RNA_FluidModifier)) {
       BL::FluidModifier b_mmd(*b_mod);
 
-      if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN)
+      if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
+          b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
         return b_mmd.domain_settings();
+      }
+    }
+  }
+
+  return BL::FluidDomainSettings(PointerRNA_NULL);
+}
+
+static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
+{
+  BL::Object::modifiers_iterator b_mod;
+
+  for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+    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();
+      }
     }
   }
 
@@ -573,248 +593,20 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
   return Mesh::SUBDIVISION_NONE;
 }
 
-/* ID Map
- *
- * Utility class to keep in sync with blender data.
- * Used for objects, meshes, lights and shaders. */
-
-template<typename K, typename T> class id_map {
- public:
-  id_map(vector<T *> *scene_data_)
-  {
-    scene_data = scene_data_;
-  }
-
-  T *find(const BL::ID &id)
-  {
-    return find(id.ptr.owner_id);
-  }
-
-  T *find(const K &key)
-  {
-    if (b_map.find(key) != b_map.end()) {
-      T *data = b_map[key];
-      return data;
-    }
-
-    return NULL;
-  }
-
-  void set_recalc(const BL::ID &id)
-  {
-    b_recalc.insert(id.ptr.data);
-  }
-
-  void set_recalc(void *id_ptr)
-  {
-    b_recalc.insert(id_ptr);
-  }
-
-  bool has_recalc()
-  {
-    return !(b_recalc.empty());
-  }
-
-  void pre_sync()
-  {
-    used_set.clear();
-  }
-
-  bool sync(T **r_data, const BL::ID &id)
-  {
-    return sync(r_data, id, id, id.ptr.owner_id);
-  }
-
-  bool sync(T **r_data, const BL::ID &id, const K &key)
-  {
-    return sync(r_data, id, id, key);
-  }
-
-  bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key)
-  {
-    T *data = find(key);
-    bool recalc;
-
-    if (!data) {
-      /* add data if it didn't exist yet */
-      data = new T();
-      scene_data->push_back(data);
-      b_map[key] = data;
-      recalc = true;
-    }
-    else {
-      recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
-      if (parent.ptr.data && parent.ptr.data != id.ptr.data) {
-        recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
-      }
-    }
-
-    used(data);
-
-    *r_data = data;
-    return recalc;
-  }
-
-  bool is_used(const K &key)
-  {
-    T *data = find(key);
-    return (data) ? used_set.find(data) != used_set.end() : false;
-  }
-
-  void used(T *data)
-  {
-    /* tag data as still in use */
-    used_set.insert(data);
-  }
-
-  void set_default(T *data)
-  {
-    b_map[NULL] = data;
-  }
-
-  bool post_sync(bool do_delete = true)
-  {
-    /* remove unused data */
-    vector<T *> new_scene_data;
-    typename vector<T *>::iterator it;
-    bool deleted = false;
-
-    for (it = scene_data->begin(); it != scene_data->end(); it++) {
-      T *data = *it;
-
-      if (do_delete && used_set.find(data) == used_set.end()) {
-        delete data;
-        deleted = true;
-      }
-      else
-        new_scene_data.push_back(data);
-    }
-
-    *scene_data = new_scene_data;
-
-    /* update mapping */
-    map<K, T *> new_map;
-    typedef pair<const K, T *> TMapPair;
-    typename map<K, T *>::iterator jt;
-
-    for (jt = b_map.begin(); jt != b_map.end(); jt++) {
-      TMapPair &pair = *jt;
-
-      if (used_set.find(pair.second) != used_set.end())
-        new_map[pair.first] = pair.second;
-    }
-
-    used_set.clear();
-    b_recalc.clear();
-    b_map = new_map;
-
-    return deleted;
-  }
-
-  const map<K, T *> &key_to_scene_data()
-  {
-    return b_map;
-  }
-
- protected:
-  vector<T *> *scene_data;
-  map<K, T *> b_map;
-  set<T *> used_set;
-  set<void *> b_recalc;
-};
-
-/* Object Key */
-
-enum { OBJECT_PERSISTENT_ID_SIZE = 16 };
-
-struct ObjectKey {
-  void *parent;
-  int id[OBJECT_PERSISTENT_ID_SIZE];
-  void *ob;
-  bool use_particle_hair;
-
-  ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_, bool use_particle_hair_)
-      : parent(parent_), ob(ob_), use_particle_hair(use_particle_hair_)
-  {
-    if (id_)
-      memcpy(id, id_, sizeof(id));
-    else
-      memset(id, 0, sizeof(id));
-  }
-
-  bool operator<(const ObjectKey &k) const
-  {
-    if (ob < k.ob) {
-      return true;
-    }
-    else if (ob == k.ob) {
-      if (parent < k.parent) {
-        return true;
-      }
-      else if (parent == k.parent) {
-        if (use_particle_hair < k.use_particle_hair) {
-          return true;
-        }
-        else if (use_particle_hair == k.use_particle_hair) {
-          return memcmp(id, k.id, sizeof(id)) < 0;
-        }
-      }
-    }
-
-    return false;
-  }
-};
-
-/* Mesh Key */
-
-struct MeshKey {
-  void *id;
-  bool use_particle_hair;
-
-  MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair)
-  {
-  }
-
-  bool operator<(const MeshKey &k) const
-  {
-    if (id < k.id) {
-      return true;
-    }
-    else if (id == k.id) {
-      if (use_particle_hair < k.use_particle_hair) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-};
-
-/* Particle System Key */
-
-struct ParticleSystemKey {
-  void *ob;
-  int id[OBJECT_PERSISTENT_ID_SIZE];
-
-  ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) : ob(ob_)
-  {
-    if (id_)
-      memcpy(id, id_, sizeof(id));
-    else
-      memset(id, 0, sizeof(id));
-  }
+static inline uint object_ray_visibility(BL::Object &b_ob)
+{
+  PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
+  uint flag = 0;
 
-  bool operator<(const ParticleSystemKey &k) const
-  {
-    /* first id is particle index, we don't compare that */
-    if (ob < k.ob)
-      return true;
-    else if (ob == k.ob)
-      return memcmp(id + 1, k.id + 1, sizeof(int) * (OBJECT_PERSISTENT_ID_SIZE - 1)) < 0;
+  flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
+  flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
+  flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
+  flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
+  flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0;
+  flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
 
-    return false;
-  }
-};
+  return flag;
+}
 
 class EdgeMap {
  public:
diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp
new file mode 100644 (file)
index 0000000..87fb962
--- /dev/null
@@ -0,0 +1,95 @@
+
+/*
+ * 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.
+ */
+
+#include "render/colorspace.h"
+#include "render/mesh.h"
+#include "render/object.h"
+
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Mesh *mesh, float frame)
+{
+  BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
+  if (!b_domain) {
+    return;
+  }
+
+  ImageManager *image_manager = scene->image_manager;
+  AttributeStandard attributes[] = {ATTR_STD_VOLUME_DENSITY,
+                                    ATTR_STD_VOLUME_COLOR,
+                                    ATTR_STD_VOLUME_FLAME,
+                                    ATTR_STD_VOLUME_HEAT,
+                                    ATTR_STD_VOLUME_TEMPERATURE,
+                                    ATTR_STD_VOLUME_VELOCITY,
+                                    ATTR_STD_NONE};
+
+  for (int i = 0; attributes[i] != ATTR_STD_NONE; i++) {
+    AttributeStandard std = attributes[i];
+    if (!mesh->need_attribute(scene, std)) {
+      continue;
+    }
+
+    mesh->volume_isovalue = b_domain.clipping();
+
+    Attribute *attr = mesh->attributes.add(std);
+    VoxelAttribute *volume_data = attr->data_voxel();
+    ImageMetaData metadata;
+    bool animated = false;
+
+    volume_data->manager = image_manager;
+    volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
+                                                 b_ob.ptr.data,
+                                                 animated,
+                                                 frame,
+                                                 INTERPOLATION_LINEAR,
+                                                 EXTENSION_CLIP,
+                                                 IMAGE_ALPHA_AUTO,
+                                                 u_colorspace_raw,
+                                                 metadata);
+  }
+
+  /* Create a matrix to transform from object space to mesh texture space.
+   * This does not work with deformations but that can probably only be done
+   * well with a volume grid mapping of coordinates. */
+  if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
+    Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
+    Transform *tfm = attr->data_transform();
+
+    BL::Mesh b_mesh(b_ob.data());
+    float3 loc, size;
+    mesh_texture_space(b_mesh, loc, size);
+
+    *tfm = transform_translate(-loc) * transform_scale(size);
+  }
+}
+
+void BlenderSync::sync_volume(BL::Object &b_ob, Mesh *mesh)
+{
+  bool old_has_voxel_attributes = mesh->has_voxel_attributes();
+
+  /* Smoke domain. */
+  sync_smoke_volume(scene, b_ob, mesh, b_scene.frame_current());
+
+  /* Tag update. */
+  bool rebuild = (old_has_voxel_attributes != mesh->has_voxel_attributes());
+  mesh->tag_update(scene, rebuild);
+}
+
+CCL_NAMESPACE_END